mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
Merge pull request #1759 from Discordius/devel
Improve speed of vote score updates (Mongo aggregator + bulkwrite)
This commit is contained in:
commit
6e2dfdc39c
2 changed files with 117 additions and 11 deletions
|
@ -1,5 +1,5 @@
|
|||
import { getSetting, registerSetting, debug } from 'meteor/vulcan:core';
|
||||
import { updateScore } from './scoring.js';
|
||||
import { /*updateScore,*/ batchUpdateScore } from './scoring.js';
|
||||
import { VoteableCollections } from '../modules/make_voteable.js';
|
||||
|
||||
registerSetting('voting.scoreUpdateInterval', 60, 'How often to update scores, in seconds');
|
||||
|
@ -14,28 +14,32 @@ Meteor.startup(function () {
|
|||
VoteableCollections.forEach(collection => {
|
||||
|
||||
// active items get updated every N seconds
|
||||
Meteor.setInterval(function () {
|
||||
Meteor.setInterval(async function () {
|
||||
|
||||
let updatedDocuments = 0;
|
||||
// let updatedDocuments = 0;
|
||||
|
||||
// console.log('tick ('+scoreInterval+')');
|
||||
collection.find({'inactive': {$ne : true}}).forEach(document => {
|
||||
updatedDocuments += updateScore({collection, item: document});
|
||||
});
|
||||
// collection.find({'inactive': {$ne : true}}).forEach(document => {
|
||||
// updatedDocuments += updateScore({collection, item: document});
|
||||
// });
|
||||
|
||||
const updatedDocuments = await batchUpdateScore(collection, false, false);
|
||||
|
||||
debug(`[vulcan:voting] Updated scores for ${updatedDocuments} active documents in collection ${collection.options.collectionName}`)
|
||||
|
||||
}, scoreInterval * 1000);
|
||||
|
||||
// inactive items get updated every hour
|
||||
Meteor.setInterval(function () {
|
||||
Meteor.setInterval(async function () {
|
||||
|
||||
|
||||
let updatedDocuments = 0;
|
||||
// let updatedDocuments = 0;
|
||||
//
|
||||
// collection.find({'inactive': true}).forEach(document => {
|
||||
// updatedDocuments += updateScore({collection, item: document});
|
||||
// });
|
||||
|
||||
collection.find({'inactive': true}).forEach(document => {
|
||||
updatedDocuments += updateScore({collection, item: document});
|
||||
});
|
||||
const updatedDocuments = await batchUpdateScore(collection, true, false);
|
||||
|
||||
debug(`[vulcan:voting] Updated scores for ${updatedDocuments} inactive documents in collection ${collection.options.collectionName}`)
|
||||
|
||||
|
|
|
@ -58,3 +58,105 @@ export const updateScore = ({collection, item, forceUpdate}) => {
|
|||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const batchUpdateScore = async (collection, inactive = false, forceUpdate = false) => {
|
||||
// n = number of days after which a single vote will not have a big enough effect to trigger a score update
|
||||
// and posts can become inactive
|
||||
const n = 30;
|
||||
// x = score increase amount of a single vote after n days (for n=100, x=0.000040295)
|
||||
const x = 1/Math.pow(n*24+2,1.3);
|
||||
// time decay factor
|
||||
const f = 1.3
|
||||
const itemsPromise = collection.rawCollection().aggregate([
|
||||
{
|
||||
$match: {
|
||||
$and: [
|
||||
{postedAt: {$exists: true}},
|
||||
{postedAt: {$lte: new Date()}},
|
||||
{inactive: inactive ? true : {$ne: true}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
postedAt: 1,
|
||||
baseScore: 1,
|
||||
score: 1,
|
||||
newScore: {
|
||||
$divide: [
|
||||
"$baseScore",
|
||||
{
|
||||
$pow: [
|
||||
{
|
||||
$add: [
|
||||
{
|
||||
$divide: [
|
||||
{
|
||||
$subtract: [new Date(), "$postedAt"] // Age in miliseconds
|
||||
},
|
||||
60 * 60 * 1000
|
||||
]
|
||||
}, // Age in hours
|
||||
2
|
||||
]
|
||||
},
|
||||
f
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
postedAt: 1,
|
||||
baseScore: 1,
|
||||
score: 1,
|
||||
newScore: 1,
|
||||
scoreDiffSignificant: {
|
||||
$gt: [
|
||||
{$abs: {$subtract: ["$score", "$newScore"]}},
|
||||
x
|
||||
]
|
||||
},
|
||||
oldEnough: { // Only set a post as inactive if it's older than n days
|
||||
$gt: [
|
||||
{$divide: [
|
||||
{
|
||||
$subtract: [new Date(), "$postedAt"] // Difference in miliseconds
|
||||
},
|
||||
60 * 60 * 1000 //Difference in hours
|
||||
]},
|
||||
n*24]
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
|
||||
const items = await itemsPromise;
|
||||
const itemsArray = await items.toArray();
|
||||
let updatedDocumentsCounter = 0;
|
||||
const itemUpdates = _.compact(itemsArray.map(i => {
|
||||
if (forceUpdate || i.scoreDiffSignificant) {
|
||||
updatedDocumentsCounter++;
|
||||
return {
|
||||
updateOne: {
|
||||
filter: {_id: i._id},
|
||||
update: {$set: {score: i.newScore, inactive: false}},
|
||||
upsert: false,
|
||||
}
|
||||
}
|
||||
} else if (i.oldEnough) {
|
||||
// only set a post as inactive if it's older than n days
|
||||
return {
|
||||
updateOne: {
|
||||
filter: {_id: i._id},
|
||||
update: {$set: {inactive: true}},
|
||||
upsert: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
if (itemUpdates && itemUpdates.length) {await collection.rawCollection().bulkWrite(itemUpdates, {ordered: false});}
|
||||
return updatedDocumentsCounter;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue