perf: batch popularity lookups in single SQLite query (100+ → 1)

boostWithIndexPopularity was calling GetPopularity() and IsInLibrary()
individually for every search result — ~100 separate SQLite queries
for a typical search (20 artists × 2 + 20 RGs × 2 + 20 recordings).
This took 7.5s on the 'fast path' that was supposed to take ~5ms.

Added GetPopularityBatch(mbids) — collects all MBIDs across all
entity types and fetches popularity + in_library in a single
SELECT ... WHERE mbid IN (...) query. The library bonus (+10M) is
applied during the batch scan.

Expected Phase 2 improvement: ~7.5s → <10ms.
This commit is contained in:
2026-03-29 23:55:26 -04:00
parent 8a138797dd
commit 3d0349a427
2 changed files with 77 additions and 21 deletions
+30 -21
View File
@@ -933,47 +933,56 @@ var mbSpecialPurposeArtists = map[string]bool{
// just SQLite lookups. This is the fast path used when the index
// is ready.
func (e *Service) boostWithIndexPopularity(result *MBSearchResult) {
// Look up popularity for all artist MBIDs.
// Give a large bonus to library artists so they rank first.
artistPop := make(map[string]int, len(result.Artists))
// Collect all MBIDs across all entity types.
allMBIDs := make([]string, 0,
len(result.Artists)+len(result.ReleaseGroups)+len(result.Recordings))
for _, a := range result.Artists {
pop := e.index.GetPopularity(a.MBID)
// Library artists get a massive popularity bonus.
if e.index.IsInLibrary(a.MBID) {
pop += 10_000_000 //nolint:mnd
if a.MBID != "" {
allMBIDs = append(allMBIDs, a.MBID)
}
}
if pop > 0 {
for _, rg := range result.ReleaseGroups {
if rg.MBID != "" {
allMBIDs = append(allMBIDs, rg.MBID)
}
}
for _, r := range result.Recordings {
if r.MBID != "" {
allMBIDs = append(allMBIDs, r.MBID)
}
}
// Single batch query for all popularity + in_library data.
popMap := e.index.GetPopularityBatch(allMBIDs)
if popMap == nil {
return
}
// Build per-entity maps from the batch result.
artistPop := make(map[string]int, len(result.Artists))
for _, a := range result.Artists {
if pop, ok := popMap[a.MBID]; ok {
artistPop[a.MBID] = pop
}
}
rerankArtists(result.Artists, artistPop)
// Look up popularity for release groups.
rgPop := make(map[string]int, len(result.ReleaseGroups))
for _, rg := range result.ReleaseGroups {
pop := e.index.GetPopularity(rg.MBID)
if e.index.IsInLibrary(rg.MBID) {
pop += 10_000_000 //nolint:mnd
}
if pop > 0 {
if pop, ok := popMap[rg.MBID]; ok {
rgPop[rg.MBID] = pop
}
}
rerankReleaseGroups(result.ReleaseGroups, rgPop)
// Look up popularity for recordings.
recPop := make(map[string]int, len(result.Recordings))
for _, r := range result.Recordings {
if pop := e.index.GetPopularity(r.MBID); pop > 0 {
if pop, ok := popMap[r.MBID]; ok {
recPop[r.MBID] = pop
}
}