",
@@ -36,6 +36,12 @@ license = "MIT"
[profile.release]
codegen-units = 1
+# We now compile heed without the NDEBUG define for better performance.
+# However, we still enable debug assertions for a better detection of
+# disk corruption on the cloud or in OSS.
+[profile.release.package.heed]
+debug-assertions = true
+
[profile.dev.package.flate2]
opt-level = 3
@@ -43,6 +49,3 @@ opt-level = 3
opt-level = 3
[profile.dev.package.roaring]
opt-level = 3
-
-[patch.crates-io]
-roaring = { git = "https://github.com/RoaringBitmap/roaring-rs", branch = "clone-iter-slice" }
diff --git a/Dockerfile b/Dockerfile
index 04557df59..5a9a4691f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Compile
-FROM rust:1.79.0-alpine3.20 AS compiler
+FROM rust:1.85-alpine3.20 AS compiler
RUN apk add -q --no-cache build-base openssl-dev
diff --git a/LICENSE b/LICENSE
index 76a573977..686f24931 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019-2024 Meili SAS
+Copyright (c) 2019-2025 Meili SAS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 4be92d439..d85942584 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,13 @@
-
+
+
+
+
+
+
+
ā” A lightning-fast search engine that fits effortlessly into your apps, websites, and workflow š
@@ -58,6 +64,7 @@ See the list of all our example apps in our [demos repository](https://github.co
- **[Multi-Tenancy](https://www.meilisearch.com/docs/learn/security/multitenancy_tenant_tokens?utm_campaign=oss&utm_source=github&utm_medium=meilisearch&utm_content=features):** personalize search results for any number of application tenants
- **Highly Customizable:** customize Meilisearch to your specific needs or use our out-of-the-box and hassle-free presets
- **[RESTful API](https://www.meilisearch.com/docs/reference/api/overview?utm_campaign=oss&utm_source=github&utm_medium=meilisearch&utm_content=features):** integrate Meilisearch in your technical stack with our plugins and SDKs
+- **AI-ready:** works out of the box with [langchain](https://www.meilisearch.com/with/langchain) and the [model context protocol](https://github.com/meilisearch/meilisearch-mcp)
- **Easy to install, deploy, and maintain**
## š Documentation
diff --git a/assets/grafana-dashboard.json b/assets/grafana-dashboard.json
index 2cfa85a46..027afcbba 100644
--- a/assets/grafana-dashboard.json
+++ b/assets/grafana-dashboard.json
@@ -1403,6 +1403,104 @@
"title": "Number of tasks by indexes",
"type": "timeseries"
},
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 15,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "none"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 11,
+ "w": 12,
+ "x": 12,
+ "y": 51
+ },
+ "id": 29,
+ "interval": "5s",
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "8.1.4",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "editorMode": "builder",
+ "exemplar": true,
+ "expr": "meilisearch_task_queue_latency_seconds{instance=\"$instance\", job=\"$job\"}",
+ "interval": "",
+ "legendFormat": "{{value}} ",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Task queue latency",
+ "type": "timeseries"
+ },
{
"collapsed": true,
"datasource": {
diff --git a/assets/ph-banner.png b/assets/ph-banner.png
new file mode 100644
index 000000000..399c7fd10
Binary files /dev/null and b/assets/ph-banner.png differ
diff --git a/bors.toml b/bors.toml
deleted file mode 100644
index 96e9ef65e..000000000
--- a/bors.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-status = [
- 'Tests on ubuntu-20.04',
- 'Tests on macos-13',
- 'Tests on windows-2022',
- 'Run Clippy',
- 'Run Rustfmt',
- 'Run tests in debug',
-]
-pr_status = ['Milestone Check']
-# 3 hours timeout
-timeout-sec = 10800
diff --git a/crates/benchmarks/Cargo.toml b/crates/benchmarks/Cargo.toml
index eec30ea3f..a2cddd554 100644
--- a/crates/benchmarks/Cargo.toml
+++ b/crates/benchmarks/Cargo.toml
@@ -11,27 +11,27 @@ edition.workspace = true
license.workspace = true
[dependencies]
-anyhow = "1.0.86"
+anyhow = "1.0.95"
bumpalo = "3.16.0"
-csv = "1.3.0"
+csv = "1.3.1"
memmap2 = "0.9.5"
milli = { path = "../milli" }
mimalloc = { version = "0.1.43", default-features = false }
-serde_json = { version = "1.0.120", features = ["preserve_order"] }
-tempfile = "3.14.0"
+serde_json = { version = "1.0.135", features = ["preserve_order"] }
+tempfile = "3.15.0"
[dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports"] }
rand = "0.8.5"
rand_chacha = "0.3.1"
-roaring = "0.10.6"
+roaring = "0.10.10"
[build-dependencies]
-anyhow = "1.0.86"
-bytes = "1.6.0"
+anyhow = "1.0.95"
+bytes = "1.9.0"
convert_case = "0.6.0"
-flate2 = "1.0.30"
-reqwest = { version = "0.12.5", features = ["blocking", "rustls-tls"], default-features = false }
+flate2 = "1.0.35"
+reqwest = { version = "0.12.12", features = ["blocking", "rustls-tls"], default-features = false }
[features]
default = ["milli/all-tokenizations"]
diff --git a/crates/benchmarks/benches/indexing.rs b/crates/benchmarks/benches/indexing.rs
index 2f33c3454..9199c3877 100644
--- a/crates/benchmarks/benches/indexing.rs
+++ b/crates/benchmarks/benches/indexing.rs
@@ -8,14 +8,16 @@ use bumpalo::Bump;
use criterion::{criterion_group, criterion_main, Criterion};
use milli::documents::PrimaryKey;
use milli::heed::{EnvOpenOptions, RwTxn};
+use milli::progress::Progress;
use milli::update::new::indexer;
-use milli::update::{IndexDocumentsMethod, IndexerConfig, Settings};
+use milli::update::{IndexerConfig, Settings};
use milli::vector::EmbeddingConfigs;
-use milli::Index;
+use milli::{FilterableAttributesRule, Index};
use rand::seq::SliceRandom;
use rand_chacha::rand_core::SeedableRng;
use roaring::RoaringBitmap;
+#[cfg(not(windows))]
#[global_allocator]
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
@@ -33,10 +35,11 @@ fn setup_dir(path: impl AsRef) {
fn setup_index() -> Index {
let path = "benches.mmdb";
setup_dir(path);
- let mut options = EnvOpenOptions::new();
+ let options = EnvOpenOptions::new();
+ let mut options = options.read_txn_without_tls();
options.map_size(100 * 1024 * 1024 * 1024); // 100 GB
options.max_readers(100);
- Index::new(options, path).unwrap()
+ Index::new(options, path, true).unwrap()
}
fn setup_settings<'t>(
@@ -55,7 +58,8 @@ fn setup_settings<'t>(
let searchable_fields = searchable_fields.iter().map(|s| s.to_string()).collect();
builder.set_searchable_fields(searchable_fields);
- let filterable_fields = filterable_fields.iter().map(|s| s.to_string()).collect();
+ let filterable_fields =
+ filterable_fields.iter().map(|s| FilterableAttributesRule::Field(s.to_string())).collect();
builder.set_filterable_fields(filterable_fields);
let sortable_fields = sortable_fields.iter().map(|s| s.to_string()).collect();
@@ -136,10 +140,9 @@ fn indexing_songs_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -150,13 +153,14 @@ fn indexing_songs_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -164,7 +168,7 @@ fn indexing_songs_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -202,10 +206,9 @@ fn reindexing_songs_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -216,13 +219,14 @@ fn reindexing_songs_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -230,7 +234,7 @@ fn reindexing_songs_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -246,10 +250,9 @@ fn reindexing_songs_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -260,13 +263,14 @@ fn reindexing_songs_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -274,7 +278,7 @@ fn reindexing_songs_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -314,10 +318,9 @@ fn deleting_songs_in_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -328,13 +331,14 @@ fn deleting_songs_in_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -342,7 +346,7 @@ fn deleting_songs_in_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -390,10 +394,9 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS_1_2, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -404,13 +407,14 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -418,7 +422,7 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -434,10 +438,9 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS_3_4, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -448,13 +451,14 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -462,7 +466,7 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -474,10 +478,9 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS_4_4, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -488,13 +491,14 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -502,7 +506,7 @@ fn indexing_songs_in_three_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -540,11 +544,10 @@ fn indexing_songs_without_faceted_numbers(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -555,13 +558,14 @@ fn indexing_songs_without_faceted_numbers(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -569,7 +573,7 @@ fn indexing_songs_without_faceted_numbers(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -607,10 +611,9 @@ fn indexing_songs_without_faceted_fields(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_SONGS, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -621,13 +624,14 @@ fn indexing_songs_without_faceted_fields(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -635,7 +639,7 @@ fn indexing_songs_without_faceted_fields(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -673,10 +677,9 @@ fn indexing_wiki(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -687,13 +690,14 @@ fn indexing_wiki(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -701,7 +705,7 @@ fn indexing_wiki(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -738,10 +742,9 @@ fn reindexing_wiki(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -752,13 +755,14 @@ fn reindexing_wiki(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -766,7 +770,7 @@ fn reindexing_wiki(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -782,10 +786,9 @@ fn reindexing_wiki(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -796,13 +799,14 @@ fn reindexing_wiki(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -810,7 +814,7 @@ fn reindexing_wiki(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -849,10 +853,9 @@ fn deleting_wiki_in_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -863,13 +866,14 @@ fn deleting_wiki_in_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -877,7 +881,7 @@ fn deleting_wiki_in_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -924,11 +928,10 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents =
utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES_1_2, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -939,13 +942,14 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -953,7 +957,7 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -969,11 +973,10 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents =
utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES_3_4, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -984,13 +987,14 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -998,7 +1002,7 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1010,11 +1014,10 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents =
utils::documents_from(datasets_paths::SMOL_WIKI_ARTICLES_4_4, "csv");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -1025,13 +1028,14 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -1039,7 +1043,7 @@ fn indexing_wiki_in_three_batches(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1077,10 +1081,9 @@ fn indexing_movies_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::MOVIES, "json");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -1091,13 +1094,14 @@ fn indexing_movies_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -1105,7 +1109,7 @@ fn indexing_movies_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1142,10 +1146,9 @@ fn reindexing_movies_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::MOVIES, "json");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -1156,13 +1159,14 @@ fn reindexing_movies_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -1170,7 +1174,7 @@ fn reindexing_movies_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1186,10 +1190,9 @@ fn reindexing_movies_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::MOVIES, "json");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -1200,13 +1203,14 @@ fn reindexing_movies_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -1214,7 +1218,7 @@ fn reindexing_movies_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1253,10 +1257,9 @@ fn deleting_movies_in_batches_default(c: &mut Criterion) {
let db_fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
let mut new_fields_ids_map = db_fields_ids_map.clone();
- let mut indexer =
- indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
+ let mut indexer = indexer::DocumentOperation::new();
let documents = utils::documents_from(datasets_paths::MOVIES, "json");
- indexer.add_documents(&documents).unwrap();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -1267,13 +1270,14 @@ fn deleting_movies_in_batches_default(c: &mut Criterion) {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -1281,7 +1285,7 @@ fn deleting_movies_in_batches_default(c: &mut Criterion) {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
@@ -1321,6 +1325,7 @@ fn delete_documents_from_ids(index: Index, document_ids_to_delete: Vec Index {
}
create_dir_all(conf.database_name).unwrap();
- let mut options = EnvOpenOptions::new();
+ let options = EnvOpenOptions::new();
+ let mut options = options.read_txn_without_tls();
options.map_size(100 * 1024 * 1024 * 1024); // 100 GB
options.max_readers(100);
- let index = Index::new(options, conf.database_name).unwrap();
+ let index = Index::new(options, conf.database_name, true).unwrap();
let config = IndexerConfig::default();
let mut wtxn = index.write_txn().unwrap();
@@ -98,8 +100,8 @@ pub fn base_setup(conf: &Conf) -> Index {
let mut new_fields_ids_map = db_fields_ids_map.clone();
let documents = documents_from(conf.dataset, conf.dataset_format);
- let mut indexer = indexer::DocumentOperation::new(IndexDocumentsMethod::ReplaceDocuments);
- indexer.add_documents(&documents).unwrap();
+ let mut indexer = indexer::DocumentOperation::new();
+ indexer.replace_documents(&documents).unwrap();
let indexer_alloc = Bump::new();
let (document_changes, _operation_stats, primary_key) = indexer
@@ -110,13 +112,14 @@ pub fn base_setup(conf: &Conf) -> Index {
None,
&mut new_fields_ids_map,
&|| false,
- &|_progress| (),
+ Progress::default(),
)
.unwrap();
indexer::index(
&mut wtxn,
&index,
+ &milli::ThreadPoolNoAbortBuilder::new().build().unwrap(),
config.grenad_parameters(),
&db_fields_ids_map,
new_fields_ids_map,
@@ -124,7 +127,7 @@ pub fn base_setup(conf: &Conf) -> Index {
&document_changes,
EmbeddingConfigs::default(),
&|| false,
- &|_| (),
+ &Progress::default(),
)
.unwrap();
diff --git a/crates/build-info/Cargo.toml b/crates/build-info/Cargo.toml
index c24dffe5c..f8ede756e 100644
--- a/crates/build-info/Cargo.toml
+++ b/crates/build-info/Cargo.toml
@@ -11,8 +11,8 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-time = { version = "0.3.36", features = ["parsing"] }
+time = { version = "0.3.37", features = ["parsing"] }
[build-dependencies]
-anyhow = "1.0.86"
-vergen-git2 = "1.0.0"
+anyhow = "1.0.95"
+vergen-git2 = "1.0.2"
diff --git a/crates/dump/Cargo.toml b/crates/dump/Cargo.toml
index f9d2a9a0b..5c427916c 100644
--- a/crates/dump/Cargo.toml
+++ b/crates/dump/Cargo.toml
@@ -11,21 +11,21 @@ readme.workspace = true
license.workspace = true
[dependencies]
-anyhow = "1.0.86"
-flate2 = "1.0.30"
-http = "1.1.0"
+anyhow = "1.0.95"
+flate2 = "1.0.35"
+http = "1.2.0"
meilisearch-types = { path = "../meilisearch-types" }
-once_cell = "1.19.0"
-regex = "1.10.5"
-roaring = { version = "0.10.6", features = ["serde"] }
-serde = { version = "1.0.204", features = ["derive"] }
-serde_json = { version = "1.0.120", features = ["preserve_order"] }
-tar = "0.4.41"
-tempfile = "3.10.1"
-thiserror = "1.0.61"
-time = { version = "0.3.36", features = ["serde-well-known", "formatting", "parsing", "macros"] }
-tracing = "0.1.40"
-uuid = { version = "1.10.0", features = ["serde", "v4"] }
+once_cell = "1.20.2"
+regex = "1.11.1"
+roaring = { version = "0.10.10", features = ["serde"] }
+serde = { version = "1.0.217", features = ["derive"] }
+serde_json = { version = "1.0.135", features = ["preserve_order"] }
+tar = "0.4.43"
+tempfile = "3.15.0"
+thiserror = "2.0.9"
+time = { version = "0.3.37", features = ["serde-well-known", "formatting", "parsing", "macros"] }
+tracing = "0.1.41"
+uuid = { version = "1.11.0", features = ["serde", "v4"] }
[dev-dependencies]
big_s = "1.0.2"
diff --git a/crates/dump/README.md b/crates/dump/README.md
index 3537f188e..42d84ec80 100644
--- a/crates/dump/README.md
+++ b/crates/dump/README.md
@@ -10,8 +10,10 @@ dump
āāā instance-uid.uuid
āāā keys.jsonl
āāā metadata.json
-āāā tasks
- āāā update_files
- ā āāā [task_id].jsonl
+āāā tasks
+ā āāā update_files
+ā ā āāā [task_id].jsonl
+ā āāā queue.jsonl
+āāā batches
āāā queue.jsonl
-```
\ No newline at end of file
+```
diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs
index 8bed7f0d4..4e2d6ac2f 100644
--- a/crates/dump/src/lib.rs
+++ b/crates/dump/src/lib.rs
@@ -141,6 +141,9 @@ pub enum KindDump {
instance_uid: Option,
},
SnapshotCreation,
+ UpgradeDatabase {
+ from: (u32, u32, u32),
+ },
}
impl From for TaskDump {
@@ -210,6 +213,9 @@ impl From for KindDump {
KindDump::DumpCreation { keys, instance_uid }
}
KindWithContent::SnapshotCreation => KindDump::SnapshotCreation,
+ KindWithContent::UpgradeDatabase { from: version } => {
+ KindDump::UpgradeDatabase { from: version }
+ }
}
}
}
@@ -222,14 +228,16 @@ pub(crate) mod test {
use big_s::S;
use maplit::{btreemap, btreeset};
+ use meilisearch_types::batches::{Batch, BatchEnqueuedAt, BatchStats};
use meilisearch_types::facet_values_sort::FacetValuesSort;
- use meilisearch_types::features::RuntimeTogglableFeatures;
+ use meilisearch_types::features::{Network, Remote, RuntimeTogglableFeatures};
use meilisearch_types::index_uid_pattern::IndexUidPattern;
use meilisearch_types::keys::{Action, Key};
- use meilisearch_types::milli;
use meilisearch_types::milli::update::Setting;
+ use meilisearch_types::milli::{self, FilterableAttributesRule};
use meilisearch_types::settings::{Checked, FacetingSettings, Settings};
- use meilisearch_types::tasks::{Details, Status};
+ use meilisearch_types::task_view::DetailsView;
+ use meilisearch_types::tasks::{Details, Kind, Status};
use serde_json::{json, Map, Value};
use time::macros::datetime;
use uuid::Uuid;
@@ -271,7 +279,10 @@ pub(crate) mod test {
let settings = Settings {
displayed_attributes: Setting::Set(vec![S("race"), S("name")]).into(),
searchable_attributes: Setting::Set(vec![S("name"), S("race")]).into(),
- filterable_attributes: Setting::Set(btreeset! { S("race"), S("age") }),
+ filterable_attributes: Setting::Set(vec![
+ FilterableAttributesRule::Field(S("race")),
+ FilterableAttributesRule::Field(S("age")),
+ ]),
sortable_attributes: Setting::Set(btreeset! { S("age") }),
ranking_rules: Setting::NotSet,
stop_words: Setting::NotSet,
@@ -292,11 +303,39 @@ pub(crate) mod test {
embedders: Setting::NotSet,
search_cutoff_ms: Setting::NotSet,
localized_attributes: Setting::NotSet,
+ facet_search: Setting::NotSet,
+ prefix_search: Setting::NotSet,
_kind: std::marker::PhantomData,
};
settings.check()
}
+ pub fn create_test_batches() -> Vec {
+ vec![Batch {
+ uid: 0,
+ details: DetailsView {
+ received_documents: Some(12),
+ indexed_documents: Some(Some(10)),
+ ..DetailsView::default()
+ },
+ progress: None,
+ stats: BatchStats {
+ total_nb_tasks: 1,
+ status: maplit::btreemap! { Status::Succeeded => 1 },
+ types: maplit::btreemap! { Kind::DocumentAdditionOrUpdate => 1 },
+ index_uids: maplit::btreemap! { "doggo".to_string() => 1 },
+ progress_trace: Default::default(),
+ write_channel_congestion: None,
+ },
+ enqueued_at: Some(BatchEnqueuedAt {
+ earliest: datetime!(2022-11-11 0:00 UTC),
+ oldest: datetime!(2022-11-11 0:00 UTC),
+ }),
+ started_at: datetime!(2022-11-20 0:00 UTC),
+ finished_at: Some(datetime!(2022-11-21 0:00 UTC)),
+ }]
+ }
+
pub fn create_test_tasks() -> Vec<(TaskDump, Option>)> {
vec![
(
@@ -419,6 +458,15 @@ pub(crate) mod test {
index.flush().unwrap();
index.settings(&settings).unwrap();
+ // ========== pushing the batch queue
+ let batches = create_test_batches();
+
+ let mut batch_queue = dump.create_batches_queue().unwrap();
+ for batch in &batches {
+ batch_queue.push_batch(batch).unwrap();
+ }
+ batch_queue.flush().unwrap();
+
// ========== pushing the task queue
let tasks = create_test_tasks();
@@ -447,6 +495,10 @@ pub(crate) mod test {
dump.create_experimental_features(features).unwrap();
+ // ========== network
+ let network = create_test_network();
+ dump.create_network(network).unwrap();
+
// create the dump
let mut file = tempfile::tempfile().unwrap();
dump.persist_to(&mut file).unwrap();
@@ -456,7 +508,14 @@ pub(crate) mod test {
}
fn create_test_features() -> RuntimeTogglableFeatures {
- RuntimeTogglableFeatures { vector_store: true, ..Default::default() }
+ RuntimeTogglableFeatures::default()
+ }
+
+ fn create_test_network() -> Network {
+ Network {
+ local: Some("myself".to_string()),
+ remotes: maplit::btreemap! {"other".to_string() => Remote { url: "http://test".to_string(), search_api_key: Some("apiKey".to_string()) }},
+ }
}
#[test]
@@ -507,5 +566,9 @@ pub(crate) mod test {
// ==== checking the features
let expected = create_test_features();
assert_eq!(dump.features().unwrap().unwrap(), expected);
+
+ // ==== checking the network
+ let expected = create_test_network();
+ assert_eq!(&expected, dump.network().unwrap().unwrap());
}
}
diff --git a/crates/dump/src/reader/compat/v5_to_v6.rs b/crates/dump/src/reader/compat/v5_to_v6.rs
index 785542cce..6b63e7c6b 100644
--- a/crates/dump/src/reader/compat/v5_to_v6.rs
+++ b/crates/dump/src/reader/compat/v5_to_v6.rs
@@ -196,6 +196,10 @@ impl CompatV5ToV6 {
pub fn features(&self) -> Result