在使用 ElasticSearch 进行了几次实验后pyodbc
,我得出以下结论:
- CData ODBC 驱动程序知道不可能进行聚合,
_score
并且不允许用户这样做
- 它实际计算聚合的行为
_score
很可能是一个错误,并且不是由 ElasticSearch 而是由驱动程序执行的。
简而言之,不要使用_score
for any GROUP BY
,它是 ElasticSearch 专门用于相关性排序的一个特殊功能。
一点介绍
正如我在问题的评论中已经提到的那样,_score
在 ElasticSearch 中是衡量文档与给定查询的相关性(请参阅docs):
每个文档的相关性分数由一个称为 _score 的正浮点数表示。_score 越高,文档越相关。
该字段不是文档的一部分,而是为每个查询和每个文档计算的。在 ElasticSearch_score
中用于排序。但是,_score
并不总是计算的,例如当需要对现有字段进行排序时:
_score 不计算,因为它不用于排序。
由于该字段是即时计算的,因此无法创建有效的聚合,因此 ElasticSearch 不允许直接这样做。但是,这仍然可以通过在聚合中使用脚本来实现。
CData ODBC 驱动程序知道 _score 字段
CData ODBC 驱动程序知道_score
字段:
When the _score column is selected, scoring will be requested by issuing a query context request, which scores the quality of the search results. 默认情况下,根据计算的 _score 以降序返回结果。可以指定 ORDER BY 子句来更改返回结果的顺序。
当 _score 列未选中时,将发送过滤上下文,在这种情况下,Elasticsearch 不会计算分数。除非明确指定 ORDER BY 子句,否则这些查询的结果将按任意顺序返回。
基本上,这意味着通过_score
在查询中明确提及将使 ODBC 返回此类字段(默认情况下可能存在)。
实验
我安装了 pyodbc 并在我的本地主机上设置了 ElasticSearch 5.4。我调整了 ES 以记录它收到的所有查询。
1.
一开始我复制了第一个案例:
cursor.execute("SELECT sum(_score) FROM my_index.my_type")
并收到此异常:
[HY000] The '_score' column is not applicable to the sum function.
在 ES 的日志中,我发现了这个查询:
{"from":0,"size":100}
2.
接下来我进行了第二个查询:
cursor.execute("SELECT _id, sum(_score) FROM my_index.my_type GROUP BY _id")
没有异常执行,但导致了这个 ES 查询:
{"from":0,"size":10000,"_source":{"includes":["_id","_score"],"excludes":[]}}
3.
然后我尝试使用不存在的字段来模拟库:
cursor.execute("SELECT sum(score42) FROM simple_index.simple_type")
在这种情况下,例外情况不同:
[HY000] 'score42' is not a valid column.
尽管发送给 ES 的查询与第一种情况相同。
4.
然后我试图找出图书馆如何发送聚合请求:
cursor.execute("SELECT sum(likes) FROM simple_index.simple_type GROUP BY likes")
事实上,它确实使用了 ES 聚合:
{
"from": 0,
"size": 0,
"aggregations": {
"likes": {
"terms": {
"field": "likes",
"size": 2147483647,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_term": "asc"
}
]
},
"aggregations": {
"sum_likes": {
"sum": {
"field": "likes"
}
}
}
}
}
}
结论
事实上,该库能够识别_score
为一个特殊的关键字,而且因为它在被要求时没有尝试生成 ES 聚合sum(_score)
,所以我假设它通常不允许进行聚合,_score
这里的“工作”案例是可能是一个错误。