Skip to content

Commit d316266

Browse files
author
Joseph Smith
committed
Minor cleanups
1 parent 516b04b commit d316266

1 file changed

Lines changed: 22 additions & 27 deletions

File tree

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

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -269,40 +269,33 @@ class ElasticSearch(
269269

270270
private case class HybridResult(id: String, lexicalScore: Double, semanticScore: Double, image: SourceWrapper[Image])
271271
private case object HybridResult {
272-
def fromSearchHit(hit: SearchHit, queryEmbedding: List[Double]): Option[HybridResult] = {
273-
val lexicalScore = hit.score
274-
resolveHit(hit) map { image =>
275-
val semanticScore = (for {
276-
embedding <- image.instance.embedding
277-
cohereEmbedV4 <- embedding.cohereEmbedV4
278-
} yield {
272+
def fromSearchHit(hit: SearchHit, queryEmbedding: List[Double]): Option[HybridResult] =
273+
resolveHit(hit).map { image =>
274+
val semanticScore = image.instance.embedding
275+
.flatMap(_.cohereEmbedV4)
279276
// Save some computation by assuming normalised vectors
280277
// TODO: double check this assumption
281-
VectorUtils.dotProduct(cohereEmbedV4.image, queryEmbedding)
282-
}).getOrElse(-1.0)
283-
HybridResult(hit.id, lexicalScore = lexicalScore, semanticScore = semanticScore, image = image)
278+
.map(e => VectorUtils.dotProduct(e.image, queryEmbedding))
279+
.getOrElse(-1.0)
280+
HybridResult(hit.id, lexicalScore = hit.score, semanticScore = semanticScore, image = image)
284281
}
285-
}
286282

287283
def getTopK(results: List[HybridResult], vecWeight: Double, k: Int)(implicit logMarker: LogMarker): List[HybridResult] = {
288-
// Account for the rare case in which KNN doesn't return the true closest vector,
289-
// and that true closest vector happens to be among the lexical-only results.
290-
// Max lexical score could still be pulled from the top of the lexical results,
291-
// but it reads better to do it in a uniform way for both.
292-
val maxLexicalScore = results.maxBy(_.lexicalScore).lexicalScore
293-
val maxSemanticScore = results.maxBy(_.semanticScore).semanticScore
294-
295284
val dedupedResults = results.distinctBy(_.id)
296285
logger.info(logMarker, s"${dedupedResults.length} deduped results")
297286

298-
dedupedResults.sortBy { result =>
299-
val maxNormedSemanticScore = (result.semanticScore + 1) / (maxSemanticScore + 1)
300-
val maxNormedLexicalScore = result.lexicalScore / maxLexicalScore
287+
// Account for the rare case in which KNN doesn't return the true closest vector,
288+
// and that true closest vector happens to be among the lexical-only results.
289+
val maxLexicalScore = dedupedResults.maxBy(_.lexicalScore).lexicalScore
290+
val maxSemanticScore = dedupedResults.maxBy(_.semanticScore).semanticScore
301291

302-
// Negative to get a descending sort order
303-
// Only other way to do this is to .reverse afterwards, apparently
304-
-((vecWeight * maxNormedSemanticScore) + ((1 - vecWeight) * maxNormedLexicalScore))
305-
}.take(k)
292+
def combinedScore(result: HybridResult): Double = {
293+
val normedSemanticScore = (result.semanticScore + 1) / (maxSemanticScore + 1)
294+
val normedLexicalScore = result.lexicalScore / maxLexicalScore
295+
(vecWeight * normedSemanticScore) + ((1 - vecWeight) * normedLexicalScore)
296+
}
297+
298+
dedupedResults.sortBy(combinedScore)(Ordering[Double].reverse).take(k)
306299
}
307300
}
308301

@@ -315,9 +308,11 @@ class ElasticSearch(
315308
vecWeight: Double,
316309
filterOpt: Option[Query]
317310
)(implicit ex: ExecutionContext, logMarker: LogMarker): Future[SearchResults] = {
311+
val lexicalQuery = createMultiMatchQuery(query, operator = Or)
312+
318313
val lexicalSearchRequest = ElasticDsl
319314
.search(imagesCurrentAlias)
320-
.query(createMultiMatchQuery(query, operator = Or))
315+
.query(lexicalQuery)
321316
.size(k)
322317

323318
val semanticSearchRequest = ElasticDsl
@@ -327,7 +322,7 @@ class ElasticSearch(
327322
.k(k)
328323
.numCandidates(numCandidates)
329324
)
330-
.rescore(Rescore(createMultiMatchQuery(query, operator = Or))
325+
.rescore(Rescore(lexicalQuery)
331326
.window(k)
332327
// We want to replace the knn score with the BM25 score,
333328
// because we can calculate cosine similarity clientside,

0 commit comments

Comments
 (0)