mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-12-23 12:57:17 +00:00
Compare commits
13 Commits
log-search
...
post-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22e6ca7ea2 | ||
|
|
6338905314 | ||
|
|
c6b0b22cd1 | ||
|
|
210e704e2a | ||
|
|
c98391eddd | ||
|
|
3769bc5b38 | ||
|
|
9170bc63af | ||
|
|
e168bcbb85 | ||
|
|
b24b1979a1 | ||
|
|
9db2b16eed | ||
|
|
2ba3fafcc3 | ||
|
|
14db3dbcc4 | ||
|
|
a61ef955fc |
2
.github/workflows/test-suite.yml
vendored
2
.github/workflows/test-suite.yml
vendored
@@ -15,7 +15,7 @@ env:
|
||||
|
||||
jobs:
|
||||
test-linux:
|
||||
name: Tests on Ubuntu
|
||||
name: Tests on ${{ matrix.runner }} ${{ matrix.features }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -2698,9 +2698,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hannoy"
|
||||
version = "0.1.0-nested-rtxns"
|
||||
version = "0.1.2-nested-rtxns"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be82bf3f2108ddc8885e3d306fcd7f4692066bfe26065ca8b42ba417f3c26dd1"
|
||||
checksum = "533c952127a7e73448f26af313ac7b98012516561e48e953781cd6b30e573436"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
|
||||
@@ -172,8 +172,7 @@ pub fn run_benches(c: &mut criterion::Criterion, confs: &[Conf]) {
|
||||
|b, &query| {
|
||||
b.iter(|| {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
let progress = Progress::default();
|
||||
let mut search = index.search(&rtxn, &progress);
|
||||
let mut search = index.search(&rtxn);
|
||||
search
|
||||
.query(query)
|
||||
.terms_matching_strategy(TermsMatchingStrategy::default());
|
||||
|
||||
@@ -346,6 +346,7 @@ pub(crate) mod test {
|
||||
prefix_search: Setting::NotSet,
|
||||
chat: Setting::NotSet,
|
||||
vector_store: Setting::NotSet,
|
||||
execute_after_update: Setting::NotSet,
|
||||
_kind: std::marker::PhantomData,
|
||||
};
|
||||
settings.check()
|
||||
|
||||
@@ -423,6 +423,7 @@ impl<T> From<v5::Settings<T>> for v6::Settings<v6::Unchecked> {
|
||||
prefix_search: v6::Setting::NotSet,
|
||||
chat: v6::Setting::NotSet,
|
||||
vector_store: v6::Setting::NotSet,
|
||||
execute_after_update: v6::Setting::NotSet,
|
||||
_kind: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,8 +153,7 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// after executing a batch we check if the database is corrupted
|
||||
let progress = Progress::default();
|
||||
let res = index.search(&wtxn, &progress).execute().unwrap();
|
||||
let res = index.search(&wtxn).execute().unwrap();
|
||||
index.documents(&wtxn, res.documents_ids).unwrap();
|
||||
progression.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
@@ -306,6 +306,18 @@ fn create_or_open_index(
|
||||
) -> Result<Index> {
|
||||
let options = EnvOpenOptions::new();
|
||||
let mut options = options.read_txn_without_tls();
|
||||
|
||||
let map_size = match std::env::var("MEILI_MAX_INDEX_SIZE") {
|
||||
Ok(max_size) => {
|
||||
let max_size = max_size.parse().unwrap();
|
||||
map_size.min(max_size)
|
||||
}
|
||||
Err(VarError::NotPresent) => map_size,
|
||||
Err(VarError::NotUnicode(e)) => {
|
||||
panic!("Non unicode max index size in `MEILI_MAX_INDEX_SIZE`: {e:?}")
|
||||
}
|
||||
};
|
||||
|
||||
options.map_size(clamp_to_page_size(map_size));
|
||||
|
||||
// You can find more details about this experimental
|
||||
|
||||
@@ -328,6 +328,7 @@ InvalidSettingsDisplayedAttributes , InvalidRequest , BAD_REQU
|
||||
InvalidSettingsDistinctAttribute , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsProximityPrecision , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsFacetSearch , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsexecuteAfterUpdate , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsPrefixSearch , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsFaceting , InvalidRequest , BAD_REQUEST ;
|
||||
InvalidSettingsFilterableAttributes , InvalidRequest , BAD_REQUEST ;
|
||||
|
||||
@@ -326,6 +326,12 @@ pub struct Settings<T> {
|
||||
#[schema(value_type = Option<VectorStoreBackend>)]
|
||||
pub vector_store: Setting<VectorStoreBackend>,
|
||||
|
||||
/// Function to execute after an update
|
||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsexecuteAfterUpdate>)]
|
||||
#[schema(value_type = Option<String>, example = json!("doc.likes += 1"))]
|
||||
pub execute_after_update: Setting<String>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[deserr(skip)]
|
||||
pub _kind: PhantomData<T>,
|
||||
@@ -395,6 +401,7 @@ impl Settings<Checked> {
|
||||
prefix_search: Setting::Reset,
|
||||
chat: Setting::Reset,
|
||||
vector_store: Setting::Reset,
|
||||
execute_after_update: Setting::Reset,
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -423,6 +430,7 @@ impl Settings<Checked> {
|
||||
prefix_search,
|
||||
chat,
|
||||
vector_store,
|
||||
execute_after_update,
|
||||
_kind,
|
||||
} = self;
|
||||
|
||||
@@ -449,6 +457,7 @@ impl Settings<Checked> {
|
||||
prefix_search,
|
||||
vector_store,
|
||||
chat,
|
||||
execute_after_update,
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -501,6 +510,7 @@ impl Settings<Unchecked> {
|
||||
prefix_search: self.prefix_search,
|
||||
chat: self.chat,
|
||||
vector_store: self.vector_store,
|
||||
execute_after_update: self.execute_after_update,
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -582,6 +592,10 @@ impl Settings<Unchecked> {
|
||||
prefix_search: other.prefix_search.or(self.prefix_search),
|
||||
chat: other.chat.clone().or(self.chat.clone()),
|
||||
vector_store: other.vector_store.or(self.vector_store),
|
||||
execute_after_update: other
|
||||
.execute_after_update
|
||||
.clone()
|
||||
.or(self.execute_after_update.clone()),
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -622,6 +636,7 @@ pub fn apply_settings_to_builder(
|
||||
prefix_search,
|
||||
chat,
|
||||
vector_store,
|
||||
execute_after_update,
|
||||
_kind,
|
||||
} = settings;
|
||||
|
||||
@@ -845,6 +860,14 @@ pub fn apply_settings_to_builder(
|
||||
Setting::Reset => builder.reset_vector_store(),
|
||||
Setting::NotSet => (),
|
||||
}
|
||||
|
||||
match execute_after_update {
|
||||
Setting::Set(execute_after_update) => {
|
||||
builder.set_execute_after_update(execute_after_update.clone())
|
||||
}
|
||||
Setting::Reset => builder.reset_execute_after_update(),
|
||||
Setting::NotSet => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SecretPolicy {
|
||||
@@ -944,13 +967,13 @@ pub fn settings(
|
||||
.collect();
|
||||
|
||||
let vector_store = index.get_vector_store(rtxn)?;
|
||||
|
||||
let embedders = Setting::Set(embedders);
|
||||
let search_cutoff_ms = index.search_cutoff(rtxn)?;
|
||||
let localized_attributes_rules = index.localized_attributes_rules(rtxn)?;
|
||||
let prefix_search = index.prefix_search(rtxn)?.map(PrefixSearchSettings::from);
|
||||
let facet_search = index.facet_search(rtxn)?;
|
||||
let chat = index.chat_config(rtxn).map(ChatSettings::from)?;
|
||||
let execute_after_update = index.execute_after_update(rtxn)?;
|
||||
|
||||
let mut settings = Settings {
|
||||
displayed_attributes: match displayed_attributes {
|
||||
@@ -995,6 +1018,10 @@ pub fn settings(
|
||||
Some(vector_store) => Setting::Set(vector_store),
|
||||
None => Setting::Reset,
|
||||
},
|
||||
execute_after_update: match execute_after_update {
|
||||
Some(function) => Setting::Set(function.to_string()),
|
||||
None => Setting::NotSet,
|
||||
},
|
||||
_kind: PhantomData,
|
||||
};
|
||||
|
||||
@@ -1225,6 +1252,7 @@ pub(crate) mod test {
|
||||
prefix_search: Setting::NotSet,
|
||||
chat: Setting::NotSet,
|
||||
vector_store: Setting::NotSet,
|
||||
execute_after_update: Setting::NotSet,
|
||||
_kind: PhantomData::<Unchecked>,
|
||||
};
|
||||
|
||||
@@ -1258,7 +1286,7 @@ pub(crate) mod test {
|
||||
prefix_search: Setting::NotSet,
|
||||
chat: Setting::NotSet,
|
||||
vector_store: Setting::NotSet,
|
||||
|
||||
execute_after_update: Setting::NotSet,
|
||||
_kind: PhantomData::<Unchecked>,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use meilisearch_types::error::{Code, ErrorCode, ResponseError};
|
||||
use meilisearch_types::milli::progress::Progress;
|
||||
use meilisearch_types::milli::{SearchStep, TimeBudget};
|
||||
use meilisearch_types::milli::TimeBudget;
|
||||
use rand::Rng;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -347,11 +346,9 @@ 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,11 +30,7 @@ use meilisearch_types::features::{
|
||||
use meilisearch_types::heed::RoTxn;
|
||||
use meilisearch_types::keys::actions;
|
||||
use meilisearch_types::milli::index::ChatConfig;
|
||||
use meilisearch_types::milli::progress::Progress;
|
||||
use meilisearch_types::milli::{
|
||||
all_obkv_to_json, obkv_to_json, OrderBy, PatternMatch, TimeBudget,
|
||||
TotalProcessingTimeStep,
|
||||
};
|
||||
use meilisearch_types::milli::{all_obkv_to_json, obkv_to_json, OrderBy, PatternMatch, TimeBudget};
|
||||
use meilisearch_types::{Document, Index};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
@@ -266,7 +262,6 @@ 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 {
|
||||
@@ -290,9 +285,7 @@ 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> {
|
||||
@@ -304,15 +297,8 @@ 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,
|
||||
&progress,
|
||||
)?;
|
||||
let (search, _is_finite_pagination, _max_total_hits, _offset) =
|
||||
prepare_search(&index_cloned, &rtxn, &query, &search_kind, time_budget, features)?;
|
||||
|
||||
match search_from_kind(index_uid, search_kind, search) {
|
||||
Ok((search_results, _)) => Ok((rtxn, Ok(search_results))),
|
||||
|
||||
@@ -8,8 +8,7 @@ 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::progress::Progress;
|
||||
use meilisearch_types::milli::{self, TotalProcessingTimeStep};
|
||||
use meilisearch_types::milli;
|
||||
use meilisearch_types::serde_cs::vec::CS;
|
||||
use serde_json::Value;
|
||||
use tracing::debug;
|
||||
@@ -337,10 +336,6 @@ 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()?;
|
||||
@@ -364,9 +359,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 {
|
||||
@@ -379,21 +374,15 @@ 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?;
|
||||
|
||||
@@ -405,12 +394,11 @@ pub async fn search_with_url_query(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
debug!(request_uid = ?request_uid, returns = ?search_result, progress = ?progress.accumulated_durations(), "Search get");
|
||||
debug!(request_uid = ?request_uid, returns = ?search_result, "Search get");
|
||||
Ok(HttpResponse::Ok().json(search_result))
|
||||
}
|
||||
|
||||
@@ -482,11 +470,6 @@ 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");
|
||||
|
||||
@@ -511,7 +494,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 progress_clone = progress.clone();
|
||||
let permit = search_queue.try_get_search_permit().await?;
|
||||
let search_result = tokio::task::spawn_blocking(move || {
|
||||
perform_search(
|
||||
SearchParams {
|
||||
@@ -524,14 +507,11 @@ 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 {
|
||||
@@ -539,8 +519,6 @@ 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?;
|
||||
|
||||
@@ -552,12 +530,11 @@ pub async fn search_with_post(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
debug!(request_uid = ?request_uid, returns = ?search_result, progress = ?progress.accumulated_durations(), "Search post");
|
||||
debug!(request_uid = ?request_uid, returns = ?search_result, "Search post");
|
||||
Ok(HttpResponse::Ok().json(search_result))
|
||||
}
|
||||
|
||||
|
||||
@@ -465,6 +465,17 @@ make_setting_routes!(
|
||||
camelcase_attr: "facetSearch",
|
||||
analytics: FacetSearchAnalytics
|
||||
},
|
||||
{
|
||||
route: "/execute-after-update",
|
||||
update_verb: put,
|
||||
value_type: String,
|
||||
err_type: meilisearch_types::deserr::DeserrJsonError<
|
||||
meilisearch_types::error::deserr_codes::InvalidSettingsexecuteAfterUpdate,
|
||||
>,
|
||||
attr: execute_after_update,
|
||||
camelcase_attr: "executeAfterUpdate",
|
||||
analytics: ExecuteAfterUpdateAnalytics
|
||||
},
|
||||
{
|
||||
route: "/prefix-search",
|
||||
update_verb: put,
|
||||
@@ -585,6 +596,9 @@ pub async fn update_all(
|
||||
new_settings.non_separator_tokens.as_ref().set(),
|
||||
),
|
||||
facet_search: FacetSearchAnalytics::new(new_settings.facet_search.as_ref().set()),
|
||||
execute_after_update: ExecuteAfterUpdateAnalytics::new(
|
||||
new_settings.execute_after_update.as_ref().set(),
|
||||
),
|
||||
prefix_search: PrefixSearchAnalytics::new(new_settings.prefix_search.as_ref().set()),
|
||||
chat: ChatAnalytics::new(new_settings.chat.as_ref().set()),
|
||||
vector_store: VectorStoreAnalytics::new(new_settings.vector_store.as_ref().set()),
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct SettingsAnalytics {
|
||||
pub prefix_search: PrefixSearchAnalytics,
|
||||
pub chat: ChatAnalytics,
|
||||
pub vector_store: VectorStoreAnalytics,
|
||||
pub execute_after_update: ExecuteAfterUpdateAnalytics,
|
||||
}
|
||||
|
||||
impl Aggregate for SettingsAnalytics {
|
||||
@@ -197,6 +198,9 @@ impl Aggregate for SettingsAnalytics {
|
||||
set: new.facet_search.set | self.facet_search.set,
|
||||
value: new.facet_search.value.or(self.facet_search.value),
|
||||
},
|
||||
execute_after_update: ExecuteAfterUpdateAnalytics {
|
||||
set: new.execute_after_update.set | self.execute_after_update.set,
|
||||
},
|
||||
prefix_search: PrefixSearchAnalytics {
|
||||
set: new.prefix_search.set | self.prefix_search.set,
|
||||
value: new.prefix_search.value.or(self.prefix_search.value),
|
||||
@@ -669,6 +673,21 @@ impl FacetSearchAnalytics {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Default)]
|
||||
pub struct ExecuteAfterUpdateAnalytics {
|
||||
pub set: bool,
|
||||
}
|
||||
|
||||
impl ExecuteAfterUpdateAnalytics {
|
||||
pub fn new(distinct: Option<&String>) -> Self {
|
||||
Self { set: distinct.is_some() }
|
||||
}
|
||||
|
||||
pub fn into_settings(self) -> SettingsAnalytics {
|
||||
SettingsAnalytics { execute_after_update: self, ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Default)]
|
||||
pub struct PrefixSearchAnalytics {
|
||||
pub set: bool,
|
||||
|
||||
@@ -8,8 +8,6 @@ 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;
|
||||
@@ -219,7 +217,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);
|
||||
@@ -236,10 +234,7 @@ async fn similar(
|
||||
Route::Similar,
|
||||
)?;
|
||||
|
||||
let progress_clone = progress.clone();
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
let _step = progress_clone.update_progress_scoped(TotalProcessingTimeStep::Searching);
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
perform_similar(
|
||||
&index,
|
||||
query,
|
||||
@@ -248,14 +243,9 @@ async fn similar(
|
||||
quantized,
|
||||
retrieve_vectors,
|
||||
index_scheduler.features(),
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
|
||||
debug!(progress = ?progress.accumulated_durations(), "Similar");
|
||||
|
||||
result?
|
||||
.await?
|
||||
}
|
||||
|
||||
#[derive(Debug, deserr::Deserr, IntoParams)]
|
||||
|
||||
@@ -6,8 +6,6 @@ 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};
|
||||
@@ -155,10 +153,7 @@ 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();
|
||||
@@ -218,7 +213,6 @@ pub async fn multi_search_with_post(
|
||||
is_proxy,
|
||||
request_uid,
|
||||
include_metadata,
|
||||
&progress,
|
||||
)
|
||||
.await;
|
||||
permit.drop().await;
|
||||
@@ -294,7 +288,6 @@ 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 {
|
||||
@@ -307,7 +300,6 @@ pub async fn multi_search_with_post(
|
||||
include_metadata,
|
||||
},
|
||||
&index,
|
||||
&progress_clone,
|
||||
)
|
||||
})
|
||||
.await
|
||||
@@ -322,7 +314,6 @@ pub async fn multi_search_with_post(
|
||||
personalize,
|
||||
personalize_query.as_deref(),
|
||||
time_budget,
|
||||
&progress,
|
||||
)
|
||||
.await
|
||||
.with_index(query_index)?;
|
||||
@@ -333,19 +324,15 @@ 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.
|
||||
@@ -358,7 +345,6 @@ pub async fn multi_search_with_post(
|
||||
debug!(
|
||||
request_uid = ?request_uid,
|
||||
returns = ?search_results,
|
||||
progress = ?progress.accumulated_durations(),
|
||||
"Multi-search"
|
||||
);
|
||||
|
||||
|
||||
@@ -11,13 +11,9 @@ 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, FederatingResultsStep, OrderBy, SearchStep, TimeBudget,
|
||||
DEFAULT_VALUES_PER_FACET,
|
||||
};
|
||||
use meilisearch_types::milli::{self, DocumentId, OrderBy, TimeBudget, DEFAULT_VALUES_PER_FACET};
|
||||
use meilisearch_types::network::{Network, Remote};
|
||||
use roaring::RoaringBitmap;
|
||||
use tokio::task::JoinHandle;
|
||||
@@ -47,7 +43,6 @@ 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")?;
|
||||
@@ -116,7 +111,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, progress)?;
|
||||
search_by_index.execute(index_uid, queries, ¶ms)?;
|
||||
}
|
||||
|
||||
// bonus step, make sure to return an error if an index wants a non-faceted field, even if no query actually uses that index.
|
||||
@@ -131,8 +126,6 @@ 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
|
||||
@@ -141,7 +134,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
|
||||
@@ -194,7 +187,6 @@ 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);
|
||||
|
||||
@@ -839,7 +831,6 @@ 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) {
|
||||
@@ -966,7 +957,6 @@ 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);
|
||||
@@ -1054,7 +1044,7 @@ impl SearchByIndex {
|
||||
hit_maker,
|
||||
query_index,
|
||||
}| {
|
||||
let mut hit = hit_maker.make_hit(docid, &score, progress)?;
|
||||
let mut hit = hit_maker.make_hit(docid, &score)?;
|
||||
let weighted_score = ScoreDetails::global_score(score.iter()) * (*weight);
|
||||
|
||||
let mut _federation = serde_json::json!(
|
||||
|
||||
@@ -17,13 +17,11 @@ 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, SearchStep,
|
||||
TimeBudget,
|
||||
FacetValueHit, InternalError, OrderBy, PatternMatch, SearchForFacetValues, TimeBudget,
|
||||
};
|
||||
use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS;
|
||||
use meilisearch_types::{milli, Document};
|
||||
@@ -1026,13 +1024,11 @@ 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, progress);
|
||||
let mut search = index.search(rtxn);
|
||||
search.time_budget(time_budget);
|
||||
if let Some(ranking_score_threshold) = query.ranking_score_threshold {
|
||||
search.ranking_score_threshold(ranking_score_threshold.0);
|
||||
@@ -1052,7 +1048,6 @@ 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();
|
||||
|
||||
@@ -1066,7 +1061,6 @@ 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)
|
||||
@@ -1179,7 +1173,6 @@ pub struct SearchParams {
|
||||
pub fn perform_search(
|
||||
params: SearchParams,
|
||||
index: &Index,
|
||||
progress: &Progress,
|
||||
) -> Result<(SearchResult, TimeBudget), ResponseError> {
|
||||
let SearchParams {
|
||||
index_uid,
|
||||
@@ -1198,15 +1191,8 @@ 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,
|
||||
progress,
|
||||
)?;
|
||||
let (search, is_finite_pagination, max_total_hits, offset) =
|
||||
prepare_search(index, &rtxn, &query, &search_kind, time_budget.clone(), features)?;
|
||||
|
||||
let (
|
||||
milli::SearchResult {
|
||||
@@ -1267,7 +1253,6 @@ pub fn perform_search(
|
||||
personalize: _,
|
||||
} = query;
|
||||
|
||||
progress.update_progress(SearchStep::FormattingResults);
|
||||
let format = AttributesFormat {
|
||||
attributes_to_retrieve,
|
||||
retrieve_vectors,
|
||||
@@ -1290,7 +1275,6 @@ 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);
|
||||
@@ -1313,13 +1297,11 @@ 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,
|
||||
@@ -1334,7 +1316,6 @@ pub fn perform_search(
|
||||
request_uid: Some(request_uid),
|
||||
metadata,
|
||||
};
|
||||
|
||||
Ok((result, time_budget))
|
||||
}
|
||||
|
||||
@@ -1599,13 +1580,7 @@ impl<'a> HitMaker<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_hit(
|
||||
&self,
|
||||
id: u32,
|
||||
score: &[ScoreDetails],
|
||||
progress: &Progress,
|
||||
) -> milli::Result<SearchHit> {
|
||||
let _step = progress.update_progress_scoped(SearchStep::FormattingResults);
|
||||
pub fn make_hit(&self, id: u32, score: &[ScoreDetails]) -> milli::Result<SearchHit> {
|
||||
let (_, obkv) =
|
||||
self.index.iter_documents(self.rtxn, std::iter::once(id))?.next().unwrap()?;
|
||||
|
||||
@@ -1694,7 +1669,6 @@ 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();
|
||||
|
||||
@@ -1712,7 +1686,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, progress)?);
|
||||
documents.push(hit_maker.make_hit(id, score)?);
|
||||
}
|
||||
Ok(documents)
|
||||
}
|
||||
@@ -1727,7 +1701,6 @@ 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)),
|
||||
@@ -1756,15 +1729,8 @@ pub fn perform_facet_search(
|
||||
.collect()
|
||||
});
|
||||
|
||||
let (search, _, _, _) = prepare_search(
|
||||
index,
|
||||
&rtxn,
|
||||
&search_query,
|
||||
&search_kind,
|
||||
time_budget,
|
||||
features,
|
||||
&progress,
|
||||
)?;
|
||||
let (search, _, _, _) =
|
||||
prepare_search(index, &rtxn, &search_query, &search_kind, time_budget, features)?;
|
||||
let mut facet_search = SearchForFacetValues::new(
|
||||
facet_name,
|
||||
search,
|
||||
@@ -1796,7 +1762,6 @@ 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()?;
|
||||
@@ -1886,7 +1851,6 @@ pub fn perform_similar(
|
||||
format,
|
||||
Default::default(),
|
||||
documents_ids.iter().copied().zip(document_scores.iter()),
|
||||
progress,
|
||||
)?;
|
||||
|
||||
let max_total_hits = index
|
||||
|
||||
@@ -91,7 +91,7 @@ rhai = { version = "1.23.6", features = [
|
||||
"sync",
|
||||
] }
|
||||
arroy = "0.6.4-nested-rtxns"
|
||||
hannoy = { version = "0.1.0-nested-rtxns", features = ["arroy"] }
|
||||
hannoy = { version = "0.1.2-nested-rtxns", features = ["arroy"] }
|
||||
rand = "0.8.5"
|
||||
tracing = "0.1.41"
|
||||
ureq = { version = "2.12.1", features = ["json"] }
|
||||
|
||||
@@ -28,7 +28,6 @@ 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;
|
||||
@@ -85,6 +84,7 @@ pub mod main_key {
|
||||
pub const SEARCH_CUTOFF: &str = "search_cutoff";
|
||||
pub const LOCALIZED_ATTRIBUTES_RULES: &str = "localized_attributes_rules";
|
||||
pub const FACET_SEARCH: &str = "facet_search";
|
||||
pub const EXECUTE_AFTER_UPDATE: &str = "execute-after-update";
|
||||
pub const PREFIX_SEARCH: &str = "prefix_search";
|
||||
pub const DOCUMENTS_STATS: &str = "documents_stats";
|
||||
pub const DISABLED_TYPOS_TERMS: &str = "disabled_typos_terms";
|
||||
@@ -600,13 +600,6 @@ 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>>()
|
||||
@@ -619,10 +612,7 @@ 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.main
|
||||
.remap_types::<Str, SerdeJson<FieldsIdsMap>>()
|
||||
.get(rtxn, main_key::FIELDS_IDS_MAP_KEY)?
|
||||
.unwrap_or_default(),
|
||||
self.fields_ids_map(rtxn)?,
|
||||
MetadataBuilder::from_index(self, rtxn)?,
|
||||
))
|
||||
}
|
||||
@@ -1488,8 +1478,8 @@ impl Index {
|
||||
FacetDistribution::new(rtxn, self)
|
||||
}
|
||||
|
||||
pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>, progress: &'a Progress) -> Search<'a> {
|
||||
Search::new(rtxn, self, progress)
|
||||
pub fn search<'a>(&'a self, rtxn: &'a RoTxn<'a>) -> Search<'a> {
|
||||
Search::new(rtxn, self)
|
||||
}
|
||||
|
||||
/// Returns the index creation time.
|
||||
@@ -1779,6 +1769,22 @@ impl Index {
|
||||
self.main.remap_key_type::<Str>().delete(txn, main_key::CHAT)
|
||||
}
|
||||
|
||||
pub fn execute_after_update<'t>(&self, txn: &'t RoTxn<'_>) -> heed::Result<Option<&'t str>> {
|
||||
self.main.remap_types::<Str, Str>().get(txn, main_key::EXECUTE_AFTER_UPDATE)
|
||||
}
|
||||
|
||||
pub(crate) fn put_execute_after_update(
|
||||
&self,
|
||||
txn: &mut RwTxn<'_>,
|
||||
val: &str,
|
||||
) -> heed::Result<()> {
|
||||
self.main.remap_types::<Str, Str>().put(txn, main_key::EXECUTE_AFTER_UPDATE, &val)
|
||||
}
|
||||
|
||||
pub(crate) fn delete_execute_after_update(&self, txn: &mut RwTxn<'_>) -> heed::Result<bool> {
|
||||
self.main.remap_key_type::<Str>().delete(txn, main_key::EXECUTE_AFTER_UPDATE)
|
||||
}
|
||||
|
||||
pub fn localized_attributes_rules(
|
||||
&self,
|
||||
rtxn: &RoTxn<'_>,
|
||||
|
||||
@@ -81,7 +81,6 @@ 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,30 +64,6 @@ 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();
|
||||
@@ -119,15 +95,7 @@ impl Progress {
|
||||
let now = Instant::now();
|
||||
push_steps_durations(steps, &mut durations, now, 0);
|
||||
|
||||
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()
|
||||
durations.drain(..).map(|(name, duration)| (name, format!("{duration:.2?}"))).collect()
|
||||
}
|
||||
|
||||
// TODO: ideally we should expose the progress in a way that let arroy use it directly
|
||||
@@ -375,14 +343,3 @@ 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 = index.search(&rtxn);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
// 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 = index.search(&rtxn);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
|
||||
search.filter(Filter::from_str("_geoRadius(45.4777599, 9.1967508, 0)").unwrap().unwrap());
|
||||
let crate::SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
|
||||
@@ -6,7 +6,6 @@ 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};
|
||||
@@ -222,7 +221,6 @@ 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();
|
||||
@@ -243,7 +241,6 @@ 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,9 +12,7 @@ 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,
|
||||
@@ -31,7 +29,6 @@ mod fst_utils;
|
||||
pub mod hybrid;
|
||||
pub mod new;
|
||||
pub mod similar;
|
||||
pub mod steps;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SemanticSearch {
|
||||
@@ -64,11 +61,10 @@ 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, progress: &'a Progress) -> Search<'a> {
|
||||
pub fn new(rtxn: &'a heed::RoTxn<'a>, index: &'a Index) -> Search<'a> {
|
||||
Search {
|
||||
query: None,
|
||||
filter: None,
|
||||
@@ -90,7 +86,6 @@ impl<'a> Search<'a> {
|
||||
locales: None,
|
||||
time_budget: TimeBudget::max(),
|
||||
ranking_score_threshold: None,
|
||||
progress,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +198,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, self.progress)
|
||||
filtered_universe(ctx.index, ctx.txn, &self.filter)
|
||||
} else {
|
||||
Ok(self.execute()?.candidates)
|
||||
}
|
||||
@@ -244,9 +239,8 @@ impl<'a> Search<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let universe = filtered_universe(ctx.index, ctx.txn, &self.filter, self.progress)?;
|
||||
let universe = filtered_universe(ctx.index, ctx.txn, &self.filter)?;
|
||||
let mut query_vector = None;
|
||||
|
||||
let PartialSearchResult {
|
||||
located_query_terms,
|
||||
candidates,
|
||||
@@ -282,7 +276,6 @@ impl<'a> Search<'a> {
|
||||
*quantized,
|
||||
self.time_budget.clone(),
|
||||
self.ranking_score_threshold,
|
||||
self.progress,
|
||||
)?
|
||||
}
|
||||
_ => execute_search(
|
||||
@@ -304,7 +297,6 @@ impl<'a> Search<'a> {
|
||||
self.time_budget.clone(),
|
||||
self.ranking_score_threshold,
|
||||
self.locales.as_ref(),
|
||||
self.progress,
|
||||
)?,
|
||||
};
|
||||
|
||||
@@ -314,7 +306,6 @@ 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),
|
||||
@@ -356,7 +347,6 @@ impl fmt::Debug for Search<'_> {
|
||||
time_budget,
|
||||
ranking_score_threshold,
|
||||
locales,
|
||||
progress: _,
|
||||
} = self;
|
||||
f.debug_struct("Search")
|
||||
.field("query", query)
|
||||
|
||||
@@ -3,12 +3,10 @@ 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 {
|
||||
@@ -36,9 +34,7 @@ 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);
|
||||
@@ -97,7 +93,6 @@ 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);
|
||||
@@ -110,7 +105,6 @@ 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).
|
||||
@@ -163,7 +157,6 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
distinct_fid,
|
||||
&ranking_rule_scores,
|
||||
$candidates,
|
||||
progress,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
@@ -192,7 +185,6 @@ 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 => {
|
||||
@@ -239,7 +231,6 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>(
|
||||
logger,
|
||||
&ranking_rule_universes[cur_ranking_rule_index],
|
||||
&time_budget,
|
||||
progress,
|
||||
)?
|
||||
else {
|
||||
back!();
|
||||
@@ -332,11 +323,9 @@ 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() {
|
||||
@@ -347,8 +336,6 @@ 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,12 +3,9 @@ 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:
|
||||
@@ -27,8 +24,8 @@ impl ExactAttribute {
|
||||
}
|
||||
|
||||
impl<'ctx> RankingRule<'ctx, QueryGraph> for ExactAttribute {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::Exactness
|
||||
fn id(&self) -> String {
|
||||
"exact_attribute".to_owned()
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, target = "search::exact_attribute")]
|
||||
@@ -51,9 +48,7 @@ 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,10 +6,7 @@ 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> {
|
||||
@@ -76,8 +73,8 @@ impl<Q: RankingRuleQueryTrait> GeoSort<Q> {
|
||||
}
|
||||
|
||||
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for GeoSort<Q> {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::GeoSort
|
||||
fn id(&self) -> String {
|
||||
"geo_sort".to_owned()
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, target = "search::geo_sort")]
|
||||
@@ -115,9 +112,7 @@ 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,54 +50,51 @@ 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(RankingRuleId::Words, Some(terms_matching_strategy))
|
||||
Self::new_with_id("words".to_owned(), 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(RankingRuleId::Proximity, terms_matching_strategy)
|
||||
Self::new_with_id("proximity".to_owned(), terms_matching_strategy)
|
||||
}
|
||||
}
|
||||
pub type Fid = GraphBasedRankingRule<FidGraph>;
|
||||
impl GraphBasedRankingRule<FidGraph> {
|
||||
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
|
||||
Self::new_with_id(RankingRuleId::AttributePosition, terms_matching_strategy)
|
||||
Self::new_with_id("fid".to_owned(), terms_matching_strategy)
|
||||
}
|
||||
}
|
||||
pub type Position = GraphBasedRankingRule<PositionGraph>;
|
||||
impl GraphBasedRankingRule<PositionGraph> {
|
||||
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
|
||||
Self::new_with_id(RankingRuleId::WordPosition, terms_matching_strategy)
|
||||
Self::new_with_id("position".to_owned(), terms_matching_strategy)
|
||||
}
|
||||
}
|
||||
pub type Typo = GraphBasedRankingRule<TypoGraph>;
|
||||
impl GraphBasedRankingRule<TypoGraph> {
|
||||
pub fn new(terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
|
||||
Self::new_with_id(RankingRuleId::Typo, terms_matching_strategy)
|
||||
Self::new_with_id("typo".to_owned(), terms_matching_strategy)
|
||||
}
|
||||
}
|
||||
pub type Exactness = GraphBasedRankingRule<ExactnessGraph>;
|
||||
impl GraphBasedRankingRule<ExactnessGraph> {
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_id(RankingRuleId::Exactness, None)
|
||||
Self::new_with_id("exactness".to_owned(), None)
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic graph-based ranking rule
|
||||
pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
|
||||
id: RankingRuleId,
|
||||
id: String,
|
||||
terms_matching_strategy: Option<TermsMatchingStrategy>,
|
||||
// When the ranking rule is not iterating over its buckets,
|
||||
// its state is `None`.
|
||||
@@ -105,10 +102,7 @@ pub struct GraphBasedRankingRule<G: RankingRuleGraphTrait> {
|
||||
}
|
||||
impl<G: RankingRuleGraphTrait> GraphBasedRankingRule<G> {
|
||||
/// Creates the ranking rule with the given identifier
|
||||
pub fn new_with_id(
|
||||
id: RankingRuleId,
|
||||
terms_matching_strategy: Option<TermsMatchingStrategy>,
|
||||
) -> Self {
|
||||
pub fn new_with_id(id: String, terms_matching_strategy: Option<TermsMatchingStrategy>) -> Self {
|
||||
Self { id, terms_matching_strategy, state: None }
|
||||
}
|
||||
}
|
||||
@@ -130,7 +124,7 @@ pub struct GraphBasedRankingRuleState<G: RankingRuleGraphTrait> {
|
||||
}
|
||||
|
||||
impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBasedRankingRule<G> {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
@@ -225,9 +219,7 @@ 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, RankingRuleId};
|
||||
use crate::search::new::ranking_rules::BoxRankingRule;
|
||||
use crate::search::new::{QueryGraph, QueryNode, RankingRule, SearchContext, SearchLogger};
|
||||
use crate::Result;
|
||||
|
||||
@@ -45,26 +45,13 @@ 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<RankingRuleId>>,
|
||||
ranking_rules_ids: Option<Vec<String>>,
|
||||
events: Vec<SearchEvents>,
|
||||
location: Vec<Location>,
|
||||
}
|
||||
@@ -97,7 +84,14 @@ impl SearchLogger<QueryGraph> for VisualSearchLogger {
|
||||
ranking_rule_idx,
|
||||
universe_len: universe.len(),
|
||||
});
|
||||
self.location.push(ranking_rule.id().into());
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
fn next_bucket_ranking_rule(
|
||||
|
||||
@@ -498,14 +498,12 @@ 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, &progress).unwrap();
|
||||
let universe = filtered_universe(ctx.index, ctx.txn, &None).unwrap();
|
||||
let crate::search::PartialSearchResult { located_query_terms, .. } = execute_search(
|
||||
&mut ctx,
|
||||
Some(query),
|
||||
@@ -525,7 +523,6 @@ mod tests {
|
||||
TimeBudget::max(),
|
||||
None,
|
||||
None,
|
||||
&progress,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -56,10 +56,8 @@ 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,
|
||||
@@ -296,9 +294,7 @@ 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,
|
||||
@@ -636,10 +632,8 @@ 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)?
|
||||
@@ -664,7 +658,6 @@ 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())?;
|
||||
|
||||
@@ -699,7 +692,6 @@ pub fn execute_vector_search(
|
||||
ranking_score_threshold,
|
||||
exhaustive_number_hits,
|
||||
max_total_hits,
|
||||
progress,
|
||||
)?;
|
||||
|
||||
Ok(PartialSearchResult {
|
||||
@@ -733,14 +725,12 @@ 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();
|
||||
|
||||
@@ -844,14 +834,8 @@ pub fn execute_search(
|
||||
terms_matching_strategy,
|
||||
)?;
|
||||
|
||||
universe &= resolve_universe(
|
||||
ctx,
|
||||
&universe,
|
||||
&graph,
|
||||
terms_matching_strategy,
|
||||
query_graph_logger,
|
||||
progress,
|
||||
)?;
|
||||
universe &=
|
||||
resolve_universe(ctx, &universe, &graph, terms_matching_strategy, query_graph_logger)?;
|
||||
|
||||
bucket_sort(
|
||||
ctx,
|
||||
@@ -867,7 +851,6 @@ pub fn execute_search(
|
||||
ranking_score_threshold,
|
||||
exhaustive_number_hits,
|
||||
max_total_hits,
|
||||
progress,
|
||||
)?
|
||||
} else {
|
||||
let ranking_rules =
|
||||
@@ -886,7 +869,6 @@ 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 = dbg!(ctx.get_db_word_fids(word.interned())?);
|
||||
let fields = 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 = dbg!(ctx.get_db_word_fids(word)?);
|
||||
let fields = ctx.get_db_word_fids(word)?;
|
||||
all_fields.extend(fields);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(word_prefix) = term.term_subset.use_prefix_db(ctx) {
|
||||
let fields = dbg!(ctx.get_db_word_prefix_fids(word_prefix.interned())?);
|
||||
let fields = ctx.get_db_word_prefix_fids(word_prefix.interned())?;
|
||||
all_fields.extend(fields);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ 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`]
|
||||
@@ -26,7 +24,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) -> RankingRuleId;
|
||||
fn id(&self) -> String;
|
||||
|
||||
/// Prepare the ranking rule such that it can start iterating over its
|
||||
/// buckets using [`next_bucket`](RankingRule::next_bucket).
|
||||
@@ -58,7 +56,6 @@ 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
|
||||
@@ -72,9 +69,7 @@ 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)
|
||||
}
|
||||
|
||||
@@ -98,54 +93,3 @@ 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,11 +5,8 @@ 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> {
|
||||
@@ -87,13 +84,9 @@ impl<'ctx, Query> Sort<'ctx, Query> {
|
||||
}
|
||||
|
||||
impl<'ctx, Query: RankingRuleQueryTrait> RankingRule<'ctx, Query> for Sort<'ctx, Query> {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
fn id(&self) -> String {
|
||||
let Self { field_name, is_ascending, .. } = self;
|
||||
if *is_ascending {
|
||||
RankingRuleId::Asc(field_name.clone())
|
||||
} else {
|
||||
RankingRuleId::Desc(field_name.clone())
|
||||
}
|
||||
format!("{field_name}:{}", if *is_ascending { "asc" } else { "desc" })
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, target = "search::sort")]
|
||||
@@ -203,9 +196,7 @@ 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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{db_snap, Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{db_snap, Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, TimeBudget};
|
||||
use crate::{Criterion, Filter, FilterableAttributesRule, Search, 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 = index.search(&rtxn);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
|
||||
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, SearchResult,
|
||||
AscDesc, Criterion, FilterableAttributesRule, Index, Member, Search, SearchResult,
|
||||
TermsMatchingStrategy,
|
||||
};
|
||||
|
||||
@@ -246,7 +246,7 @@ fn test_distinct_placeholder_no_ranking_rules() {
|
||||
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut s = Search::new(&rtxn, &index);
|
||||
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::SearchResult;
|
||||
use crate::{Search, 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 = index.search(&txn);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.query("summer holiday");
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -17,7 +17,9 @@ use meili_snap::insta;
|
||||
|
||||
use crate::index::tests::TempIndex;
|
||||
use crate::search::new::tests::collect_field_values;
|
||||
use crate::{score_details, AscDesc, Criterion, Member, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{
|
||||
score_details, AscDesc, Criterion, Member, Search, SearchResult, TermsMatchingStrategy,
|
||||
};
|
||||
|
||||
fn create_index() -> TempIndex {
|
||||
let index = TempIndex::new();
|
||||
@@ -182,7 +184,7 @@ fn test_sort() {
|
||||
let index = create_index();
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("letter")))]);
|
||||
@@ -217,7 +219,7 @@ fn test_sort() {
|
||||
]
|
||||
"###);
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("rank")))]);
|
||||
@@ -252,7 +254,7 @@ fn test_sort() {
|
||||
]
|
||||
"###);
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Asc(Member::Field(S("vague")))]);
|
||||
@@ -287,7 +289,7 @@ fn test_sort() {
|
||||
]
|
||||
"###);
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::Last);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
s.sort_criteria(vec![AscDesc::Desc(Member::Field(S("vague")))]);
|
||||
@@ -336,7 +338,7 @@ fn test_redacted() {
|
||||
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let mut s = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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::{SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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, SearchResult, TermsMatchingStrategy};
|
||||
use crate::{Criterion, Search, 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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
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 = index.search(&txn);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.query("extravagant");
|
||||
s.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
s.scoring_strategy(crate::score_details::ScoringStrategy::Detailed);
|
||||
|
||||
@@ -6,10 +6,7 @@ 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};
|
||||
|
||||
@@ -97,8 +94,8 @@ impl<Q: RankingRuleQueryTrait> VectorSort<Q> {
|
||||
}
|
||||
|
||||
impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
|
||||
fn id(&self) -> RankingRuleId {
|
||||
RankingRuleId::VectorSort
|
||||
fn id(&self) -> String {
|
||||
"vector_sort".to_owned()
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")]
|
||||
@@ -126,9 +123,7 @@ 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;
|
||||
|
||||
@@ -163,7 +158,7 @@ impl<'ctx, Q: RankingRuleQueryTrait> RankingRule<'ctx, Q> for VectorSort<Q> {
|
||||
}));
|
||||
}
|
||||
|
||||
self.next_bucket(ctx, _logger, universe, time_budget, progress)
|
||||
self.next_bucket(ctx, _logger, universe, time_budget)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, target = "search::vector_sort")]
|
||||
@@ -176,9 +171,7 @@ 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,12 +57,7 @@ impl<'a> Similar<'a> {
|
||||
}
|
||||
|
||||
pub fn execute(&self) -> Result<SearchResult> {
|
||||
let mut universe = filtered_universe(
|
||||
self.index,
|
||||
self.rtxn,
|
||||
&self.filter,
|
||||
&crate::progress::Progress::default(),
|
||||
)?;
|
||||
let mut universe = filtered_universe(self.index, self.rtxn, &self.filter)?;
|
||||
|
||||
// we never want to receive the docid
|
||||
universe.remove(self.id);
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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,7 +26,6 @@ pub(crate) struct TempIndex {
|
||||
pub inner: Index,
|
||||
pub indexer_config: IndexerConfig,
|
||||
pub index_documents_config: IndexDocumentsConfig,
|
||||
pub progress: Progress,
|
||||
_tempdir: TempDir,
|
||||
}
|
||||
|
||||
@@ -48,9 +47,7 @@ impl TempIndex {
|
||||
let inner = Index::new(options, _tempdir.path(), true).unwrap();
|
||||
let indexer_config = IndexerConfig::default();
|
||||
let index_documents_config = IndexDocumentsConfig::default();
|
||||
let progress = Progress::default();
|
||||
|
||||
Self { inner, indexer_config, index_documents_config, progress, _tempdir }
|
||||
Self { inner, indexer_config, index_documents_config, _tempdir }
|
||||
}
|
||||
/// Creates a temporary index, with a default `4096 * 2000` size. This should be enough for
|
||||
/// most tests.
|
||||
@@ -213,10 +210,6 @@ 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]
|
||||
@@ -1102,7 +1095,7 @@ fn bug_3021_fourth() {
|
||||
"###);
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
let search = index.search(&rtxn);
|
||||
let search = Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
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 = index.search(&rtxn);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
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,7 +1358,6 @@ mod tests {
|
||||
#[test]
|
||||
fn index_documents_with_nested_primary_key() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.update_settings(|settings| {
|
||||
@@ -1398,7 +1397,7 @@ mod tests {
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
// testing the simple query search
|
||||
let mut search = crate::Search::new(&rtxn, &index, &progress);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
search.query("document");
|
||||
search.terms_matching_strategy(TermsMatchingStrategy::default());
|
||||
// all documents should be returned
|
||||
@@ -1454,7 +1453,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_facets_generation() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.add_documents(documents!([
|
||||
@@ -1509,7 +1507,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, &progress);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
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();
|
||||
@@ -1547,7 +1545,7 @@ mod tests {
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let mut search = crate::Search::new(&rtxn, &index, &progress);
|
||||
let mut search = crate::Search::new(&rtxn, &index);
|
||||
search.sort_criteria(vec![crate::AscDesc::Asc(crate::Member::Field(S(
|
||||
"dog.race.bernese mountain",
|
||||
)))]);
|
||||
@@ -2913,6 +2911,7 @@ mod tests {
|
||||
]
|
||||
*/
|
||||
let index = TempIndex::new();
|
||||
|
||||
// START OF BATCH
|
||||
|
||||
println!("--- ENTERING BATCH 1");
|
||||
@@ -3602,7 +3601,6 @@ mod tests {
|
||||
#[test]
|
||||
fn delete_words_exact_attributes() {
|
||||
let index = TempIndex::new();
|
||||
let progress = Progress::default();
|
||||
|
||||
index
|
||||
.update_settings(|settings| {
|
||||
@@ -3641,7 +3639,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, &progress);
|
||||
let mut s = Search::new(&txn, &index);
|
||||
s.query("hello");
|
||||
let crate::SearchResult { documents_ids, .. } = s.execute().unwrap();
|
||||
insta::assert_snapshot!(format!("{documents_ids:?}"), @"[0]");
|
||||
|
||||
@@ -470,6 +470,71 @@ impl<'doc> Versions<'doc> {
|
||||
Ok(Some(Self::single(data)))
|
||||
}
|
||||
|
||||
pub fn multiple_with_edits(
|
||||
doc: Option<rhai::Map>,
|
||||
mut versions: impl Iterator<Item = Result<RawMap<'doc, FxBuildHasher>>>,
|
||||
engine: &rhai::Engine,
|
||||
edit_function: &rhai::AST,
|
||||
doc_alloc: &'doc bumpalo::Bump,
|
||||
) -> Result<Option<Option<Self>>> {
|
||||
let Some(data) = versions.next() else { return Ok(None) };
|
||||
|
||||
let mut doc = doc.unwrap_or_default();
|
||||
let mut data = data?;
|
||||
for version in versions {
|
||||
let version = version?;
|
||||
for (field, value) in version {
|
||||
data.insert(field, value);
|
||||
}
|
||||
|
||||
let mut scope = rhai::Scope::new();
|
||||
data.iter().for_each(|(k, v)| {
|
||||
doc.insert(k.into(), serde_json::from_str(v.get()).unwrap());
|
||||
});
|
||||
scope.push("doc", doc.clone());
|
||||
|
||||
let _ = engine.eval_ast_with_scope::<rhai::Dynamic>(&mut scope, edit_function).unwrap();
|
||||
data = RawMap::with_hasher_in(FxBuildHasher, doc_alloc);
|
||||
match scope.get_value::<rhai::Map>("doc") {
|
||||
Some(map) => {
|
||||
for (key, value) in map {
|
||||
let mut vec = bumpalo::collections::Vec::new_in(doc_alloc);
|
||||
serde_json::to_writer(&mut vec, &value).unwrap();
|
||||
let key = doc_alloc.alloc_str(key.as_str());
|
||||
let raw_value = serde_json::from_slice(vec.into_bump_slice()).unwrap();
|
||||
data.insert(key, raw_value);
|
||||
}
|
||||
}
|
||||
// In case the deletes the document and it's not the last change
|
||||
// we simply set the document to an empty one and await the next change.
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
// We must also run the code after the last change
|
||||
let mut scope = rhai::Scope::new();
|
||||
data.iter().for_each(|(k, v)| {
|
||||
doc.insert(k.into(), serde_json::from_str(v.get()).unwrap());
|
||||
});
|
||||
scope.push("doc", doc);
|
||||
|
||||
let _ = engine.eval_ast_with_scope::<rhai::Dynamic>(&mut scope, edit_function).unwrap();
|
||||
data = RawMap::with_hasher_in(FxBuildHasher, doc_alloc);
|
||||
match scope.get_value::<rhai::Map>("doc") {
|
||||
Some(map) => {
|
||||
for (key, value) in map {
|
||||
let mut vec = bumpalo::collections::Vec::new_in(doc_alloc);
|
||||
serde_json::to_writer(&mut vec, &value).unwrap();
|
||||
let key = doc_alloc.alloc_str(key.as_str());
|
||||
let raw_value = serde_json::from_slice(vec.into_bump_slice()).unwrap();
|
||||
data.insert(key, raw_value);
|
||||
}
|
||||
Ok(Some(Some(Self::single(data))))
|
||||
}
|
||||
None => Ok(Some(None)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn single(version: RawMap<'doc, FxBuildHasher>) -> Self {
|
||||
Self { data: version }
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::documents::PrimaryKey;
|
||||
use crate::progress::{AtomicPayloadStep, Progress};
|
||||
use crate::update::new::document::{DocumentContext, Versions};
|
||||
use crate::update::new::indexer::current_edition::sharding::Shards;
|
||||
use crate::update::new::indexer::update_by_function::obkv_to_rhaimap;
|
||||
use crate::update::new::steps::IndexingStep;
|
||||
use crate::update::new::thread_local::MostlySend;
|
||||
use crate::update::new::{DocumentIdentifiers, Insertion, Update};
|
||||
@@ -176,7 +177,16 @@ impl<'pl> DocumentOperation<'pl> {
|
||||
.sort_unstable_by_key(|(_, po)| first_update_pointer(&po.operations).unwrap_or(0));
|
||||
|
||||
let docids_version_offsets = docids_version_offsets.into_bump_slice();
|
||||
Ok((DocumentOperationChanges { docids_version_offsets }, operations_stats, primary_key))
|
||||
let engine = rhai::Engine::new();
|
||||
// Make sure to correctly setup the engine and remove all settings
|
||||
let ast = index.execute_after_update(rtxn)?.map(|f| engine.compile(f).unwrap());
|
||||
let fidmap = index.fields_ids_map(rtxn)?;
|
||||
|
||||
Ok((
|
||||
DocumentOperationChanges { docids_version_offsets, engine, ast, fidmap },
|
||||
operations_stats,
|
||||
primary_key,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +484,15 @@ impl<'pl> DocumentChanges<'pl> for DocumentOperationChanges<'pl> {
|
||||
'pl: 'doc,
|
||||
{
|
||||
let (external_doc, payload_operations) = item;
|
||||
payload_operations.merge(external_doc, &context.doc_alloc)
|
||||
payload_operations.merge(
|
||||
&context.rtxn,
|
||||
context.index,
|
||||
&self.fidmap,
|
||||
&self.engine,
|
||||
self.ast.as_ref(),
|
||||
external_doc,
|
||||
&context.doc_alloc,
|
||||
)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
@@ -483,6 +501,9 @@ impl<'pl> DocumentChanges<'pl> for DocumentOperationChanges<'pl> {
|
||||
}
|
||||
|
||||
pub struct DocumentOperationChanges<'pl> {
|
||||
engine: rhai::Engine,
|
||||
ast: Option<rhai::AST>,
|
||||
fidmap: FieldsIdsMap,
|
||||
docids_version_offsets: &'pl [(&'pl str, PayloadOperations<'pl>)],
|
||||
}
|
||||
|
||||
@@ -571,10 +592,14 @@ impl<'pl> PayloadOperations<'pl> {
|
||||
}
|
||||
|
||||
/// Returns only the most recent version of a document based on the updates from the payloads.
|
||||
///
|
||||
/// This function is only meant to be used when doing a replacement and not an update.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn merge<'doc>(
|
||||
&self,
|
||||
rtxn: &heed::RoTxn,
|
||||
index: &Index,
|
||||
fidmap: &FieldsIdsMap,
|
||||
engine: &rhai::Engine,
|
||||
ast: Option<&rhai::AST>,
|
||||
external_doc: &'doc str,
|
||||
doc_alloc: &'doc Bump,
|
||||
) -> Result<Option<DocumentChange<'doc>>>
|
||||
@@ -638,9 +663,33 @@ impl<'pl> PayloadOperations<'pl> {
|
||||
Ok(document)
|
||||
});
|
||||
|
||||
let Some(versions) = Versions::multiple(versions)? else { return Ok(None) };
|
||||
let versions = match ast {
|
||||
Some(ast) => {
|
||||
let doc = index
|
||||
.documents
|
||||
.get(rtxn, &self.docid)?
|
||||
.map(|obkv| obkv_to_rhaimap(obkv, fidmap))
|
||||
.transpose()?;
|
||||
match Versions::multiple_with_edits(doc, versions, engine, ast, doc_alloc)?
|
||||
{
|
||||
Some(Some(versions)) => Some(versions),
|
||||
Some(None) if self.is_new => return Ok(None),
|
||||
Some(None) => {
|
||||
return Ok(Some(DocumentChange::Deletion(
|
||||
DocumentIdentifiers::create(self.docid, external_doc),
|
||||
)));
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
None => Versions::multiple(versions)?,
|
||||
};
|
||||
|
||||
if self.is_new {
|
||||
let Some(versions) = versions else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if self.is_new || ast.is_some() {
|
||||
Ok(Some(DocumentChange::Insertion(Insertion::create(
|
||||
self.docid,
|
||||
external_doc,
|
||||
|
||||
@@ -187,7 +187,7 @@ impl<'index> DocumentChanges<'index> for UpdateByFunctionChanges<'index> {
|
||||
}
|
||||
}
|
||||
|
||||
fn obkv_to_rhaimap(obkv: &KvReaderFieldId, fields_ids_map: &FieldsIdsMap) -> Result<rhai::Map> {
|
||||
pub fn obkv_to_rhaimap(obkv: &KvReaderFieldId, fields_ids_map: &FieldsIdsMap) -> Result<rhai::Map> {
|
||||
let all_keys = obkv.iter().map(|(k, _v)| k).collect::<Vec<_>>();
|
||||
let map: Result<rhai::Map> = all_keys
|
||||
.iter()
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::cell::RefCell;
|
||||
use std::collections::BTreeSet;
|
||||
use std::io::{BufReader, BufWriter, Read, Seek, Write};
|
||||
use std::iter;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use heed::types::{Bytes, DecodeIgnore, Str};
|
||||
@@ -345,7 +346,7 @@ impl<'i> WordPrefixIntegerDocids<'i> {
|
||||
indexes.push(PrefixIntegerEntry {
|
||||
prefix,
|
||||
pos,
|
||||
serialized_length: Some(buffer.len()),
|
||||
serialized_length: NonZeroUsize::new(buffer.len()),
|
||||
});
|
||||
file.write_all(&buffer)?;
|
||||
}
|
||||
@@ -371,7 +372,7 @@ impl<'i> WordPrefixIntegerDocids<'i> {
|
||||
key_buffer.extend_from_slice(&pos.to_be_bytes());
|
||||
match serialized_length {
|
||||
Some(serialized_length) => {
|
||||
buffer.resize(serialized_length, 0);
|
||||
buffer.resize(serialized_length.get(), 0);
|
||||
file.read_exact(&mut buffer)?;
|
||||
self.prefix_database.remap_data_type::<Bytes>().put(
|
||||
wtxn,
|
||||
@@ -426,7 +427,7 @@ impl<'i> WordPrefixIntegerDocids<'i> {
|
||||
index.push(PrefixIntegerEntry {
|
||||
prefix,
|
||||
pos,
|
||||
serialized_length: Some(buffer.len()),
|
||||
serialized_length: NonZeroUsize::new(buffer.len()),
|
||||
});
|
||||
file.write_all(buffer)?;
|
||||
}
|
||||
@@ -452,7 +453,7 @@ impl<'i> WordPrefixIntegerDocids<'i> {
|
||||
key_buffer.extend_from_slice(&pos.to_be_bytes());
|
||||
match serialized_length {
|
||||
Some(serialized_length) => {
|
||||
buffer.resize(serialized_length, 0);
|
||||
buffer.resize(serialized_length.get(), 0);
|
||||
file.read_exact(&mut buffer)?;
|
||||
self.prefix_database.remap_data_type::<Bytes>().put(
|
||||
wtxn,
|
||||
@@ -475,7 +476,7 @@ impl<'i> WordPrefixIntegerDocids<'i> {
|
||||
struct PrefixIntegerEntry<'a> {
|
||||
prefix: &'a str,
|
||||
pos: u16,
|
||||
serialized_length: Option<usize>,
|
||||
serialized_length: Option<NonZeroUsize>,
|
||||
}
|
||||
|
||||
/// TODO doc
|
||||
|
||||
@@ -197,6 +197,7 @@ pub struct Settings<'a, 't, 'i> {
|
||||
facet_search: Setting<bool>,
|
||||
chat: Setting<ChatSettings>,
|
||||
vector_store: Setting<VectorStoreBackend>,
|
||||
execute_after_update: Setting<String>,
|
||||
}
|
||||
|
||||
impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
@@ -237,6 +238,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
facet_search: Setting::NotSet,
|
||||
chat: Setting::NotSet,
|
||||
vector_store: Setting::NotSet,
|
||||
execute_after_update: Setting::NotSet,
|
||||
indexer_config,
|
||||
}
|
||||
}
|
||||
@@ -483,6 +485,14 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
self.vector_store = Setting::Reset;
|
||||
}
|
||||
|
||||
pub fn set_execute_after_update(&mut self, value: String) {
|
||||
self.execute_after_update = Setting::Set(value);
|
||||
}
|
||||
|
||||
pub fn reset_execute_after_update(&mut self) {
|
||||
self.execute_after_update = Setting::Reset;
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
level = "trace"
|
||||
skip(self, progress_callback, should_abort, settings_diff, embedder_stats),
|
||||
@@ -1054,6 +1064,18 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
fn update_execute_after_update(&mut self) -> Result<()> {
|
||||
match self.execute_after_update.as_ref() {
|
||||
Setting::Set(new) => {
|
||||
self.index.put_execute_after_update(self.wtxn, &new).map_err(Into::into)
|
||||
}
|
||||
Setting::Reset => {
|
||||
self.index.delete_execute_after_update(self.wtxn).map(drop).map_err(Into::into)
|
||||
}
|
||||
Setting::NotSet => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_embedding_configs(&mut self) -> Result<BTreeMap<String, EmbedderAction>> {
|
||||
match std::mem::take(&mut self.embedder_settings) {
|
||||
Setting::Set(configs) => self.update_embedding_configs_set(configs),
|
||||
@@ -1464,6 +1486,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
self.update_proximity_precision()?;
|
||||
self.update_prefix_search()?;
|
||||
self.update_facet_search()?;
|
||||
self.update_execute_after_update()?;
|
||||
self.update_localized_attributes_rules()?;
|
||||
self.update_disabled_typos_terms()?;
|
||||
self.update_chat_config()?;
|
||||
@@ -1613,6 +1636,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||
disable_on_numbers: Setting::NotSet, // TODO (require force reindexing of searchables)
|
||||
chat: Setting::NotSet,
|
||||
vector_store: Setting::NotSet,
|
||||
execute_after_update: Setting::NotSet,
|
||||
wtxn: _,
|
||||
index: _,
|
||||
indexer_config: _,
|
||||
|
||||
@@ -892,6 +892,7 @@ fn test_correct_settings_init() {
|
||||
disable_on_numbers,
|
||||
chat,
|
||||
vector_store,
|
||||
execute_after_update,
|
||||
} = settings;
|
||||
assert!(matches!(searchable_fields, Setting::NotSet));
|
||||
assert!(matches!(displayed_fields, Setting::NotSet));
|
||||
@@ -922,6 +923,7 @@ fn test_correct_settings_init() {
|
||||
assert!(matches!(disable_on_numbers, Setting::NotSet));
|
||||
assert!(matches!(chat, Setting::NotSet));
|
||||
assert!(matches!(vector_store, Setting::NotSet));
|
||||
assert!(matches!(execute_after_update, Setting::NotSet));
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ macro_rules! test_distinct {
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.query(search::TEST_QUERY);
|
||||
search.limit($limit);
|
||||
search.offset($offset);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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};
|
||||
@@ -17,8 +15,7 @@ macro_rules! test_filter {
|
||||
let filter_conditions =
|
||||
Filter::from_array::<Vec<Either<Vec<&str>, &str>>, _>($filter).unwrap().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.query(search::TEST_QUERY);
|
||||
search.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@ fn test_phrase_search_with_stop_words_given_criteria(criteria: &[Criterion]) {
|
||||
// Phrase search containing stop words
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("\"the use of force\"");
|
||||
search.limit(10);
|
||||
search.terms_matching_strategy(TermsMatchingStrategy::All);
|
||||
|
||||
@@ -27,8 +27,7 @@ macro_rules! test_criterion {
|
||||
let index = search::setup_search_index_with_criteria(&criteria);
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.query(search::TEST_QUERY);
|
||||
search.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
search.terms_matching_strategy($optional_word);
|
||||
@@ -242,8 +241,7 @@ fn criteria_mixup() {
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.query(search::TEST_QUERY);
|
||||
search.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
search.terms_matching_strategy(ALLOW_OPTIONAL_WORDS);
|
||||
@@ -367,8 +365,7 @@ fn criteria_ascdesc() {
|
||||
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.limit(ASC_DESC_CANDIDATES_THRESHOLD + 1);
|
||||
|
||||
let SearchResult { documents_ids, .. } = search.execute().unwrap();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use big_s::S;
|
||||
use milli::progress::Progress;
|
||||
use milli::Criterion::{Attribute, Exactness, Proximity, Typo, Words};
|
||||
use milli::{AscDesc, Error, Member, Search, TermsMatchingStrategy, UserError};
|
||||
|
||||
@@ -12,8 +11,7 @@ fn sort_ranking_rule_missing() {
|
||||
let index = search::setup_search_index_with_criteria(&criteria);
|
||||
let rtxn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&rtxn, &index, &progress);
|
||||
let mut search = Search::new(&rtxn, &index);
|
||||
search.query(search::TEST_QUERY);
|
||||
search.limit(EXTERNAL_DOCUMENTS_IDS.len());
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ fn test_typo_tolerance_one_typo() {
|
||||
{
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zeal");
|
||||
search.limit(10);
|
||||
|
||||
@@ -32,8 +31,7 @@ fn test_typo_tolerance_one_typo() {
|
||||
let result = search.execute().unwrap();
|
||||
assert_eq!(result.documents_ids.len(), 1);
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zean");
|
||||
search.limit(10);
|
||||
|
||||
@@ -51,8 +49,7 @@ fn test_typo_tolerance_one_typo() {
|
||||
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
|
||||
|
||||
// typo is now supported for 4 letters words
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zean");
|
||||
search.limit(10);
|
||||
|
||||
@@ -71,8 +68,7 @@ fn test_typo_tolerance_two_typo() {
|
||||
{
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zealand");
|
||||
search.limit(10);
|
||||
|
||||
@@ -81,8 +77,7 @@ fn test_typo_tolerance_two_typo() {
|
||||
let result = search.execute().unwrap();
|
||||
assert_eq!(result.documents_ids.len(), 1);
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zealemd");
|
||||
search.limit(10);
|
||||
|
||||
@@ -100,8 +95,7 @@ fn test_typo_tolerance_two_typo() {
|
||||
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
|
||||
|
||||
// typo is now supported for 4 letters words
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zealemd");
|
||||
search.limit(10);
|
||||
|
||||
@@ -170,8 +164,7 @@ fn test_typo_disabled_on_word() {
|
||||
{
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zealand");
|
||||
search.limit(10);
|
||||
|
||||
@@ -191,8 +184,7 @@ fn test_typo_disabled_on_word() {
|
||||
builder.set_exact_words(exact_words);
|
||||
builder.execute(&|| false, &Progress::default(), Default::default()).unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("zealand");
|
||||
search.limit(10);
|
||||
|
||||
@@ -211,8 +203,7 @@ fn test_disable_typo_on_attribute() {
|
||||
{
|
||||
let txn = index.read_txn().unwrap();
|
||||
|
||||
let progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
// typo in `antebel(l)um`
|
||||
search.query("antebelum");
|
||||
search.limit(10);
|
||||
@@ -231,8 +222,7 @@ 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 progress = Progress::default();
|
||||
let mut search = Search::new(&txn, &index, &progress);
|
||||
let mut search = Search::new(&txn, &index);
|
||||
search.query("antebelum");
|
||||
search.limit(10);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user