Elasticsearch在使用" must_not"时给出不正确的结果运营商和#34;必须"操作者

时间:2015-02-21 13:19:40

标签: elasticsearch

查询示例 -

    GET /beta/user/_search?routing=1&q=_id:54e5dc4817cf03cbbbe490e5
{
   "from":0,
   "size":1,
   "filter":{
      "and":[
         {
            "query":{
               "nested":{
                  "path":"event",
                  "query":{
                     "bool":{
                        "must":[
                           {
                              "match":{
                                 "event.name":"e1"
                              }
                           },
                           {
                              "match":{
                                 "event.count":"4"
                              }
                           }
                        ]
                     }
                  }
               }
            }
         },
         {
            "query":{
               "nested":{
                  "path":"event",
                  "query":{
                     "bool":{
                        "must_not":{
                           "match":{
                              "event.name":"e2"
                           }
                        }
                     }
                  }
               }
            }
         }
      ]
   }
}

当我尝试在单个查询中使用“must_not”和“must”运算符时,我遇到上述查询的问题。任何帮助将受到高度赞赏。

上面的查询有一个名为“e1”的事件,我试图使用必须运算符和“must_not”运算符,并使用名为“e2”的事件。

1 个答案:

答案 0 :(得分:2)

只有嵌套查询(或嵌套过滤器)才能实现这一点。问题是文档一次只能评估一个文档。在内部,Elasticsearch将嵌套文档存储为独立的Lucene文档。根对象成为一个Lucene doc,每个后续的嵌套doc成为自己的Lucene doc。

这就是他们如何在不与其他嵌套文档交互的情况下维护字段之间的关系。 More details here

在评估查询时,它会逐个迭代每个嵌套文档。查询只能“查看”该单个嵌套文档中的值。这意味着它一次只能知道一组event.nameevent.count,并且无法将must与嵌套文档#1和must_not对齐嵌套文档#2。

解决方法是将嵌套数据反规范化回根对象。这样您就可以检查mustmust_not所包含的字词的非规范化“值包”。例如:

创建一个新索引...请注意我们为嵌套映射添加"include_in_root"

PUT /nestedtest/
{
    "mappings": {
        "test" : {
            "properties" : {
                "event" : {
                    "type" : "nested",
                    "include_in_root":true,
                    "properties": {
                        "name" : {"type": "string" },
                        "count"  : {"type": "integer" }
                    }
                }
            }
        }
    }
}

索引一些文档:

POST /nestedtest/test/
{
    "event": [
        {
            "name": "e1",
            "count": 1
        },
        {
            "name": "e2",
            "count": 2
        }
    ]
}

POST /nestedtest/test/
{
    "event": [
        {
            "name": "e1",
            "count": 1
        },
        {
            "name": "e3",
            "count": 3
        }
    ]
}

现在执行搜索。此查询是bool,其中包含两个必须条款:

  • 首先必须是nested查询。这将检查以确保嵌套文档具有正确的名称和计数
  • 第二个必须是bool,以确保至少有一个嵌套文档具有name: e1且没有文档具有name: e2

最终查询如下:

GET /nestedtest/test/_search
{
   "query": {
      "bool": {
         "must": [
            {
               "nested": {
                  "path": "event",
                  "query": {
                     "bool": {
                        "must": [
                           {
                              "match": {
                                 "event.name": "e1"
                              }
                           },
                           {
                              "match": {
                                 "event.count": "1"
                              }
                           }
                        ]
                     }
                  }
               }
            },
            {
               "bool": {
                  "must": [
                     {
                        "match": {
                           "event.name": "e1"
                        }
                     }
                  ],
                  "must_not": [
                     {
                        "match": {
                           "event.name": "e2"
                        }
                     }
                  ]
               }
            }
         ]
      }
   }
}

它只返回我们感兴趣的文档:

{
   "took": 2,
   "timed_out": false,
   "_shards": {...},
   "hits": {
      "total": 1,
      "max_score": 1.5155444,
      "hits": [
         {
            "_index": "nestedtest",
            "_type": "test",
            "_id": "AUus7jbcS8gWlP4VLwGZ",
            "_score": 1.5155444,
            "_source": {
               "event": [
                  {
                     "name": "e1",
                     "count": 1
                  },
                  {
                     "name": "e3",
                     "count": 3
                  }
               ]
            }
         }
      ]
   }
}