Skip to content

Commit 15aff72

Browse files
author
Joseph Smith
committed
More silly cleanup
1 parent 298e752 commit 15aff72

1 file changed

Lines changed: 5 additions & 21 deletions

File tree

media-api/app/lib/elasticsearch/HybridResult.scala

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ case class HybridResult(
1111
image: SourceWrapper[Image]
1212
)
1313

14-
// Whether a result was originally returned by the lexical query, the semantic
15-
// query, or both. A shared result tends to rank highly, so this is useful both
16-
// for debugging and for understanding why something appears where it does.
14+
1715
sealed trait ResultSource
1816
object ResultSource {
1917
case object Lexical extends ResultSource
@@ -24,23 +22,17 @@ object ResultSource {
2422
(inLexical, inSemantic) match {
2523
case (true, true) => Both
2624
case (true, false) => Lexical
27-
// A ranked result always comes from at least one side, so the remaining
28-
// case is "semantic only".
29-
case (false, _) => Semantic
25+
case (false, true) => Semantic
26+
case _ => throw new IllegalArgumentException("Result must be in either lexical or semantic")
3027
}
3128
}
3229

33-
// The intermediate scoring detail for a single result: the two normalised
34-
// component scores and the weighted blend of them that we actually rank by.
3530
case class FusedScore(
3631
normedLexicalScore: Double,
3732
normedSemanticScore: Double,
3833
fusedScore: Double
3934
)
4035

41-
// A fully scored, ranked result. Carries the original scores (via `result`),
42-
// where it came from (`source`), the normalised scores and the fused score
43-
// (both via `score`) so the whole ranking decision is inspectable.
4436
case class RankedResult(
4537
result: HybridResult,
4638
source: ResultSource,
@@ -65,15 +57,14 @@ object HybridResult {
6557
// are truncated 256-dim versions of a normalised 1536-dim vector,
6658
// meaning they will not have magnitude 1.
6759
// Note this is true cosine similarity from -1 to 1,
68-
// *not* the ES-normalised score, but when we max-normalise
60+
// *not* the ES-normalised score, but when we normalise
6961
// later it will end up in the range 0-1.
7062
.map(e => VectorUtils.cosineSimilarity(e.image, queryEmbedding))
7163
.getOrElse(CosineSimilarityTheoreticalMin)
7264
HybridResult(hit.id, lexicalScore = hit.score, semanticScore = semanticScore, image = image)
7365
}
7466

75-
// This is the "theoretical min-max" normalisation chosen by
76-
// "An Analysis of Fusion Functions for Hybrid Retrieval"
67+
// This is the "theoretical min-max" normalisation chosen in
7768
// https://arxiv.org/pdf/2210.11934
7869
def normalise(score: Double, max: Double, theoreticalMin: Double): Double =
7970
if (max == theoreticalMin) 0.0
@@ -93,13 +84,6 @@ object HybridResult {
9384
FusedScore(normedLexicalScore, normedSemanticScore, fusedScore)
9485
}
9586

96-
// Combines the lexical and semantic result sets into a single, ranked list.
97-
//
98-
// Each input result already carries both scores (the semantic query is
99-
// rescored to BM25 server-side, and resolveHitAndFillInSemanticScore fills in
100-
// the cosine similarity client-side), so this function only has to: tag each
101-
// result with where it came from, de-duplicate, normalise + fuse the scores,
102-
// then sort and take the top k.
10387
def fuseAndRank(
10488
lexicalResults: List[HybridResult],
10589
semanticResults: List[HybridResult],

0 commit comments

Comments
 (0)