在字段上排序时 Elastic 的搜索结果不稳定
Erratic search results from Elastic when sorting on a field
我们刚刚升级到 Elasticsearch 2.3.1(从 1.7),我们遇到了我无法解释的奇怪搜索行为。似乎发生的是包含 bool
查询和 sort
子句的搜索请求是 returning:
- 似乎在任何方面都不符合给定搜索条件的文档。
- 对每个请求的
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?
我们发现了两种解决此行为的方法:
- 按
_score
排序或完全省略 sort
子句。对任何其他内容进行排序,例如上面的字段或 _doc
会产生不稳定的行为。
- 在请求中包含
track_scores : true
。
所以它似乎与评分和相关性有关。但由于我们是在我们自己的字段上排序,我们对相关性或分数不感兴趣。如果没有解决方法,响应中的 max_score
是 null
,每个文档的 _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"
]
}
}
]
}
}
}
- 执行查询。您在此处的查询字符串中搜索 "surface",这应该会导致总共 22 次匹配。这是对的。多次执行此查询(这似乎对第 2 步很重要)。
- 将查询字符串更改为 "iphone"。这仍然会导致 22 次匹配,即使数据集只包含一个应该匹配的项目。
_explanation
还提到找到的文档实际上并不匹配,就像我上面的例子一样。
- 执行这个:
post pim_search_1/_cache/clear
- 再次执行 "iphone" 的查询。现在应该只有 return 1 次命中,这是正确的。也执行这个多次。
- 再次为 "surface" 执行查询,这现在 return 只有 1 次命中,并且
_explanation
再次声明它没有在结果文档中找到匹配项。
- 从查询中删除
sort
子句,一切正常。包括 "track_scores" : true
也是如此。
而不是_cache/clear
它也可以只重启集群。
我说它与 _all
字段有关,因为将 query_string
的 default_field
更改为 primitive_name
字段(分析的字段)会导致正确的行为.对于这个例子,我已经将 _all
设为一个存储字段(我们通常不会使用它)并且它在搜索结果中被 return 编辑,因此您可以检查它(似乎不包含任何内容诡异的)。
以上是在 Elasticsearch 2.3.5 上的单节点集群(我的本地 PC)上完成的。
ThisGithub问题好像和我的问题差不多,但是当时无法重现,关闭了
这已在 Elasticsearch 2.4 中修复:
我们刚刚升级到 Elasticsearch 2.3.1(从 1.7),我们遇到了我无法解释的奇怪搜索行为。似乎发生的是包含 bool
查询和 sort
子句的搜索请求是 returning:
- 似乎在任何方面都不符合给定搜索条件的文档。
- 对每个请求的
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?
我们发现了两种解决此行为的方法:
- 按
_score
排序或完全省略sort
子句。对任何其他内容进行排序,例如上面的字段或_doc
会产生不稳定的行为。 - 在请求中包含
track_scores : true
。
所以它似乎与评分和相关性有关。但由于我们是在我们自己的字段上排序,我们对相关性或分数不感兴趣。如果没有解决方法,响应中的 max_score
是 null
,每个文档的 _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"
]
}
}
]
}
}
}
- 执行查询。您在此处的查询字符串中搜索 "surface",这应该会导致总共 22 次匹配。这是对的。多次执行此查询(这似乎对第 2 步很重要)。
- 将查询字符串更改为 "iphone"。这仍然会导致 22 次匹配,即使数据集只包含一个应该匹配的项目。
_explanation
还提到找到的文档实际上并不匹配,就像我上面的例子一样。 - 执行这个:
post pim_search_1/_cache/clear
- 再次执行 "iphone" 的查询。现在应该只有 return 1 次命中,这是正确的。也执行这个多次。
- 再次为 "surface" 执行查询,这现在 return 只有 1 次命中,并且
_explanation
再次声明它没有在结果文档中找到匹配项。 - 从查询中删除
sort
子句,一切正常。包括"track_scores" : true
也是如此。
而不是_cache/clear
它也可以只重启集群。
我说它与 _all
字段有关,因为将 query_string
的 default_field
更改为 primitive_name
字段(分析的字段)会导致正确的行为.对于这个例子,我已经将 _all
设为一个存储字段(我们通常不会使用它)并且它在搜索结果中被 return 编辑,因此您可以检查它(似乎不包含任何内容诡异的)。
以上是在 Elasticsearch 2.3.5 上的单节点集群(我的本地 PC)上完成的。
ThisGithub问题好像和我的问题差不多,但是当时无法重现,关闭了
这已在 Elasticsearch 2.4 中修复: