WIP merge by score details strategy

This commit is contained in:
Louis Dureuil 2023-06-09 08:32:47 +02:00
parent fafe432eb1
commit da138deaf7
No known key found for this signature in database
2 changed files with 78 additions and 2 deletions

View File

@ -1,3 +1,6 @@
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use actix_http::StatusCode;
use actix_web::web::{self, Data};
use actix_web::{HttpRequest, HttpResponse};
@ -9,12 +12,14 @@ use meilisearch_types::deserr::DeserrJsonError;
use meilisearch_types::error::deserr_codes::InvalidMultiSearchMergeStrategy;
use meilisearch_types::error::ResponseError;
use meilisearch_types::keys::actions;
use meilisearch_types::milli::score_details::NotComparable;
use serde::Serialize;
use crate::analytics::{Analytics, MultiSearchAggregator};
use crate::extractors::authentication::policies::ActionPolicy;
use crate::extractors::authentication::{AuthenticationError, GuardedData};
use crate::extractors::sequential_extractor::SeqHandler;
use crate::milli::score_details::ScoreDetails;
use crate::search::{
add_search_rules, perform_search, SearchHit, SearchQueryWithIndex, SearchResultWithIndex,
};
@ -135,7 +140,7 @@ pub async fn multi_search_with_post(
let aggregate_hits = match merge_strategy {
MergeStrategy::None => None,
MergeStrategy::ByScoreDetails => todo!(),
MergeStrategy::ByScoreDetails => Some(merge_by_score_details(&search_results, max_hits)),
MergeStrategy::ByNormalizedScore => {
Some(merge_by_normalized_score(&search_results, max_hits))
}
@ -144,6 +149,72 @@ pub async fn multi_search_with_post(
Ok(HttpResponse::Ok().json(SearchResults { aggregate_hits, results: search_results }))
}
fn merge_by_score_details(
search_results: &[SearchResultWithIndex],
max_hits: usize,
) -> Vec<SearchHitWithIndex> {
let mut iterators: Vec<_> = search_results
.iter()
.filter_map(|SearchResultWithIndex { index_uid, result }| {
let mut it = result.hits.iter();
let next = it.next()?;
Some((index_uid, it, next))
})
.collect();
let mut hits = Vec::with_capacity(max_hits);
let mut inconsistent_indexes = HashMap::new();
for _ in 0..max_hits {
iterators.sort_by(|(left_uid, _, left_hit), (right_uid, _, right_hit)| {
let error = match ScoreDetails::partial_cmp_iter(
left_hit.ranking_score_raw.iter(),
right_hit.ranking_score_raw.iter(),
) {
Ok(ord) => return ord,
Err(NotComparable(incomparable_index)) => incomparable_index,
};
inconsistent_indexes.entry((left_uid.to_owned(), right_uid.to_owned())).or_insert_with(
|| {
format!(
"Detailed score {:?} is not comparable with {:?}: (left: {:#?}, right: {:#?})",
left_hit.ranking_score_raw.get(error),
right_hit.ranking_score_raw.get(error),
left_hit.ranking_score_raw,
right_hit.ranking_score_raw
)
},
);
std::cmp::Ordering::Less
});
if !inconsistent_indexes.is_empty() {
let mut s = String::new();
for ((left_uid, right_uid), error) in &inconsistent_indexes {
use std::fmt::Write;
writeln!(s, "Indexes {} and {} are inconsistent: {}", left_uid, right_uid, error)
.unwrap();
}
// Replace panic with proper error
panic!("{}", s);
}
let Some((index_uid, it, next)) = iterators.last_mut()
else {
break;
};
let hit = SearchHitWithIndex { index_uid: index_uid.clone(), hit: next.clone() };
if let Some(next_hit) = it.next() {
*next = next_hit;
} else {
iterators.pop();
}
hits.push(hit);
}
hits
}
fn merge_by_normalized_score(
search_results: &[SearchResultWithIndex],
max_hits: usize,
@ -160,7 +231,9 @@ fn merge_by_normalized_score(
let mut hits = Vec::with_capacity(max_hits);
for _ in 0..max_hits {
iterators.sort_by_key(|(_, _, peeked)| peeked.ranking_score.unwrap());
iterators.sort_by_key(|(_, _, hit)| {
ScoreDetails::global_score_linear_scale(hit.ranking_score_raw.iter())
});
let Some((index_uid, it, next)) = iterators.last_mut()
else {

View File

@ -219,6 +219,8 @@ pub struct SearchHit {
pub ranking_score: Option<u64>,
#[serde(rename = "_rankingScoreDetails", skip_serializing_if = "Option::is_none")]
pub ranking_score_details: Option<serde_json::Map<String, serde_json::Value>>,
#[serde(skip)]
pub ranking_score_raw: Vec<ScoreDetails>,
}
#[derive(Serialize, Debug, Clone, PartialEq)]
@ -445,6 +447,7 @@ pub fn perform_search(
matches_position,
ranking_score_details,
ranking_score,
ranking_score_raw: score,
};
documents.push(hit);
}