多重搜索
/multi-search
路由允许你通过将多个搜索查询捆绑到一个 HTTP 请求中,对一个或多个索引执行多个搜索查询。多重搜索也称为联合搜索。
执行多重搜索
将多个搜索查询捆绑到一个 API 请求中。使用此端点一次搜索多个索引。
请求体
名称 | 类型 | 描述 |
---|---|---|
federation | 对象 | 如果存在且不为 null ,则返回合并所有指定查询的搜索结果的单个列表 |
queries | 对象数组 | 包含要执行的搜索查询列表。需要 indexUid 搜索参数,所有其他参数都是可选的 |
警告
如果 Meilisearch 在处理多重搜索请求中的任何查询时遇到错误,它会立即停止处理请求并返回错误消息。返回的消息将仅涉及遇到的第一个错误。
federation
使用 federation
接收包含来自所有指定查询的所有搜索结果的单个列表,并按降序排名分数排列。这称为联合搜索。
federation
可以选择性地包含以下参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
offset | 整数 | 0 | 要跳过的文档数量 |
limit | 整数 | 20 | 返回的最大文档数 |
facetsByIndex | 数组对象 | null | 显示指定索引的分面信息 |
mergeFacets | 对象 | null | 显示指定索引的分面信息 |
如果 federation
缺失或为 null
,Meilisearch 将返回多个搜索结果对象的列表,列表中的每个项目对应于请求中的一个搜索查询。
facetsByIndex
facetsByIndex
必须是一个对象。它的键必须对应于你的 Meilisearch 项目中的索引。每个键必须与该索引的可过滤属性列表中的属性数组关联
"facetsByIndex": {
"INDEX_A": ["ATTRIBUTE_X", "ATTRIBUTE_Y"],
"INDEX_B": ["ATTRIBUTE_Z"]
}
当你指定 facetsByIndex
时,多重搜索响应包含一个额外的 facetsByIndex
字段。响应的 facetsByIndex
是一个对象,每个查询的索引都有一个字段
{
"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
必须是一个对象,并且可以包含以下字段
maxValuesPerFacet
:必须是整数。指定后,表示单个分面返回的最大值数量。默认为分配给maxValuesPerFacet
索引设置 的值
当 facetsByIndex
和 mergeFacets
都存在且不为 null 时,多重搜索响应中包含的分面信息将在所有查询的索引中合并。响应不包含 facetsByIndex
,而是包含两个额外的字段:facetDistribution
和 facetStats
{
"hits": [ … ],
…
"facetDistribution": {
"ATTRIBUTE": {
"VALUE": <Integer>,
"VALUE": <Integer>
}
},
"facetStats": {
"ATTRIBUTE": {
"min": <Integer>,
"max": <Integer>
}
}
}
联合搜索的合并算法
联合搜索的合并结果按降序排名分数返回。为了获得最终的结果列表,Meilisearch 使用以下过程进行比较
- 详细的排名分数对两个命中项都以以下方式进行标准化
- 连续相关性分数(与规则
words
、typo
、attribute
、exactness
或vector
相关)在每个命中项中分组为一个分数 sort
和geosort
分数详情保持不变
- 连续相关性分数(与规则
- 标准化的详细排名分数对两个命中项进行词典编纂比较
- 如果两个命中项都有相关性分数,则分数较大的获胜。如果是平局,则移至下一步
- 如果一个结果具有相关性分数或(地理)排序分数,Meilisearch 将选择它
- 如果两个结果在相同的排序方向上都有排序或地理排序分数,则 Meilisearch 会根据共同的排序方向比较值。根据共同的排序方向,值必须首先出现的结果获胜。如果是平局,则转到下一步
- 比较两个命中项的全局排名分数,以确定哪个先出现,忽略任何排序或地理排序
- 在完全平局的情况下,来自
queries
数组中排名最低的查询的文档优先。
不同文档和联合搜索
如果满足以下条件,Meilisearch 认为两个文档相同
- 它们来自同一个索引
- 并且它们的主键相同
无法指定应将跨多个索引的两个文档视为相同。
queries
queries
必须是对象数组。每个对象可以包含以下搜索参数
搜索参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
federationOptions | 对象 | null | 为特定查询配置联合设置 |
indexUid | 字符串 | N/A | 请求索引的 uid |
q | 字符串 | "" | 查询字符串 |
offset | 整数 | 0 | 要跳过的文档数量 |
limit | 整数 | 20 | 返回的最大文档数 |
hitsPerPage | 整数 | 1 | 每页返回的最大文档数 |
page | 整数 | 1 | 请求特定页面的结果 |
filter | 字符串 | null | 按属性值过滤查询 |
facets | 字符串数组 | null | 显示每个分面的匹配计数 |
distinct | 字符串 | null | 将搜索限制为具有指定属性唯一值的文档 |
attributesToRetrieve | 字符串数组 | ["*"] | 要在返回的文档中显示的属性 |
attributesToCrop | 字符串数组 | null | 值需要裁剪的属性 |
cropLength | 整数 | 10 | 裁剪值在字词中的最大长度 |
cropMarker | 字符串 | "…" | 标记裁剪边界的字符串 |
attributesToHighlight | 字符串数组 | null | 突出显示属性中包含的匹配项 |
highlightPreTag | 字符串 | "<em>" | 插入到突出显示词语开头的字符串 |
highlightPostTag | 字符串 | "</em>" | 插入到突出显示词语末尾的字符串 |
showMatchesPosition | 布尔值 | false | 返回匹配项位置 |
sort | 字符串数组 | null | 按属性值对搜索结果进行排序 |
matchingStrategy | 字符串 | last | 用于匹配文档中查询词语的策略 |
showRankingScore | 布尔值 | false | 显示文档的全局排名分数 |
showRankingScoreDetails | 布尔值 | false | 添加详细的全局排名分数字段 |
rankingScoreThreshold | 数字 | null | 排除排名分数低的结果 |
attributesToSearchOn | 字符串数组 | ["*"] | 将搜索限制为指定的属性 |
hybrid | 对象 | null | 根据查询关键字和含义返回结果 |
vector | 数字数组 | null | 使用自定义查询向量进行搜索 |
retrieveVectors | 布尔值 | false | 返回文档向量数据 |
locales | 字符串数组 | null | 显式指定查询中使用的语言 |
除非另有说明,否则多重搜索查询的搜索参数的功能与 /search
端点的搜索参数 完全相同。
limit
、offset
、hitsPerPage
和 page
这些选项与联合搜索不兼容。
federationOptions
federationOptions
必须是一个对象。它接受以下参数
weight
:充当此特定查询中搜索结果排名分数的乘法因子。如果 <1.0
,则来自此查询的命中项不太可能出现在最终结果列表中。如果 >1.0
,则来自此查询的命中项更可能出现在最终结果列表中。必须为正浮点数。默认为1.0
remote
实验性:指示 Meilisearch 将在其中执行查询的远程实例。必须是与 远程对象 对应的字符串。默认为null
响应
/multi-search
查询的响应可能采用不同的形式,具体取决于你正在进行的查询类型。
非联合多重搜索请求
名称 | 类型 | 描述 |
---|---|---|
results | 对象数组 | 搜索查询的结果,顺序与请求中的顺序相同 |
每个搜索结果对象都由以下字段组成
名称 | 类型 | 描述 |
---|---|---|
indexUid | 字符串 | uid 请求索引的 |
hits | 对象数组 | 查询结果 |
offset | 数字 | 跳过的文档数量 |
limit | 数字 | 要获取的文档数量 |
estimatedTotalHits | 数字 | 估计的总匹配数 |
totalHits | 数字 | 详尽的总匹配数 |
totalPages | 数字 | 搜索结果页面的详尽总数 |
hitsPerPage | 数字 | 每页的结果数 |
page | 数字 | 当前搜索结果页面 |
facetDistribution | 对象 | 给定分面的分布 |
facetStats | 对象 | 每个分面的数值 min 和 max 值 |
processingTimeMs | 数字 | 查询的处理时间 |
query | 字符串 | 生成响应的查询 |
联合多重搜索请求
联合搜索请求返回单个对象和以下字段
名称 | 类型 | 描述 |
---|---|---|
hits | 对象数组 | 查询结果 |
offset | 数字 | 跳过的文档数量 |
limit | 数字 | 要获取的文档数量 |
estimatedTotalHits | 数字 | 估计的总匹配数 |
processingTimeMs | 数字 | 查询的处理时间 |
facetsByIndex | 对象 | 搜索结果中存在的分面的数据 |
facetDistribution | 对象 | 给定分面的分布 |
facetStats | 对象 | 每个分面的数值 min 和 max 值 |
remoteErrors | 对象 | 指示哪些远程请求失败以及原因 |
hits
数组中的每个结果都包含一个额外的 _federation
字段,其中包含以下字段
名称 | 类型 | 描述 |
---|---|---|
indexUid | 字符串 | 此文档的来源索引 |
queriesPosition | 数字 | 请求的 queries 数组中查询的数组索引号 |
remote | 字符串 | 此文档的来源远程实例 |
weightedRankingScore | 数字 | 命中项的 _rankingScore 与来源查询权重的乘积。 |
示例
非联合多重搜索
curl \
-X POST 'MEILISEARCH_URL/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"
}
]
}'
响应: 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
}
]
}
联合多重搜索
curl \
-X POST 'MEILISEARCH_URL/multi-search' \
-H 'Content-Type: application/json' \
--data-binary '{
"federation": {},
"queries": [
{
"indexUid": "movies",
"q": "batman"
},
{
"indexUid": "comics",
"q": "batman"
}
]
}'
响应: 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
}
远程联合多重搜索 实验性
curl \
-X POST 'MEILISEARCH_URL/multi-search' \
-H 'Content-Type: application/json' \
--data-binary '{
"federation": {},
"queries": [
{
"indexUid": "movies",
"q": "batman",
"federationOptions": {
"remote": "ms-00"
}
},
{
"indexUid": "movies",
"q": "batman",
"federationOptions": {
"remote": "ms-01"
}
}
]
}'
响应: 200 Ok
{
"hits": [
{
"id": 42,
"title": "Batman returns",
"overview": …,
"_federation": {
"indexUid": "movies",
"queriesPosition": 0,
"weightedRankingScore": 1.0,
"remote": "ms-01"
}
},
{
"id": 87,
"description": …,
"title": "Batman: the killing joke",
"_federation": {
"indexUid": "movies",
"queriesPosition": 1,
"weightedRankingScore": 0.9848484848484849,
"remote": "ms-00"
}
},
…
],
"processingTimeMs": 35,
"limit": 5,
"offset": 0,
"estimatedTotalHits": 111,
"remoteErrors": {
"ms-02": {
"message": "error sending request",
"code": "proxy_could_not_send_request",
"type": "system",
"link": "https://docs.meilisearch.com/errors#proxy_could_not_make_request"
}
}
}