Skip to content

Commit

Permalink
matches controller updated. query added, analyzers added. user schema…
Browse files Browse the repository at this point in the history
… updated. matches page is now dynamic
  • Loading branch information
mbareeva committed Aug 22, 2021
1 parent 805be4b commit 7cec340
Show file tree
Hide file tree
Showing 9 changed files with 26,944 additions and 328 deletions.
247 changes: 173 additions & 74 deletions controllers/matchesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const Media = require("../models/media");
const { Client } = require('elasticsearch');
const bonsai = process.env.BONSAI_URL || "http://localhost:9200";
const client = new Client({ host: bonsai });
const graphApiController = require("./instaGraphApiController");
//const graphApiController = require("./instaGraphApiController");
const { query } = require("express");
const user = require("../models/user");
//The controller where the query is defined that generated the matches for business profile
//in Instagram.
module.exports = {
Expand All @@ -12,9 +14,9 @@ module.exports = {
* Get all recommendations for the logged in user.
*/
renderAllMatches: (req, res) => {
// if (res.locals.matches) {
res.render("matches/index")
//}
res.render("matches/index", {
users: res.locals.matches
})
},

/**
Expand All @@ -34,23 +36,42 @@ module.exports = {
* @param {*} next Next function to be called.
*/
getMatches: (req, res, next) => {
let userId = req.params._id;
User.findById(userId).then(thisUser => {
res.locals.user = user;
let userId = req.params.id;
console.log(userId)
User.findOne({ _id: userId }).then(thisUser => {
console.log(thisUser);
res.locals.user = thisUser;
Media.find({ _id: { $in: thisUser.latestMedia } }).then(mediaItems => {
res.locals.media = mediaItems; // here maybe extracted keywords from captions
let keywords = [];
let queryObject = {
"specialisation": user.specialisation,
"profileCategory": user.profileCategory,
"keywords": this.getKeywords(thisUser)
}
let query = this.setQuery("users", queryObject);
res.locals.media = mediaItems;
//console.log("Check the media.locals: ", res.locals.media ? res.locals.media : "") // here maybe extracted keywords from captions

//Object definition for query later on.
let queryObject = {}
//Keywords extraction according to NLTK Algorithm. Link to the library: ... !!!!.
//let keywordsBiography = { keywords: this.getKeywords(thisUser) };
//let keywordsCaptions = { keywords: this.getKeywords(mediaItems.caption) }
//Push values to the object.
console.log("Specialisation: ", thisUser.specialisation)
queryObject.specialisation = thisUser.specialisation

queryObject.interest = thisUser.interest
queryObject.location = thisUser.location
queryObject.keywordsBio = thisUser.biography
// queryObject[keywordsMedia] = keywordsCaptions
queryObject.captions = "";
mediaItems.forEach(item => {
queryObject.captions += item.caption + " "
})

//Set the query with the object with important values.
let query = module.exports.setQuery("users", queryObject, thisUser);

this.sendQueryRequest(req, res, next, user, query);
module.exports.sendQueryRequest(req, res, next, thisUser, query);
}).catch(error => {
console.error(`Error while indexing media items`, error);
console.error(`Error while searching for media items.`, error);
})
}).catch(error => {
console.error(`Error while searching for the user.`, error);
})
},

Expand All @@ -62,82 +83,160 @@ module.exports = {
})
},

setQuery: (index, queryObject) => {
keywords.forEach(keyword => {

})

let engagementRate = this.getEngagementRate();
/**
*
* @param {String} index The index for search query.
* @param {Object} queryObject The values that user has in its profile.
* @param {Object} user The logged in user for whom the matches should be generated.
*/
setQuery: (index, queryObject, user) => {
let query = {
index: index,
body: {
query: {
function_score: {
query: {
match: {
category: ""
bool: {
should: [
{
match: {
"specialisation": {
query: queryObject.specialisation,
boost: Math.pow(2, 2)
}
}
},
{
match: {
"interest": {
query: queryObject.interest,
boost: Math.pow(2, 2)
},
}
},
{
match: {
"location": {
query: queryObject.location
}
}
},
{
match: {
"latestMedia.caption": {
query: queryObject.captions,
analyzer: "my_analyzer"
}
}
},
{
match: {
"biography": {
query: queryObject.keywordsBio,
analyzer: "my_analyzer",
boost: Math.pow(2, 2)
}
}
}
]
}
}
},
functions: [
{
script_score: {
script: {
source: (doc['likes'].value / doc['comments'] / doc['followers_count'].value * 100)
}
}
}
],
boost: 5,
boost_mode: "sum"
// functions: [
// {
// script_score: {
// script: {
// source: (doc['likes'].value + doc['comments'] / doc['followers_count'].value * 100)
// }
// }
// }
// ],
// boost: engagementRate,
// boost_mode: "sum"
}
}
}
return query;
},

sendQueryRequest: () => {
client.search(query, (err, res) => {
if (err) return next(err);
let data = res.hits.hits;
let result = [];
if (data) {
let matchesFound = data.map(async hit => {
let user = await User.findById(hit._id);
result.push(user);
})
res.local.matches = matchesFound;
next();
/**
* Sends the search API request to Elasticsearch index.
* Searches for matches according to the given query and
* saves the results. Redirects to the next middleware function.
*/
sendQueryRequest: (req, res, next, thisUser, query) => {
client.search(query, async (err, result) => {
if (err) {
console.log("Error while searching for the matches.")
return next(err);
} else {
console.log("No matches found.")
let data = result.hits.hits;
let maxScore = result.hits.max_score;
console.log("Max Score: ", maxScore)
console.log("Total matches count: ", data.length)
let finalResult = [];
if (data) {
let matchesFound = data.map(async hit => {
let user = await User.findById(hit._id);
user.score = userScore(hit._score, maxScore);
console.log("Score: ", user.score)
user.engagementRate = await getEngagementRate(user);
console.log("rate: ", user.engagementRate)
if (user.username !== thisUser.username)
finalResult.push(user);
})
await Promise.all(matchesFound)
res.locals.matches = sortInfluentialUsers(finalResult);
next();
} else {
console.log("No matches found.")
}
}
}).then(response => {

})

},

//////// HELPER FUNCTIONS ///////
/**
*
* @param {Object} user The user whose engagement rate is calculated.
* @returns The engagement rate of the user based on the activity of its followers.
*/
getEngagementRate: (user) => {
//engagement rate = (likes + comments) / Followers x 100
let totalLikes
let totalCommentCount
user.latesMedia.forEach(mediaItem => {
}
}

//////// HELPER FUNCTIONS ///////
/**
* Sorts users according to the relevance score.
* @param {Object} results The matched user generated by Elasticsearch.
* @returns Sorted list of users.
*/
function sortInfluentialUsers(results) {
results.sort((user1, user2) => {
return user2.score - user1.score;
})
return results;
}

/**
* Calculates the ration between the given score of a match and the max_score.
* @param {*} usersScore The score of the match.
* @param {*} maxScore The max score of the response.
* @returns The score in percent.
*/
function userScore(userScore, maxScore) {
return (userScore / maxScore * 100).toFixed(2);
}


/**
*
* @param {Object} user The user whose engagement rate is calculated.
* @returns The engagement rate of the user based on the activity of its followers.
*/
async function getEngagementRate(user) {
//engagement rate = (likes + comments) / Followers x 100
let totalLikes = 0
let totalCommentCount = 0
let points = await Media.find({ _id: { $in: user.latestMedia } }).then(items => {
items.forEach(mediaItem => {
totalLikes += mediaItem.likes
totalCommentCount += mediaItem.commentCount
})
let average = (totalLikes + totalCommentCount) / user.followers_count * 100;
return average;
},


getKeywords: (user) => {

}


return totalLikes + totalCommentCount
})
let average = ((points) / user.followers_count) * 100;
return average;
}
8 changes: 4 additions & 4 deletions models/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ mediaSchema.plugin(mongoosastic, {
});

let Media = mongoose.model('Media', mediaSchema);
Media.createMapping((err, mapping) => {
console.log('** elasticsearch mapping created for Medias');
console.log("***port: ", process.env.BONSAI_PORT)
})
// Media.createMapping((err, mapping) => {
// console.log('** elasticsearch mapping created for Medias');
// console.log("***port: ", process.env.BONSAI_PORT)
// })

module.exports = mongoose.model("Media", mediaSchema);
43 changes: 40 additions & 3 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ userSchema = mongoose.Schema({
role: {
type: String,
enum: ["business", "influencer"]
}
},
score: Number,
engagementRate: Number
});

// ***** Retrieve auth credentials from bonsai elasticsearch add-on ***** //
Expand All @@ -63,8 +65,43 @@ userSchema.plugin(passportLocalMongoose);
let User = mongoose.model('User', userSchema);

// ***** create a mapping *****
User.createMapping((err, mapping) => {
console.log('** elasticsearch mapping created for Users');
User.createMapping({
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": [
"lowercase",
"my_stemmer",
"my_stopwords",
"synonym"
]
}
},
"filter": {
"my_stemmer": {
"type": "stemmer",
"language": "light_english"
},
"my_stopwords": {
"type": "stop",
"stopwords": "_english_"
},
"synonym": {
"type": "synonym",
"synonyms": [
"gym, training, sport, workout",
"jumped, jump",
"priveleged, privelege, honor"
]
}
}
}
}, (err, mapping) => {
if (err) { 'error creating the mapping' }
else {
console.log('** elasticsearch mapping created for Users');
}
})


Expand Down
4 changes: 4 additions & 0 deletions public/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,8 @@ h1 .profile{

.error {
background: rgba(209, 46, 42, 0.7);
}

.col-md-4{
margin-bottom: 10px;
}
4 changes: 1 addition & 3 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ router.get('/users/logout', userController.logout);

router.get('/handleauth', instaGraphApiController.getAccess);
router.get('/users/profile/:id', instaGraphApiController.index, instaGraphApiController.indexView);

router.get('/users/matches/', matchesController.renderAllMatches); //tryout
// router.get('/users/matches/', matchesController.getMatches, matchesController.renderAllMatches);
router.get('/users/matches/:id', matchesController.getMatches, matchesController.renderAllMatches);
// router.get('/users/matches/:userId', matchesController.getMatch, matchesController.renderSingleMatch);
module.exports = router;
Loading

0 comments on commit 7cec340

Please sign in to comment.