Using packed keys instead of actor-tags table.

This commit is contained in:
2026-07-03 02:15:04 +02:00
parent 287932d9d7
commit 1543bf9d03
4 changed files with 55 additions and 23 deletions

View File

@@ -418,6 +418,20 @@ function curateFacet(results, field) {
|| [];
}
const packN = 100_000;
function mergePackedTags(tags) {
const mergedCounts = tags.reduce((merged, tag) => {
const tagId = tag.key % packN;
merged.set(tagId, (merged.get(tagId) ?? 0) + tag.doc_count);
return merged;
}, new Map());
return Array.from(mergedCounts.entries(), ([key, count]) => ({ key, doc_count: count }));
}
async function queryManticoreSql(filters, options, _reqUser) {
const aggSize = config.database.manticore.maxAggregateSize;
@@ -440,7 +454,6 @@ async function queryManticoreSql(filters, options, _reqUser) {
:yearsFacet:
:actorsFacet:
:tagsFacet:
:actorTagsFacet:
:channelsFacet:
:studiosFacet:;
show meta;
@@ -473,11 +486,6 @@ async function queryManticoreSql(filters, options, _reqUser) {
year(scenes.effective_date) as effective_year,
weight() as _score
`));
// manticore only supports one joined table, so we can't use it inside stashes
builder
.leftJoin('scenes_tags', 'scenes_tags.scene_id', 'scenes_.id')
.groupBy('scenes.id');
}
if (filters.query) {
@@ -533,12 +541,6 @@ async function queryManticoreSql(filters, options, _reqUser) {
builder.where('scenes.is_showcased', filters.isShowcased);
}
/*
if (filters.isShowcased) {
builder.where('scenes.date', '>', 0);
}
*/
if (options.dedupe) {
builder.where('scenes.dupe_index', '<', 2);
}
@@ -583,11 +585,7 @@ async function queryManticoreSql(filters, options, _reqUser) {
// option threads=1 fixes actors, but drastically slows down performance, wait for fix
yearsFacet: options.aggregateYears ? knex.raw('facet effective_year as years_facet order by effective_year desc limit ?', [aggSize]) : null,
actorsFacet: options.aggregateActors ? knex.raw('facet scenes.actor_ids as actors_facet distinct id order by count(*) desc limit ?', [aggSize]) : null,
// don't facet tags associated to other actors, actor ID 0 means global
tagsFacet: options.aggregateTags ? knex.raw('facet scenes.tag_ids as tags_facet distinct id order by count(*) desc limit ?', [aggSize]) : null,
actorTagsFacet: options.aggregateTags && !filters.stashId // eslint-disable-line no-nested-ternary
? knex.raw(`facet IF(IN(scenes_tags.actor_id, ${[0, ...filters?.actorIds || []]}), scenes_tags.tag_id, 0) as actor_tags_facet distinct id order by count(*) desc limit ?`, [aggSize])
: null,
tagsFacet: options.aggregateTags ? knex.raw('facet scenes.assigned_tag_ids as tags_facet distinct id order by count(*) desc limit ?', [aggSize]) : null,
channelsFacet: options.aggregateChannels ? knex.raw('facet scenes.channel_id as channels_facet distinct id order by count(*) desc limit ?', [aggSize]) : null,
studiosFacet: options.aggregateChannels ? knex.raw('facet scenes.studio_id as studios_facet distinct id order by count(*) desc limit ?', [aggSize]) : null,
maxMatches: config.database.manticore.maxMatches,
@@ -610,10 +608,26 @@ async function queryManticoreSql(filters, options, _reqUser) {
const years = curateFacet(results, 'years_facet');
const actorIds = curateFacet(results, 'actors_facet');
const tagIds = curateFacet(results, 'tags_facet');
const actorTagIds = curateFacet(results, 'actor_tags_facet');
const channelIds = curateFacet(results, 'channels_facet');
const studioIds = curateFacet(results, 'studios_facet');
const allTagIds = mergePackedTags(tagIds);
const actorTagIds = mergePackedTags(tagIds.filter((tag) => {
if (tag.key < packN || !filters?.actorIds.length) {
// global
return true;
}
const tagActorId = Math.floor(tag.key / packN);
if (filters.actorIds.includes(tagActorId)) {
return true;
}
return false;
}));
const total = Number(results.at(-1).data.find((entry) => entry.Variable_name === 'total_found')?.Value) || 0;
return {
@@ -622,7 +636,7 @@ async function queryManticoreSql(filters, options, _reqUser) {
aggregations: {
years,
actorIds,
tagIds,
tagIds: allTagIds,
actorTagIds,
channelIds,
studioIds,