Multi-search
The /multi-search
route allows you to perform multiple search queries on one or more indexes by bundling them into a single HTTP request. Multi-search is also known as federated search.
Perform a multi-search
Bundle multiple search queries in a single API request. Use this endpoint to search through multiple indexes at once.
Body
Name | Type | Description |
---|---|---|
federation | Object | If present and not null , returns a single list merging all search results across all specified queries |
queries | Array of objects | Contains the list of search queries to perform. The indexUid search parameter is required, all other parameters are optional |
WARNING
If Meilisearch encounters an error when handling any of the queries in a multi-search request, it immediately stops processing the request and returns an error message. The returned message will only address the first error encountered.
federation
Use federation
to receive a single list with all search results from all specified queries, in descending ranking score order. This is called federated search.
federation
may optionally contain the following parameters:
Parameter | Type | Default value | Description |
---|---|---|---|
offset | Integer | 0 | Number of documents to skip |
limit | Integer | 20 | Maximum number of documents returned |
facetsByIndex | Object of arrays | null | Display facet information for the specified indexes |
mergeFacets | Object | null | Display facet information for the specified indexes |
If federation
is missing or null
, Meilisearch returns a list of multiple search result objects, with each item from the list corresponding to a search query in the request.
facetsByIndex
facetsByIndex
must be an object. Its keys must correspond to indexes in your Meilisearch project. Each key must be associated with an array of attributes in the filterable attributes list of that index:
"facetsByIndex": {
"INDEX_A": ["ATTRIBUTE_X", "ATTRIBUTE_Y"],
"INDEX_B": ["ATTRIBUTE_Z"]
}
When you specify facetsByIndex
, multi-search responses include an extra facetsByIndex
field. The response's facetsByIndex
is an object with one field for each queried index:
{
"hits" [ … ],
…
"facetsByIndex": {
"INDEX_A": {
"distribution": {
"ATTRIBUTE_X": {
"KEY": <Integer>,
"KEY": <Integer>,
…
},
"ATTRIBUTE_Y": {
"KEY": <Integer>,
…
}
},
"stats": {
"KEY": {
"min": <Integer>,
"max": <Integer>
}
}
},
"INDEX_B": {
…
}
}
}
mergeFacets
mergeFacets
must be an object and may contain the following fields:
maxValuesPerFacet
: must be an integer. When specified, indicates the maximum number of returned values for a single facet. Defaults to the value assigned to themaxValuesPerFacet
index setting
When both facetsByIndex
and mergeFacets
are present and not null, facet information included in multi-search responses is merged across all queried indexes. Instead of facetsByIndex
, the response includes two extra fields: facetDistribution
and facetStats
:
{
"hits": [ … ],
…
"facetFederation": {
"ATTRIBUTE": {
"VALUE": <Integer>,
"VALUE": <Integer>
}
},
"facetStats": {
"ATTRIBUTE": {
"min": <Integer>,
"max": <Integer>
}
}
}
Merge algorithm for federated searches
Federated search's merged results are returned in decreasing ranking score. To obtain the final list of results, Meilisearch compares with the following procedure:
- Detailed ranking scores are normalized in the following way for both hits:
- Consecutive relevancy scores (related to the rules
words
,typo
,attribute
,exactness
orvector
) are grouped in a single score for each hit sort
andgeosort
score details remain unchanged
- Consecutive relevancy scores (related to the rules
- Normalized detailed ranking scores are compared lexicographically for both hits:
- If both hits have a relevancy score, then the bigger score wins. If it is a tie, move to next step
- If one result has a relevancy score or a (geo)sort score, Meilisearch picks it
- If both results have a sort or geosort score in the same sorting direction, then Meilisearch compares the values according to the common sort direction. The result with the value that must come first according to the common sort direction wins. If it is a tie, go to the next step
- Compare the global ranking scores of both hits to determine which comes first, ignoring any sorting or geosorting
- In the case of a perfect tie, documents from the query with the lowest rank in the
queries
array are preferred.
Distinct documents and federated search
Meilisearch considers two documents the same if:
- They come from the same index
- And their primary key is the same
There is no way to specify that two documents should be treated as the same across multiple indexes.
queries
queries
must be an array of objects. Each object may contain the following search parameters:
Search parameter | Type | Default value | Description |
---|---|---|---|
federationOptions | Object | null | Configure federation settings for a specific query |
indexUid | String | N/A | uid of the requested index |
q | String | "" | Query string |
offset | Integer | 0 | Number of documents to skip |
limit | Integer | 20 | Maximum number of documents returned |
hitsPerPage | Integer | 1 | Maximum number of documents returned for a page |
page | Integer | 1 | Request a specific page of results |
filter | String | null | Filter queries by an attribute's value |
facets | Array of strings | null | Display the count of matches per facet |
attributesToRetrieve | Array of strings | ["*"] | Attributes to display in the returned documents |
attributesToCrop | Array of strings | null | Attributes whose values have to be cropped |
cropLength | Integer | 10 | Maximum length of cropped value in words |
cropMarker | String | "…" | String marking crop boundaries |
attributesToHighlight | Array of strings | null | Highlight matching terms contained in an attribute |
highlightPreTag | String | "<em>" | String inserted at the start of a highlighted term |
highlightPostTag | String | "</em>" | String inserted at the end of a highlighted term |
showMatchesPosition | Boolean | false | Return matching terms location |
sort | Array of strings | null | Sort search results by an attribute's value |
matchingStrategy | String | last | Strategy used to match query terms within documents |
showRankingScore | Boolean | false | Display the global ranking score of a document |
attributesToSearchOn | Array of strings | ["*"] | Restrict search to the specified attributes |
Unless otherwise noted, search parameters for multi-search queries function exactly like search parameters for the /search
endpoint.
limit
, offset
, hitsPerPage
and page
These options are not compatible with federated searches.
federationOptions
federationOptions
must be an object. It accepts the following parameters:
weight
: serves as a multiplicative factor to ranking scores of search results in this specific query. If <1.0
, the hits from this query are less likely to appear in the final results list. If >1.0
, the hits from this query are more likely to appear in the final results list. Must be a positive floating-point number. Defaults to1.0
Response
The response to /multi-search
queries may take two shapes: federated and non-federated.
Non-federated multi-search requests
Name | Type | Description |
---|---|---|
results | Array of objects | Results of the search queries in the same order they were requested in |
Each search result object is composed of the following fields:
Name | Type | Description |
---|---|---|
indexUid | String | uid of the requested index |
hits | Array of objects | Results of the query |
offset | Number | Number of documents skipped |
limit | Number | Number of documents to take |
estimatedTotalHits | Number | Estimated total number of matches |
totalHits | Number | Exhaustive total number of matches |
totalPages | Number | Exhaustive total number of search result pages |
hitsPerPage | Number | Number of results on each page |
page | Number | Current search results page |
facetDistribution | Object | Distribution of the given facets |
facetStats | Object | The numeric min and max values per facet |
processingTimeMs | Number | Processing time of the query |
query | String | Query originating the response |
Federated multi-search requests
Federated search requests return a single object and the following fields:
Name | Type | Description |
---|---|---|
indexUid | String | uid of the requested index |
hits | Array of objects | Results of the query |
offset | Number | Number of documents skipped |
limit | Number | Number of documents to take |
estimatedTotalHits | Number | Estimated total number of matches |
totalHits | Number | Exhaustive total number of matches |
totalPages | Number | Exhaustive total number of search result pages |
hitsPerPage | Number | Number of results on each page |
page | Number | Current search results page |
facetDistribution | Object | Distribution of the given facets |
facetStats | Object | The numeric min and max values per facet |
processingTimeMs | Number | Processing time of the query |
query | String | Query originating the response |
Each result in the hits
array contains an additional _federation
field with the following fields:
Name | Type | Description |
---|---|---|
indexUid | String | Index of origin for this document |
queriesPosition | Number | Array index number of the query in the request's queries array |
Example
Non-federated multi-search
curl \
-X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
--data-binary '{
"queries": [
{
"indexUid": "movies",
"q": "pooh",
"limit": 5
},
{
"indexUid": "movies",
"q": "nemo",
"limit": 5
},
{
"indexUid": "movie_ratings",
"q": "us"
}
]
}'
Response: 200 Ok
{
"results":[
{
"indexUid":"movies",
"hits":[
{
"id":13682,
"title":"Pooh's Heffalump Movie",
…
},
…
],
"query":"pooh",
"processingTimeMs":26,
"limit":5,
"offset":0,
"estimatedTotalHits":22
},
{
"indexUid":"movies",
"hits":[
{
"id":12,
"title":"Finding Nemo",
…
},
…
],
"query":"nemo",
"processingTimeMs":5,
"limit":5,
"offset":0,
"estimatedTotalHits":11
},
{
"indexUid":"movie_ratings",
"hits":[
{
"id":"Us",
"director": "Jordan Peele",
…
}
],
"query":"Us",
"processingTimeMs":0,
"limit":20,
"offset":0,
"estimatedTotalHits":1
}
]
}
Federated multi-search
curl \
-X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
--data-binary '{
"federation": {},
"queries": [
{
"indexUid": "movies",
"q": "batman"
},
{
"indexUid": "comics",
"q": "batman"
}
]
}'
Response: 200 Ok
{
"hits": [
{
"id": 42,
"title": "Batman returns",
"overview": …,
"_federation": {
"indexUid": "movies",
"queriesPosition": 0
}
},
{
"comicsId": "batman-killing-joke",
"description": …,
"title": "Batman: the killing joke",
"_federation": {
"indexUid": "comics",
"queriesPosition": 1
}
},
…
],
"processingTimeMs": 0,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 2,
"semanticHitCount": 0
}