mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-12-23 12:57:17 +00:00
Compare commits
1 Commits
main
...
log-search
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac76f243c7 |
@@ -172,7 +172,8 @@ pub fn run_benches(c: &mut criterion::Criterion, confs: &[Conf]) {
|
||||
|b, &query| {
|
||||
b.iter(|| {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
let mut search = index.search(&rtxn);
|
||||
let progress = Progress::default();
|
||||
let mut search = index.search(&rtxn, &progress);
|
||||
search
|
||||
.query(query)
|
||||
.terms_matching_strategy(TermsMatchingStrategy::default());
|
||||
|
||||
@@ -153,7 +153,8 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// 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();
|
||||
progression.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::time::Duration;
|
||||
|
||||
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 reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -346,9 +347,11 @@ impl PersonalizationService {
|
||||
personalize: &Personalize,
|
||||
query: Option<&str>,
|
||||
time_budget: TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<SearchResult, ResponseError> {
|
||||
match self {
|
||||
Self::Cohere(cohere_service) => {
|
||||
let _ = progress.update_progress_scoped(SearchStep::ApplyingPersonalization);
|
||||
cohere_service
|
||||
.rerank_search_results(search_result, personalize, query, time_budget)
|
||||
.await
|
||||
|
||||
@@ -30,7 +30,11 @@ use meilisearch_types::features::{
|
||||
use meilisearch_types::heed::RoTxn;
|
||||
use meilisearch_types::keys::actions;
|
||||
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 serde::Deserialize;
|
||||
use serde_json::json;
|
||||
@@ -262,6 +266,7 @@ async fn process_search_request(
|
||||
filter: Option<String>,
|
||||
) -> Result<(Index, Vec<Document>, String), ResponseError> {
|
||||
let index = index_scheduler.index(&index_uid)?;
|
||||
let progress = Progress::default();
|
||||
let rtxn = index.static_read_txn()?;
|
||||
let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?;
|
||||
let mut query = SearchQuery {
|
||||
@@ -285,7 +290,9 @@ async fn process_search_request(
|
||||
let search_kind =
|
||||
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?;
|
||||
progress.update_progress(TotalProcessingTimeStep::Searching);
|
||||
let features = index_scheduler.features();
|
||||
let index_cloned = index.clone();
|
||||
let output = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> {
|
||||
@@ -297,8 +304,15 @@ async fn process_search_request(
|
||||
None => TimeBudget::default(),
|
||||
};
|
||||
|
||||
let (search, _is_finite_pagination, _max_total_hits, _offset) =
|
||||
prepare_search(&index_cloned, &rtxn, &query, &search_kind, time_budget, features)?;
|
||||
let (search, _is_finite_pagination, _max_total_hits, _offset) = prepare_search(
|
||||
&index_cloned,
|
||||
&rtxn,
|
||||
&query,
|
||||
&search_kind,
|
||||
time_budget,
|
||||
features,
|
||||
&progress,
|
||||
)?;
|
||||
|
||||
match search_from_kind(index_uid, search_kind, search) {
|
||||
Ok((search_results, _)) => Ok((rtxn, Ok(search_results))),
|
||||
|
||||
@@ -8,7 +8,8 @@ use meilisearch_types::error::deserr_codes::*;
|
||||
use meilisearch_types::error::ResponseError;
|
||||
use meilisearch_types::index_uid::IndexUid;
|
||||
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 serde_json::Value;
|
||||
use tracing::debug;
|
||||
@@ -336,6 +337,10 @@ pub async fn search_with_url_query(
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
let request_uid = Uuid::now_v7();
|
||||
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 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
|
||||
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 progress_clone = progress.clone();
|
||||
let search_result = tokio::task::spawn_blocking(move || {
|
||||
perform_search(
|
||||
SearchParams {
|
||||
@@ -374,15 +379,21 @@ pub async fn search_with_url_query(
|
||||
include_metadata,
|
||||
},
|
||||
&index,
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
permit.drop().await;
|
||||
let search_result = search_result?;
|
||||
|
||||
let analytics_step =
|
||||
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
|
||||
if let Ok((search_result, _)) = search_result.as_ref() {
|
||||
aggregate.succeed(search_result);
|
||||
}
|
||||
analytics.publish(aggregate, &req);
|
||||
// early finish progress step
|
||||
drop(analytics_step);
|
||||
|
||||
let (mut search_result, time_budget) = search_result?;
|
||||
|
||||
@@ -394,11 +405,12 @@ pub async fn search_with_url_query(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.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))
|
||||
}
|
||||
|
||||
@@ -470,6 +482,11 @@ pub async fn search_with_post(
|
||||
let index_uid = IndexUid::try_from(index_uid.into_inner())?;
|
||||
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();
|
||||
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
|
||||
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 || {
|
||||
perform_search(
|
||||
SearchParams {
|
||||
@@ -507,11 +524,14 @@ pub async fn search_with_post(
|
||||
include_metadata,
|
||||
},
|
||||
&index,
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
permit.drop().await;
|
||||
let search_result = search_result?;
|
||||
let analytics_step =
|
||||
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
|
||||
if let Ok((ref search_result, _)) = search_result {
|
||||
aggregate.succeed(search_result);
|
||||
if search_result.degraded {
|
||||
@@ -519,6 +539,8 @@ pub async fn search_with_post(
|
||||
}
|
||||
}
|
||||
analytics.publish(aggregate, &req);
|
||||
// early finish progress step
|
||||
drop(analytics_step);
|
||||
|
||||
let (mut search_result, time_budget) = search_result?;
|
||||
|
||||
@@ -530,11 +552,12 @@ pub async fn search_with_post(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.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))
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ use meilisearch_types::error::deserr_codes::*;
|
||||
use meilisearch_types::error::ResponseError;
|
||||
use meilisearch_types::index_uid::IndexUid;
|
||||
use meilisearch_types::keys::actions;
|
||||
use meilisearch_types::milli::progress::Progress;
|
||||
use meilisearch_types::milli::TotalProcessingTimeStep;
|
||||
use meilisearch_types::serde_cs::vec::CS;
|
||||
use serde_json::Value;
|
||||
use tracing::debug;
|
||||
@@ -217,7 +219,7 @@ async fn similar(
|
||||
mut query: SimilarQuery,
|
||||
) -> Result<SimilarResult, ResponseError> {
|
||||
let retrieve_vectors = RetrieveVectors::new(query.retrieve_vectors);
|
||||
|
||||
let progress = Progress::default();
|
||||
// Tenant token search_rules.
|
||||
if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) {
|
||||
add_search_rules(&mut query.filter, search_rules);
|
||||
@@ -234,7 +236,10 @@ async fn 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(
|
||||
&index,
|
||||
query,
|
||||
@@ -243,9 +248,14 @@ async fn similar(
|
||||
quantized,
|
||||
retrieve_vectors,
|
||||
index_scheduler.features(),
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await?
|
||||
.await;
|
||||
|
||||
debug!(progress = ?progress.accumulated_durations(), "Similar");
|
||||
|
||||
result?
|
||||
}
|
||||
|
||||
#[derive(Debug, deserr::Deserr, IntoParams)]
|
||||
|
||||
@@ -6,6 +6,8 @@ use index_scheduler::IndexScheduler;
|
||||
use meilisearch_types::deserr::DeserrJsonError;
|
||||
use meilisearch_types::error::ResponseError;
|
||||
use meilisearch_types::keys::actions;
|
||||
use meilisearch_types::milli::progress::Progress;
|
||||
use meilisearch_types::milli::TotalProcessingTimeStep;
|
||||
use serde::Serialize;
|
||||
use tracing::debug;
|
||||
use utoipa::{OpenApi, ToSchema};
|
||||
@@ -153,7 +155,10 @@ pub async fn multi_search_with_post(
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
// 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.
|
||||
let progress = Progress::default();
|
||||
progress.update_progress(TotalProcessingTimeStep::WaitingForPermit);
|
||||
let permit = search_queue.try_get_search_permit().await?;
|
||||
progress.update_progress(TotalProcessingTimeStep::Searching);
|
||||
let request_uid = Uuid::now_v7();
|
||||
|
||||
let federated_search = params.into_inner();
|
||||
@@ -213,6 +218,7 @@ pub async fn multi_search_with_post(
|
||||
is_proxy,
|
||||
request_uid,
|
||||
include_metadata,
|
||||
&progress,
|
||||
)
|
||||
.await;
|
||||
permit.drop().await;
|
||||
@@ -288,6 +294,7 @@ pub async fn multi_search_with_post(
|
||||
.with_index(query_index)?;
|
||||
let retrieve_vector = RetrieveVectors::new(query.retrieve_vectors);
|
||||
|
||||
let progress_clone = progress.clone();
|
||||
let (mut search_result, time_budget) = tokio::task::spawn_blocking(move || {
|
||||
perform_search(
|
||||
SearchParams {
|
||||
@@ -300,6 +307,7 @@ pub async fn multi_search_with_post(
|
||||
include_metadata,
|
||||
},
|
||||
&index,
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await
|
||||
@@ -314,6 +322,7 @@ pub async fn multi_search_with_post(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.await
|
||||
.with_index(query_index)?;
|
||||
@@ -324,15 +333,19 @@ pub async fn multi_search_with_post(
|
||||
result: search_result,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(search_results)
|
||||
}
|
||||
.await;
|
||||
permit.drop().await;
|
||||
|
||||
let analytics_step =
|
||||
progress.update_progress_scoped(TotalProcessingTimeStep::PublishingAnalytics);
|
||||
if search_results.is_ok() {
|
||||
multi_aggregate.succeed();
|
||||
}
|
||||
analytics.publish(multi_aggregate, &req);
|
||||
drop(analytics_step);
|
||||
|
||||
let search_results = search_results.map_err(|(mut err, query_index)| {
|
||||
// Add the query index that failed as context for the error message.
|
||||
@@ -345,6 +358,7 @@ pub async fn multi_search_with_post(
|
||||
debug!(
|
||||
request_uid = ?request_uid,
|
||||
returns = ?search_results,
|
||||
progress = ?progress.accumulated_durations(),
|
||||
"Multi-search"
|
||||
);
|
||||
|
||||
|
||||
@@ -11,9 +11,13 @@ use index_scheduler::{IndexScheduler, RoFeatures};
|
||||
use itertools::Itertools;
|
||||
use meilisearch_types::error::ResponseError;
|
||||
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::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 roaring::RoaringBitmap;
|
||||
use tokio::task::JoinHandle;
|
||||
@@ -43,6 +47,7 @@ pub async fn perform_federated_search(
|
||||
is_proxy: bool,
|
||||
request_uid: Uuid,
|
||||
include_metadata: bool,
|
||||
progress: &Progress,
|
||||
) -> Result<FederatedSearchResult, ResponseError> {
|
||||
if is_proxy {
|
||||
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 {
|
||||
// note: this is the only place we open `index_uid`
|
||||
search_by_index.execute(index_uid, queries, ¶ms)?;
|
||||
search_by_index.execute(index_uid, queries, ¶ms, 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.
|
||||
@@ -126,6 +131,8 @@ pub async fn perform_federated_search(
|
||||
facet_order,
|
||||
} = search_by_index;
|
||||
|
||||
progress.update_progress(SearchStep::FederatingResults);
|
||||
progress.update_progress(FederatingResultsStep::WaitingForRemoteResults);
|
||||
let before_waiting_remote_results = std::time::Instant::now();
|
||||
|
||||
// 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();
|
||||
|
||||
// 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
|
||||
let query_metadata = precomputed_query_metadata.map(|precomputed_query_metadata| {
|
||||
// If a remote is present, set the local remote name
|
||||
@@ -187,6 +194,7 @@ pub async fn perform_federated_search(
|
||||
};
|
||||
|
||||
// 3.5. merge facets
|
||||
progress.update_progress(FederatingResultsStep::MergingFacets);
|
||||
let (facet_distribution, facet_stats, facets_by_index) =
|
||||
facet_order.merge(federation.merge_facets, remote_results, facets);
|
||||
|
||||
@@ -831,6 +839,7 @@ impl SearchByIndex {
|
||||
index_uid: String,
|
||||
queries: Vec<QueryByIndex>,
|
||||
params: &SearchByIndexParams<'_>,
|
||||
progress: &Progress,
|
||||
) -> Result<(), ResponseError> {
|
||||
let first_query_index = queries.first().map(|query| query.query_index);
|
||||
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
|
||||
time_budget.clone(),
|
||||
params.features,
|
||||
progress,
|
||||
)?;
|
||||
|
||||
search.scoring_strategy(milli::score_details::ScoringStrategy::Detailed);
|
||||
@@ -1044,7 +1054,7 @@ impl SearchByIndex {
|
||||
hit_maker,
|
||||
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 mut _federation = serde_json::json!(
|
||||
|
||||
@@ -17,11 +17,13 @@ use meilisearch_types::heed::RoTxn;
|
||||
use meilisearch_types::index_uid::IndexUid;
|
||||
use meilisearch_types::locales::Locale;
|
||||
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::vector::parsed_vectors::ExplicitVectors;
|
||||
use meilisearch_types::milli::vector::Embedder;
|
||||
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::{milli, Document};
|
||||
@@ -1024,11 +1026,13 @@ pub fn prepare_search<'t>(
|
||||
search_kind: &SearchKind,
|
||||
time_budget: TimeBudget,
|
||||
features: RoFeatures,
|
||||
progress: &'t Progress,
|
||||
) -> Result<(milli::Search<'t>, bool, usize, usize), ResponseError> {
|
||||
let _step = progress.update_progress_scoped(SearchStep::PreparingSearch);
|
||||
if query.media.is_some() {
|
||||
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);
|
||||
if let Some(ranking_score_threshold) = query.ranking_score_threshold {
|
||||
search.ranking_score_threshold(ranking_score_threshold.0);
|
||||
@@ -1048,6 +1052,7 @@ pub fn prepare_search<'t>(
|
||||
let vector = match query.vector.clone() {
|
||||
Some(vector) => vector,
|
||||
None => {
|
||||
let _ = progress.update_progress_scoped(SearchStep::EmbeddingQuery);
|
||||
let span = tracing::trace_span!(target: "search::vector", "embed_one");
|
||||
let _entered = span.enter();
|
||||
|
||||
@@ -1061,6 +1066,7 @@ pub fn prepare_search<'t>(
|
||||
(q, media) => milli::vector::SearchQuery::Media { q, media },
|
||||
};
|
||||
|
||||
|
||||
embedder
|
||||
.embed_search(search_query, Some(deadline))
|
||||
.map_err(milli::vector::Error::from)
|
||||
@@ -1173,6 +1179,7 @@ pub struct SearchParams {
|
||||
pub fn perform_search(
|
||||
params: SearchParams,
|
||||
index: &Index,
|
||||
progress: &Progress,
|
||||
) -> Result<(SearchResult, TimeBudget), ResponseError> {
|
||||
let SearchParams {
|
||||
index_uid,
|
||||
@@ -1191,8 +1198,15 @@ pub fn perform_search(
|
||||
None => TimeBudget::default(),
|
||||
};
|
||||
|
||||
let (search, is_finite_pagination, max_total_hits, offset) =
|
||||
prepare_search(index, &rtxn, &query, &search_kind, time_budget.clone(), features)?;
|
||||
let (search, is_finite_pagination, max_total_hits, offset) = prepare_search(
|
||||
index,
|
||||
&rtxn,
|
||||
&query,
|
||||
&search_kind,
|
||||
time_budget.clone(),
|
||||
features,
|
||||
progress,
|
||||
)?;
|
||||
|
||||
let (
|
||||
milli::SearchResult {
|
||||
@@ -1253,6 +1267,7 @@ pub fn perform_search(
|
||||
personalize: _,
|
||||
} = query;
|
||||
|
||||
progress.update_progress(SearchStep::FormattingResults);
|
||||
let format = AttributesFormat {
|
||||
attributes_to_retrieve,
|
||||
retrieve_vectors,
|
||||
@@ -1275,6 +1290,7 @@ pub fn perform_search(
|
||||
format,
|
||||
matching_words,
|
||||
documents_ids.iter().copied().zip(document_scores.iter()),
|
||||
progress,
|
||||
)?;
|
||||
|
||||
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
|
||||
.map(move |facets| {
|
||||
let _ = progress.update_progress_scoped(SearchStep::ComputingFacetDistribution);
|
||||
compute_facet_distribution_stats(&facets, index, &rtxn, candidates, Route::Search)
|
||||
})
|
||||
.transpose()?
|
||||
.map(|ComputedFacets { distribution, stats }| (distribution, stats))
|
||||
.unzip();
|
||||
|
||||
let result = SearchResult {
|
||||
hits: documents,
|
||||
hits_info,
|
||||
@@ -1316,6 +1334,7 @@ pub fn perform_search(
|
||||
request_uid: Some(request_uid),
|
||||
metadata,
|
||||
};
|
||||
|
||||
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) =
|
||||
self.index.iter_documents(self.rtxn, std::iter::once(id))?.next().unwrap()?;
|
||||
|
||||
@@ -1669,6 +1694,7 @@ fn make_hits<'a>(
|
||||
format: AttributesFormat,
|
||||
matching_words: milli::MatchingWords,
|
||||
documents_ids_scores: impl Iterator<Item = (u32, &'a Vec<ScoreDetails>)> + 'a,
|
||||
progress: &Progress,
|
||||
) -> milli::Result<Vec<SearchHit>> {
|
||||
let mut documents = Vec::new();
|
||||
|
||||
@@ -1686,7 +1712,7 @@ fn make_hits<'a>(
|
||||
let hit_maker = HitMaker::new(index, rtxn, format, formatter_builder)?;
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1701,6 +1727,7 @@ pub fn perform_facet_search(
|
||||
locales: Option<Vec<Language>>,
|
||||
) -> Result<FacetSearchResult, ResponseError> {
|
||||
let before_search = Instant::now();
|
||||
let progress = Progress::default();
|
||||
let rtxn = index.read_txn()?;
|
||||
let time_budget = match index.search_cutoff(&rtxn)? {
|
||||
Some(cutoff) => TimeBudget::new(Duration::from_millis(cutoff)),
|
||||
@@ -1729,8 +1756,15 @@ pub fn perform_facet_search(
|
||||
.collect()
|
||||
});
|
||||
|
||||
let (search, _, _, _) =
|
||||
prepare_search(index, &rtxn, &search_query, &search_kind, time_budget, features)?;
|
||||
let (search, _, _, _) = prepare_search(
|
||||
index,
|
||||
&rtxn,
|
||||
&search_query,
|
||||
&search_kind,
|
||||
time_budget,
|
||||
features,
|
||||
&progress,
|
||||
)?;
|
||||
let mut facet_search = SearchForFacetValues::new(
|
||||
facet_name,
|
||||
search,
|
||||
@@ -1762,6 +1796,7 @@ pub fn perform_similar(
|
||||
quantized: bool,
|
||||
retrieve_vectors: RetrieveVectors,
|
||||
features: RoFeatures,
|
||||
progress: &Progress,
|
||||
) -> Result<SimilarResult, ResponseError> {
|
||||
let before_search = Instant::now();
|
||||
let rtxn = index.read_txn()?;
|
||||
@@ -1851,6 +1886,7 @@ pub fn perform_similar(
|
||||
format,
|
||||
Default::default(),
|
||||
documents_ids.iter().copied().zip(document_scores.iter()),
|
||||
progress,
|
||||
)?;
|
||||
|
||||
let max_total_hits = index
|
||||
|
||||
@@ -28,6 +28,7 @@ use crate::heed_codec::facet::{
|
||||
use crate::heed_codec::version::VersionCodec;
|
||||
use crate::heed_codec::{BEU16StrCodec, FstSetCodec, StrBEU16Codec, StrRefCodec};
|
||||
use crate::order_by_map::OrderByMap;
|
||||
use crate::progress::Progress;
|
||||
use crate::prompt::PromptData;
|
||||
use crate::proximity::ProximityPrecision;
|
||||
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
|
||||
/// (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> {
|
||||
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
|
||||
.main
|
||||
.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.
|
||||
pub fn fields_ids_map_with_metadata(&self, rtxn: &RoTxn<'_>) -> Result<FieldIdMapWithMetadata> {
|
||||
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)?,
|
||||
))
|
||||
}
|
||||
@@ -1477,8 +1488,8 @@ impl Index {
|
||||
FacetDistribution::new(rtxn, self)
|
||||
}
|
||||
|
||||
pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>) -> Search<'a> {
|
||||
Search::new(rtxn, self)
|
||||
pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>, progress: &'a Progress) -> Search<'a> {
|
||||
Search::new(rtxn, self, progress)
|
||||
}
|
||||
|
||||
/// Returns the index creation time.
|
||||
|
||||
@@ -81,6 +81,7 @@ pub use self::index::Index;
|
||||
pub use self::localized_attributes_rules::LocalizedAttributesRule;
|
||||
pub use self::search::facet::{FacetValueHit, SearchForFacetValues};
|
||||
pub use self::search::similar::Similar;
|
||||
pub use self::search::steps::{FederatingResultsStep, SearchStep, TotalProcessingTimeStep};
|
||||
pub use self::search::{
|
||||
FacetDistribution, Filter, FormatOptions, MatchBounds, MatcherBuilder, MatchingWords, OrderBy,
|
||||
Search, SearchResult, SemanticSearch, TermsMatchingStrategy, DEFAULT_VALUES_PER_FACET,
|
||||
|
||||
@@ -64,6 +64,30 @@ impl Progress {
|
||||
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
|
||||
pub fn as_progress_view(&self) -> ProgressView {
|
||||
let inner = self.steps.read().unwrap();
|
||||
@@ -95,7 +119,15 @@ impl Progress {
|
||||
let now = Instant::now();
|
||||
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
|
||||
@@ -343,3 +375,14 @@ impl<T: steppe::Step> Step for Compat<T> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,7 +1165,7 @@ mod tests {
|
||||
|
||||
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
|
||||
search.filter(Filter::from_str("monitor_diagonal = '27\" to 30\\''").unwrap().unwrap());
|
||||
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
@@ -1225,7 +1225,7 @@ mod tests {
|
||||
|
||||
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());
|
||||
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
|
||||
@@ -6,6 +6,7 @@ use roaring::RoaringBitmap;
|
||||
|
||||
use crate::score_details::{ScoreDetails, ScoreValue, ScoringStrategy};
|
||||
use crate::search::new::{distinct_fid, distinct_single_docid};
|
||||
use crate::search::steps::SearchStep;
|
||||
use crate::search::SemanticSearch;
|
||||
use crate::vector::{Embedding, SearchQuery};
|
||||
use crate::{Index, MatchingWords, Result, Search, SearchResult};
|
||||
@@ -221,6 +222,7 @@ impl Search<'_> {
|
||||
time_budget: self.time_budget.clone(),
|
||||
ranking_score_threshold: self.ranking_score_threshold,
|
||||
locales: self.locales.clone(),
|
||||
progress: self.progress,
|
||||
};
|
||||
|
||||
let semantic = search.semantic.take();
|
||||
@@ -241,6 +243,7 @@ impl Search<'_> {
|
||||
Some(vector_query) => vector_query,
|
||||
None => {
|
||||
// attempt to embed the vector
|
||||
self.progress.update_progress(SearchStep::EmbeddingQuery);
|
||||
let span = tracing::trace_span!(target: "search::hybrid", "embed_one");
|
||||
let _entered = span.enter();
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ use self::new::{execute_vector_search, PartialSearchResult, VectorStoreStats};
|
||||
use crate::documents::GeoSortParameter;
|
||||
use crate::filterable_attributes_rules::{filtered_matching_patterns, matching_features};
|
||||
use crate::index::MatchingStrategy;
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||
use crate::search::steps::SearchStep;
|
||||
use crate::vector::{Embedder, Embedding};
|
||||
use crate::{
|
||||
execute_search, filtered_universe, AscDesc, DefaultSearchLogger, DocumentId, Error, Index,
|
||||
@@ -29,6 +31,7 @@ mod fst_utils;
|
||||
pub mod hybrid;
|
||||
pub mod new;
|
||||
pub mod similar;
|
||||
pub mod steps;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SemanticSearch {
|
||||
@@ -61,10 +64,11 @@ pub struct Search<'a> {
|
||||
time_budget: TimeBudget,
|
||||
ranking_score_threshold: Option<f64>,
|
||||
locales: Option<Vec<Language>>,
|
||||
progress: &'a Progress,
|
||||
}
|
||||
|
||||
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 {
|
||||
query: None,
|
||||
filter: None,
|
||||
@@ -86,6 +90,7 @@ impl<'a> Search<'a> {
|
||||
locales: None,
|
||||
time_budget: TimeBudget::max(),
|
||||
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> {
|
||||
if has_vector_search {
|
||||
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 {
|
||||
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 PartialSearchResult {
|
||||
located_query_terms,
|
||||
candidates,
|
||||
@@ -276,6 +282,7 @@ impl<'a> Search<'a> {
|
||||
*quantized,
|
||||
self.time_budget.clone(),
|
||||
self.ranking_score_threshold,
|
||||
self.progress,
|
||||
)?
|
||||
}
|
||||
_ => execute_search(
|
||||
@@ -297,6 +304,7 @@ impl<'a> Search<'a> {
|
||||
self.time_budget.clone(),
|
||||
self.ranking_score_threshold,
|
||||
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}");
|
||||
}
|
||||
|
||||
self.progress.update_progress(SearchStep::FormattingResults);
|
||||
// consume context and located_query_terms to build MatchingWords.
|
||||
let matching_words = match located_query_terms {
|
||||
Some(located_query_terms) => MatchingWords::new(ctx, located_query_terms),
|
||||
@@ -347,6 +356,7 @@ impl fmt::Debug for Search<'_> {
|
||||
time_budget,
|
||||
ranking_score_threshold,
|
||||
locales,
|
||||
progress: _,
|
||||
} = self;
|
||||
f.debug_struct("Search")
|
||||
.field("query", query)
|
||||
|
||||
@@ -3,10 +3,12 @@ use roaring::RoaringBitmap;
|
||||
use super::logger::SearchLogger;
|
||||
use super::ranking_rules::{BoxRankingRule, RankingRuleQueryTrait};
|
||||
use super::SearchContext;
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||
use crate::search::new::distinct::{
|
||||
apply_distinct_rule, distinct_fid, distinct_single_docid, DistinctOutput,
|
||||
};
|
||||
use crate::search::steps::{ComputingBucketSortStep, SearchStep};
|
||||
use crate::{Result, TimeBudget};
|
||||
|
||||
pub struct BucketSortOutput {
|
||||
@@ -34,7 +36,9 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
ranking_score_threshold: Option<f64>,
|
||||
exhaustive_number_hits: bool,
|
||||
max_total_hits: Option<usize>,
|
||||
progress: &Progress,
|
||||
) -> Result<BucketSortOutput> {
|
||||
let _step = progress.update_progress_scoped(SearchStep::ComputingBucketSort);
|
||||
logger.initial_query(query);
|
||||
logger.ranking_rules(&ranking_rules);
|
||||
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();
|
||||
|
||||
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];
|
||||
ranking_rule_universes[0].clone_from(universe);
|
||||
let mut cur_ranking_rule_index = 0;
|
||||
drop(step);
|
||||
|
||||
/// Finish iterating over the current ranking rule, yielding
|
||||
/// control to the parent (or finishing the search if not possible).
|
||||
@@ -157,6 +163,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
distinct_fid,
|
||||
&ranking_rule_scores,
|
||||
$candidates,
|
||||
progress,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
@@ -185,6 +192,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
ctx,
|
||||
logger,
|
||||
&ranking_rule_universes[cur_ranking_rule_index],
|
||||
progress,
|
||||
)? {
|
||||
std::task::Poll::Ready(bucket) => bucket,
|
||||
std::task::Poll::Pending => {
|
||||
@@ -231,6 +239,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
logger,
|
||||
&ranking_rule_universes[cur_ranking_rule_index],
|
||||
&time_budget,
|
||||
progress,
|
||||
)?
|
||||
else {
|
||||
back!();
|
||||
@@ -323,9 +332,11 @@ fn maybe_add_to_results<'ctx, Q: RankingRuleQueryTrait>(
|
||||
distinct_fid: Option<u16>,
|
||||
ranking_rule_scores: &[ScoreDetails],
|
||||
candidates: RoaringBitmap,
|
||||
progress: &Progress,
|
||||
) -> Result<()> {
|
||||
// First apply the distinct rule on the candidates, reducing the universes if necessary
|
||||
let candidates = if let Some(distinct_fid) = distinct_fid {
|
||||
progress.update_progress(ComputingBucketSortStep::ApplyingDistinctRule);
|
||||
let DistinctOutput { remaining, excluded } =
|
||||
apply_distinct_rule(ctx, distinct_fid, &candidates)?;
|
||||
for universe in ranking_rule_universes.iter_mut() {
|
||||
@@ -336,6 +347,8 @@ fn maybe_add_to_results<'ctx, Q: RankingRuleQueryTrait>(
|
||||
} else {
|
||||
candidates.clone()
|
||||
};
|
||||
|
||||
progress.update_progress(ComputingBucketSortStep::MergingCandidates);
|
||||
*all_candidates |= &candidates;
|
||||
|
||||
// if the candidates are empty, there is nothing to do;
|
||||
|
||||
@@ -3,9 +3,12 @@ use roaring::{MultiOps, RoaringBitmap};
|
||||
|
||||
use super::query_graph::QueryGraph;
|
||||
use super::ranking_rules::{RankingRule, RankingRuleOutput};
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::{self, ScoreDetails};
|
||||
use crate::search::new::query_graph::QueryNodeData;
|
||||
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};
|
||||
|
||||
/// A ranking rule that produces 3 disjoint buckets:
|
||||
@@ -24,8 +27,8 @@ impl ExactAttribute {
|
||||
}
|
||||
|
||||
impl<'ctx> RankingRule<'ctx, QueryGraph> for ExactAttribute {
|
||||
fn id(&self) -> String {
|
||||
"exact_attribute".to_owned()
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::Exactness
|
||||
}
|
||||
|
||||
#[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>,
|
||||
universe: &roaring::RoaringBitmap,
|
||||
_time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<Option<RankingRuleOutput<QueryGraph>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
let state = std::mem::take(&mut self.state);
|
||||
let (state, output) = State::next(state, universe);
|
||||
self.state = state;
|
||||
|
||||
@@ -6,7 +6,10 @@ use rstar::RTree;
|
||||
use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait};
|
||||
use crate::documents::geo_sort::{fill_cache, next_bucket};
|
||||
use crate::documents::{GeoSortParameter, GeoSortStrategy};
|
||||
use crate::progress::Progress;
|
||||
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};
|
||||
|
||||
pub struct GeoSort<Q: RankingRuleQueryTrait> {
|
||||
@@ -73,8 +76,8 @@ impl<Q: RankingRuleQueryTrait> GeoSort<Q> {
|
||||
}
|
||||
|
||||
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for GeoSort<Q> {
|
||||
fn id(&self) -> String {
|
||||
"geo_sort".to_owned()
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::GeoSort
|
||||
}
|
||||
|
||||
#[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>,
|
||||
universe: &RoaringBitmap,
|
||||
_time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<Option<RankingRuleOutput<Q>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
let query = self.query.as_ref().unwrap().clone();
|
||||
|
||||
next_bucket(
|
||||
|
||||
@@ -50,51 +50,54 @@ use super::ranking_rule_graph::{
|
||||
};
|
||||
use super::small_bitmap::SmallBitmap;
|
||||
use super::{QueryGraph, RankingRule, RankingRuleOutput, SearchContext};
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::Rank;
|
||||
use crate::search::new::query_term::LocatedQueryTermSubset;
|
||||
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};
|
||||
|
||||
pub type Words = GraphBasedRankingRule<WordsGraph>;
|
||||
impl GraphBasedRankingRule<WordsGraph> {
|
||||
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>;
|
||||
impl GraphBasedRankingRule<ProximityGraph> {
|
||||
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>;
|
||||
impl GraphBasedRankingRule<FidGraph> {
|
||||
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>;
|
||||
impl GraphBasedRankingRule<PositionGraph> {
|
||||
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>;
|
||||
impl GraphBasedRankingRule<TypoGraph> {
|
||||
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>;
|
||||
impl GraphBasedRankingRule<ExactnessGraph> {
|
||||
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
|
||||
pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
|
||||
id: String,
|
||||
id: RankingRuleId,
|
||||
terms_matching_strategy: Option<TermsMatchingStrategy>,
|
||||
// When the ranking rule is not iterating over its buckets,
|
||||
// its state is `None`.
|
||||
@@ -102,7 +105,10 @@ pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
|
||||
}
|
||||
impl<G: RankingRuleGraphTrait> GraphBasedRankingRule<G> {
|
||||
/// 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 }
|
||||
}
|
||||
}
|
||||
@@ -124,7 +130,7 @@ pub struct GraphBasedRankingRuleState<G: RankingRuleGraphTrait> {
|
||||
}
|
||||
|
||||
impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBasedRankingRule<G> {
|
||||
fn id(&self) -> String {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
@@ -219,7 +225,9 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
|
||||
logger: &mut dyn SearchLogger<QueryGraph>,
|
||||
universe: &RoaringBitmap,
|
||||
_time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> 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`,
|
||||
// should never happen
|
||||
let mut state = self.state.take().unwrap();
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::search::new::ranking_rule_graph::{
|
||||
ProximityGraph, RankingRuleGraph, RankingRuleGraphTrait, TypoCondition, TypoGraph,
|
||||
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::Result;
|
||||
|
||||
@@ -45,13 +45,26 @@ enum Location {
|
||||
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)]
|
||||
pub struct VisualSearchLogger {
|
||||
initial_query: Option<QueryGraph>,
|
||||
initial_query_time: Option<Instant>,
|
||||
query_for_universe: Option<QueryGraph>,
|
||||
initial_universe: Option<RoaringBitmap>,
|
||||
ranking_rules_ids: Option<Vec<String>>,
|
||||
ranking_rules_ids: Option<Vec<RankingRuleId>>,
|
||||
events: Vec<SearchEvents>,
|
||||
location: Vec<Location>,
|
||||
}
|
||||
@@ -84,14 +97,7 @@ impl SearchLogger<QueryGraph> for VisualSearchLogger {
|
||||
ranking_rule_idx,
|
||||
universe_len: universe.len(),
|
||||
});
|
||||
self.location.push(match ranking_rule.id().as_str() {
|
||||
"words" => Location::Words,
|
||||
"typo" => Location::Typo,
|
||||
"proximity" => Location::Proximity,
|
||||
"fid" => Location::Fid,
|
||||
"position" => Location::Position,
|
||||
_ => Location::Other,
|
||||
});
|
||||
self.location.push(ranking_rule.id().into());
|
||||
}
|
||||
|
||||
fn next_bucket_ranking_rule(
|
||||
|
||||
@@ -498,12 +498,14 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::progress::Progress;
|
||||
use crate::{execute_search, filtered_universe, SearchContext, TimeBudget};
|
||||
|
||||
impl<'a> MatcherBuilder<'a> {
|
||||
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 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(
|
||||
&mut ctx,
|
||||
Some(query),
|
||||
@@ -523,6 +525,7 @@ mod tests {
|
||||
TimeBudget::max(),
|
||||
None,
|
||||
None,
|
||||
&progress,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -56,8 +56,10 @@ use crate::constants::RESERVED_GEO_FIELD_NAME;
|
||||
use crate::documents::GeoSortParameter;
|
||||
use crate::index::PrefixSearch;
|
||||
use crate::localized_attributes_rules::LocalizedFieldIds;
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||
use crate::search::new::distinct::apply_distinct_rule;
|
||||
use crate::search::steps::SearchStep;
|
||||
use crate::vector::Embedder;
|
||||
use crate::{
|
||||
AscDesc, DocumentId, FieldId, Filter, Index, Member, Result, TermsMatchingStrategy, TimeBudget,
|
||||
@@ -294,7 +296,9 @@ fn resolve_universe(
|
||||
query_graph: &QueryGraph,
|
||||
matching_strategy: TermsMatchingStrategy,
|
||||
logger: &mut dyn SearchLogger<QueryGraph>,
|
||||
progress: &Progress,
|
||||
) -> Result<RoaringBitmap> {
|
||||
let _step = progress.update_progress_scoped(SearchStep::ResolvingUniverse);
|
||||
resolve_maximally_reduced_query_graph(
|
||||
ctx,
|
||||
initial_universe,
|
||||
@@ -632,8 +636,10 @@ pub fn filtered_universe(
|
||||
index: &Index,
|
||||
txn: &RoTxn<'_>,
|
||||
filters: &Option<Filter<'_>>,
|
||||
progress: &Progress,
|
||||
) -> Result<RoaringBitmap> {
|
||||
Ok(if let Some(filters) = filters {
|
||||
let _step = progress.update_progress_scoped(SearchStep::ComputingFilter);
|
||||
filters.evaluate(txn, index)?
|
||||
} else {
|
||||
index.documents_ids(txn)?
|
||||
@@ -658,6 +664,7 @@ pub fn execute_vector_search(
|
||||
quantized: bool,
|
||||
time_budget: TimeBudget,
|
||||
ranking_score_threshold: Option<f64>,
|
||||
progress: &Progress,
|
||||
) -> Result<PartialSearchResult> {
|
||||
check_sort_criteria(ctx, sort_criteria.as_ref())?;
|
||||
|
||||
@@ -692,6 +699,7 @@ pub fn execute_vector_search(
|
||||
ranking_score_threshold,
|
||||
exhaustive_number_hits,
|
||||
max_total_hits,
|
||||
progress,
|
||||
)?;
|
||||
|
||||
Ok(PartialSearchResult {
|
||||
@@ -725,12 +733,14 @@ pub fn execute_search(
|
||||
time_budget: TimeBudget,
|
||||
ranking_score_threshold: Option<f64>,
|
||||
locales: Option<&Vec<Language>>,
|
||||
progress: &Progress,
|
||||
) -> Result<PartialSearchResult> {
|
||||
check_sort_criteria(ctx, sort_criteria.as_ref())?;
|
||||
|
||||
let mut used_negative_operator = false;
|
||||
let mut located_query_terms = None;
|
||||
let query_terms = if let Some(query) = query {
|
||||
progress.update_progress(SearchStep::TokenizingQuery);
|
||||
let span = tracing::trace_span!(target: "search::tokens", "tokenizer_builder");
|
||||
let entered = span.enter();
|
||||
|
||||
@@ -834,8 +844,14 @@ pub fn execute_search(
|
||||
terms_matching_strategy,
|
||||
)?;
|
||||
|
||||
universe &=
|
||||
resolve_universe(ctx, &universe, &graph, terms_matching_strategy, query_graph_logger)?;
|
||||
universe &= resolve_universe(
|
||||
ctx,
|
||||
&universe,
|
||||
&graph,
|
||||
terms_matching_strategy,
|
||||
query_graph_logger,
|
||||
progress,
|
||||
)?;
|
||||
|
||||
bucket_sort(
|
||||
ctx,
|
||||
@@ -851,6 +867,7 @@ pub fn execute_search(
|
||||
ranking_score_threshold,
|
||||
exhaustive_number_hits,
|
||||
max_total_hits,
|
||||
progress,
|
||||
)?
|
||||
} else {
|
||||
let ranking_rules =
|
||||
@@ -869,6 +886,7 @@ pub fn execute_search(
|
||||
ranking_score_threshold,
|
||||
exhaustive_number_hits,
|
||||
max_total_hits,
|
||||
progress,
|
||||
)?
|
||||
};
|
||||
|
||||
|
||||
@@ -59,19 +59,19 @@ impl RankingRuleGraphTrait for FidGraph {
|
||||
let mut all_fields = FxHashSet::default();
|
||||
let mut current_max_weight = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
for phrase in term.term_subset.all_phrases(ctx)? {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ use roaring::RoaringBitmap;
|
||||
|
||||
use super::logger::SearchLogger;
|
||||
use super::{QueryGraph, SearchContext};
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::ScoreDetails;
|
||||
use crate::search::steps::ComputingBucketSortStep;
|
||||
use crate::{Result, TimeBudget};
|
||||
|
||||
/// 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
|
||||
/// can be either [`PlaceholderQuery`] or [`QueryGraph`].
|
||||
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
|
||||
/// buckets using [`next_bucket`](RankingRule::next_bucket).
|
||||
@@ -56,6 +58,7 @@ pub trait RankingRule<'ctx, Query: RankingRuleQueryTrait> {
|
||||
logger: &mut dyn SearchLogger<Query>,
|
||||
universe: &RoaringBitmap,
|
||||
time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<Option<RankingRuleOutput<Query>>>;
|
||||
|
||||
/// 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>,
|
||||
_logger: &mut dyn SearchLogger<Query>,
|
||||
_universe: &RoaringBitmap,
|
||||
progress: &Progress,
|
||||
) -> Result<Poll<RankingRuleOutput<Query>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
Ok(Poll::Pending)
|
||||
}
|
||||
|
||||
@@ -93,3 +98,54 @@ pub struct RankingRuleOutput<Q> {
|
||||
/// The score for the candidates of the current bucket
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ use super::logger::SearchLogger;
|
||||
use super::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait, SearchContext};
|
||||
use crate::heed_codec::facet::{FacetGroupKeyCodec, OrderedF64Codec};
|
||||
use crate::heed_codec::{BytesRefCodec, StrRefCodec};
|
||||
use crate::progress::Progress;
|
||||
use crate::score_details::{self, ScoreDetails};
|
||||
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};
|
||||
|
||||
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> {
|
||||
fn id(&self) -> String {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
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")]
|
||||
@@ -196,7 +203,9 @@ impl<'ctx, Query: RankingRuleQueryTrait> RankingRule<'ctx, Query> for Sort<'ctx,
|
||||
_logger: &mut dyn SearchLogger<Query>,
|
||||
universe: &RoaringBitmap,
|
||||
_time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<Option<RankingRuleOutput<Query>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
let iter = self.iter.as_mut().unwrap();
|
||||
if let Some(mut bucket) = iter.next_bucket()? {
|
||||
bucket.candidates &= universe;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::{db_snap, Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{db_snap, Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -119,7 +119,7 @@ fn test_attribute_fid_simple() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -147,7 +147,7 @@ fn test_attribute_fid_ngrams() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::{db_snap, Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{db_snap, Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -134,7 +134,7 @@ fn test_attribute_position_simple() {
|
||||
|
||||
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.query("quick brown");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -150,7 +150,7 @@ fn test_attribute_position_repeated() {
|
||||
|
||||
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.query("a a a a a");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("quick brown");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -184,7 +184,7 @@ fn test_attribute_position_ngrams() {
|
||||
|
||||
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.query("quick brown");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||
use crate::update::Setting;
|
||||
use crate::vector::settings::EmbeddingSettings;
|
||||
use crate::vector::{Embedder, EmbedderOptions};
|
||||
use crate::{Criterion, Filter, FilterableAttributesRule, Search, TimeBudget};
|
||||
use crate::{Criterion, Filter, FilterableAttributesRule, TimeBudget};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -61,7 +61,7 @@ fn basic_degraded_search() {
|
||||
let index = create_index();
|
||||
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.limit(3);
|
||||
search.time_budget(TimeBudget::new(Duration::from_millis(0)));
|
||||
@@ -75,7 +75,7 @@ fn degraded_search_cannot_skip_filter() {
|
||||
let index = create_index();
|
||||
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.limit(100);
|
||||
search.time_budget(TimeBudget::new(Duration::from_millis(0)));
|
||||
@@ -96,7 +96,7 @@ fn degraded_search_and_score_details() {
|
||||
let index = create_index();
|
||||
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.limit(4);
|
||||
search.scoring_strategy(ScoringStrategy::Detailed);
|
||||
@@ -560,7 +560,7 @@ fn degraded_search_and_score_details_vector() {
|
||||
.unwrap();
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
let mut search = index.search(&rtxn);
|
||||
|
||||
let embedder = Arc::new(
|
||||
Embedder::new(
|
||||
|
||||
@@ -20,7 +20,7 @@ use maplit::hashset;
|
||||
use super::collect_field_values;
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::{
|
||||
AscDesc, Criterion, FilterableAttributesRule, Index, Member, Search, SearchResult,
|
||||
AscDesc, Criterion, FilterableAttributesRule, Index, Member, SearchResult,
|
||||
TermsMatchingStrategy,
|
||||
};
|
||||
|
||||
@@ -246,7 +246,7 @@ fn test_distinct_placeholder_no_ranking_rules() {
|
||||
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.distinct(S("letter"));
|
||||
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]");
|
||||
@@ -275,7 +275,7 @@ fn test_distinct_at_search_placeholder_no_ranking_rules() {
|
||||
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let s = Search::new(&txn, &index);
|
||||
let s = index.search(&txn);
|
||||
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]");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]);
|
||||
|
||||
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")))]);
|
||||
|
||||
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![
|
||||
AscDesc::Desc(Member::Field(S("letter"))),
|
||||
AscDesc::Desc(Member::Field(S("rank1"))),
|
||||
@@ -443,7 +443,7 @@ fn test_distinct_words() {
|
||||
|
||||
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.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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("the quick brown fox jumps over the lazy dog");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank1")))]);
|
||||
s.exhaustive_number_hits(true);
|
||||
@@ -592,7 +592,7 @@ fn test_distinct_typo() {
|
||||
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ This module tests the following properties about the exactness ranking rule:
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
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 {
|
||||
let index = TempIndex::new();
|
||||
@@ -471,7 +471,7 @@ fn test_exactness_simple_ordered() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -503,7 +503,7 @@ fn test_exactness_simple_reversed() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -556,7 +556,7 @@ fn test_exactness_simple_random() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("this balcony");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("\"overlooking the sea\" is a beautiful balcony");
|
||||
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.query("overlooking the sea is a beautiful balcony");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("overlocking the sea is a beautiful balcony");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -696,7 +696,7 @@ fn test_exactness_after_words() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -744,7 +744,7 @@ fn test_words_after_exactness() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -792,7 +792,7 @@ fn test_proximity_after_exactness() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -829,7 +829,7 @@ fn test_proximity_after_exactness() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("quick brown fox extra");
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.query("extraordinarily quick brown fox");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -82,7 +82,7 @@ fn test_geo_sort() {
|
||||
|
||||
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.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 mut s = Search::new(&rtxn, &index);
|
||||
let mut s = index.search(&rtxn);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![
|
||||
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 mut s = Search::new(&rtxn, &index);
|
||||
let mut s = index.search(&rtxn);
|
||||
s.geo_max_bucket_size(2);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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 mut s = Search::new(&rtxn, &index);
|
||||
let mut s = index.search(&rtxn);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
// --- asc
|
||||
@@ -295,7 +295,7 @@ fn geo_sort_mixed_with_words() {
|
||||
|
||||
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.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 mut s = Search::new(&rtxn, &index);
|
||||
let mut s = index.search(&rtxn);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Asc(Member::Geo([0., 0.]))]);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::{Search, SearchResult};
|
||||
use crate::SearchResult;
|
||||
|
||||
#[test]
|
||||
fn test_kanji_language_detection() {
|
||||
@@ -14,7 +14,7 @@ fn test_kanji_language_detection() {
|
||||
.unwrap();
|
||||
|
||||
let txn = index.write_txn().unwrap();
|
||||
let mut search = Search::new(&txn, &index);
|
||||
let mut search = index.search(&txn);
|
||||
|
||||
search.query("東京");
|
||||
let SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
|
||||
@@ -19,7 +19,7 @@ This module tests the following properties:
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -78,7 +78,7 @@ fn test_2gram_simple() {
|
||||
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("sun flower");
|
||||
@@ -109,7 +109,7 @@ fn test_3gram_simple() {
|
||||
|
||||
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.query("sun flower s are");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -129,7 +129,7 @@ fn test_2gram_typo() {
|
||||
let index = create_index();
|
||||
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.query("sun flawer");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -159,7 +159,7 @@ fn test_no_disable_ngrams() {
|
||||
|
||||
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.query("sun flower ");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -185,7 +185,7 @@ fn test_2gram_prefix() {
|
||||
|
||||
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.query("sun flow");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -214,7 +214,7 @@ fn test_3gram_prefix() {
|
||||
|
||||
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.query("su nf l");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -237,7 +237,7 @@ fn test_split_words() {
|
||||
let index = create_index();
|
||||
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.query("sunflower ");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -266,7 +266,7 @@ fn test_disable_split_words() {
|
||||
|
||||
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.query("sunflower ");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -286,7 +286,7 @@ fn test_2gram_split_words() {
|
||||
let index = create_index();
|
||||
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.query("sunf lower");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -310,7 +310,7 @@ fn test_3gram_no_split_words() {
|
||||
let index = create_index();
|
||||
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.query("sunf lo wer");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -333,7 +333,7 @@ fn test_3gram_no_typos() {
|
||||
let index = create_index();
|
||||
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.query("sunf la wer");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -352,7 +352,7 @@ fn test_no_ngram_phrases() {
|
||||
let index = create_index();
|
||||
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.query("\"sun\" flower");
|
||||
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.query("\"sun\" \"flower\"");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -385,7 +385,7 @@ fn test_short_split_words() {
|
||||
let index = create_index();
|
||||
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.query("xyz");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -412,7 +412,7 @@ fn test_split_words_never_disabled() {
|
||||
|
||||
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.query("the sunflower is tall");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_simple_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -268,7 +268,7 @@ fn test_proximity_simple() {
|
||||
let index = create_simple_index();
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
@@ -295,7 +295,7 @@ fn test_proximity_split_word() {
|
||||
let index = create_edge_cases_index();
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("\"sun flower\" wilting");
|
||||
@@ -342,7 +342,7 @@ fn test_proximity_split_word() {
|
||||
.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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("xyz wilting");
|
||||
@@ -365,7 +365,7 @@ fn test_proximity_prefix_db() {
|
||||
let index = create_edge_cases_index();
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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
|
||||
// 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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("best win");
|
||||
@@ -441,7 +441,7 @@ fn test_proximity_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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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
|
||||
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("best wi");
|
||||
|
||||
@@ -8,7 +8,7 @@ implemented.
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -57,7 +57,7 @@ fn test_trap_basic() {
|
||||
let index = create_index();
|
||||
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.query("summer holiday");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -17,9 +17,7 @@ use meili_snap::insta;
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{
|
||||
score_details, AscDesc, Criterion, Member, Search, SearchResult, TermsMatchingStrategy,
|
||||
};
|
||||
use crate::{score_details, AscDesc, Criterion, Member, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -184,7 +182,7 @@ fn test_sort() {
|
||||
let index = create_index();
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("vague")))]);
|
||||
@@ -338,7 +336,7 @@ fn test_redacted() {
|
||||
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::collections::BTreeSet;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::{Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -79,7 +79,7 @@ fn test_ignore_stop_words() {
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
// `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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.query("to the xyz");
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.query("to the xyz ");
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.query("\"how to train your dragon\"");
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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!("{document_scores:#?}"));
|
||||
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.query("\"to\"");
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -157,7 +157,7 @@ fn test_no_typo() {
|
||||
|
||||
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.query("the quick brown fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -182,7 +182,7 @@ fn test_default_typo() {
|
||||
insta::assert_debug_snapshot!(tt, @"9");
|
||||
|
||||
// 0 typo
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("the quick brown fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -202,7 +202,7 @@ fn test_default_typo() {
|
||||
"###);
|
||||
|
||||
// 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.query("the quack brown fox jumps over the lazy dog");
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("the quicest brownest fox jummps over the laziest dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -235,7 +235,7 @@ fn test_phrase_no_typo_allowed() {
|
||||
let index = create_index();
|
||||
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.query("the \"quick brewn\" fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -265,7 +265,7 @@ fn test_typo_exact_word() {
|
||||
insta::assert_debug_snapshot!(tt, @"9");
|
||||
|
||||
// don't match quivk
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("the quick brown fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -279,7 +279,7 @@ fn test_typo_exact_word() {
|
||||
"###);
|
||||
|
||||
// Don't match quick
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("the quack brown fox jumps over the lazy dog");
|
||||
let SearchResult { documents_ids, document_scores, .. } = s.execute().unwrap();
|
||||
@@ -287,7 +287,7 @@ fn test_typo_exact_word() {
|
||||
insta::assert_snapshot!(format!("{document_scores:?}"), @"[]");
|
||||
|
||||
// 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.query("the quicest brownest fox jummps over the laziest dog");
|
||||
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)
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("network interconnection sunflower");
|
||||
@@ -340,7 +340,7 @@ fn test_typo_exact_attribute() {
|
||||
insta::assert_debug_snapshot!(tt, @"9");
|
||||
|
||||
// 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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("the quidk brown fox jumps over the lazy dog");
|
||||
@@ -386,7 +386,7 @@ fn test_typo_exact_attribute() {
|
||||
"###);
|
||||
|
||||
// combine with exact words
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("the quicest brownest fox jummps over the laziest dog");
|
||||
@@ -428,7 +428,7 @@ fn test_ngram_typos() {
|
||||
let index = create_index();
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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 mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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();
|
||||
|
||||
let mut s = Search::new(&txn, &index);
|
||||
let mut s = index.search(&txn);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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();
|
||||
|
||||
// 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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("network interconnection sunflower");
|
||||
@@ -545,7 +545,7 @@ fn test_typo_bucketing() {
|
||||
.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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("network interconnection sun flower");
|
||||
@@ -600,7 +600,7 @@ fn test_typo_synonyms() {
|
||||
.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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
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.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.query("the fast brownish fox jumps over the lackadaisical dog");
|
||||
|
||||
@@ -17,7 +17,7 @@ because the typo ranking rule before it only used the derivation `beautiful`.
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -87,7 +87,7 @@ fn test_trap_basic_and_complex1() {
|
||||
let index = create_index();
|
||||
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.query("beautiful summer");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -110,7 +110,7 @@ fn test_trap_complex2() {
|
||||
let index = create_index();
|
||||
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.query("delicious sweet dessert");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -14,7 +14,7 @@ This module tests the following properties:
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{Criterion, Search, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -131,7 +131,7 @@ fn test_words_tms_last_simple() {
|
||||
let index = create_index();
|
||||
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -180,7 +180,7 @@ fn test_words_tms_last_phrase() {
|
||||
let index = create_index();
|
||||
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -270,7 +270,7 @@ fn test_words_proximity_tms_last_simple() {
|
||||
.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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -351,7 +351,7 @@ fn test_words_proximity_tms_last_phrase() {
|
||||
.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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
@@ -421,7 +421,7 @@ fn test_words_tms_all() {
|
||||
.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.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
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.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -6,7 +6,10 @@ use roaring::RoaringBitmap;
|
||||
|
||||
use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait};
|
||||
use super::VectorStoreStats;
|
||||
use crate::progress::Progress;
|
||||
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::{DocumentId, Result, SearchContext, SearchLogger, TimeBudget};
|
||||
|
||||
@@ -94,8 +97,8 @@ impl<Q: RankingRuleQueryTrait> VectorSort<Q> {
|
||||
}
|
||||
|
||||
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
|
||||
fn id(&self) -> String {
|
||||
"vector_sort".to_owned()
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::VectorSort
|
||||
}
|
||||
|
||||
#[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>,
|
||||
universe: &RoaringBitmap,
|
||||
time_budget: &TimeBudget,
|
||||
progress: &Progress,
|
||||
) -> Result<Option<RankingRuleOutput<Q>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
let query = self.query.as_ref().unwrap().clone();
|
||||
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")]
|
||||
@@ -171,7 +176,9 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
|
||||
_ctx: &mut SearchContext<'ctx>,
|
||||
_logger: &mut dyn SearchLogger<Q>,
|
||||
universe: &RoaringBitmap,
|
||||
progress: &Progress,
|
||||
) -> Result<Poll<RankingRuleOutput<Q>>> {
|
||||
progress.update_progress(ComputingBucketSortStep::from(self.id()));
|
||||
let query = self.query.as_ref().unwrap().clone();
|
||||
let vector_candidates = &self.vector_candidates & universe;
|
||||
|
||||
|
||||
@@ -57,7 +57,12 @@ impl<'a> Similar<'a> {
|
||||
}
|
||||
|
||||
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
|
||||
universe.remove(self.id);
|
||||
|
||||
52
crates/milli/src/search/steps.rs
Normal file
52
crates/milli/src/search/steps.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ pub(crate) struct TempIndex {
|
||||
pub inner: Index,
|
||||
pub indexer_config: IndexerConfig,
|
||||
pub index_documents_config: IndexDocumentsConfig,
|
||||
pub progress: Progress,
|
||||
_tempdir: TempDir,
|
||||
}
|
||||
|
||||
@@ -47,7 +48,9 @@ impl TempIndex {
|
||||
let inner = Index::new(options, _tempdir.path(), true).unwrap();
|
||||
let indexer_config = IndexerConfig::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
|
||||
/// most tests.
|
||||
@@ -210,6 +213,10 @@ impl TempIndex {
|
||||
pub fn delete_document(&self, external_document_id: &str) {
|
||||
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]
|
||||
@@ -1095,7 +1102,7 @@ fn bug_3021_fourth() {
|
||||
"###);
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
let search = Search::new(&rtxn, &index);
|
||||
let search = index.search(&rtxn);
|
||||
let SearchResult {
|
||||
matching_words: _,
|
||||
candidates: _,
|
||||
|
||||
@@ -1292,7 +1292,7 @@ mod tests {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
// testing the simple query search
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
let mut search = index.search(&rtxn);
|
||||
search.query("document");
|
||||
search.terms_matching_strategy(TermsMatchingStrategy::default());
|
||||
// all documents should be returned
|
||||
@@ -1333,7 +1333,7 @@ mod tests {
|
||||
assert!(documents_ids.is_empty()); // nested is not searchable
|
||||
|
||||
// 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());
|
||||
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
assert_eq!(documents_ids, vec![1]);
|
||||
@@ -1358,6 +1358,7 @@ mod tests {
|
||||
#[test]
|
||||
fn index_documents_with_nested_primary_key() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.update_settings(|settings| {
|
||||
@@ -1397,7 +1398,7 @@ mod tests {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
// 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.terms_matching_strategy(TermsMatchingStrategy::default());
|
||||
// all documents should be returned
|
||||
@@ -1453,6 +1454,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_facets_generation() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.add_documents(documents!([
|
||||
@@ -1507,7 +1509,7 @@ mod tests {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
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}"#);
|
||||
search.filter(crate::Filter::from_str(&filter).unwrap().unwrap());
|
||||
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
@@ -1545,7 +1547,7 @@ mod tests {
|
||||
|
||||
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(
|
||||
"dog.race.bernese mountain",
|
||||
)))]);
|
||||
@@ -2911,7 +2913,6 @@ mod tests {
|
||||
]
|
||||
*/
|
||||
let index = TempIndex::new();
|
||||
|
||||
// START OF BATCH
|
||||
|
||||
println!("--- ENTERING BATCH 1");
|
||||
@@ -3601,6 +3602,7 @@ mod tests {
|
||||
#[test]
|
||||
fn delete_words_exact_attributes() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.update_settings(|settings| {
|
||||
@@ -3639,7 +3641,7 @@ mod tests {
|
||||
let words = index.words_fst(&txn).unwrap().into_stream().into_strs().unwrap();
|
||||
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");
|
||||
let crate::SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0]");
|
||||
|
||||
@@ -25,7 +25,8 @@ macro_rules! test_distinct {
|
||||
|
||||
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.limit($limit);
|
||||
search.offset($offset);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use either::{Either, Left, Right};
|
||||
use milli::progress::Progress;
|
||||
use milli::{Criterion, Filter, Search, SearchResult, TermsMatchingStrategy};
|
||||
|
||||
use Criterion::*;
|
||||
|
||||
use crate::search::{self, EXTERNAL_DOCUMENTS_IDS};
|
||||
@@ -15,7 +17,8 @@ macro_rules! test_filter {
|
||||
let filter_conditions =
|
||||
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.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ fn test_phrase_search_with_stop_words_given_criteria(criteria: &[Criterion]) {
|
||||
// Phrase search containing stop words
|
||||
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.limit(10);
|
||||
search.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
|
||||
@@ -27,7 +27,8 @@ macro_rules! test_criterion {
|
||||
let index = search::setup_search_index_with_criteria(&criteria);
|
||||
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.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
search.terms_matching_strategy($optional_word);
|
||||
@@ -241,7 +242,8 @@ fn criteria_mixup() {
|
||||
|
||||
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.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
search.terms_matching_strategy(ALLOW_OPTIONAL_WORDS);
|
||||
@@ -365,7 +367,8 @@ fn criteria_ascdesc() {
|
||||
|
||||
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);
|
||||
|
||||
let SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use big_s::S;
|
||||
use milli::progress::Progress;
|
||||
use milli::Criterion::{Attribute, Exactness, Proximity, Typo, Words};
|
||||
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 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.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ fn test_typo_tolerance_one_typo() {
|
||||
{
|
||||
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.limit(10);
|
||||
|
||||
@@ -31,7 +32,8 @@ fn test_typo_tolerance_one_typo() {
|
||||
let result = search.execute().unwrap();
|
||||
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.limit(10);
|
||||
|
||||
@@ -49,7 +51,8 @@ fn test_typo_tolerance_one_typo() {
|
||||
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
|
||||
|
||||
// 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.limit(10);
|
||||
|
||||
@@ -68,7 +71,8 @@ fn test_typo_tolerance_two_typo() {
|
||||
{
|
||||
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.limit(10);
|
||||
|
||||
@@ -77,7 +81,8 @@ fn test_typo_tolerance_two_typo() {
|
||||
let result = search.execute().unwrap();
|
||||
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.limit(10);
|
||||
|
||||
@@ -95,7 +100,8 @@ fn test_typo_tolerance_two_typo() {
|
||||
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
|
||||
|
||||
// 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.limit(10);
|
||||
|
||||
@@ -164,7 +170,8 @@ fn test_typo_disabled_on_word() {
|
||||
{
|
||||
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.limit(10);
|
||||
|
||||
@@ -184,7 +191,8 @@ fn test_typo_disabled_on_word() {
|
||||
builder.set_exact_words(exact_words);
|
||||
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.limit(10);
|
||||
|
||||
@@ -203,7 +211,8 @@ fn test_disable_typo_on_attribute() {
|
||||
{
|
||||
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`
|
||||
search.query("antebelum");
|
||||
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.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.limit(10);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user