Compare commits

...

1 Commits

Author SHA1 Message Date
ManyTheFish
ac76f243c7 WIP 2025-12-22 14:08:42 +01:00
51 changed files with 621 additions and 227 deletions

View File

@@ -172,7 +172,8 @@ pub fn run_benches(c: &mut criterion::Criterion, confs: &[Conf]) {
|b, &query| { |b, &query| {
b.iter(|| { b.iter(|| {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = index.search(&rtxn); let progress = Progress::default();
let mut search = index.search(&rtxn, &progress);
search search
.query(query) .query(query)
.terms_matching_strategy(TermsMatchingStrategy::default()); .terms_matching_strategy(TermsMatchingStrategy::default());

View File

@@ -153,7 +153,8 @@ fn main() {
.unwrap(); .unwrap();
// after executing a batch we check if the database is corrupted // after executing a batch we check if the database is corrupted
let res = index.search(&wtxn).execute().unwrap(); let progress = Progress::default();
let res = index.search(&wtxn, &progress).execute().unwrap();
index.documents(&wtxn, res.documents_ids).unwrap(); index.documents(&wtxn, res.documents_ids).unwrap();
progression.fetch_add(1, Ordering::Relaxed); progression.fetch_add(1, Ordering::Relaxed);
} }

View File

@@ -1,7 +1,8 @@
use std::time::Duration; use std::time::Duration;
use meilisearch_types::error::{Code, ErrorCode, ResponseError}; use meilisearch_types::error::{Code, ErrorCode, ResponseError};
use meilisearch_types::milli::TimeBudget; use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::{SearchStep, TimeBudget};
use rand::Rng; use rand::Rng;
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -346,9 +347,11 @@ impl PersonalizationService {
personalize: &Personalize, personalize: &Personalize,
query: Option<&str>, query: Option<&str>,
time_budget: TimeBudget, time_budget: TimeBudget,
progress: &Progress,
) -> Result<SearchResult, ResponseError> { ) -> Result<SearchResult, ResponseError> {
match self { match self {
Self::Cohere(cohere_service) => { Self::Cohere(cohere_service) => {
let _ = progress.update_progress_scoped(SearchStep::ApplyingPersonalization);
cohere_service cohere_service
.rerank_search_results(search_result, personalize, query, time_budget) .rerank_search_results(search_result, personalize, query, time_budget)
.await .await

View File

@@ -30,7 +30,11 @@ use meilisearch_types::features::{
use meilisearch_types::heed::RoTxn; use meilisearch_types::heed::RoTxn;
use meilisearch_types::keys::actions; use meilisearch_types::keys::actions;
use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::index::ChatConfig;
use meilisearch_types::milli::{all_obkv_to_json, obkv_to_json, OrderBy, PatternMatch, TimeBudget}; use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::{
all_obkv_to_json, obkv_to_json, OrderBy, PatternMatch, TimeBudget,
TotalProcessingTimeStep,
};
use meilisearch_types::{Document, Index}; use meilisearch_types::{Document, Index};
use serde::Deserialize; use serde::Deserialize;
use serde_json::json; use serde_json::json;
@@ -262,6 +266,7 @@ async fn process_search_request(
filter: Option<String>, filter: Option<String>,
) -> Result<(Index, Vec<Document>, String), ResponseError> { ) -> Result<(Index, Vec<Document>, String), ResponseError> {
let index = index_scheduler.index(&index_uid)?; let index = index_scheduler.index(&index_uid)?;
let progress = Progress::default();
let rtxn = index.static_read_txn()?; let rtxn = index.static_read_txn()?;
let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?; let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?;
let mut query = SearchQuery { let mut query = SearchQuery {
@@ -285,7 +290,9 @@ async fn process_search_request(
let search_kind = let search_kind =
search_kind(&query, index_scheduler.get_ref(), index_uid.to_string(), &index)?; search_kind(&query, index_scheduler.get_ref(), index_uid.to_string(), &index)?;
progress.update_progress(TotalProcessingTimeStep::WaitingForPermit);
let permit = search_queue.try_get_search_permit().await?; let permit = search_queue.try_get_search_permit().await?;
progress.update_progress(TotalProcessingTimeStep::Searching);
let features = index_scheduler.features(); let features = index_scheduler.features();
let index_cloned = index.clone(); let index_cloned = index.clone();
let output = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> { let output = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> {
@@ -297,8 +304,15 @@ async fn process_search_request(
None => TimeBudget::default(), None => TimeBudget::default(),
}; };
let (search, _is_finite_pagination, _max_total_hits, _offset) = let (search, _is_finite_pagination, _max_total_hits, _offset) = prepare_search(
prepare_search(&index_cloned, &rtxn, &query, &search_kind, time_budget, features)?; &index_cloned,
&rtxn,
&query,
&search_kind,
time_budget,
features,
&progress,
)?;
match search_from_kind(index_uid, search_kind, search) { match search_from_kind(index_uid, search_kind, search) {
Ok((search_results, _)) => Ok((rtxn, Ok(search_results))), Ok((search_results, _)) => Ok((rtxn, Ok(search_results))),

View File

@@ -8,7 +8,8 @@ use meilisearch_types::error::deserr_codes::*;
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use meilisearch_types::index_uid::IndexUid; use meilisearch_types::index_uid::IndexUid;
use meilisearch_types::locales::Locale; use meilisearch_types::locales::Locale;
use meilisearch_types::milli; use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::{self, TotalProcessingTimeStep};
use meilisearch_types::serde_cs::vec::CS; use meilisearch_types::serde_cs::vec::CS;
use serde_json::Value; use serde_json::Value;
use tracing::debug; use tracing::debug;
@@ -336,6 +337,10 @@ pub async fn search_with_url_query(
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let request_uid = Uuid::now_v7(); let request_uid = Uuid::now_v7();
debug!(request_uid = ?request_uid, parameters = ?params, "Search get"); debug!(request_uid = ?request_uid, parameters = ?params, "Search get");
let progress = Progress::default();
progress.update_progress(TotalProcessingTimeStep::WaitingForPermit);
let permit = search_queue.try_get_search_permit().await?;
progress.update_progress(TotalProcessingTimeStep::Searching);
let index_uid = IndexUid::try_from(index_uid.into_inner())?; let index_uid = IndexUid::try_from(index_uid.into_inner())?;
let mut query: SearchQuery = params.into_inner().try_into()?; let mut query: SearchQuery = params.into_inner().try_into()?;
@@ -359,9 +364,9 @@ pub async fn search_with_url_query(
// Save the query string for personalization if requested // Save the query string for personalization if requested
let personalize_query = personalize.is_some().then(|| query.q.clone()).flatten(); let personalize_query = personalize.is_some().then(|| query.q.clone()).flatten();
let permit = search_queue.try_get_search_permit().await?;
let include_metadata = parse_include_metadata_header(&req); let include_metadata = parse_include_metadata_header(&req);
let progress_clone = progress.clone();
let search_result = tokio::task::spawn_blocking(move || { let search_result = tokio::task::spawn_blocking(move || {
perform_search( perform_search(
SearchParams { SearchParams {
@@ -374,15 +379,21 @@ pub async fn search_with_url_query(
include_metadata, include_metadata,
}, },
&index, &index,
&progress_clone,
) )
}) })
.await; .await;
permit.drop().await; permit.drop().await;
let search_result = search_result?; let search_result = search_result?;
let analytics_step =
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
if let Ok((search_result, _)) = search_result.as_ref() { if let Ok((search_result, _)) = search_result.as_ref() {
aggregate.succeed(search_result); aggregate.succeed(search_result);
} }
analytics.publish(aggregate, &req); analytics.publish(aggregate, &req);
// early finish progress step
drop(analytics_step);
let (mut search_result, time_budget) = search_result?; let (mut search_result, time_budget) = search_result?;
@@ -394,11 +405,12 @@ pub async fn search_with_url_query(
personalize, personalize,
personalize_query.as_deref(), personalize_query.as_deref(),
time_budget, time_budget,
&progress,
) )
.await?; .await?;
} }
debug!(request_uid = ?request_uid, returns = ?search_result, "Search get"); debug!(request_uid = ?request_uid, returns = ?search_result, progress = ?progress.accumulated_durations(), "Search get");
Ok(HttpResponse::Ok().json(search_result)) Ok(HttpResponse::Ok().json(search_result))
} }
@@ -470,6 +482,11 @@ pub async fn search_with_post(
let index_uid = IndexUid::try_from(index_uid.into_inner())?; let index_uid = IndexUid::try_from(index_uid.into_inner())?;
let request_uid = Uuid::now_v7(); let request_uid = Uuid::now_v7();
let progress = Progress::default();
progress.update_progress(TotalProcessingTimeStep::WaitingForPermit);
let permit = search_queue.try_get_search_permit().await?;
progress.update_progress(TotalProcessingTimeStep::Searching);
let mut query = params.into_inner(); let mut query = params.into_inner();
debug!(request_uid = ?request_uid, parameters = ?query, "Search post"); debug!(request_uid = ?request_uid, parameters = ?query, "Search post");
@@ -494,7 +511,7 @@ pub async fn search_with_post(
// Save the query string for personalization if requested // Save the query string for personalization if requested
let personalize_query = personalize.is_some().then(|| query.q.clone()).flatten(); let personalize_query = personalize.is_some().then(|| query.q.clone()).flatten();
let permit = search_queue.try_get_search_permit().await?; let progress_clone = progress.clone();
let search_result = tokio::task::spawn_blocking(move || { let search_result = tokio::task::spawn_blocking(move || {
perform_search( perform_search(
SearchParams { SearchParams {
@@ -507,11 +524,14 @@ pub async fn search_with_post(
include_metadata, include_metadata,
}, },
&index, &index,
&progress_clone,
) )
}) })
.await; .await;
permit.drop().await; permit.drop().await;
let search_result = search_result?; let search_result = search_result?;
let analytics_step =
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
if let Ok((ref search_result, _)) = search_result { if let Ok((ref search_result, _)) = search_result {
aggregate.succeed(search_result); aggregate.succeed(search_result);
if search_result.degraded { if search_result.degraded {
@@ -519,6 +539,8 @@ pub async fn search_with_post(
} }
} }
analytics.publish(aggregate, &req); analytics.publish(aggregate, &req);
// early finish progress step
drop(analytics_step);
let (mut search_result, time_budget) = search_result?; let (mut search_result, time_budget) = search_result?;
@@ -530,11 +552,12 @@ pub async fn search_with_post(
personalize, personalize,
personalize_query.as_deref(), personalize_query.as_deref(),
time_budget, time_budget,
&progress,
) )
.await?; .await?;
} }
debug!(request_uid = ?request_uid, returns = ?search_result, "Search post"); debug!(request_uid = ?request_uid, returns = ?search_result, progress = ?progress.accumulated_durations(), "Search post");
Ok(HttpResponse::Ok().json(search_result)) Ok(HttpResponse::Ok().json(search_result))
} }

View File

@@ -8,6 +8,8 @@ use meilisearch_types::error::deserr_codes::*;
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use meilisearch_types::index_uid::IndexUid; use meilisearch_types::index_uid::IndexUid;
use meilisearch_types::keys::actions; use meilisearch_types::keys::actions;
use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::TotalProcessingTimeStep;
use meilisearch_types::serde_cs::vec::CS; use meilisearch_types::serde_cs::vec::CS;
use serde_json::Value; use serde_json::Value;
use tracing::debug; use tracing::debug;
@@ -217,7 +219,7 @@ async fn similar(
mut query: SimilarQuery, mut query: SimilarQuery,
) -> Result<SimilarResult, ResponseError> { ) -> Result<SimilarResult, ResponseError> {
let retrieve_vectors = RetrieveVectors::new(query.retrieve_vectors); let retrieve_vectors = RetrieveVectors::new(query.retrieve_vectors);
let progress = Progress::default();
// Tenant token search_rules. // Tenant token search_rules.
if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) { if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) {
add_search_rules(&mut query.filter, search_rules); add_search_rules(&mut query.filter, search_rules);
@@ -234,7 +236,10 @@ async fn similar(
Route::Similar, Route::Similar,
)?; )?;
tokio::task::spawn_blocking(move || { let progress_clone = progress.clone();
let result = tokio::task::spawn_blocking(move || {
let _step = progress_clone.update_progress_scoped(TotalProcessingTimeStep::Searching);
perform_similar( perform_similar(
&index, &index,
query, query,
@@ -243,9 +248,14 @@ async fn similar(
quantized, quantized,
retrieve_vectors, retrieve_vectors,
index_scheduler.features(), index_scheduler.features(),
&progress_clone,
) )
}) })
.await? .await;
debug!(progress = ?progress.accumulated_durations(), "Similar");
result?
} }
#[derive(Debug, deserr::Deserr, IntoParams)] #[derive(Debug, deserr::Deserr, IntoParams)]

View File

@@ -6,6 +6,8 @@ use index_scheduler::IndexScheduler;
use meilisearch_types::deserr::DeserrJsonError; use meilisearch_types::deserr::DeserrJsonError;
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use meilisearch_types::keys::actions; use meilisearch_types::keys::actions;
use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::TotalProcessingTimeStep;
use serde::Serialize; use serde::Serialize;
use tracing::debug; use tracing::debug;
use utoipa::{OpenApi, ToSchema}; use utoipa::{OpenApi, ToSchema};
@@ -153,7 +155,10 @@ pub async fn multi_search_with_post(
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
// Since we don't want to process half of the search requests and then get a permit refused // Since we don't want to process half of the search requests and then get a permit refused
// we're going to get one permit for the whole duration of the multi-search request. // we're going to get one permit for the whole duration of the multi-search request.
let progress = Progress::default();
progress.update_progress(TotalProcessingTimeStep::WaitingForPermit);
let permit = search_queue.try_get_search_permit().await?; let permit = search_queue.try_get_search_permit().await?;
progress.update_progress(TotalProcessingTimeStep::Searching);
let request_uid = Uuid::now_v7(); let request_uid = Uuid::now_v7();
let federated_search = params.into_inner(); let federated_search = params.into_inner();
@@ -213,6 +218,7 @@ pub async fn multi_search_with_post(
is_proxy, is_proxy,
request_uid, request_uid,
include_metadata, include_metadata,
&progress,
) )
.await; .await;
permit.drop().await; permit.drop().await;
@@ -288,6 +294,7 @@ pub async fn multi_search_with_post(
.with_index(query_index)?; .with_index(query_index)?;
let retrieve_vector = RetrieveVectors::new(query.retrieve_vectors); let retrieve_vector = RetrieveVectors::new(query.retrieve_vectors);
let progress_clone = progress.clone();
let (mut search_result, time_budget) = tokio::task::spawn_blocking(move || { let (mut search_result, time_budget) = tokio::task::spawn_blocking(move || {
perform_search( perform_search(
SearchParams { SearchParams {
@@ -300,6 +307,7 @@ pub async fn multi_search_with_post(
include_metadata, include_metadata,
}, },
&index, &index,
&progress_clone,
) )
}) })
.await .await
@@ -314,6 +322,7 @@ pub async fn multi_search_with_post(
personalize, personalize,
personalize_query.as_deref(), personalize_query.as_deref(),
time_budget, time_budget,
&progress,
) )
.await .await
.with_index(query_index)?; .with_index(query_index)?;
@@ -324,15 +333,19 @@ pub async fn multi_search_with_post(
result: search_result, result: search_result,
}); });
} }
Ok(search_results) Ok(search_results)
} }
.await; .await;
permit.drop().await; permit.drop().await;
let analytics_step =
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
if search_results.is_ok() { if search_results.is_ok() {
multi_aggregate.succeed(); multi_aggregate.succeed();
} }
analytics.publish(multi_aggregate, &req); analytics.publish(multi_aggregate, &req);
drop(analytics_step);
let search_results = search_results.map_err(|(mut err, query_index)| { let search_results = search_results.map_err(|(mut err, query_index)| {
// Add the query index that failed as context for the error message. // Add the query index that failed as context for the error message.
@@ -345,6 +358,7 @@ pub async fn multi_search_with_post(
debug!( debug!(
request_uid = ?request_uid, request_uid = ?request_uid,
returns = ?search_results, returns = ?search_results,
progress = ?progress.accumulated_durations(),
"Multi-search" "Multi-search"
); );

View File

@@ -11,9 +11,13 @@ use index_scheduler::{IndexScheduler, RoFeatures};
use itertools::Itertools; use itertools::Itertools;
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use meilisearch_types::milli::order_by_map::OrderByMap; use meilisearch_types::milli::order_by_map::OrderByMap;
use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::score_details::{ScoreDetails, WeightedScoreValue}; use meilisearch_types::milli::score_details::{ScoreDetails, WeightedScoreValue};
use meilisearch_types::milli::vector::Embedding; use meilisearch_types::milli::vector::Embedding;
use meilisearch_types::milli::{self, DocumentId, OrderBy, TimeBudget, DEFAULT_VALUES_PER_FACET}; use meilisearch_types::milli::{
self, DocumentId, FederatingResultsStep, OrderBy, SearchStep, TimeBudget,
DEFAULT_VALUES_PER_FACET,
};
use meilisearch_types::network::{Network, Remote}; use meilisearch_types::network::{Network, Remote};
use roaring::RoaringBitmap; use roaring::RoaringBitmap;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
@@ -43,6 +47,7 @@ pub async fn perform_federated_search(
is_proxy: bool, is_proxy: bool,
request_uid: Uuid, request_uid: Uuid,
include_metadata: bool, include_metadata: bool,
progress: &Progress,
) -> Result<FederatedSearchResult, ResponseError> { ) -> Result<FederatedSearchResult, ResponseError> {
if is_proxy { if is_proxy {
features.check_network("Performing a remote federated search")?; features.check_network("Performing a remote federated search")?;
@@ -111,7 +116,7 @@ pub async fn perform_federated_search(
for (index_uid, queries) in partitioned_queries.local_queries_by_index { for (index_uid, queries) in partitioned_queries.local_queries_by_index {
// note: this is the only place we open `index_uid` // note: this is the only place we open `index_uid`
search_by_index.execute(index_uid, queries, &params)?; search_by_index.execute(index_uid, queries, &params, progress)?;
} }
// bonus step, make sure to return an error if an index wants a non-faceted field, even if no query actually uses that index. // bonus step, make sure to return an error if an index wants a non-faceted field, even if no query actually uses that index.
@@ -126,6 +131,8 @@ pub async fn perform_federated_search(
facet_order, facet_order,
} = search_by_index; } = search_by_index;
progress.update_progress(SearchStep::FederatingResults);
progress.update_progress(FederatingResultsStep::WaitingForRemoteResults);
let before_waiting_remote_results = std::time::Instant::now(); let before_waiting_remote_results = std::time::Instant::now();
// 2.3. Wait for proxy search requests to complete // 2.3. Wait for proxy search requests to complete
@@ -134,7 +141,7 @@ pub async fn perform_federated_search(
let after_waiting_remote_results = std::time::Instant::now(); let after_waiting_remote_results = std::time::Instant::now();
// 3. merge hits and metadata across indexes and hosts // 3. merge hits and metadata across indexes and hosts
progress.update_progress(FederatingResultsStep::MergingResults);
// 3.1. Build metadata in the same order as the original queries // 3.1. Build metadata in the same order as the original queries
let query_metadata = precomputed_query_metadata.map(|precomputed_query_metadata| { let query_metadata = precomputed_query_metadata.map(|precomputed_query_metadata| {
// If a remote is present, set the local remote name // If a remote is present, set the local remote name
@@ -187,6 +194,7 @@ pub async fn perform_federated_search(
}; };
// 3.5. merge facets // 3.5. merge facets
progress.update_progress(FederatingResultsStep::MergingFacets);
let (facet_distribution, facet_stats, facets_by_index) = let (facet_distribution, facet_stats, facets_by_index) =
facet_order.merge(federation.merge_facets, remote_results, facets); facet_order.merge(federation.merge_facets, remote_results, facets);
@@ -831,6 +839,7 @@ impl SearchByIndex {
index_uid: String, index_uid: String,
queries: Vec<QueryByIndex>, queries: Vec<QueryByIndex>,
params: &SearchByIndexParams<'_>, params: &SearchByIndexParams<'_>,
progress: &Progress,
) -> Result<(), ResponseError> { ) -> Result<(), ResponseError> {
let first_query_index = queries.first().map(|query| query.query_index); let first_query_index = queries.first().map(|query| query.query_index);
let index = match params.index_scheduler.index(&index_uid) { let index = match params.index_scheduler.index(&index_uid) {
@@ -957,6 +966,7 @@ impl SearchByIndex {
// clones of `TimeBudget` share the budget rather than restart it // clones of `TimeBudget` share the budget rather than restart it
time_budget.clone(), time_budget.clone(),
params.features, params.features,
progress,
)?; )?;
search.scoring_strategy(milli::score_details::ScoringStrategy::Detailed); search.scoring_strategy(milli::score_details::ScoringStrategy::Detailed);
@@ -1044,7 +1054,7 @@ impl SearchByIndex {
hit_maker, hit_maker,
query_index, query_index,
}| { }| {
let mut hit = hit_maker.make_hit(docid, &score)?; let mut hit = hit_maker.make_hit(docid, &score, progress)?;
let weighted_score = ScoreDetails::global_score(score.iter()) * (*weight); let weighted_score = ScoreDetails::global_score(score.iter()) * (*weight);
let mut _federation = serde_json::json!( let mut _federation = serde_json::json!(

View File

@@ -17,11 +17,13 @@ use meilisearch_types::heed::RoTxn;
use meilisearch_types::index_uid::IndexUid; use meilisearch_types::index_uid::IndexUid;
use meilisearch_types::locales::Locale; use meilisearch_types::locales::Locale;
use meilisearch_types::milli::index::{self, EmbeddingsWithMetadata, SearchParameters}; use meilisearch_types::milli::index::{self, EmbeddingsWithMetadata, SearchParameters};
use meilisearch_types::milli::progress::Progress;
use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy}; use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy};
use meilisearch_types::milli::vector::parsed_vectors::ExplicitVectors; use meilisearch_types::milli::vector::parsed_vectors::ExplicitVectors;
use meilisearch_types::milli::vector::Embedder; use meilisearch_types::milli::vector::Embedder;
use meilisearch_types::milli::{ use meilisearch_types::milli::{
FacetValueHit, InternalError, OrderBy, PatternMatch, SearchForFacetValues, TimeBudget, FacetValueHit, InternalError, OrderBy, PatternMatch, SearchForFacetValues, SearchStep,
TimeBudget,
}; };
use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS; use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS;
use meilisearch_types::{milli, Document}; use meilisearch_types::{milli, Document};
@@ -1024,11 +1026,13 @@ pub fn prepare_search<'t>(
search_kind: &SearchKind, search_kind: &SearchKind,
time_budget: TimeBudget, time_budget: TimeBudget,
features: RoFeatures, features: RoFeatures,
progress: &'t Progress,
) -> Result<(milli::Search<'t>, bool, usize, usize), ResponseError> { ) -> Result<(milli::Search<'t>, bool, usize, usize), ResponseError> {
let _step = progress.update_progress_scoped(SearchStep::PreparingSearch);
if query.media.is_some() { if query.media.is_some() {
features.check_multimodal("passing `media` in a search query")?; features.check_multimodal("passing `media` in a search query")?;
} }
let mut search = index.search(rtxn); let mut search = index.search(rtxn, progress);
search.time_budget(time_budget); search.time_budget(time_budget);
if let Some(ranking_score_threshold) = query.ranking_score_threshold { if let Some(ranking_score_threshold) = query.ranking_score_threshold {
search.ranking_score_threshold(ranking_score_threshold.0); search.ranking_score_threshold(ranking_score_threshold.0);
@@ -1048,6 +1052,7 @@ pub fn prepare_search<'t>(
let vector = match query.vector.clone() { let vector = match query.vector.clone() {
Some(vector) => vector, Some(vector) => vector,
None => { None => {
let _ = progress.update_progress_scoped(SearchStep::EmbeddingQuery);
let span = tracing::trace_span!(target: "search::vector", "embed_one"); let span = tracing::trace_span!(target: "search::vector", "embed_one");
let _entered = span.enter(); let _entered = span.enter();
@@ -1061,6 +1066,7 @@ pub fn prepare_search<'t>(
(q, media) => milli::vector::SearchQuery::Media { q, media }, (q, media) => milli::vector::SearchQuery::Media { q, media },
}; };
embedder embedder
.embed_search(search_query, Some(deadline)) .embed_search(search_query, Some(deadline))
.map_err(milli::vector::Error::from) .map_err(milli::vector::Error::from)
@@ -1173,6 +1179,7 @@ pub struct SearchParams {
pub fn perform_search( pub fn perform_search(
params: SearchParams, params: SearchParams,
index: &Index, index: &Index,
progress: &Progress,
) -> Result<(SearchResult, TimeBudget), ResponseError> { ) -> Result<(SearchResult, TimeBudget), ResponseError> {
let SearchParams { let SearchParams {
index_uid, index_uid,
@@ -1191,8 +1198,15 @@ pub fn perform_search(
None => TimeBudget::default(), None => TimeBudget::default(),
}; };
let (search, is_finite_pagination, max_total_hits, offset) = let (search, is_finite_pagination, max_total_hits, offset) = prepare_search(
prepare_search(index, &rtxn, &query, &search_kind, time_budget.clone(), features)?; index,
&rtxn,
&query,
&search_kind,
time_budget.clone(),
features,
progress,
)?;
let ( let (
milli::SearchResult { milli::SearchResult {
@@ -1253,6 +1267,7 @@ pub fn perform_search(
personalize: _, personalize: _,
} = query; } = query;
progress.update_progress(SearchStep::FormattingResults);
let format = AttributesFormat { let format = AttributesFormat {
attributes_to_retrieve, attributes_to_retrieve,
retrieve_vectors, retrieve_vectors,
@@ -1275,6 +1290,7 @@ pub fn perform_search(
format, format,
matching_words, matching_words,
documents_ids.iter().copied().zip(document_scores.iter()), documents_ids.iter().copied().zip(document_scores.iter()),
progress,
)?; )?;
let number_of_hits = min(candidates.len() as usize, max_total_hits); let number_of_hits = min(candidates.len() as usize, max_total_hits);
@@ -1297,11 +1313,13 @@ pub fn perform_search(
let (facet_distribution, facet_stats) = facets let (facet_distribution, facet_stats) = facets
.map(move |facets| { .map(move |facets| {
let _ = progress.update_progress_scoped(SearchStep::ComputingFacetDistribution);
compute_facet_distribution_stats(&facets, index, &rtxn, candidates, Route::Search) compute_facet_distribution_stats(&facets, index, &rtxn, candidates, Route::Search)
}) })
.transpose()? .transpose()?
.map(|ComputedFacets { distribution, stats }| (distribution, stats)) .map(|ComputedFacets { distribution, stats }| (distribution, stats))
.unzip(); .unzip();
let result = SearchResult { let result = SearchResult {
hits: documents, hits: documents,
hits_info, hits_info,
@@ -1316,6 +1334,7 @@ pub fn perform_search(
request_uid: Some(request_uid), request_uid: Some(request_uid),
metadata, metadata,
}; };
Ok((result, time_budget)) Ok((result, time_budget))
} }
@@ -1580,7 +1599,13 @@ impl<'a> HitMaker<'a> {
}) })
} }
pub fn make_hit(&self, id: u32, score: &[ScoreDetails]) -> milli::Result<SearchHit> { pub fn make_hit(
&self,
id: u32,
score: &[ScoreDetails],
progress: &Progress,
) -> milli::Result<SearchHit> {
let _step = progress.update_progress_scoped(SearchStep::FormattingResults);
let (_, obkv) = let (_, obkv) =
self.index.iter_documents(self.rtxn, std::iter::once(id))?.next().unwrap()?; self.index.iter_documents(self.rtxn, std::iter::once(id))?.next().unwrap()?;
@@ -1669,6 +1694,7 @@ fn make_hits<'a>(
format: AttributesFormat, format: AttributesFormat,
matching_words: milli::MatchingWords, matching_words: milli::MatchingWords,
documents_ids_scores: impl Iterator<Item = (u32, &'a Vec<ScoreDetails>)> + 'a, documents_ids_scores: impl Iterator<Item = (u32, &'a Vec<ScoreDetails>)> + 'a,
progress: &Progress,
) -> milli::Result<Vec<SearchHit>> { ) -> milli::Result<Vec<SearchHit>> {
let mut documents = Vec::new(); let mut documents = Vec::new();
@@ -1686,7 +1712,7 @@ fn make_hits<'a>(
let hit_maker = HitMaker::new(index, rtxn, format, formatter_builder)?; let hit_maker = HitMaker::new(index, rtxn, format, formatter_builder)?;
for (id, score) in documents_ids_scores { for (id, score) in documents_ids_scores {
documents.push(hit_maker.make_hit(id, score)?); documents.push(hit_maker.make_hit(id, score, progress)?);
} }
Ok(documents) Ok(documents)
} }
@@ -1701,6 +1727,7 @@ pub fn perform_facet_search(
locales: Option<Vec<Language>>, locales: Option<Vec<Language>>,
) -> Result<FacetSearchResult, ResponseError> { ) -> Result<FacetSearchResult, ResponseError> {
let before_search = Instant::now(); let before_search = Instant::now();
let progress = Progress::default();
let rtxn = index.read_txn()?; let rtxn = index.read_txn()?;
let time_budget = match index.search_cutoff(&rtxn)? { let time_budget = match index.search_cutoff(&rtxn)? {
Some(cutoff) => TimeBudget::new(Duration::from_millis(cutoff)), Some(cutoff) => TimeBudget::new(Duration::from_millis(cutoff)),
@@ -1729,8 +1756,15 @@ pub fn perform_facet_search(
.collect() .collect()
}); });
let (search, _, _, _) = let (search, _, _, _) = prepare_search(
prepare_search(index, &rtxn, &search_query, &search_kind, time_budget, features)?; index,
&rtxn,
&search_query,
&search_kind,
time_budget,
features,
&progress,
)?;
let mut facet_search = SearchForFacetValues::new( let mut facet_search = SearchForFacetValues::new(
facet_name, facet_name,
search, search,
@@ -1762,6 +1796,7 @@ pub fn perform_similar(
quantized: bool, quantized: bool,
retrieve_vectors: RetrieveVectors, retrieve_vectors: RetrieveVectors,
features: RoFeatures, features: RoFeatures,
progress: &Progress,
) -> Result<SimilarResult, ResponseError> { ) -> Result<SimilarResult, ResponseError> {
let before_search = Instant::now(); let before_search = Instant::now();
let rtxn = index.read_txn()?; let rtxn = index.read_txn()?;
@@ -1851,6 +1886,7 @@ pub fn perform_similar(
format, format,
Default::default(), Default::default(),
documents_ids.iter().copied().zip(document_scores.iter()), documents_ids.iter().copied().zip(document_scores.iter()),
progress,
)?; )?;
let max_total_hits = index let max_total_hits = index

View File

@@ -28,6 +28,7 @@ use crate::heed_codec::facet::{
use crate::heed_codec::version::VersionCodec; use crate::heed_codec::version::VersionCodec;
use crate::heed_codec::{BEU16StrCodec, FstSetCodec, StrBEU16Codec, StrRefCodec}; use crate::heed_codec::{BEU16StrCodec, FstSetCodec, StrBEU16Codec, StrRefCodec};
use crate::order_by_map::OrderByMap; use crate::order_by_map::OrderByMap;
use crate::progress::Progress;
use crate::prompt::PromptData; use crate::prompt::PromptData;
use crate::proximity::ProximityPrecision; use crate::proximity::ProximityPrecision;
use crate::update::new::StdResult; use crate::update::new::StdResult;
@@ -599,6 +600,13 @@ impl Index {
/// Returns the fields ids map which associate the documents keys with an internal field id /// Returns the fields ids map which associate the documents keys with an internal field id
/// (i.e. `u8`), this field id is used to identify fields in the obkv documents. /// (i.e. `u8`), this field id is used to identify fields in the obkv documents.
pub fn fields_ids_map(&self, rtxn: &RoTxn<'_>) -> heed::Result<FieldsIdsMap> { pub fn fields_ids_map(&self, rtxn: &RoTxn<'_>) -> heed::Result<FieldsIdsMap> {
let map = self.fields_ids_map_with_metadata(rtxn).unwrap();
eprintln!(
"fields_ids_map: {:?}",
map.iter_id_metadata()
.map(|(id, metadata)| (id, map.name(id).unwrap(), metadata))
.collect::<Vec<_>>()
);
Ok(self Ok(self
.main .main
.remap_types::<Str, SerdeJson<FieldsIdsMap>>() .remap_types::<Str, SerdeJson<FieldsIdsMap>>()
@@ -611,7 +619,10 @@ impl Index {
/// This structure is not yet stored in the index, and is generated on the fly. /// This structure is not yet stored in the index, and is generated on the fly.
pub fn fields_ids_map_with_metadata(&self, rtxn: &RoTxn<'_>) -> Result<FieldIdMapWithMetadata> { pub fn fields_ids_map_with_metadata(&self, rtxn: &RoTxn<'_>) -> Result<FieldIdMapWithMetadata> {
Ok(FieldIdMapWithMetadata::new( Ok(FieldIdMapWithMetadata::new(
self.fields_ids_map(rtxn)?, self.main
.remap_types::<Str, SerdeJson<FieldsIdsMap>>()
.get(rtxn, main_key::FIELDS_IDS_MAP_KEY)?
.unwrap_or_default(),
MetadataBuilder::from_index(self, rtxn)?, MetadataBuilder::from_index(self, rtxn)?,
)) ))
} }
@@ -1477,8 +1488,8 @@ impl Index {
FacetDistribution::new(rtxn, self) FacetDistribution::new(rtxn, self)
} }
pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>) -> Search<'a> { pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>, progress: &'a Progress) -> Search<'a> {
Search::new(rtxn, self) Search::new(rtxn, self, progress)
} }
/// Returns the index creation time. /// Returns the index creation time.

View File

@@ -81,6 +81,7 @@ pub use self::index::Index;
pub use self::localized_attributes_rules::LocalizedAttributesRule; pub use self::localized_attributes_rules::LocalizedAttributesRule;
pub use self::search::facet::{FacetValueHit, SearchForFacetValues}; pub use self::search::facet::{FacetValueHit, SearchForFacetValues};
pub use self::search::similar::Similar; pub use self::search::similar::Similar;
pub use self::search::steps::{FederatingResultsStep, SearchStep, TotalProcessingTimeStep};
pub use self::search::{ pub use self::search::{
FacetDistribution, Filter, FormatOptions, MatchBounds, MatcherBuilder, MatchingWords, OrderBy, FacetDistribution, Filter, FormatOptions, MatchBounds, MatcherBuilder, MatchingWords, OrderBy,
Search, SearchResult, SemanticSearch, TermsMatchingStrategy, DEFAULT_VALUES_PER_FACET, Search, SearchResult, SemanticSearch, TermsMatchingStrategy, DEFAULT_VALUES_PER_FACET,

View File

@@ -64,6 +64,30 @@ impl Progress {
steps.push((step_type, Box::new(sub_progress), now)); steps.push((step_type, Box::new(sub_progress), now));
} }
/// End a step that has been started without having to start a new step.
fn end_progress_step<P: Step>(&self, sub_progress: P) {
let mut inner = self.steps.write().unwrap();
let InnerProgress { steps, durations } = &mut *inner;
let now = Instant::now();
let step_type = TypeId::of::<P>();
debug_assert!(
steps.iter().any(|(id, s, _)| *id == step_type && s.name() == sub_progress.name()),
"Step `{}` must have been started",
sub_progress.name()
);
if let Some(idx) = steps.iter().position(|(id, _, _)| *id == step_type) {
push_steps_durations(steps, durations, now, idx);
steps.truncate(idx);
}
}
/// Update the progress and return a scoped progress step that will end the progress step when dropped.
pub fn update_progress_scoped<P: Step + Copy>(&self, step: P) -> ScopedProgressStep<'_, P> {
self.update_progress(step);
ScopedProgressStep { progress: self, step }
}
// TODO: This code should be in meilisearch_types but cannot because milli can't depend on meilisearch_types // TODO: This code should be in meilisearch_types but cannot because milli can't depend on meilisearch_types
pub fn as_progress_view(&self) -> ProgressView { pub fn as_progress_view(&self) -> ProgressView {
let inner = self.steps.read().unwrap(); let inner = self.steps.read().unwrap();
@@ -95,7 +119,15 @@ impl Progress {
let now = Instant::now(); let now = Instant::now();
push_steps_durations(steps, &mut durations, now, 0); push_steps_durations(steps, &mut durations, now, 0);
durations.drain(..).map(|(name, duration)| (name, format!("{duration:.2?}"))).collect() let mut accumulated_durations = IndexMap::new();
for (name, duration) in durations.drain(..) {
accumulated_durations.entry(name).and_modify(|d| *d += duration).or_insert(duration);
}
accumulated_durations
.into_iter()
.map(|(name, duration)| (name, format!("{duration:.2?}")))
.collect()
} }
// TODO: ideally we should expose the progress in a way that let arroy use it directly // TODO: ideally we should expose the progress in a way that let arroy use it directly
@@ -343,3 +375,14 @@ impl<T: steppe::Step> Step for Compat<T> {
self.0.total().try_into().unwrap_or(u32::MAX) self.0.total().try_into().unwrap_or(u32::MAX)
} }
} }
pub struct ScopedProgressStep<'a, P: Step + Copy> {
progress: &'a Progress,
step: P,
}
impl<'a, P: Step + Copy> Drop for ScopedProgressStep<'a, P> {
fn drop(&mut self) {
self.progress.end_progress_step(self.step);
}
}

View File

@@ -1165,7 +1165,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = crate::Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
// this filter is copy pasted from #2380 with the exact same espace sequence // this filter is copy pasted from #2380 with the exact same espace sequence
search.filter(Filter::from_str("monitor_diagonal = '27\" to 30\\''").unwrap().unwrap()); search.filter(Filter::from_str("monitor_diagonal = '27\" to 30\\''").unwrap().unwrap());
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap(); let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
@@ -1225,7 +1225,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = crate::Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.filter(Filter::from_str("_geoRadius(45.4777599, 9.1967508, 0)").unwrap().unwrap()); search.filter(Filter::from_str("_geoRadius(45.4777599, 9.1967508, 0)").unwrap().unwrap());
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap(); let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();

View File

@@ -6,6 +6,7 @@ use roaring::RoaringBitmap;
use crate::score_details::{ScoreDetails, ScoreValue, ScoringStrategy}; use crate::score_details::{ScoreDetails, ScoreValue, ScoringStrategy};
use crate::search::new::{distinct_fid, distinct_single_docid}; use crate::search::new::{distinct_fid, distinct_single_docid};
use crate::search::steps::SearchStep;
use crate::search::SemanticSearch; use crate::search::SemanticSearch;
use crate::vector::{Embedding, SearchQuery}; use crate::vector::{Embedding, SearchQuery};
use crate::{Index, MatchingWords, Result, Search, SearchResult}; use crate::{Index, MatchingWords, Result, Search, SearchResult};
@@ -221,6 +222,7 @@ impl Search<'_> {
time_budget: self.time_budget.clone(), time_budget: self.time_budget.clone(),
ranking_score_threshold: self.ranking_score_threshold, ranking_score_threshold: self.ranking_score_threshold,
locales: self.locales.clone(), locales: self.locales.clone(),
progress: self.progress,
}; };
let semantic = search.semantic.take(); let semantic = search.semantic.take();
@@ -241,6 +243,7 @@ impl Search<'_> {
Some(vector_query) => vector_query, Some(vector_query) => vector_query,
None => { None => {
// attempt to embed the vector // attempt to embed the vector
self.progress.update_progress(SearchStep::EmbeddingQuery);
let span = tracing::trace_span!(target: "search::hybrid", "embed_one"); let span = tracing::trace_span!(target: "search::hybrid", "embed_one");
let _entered = span.enter(); let _entered = span.enter();

View File

@@ -12,7 +12,9 @@ use self::new::{execute_vector_search, PartialSearchResult, VectorStoreStats};
use crate::documents::GeoSortParameter; use crate::documents::GeoSortParameter;
use crate::filterable_attributes_rules::{filtered_matching_patterns, matching_features}; use crate::filterable_attributes_rules::{filtered_matching_patterns, matching_features};
use crate::index::MatchingStrategy; use crate::index::MatchingStrategy;
use crate::progress::Progress;
use crate::score_details::{ScoreDetails, ScoringStrategy}; use crate::score_details::{ScoreDetails, ScoringStrategy};
use crate::search::steps::SearchStep;
use crate::vector::{Embedder, Embedding}; use crate::vector::{Embedder, Embedding};
use crate::{ use crate::{
execute_search, filtered_universe, AscDesc, DefaultSearchLogger, DocumentId, Error, Index, execute_search, filtered_universe, AscDesc, DefaultSearchLogger, DocumentId, Error, Index,
@@ -29,6 +31,7 @@ mod fst_utils;
pub mod hybrid; pub mod hybrid;
pub mod new; pub mod new;
pub mod similar; pub mod similar;
pub mod steps;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SemanticSearch { pub struct SemanticSearch {
@@ -61,10 +64,11 @@ pub struct Search<'a> {
time_budget: TimeBudget, time_budget: TimeBudget,
ranking_score_threshold: Option<f64>, ranking_score_threshold: Option<f64>,
locales: Option<Vec<Language>>, locales: Option<Vec<Language>>,
progress: &'a Progress,
} }
impl<'a> Search<'a> { impl<'a> Search<'a> {
pub fn new(rtxn: &'a heed::RoTxn<'a>, index: &'a Index) -> Search<'a> { pub fn new(rtxn: &'a heed::RoTxn<'a>, index: &'a Index, progress: &'a Progress) -> Search<'a> {
Search { Search {
query: None, query: None,
filter: None, filter: None,
@@ -86,6 +90,7 @@ impl<'a> Search<'a> {
locales: None, locales: None,
time_budget: TimeBudget::max(), time_budget: TimeBudget::max(),
ranking_score_threshold: None, ranking_score_threshold: None,
progress,
} }
} }
@@ -198,7 +203,7 @@ impl<'a> Search<'a> {
pub fn execute_for_candidates(&self, has_vector_search: bool) -> Result<RoaringBitmap> { pub fn execute_for_candidates(&self, has_vector_search: bool) -> Result<RoaringBitmap> {
if has_vector_search { if has_vector_search {
let ctx = SearchContext::new(self.index, self.rtxn)?; let ctx = SearchContext::new(self.index, self.rtxn)?;
filtered_universe(ctx.index, ctx.txn, &self.filter) filtered_universe(ctx.index, ctx.txn, &self.filter, self.progress)
} else { } else {
Ok(self.execute()?.candidates) Ok(self.execute()?.candidates)
} }
@@ -239,8 +244,9 @@ impl<'a> Search<'a> {
} }
} }
let universe = filtered_universe(ctx.index, ctx.txn, &self.filter)?; let universe = filtered_universe(ctx.index, ctx.txn, &self.filter, self.progress)?;
let mut query_vector = None; let mut query_vector = None;
let PartialSearchResult { let PartialSearchResult {
located_query_terms, located_query_terms,
candidates, candidates,
@@ -276,6 +282,7 @@ impl<'a> Search<'a> {
*quantized, *quantized,
self.time_budget.clone(), self.time_budget.clone(),
self.ranking_score_threshold, self.ranking_score_threshold,
self.progress,
)? )?
} }
_ => execute_search( _ => execute_search(
@@ -297,6 +304,7 @@ impl<'a> Search<'a> {
self.time_budget.clone(), self.time_budget.clone(),
self.ranking_score_threshold, self.ranking_score_threshold,
self.locales.as_ref(), self.locales.as_ref(),
self.progress,
)?, )?,
}; };
@@ -306,6 +314,7 @@ impl<'a> Search<'a> {
tracing::debug!("Vector store stats: total_time={total_time:.02?}, total_queries={total_queries}, total_results={total_results}"); tracing::debug!("Vector store stats: total_time={total_time:.02?}, total_queries={total_queries}, total_results={total_results}");
} }
self.progress.update_progress(SearchStep::FormattingResults);
// consume context and located_query_terms to build MatchingWords. // consume context and located_query_terms to build MatchingWords.
let matching_words = match located_query_terms { let matching_words = match located_query_terms {
Some(located_query_terms) => MatchingWords::new(ctx, located_query_terms), Some(located_query_terms) => MatchingWords::new(ctx, located_query_terms),
@@ -347,6 +356,7 @@ impl fmt::Debug for Search<'_> {
time_budget, time_budget,
ranking_score_threshold, ranking_score_threshold,
locales, locales,
progress: _,
} = self; } = self;
f.debug_struct("Search") f.debug_struct("Search")
.field("query", query) .field("query", query)

View File

@@ -3,10 +3,12 @@ use roaring::RoaringBitmap;
use super::logger::SearchLogger; use super::logger::SearchLogger;
use super::ranking_rules::{BoxRankingRule, RankingRuleQueryTrait}; use super::ranking_rules::{BoxRankingRule, RankingRuleQueryTrait};
use super::SearchContext; use super::SearchContext;
use crate::progress::Progress;
use crate::score_details::{ScoreDetails, ScoringStrategy}; use crate::score_details::{ScoreDetails, ScoringStrategy};
use crate::search::new::distinct::{ use crate::search::new::distinct::{
apply_distinct_rule, distinct_fid, distinct_single_docid, DistinctOutput, apply_distinct_rule, distinct_fid, distinct_single_docid, DistinctOutput,
}; };
use crate::search::steps::{ComputingBucketSortStep, SearchStep};
use crate::{Result, TimeBudget}; use crate::{Result, TimeBudget};
pub struct BucketSortOutput { pub struct BucketSortOutput {
@@ -34,7 +36,9 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
ranking_score_threshold: Option<f64>, ranking_score_threshold: Option<f64>,
exhaustive_number_hits: bool, exhaustive_number_hits: bool,
max_total_hits: Option<usize>, max_total_hits: Option<usize>,
progress: &Progress,
) -> Result<BucketSortOutput> { ) -> Result<BucketSortOutput> {
let _step = progress.update_progress_scoped(SearchStep::ComputingBucketSort);
logger.initial_query(query); logger.initial_query(query);
logger.ranking_rules(&ranking_rules); logger.ranking_rules(&ranking_rules);
logger.initial_universe(universe); logger.initial_universe(universe);
@@ -93,6 +97,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
}; };
} }
let step = progress.update_progress_scoped(ComputingBucketSortStep::Initializing);
let ranking_rules_len = ranking_rules.len(); let ranking_rules_len = ranking_rules.len();
logger.start_iteration_ranking_rule(0, ranking_rules[0].as_ref(), query, universe); logger.start_iteration_ranking_rule(0, ranking_rules[0].as_ref(), query, universe);
@@ -105,6 +110,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
vec![RoaringBitmap::default(); ranking_rules_len]; vec![RoaringBitmap::default(); ranking_rules_len];
ranking_rule_universes[0].clone_from(universe); ranking_rule_universes[0].clone_from(universe);
let mut cur_ranking_rule_index = 0; let mut cur_ranking_rule_index = 0;
drop(step);
/// Finish iterating over the current ranking rule, yielding /// Finish iterating over the current ranking rule, yielding
/// control to the parent (or finishing the search if not possible). /// control to the parent (or finishing the search if not possible).
@@ -157,6 +163,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
distinct_fid, distinct_fid,
&ranking_rule_scores, &ranking_rule_scores,
$candidates, $candidates,
progress,
)?; )?;
}; };
} }
@@ -185,6 +192,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
ctx, ctx,
logger, logger,
&ranking_rule_universes[cur_ranking_rule_index], &ranking_rule_universes[cur_ranking_rule_index],
progress,
)? { )? {
std::task::Poll::Ready(bucket) => bucket, std::task::Poll::Ready(bucket) => bucket,
std::task::Poll::Pending => { std::task::Poll::Pending => {
@@ -231,6 +239,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
logger, logger,
&ranking_rule_universes[cur_ranking_rule_index], &ranking_rule_universes[cur_ranking_rule_index],
&time_budget, &time_budget,
progress,
)? )?
else { else {
back!(); back!();
@@ -323,9 +332,11 @@ fn maybe_add_to_results<'ctx, Q: RankingRuleQueryTrait>(
distinct_fid: Option<u16>, distinct_fid: Option<u16>,
ranking_rule_scores: &[ScoreDetails], ranking_rule_scores: &[ScoreDetails],
candidates: RoaringBitmap, candidates: RoaringBitmap,
progress: &Progress,
) -> Result<()> { ) -> Result<()> {
// First apply the distinct rule on the candidates, reducing the universes if necessary // First apply the distinct rule on the candidates, reducing the universes if necessary
let candidates = if let Some(distinct_fid) = distinct_fid { let candidates = if let Some(distinct_fid) = distinct_fid {
progress.update_progress(ComputingBucketSortStep::ApplyingDistinctRule);
let DistinctOutput { remaining, excluded } = let DistinctOutput { remaining, excluded } =
apply_distinct_rule(ctx, distinct_fid, &candidates)?; apply_distinct_rule(ctx, distinct_fid, &candidates)?;
for universe in ranking_rule_universes.iter_mut() { for universe in ranking_rule_universes.iter_mut() {
@@ -336,6 +347,8 @@ fn maybe_add_to_results<'ctx, Q: RankingRuleQueryTrait>(
} else { } else {
candidates.clone() candidates.clone()
}; };
progress.update_progress(ComputingBucketSortStep::MergingCandidates);
*all_candidates |= &candidates; *all_candidates |= &candidates;
// if the candidates are empty, there is nothing to do; // if the candidates are empty, there is nothing to do;

View File

@@ -3,9 +3,12 @@ use roaring::{MultiOps, RoaringBitmap};
use super::query_graph::QueryGraph; use super::query_graph::QueryGraph;
use super::ranking_rules::{RankingRule, RankingRuleOutput}; use super::ranking_rules::{RankingRule, RankingRuleOutput};
use crate::progress::Progress;
use crate::score_details::{self, ScoreDetails}; use crate::score_details::{self, ScoreDetails};
use crate::search::new::query_graph::QueryNodeData; use crate::search::new::query_graph::QueryNodeData;
use crate::search::new::query_term::ExactTerm; use crate::search::new::query_term::ExactTerm;
use crate::search::new::ranking_rules::RankingRuleId;
use crate::search::steps::ComputingBucketSortStep;
use crate::{CboRoaringBitmapCodec, Result, SearchContext, SearchLogger, TimeBudget}; use crate::{CboRoaringBitmapCodec, Result, SearchContext, SearchLogger, TimeBudget};
/// A ranking rule that produces 3 disjoint buckets: /// A ranking rule that produces 3 disjoint buckets:
@@ -24,8 +27,8 @@ impl ExactAttribute {
} }
impl<'ctx> RankingRule<'ctx, QueryGraph> for ExactAttribute { impl<'ctx> RankingRule<'ctx, QueryGraph> for ExactAttribute {
fn id(&self) -> String { fn id(&self) -> RankingRuleId {
"exact_attribute".to_owned() RankingRuleId::Exactness
} }
#[tracing::instrument(level = "trace", skip_all, target = "search::exact_attribute")] #[tracing::instrument(level = "trace", skip_all, target = "search::exact_attribute")]
@@ -48,7 +51,9 @@ impl<'ctx> RankingRule<'ctx, QueryGraph> for ExactAttribute {
_logger: &mut dyn SearchLogger<QueryGraph>, _logger: &mut dyn SearchLogger<QueryGraph>,
universe: &roaring::RoaringBitmap, universe: &roaring::RoaringBitmap,
_time_budget: &TimeBudget, _time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<QueryGraph>>> { ) -> Result<Option<RankingRuleOutput<QueryGraph>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
let state = std::mem::take(&mut self.state); let state = std::mem::take(&mut self.state);
let (state, output) = State::next(state, universe); let (state, output) = State::next(state, universe);
self.state = state; self.state = state;

View File

@@ -6,7 +6,10 @@ use rstar::RTree;
use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait}; use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait};
use crate::documents::geo_sort::{fill_cache, next_bucket}; use crate::documents::geo_sort::{fill_cache, next_bucket};
use crate::documents::{GeoSortParameter, GeoSortStrategy}; use crate::documents::{GeoSortParameter, GeoSortStrategy};
use crate::progress::Progress;
use crate::score_details::{self, ScoreDetails}; use crate::score_details::{self, ScoreDetails};
use crate::search::new::ranking_rules::RankingRuleId;
use crate::search::steps::ComputingBucketSortStep;
use crate::{GeoPoint, Result, SearchContext, SearchLogger, TimeBudget}; use crate::{GeoPoint, Result, SearchContext, SearchLogger, TimeBudget};
pub struct GeoSort<Q: RankingRuleQueryTrait> { pub struct GeoSort<Q: RankingRuleQueryTrait> {
@@ -73,8 +76,8 @@ impl<Q: RankingRuleQueryTrait> GeoSort<Q> {
} }
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for GeoSort<Q> { impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for GeoSort<Q> {
fn id(&self) -> String { fn id(&self) -> RankingRuleId {
"geo_sort".to_owned() RankingRuleId::GeoSort
} }
#[tracing::instrument(level = "trace", skip_all, target = "search::geo_sort")] #[tracing::instrument(level = "trace", skip_all, target = "search::geo_sort")]
@@ -112,7 +115,9 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for GeoSort<Q> {
_logger: &mut dyn SearchLogger<Q>, _logger: &mut dyn SearchLogger<Q>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
_time_budget: &TimeBudget, _time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<Q>>> { ) -> Result<Option<RankingRuleOutput<Q>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
let query = self.query.as_ref().unwrap().clone(); let query = self.query.as_ref().unwrap().clone();
next_bucket( next_bucket(

View File

@@ -50,51 +50,54 @@ use super::ranking_rule_graph::{
}; };
use super::small_bitmap::SmallBitmap; use super::small_bitmap::SmallBitmap;
use super::{QueryGraph, RankingRule, RankingRuleOutput, SearchContext}; use super::{QueryGraph, RankingRule, RankingRuleOutput, SearchContext};
use crate::progress::Progress;
use crate::score_details::Rank; use crate::score_details::Rank;
use crate::search::new::query_term::LocatedQueryTermSubset; use crate::search::new::query_term::LocatedQueryTermSubset;
use crate::search::new::ranking_rule_graph::PathVisitor; use crate::search::new::ranking_rule_graph::PathVisitor;
use crate::search::new::ranking_rules::RankingRuleId;
use crate::search::steps::ComputingBucketSortStep;
use crate::{Result, TermsMatchingStrategy, TimeBudget}; use crate::{Result, TermsMatchingStrategy, TimeBudget};
pub type Words = GraphBasedRankingRule<WordsGraph>; pub type Words = GraphBasedRankingRule<WordsGraph>;
impl GraphBasedRankingRule<WordsGraph> { impl GraphBasedRankingRule<WordsGraph> {
pub fn new(terms_matching_strategy: TermsMatchingStrategy) -> Self { pub fn new(terms_matching_strategy: TermsMatchingStrategy) -> Self {
Self::new_with_id("words".to_owned(), Some(terms_matching_strategy)) Self::new_with_id(RankingRuleId::Words, Some(terms_matching_strategy))
} }
} }
pub type Proximity = GraphBasedRankingRule<ProximityGraph>; pub type Proximity = GraphBasedRankingRule<ProximityGraph>;
impl GraphBasedRankingRule<ProximityGraph> { impl GraphBasedRankingRule<ProximityGraph> {
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self { pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
Self::new_with_id("proximity".to_owned(), terms_matching_strategy) Self::new_with_id(RankingRuleId::Proximity, terms_matching_strategy)
} }
} }
pub type Fid = GraphBasedRankingRule<FidGraph>; pub type Fid = GraphBasedRankingRule<FidGraph>;
impl GraphBasedRankingRule<FidGraph> { impl GraphBasedRankingRule<FidGraph> {
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self { pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
Self::new_with_id("fid".to_owned(), terms_matching_strategy) Self::new_with_id(RankingRuleId::AttributePosition, terms_matching_strategy)
} }
} }
pub type Position = GraphBasedRankingRule<PositionGraph>; pub type Position = GraphBasedRankingRule<PositionGraph>;
impl GraphBasedRankingRule<PositionGraph> { impl GraphBasedRankingRule<PositionGraph> {
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self { pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
Self::new_with_id("position".to_owned(), terms_matching_strategy) Self::new_with_id(RankingRuleId::WordPosition, terms_matching_strategy)
} }
} }
pub type Typo = GraphBasedRankingRule<TypoGraph>; pub type Typo = GraphBasedRankingRule<TypoGraph>;
impl GraphBasedRankingRule<TypoGraph> { impl GraphBasedRankingRule<TypoGraph> {
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self { pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
Self::new_with_id("typo".to_owned(), terms_matching_strategy) Self::new_with_id(RankingRuleId::Typo, terms_matching_strategy)
} }
} }
pub type Exactness = GraphBasedRankingRule<ExactnessGraph>; pub type Exactness = GraphBasedRankingRule<ExactnessGraph>;
impl GraphBasedRankingRule<ExactnessGraph> { impl GraphBasedRankingRule<ExactnessGraph> {
pub fn new() -> Self { pub fn new() -> Self {
Self::new_with_id("exactness".to_owned(), None) Self::new_with_id(RankingRuleId::Exactness, None)
} }
} }
/// A generic graph-based ranking rule /// A generic graph-based ranking rule
pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> { pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
id: String, id: RankingRuleId,
terms_matching_strategy: Option<TermsMatchingStrategy>, terms_matching_strategy: Option<TermsMatchingStrategy>,
// When the ranking rule is not iterating over its buckets, // When the ranking rule is not iterating over its buckets,
// its state is `None`. // its state is `None`.
@@ -102,7 +105,10 @@ pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
} }
impl<G: RankingRuleGraphTrait> GraphBasedRankingRule<G> { impl<G: RankingRuleGraphTrait> GraphBasedRankingRule<G> {
/// Creates the ranking rule with the given identifier /// Creates the ranking rule with the given identifier
pub fn new_with_id(id: String, terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self { pub fn new_with_id(
id: RankingRuleId,
terms_matching_strategy: Option<TermsMatchingStrategy>,
) -> Self {
Self { id, terms_matching_strategy, state: None } Self { id, terms_matching_strategy, state: None }
} }
} }
@@ -124,7 +130,7 @@ pub struct GraphBasedRankingRuleState<G: RankingRuleGraphTrait> {
} }
impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBasedRankingRule<G> { impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBasedRankingRule<G> {
fn id(&self) -> String { fn id(&self) -> RankingRuleId {
self.id.clone() self.id.clone()
} }
@@ -219,7 +225,9 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
logger: &mut dyn SearchLogger<QueryGraph>, logger: &mut dyn SearchLogger<QueryGraph>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
_time_budget: &TimeBudget, _time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<QueryGraph>>> { ) -> Result<Option<RankingRuleOutput<QueryGraph>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
// Will crash if `next_bucket` is called before `start_iteration` or after `end_iteration`, // Will crash if `next_bucket` is called before `start_iteration` or after `end_iteration`,
// should never happen // should never happen
let mut state = self.state.take().unwrap(); let mut state = self.state.take().unwrap();

View File

@@ -14,7 +14,7 @@ use crate::search::new::ranking_rule_graph::{
ProximityGraph, RankingRuleGraph, RankingRuleGraphTrait, TypoCondition, TypoGraph, ProximityGraph, RankingRuleGraph, RankingRuleGraphTrait, TypoCondition, TypoGraph,
WordsCondition, WordsGraph, WordsCondition, WordsGraph,
}; };
use crate::search::new::ranking_rules::BoxRankingRule; use crate::search::new::ranking_rules::{BoxRankingRule, RankingRuleId};
use crate::search::new::{QueryGraph, QueryNode, RankingRule, SearchContext, SearchLogger}; use crate::search::new::{QueryGraph, QueryNode, RankingRule, SearchContext, SearchLogger};
use crate::Result; use crate::Result;
@@ -45,13 +45,26 @@ enum Location {
Other, Other,
} }
impl From<RankingRuleId> for Location {
fn from(ranking_rule_id: RankingRuleId) -> Self {
match ranking_rule_id {
RankingRuleId::Words => Self::Words,
RankingRuleId::Typo => Self::Typo,
RankingRuleId::Proximity => Self::Proximity,
RankingRuleId::AttributePosition => Self::Fid,
RankingRuleId::WordPosition => Self::Position,
_ => Self::Other,
}
}
}
#[derive(Default)] #[derive(Default)]
pub struct VisualSearchLogger { pub struct VisualSearchLogger {
initial_query: Option<QueryGraph>, initial_query: Option<QueryGraph>,
initial_query_time: Option<Instant>, initial_query_time: Option<Instant>,
query_for_universe: Option<QueryGraph>, query_for_universe: Option<QueryGraph>,
initial_universe: Option<RoaringBitmap>, initial_universe: Option<RoaringBitmap>,
ranking_rules_ids: Option<Vec<String>>, ranking_rules_ids: Option<Vec<RankingRuleId>>,
events: Vec<SearchEvents>, events: Vec<SearchEvents>,
location: Vec<Location>, location: Vec<Location>,
} }
@@ -84,14 +97,7 @@ impl SearchLogger<QueryGraph> for VisualSearchLogger {
ranking_rule_idx, ranking_rule_idx,
universe_len: universe.len(), universe_len: universe.len(),
}); });
self.location.push(match ranking_rule.id().as_str() { self.location.push(ranking_rule.id().into());
"words" => Location::Words,
"typo" => Location::Typo,
"proximity" => Location::Proximity,
"fid" => Location::Fid,
"position" => Location::Position,
_ => Location::Other,
});
} }
fn next_bucket_ranking_rule( fn next_bucket_ranking_rule(

View File

@@ -498,12 +498,14 @@ mod tests {
use super::*; use super::*;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::progress::Progress;
use crate::{execute_search, filtered_universe, SearchContext, TimeBudget}; use crate::{execute_search, filtered_universe, SearchContext, TimeBudget};
impl<'a> MatcherBuilder<'a> { impl<'a> MatcherBuilder<'a> {
fn new_test(rtxn: &'a heed::RoTxn<'a>, index: &'a TempIndex, query: &str) -> Self { fn new_test(rtxn: &'a heed::RoTxn<'a>, index: &'a TempIndex, query: &str) -> Self {
let progress = Progress::default();
let mut ctx = SearchContext::new(index, rtxn).unwrap(); let mut ctx = SearchContext::new(index, rtxn).unwrap();
let universe = filtered_universe(ctx.index, ctx.txn, &None).unwrap(); let universe = filtered_universe(ctx.index, ctx.txn, &None, &progress).unwrap();
let crate::search::PartialSearchResult { located_query_terms, .. } = execute_search( let crate::search::PartialSearchResult { located_query_terms, .. } = execute_search(
&mut ctx, &mut ctx,
Some(query), Some(query),
@@ -523,6 +525,7 @@ mod tests {
TimeBudget::max(), TimeBudget::max(),
None, None,
None, None,
&progress,
) )
.unwrap(); .unwrap();

View File

@@ -56,8 +56,10 @@ use crate::constants::RESERVED_GEO_FIELD_NAME;
use crate::documents::GeoSortParameter; use crate::documents::GeoSortParameter;
use crate::index::PrefixSearch; use crate::index::PrefixSearch;
use crate::localized_attributes_rules::LocalizedFieldIds; use crate::localized_attributes_rules::LocalizedFieldIds;
use crate::progress::Progress;
use crate::score_details::{ScoreDetails, ScoringStrategy}; use crate::score_details::{ScoreDetails, ScoringStrategy};
use crate::search::new::distinct::apply_distinct_rule; use crate::search::new::distinct::apply_distinct_rule;
use crate::search::steps::SearchStep;
use crate::vector::Embedder; use crate::vector::Embedder;
use crate::{ use crate::{
AscDesc, DocumentId, FieldId, Filter, Index, Member, Result, TermsMatchingStrategy, TimeBudget, AscDesc, DocumentId, FieldId, Filter, Index, Member, Result, TermsMatchingStrategy, TimeBudget,
@@ -294,7 +296,9 @@ fn resolve_universe(
query_graph: &QueryGraph, query_graph: &QueryGraph,
matching_strategy: TermsMatchingStrategy, matching_strategy: TermsMatchingStrategy,
logger: &mut dyn SearchLogger<QueryGraph>, logger: &mut dyn SearchLogger<QueryGraph>,
progress: &Progress,
) -> Result<RoaringBitmap> { ) -> Result<RoaringBitmap> {
let _step = progress.update_progress_scoped(SearchStep::ResolvingUniverse);
resolve_maximally_reduced_query_graph( resolve_maximally_reduced_query_graph(
ctx, ctx,
initial_universe, initial_universe,
@@ -632,8 +636,10 @@ pub fn filtered_universe(
index: &Index, index: &Index,
txn: &RoTxn<'_>, txn: &RoTxn<'_>,
filters: &Option<Filter<'_>>, filters: &Option<Filter<'_>>,
progress: &Progress,
) -> Result<RoaringBitmap> { ) -> Result<RoaringBitmap> {
Ok(if let Some(filters) = filters { Ok(if let Some(filters) = filters {
let _step = progress.update_progress_scoped(SearchStep::ComputingFilter);
filters.evaluate(txn, index)? filters.evaluate(txn, index)?
} else { } else {
index.documents_ids(txn)? index.documents_ids(txn)?
@@ -658,6 +664,7 @@ pub fn execute_vector_search(
quantized: bool, quantized: bool,
time_budget: TimeBudget, time_budget: TimeBudget,
ranking_score_threshold: Option<f64>, ranking_score_threshold: Option<f64>,
progress: &Progress,
) -> Result<PartialSearchResult> { ) -> Result<PartialSearchResult> {
check_sort_criteria(ctx, sort_criteria.as_ref())?; check_sort_criteria(ctx, sort_criteria.as_ref())?;
@@ -692,6 +699,7 @@ pub fn execute_vector_search(
ranking_score_threshold, ranking_score_threshold,
exhaustive_number_hits, exhaustive_number_hits,
max_total_hits, max_total_hits,
progress,
)?; )?;
Ok(PartialSearchResult { Ok(PartialSearchResult {
@@ -725,12 +733,14 @@ pub fn execute_search(
time_budget: TimeBudget, time_budget: TimeBudget,
ranking_score_threshold: Option<f64>, ranking_score_threshold: Option<f64>,
locales: Option<&Vec<Language>>, locales: Option<&Vec<Language>>,
progress: &Progress,
) -> Result<PartialSearchResult> { ) -> Result<PartialSearchResult> {
check_sort_criteria(ctx, sort_criteria.as_ref())?; check_sort_criteria(ctx, sort_criteria.as_ref())?;
let mut used_negative_operator = false; let mut used_negative_operator = false;
let mut located_query_terms = None; let mut located_query_terms = None;
let query_terms = if let Some(query) = query { let query_terms = if let Some(query) = query {
progress.update_progress(SearchStep::TokenizingQuery);
let span = tracing::trace_span!(target: "search::tokens", "tokenizer_builder"); let span = tracing::trace_span!(target: "search::tokens", "tokenizer_builder");
let entered = span.enter(); let entered = span.enter();
@@ -834,8 +844,14 @@ pub fn execute_search(
terms_matching_strategy, terms_matching_strategy,
)?; )?;
universe &= universe &= resolve_universe(
resolve_universe(ctx, &universe, &graph, terms_matching_strategy, query_graph_logger)?; ctx,
&universe,
&graph,
terms_matching_strategy,
query_graph_logger,
progress,
)?;
bucket_sort( bucket_sort(
ctx, ctx,
@@ -851,6 +867,7 @@ pub fn execute_search(
ranking_score_threshold, ranking_score_threshold,
exhaustive_number_hits, exhaustive_number_hits,
max_total_hits, max_total_hits,
progress,
)? )?
} else { } else {
let ranking_rules = let ranking_rules =
@@ -869,6 +886,7 @@ pub fn execute_search(
ranking_score_threshold, ranking_score_threshold,
exhaustive_number_hits, exhaustive_number_hits,
max_total_hits, max_total_hits,
progress,
)? )?
}; };

View File

@@ -59,19 +59,19 @@ impl RankingRuleGraphTrait for FidGraph {
let mut all_fields = FxHashSet::default(); let mut all_fields = FxHashSet::default();
let mut current_max_weight = 0; let mut current_max_weight = 0;
for word in term.term_subset.all_single_words_except_prefix_db(ctx)? { for word in term.term_subset.all_single_words_except_prefix_db(ctx)? {
let fields = ctx.get_db_word_fids(word.interned())?; let fields = dbg!(ctx.get_db_word_fids(word.interned())?);
all_fields.extend(fields); all_fields.extend(fields);
} }
for phrase in term.term_subset.all_phrases(ctx)? { for phrase in term.term_subset.all_phrases(ctx)? {
for &word in phrase.words(ctx).iter().flatten() { for &word in phrase.words(ctx).iter().flatten() {
let fields = ctx.get_db_word_fids(word)?; let fields = dbg!(ctx.get_db_word_fids(word)?);
all_fields.extend(fields); all_fields.extend(fields);
} }
} }
if let Some(word_prefix) = term.term_subset.use_prefix_db(ctx) { if let Some(word_prefix) = term.term_subset.use_prefix_db(ctx) {
let fields = ctx.get_db_word_prefix_fids(word_prefix.interned())?; let fields = dbg!(ctx.get_db_word_prefix_fids(word_prefix.interned())?);
all_fields.extend(fields); all_fields.extend(fields);
} }

View File

@@ -4,7 +4,9 @@ use roaring::RoaringBitmap;
use super::logger::SearchLogger; use super::logger::SearchLogger;
use super::{QueryGraph, SearchContext}; use super::{QueryGraph, SearchContext};
use crate::progress::Progress;
use crate::score_details::ScoreDetails; use crate::score_details::ScoreDetails;
use crate::search::steps::ComputingBucketSortStep;
use crate::{Result, TimeBudget}; use crate::{Result, TimeBudget};
/// An internal trait implemented by only [`PlaceholderQuery`] and [`QueryGraph`] /// An internal trait implemented by only [`PlaceholderQuery`] and [`QueryGraph`]
@@ -24,7 +26,7 @@ pub type BoxRankingRule<'ctx, Query> = Box<dyn RankingRule<'ctx, Query> + 'ctx>;
/// (i.e. the read transaction and the cache) and over `Query`, which /// (i.e. the read transaction and the cache) and over `Query`, which
/// can be either [`PlaceholderQuery`] or [`QueryGraph`]. /// can be either [`PlaceholderQuery`] or [`QueryGraph`].
pub trait RankingRule<'ctx, Query: RankingRuleQueryTrait> { pub trait RankingRule<'ctx, Query: RankingRuleQueryTrait> {
fn id(&self) -> String; fn id(&self) -> RankingRuleId;
/// Prepare the ranking rule such that it can start iterating over its /// Prepare the ranking rule such that it can start iterating over its
/// buckets using [`next_bucket`](RankingRule::next_bucket). /// buckets using [`next_bucket`](RankingRule::next_bucket).
@@ -56,6 +58,7 @@ pub trait RankingRule<'ctx, Query: RankingRuleQueryTrait> {
logger: &mut dyn SearchLogger<Query>, logger: &mut dyn SearchLogger<Query>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
time_budget: &TimeBudget, time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<Query>>>; ) -> Result<Option<RankingRuleOutput<Query>>>;
/// Return the next bucket of this ranking rule, if doing so can be done without blocking /// Return the next bucket of this ranking rule, if doing so can be done without blocking
@@ -69,7 +72,9 @@ pub trait RankingRule<'ctx, Query: RankingRuleQueryTrait> {
_ctx: &mut SearchContext<'ctx>, _ctx: &mut SearchContext<'ctx>,
_logger: &mut dyn SearchLogger<Query>, _logger: &mut dyn SearchLogger<Query>,
_universe: &RoaringBitmap, _universe: &RoaringBitmap,
progress: &Progress,
) -> Result<Poll<RankingRuleOutput<Query>>> { ) -> Result<Poll<RankingRuleOutput<Query>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
Ok(Poll::Pending) Ok(Poll::Pending)
} }
@@ -93,3 +98,54 @@ pub struct RankingRuleOutput<Q> {
/// The score for the candidates of the current bucket /// The score for the candidates of the current bucket
pub score: ScoreDetails, pub score: ScoreDetails,
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RankingRuleId {
Words,
Typo,
Proximity,
AttributePosition,
WordPosition,
Exactness,
Sort,
GeoSort,
VectorSort,
Asc(String),
Desc(String),
}
impl std::fmt::Display for RankingRuleId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RankingRuleId::Words => write!(f, "words"),
RankingRuleId::Typo => write!(f, "typo"),
RankingRuleId::Proximity => write!(f, "proximity"),
RankingRuleId::AttributePosition => write!(f, "attribute_position"),
RankingRuleId::WordPosition => write!(f, "word_position"),
RankingRuleId::Exactness => write!(f, "exactness"),
RankingRuleId::Sort => write!(f, "sort"),
RankingRuleId::GeoSort => write!(f, "geo_sort"),
RankingRuleId::VectorSort => write!(f, "vector_sort"),
RankingRuleId::Asc(field_name) => write!(f, "asc:{}", field_name),
RankingRuleId::Desc(field_name) => write!(f, "desc:{}", field_name),
}
}
}
impl From<RankingRuleId> for ComputingBucketSortStep {
fn from(ranking_rule_id: RankingRuleId) -> Self {
match ranking_rule_id {
RankingRuleId::Words => Self::Words,
RankingRuleId::Typo => Self::Typo,
RankingRuleId::Proximity => Self::Proximity,
RankingRuleId::AttributePosition => Self::AttributePosition,
RankingRuleId::WordPosition => Self::WordPosition,
RankingRuleId::Exactness => Self::Exactness,
RankingRuleId::Sort => Self::Sort,
RankingRuleId::GeoSort => Self::GeoSort,
RankingRuleId::VectorSort => Self::VectorSort,
RankingRuleId::Asc(_) => Self::Asc,
RankingRuleId::Desc(_) => Self::Desc,
}
}
}

View File

@@ -5,8 +5,11 @@ use super::logger::SearchLogger;
use super::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait, SearchContext}; use super::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait, SearchContext};
use crate::heed_codec::facet::{FacetGroupKeyCodec, OrderedF64Codec}; use crate::heed_codec::facet::{FacetGroupKeyCodec, OrderedF64Codec};
use crate::heed_codec::{BytesRefCodec, StrRefCodec}; use crate::heed_codec::{BytesRefCodec, StrRefCodec};
use crate::progress::Progress;
use crate::score_details::{self, ScoreDetails}; use crate::score_details::{self, ScoreDetails};
use crate::search::facet::{ascending_facet_sort, descending_facet_sort}; use crate::search::facet::{ascending_facet_sort, descending_facet_sort};
use crate::search::new::ranking_rules::RankingRuleId;
use crate::search::steps::ComputingBucketSortStep;
use crate::{FieldId, Index, Result, TimeBudget}; use crate::{FieldId, Index, Result, TimeBudget};
pub trait RankingRuleOutputIter<'ctx, Query> { pub trait RankingRuleOutputIter<'ctx, Query> {
@@ -84,9 +87,13 @@ impl<'ctx, Query> Sort<'ctx, Query> {
} }
impl<'ctx, Query: RankingRuleQueryTrait> RankingRule<'ctx, Query> for Sort<'ctx, Query> { impl<'ctx, Query: RankingRuleQueryTrait> RankingRule<'ctx, Query> for Sort<'ctx, Query> {
fn id(&self) -> String { fn id(&self) -> RankingRuleId {
let Self { field_name, is_ascending, .. } = self; let Self { field_name, is_ascending, .. } = self;
format!("{field_name}:{}", if *is_ascending { "asc" } else { "desc" }) if *is_ascending {
RankingRuleId::Asc(field_name.clone())
} else {
RankingRuleId::Desc(field_name.clone())
}
} }
#[tracing::instrument(level = "trace", skip_all, target = "search::sort")] #[tracing::instrument(level = "trace", skip_all, target = "search::sort")]
@@ -196,7 +203,9 @@ impl<'ctx, Query: RankingRuleQueryTrait> RankingRule<'ctx, Query> for Sort<'ctx,
_logger: &mut dyn SearchLogger<Query>, _logger: &mut dyn SearchLogger<Query>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
_time_budget: &TimeBudget, _time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<Query>>> { ) -> Result<Option<RankingRuleOutput<Query>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
let iter = self.iter.as_mut().unwrap(); let iter = self.iter.as_mut().unwrap();
if let Some(mut bucket) = iter.next_bucket()? { if let Some(mut bucket) = iter.next_bucket()? {
bucket.candidates &= universe; bucket.candidates &= universe;

View File

@@ -1,5 +1,5 @@
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::{db_snap, Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{db_snap, Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -119,7 +119,7 @@ fn test_attribute_fid_simple() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -147,7 +147,7 @@ fn test_attribute_fid_ngrams() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -1,5 +1,5 @@
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::{db_snap, Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{db_snap, Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -134,7 +134,7 @@ fn test_attribute_position_simple() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("quick brown"); s.query("quick brown");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -150,7 +150,7 @@ fn test_attribute_position_repeated() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("a a a a a"); s.query("a a a a a");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -167,7 +167,7 @@ fn test_attribute_position_different_fields() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("quick brown"); s.query("quick brown");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -184,7 +184,7 @@ fn test_attribute_position_ngrams() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("quick brown"); s.query("quick brown");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -14,7 +14,7 @@ use crate::score_details::{ScoreDetails, ScoringStrategy};
use crate::update::Setting; use crate::update::Setting;
use crate::vector::settings::EmbeddingSettings; use crate::vector::settings::EmbeddingSettings;
use crate::vector::{Embedder, EmbedderOptions}; use crate::vector::{Embedder, EmbedderOptions};
use crate::{Criterion, Filter, FilterableAttributesRule, Search, TimeBudget}; use crate::{Criterion, Filter, FilterableAttributesRule, TimeBudget};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -61,7 +61,7 @@ fn basic_degraded_search() {
let index = create_index(); let index = create_index();
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.query("hello puppy kefir"); search.query("hello puppy kefir");
search.limit(3); search.limit(3);
search.time_budget(TimeBudget::new(Duration::from_millis(0))); search.time_budget(TimeBudget::new(Duration::from_millis(0)));
@@ -75,7 +75,7 @@ fn degraded_search_cannot_skip_filter() {
let index = create_index(); let index = create_index();
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.query("hello puppy kefir"); search.query("hello puppy kefir");
search.limit(100); search.limit(100);
search.time_budget(TimeBudget::new(Duration::from_millis(0))); search.time_budget(TimeBudget::new(Duration::from_millis(0)));
@@ -96,7 +96,7 @@ fn degraded_search_and_score_details() {
let index = create_index(); let index = create_index();
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.query("hello puppy kefir"); search.query("hello puppy kefir");
search.limit(4); search.limit(4);
search.scoring_strategy(ScoringStrategy::Detailed); search.scoring_strategy(ScoringStrategy::Detailed);
@@ -560,7 +560,7 @@ fn degraded_search_and_score_details_vector() {
.unwrap(); .unwrap();
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
let embedder = Arc::new( let embedder = Arc::new(
Embedder::new( Embedder::new(

View File

@@ -20,7 +20,7 @@ use maplit::hashset;
use super::collect_field_values; use super::collect_field_values;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::{ use crate::{
AscDesc, Criterion, FilterableAttributesRule, Index, Member, Search, SearchResult, AscDesc, Criterion, FilterableAttributesRule, Index, Member, SearchResult,
TermsMatchingStrategy, TermsMatchingStrategy,
}; };
@@ -246,7 +246,7 @@ fn test_distinct_placeholder_no_ranking_rules() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.distinct(S("letter")); s.distinct(S("letter"));
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0, 2, 5, 8, 9, 15, 18, 20, 21, 24, 25, 26]"); insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0, 2, 5, 8, 9, 15, 18, 20, 21, 24, 25, 26]");
@@ -275,7 +275,7 @@ fn test_distinct_at_search_placeholder_no_ranking_rules() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let s = Search::new(&txn, &index); let s = index.search(&txn);
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0, 2, 5, 8, 9, 15, 18, 20, 21, 24, 25, 26]"); insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0, 2, 5, 8, 9, 15, 18, 20, 21, 24, 25, 26]");
let distinct_values = verify_distinct(&index, &txn, None, &documents_ids); let distinct_values = verify_distinct(&index, &txn, None, &documents_ids);
@@ -308,7 +308,7 @@ fn test_distinct_placeholder_sort() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]);
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -348,7 +348,7 @@ fn test_distinct_placeholder_sort() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]);
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -388,7 +388,7 @@ fn test_distinct_placeholder_sort() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.sort_criteria(vec![ s.sort_criteria(vec![
AscDesc::Desc(Member::Field(S("letter"))), AscDesc::Desc(Member::Field(S("letter"))),
AscDesc::Desc(Member::Field(S("rank1"))), AscDesc::Desc(Member::Field(S("rank1"))),
@@ -443,7 +443,7 @@ fn test_distinct_words() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
@@ -496,7 +496,7 @@ fn test_distinct_sort_words() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]);
@@ -569,7 +569,7 @@ fn test_distinct_all_candidates() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]);
s.exhaustive_number_hits(true); s.exhaustive_number_hits(true);
@@ -592,7 +592,7 @@ fn test_distinct_typo() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);

View File

@@ -21,7 +21,7 @@ This module tests the following properties about the exactness ranking rule:
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index_simple_ordered() -> TempIndex { fn create_index_simple_ordered() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -471,7 +471,7 @@ fn test_exactness_simple_ordered() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -503,7 +503,7 @@ fn test_exactness_simple_reversed() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -526,7 +526,7 @@ fn test_exactness_simple_reversed() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -556,7 +556,7 @@ fn test_exactness_simple_random() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -585,7 +585,7 @@ fn test_exactness_attribute_starts_with_simple() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("this balcony"); s.query("this balcony");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -611,7 +611,7 @@ fn test_exactness_attribute_starts_with_phrase() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("\"overlooking the sea\" is a beautiful balcony"); s.query("\"overlooking the sea\" is a beautiful balcony");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -631,7 +631,7 @@ fn test_exactness_attribute_starts_with_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("overlooking the sea is a beautiful balcony"); s.query("overlooking the sea is a beautiful balcony");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -660,7 +660,7 @@ fn test_exactness_all_candidates_with_typo() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("overlocking the sea is a beautiful balcony"); s.query("overlocking the sea is a beautiful balcony");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -696,7 +696,7 @@ fn test_exactness_after_words() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -744,7 +744,7 @@ fn test_words_after_exactness() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -792,7 +792,7 @@ fn test_proximity_after_exactness() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -829,7 +829,7 @@ fn test_proximity_after_exactness() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -862,7 +862,7 @@ fn test_exactness_followed_by_typo_prefer_no_typo_prefix() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("quick brown fox extra"); s.query("quick brown fox extra");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -897,7 +897,7 @@ fn test_typo_followed_by_exactness() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.query("extraordinarily quick brown fox"); s.query("extraordinarily quick brown fox");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -82,7 +82,7 @@ fn test_geo_sort() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]); s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]);
@@ -118,7 +118,7 @@ fn test_geo_sort_with_following_ranking_rules() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![ s.sort_criteria(vec![
AscDesc::Asc(Member::Geo([0., 0.])), AscDesc::Asc(Member::Geo([0., 0.])),
@@ -159,7 +159,7 @@ fn test_geo_sort_reached_max_bucket_size() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.geo_max_bucket_size(2); s.geo_max_bucket_size(2);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![ s.sort_criteria(vec![
@@ -219,7 +219,7 @@ fn test_geo_sort_around_the_edge_of_the_flat_earth() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
// --- asc // --- asc
@@ -295,7 +295,7 @@ fn geo_sort_mixed_with_words() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]); s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]);
@@ -406,7 +406,7 @@ fn geo_sort_without_any_geo_faceted_documents() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut s = Search::new(&rtxn, &index); let mut s = index.search(&rtxn);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]); s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]);

View File

@@ -1,5 +1,5 @@
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::{Search, SearchResult}; use crate::SearchResult;
#[test] #[test]
fn test_kanji_language_detection() { fn test_kanji_language_detection() {
@@ -14,7 +14,7 @@ fn test_kanji_language_detection() {
.unwrap(); .unwrap();
let txn = index.write_txn().unwrap(); let txn = index.write_txn().unwrap();
let mut search = Search::new(&txn, &index); let mut search = index.search(&txn);
search.query("東京"); search.query("東京");
let SearchResult { documents_ids, .. } = search.execute().unwrap(); let SearchResult { documents_ids, .. } = search.execute().unwrap();

View File

@@ -19,7 +19,7 @@ This module tests the following properties:
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -78,7 +78,7 @@ fn test_2gram_simple() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("sun flower"); s.query("sun flower");
@@ -109,7 +109,7 @@ fn test_3gram_simple() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sun flower s are"); s.query("sun flower s are");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -129,7 +129,7 @@ fn test_2gram_typo() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sun flawer"); s.query("sun flawer");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -159,7 +159,7 @@ fn test_no_disable_ngrams() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sun flower "); s.query("sun flower ");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -185,7 +185,7 @@ fn test_2gram_prefix() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sun flow"); s.query("sun flow");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -214,7 +214,7 @@ fn test_3gram_prefix() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("su nf l"); s.query("su nf l");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -237,7 +237,7 @@ fn test_split_words() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sunflower "); s.query("sunflower ");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -266,7 +266,7 @@ fn test_disable_split_words() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sunflower "); s.query("sunflower ");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -286,7 +286,7 @@ fn test_2gram_split_words() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sunf lower"); s.query("sunf lower");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -310,7 +310,7 @@ fn test_3gram_no_split_words() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sunf lo wer"); s.query("sunf lo wer");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -333,7 +333,7 @@ fn test_3gram_no_typos() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("sunf la wer"); s.query("sunf la wer");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -352,7 +352,7 @@ fn test_no_ngram_phrases() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("\"sun\" flower"); s.query("\"sun\" flower");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -366,7 +366,7 @@ fn test_no_ngram_phrases() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("\"sun\" \"flower\""); s.query("\"sun\" \"flower\"");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -385,7 +385,7 @@ fn test_short_split_words() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("xyz"); s.query("xyz");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -412,7 +412,7 @@ fn test_split_words_never_disabled() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the sunflower is tall"); s.query("the sunflower is tall");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();

View File

@@ -18,7 +18,7 @@ use std::collections::BTreeMap;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_simple_index() -> TempIndex { fn create_simple_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -268,7 +268,7 @@ fn test_proximity_simple() {
let index = create_simple_index(); let index = create_simple_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
let SearchResult { documents_ids, .. } = s.execute().unwrap(); let SearchResult { documents_ids, .. } = s.execute().unwrap();
@@ -295,7 +295,7 @@ fn test_proximity_split_word() {
let index = create_edge_cases_index(); let index = create_edge_cases_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("sunflower wilting"); s.query("sunflower wilting");
@@ -315,7 +315,7 @@ fn test_proximity_split_word() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("\"sun flower\" wilting"); s.query("\"sun flower\" wilting");
@@ -342,7 +342,7 @@ fn test_proximity_split_word() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("xyz wilting"); s.query("xyz wilting");
@@ -365,7 +365,7 @@ fn test_proximity_prefix_db() {
let index = create_edge_cases_index(); let index = create_edge_cases_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("best s"); s.query("best s");
@@ -390,7 +390,7 @@ fn test_proximity_prefix_db() {
"###); "###);
// Difference when using the `su` prefix, which is not in the prefix DB // Difference when using the `su` prefix, which is not in the prefix DB
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("best su"); s.query("best su");
@@ -417,7 +417,7 @@ fn test_proximity_prefix_db() {
// **proximity** prefix DB. In that case, its sprximity score will always be // **proximity** prefix DB. In that case, its sprximity score will always be
// the maximum. This happens for prefixes that are larger than 2 bytes. // the maximum. This happens for prefixes that are larger than 2 bytes.
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("best win"); s.query("best win");
@@ -441,7 +441,7 @@ fn test_proximity_prefix_db() {
// Now using `wint`, which is not in the prefix DB: // Now using `wint`, which is not in the prefix DB:
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("best wint"); s.query("best wint");
@@ -465,7 +465,7 @@ fn test_proximity_prefix_db() {
// and using `wi` which is in the prefix DB and proximity prefix DB // and using `wi` which is in the prefix DB and proximity prefix DB
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("best wi"); s.query("best wi");

View File

@@ -8,7 +8,7 @@ implemented.
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -57,7 +57,7 @@ fn test_trap_basic() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("summer holiday"); s.query("summer holiday");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -17,9 +17,7 @@ use meili_snap::insta;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{ use crate::{score_details, AscDesc, Criterion, Member, SearchResult, TermsMatchingStrategy};
score_details, AscDesc, Criterion, Member, Search, SearchResult, TermsMatchingStrategy,
};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -184,7 +182,7 @@ fn test_sort() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]);
@@ -219,7 +217,7 @@ fn test_sort() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank")))]);
@@ -254,7 +252,7 @@ fn test_sort() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Asc(Member::Field(S("vague")))]); s.sort_criteria(vec![AscDesc::Asc(Member::Field(S("vague")))]);
@@ -289,7 +287,7 @@ fn test_sort() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("vague")))]); s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("vague")))]);
@@ -338,7 +336,7 @@ fn test_redacted() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.sort_criteria(vec![ s.sort_criteria(vec![

View File

@@ -13,7 +13,7 @@ use std::collections::BTreeSet;
use std::iter::FromIterator; use std::iter::FromIterator;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::{Search, SearchResult, TermsMatchingStrategy}; use crate::{SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -79,7 +79,7 @@ fn test_ignore_stop_words() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
// `the` is treated as a prefix here, so it's not ignored // `the` is treated as a prefix here, so it's not ignored
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("xyz to the"); s.query("xyz to the");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -132,7 +132,7 @@ fn test_ignore_stop_words() {
"###); "###);
// `xyz` is treated as a prefix here, so it's not ignored // `xyz` is treated as a prefix here, so it's not ignored
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("to the xyz"); s.query("to the xyz");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -185,7 +185,7 @@ fn test_ignore_stop_words() {
"###); "###);
// `xyz` is not treated as a prefix anymore because of the trailing space, so it's ignored // `xyz` is not treated as a prefix anymore because of the trailing space, so it's ignored
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("to the xyz "); s.query("to the xyz ");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -237,7 +237,7 @@ fn test_ignore_stop_words() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("to the dragon xyz"); s.query("to the dragon xyz");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -296,7 +296,7 @@ fn test_stop_words_in_phrase() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"how to train your dragon\""); s.query("\"how to train your dragon\"");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -389,7 +389,7 @@ fn test_stop_words_in_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("how \"to\" train \"the"); s.query("how \"to\" train \"the");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -441,7 +441,7 @@ fn test_stop_words_in_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("how \"to\" train \"The dragon"); s.query("how \"to\" train \"The dragon");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -449,7 +449,7 @@ fn test_stop_words_in_phrase() {
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[3, 6, 5]"); insta::assert_snapshot!(format!("{documents_ids:?}"), @"[3, 6, 5]");
insta::assert_snapshot!(format!("{document_scores:#?}")); insta::assert_snapshot!(format!("{document_scores:#?}"));
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"to\""); s.query("\"to\"");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -22,7 +22,7 @@ use std::collections::BTreeMap;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -157,7 +157,7 @@ fn test_no_typo() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -182,7 +182,7 @@ fn test_default_typo() {
insta::assert_debug_snapshot!(tt, @"9"); insta::assert_debug_snapshot!(tt, @"9");
// 0 typo // 0 typo
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -202,7 +202,7 @@ fn test_default_typo() {
"###); "###);
// 1 typo on one word, replaced letter // 1 typo on one word, replaced letter
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quack brown fox jumps over the lazy dog"); s.query("the quack brown fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -216,7 +216,7 @@ fn test_default_typo() {
"###); "###);
// 1 typo on one word, missing letter, extra letter // 1 typo on one word, missing letter, extra letter
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quicest brownest fox jummps over the laziest dog"); s.query("the quicest brownest fox jummps over the laziest dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -235,7 +235,7 @@ fn test_phrase_no_typo_allowed() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the \"quick brewn\" fox jumps over the lazy dog"); s.query("the \"quick brewn\" fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -265,7 +265,7 @@ fn test_typo_exact_word() {
insta::assert_debug_snapshot!(tt, @"9"); insta::assert_debug_snapshot!(tt, @"9");
// don't match quivk // don't match quivk
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -279,7 +279,7 @@ fn test_typo_exact_word() {
"###); "###);
// Don't match quick // Don't match quick
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quack brown fox jumps over the lazy dog"); s.query("the quack brown fox jumps over the lazy dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -287,7 +287,7 @@ fn test_typo_exact_word() {
insta::assert_snapshot!(format!("{document_scores:?}"), @"[]"); insta::assert_snapshot!(format!("{document_scores:?}"), @"[]");
// words not in exact_words (quicest, jummps) have normal typo handling // words not in exact_words (quicest, jummps) have normal typo handling
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("the quicest brownest fox jummps over the laziest dog"); s.query("the quicest brownest fox jummps over the laziest dog");
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap(); let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
@@ -301,7 +301,7 @@ fn test_typo_exact_word() {
"###); "###);
// exact words do not disable prefix (sunflowering OK, but no sunflowar) // exact words do not disable prefix (sunflowering OK, but no sunflowar)
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("network interconnection sunflower"); s.query("network interconnection sunflower");
@@ -340,7 +340,7 @@ fn test_typo_exact_attribute() {
insta::assert_debug_snapshot!(tt, @"9"); insta::assert_debug_snapshot!(tt, @"9");
// Exact match returns both exact attributes and tolerant ones. // Exact match returns both exact attributes and tolerant ones.
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
@@ -365,7 +365,7 @@ fn test_typo_exact_attribute() {
"###); "###);
// 1 typo only returns the tolerant attribute // 1 typo only returns the tolerant attribute
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quidk brown fox jumps over the lazy dog"); s.query("the quidk brown fox jumps over the lazy dog");
@@ -386,7 +386,7 @@ fn test_typo_exact_attribute() {
"###); "###);
// combine with exact words // combine with exact words
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quivk brown fox jumps over the lazy dog"); s.query("the quivk brown fox jumps over the lazy dog");
@@ -414,7 +414,7 @@ fn test_typo_exact_attribute() {
"###); "###);
// No result in tolerant attribute // No result in tolerant attribute
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quicest brownest fox jummps over the laziest dog"); s.query("the quicest brownest fox jummps over the laziest dog");
@@ -428,7 +428,7 @@ fn test_ngram_typos() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the extra lagant fox skyrocketed over the languorous dog"); s.query("the extra lagant fox skyrocketed over the languorous dog");
@@ -442,7 +442,7 @@ fn test_ngram_typos() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the ex tra lagant fox skyrocketed over the languorous dog"); s.query("the ex tra lagant fox skyrocketed over the languorous dog");
@@ -463,7 +463,7 @@ fn test_typo_ranking_rule_not_preceded_by_words_ranking_rule() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
@@ -499,7 +499,7 @@ fn test_typo_ranking_rule_not_preceded_by_words_ranking_rule() {
}) })
.unwrap(); .unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
@@ -517,7 +517,7 @@ fn test_typo_bucketing() {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
// First do the search with just the Words ranking rule // First do the search with just the Words ranking rule
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("network interconnection sunflower"); s.query("network interconnection sunflower");
@@ -545,7 +545,7 @@ fn test_typo_bucketing() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("network interconnection sunflower"); s.query("network interconnection sunflower");
@@ -564,7 +564,7 @@ fn test_typo_bucketing() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("network interconnection sun flower"); s.query("network interconnection sun flower");
@@ -600,7 +600,7 @@ fn test_typo_synonyms() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the quick brown fox jumps over the lackadaisical dog"); s.query("the quick brown fox jumps over the lackadaisical dog");
@@ -616,7 +616,7 @@ fn test_typo_synonyms() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
s.query("the fast brownish fox jumps over the lackadaisical dog"); s.query("the fast brownish fox jumps over the lackadaisical dog");

View File

@@ -17,7 +17,7 @@ because the typo ranking rule before it only used the derivation `beautiful`.
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -87,7 +87,7 @@ fn test_trap_basic_and_complex1() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("beautiful summer"); s.query("beautiful summer");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -110,7 +110,7 @@ fn test_trap_complex2() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.query("delicious sweet dessert"); s.query("delicious sweet dessert");
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -14,7 +14,7 @@ This module tests the following properties:
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::search::new::tests::collect_field_values; use crate::search::new::tests::collect_field_values;
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy}; use crate::{Criterion, SearchResult, TermsMatchingStrategy};
fn create_index() -> TempIndex { fn create_index() -> TempIndex {
let index = TempIndex::new(); let index = TempIndex::new();
@@ -131,7 +131,7 @@ fn test_words_tms_last_simple() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -166,7 +166,7 @@ fn test_words_tms_last_simple() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("extravagant the quick brown fox jumps over the lazy dog"); s.query("extravagant the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -180,7 +180,7 @@ fn test_words_tms_last_phrase() {
let index = create_index(); let index = create_index();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"the quick brown fox\" jumps over the lazy dog"); s.query("\"the quick brown fox\" jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -205,7 +205,7 @@ fn test_words_tms_last_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"the quick brown fox\" jumps over the \"lazy\" dog"); s.query("\"the quick brown fox\" jumps over the \"lazy\" dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -227,7 +227,7 @@ fn test_words_tms_last_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"the quick brown fox jumps over the lazy dog\""); s.query("\"the quick brown fox jumps over the lazy dog\"");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -243,7 +243,7 @@ fn test_words_tms_last_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("\"the quick brown fox jumps over the lazy dog"); s.query("\"the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -270,7 +270,7 @@ fn test_words_proximity_tms_last_simple() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -305,7 +305,7 @@ fn test_words_proximity_tms_last_simple() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the brown quick fox jumps over the lazy dog"); s.query("the brown quick fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -351,7 +351,7 @@ fn test_words_proximity_tms_last_phrase() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the \"quick brown\" fox jumps over the lazy dog"); s.query("the \"quick brown\" fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -382,7 +382,7 @@ fn test_words_proximity_tms_last_phrase() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the \"quick brown\" \"fox jumps\" over the lazy dog"); s.query("the \"quick brown\" \"fox jumps\" over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::Last); s.terms_matching_strategy(TermsMatchingStrategy::Last);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -421,7 +421,7 @@ fn test_words_tms_all() {
.unwrap(); .unwrap();
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("the quick brown fox jumps over the lazy dog"); s.query("the quick brown fox jumps over the lazy dog");
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
@@ -447,7 +447,7 @@ fn test_words_tms_all() {
] ]
"###); "###);
let mut s = Search::new(&txn, &index); let mut s = index.search(&txn);
s.query("extravagant"); s.query("extravagant");
s.terms_matching_strategy(TermsMatchingStrategy::All); s.terms_matching_strategy(TermsMatchingStrategy::All);
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed); s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);

View File

@@ -6,7 +6,10 @@ use roaring::RoaringBitmap;
use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait}; use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait};
use super::VectorStoreStats; use super::VectorStoreStats;
use crate::progress::Progress;
use crate::score_details::{self, ScoreDetails}; use crate::score_details::{self, ScoreDetails};
use crate::search::new::ranking_rules::RankingRuleId;
use crate::search::steps::ComputingBucketSortStep;
use crate::vector::{DistributionShift, Embedder, VectorStore}; use crate::vector::{DistributionShift, Embedder, VectorStore};
use crate::{DocumentId, Result, SearchContext, SearchLogger, TimeBudget}; use crate::{DocumentId, Result, SearchContext, SearchLogger, TimeBudget};
@@ -94,8 +97,8 @@ impl<Q: RankingRuleQueryTrait> VectorSort<Q> {
} }
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> { impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
fn id(&self) -> String { fn id(&self) -> RankingRuleId {
"vector_sort".to_owned() RankingRuleId::VectorSort
} }
#[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")] #[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")]
@@ -123,7 +126,9 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
_logger: &mut dyn SearchLogger<Q>, _logger: &mut dyn SearchLogger<Q>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
time_budget: &TimeBudget, time_budget: &TimeBudget,
progress: &Progress,
) -> Result<Option<RankingRuleOutput<Q>>> { ) -> Result<Option<RankingRuleOutput<Q>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
let query = self.query.as_ref().unwrap().clone(); let query = self.query.as_ref().unwrap().clone();
let vector_candidates = &self.vector_candidates & universe; let vector_candidates = &self.vector_candidates & universe;
@@ -158,7 +163,7 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
})); }));
} }
self.next_bucket(ctx, _logger, universe, time_budget) self.next_bucket(ctx, _logger, universe, time_budget, progress)
} }
#[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")] #[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")]
@@ -171,7 +176,9 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
_ctx: &mut SearchContext<'ctx>, _ctx: &mut SearchContext<'ctx>,
_logger: &mut dyn SearchLogger<Q>, _logger: &mut dyn SearchLogger<Q>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
progress: &Progress,
) -> Result<Poll<RankingRuleOutput<Q>>> { ) -> Result<Poll<RankingRuleOutput<Q>>> {
progress.update_progress(ComputingBucketSortStep::from(self.id()));
let query = self.query.as_ref().unwrap().clone(); let query = self.query.as_ref().unwrap().clone();
let vector_candidates = &self.vector_candidates & universe; let vector_candidates = &self.vector_candidates & universe;

View File

@@ -57,7 +57,12 @@ impl<'a> Similar<'a> {
} }
pub fn execute(&self) -> Result<SearchResult> { pub fn execute(&self) -> Result<SearchResult> {
let mut universe = filtered_universe(self.index, self.rtxn, &self.filter)?; let mut universe = filtered_universe(
self.index,
self.rtxn,
&self.filter,
&crate::progress::Progress::default(),
)?;
// we never want to receive the docid // we never want to receive the docid
universe.remove(self.id); universe.remove(self.id);

View File

@@ -0,0 +1,52 @@
use crate::make_enum_progress;
make_enum_progress! {
pub enum SearchStep {
PreparingSearch,
TokenizingQuery,
EmbeddingQuery,
ComputingFilter,
ResolvingUniverse,
ComputingBucketSort,
FormattingResults,
ComputingFacetDistribution,
FederatingResults,
ApplyingPersonalization,
}
}
make_enum_progress! {
pub enum ComputingBucketSortStep {
Initializing,
MergingCandidates,
ApplyingDistinctRule,
Words,
Typo,
Proximity,
AttributePosition,
WordPosition,
Exactness,
Sort,
GeoSort,
VectorSort,
Asc,
Desc,
}
}
make_enum_progress! {
pub enum FederatingResultsStep {
WaitingForRemoteResults,
MergingFacets,
MergingResults,
}
}
make_enum_progress! {
pub enum TotalProcessingTimeStep {
WaitingForPermit,
Searching,
FetchingSimilar,
PublishingAnalytics,
}
}

View File

@@ -26,6 +26,7 @@ pub(crate) struct TempIndex {
pub inner: Index, pub inner: Index,
pub indexer_config: IndexerConfig, pub indexer_config: IndexerConfig,
pub index_documents_config: IndexDocumentsConfig, pub index_documents_config: IndexDocumentsConfig,
pub progress: Progress,
_tempdir: TempDir, _tempdir: TempDir,
} }
@@ -47,7 +48,9 @@ impl TempIndex {
let inner = Index::new(options, _tempdir.path(), true).unwrap(); let inner = Index::new(options, _tempdir.path(), true).unwrap();
let indexer_config = IndexerConfig::default(); let indexer_config = IndexerConfig::default();
let index_documents_config = IndexDocumentsConfig::default(); let index_documents_config = IndexDocumentsConfig::default();
Self { inner, indexer_config, index_documents_config, _tempdir } let progress = Progress::default();
Self { inner, indexer_config, index_documents_config, progress, _tempdir }
} }
/// Creates a temporary index, with a default `4096 * 2000` size. This should be enough for /// Creates a temporary index, with a default `4096 * 2000` size. This should be enough for
/// most tests. /// most tests.
@@ -210,6 +213,10 @@ impl TempIndex {
pub fn delete_document(&self, external_document_id: &str) { pub fn delete_document(&self, external_document_id: &str) {
self.delete_documents(vec![external_document_id.to_string()]) self.delete_documents(vec![external_document_id.to_string()])
} }
pub fn search<'a>(&'a self, rtxn: &'a heed::RoTxn<'a>) -> Search<'a> {
self.inner.search(rtxn, &self.progress)
}
} }
#[test] #[test]
@@ -1095,7 +1102,7 @@ fn bug_3021_fourth() {
"###); "###);
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let search = Search::new(&rtxn, &index); let search = index.search(&rtxn);
let SearchResult { let SearchResult {
matching_words: _, matching_words: _,
candidates: _, candidates: _,

View File

@@ -1292,7 +1292,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
// testing the simple query search // testing the simple query search
let mut search = crate::Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.query("document"); search.query("document");
search.terms_matching_strategy(TermsMatchingStrategy::default()); search.terms_matching_strategy(TermsMatchingStrategy::default());
// all documents should be returned // all documents should be returned
@@ -1333,7 +1333,7 @@ mod tests {
assert!(documents_ids.is_empty()); // nested is not searchable assert!(documents_ids.is_empty()); // nested is not searchable
// testing the filters // testing the filters
let mut search = crate::Search::new(&rtxn, &index); let mut search = index.search(&rtxn);
search.filter(crate::Filter::from_str(r#"title = "The first document""#).unwrap().unwrap()); search.filter(crate::Filter::from_str(r#"title = "The first document""#).unwrap().unwrap());
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap(); let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
assert_eq!(documents_ids, vec![1]); assert_eq!(documents_ids, vec![1]);
@@ -1358,6 +1358,7 @@ mod tests {
#[test] #[test]
fn index_documents_with_nested_primary_key() { fn index_documents_with_nested_primary_key() {
let index = TempIndex::new(); let index = TempIndex::new();
let progress = Progress::default();
index index
.update_settings(|settings| { .update_settings(|settings| {
@@ -1397,7 +1398,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
// testing the simple query search // testing the simple query search
let mut search = crate::Search::new(&rtxn, &index); let mut search = crate::Search::new(&rtxn, &index, &progress);
search.query("document"); search.query("document");
search.terms_matching_strategy(TermsMatchingStrategy::default()); search.terms_matching_strategy(TermsMatchingStrategy::default());
// all documents should be returned // all documents should be returned
@@ -1453,6 +1454,7 @@ mod tests {
#[test] #[test]
fn test_facets_generation() { fn test_facets_generation() {
let index = TempIndex::new(); let index = TempIndex::new();
let progress = Progress::default();
index index
.add_documents(documents!([ .add_documents(documents!([
@@ -1507,7 +1509,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
for (s, i) in [("zeroth", 0), ("first", 1), ("second", 2), ("third", 3)] { for (s, i) in [("zeroth", 0), ("first", 1), ("second", 2), ("third", 3)] {
let mut search = crate::Search::new(&rtxn, &index); let mut search = crate::Search::new(&rtxn, &index, &progress);
let filter = format!(r#""dog.race.bernese mountain" = {s}"#); let filter = format!(r#""dog.race.bernese mountain" = {s}"#);
search.filter(crate::Filter::from_str(&filter).unwrap().unwrap()); search.filter(crate::Filter::from_str(&filter).unwrap().unwrap());
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap(); let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
@@ -1545,7 +1547,7 @@ mod tests {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = crate::Search::new(&rtxn, &index); let mut search = crate::Search::new(&rtxn, &index, &progress);
search.sort_criteria(vec![crate::AscDesc::Asc(crate::Member::Field(S( search.sort_criteria(vec![crate::AscDesc::Asc(crate::Member::Field(S(
"dog.race.bernese mountain", "dog.race.bernese mountain",
)))]); )))]);
@@ -2911,7 +2913,6 @@ mod tests {
] ]
*/ */
let index = TempIndex::new(); let index = TempIndex::new();
// START OF BATCH // START OF BATCH
println!("--- ENTERING BATCH 1"); println!("--- ENTERING BATCH 1");
@@ -3601,6 +3602,7 @@ mod tests {
#[test] #[test]
fn delete_words_exact_attributes() { fn delete_words_exact_attributes() {
let index = TempIndex::new(); let index = TempIndex::new();
let progress = Progress::default();
index index
.update_settings(|settings| { .update_settings(|settings| {
@@ -3639,7 +3641,7 @@ mod tests {
let words = index.words_fst(&txn).unwrap().into_stream().into_strs().unwrap(); let words = index.words_fst(&txn).unwrap().into_stream().into_strs().unwrap();
insta::assert_snapshot!(format!("{words:?}"), @r###"["hello"]"###); insta::assert_snapshot!(format!("{words:?}"), @r###"["hello"]"###);
let mut s = Search::new(&txn, &index); let mut s = Search::new(&txn, &index, &progress);
s.query("hello"); s.query("hello");
let crate::SearchResult { documents_ids, .. } = s.execute().unwrap(); let crate::SearchResult { documents_ids, .. } = s.execute().unwrap();
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0]"); insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0]");

View File

@@ -25,7 +25,8 @@ macro_rules! test_distinct {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.query(search::TEST_QUERY); search.query(search::TEST_QUERY);
search.limit($limit); search.limit($limit);
search.offset($offset); search.offset($offset);

View File

@@ -1,5 +1,7 @@
use either::{Either, Left, Right}; use either::{Either, Left, Right};
use milli::progress::Progress;
use milli::{Criterion, Filter, Search, SearchResult, TermsMatchingStrategy}; use milli::{Criterion, Filter, Search, SearchResult, TermsMatchingStrategy};
use Criterion::*; use Criterion::*;
use crate::search::{self, EXTERNAL_DOCUMENTS_IDS}; use crate::search::{self, EXTERNAL_DOCUMENTS_IDS};
@@ -15,7 +17,8 @@ macro_rules! test_filter {
let filter_conditions = let filter_conditions =
Filter::from_array::<Vec<Either<Vec<&str>, &str>>, _>($filter).unwrap().unwrap(); Filter::from_array::<Vec<Either<Vec<&str>, &str>>, _>($filter).unwrap().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.query(search::TEST_QUERY); search.query(search::TEST_QUERY);
search.limit(EXTERNAL_DOCUMENTS_IDS.len()); search.limit(EXTERNAL_DOCUMENTS_IDS.len());

View File

@@ -24,7 +24,8 @@ fn test_phrase_search_with_stop_words_given_criteria(criteria: &[Criterion]) {
// Phrase search containing stop words // Phrase search containing stop words
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("\"the use of force\""); search.query("\"the use of force\"");
search.limit(10); search.limit(10);
search.terms_matching_strategy(TermsMatchingStrategy::All); search.terms_matching_strategy(TermsMatchingStrategy::All);

View File

@@ -27,7 +27,8 @@ macro_rules! test_criterion {
let index = search::setup_search_index_with_criteria(&criteria); let index = search::setup_search_index_with_criteria(&criteria);
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.query(search::TEST_QUERY); search.query(search::TEST_QUERY);
search.limit(EXTERNAL_DOCUMENTS_IDS.len()); search.limit(EXTERNAL_DOCUMENTS_IDS.len());
search.terms_matching_strategy($optional_word); search.terms_matching_strategy($optional_word);
@@ -241,7 +242,8 @@ fn criteria_mixup() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.query(search::TEST_QUERY); search.query(search::TEST_QUERY);
search.limit(EXTERNAL_DOCUMENTS_IDS.len()); search.limit(EXTERNAL_DOCUMENTS_IDS.len());
search.terms_matching_strategy(ALLOW_OPTIONAL_WORDS); search.terms_matching_strategy(ALLOW_OPTIONAL_WORDS);
@@ -365,7 +367,8 @@ fn criteria_ascdesc() {
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.limit(ASC_DESC_CANDIDATES_THRESHOLD + 1); search.limit(ASC_DESC_CANDIDATES_THRESHOLD + 1);
let SearchResult { documents_ids, .. } = search.execute().unwrap(); let SearchResult { documents_ids, .. } = search.execute().unwrap();

View File

@@ -1,4 +1,5 @@
use big_s::S; use big_s::S;
use milli::progress::Progress;
use milli::Criterion::{Attribute, Exactness, Proximity, Typo, Words}; use milli::Criterion::{Attribute, Exactness, Proximity, Typo, Words};
use milli::{AscDesc, Error, Member, Search, TermsMatchingStrategy, UserError}; use milli::{AscDesc, Error, Member, Search, TermsMatchingStrategy, UserError};
@@ -11,7 +12,8 @@ fn sort_ranking_rule_missing() {
let index = search::setup_search_index_with_criteria(&criteria); let index = search::setup_search_index_with_criteria(&criteria);
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let mut search = Search::new(&rtxn, &index); let progress = Progress::default();
let mut search = Search::new(&rtxn, &index, &progress);
search.query(search::TEST_QUERY); search.query(search::TEST_QUERY);
search.limit(EXTERNAL_DOCUMENTS_IDS.len()); search.limit(EXTERNAL_DOCUMENTS_IDS.len());

View File

@@ -22,7 +22,8 @@ fn test_typo_tolerance_one_typo() {
{ {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zeal"); search.query("zeal");
search.limit(10); search.limit(10);
@@ -31,7 +32,8 @@ fn test_typo_tolerance_one_typo() {
let result = search.execute().unwrap(); let result = search.execute().unwrap();
assert_eq!(result.documents_ids.len(), 1); assert_eq!(result.documents_ids.len(), 1);
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zean"); search.query("zean");
search.limit(10); search.limit(10);
@@ -49,7 +51,8 @@ fn test_typo_tolerance_one_typo() {
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap(); builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
// typo is now supported for 4 letters words // typo is now supported for 4 letters words
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zean"); search.query("zean");
search.limit(10); search.limit(10);
@@ -68,7 +71,8 @@ fn test_typo_tolerance_two_typo() {
{ {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zealand"); search.query("zealand");
search.limit(10); search.limit(10);
@@ -77,7 +81,8 @@ fn test_typo_tolerance_two_typo() {
let result = search.execute().unwrap(); let result = search.execute().unwrap();
assert_eq!(result.documents_ids.len(), 1); assert_eq!(result.documents_ids.len(), 1);
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zealemd"); search.query("zealemd");
search.limit(10); search.limit(10);
@@ -95,7 +100,8 @@ fn test_typo_tolerance_two_typo() {
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap(); builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
// typo is now supported for 4 letters words // typo is now supported for 4 letters words
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zealemd"); search.query("zealemd");
search.limit(10); search.limit(10);
@@ -164,7 +170,8 @@ fn test_typo_disabled_on_word() {
{ {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zealand"); search.query("zealand");
search.limit(10); search.limit(10);
@@ -184,7 +191,8 @@ fn test_typo_disabled_on_word() {
builder.set_exact_words(exact_words); builder.set_exact_words(exact_words);
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap(); builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("zealand"); search.query("zealand");
search.limit(10); search.limit(10);
@@ -203,7 +211,8 @@ fn test_disable_typo_on_attribute() {
{ {
let txn = index.read_txn().unwrap(); let txn = index.read_txn().unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
// typo in `antebel(l)um` // typo in `antebel(l)um`
search.query("antebelum"); search.query("antebelum");
search.limit(10); search.limit(10);
@@ -222,7 +231,8 @@ fn test_disable_typo_on_attribute() {
builder.set_exact_attributes(vec!["description".to_string()].into_iter().collect()); builder.set_exact_attributes(vec!["description".to_string()].into_iter().collect());
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap(); builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
let mut search = Search::new(&txn, &index); let progress = Progress::default();
let mut search = Search::new(&txn, &index, &progress);
search.query("antebelum"); search.query("antebelum");
search.limit(10); search.limit(10);