定义
语法
compound 通过以下语法实现:
1 { 2 $search: { 3 "index": <index name>, // optional, defaults to "default" 4 "compound": { 5 <must | mustNot | should | filter>: [ { <clauses> } ], 6 "score": <options>, 7 "doesNotAffect": "<facet-to-exclude>" | [<array-of-facets>] 8 } 9 } 10 }
每个 must、mustNot、should 和 filter 子句都包含一个子句数组。即使数组只包含一个子句,也仍然使用数组语法。请参阅本页的示例。
选项
compound 使用以下词条来构造查询:
要将文档包含在结果中必须匹配的子句。返回的分数是子句中所有子查询的分数总和。 映射到 | ||||||||||||||
要将文档包含在结果中必须不能匹配的子句。 映射到 | ||||||||||||||
您希望与结果所包含文档匹配的子句。与不包含 如果使用多个 请参阅示例。 映射到 如果在复合查询中仅使用 | ||||||||||||||
要将文档包含在结果中必须全部匹配的子句。 例如,您可以使用 您可以改用 请参阅另一过滤示例。 | ||||||||||||||
| ||||||||||||||
| 要从基于此查询的计数重新计算中排除的分面(Facet)或分面(Facet)列表。值必须是 |
使用
您可以使用任何带有任何顶层操作符(例如自动完成、文本或跨度)的子句来指定查询条件。
为优化性能,请将非评分操作符(例如 equals、range 和 in)放入 filter 子句中,避免不必要的评分操作。如果您想运行必须作为 OR 条件求值的操作,请在顶层 filter 中嵌套一个 should子句。
例子
[ { $search: { index: "default", compound: { filter: [ { compound: { should: [ { equals: { path: "accommodates", value: 2 } }, { range: { path: "pricePerNight", lte: 200 } } ] } } ] } } } ]
评分行为
MongoDB搜索通过文档在文档上生成匹配项的每个子句获得的分数求和,对结果设立进行评分。只有 must 和 should 子句参与评分。结果设立按分数从最高到最低排序。
下表显示了影响和不影响分数的 compound子句。
子句 | 影响分数 |
|---|---|
| |
| |
| |
|
您可以用 score 选项提高或替换整个复合查询的分数。有关替换整个复合分数的示例,请参阅下面的 复合分数示例 。您还可以用分数来提高或更改每个子句中每个子查询的分数。有关 compound 操作符子句中已更改分数的部分示例,请参阅修改分数。
示例
您可以在MongoDB Search Playground 或集群中尝试以下示例。
样本集合
要在此页面上运行 示例查询,请在集群上创建一个名为 fruit 的集合,并将以下文档插入集合:
1 { 2 "_id" : 1, 3 "type" : "apple", 4 "description" : "Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp.", 5 "category" : "nonorganic", 6 "in_stock" : false 7 }, 8 { 9 "_id" : 2, 10 "type" : "banana", 11 "description" : "Bananas are usually sold in bunches of five or six.", 12 "category" : "nonorganic", 13 "in_stock" : true 14 }, 15 { 16 "_id" : 3, 17 "type" : "pear", 18 "description" : "Bosc and Bartlett are the most common varieties of pears.", 19 "category" : "organic", 20 "in_stock" : true 21 }
样本索引
要在此页面上运行 示例查询,请在 fruit 示例集合上创建名为 default 的以下 MongoDB Search 索引。索引定义将 MongoDB Search 配置为执行以下操作:
fruit使用默认 标准 分析器提取令牌,动态索引 集合中的所有字段。standard分析器将所有单词转为小写,并忽略常见的停用词,例如"the"、"a"、"and"等。
1 { 2 "mappings": { 3 "dynamic": true, 4 "fields": { 5 "type": [ 6 { "type": "string" }, 7 { "type": "token" } 8 ] 9 } 10 } 11 }
样本查询
以下查询演示了MongoDB搜索查询中的$search compound操作符。
must 和 mustNot 示例
以下示例使用 must 和 mustNot 子句的组合来构建查询。must 子句使用文本操作符在 description 字段中搜索术语 varieties。要匹配文档,它必须满足 must 子句。mustNot 子句对 description 字段中的术语 apples 执行搜索操作。要匹配文档,它必须不满足 mustNot 子句。
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "mustNot": [{ 12 "text": { 13 "query": "apples", 14 "path": "description" 15 } 16 }] 17 } 18 } 19 } 20 ])
上述查询返回的文档包含 _id: 3,因为其 description 字段包含单词 varieties,而不包含 apples。
➤ 在MongoDB Search Playground中尝试一下。
must 和 should 示例
以下查询使用 must 指定必须满足的搜索条件,使用 should 指定优先搜索包含单词 Fuji 的文档。
对于此查询,$project 管道阶段排除除 _id 之外的所有文档字段,并添加了一个 score 字段,该字段显示文档的相关性分数。
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }] 17 } 18 } 19 }, 20 { 21 "$project": { 22 "score": { "$meta": "searchScore" } 23 } 24 } 25 ])
包含 _id: 1 的文档分数较高,因为其 description 字段包含单词 Fuji,并且满足 should 子句。
➤ 在MongoDB Search Playground中尝试一下。
以下查询还为结果中的所有文档指定 3 的 constant分数。对于此查询,$project 管道阶段排除了除 _id 之外的所有文档字段,并添加了 score 字段。
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }], 17 "score": { "constant": { "value": 3 } } 18 } 19 } 20 }, 21 { 22 "$project": { 23 "score": { "$meta": "searchScore" } 24 } 25 } 26 ])
这两个文档获得相同的分数,因为查询中的 constant 选项将结果中每个文档的分数替换为数字 3。
➤ 在MongoDB Search Playground中尝试一下。
minimumShouldMatch 示例
在包含多个 should 子句的查询中,可以使用 miniumumShouldMatch 选项来指定必须匹配才能返回结果的最小子句数。
下面的查询有一个 must 子句和两个 should 子句,minimumShouldMatch 值为 1。文档必须在 description 字段中包含术语 varieties,必须在描述字段中包含 Fuji 或 Golden Delicious,才能被包含在结果集中。
1 db.fruit.aggregate([ 2 { 3 $search: { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }, 17 { 18 "text": { 19 "query": "Golden Delicious", 20 "path": "description" 21 } 22 }], 23 "minimumShouldMatch": 1 24 } 25 } 26 } 27 ])
带有 _id: 1 的文档匹配 must 子句和两个 should 子句中的第一个。
➤ 在MongoDB Search Playground中尝试一下。
filter 示例
filter 其行为与must相同,但返回文档的分数中不考虑filter子句,因此不会影响返回文档的顺序。
以下查询使用了以下子句:
must和filter指定必须满足的搜索条件。should指定包含单词banana的文档的首选项。should子句不包含minimumShouldMatch选项。如果省略minimumShouldMatch,则默认为0。
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "banana", 14 "path": "description" 15 } 16 }], 17 "filter": [{ 18 "text": { 19 "query": "granny", 20 "path": "description" 21 } 22 }] 23 } 24 } 25 } 26 ])
上述文档满足所有包含要求:
must子句和filter子句都匹配。未指定
minimumShouldMatch值,因此默认为0。因此,should子句失败,但仍返回文档。
➤ 在MongoDB Search Playground中尝试一下。
当 $match 阶段跟随 $search 阶段时,您可以通过将匹配条件移动到 $search 阶段内的 filter 子句中来提高查询性能。MongoDB Search 在搜索过程中应用 filter 条件,而不是重新扫描结果集以运行 $match 阶段。
考虑以下管道,它在description 字段中搜索术语 ,然后使用带有varieties $match$in的 仅保留苹果和香蕉:
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "text": { 5 "query": "varieties", 6 "path": "description" 7 } 8 } 9 }, 10 { 11 "$match": { 12 "type": { "$in": [ "apple", "banana" ] } 13 } 14 }, 15 { 16 "$project": { 17 "description": 1, 18 "score": { "$meta": "searchScore" } 19 } 20 } 21 ])
以下查询会将 $match 阶段替换为 filter 子句,该子句在 type 字段上使用 equals 操作符。$search 阶段使用 compound 操作符合并以下子句:
must子句在description字段中匹配varieties搜索术语filter子句匹配apple和banana类型
$project 阶段会执行以下操作:
排除
_id和description之外的所有字段添加一个
score字段,其中包含文档的相关性分数
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "filter": [{ 12 "in": { 13 "path": "type", 14 "value": [ "apple", "banana" ] 15 } 16 }] 17 } 18 } 19 }, 20 { 21 "$project": { 22 "description": 1, 23 "score": { "$meta": "searchScore" } 24 } 25 } 26 ])
结果中的文档满足所有包含要求:
两个文档的
type值均为apple或banana,这在查询的filter子句中指定。包含
_id: 1的文档比包含_id: 2的文档得分更高,因为它包含查询 的should子句中指定的术语varieties。
嵌套示例
以下示例使用嵌套的 compound 子句构造查询。对于此示例,fruit 集合具有针对 type、category 和 in_stock 字段的索引,且其文本字段使用默认分析器。此查询要求文档仅满足以下 should 子句之一:
在
type字段中包含单词apple。在
category字段中包含organic一词,并在in_stock字段中使用值true。
1 db.fruit.aggregate([ 2 { 3 $search: { 4 "compound": { 5 "should": [ 6 { 7 "text": { 8 "query": "apple", 9 "path": "type" 10 } 11 }, 12 { 13 "compound": { 14 "must": [ 15 { 16 "text": { 17 "query": "organic", 18 "path": "category" 19 } 20 }, 21 { 22 "equals": { 23 "value": true, 24 "path": "in_stock" 25 } 26 } 27 ] 28 } 29 } 30 ], 31 "minimumShouldMatch": 1 32 } 33 } 34 } 35 ])
结果中的文档满足所有包含要求:
_id: 3的文档与嵌套在第二个should子句中的must子句匹配。_id: 1的文档与第一个should子句匹配。
➤ 在MongoDB Search Playground中尝试一下。
元数据示例
以下查询使用 $searchMeta 管道阶段或 $search 阶段的 $$SEARCHMETA 变量检索元数据,以返回 fruit 集合中的类别数。
以下查询仅返回结果中的元数据。
db.fruit.aggregate([ { "$searchMeta": { "facet": { "operator": { "compound": { "must": [{ "text": { "query": "varieties", "path": "description" } }], "should": [{ "text": { "query": "Fuji", "path": "description" } }] } }, "facets": { "categoryFacet": { "type": "string", "path": "category" } } } } } ])
以下查询返回元数据和搜索结果。
db.fruit.aggregate([ { "$search": { "facet": { "operator": { "compound": { "must": [{ "text": { "query": "varieties", "path": "description" } }], "should": [{ "text": { "query": "Fuji", "path": "description" } }] } }, "facets": { "categoryFacet": { "type": "string", "path": "category" } } } } }, { "$limit": 2 }, { "$facet": { "docs": [ { "$project": { "type": 1, "description": 1 } } ], "meta": [ {"$replaceWith": "$$SEARCH_META"}, {"$limit": 1} ] } }, { "$set": { "meta": { "$arrayElemAt": ["$meta", 0] } } } ])