Releases: meilisearch/meilisearch
Release list
v1.51.0 👽
✨ Enhancement
-
Add filter condition to DSRs by @dureuill in #6505
New
filterrule activation conditionDynamic search rules (DSR) can now declare a new
filtercondition: it contains a singlevalueskey, whose value is a JSON object.
The keys of thisvaluesJSON object are the facet names (e.g.,color,genres, ...), while their values are the values that a filter must resolve to for these facets, so that the rule is active.Example of sending a DSR with a filter condition
Example of search query that enables the DSR above
{ "filter": "(category = shirt AND color = red) OR (category = jeans AND color = blue)" }Note that the filter only needs to have one branch resolving to all the facet values declared in the rule for the rule to be active.
New
lastUpdatedAtfieldDynamic search rules returned by
GET /dynamic-search-rules/{:ruleUid}andPOST /dynamic-search-rulescontain an additionallastUpdatedAtfield.This field is automatically updated with the
enqueuedAtvalue of the last task that modified the rule.Rules are listed with the most recently updated first
POST /dynamic-search-rulesnow lists rules in descendinglastUpdatedAtorder, meaning that the most recently updated rules will be listed first.New environment variables
New environment variables are defined to control the behavior of the DSR fuel:
MEILI_EXPERIMENTAL_DSR_FUEL_FILTER_FUEL(in range 0..4294967296): controls how many filter constraint combinations Meilisearch will attempt to resolve at search time before giving up and applying partial rules.MEILI_EXPERIMENTAL_DSR_FUEL_FILTER_OR_FUEL(in range 0..65536): controls how many filter disjunctions Meilisearch will build when turning a filter to its canonical shapeMEILI_EXPERIMENTAL_DSR_FUEL_FILTER_AND_FUEL(in range 0..65536): controls how many filter conjunctions Meilisearch will build in total when turning a filter to its canonical shapeMEILI_EXPERIMENTAL_DSR_FUEL_FILTER_DEPTH_FUEL(in range 0..256): controls the maximum recursive depth that Meilisearch allows when turning a filter to its canonical shape
-
Speed up search requests by @Kerollmops in #6528
Improves Meilisearch search speed by avoiding unnecessary internal work. We drastically reduced the number of times we retrieve data from disk to a single time across the whole search pipeline. This improvement will have the greatest effect on datasets with a large number of distinct fields across documents. We have seen search speeds up to 5.4x on a dataset with more than 14k different fields. -
Stabilize dumpless upgrade by @curquiza in #6486
⚠️ Breaking change following the stabilization of an experimental feature⚠️ The flag
—-experimental-dumpless-upgradeis renamed—-upgrade-db, keeping the exact same behavior. -
Remove unused experimental features by @curquiza in #6489
⚠️ Breaking change: removing the following experimental features⚠️ - Replication parameters: removing
--experimental-replication-parametersbecause outdated. We now have another way to handle replication. - Import dumps with old document indexer fallback: removing
--experimental-no-edition-2024-for-dumps. This flag existed to prevent bugs related to our new indexer, which is now stable. - No snapshot compression: removing
--experimental-no-snapshot-compactionbecause it's not useful anymore.
- Replication parameters: removing
🪲 Bug fixes
- Make sure legacy attribute patterns work by @Kerollmops in #6531
- Missing support for the shorthand filterable attributes syntax
🔩 Miscellaneous
- Add missing logs in multisearch by @ManyTheFish in #6529
- Docs: Fix stale pre-v1.0 supported versions statement by @vishnujayvel in #6524
- Bump sigstore/cosign-installer from 4.1.1 to 4.1.2 by @dependabot[bot] in #6427
- Bump actions/github-script from 7 to 9 by @dependabot[bot] in #6425
- Bump actions/upload-artifact from 4 to 7 by @dependabot[bot] in #6428
New Contributors
- @vishnujayvel made their first contribution in #6524
v1.50.0 🐐
Meilisearch v1.50 revamps the Dynamic Search Rules, adds support for federated document fetch in sharded configurations, among other improvements
Breaking changes
This release introduces breaking changes for users using some experimental features
dynamicSearchRules experimental feature
Request type changes
priorityhas been replaced withprecedence, which better reflects the behavior (lower precedence means the rule is applied first)conditionshas been modified from an array to an object with two fields: "query" of typeQueryConditionand "time" of timeTimeCondition- New type
QueryConditionthat contains the fieldsisEmpty(as previously) andwordsinstead ofcontains(same type) - It is now possible to pass
isEmpty: falsewithwordsin aQueryCondition. PassingisEmpty:truewithwordsstill results in a synchronous error. - New type
TimeConditionwith fieldsstartandend(unchanged semantics from previous type). - When specifying the
selectorof anAction, it is now mandatory to specify anid. Previously, it was optional, but the action would never trigger. - When listing rules with
POST /dynamic-search-rules,filter.attributePatternshas been replaced withfilter.query, an optional string that searches in ruledescriptionandconditions.query.words. - When calling
DELETE /dynamic-search-rules/{:ruleUid}orPATCH /dynamic-search-rules/{:ruleUid}in a sharded configuration, endpoint will not return a HTTP 400 error if called on a follower remote rather than on the leader.
Response changes
PATCH /dynamic-search-rules/{:ruleUid}andDELETE /dynamic-search-rules/{:ruleUid}now register an asynchronous task..- The response is modified to return the registered task instead of the modified dynamic search rule.
- HTTP 404 is no longer returned if the
{:ruleUid}portion of the URL refers to a rule that doesn't exist. This is because rules are processed asynchronously, and is consistent with the behavior ofDELETE /indexes/{:indexUid}/documents/{:docId}for{:docId}
network experimental feature
The default behavior for users using the network experimental feature with sharding configured (leader not null) will change on the following routes:
- GET
indexes/:uid/documents - GET
indexes/:uid/documents/:document_id - POST
indexes/:uid/documents/fetch
Meilisearch will now fetch the documents from all the shards and not only on the local machine when processing the request.
To keep the same behavior as before, users will have to set useNetwork to false when making their request.
🌈 Improvements
Scaling up the Dynamic Search Rules
- Dynamic search rules scale up to 75K rules without any impact on the search
- The API of Dynamic Search Rules has been simplified
- It is harder to send conditions that will result in the rules never activating
- This also unlocks future improvements such as filter activation conditions for search rules
Additions
- Add a new
DELETE /dynamic-search-ruleroute that deletes all the DSRs - Add the concept of "DSR fuel" that determines how much energy is spent resolving DSR during a search. The fuel is initialized with some default variables that can be overridden using environment variables:
MEILI_EXPERIMENTAL_DSR_FUEL_MAX_COUNTED_WORDS: max number of words considered inside of a search query for the purpose of findingconditions.query.wordsconstraints. Defaults to 10, max value is 255MEILI_EXPERIMENTAL_DSR_FUEL_MAX_ACTIVE_RULES: max number of active rules whose actions are evaluated. Defaults to 1000, max value is 4294967295MEILI_EXPERIMENTAL_DSR_FUEL_MAX_PIN_ACTIONS: max number of pin actions that are applied. Defaults to 100, max value is 4294967295MEILI_EXPERIMENTAL_DSR_FUEL_WORD_FUEL: max number of constraint combinations that are evaluated for the purpose of findingconditions.query.wordsconstraints. Defaults to 4096, max value is 4294967295
By @dureuill in #6484 and #6506
Behavior changes
- The
conditions.query.wordsbehaves differently fromquery.contains: previously, a rule would match if its conditionsquery.containswould be substrings ofqin the search query in the sense ofstr::contains. Now, a rule matches if all the words inconditions.query.wordsappear inq(after normalization). Forq = hero super,query.contains = super herowould not match, whereasconditions.query.words = super herodoes now match. This behavior is more in line with regular search, and allows improving performance. - Dynamic search rules are now replicated from the leader to its follower, when in a sharded configuration
Federated document fetch routes
GET indexes/:uid/documents, GET indexes/:uid/documents/:document_id and POST indexes/:uid/documents/fetch will now fetch the documents from all the shards in the configured network.
Moreover, a new useNetwork parameter is available to activate or deactivate the usage of the network.
By @ManyTheFish in #6495
Support partial wildcards when requesting facets
The facets parameter in search and federated search now supports more wildcards. Previously, only the single wildcard "*" was supported, requesting all filterable fields.
Now, patterns containing * are supported with the same matching rules as in filterableAttributes.attributePatterns and localizedAttributes.attributePatterns, such as dogs.*, which will add to the facet distribution all filterable fields that match the pattern (such as dogs.intel, dogs.kefir, etc.).
By @Kerollmops in #6497
🦋 Fixes
Fix migration from v1.48 and earlier
Migration via --experimental-dumpless-upgrade would fail in some cases in v1.49, when trying to migrate synonyms that contained no words (empty synonyms, or containing only separator tokens such as &).
Such synonyms are now ignored during migration, avoiding the issue.
By @Kerollmops in #6501
Fix filter memory consumption in some cases
In some conditions, the memory consumption of filters would increase quadratically with the length of the filter. This is now resolved for these cases.
By @ManyTheFish in #6509
No longer reject some correctly-escaped filters
Fix a bug where some filters containing escaped characters (such as \) would cause search requests to fail with invalid_search_filter
More fault-tolerant S3 snapshots
Potentially fix an issue when sending a request to AWS S3 to create a new multipart upload, ensuring we resend the request if it fails.
By @Kerollmops in #6494
🔩 Miscellaneous changes
- Add missing route descriptions for documentation by @curquiza in #6500
- Make the prototype docs clearer by @curquiza in #6503
- Improve maintenability by simplifying partitioning step by @ManyTheFish in #6511
- Fix frequently failing tests on Windows by @dureuill in #6520
Full Changelog: v1.49.0...v1.50.0
v1.49.0 🪺
✨ Enhancement
- Improve the synonyms storage by @Kerollmops in #6466
We improve synonyms' performance by changing how we store and retrieve them during query processing. Users may have experienced performance issues when the number of synonyms in an index was high, resulting in a significant impact on search performance. The Meilisearch support team advised moving the settings and synonyms-as-keywords to the dedicated documents. This is no longer an issue; synonyms are loaded lazily, only when a word matches a synonym. You can see performance improvements of up to 13x, depending on the number of synonyms.
🔩 Miscellaneous
- Fix the workflow after broken ranking scores by @Kerollmops in #6470
- Make OpenAPI rule less strict for routes returning 202 by @curquiza in #6488
v1.48.3 🫎
🪲 Bug fixes
-
Fix a rare S3 snapshots bug by @Kerollmops in #6472
We fixed a rare bug that could appear when using the S3 snapshot system. The bug is a race condition that occurs when we try to recycle internal buffers to reduce memory usage, which can cause an internal error and abort the snapshot upload.
-
Avoid remote search to return the same document twice by @ManyTheFish in #6473
When using the remote federated search, Meilisearch was returning the same document twice from different machines. This was due to an internal filter that was not forwarded properly to the remote instances.
🔩 Miscellaneous
- Add missing searchFilterParam to GET chat workspace settings response by @CaroFG in #6475
- Split unit tests into separate files (one commit per file) by @0xfandom in #6468
- Add missing information from pre-openAPI-migration by @curquiza in #6467
New Contributors
Thanks to @0xfandom, who made his first contribution in #6468 🎉
Full Changelog: v1.48.2...v1.48.3
v1.48.2 🫎
Meilisearch v1.48.2 and Meilisearch v1.47.1 address CVE-2026-57823 and CVE-2026-57824.
We recommend updating if you are in one of the following situations:
- You have API keys where
indexesis not["*"]and whereactionscontains more permissions than:["search", "documents.*", "indexes.*", "tasks.cancel", "tasks.delete", "tasks.get", "settings.*", "stats.*", "fields.post"] - You have search tenant tokens and either an embedder or a chat workspace
- We recommend that users of Meilisearch v1.48 update to Meilisearch v1.48.2
- We recommend that users of Meilisearch v1.47 or lower update to Meilisearch v1.47.1
These versions both fix the following:
- CVE-2026-57824: Improper authentication leads to privilege escalation: an authenticated user with an index-scoped API and the appropriate set of actions could use global actions to read and write the global state of the Meilisearch instance. Possibly impacted users of Meilisearch Cloud were contacted ahead-of-time.
- CVE-2026-57823: Improper authentication leads to information disclosure: a user with a search tenant token could get some limited information about the existence of a document outside of the scope of the search rules attached to the tenant token, an indirect information about the content of the document.
We detected no trace of exploitation of these vulnerabilities.
We thank PuH4ck3rX for reporting these vulnerabilities ❤️
v1.47.1 🦇
Meilisearch v1.48.2 and Meilisearch v1.47.1 address CVE-2026-57823 and CVE-2026-57824.
We recommend updating if you are in one of the following situations:
- You have API keys where
indexesis not["*"]and whereactionscontains more permissions than:["search", "documents.*", "indexes.*", "tasks.cancel", "tasks.delete", "tasks.get", "settings.*", "stats.*", "fields.post"] - You have search tenant tokens and either an embedder or a chat workspace
- We recommend that users of Meilisearch v1.48 update to Meilisearch v1.48.2
- We recommend that users of Meilisearch v1.47 or lower update to Meilisearch v1.47.1
These versions both fix the following:
- CVE-2026-57824: Improper authentication leads to privilege escalation: an authenticated user with an index-scoped API and the appropriate set of actions could use global actions to read and write the global state of the Meilisearch instance. Possibly impacted users of Meilisearch Cloud were contacted ahead-of-time.
- CVE-2026-57823: Improper authentication leads to information disclosure: a user with a search tenant token could get some limited information about the existence of a document outside of the scope of the search rules attached to the tenant token, an indirect information about the content of the document.
We detected no trace of exploitation of these vulnerabilities.
We thank PuH4ck3rX for reporting these vulnerabilities ❤️
v1.48.1 🫎
Revert #6432 due to a dumpless upgrade bug report.
Full Changelog: v1.48.0...v1.48.1
v1.48.0 🫎
✨ Enhancement
[Experimental] Render 🫎 template route
by @Mubelotix in #5765
Introduces a new POST /render-template route that can be used to render any template or fragment on any input and associated renderRoute experimental feature that gates access to the route.
This route can be used to test document templates and fragments before and after having configured an embedder.
A body payload for the route is of the form:
{
"template": /* templateTarget object */,
"input": /* inputTarget object or null */
}where template describes the template or fragment to render, and input describes what to use to render the template.
Upon calling this route, Meilisearch responds with:
{
"template": "{{doc.text}}",
"rendered": "template text after rendering using the input"
}where template contains the unrendered base text of the document template, or the unrendered base JSON object of a fragment, and rendered contains the result of rendering the template of the chosen input.
If input is null in the request, then rendered is null in the response, and the route can be used solely to retrieve a template or fragment from the settings of an index.
Before calling the route
The API of this route is subject to change, so before calling this route, please enable the renderRoute experimental feature:
PATCH /experimental-features --json '{"renderRoute": true}'Examples
- Rendering a document from an index on a document template from an embedder of that index
request
// POST /render-template
{
"template": {
"kind": "documentTemplate",
"indexUid": "movies",
"embedder": "myMoviesEmbedder"
},
"input": {
"kind": "indexDocument",
"indexUid": "movies",
"id": "2"
}response
{
"template": "A movie titled {{doc.title}} whose description starts with {{doc.overview|truncatewords:10}}",
"rendered": "A movie titled Ariel whose description starts with Taisto Kasurinen is a Finnish coal miner whose father has..."
}- Rendering an inline document on a fragment from an embedder of an index
request
// POST /render-template
{
"template": {
"kind": "indexingFragment",
"indexUid": "dogs",
"embedder": "multi",
"fragment": "captionedImage"
},
"input": {
"kind": "inlineDocument",
"inline": { // pass your document inline as a JSON object
"kind": "dog",
"name": "iko",
"breed": "jack russell",
"mime": "image/png",
"image": "/9j/4AAQSk..."
}
}
}
response
{
"template": {
"content": [
{
"type": "text",
"text": "A picture of a {{doc.kind}} of breed {{doc.breed}}"
},
{
"type": "image_base64",
"image_base64": "data:{{doc.mime}};base64,{{doc.image}}"
}
]
},
"rendered": {
"content": [
{
"type": "text",
"text": "A picture of a dog of breed jack russell"
},
{
"type": "image_base64",
"image_base64": "data:image/png;base64,/9j/4AAQSk..."
}
]
}
}- Rendering a search query on a search fragment from a multimodal embedder of an index
request
// POST /render-template
{
"template": {
"kind": "searchFragment",
"indexUid": "testIndex",
"embedder": "testEmbedder",
"fragment": "justBreed"
},
"input": {
"kind": "inlineSearch",
"inline": { // pass the search query inline
"q": "unused",
"media": {
"name": "iko",
"breed": "jack russell"
},
"filter": "ignored"
}
}
}response
{
"template": "It's a {{ media.breed }}",
"rendered": "It's a jack russell"
}- Rendering an inline document on the document template from the chat settings of an index
request
// POST /render-template
{
"template": {
"kind": "chatDocumentTemplate",
"indexUid": "movies"
// no embedder to specify since chat document template is global to index
},
"input": {
"kind": "indexDocument",
"indexUid": "movies",
"id": "2"
}response
{
"template": "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
"rendered": "id: 2\ntitle: Ariel\noverview: Taisto Kasurinen is a Finnish coal miner whose father has just committed suicide and who is framed for a crime he did not commit. In jail, he starts to dream about leaving the country and starting a new life. He escapes from prison but things don't go as planned...\ngenres: DramaCrimeComedy\nposter: https://image.tmdb.org/t/p/w500/ojDg0PGvs6R9xYFodRct2kdI6wC.jpg\nrelease_date: 593395200\n"
}- Rendering a document from an index on an inline document template
request
// POST /render-template
{
"template": {
"kind": "inlineDocumentTemplate",
"inline": "You can pass templates inline as well: nice to test them! {{doc.id}}"
},
"input": {
"kind": "indexDocument",
"indexUid": "movies",
"id": "2"
}response
{
"template": "You can pass templates inline as well: nice to test them! {{doc.id}}",
"rendered": "You can pass templates inline as well: nice to test them! 2"
}- Rendering an inline document on an inline indexing fragment
request
// POST /render-template
{
"template": {
"kind": "inlineFragment",
"inline": {
"json_maps": "supported for fragments",
"any_string": "is in liquid format: {{doc.test}}"
}
},
"input": {
"kind": "inlineDocument",
"inline": {
"test": true
}
}
}response
{
"template": {
"json_maps": "supported for fragments",
"any_string": "is in liquid format: {{doc.test}}"
},
"rendered": {
"json_maps": "supported for fragments",
"any_string": "is in liquid format: true"
}
}[Experimental] Only support foreign filters on retrieval routes
by @ManyTheFish in #6446
Foreign filters are meant to be used in a retrieval context (search, get document...), but all the actions related to writing or modifying a document could have several unexpected behaviors if foreign filters are accepted.
We prefer forbidding the usage of this feature on the writing routes.
The following routes do not support Foreign-filter anymore:
- Edit documents by function: POST
/indexes/{index_uid}/documents/edit - Delete documents by filter: POST
/indexes/{index_uid}/documents/delete - Export to a remote Meilisearch: POST
/export
Additional change: we now ensure that the experimental features are checked when parsing a filter
🪲 Bug fixes
- Support prefix search on words registered in the disableOnAttributes and disableOnNumbers settings by @antcybersec in #6432
- Add missing logs in search performance details @ManyTheFish in #6457
- Ensure the index map budget is a multiplier of the OS page size by @genisis0x in #6454
🔒 Security
🔩 Miscellaneous
- Replace the
queueDocumentsFetchexperimental feature withdisableDocumentsFetchQueueconverting the feature from an opt-in to an opt-out
By @ManyTheFish in #6456 - Bump and removes unused dependencies by @Kerollmops in #6444
- Fix Ollama embeddings changes to fix CI tests by @Kerollmops in #6450
❤️ Thanks again to @genisis0x and @antcybersec
v1.47.0 🦇
🌈 Enhancements
Search personalization on federated search
We now support using the search personalization feature on federated search requests.
Like page/hitPerPage or limit/offset, the personalization option must be specified in the federation attribute to work properly.
Otherwise, an error will be returned reminding you to move the attribute in federation.
By @ManyTheFish in #6414
The new settings indexer is feature complete 🎉
- We now better support the tokenizer-related settings
- We improved the quality of the new settings indexer to enhance the engine's performance when changing the locales, the dictionary, synonyms, stop words, separator, and non-separator tokens.
- This makes the new settings indexer feature-complete, meaning that, unless you set the
MEILI_EXPERIMENTAL_NO_EDITION_2024_FOR_SETTINGSenvironment variable totrue, all settings tasks can now be handled by the new settings indexer, bringing a better scaling behavior, much faster cancellation, and a more precise progress view.
By @Kerollmops in #6409
Observability improvements
We expose more Prometheus metrics to improve observability, specifically to show more metrics on document throughput and ease debugging.
By @Kerollmops in #6430
🦋 Fixes
- Putting attributeRank/ wordPosition before words in the rankingRules list will no longer remove hits from the response, by @pjdurden in #6437
- Meilisearch will no longer ignore the
searchCutoffMsin some conditions when embedding documents, by @dureuill in #6447 - Meilisearch will no longer fail to proxy a search request with a filter containing a
'during remote federated search oruseNetwork: truesearch requests, by @dureuill in #6445
🔒 Security
🔩 Misc. changes
Search implementation refactor
Refactor the search pipeline to mutualize the code.
The new implementation will always perform a federated search under the hood, and then the output will be transformed into the expected route's output.
Noticeable changes from the user perspective:
- Some error messages have been modified
- Small breaking change: a few error codes change, such as
MultiSearch<Error><-->Search<Error>
Other changes
- Make it easier and less error-prone to declare a type that is used as a body parameter on a Meilisearch endpoint, by @dureuill in #6429
- Remove the now unused
vectorStoreBackendsetting from the settings, by @Kerollmops in #6399 - Replace custom hf-hub git dependency by the official one by @Kerollmops in #6442
- Update Python SDK test CI by @Strift in #6439
- Refactor the code to use the
MustStopProcessingtype everywhere by @Kerollmops in #6423
New Contributors
Full Changelog: v1.46.1...v1.47.0
v1.46.1 🦆
Queue documents fetch routes
Add an experimental feature, queueDocumentsFetch, forcing the routes GET indexes/:uid/documents and POST indexes/:uid/documents/fetch to wait in the search queue if there is no available thread to process them.