【发布时间】:2015-03-16 02:25:31
【问题描述】:
我有一组类似的文档
{
tags:['a','b','c']
// ... a bunch properties
}
如标题所述:有没有办法使用 Nest 过滤包含任何给定标签的所有文档?
例如,上面的记录将匹配 ['c','d']
或者我应该手动构建多个“OR”吗?
【问题讨论】:
标签: elasticsearch nest
我有一组类似的文档
{
tags:['a','b','c']
// ... a bunch properties
}
如标题所述:有没有办法使用 Nest 过滤包含任何给定标签的所有文档?
例如,上面的记录将匹配 ['c','d']
或者我应该手动构建多个“OR”吗?
【问题讨论】:
标签: elasticsearch nest
弹性搜索 2.0.1:
还有terms query 可以为您节省一些工作。这里是来自文档的示例:
{
"terms" : {
"tags" : [ "blue", "pill" ],
"minimum_should_match" : 1
}
}
在引擎盖下它构造布尔值应该。所以它基本上和上面一样,但更短。
还有一个对应的terms filter。
所以总结一下您的查询可能如下所示:
{
"filtered": {
"query": {
"match": { "title": "hello world" }
},
"filter": {
"terms": {
"tags": ["c", "d"]
}
}
}
}
随着标签数量的增加,这可能会产生相当大的长度差异。
【讨论】:
minimum_should_match 已弃用并将失败。
boolean 查询的mustNot 子句中使用完全相同的terms 条件,它将搜索所有没有任何标签的文档。
编辑:下面的 bitset 内容可能很有趣,但答案本身有点过时。其中一些功能在 2.x 中发生了变化。此外,Slawek 在另一个答案中指出,terms 查询是在这种情况下干燥搜索的一种简单方法。最后针对当前的最佳实践进行了重构。 —nz
您可能需要 Bool Query(或者更可能是 Filter 旁边的另一个查询),并带有 should 子句。
bool 查询具有三个主要属性:must、should 和 must_not。其中每一个都接受另一个查询或查询数组。子句名称是不言自明的;在您的情况下,should 子句可以指定一个列表过滤器,与其中任何一个匹配将返回您要查找的文档。
来自文档:
在没有
must子句的布尔查询中,一个或多个should子句必须与文档匹配。可以使用minimum_should_match参数设置要匹配的应子句的最小数量。
以下是 Bool 查询单独显示的示例:
{
"bool": {
"should": [
{ "term": { "tag": "c" }},
{ "term": { "tag": "d" }}
]
}
}
这是另一个 Bool 查询示例,作为更通用的Filtered Query 中的过滤器:
{
"filtered": {
"query": {
"match": { "title": "hello world" }
},
"filter": {
"bool": {
"should": [
{ "term": { "tag": "c" }},
{ "term": { "tag": "d" }}
]
}
}
}
}
您是使用 Bool 作为查询(例如,影响匹配分数)还是过滤器(例如,减少被评分或后过滤的命中)是主观的,这取决于您的要求。
通常最好使用 Bool 而不是 Or Filter,除非您有理由使用 And/Or/Not(这样的原因确实存在)。 Elasticsearch 博客提供了有关每种方法的不同实现的更多信息,以及在何时您可能更喜欢 Bool 而不是 And/Or/Not(反之亦然)的好例子。
Elasticsearch 博客:All About Elasticsearch Filter Bitsets
使用重构查询更新...
现在,除了所有 之外,terms 查询是上述所有内容的 DRYer 版本。它在底层的查询类型方面做了正确的事情,它的行为与使用 minimum_should_match 选项的 bool + should 相同,总体而言更简洁一些。
这是最后一个查询的重构:
{
"filtered": {
"query": {
"match": { "title": "hello world" }
},
"filter": {
"terms": {
"tag": [ "c", "d" ],
"minimum_should_match": 1
}
}
}
}
【讨论】:
虽然这是一个老问题,但我最近自己遇到了这个问题,这里的一些答案现在已被弃用(正如 cmets 指出的那样)。因此,为了其他可能在这里偶然发现的人的利益:
term 查询可用于查找反向索引中指定的确切术语:
{
"query": {
"term" : { "tags" : "a" }
}
来自文档https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
或者,您可以使用terms 查询,它将匹配所有文档与给定数组中指定的任何项目:
{
"query": {
"terms" : { "tags" : ["a", "c"]}
}
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
需要注意的一个问题(这让我大吃一惊)——您如何定义文档也会产生影响。如果您要搜索的字段已被索引为 text 类型,则 Elasticsearch 将执行全文搜索(即使用 analyzed 字符串)。
如果您已将该字段索引为keyword,则使用“未分析”字符串执行关键字搜索。这可能会产生巨大的实际影响,因为已分析的字符串是经过预处理的(小写、标点符号删除等)请参阅 (https://www.elastic.co/guide/en/elasticsearch/guide/master/term-vs-full-text.html)
为避免这些问题,字符串字段已拆分为两种新类型:文本,应该用于全文搜索,以及关键字,应该用于关键字搜索。 (https://www.elastic.co/blog/strings-are-dead-long-live-strings)
【讨论】:
对于那些在 2020 年关注此问题的人,您可能会注意到已接受的答案在 2020 年被弃用,但使用terms_set 和minimum_should_match_script 组合可以使用类似的方法。
详细答案请看SO线程here
【讨论】:
你应该使用Terms Query
{
"query" : {
"terms" : {
"tags" : ["c", "d"]
}
}
}
【讨论】: