From 17ca0390870220ae20cc2e709a99c175af9e09f7 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 7 Jun 2026 10:21:57 +0200 Subject: [PATCH] Speed up audio similarity engine startup for big collections --- .../AudioSimilarityEngine.impl.hpp | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp b/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp index bba489df..80960b9f 100644 --- a/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp +++ b/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp @@ -31,7 +31,6 @@ #include "core/ILogger.hpp" #include "core/ITraceLogger.hpp" -#include "core/Random.hpp" #include "database/IDb.hpp" #include "database/Session.hpp" @@ -682,20 +681,26 @@ namespace lms::recommendation LMS_SCOPED_TRACE_DETAILED("AudioSimilarityEngine", "computeTrackDistanceThreshold"); constexpr std::size_t maxSampleCount{ 500 }; + constexpr std::size_t maxCandidateCount{ 10'000 }; constexpr float stdDevMultiplier{ 2.F }; - const std::size_t sampleCount{ std::min(_trackVectors.size(), maxSampleCount) }; - - LOG(INFO, "computing track distance threshold using " << sampleCount << " samples..."); - - // Collect all vector pointers and shuffle for an unbiased random sample. std::vector allVectors; allVectors.reserve(_trackVectors.size()); for (const auto& [id, vec] : _trackVectors) allVectors.push_back(vec); + // move maxCandidateCount random elements to the front + const std::size_t candidateCount{ std::min(allVectors.size(), maxCandidateCount) }; std::minstd_rand randomEngine{ 42 }; - core::random::shuffleContainer(randomEngine, allVectors); + for (std::size_t i{}; i < candidateCount; ++i) + { + std::uniform_int_distribution dist{ i, allVectors.size() - 1 }; + std::swap(allVectors[i], allVectors[dist(randomEngine)]); + } + allVectors.resize(candidateCount); + + const std::size_t sampleCount{ std::min(candidateCount, maxSampleCount) }; + LOG(INFO, "computing track distance threshold using " << sampleCount << " samples on " << candidateCount << " candidates..."); math::StatsAccumulator stats; for (std::size_t i{}; i < sampleCount; ++i) @@ -714,7 +719,8 @@ namespace lms::recommendation minDist = d; } - stats.add(minDist); + if (minDist < std::numeric_limits::max()) + stats.add(minDist); } if (stats.getCount() >= 2) @@ -731,7 +737,7 @@ namespace lms::recommendation LMS_SCOPED_TRACE_DETAILED("AudioSimilarityEngine", "ComputeReleaseDistanceThreshold"); constexpr std::size_t maxSampleCount{ 200 }; - constexpr std::size_t maxCandidateCount{ 1'000 }; + constexpr std::size_t maxCandidateCount{ 2'000 }; constexpr float stdDevMultiplier{ 2.F }; using CosineDistance = math::NormalizedCosineDistance; @@ -784,7 +790,7 @@ namespace lms::recommendation LMS_SCOPED_TRACE_DETAILED("AudioSimilarityEngine", "ComputeArtistDistanceThreshold"); constexpr std::size_t maxSampleCount{ 200 }; - constexpr std::size_t maxCandidateCount{ 1'000 }; + constexpr std::size_t maxCandidateCount{ 2'000 }; constexpr float stdDevMultiplier{ 2.F }; using CosineDistance = math::NormalizedCosineDistance;