在字段上排序时 Elastic 的搜索结果不稳定

Erratic search results from Elastic when sorting on a field

我们刚刚升级到 Elasticsearch 2.3.1(从 1.7),我们遇到了我无法解释的奇怪搜索行为。似乎发生的是包含 bool 查询和 sort 子句的搜索请求是 returning:

  1. 似乎在任何方面都不符合给定搜索条件的文档。
  2. 对每个请求的 total 匹配文档的估计大不相同

具有此行为的请求的最小示例:

post pim_search_1/_search
{
   "explain": false,
   "track_scores": false,
   "sort": [
      {
         "product_id": {
            "order": "desc"
         }
      }
   ],
   "query": {
      "bool": {
         "filter": [
            {
               "terms": {
                  "publication": [
                     "public"
                  ]
               }
            },
            {
               "query_string": {
                  "query": "iphone",
                  "default_operator": "and"
               }
            }
         ]
      }
   }
}

所以在这种情况下,"iphone" return 的查询字符串根本没有 iPhone。将 explain 设置为 true 会为似乎根本没有匹配项的文档产生此结果:

 "_explanation": {
           "value": 0,
           "description": "Failure to meet condition(s) of required/prohibited clause(s)",
           "details": [
              {
                 "value": 0,
                 "description": "no match on required clause (#ConstantScore(publication:public) #_all:iphone)",

所以文档没有匹配的子句,但它仍然是 returned?

我们发现了两种解决此行为的方法:

  1. _score 排序或完全省略 sort 子句。对任何其他内容进行排序,例如上面的字段或 _doc 会产生不稳定的行为。
  2. 在请求中包含 track_scores : true

所以它似乎与评分和相关性有关。但由于我们是在我们自己的字段上排序,我们对相关性或分数不感兴趣。如果没有解决方法,响应中的 max_scorenull,每个文档的 _score 也是如此。

这种行为是否可以用任何方式解释,或者我们应该查看集群 health/configuration/corruption?根据集群,它的健康状况是绿色的,并且该索引的所有分片看起来都很健康。它目前是一个小型索引,在 3 个节点上有 3 个分片(每个分片 1 个副本)。

更新

我进一步调查了这个问题,它似乎与缓存有关。具体来说,_all 字段的字段数据缓存(我对 Elasticsearch 的内部结构不是很熟悉,所以如果这不是问题请纠正我)。

重现步骤

我有一个重现问题的数据集,留下评论,我可以发给你。

使用以下查询:

post pim_search_1/_search
{
   "fields": [
       "_all"
   ],
   "explain": true,
   "size": 100,
   "sort": [
      {
         "product_id": {
            "order": "desc"
         }
      }
   ],
   "query": {
      "bool": {
         "must": [
            {
               "query_string": {
                  "default_field": "_all", 
                  "query": "surface",
                  "default_operator": "and"
               }
            }
         ],
         "filter": [
            {
               "terms": {
                  "publication": [
                     "public"
                  ]
               }
            }
         ]
      }  
   }
}
  1. 执行查询。您在此处的查询字符串中搜索 "surface",这应该会导致总共 22 次匹配。这是对的。多次执行此查询(这似乎对第 2 步很重要)。
  2. 将查询字符串更改为 "iphone"。这仍然会导致 22 次匹配,即使数据集只包含一个应该匹配的项目。 _explanation 还提到找到的文档实际上并不匹配,就像我上面的例子一样。
  3. 执行这个:post pim_search_1/_cache/clear
  4. 再次执行 "iphone" 的查询。现在应该只有 return 1 次命中,这是正确的。也执行这个多次。
  5. 再次为 "surface" 执行查询,这现在 return 只有 1 次命中,并且 _explanation 再次声明它没有在结果文档中找到匹配项。
  6. 从查询中删除 sort 子句,一切正常。包括 "track_scores" : true 也是如此。

而不是_cache/clear它也可以只重启集群。

我说它与 _all 字段有关,因为将 query_stringdefault_field 更改为 primitive_name 字段(分析的字段)会导致正确的行为.对于这个例子,我已经将 _all 设为一个存储字段(我们通常不会使用它)并且它在搜索结果中被 return 编辑,因此您可以检查它(似乎不包含任何内容诡异的)。

以上是在 Elasticsearch 2.3.5 上的单节点集群(我的本地 PC)上完成的。

ThisGithub问题好像和我的问题差不多,但是当时无法重现,关闭了

这已在 Elasticsearch 2.4 中修复:

https://github.com/elastic/elasticsearch/pull/20196