refactor: remove cid👎tids (and variants) from intersection in /world, fixes #13125

- remove "poor man's intersect" but not considering the main `cid👎tids` set at all
  including its variants (voting, reply time, etc.)
- added a new method Categories.sortTidsBySet which allows after-the-fact sorting
  of tids by their score in a set.
This commit is contained in:
Julian Lam
2025-02-19 14:18:20 -05:00
parent 0d14ff15d7
commit d0561a602e
2 changed files with 25 additions and 18 deletions

View File

@@ -99,7 +99,8 @@ module.exports = function (Categories) {
most_views: `cid:${cid}:tids:views`,
};
const set = new Set([sortToSet.hasOwnProperty(sort) ? sortToSet[sort] : `cid:${cid}:tids`]);
const mainSet = sortToSet.hasOwnProperty(sort) ? sortToSet[sort] : `cid:${cid}:tids`;
const set = new Set([mainSet]);
if (data.tag) {
if (Array.isArray(data.tag)) {
@@ -116,6 +117,7 @@ module.exports = function (Categories) {
}
if (parseInt(cid, 10) === -1 && uid > 0) {
set.delete(mainSet);
set.add(`uid:${uid}:inbox`);
}
const setValue = Array.from(set);
@@ -251,4 +253,24 @@ module.exports = function (Categories) {
});
notifications.push(notification, followers);
};
Categories.sortTidsBySet = async (tids, cid, sort) => {
sort = sort || meta.config.categoryTopicSort || 'recently_replied';
const sortToSet = {
recently_replied: `cid:${cid}:tids`,
recently_created: `cid:${cid}:tids:create`,
most_posts: `cid:${cid}:tids:posts`,
most_votes: `cid:${cid}:tids:votes`,
most_views: `cid:${cid}:tids:views`,
};
const orderBy = sortToSet[sort];
const scores = await db.sortedSetScores(orderBy, tids);
const sorted = tids
.map((tid, idx) => [tid, scores[idx]])
.sort(([, a], [, b]) => b - a)
.map(([tid]) => tid);
return sorted;
};
};

View File

@@ -20,22 +20,6 @@ const validSorts = [
'recently_replied', 'recently_created', 'most_posts', 'most_votes', 'most_views',
];
async function getTids(data) {
// Poor man's intersect used instead of getSortedSetIntersect because the zsets are huge
const sets = await categories.buildTopicsSortedSet(data);
const intersect = Array.isArray(sets);
const mainSet = intersect ? sets.shift() : sets;
let tids = await db.getSortedSetRevRange(mainSet, 0, 499);
if (!intersect) {
return tids.slice(data.start, data.stop + 1);
}
let intersection = await Promise.all(sets.map(async set => db.isSortedSetMembers(set, tids)));
intersection = intersection.reduce((memo, cur) => memo.map((show, idx) => show && cur[idx]));
tids = tids.filter((_, idx) => intersection[idx]);
return tids.slice(data.start, data.stop + 1);
}
controller.list = async function (req, res) {
if (!req.uid) {
return helpers.redirect(res, '/recent?cid=-1', false);
@@ -69,7 +53,8 @@ controller.list = async function (req, res) {
data.name = '[[world:name]]';
delete data.children;
const tids = await getTids(cidQuery);
let tids = await categories.getTopicIds(cidQuery);
tids = await categories.sortTidsBySet(tids, -1, sort); // sorting not handled if cid is -1
data.topicCount = tids.length;
data.topics = await topics.getTopicsByTids(tids, { uid: req.uid });
topics.calculateTopicIndices(data.topics, start);