我是Elasticsearch的新手。我试图使用CDataElasticsearchODBC驱动程序从ES中获得结果。有可能得到分数总和字段吗?
我的代码:
OdbcConnection connection = new OdbcConnection("Driver={CData ODBC Driver for Elasticsearch};server=localhost");
connection.Open();
string query = "select sum(_score) from ordersdetails";
OdbcCommand odbcCommand = new OdbcCommand(query, connection);
OdbcDataReader dataReader = odbcCommand.ExecuteReader();
DataTable dataTable = new DataTable();
dataTable.Load(dataReader);
connection.Close();
我遇到了以下异常
System.Data.Odbc.OdbcException:"ERROR[HY000]"_score"列不适用于sum函数。">
但是下面的查询返回结果:
"select _id,sum(_score)from orders tails group by _id">
有人知道吗,为什么我在试图获得单个列的结果时出现异常
如果你知道解决方案,请与我分享。
在用pyodbc
和ElasticSearch做了几个实验后,我得出了以下结论:
- CData ODBC驱动程序知道不可能在
_score
上进行聚合,并且不允许用户这样做 - 它实际通过
_score
计算聚合的行为很可能是一个错误,它不是由ElasticSearch执行的,而是由驱动程序执行的
简而言之,不要将_score
用于任何GROUP BY
,这是ElasticSearch专门用于相关性排序的一个特殊功能。
介绍一下
正如我在对该问题的评论中所提到的,ElasticSearch中的_score
是衡量文档如何与给定查询相关的指标(请参阅文档):
每个文档的相关性得分由正数表示称为_score的浮点数。_score越高更相关的文件。
此字段不是文档的一部分,是为每个查询和每个文档计算的。在ElasticSearch中,_score
用于排序。然而,并不总是计算_score
,例如,当需要对现有字段进行排序时:
_score未计算,因为它未用于排序。
由于此字段是动态计算的,因此不可能创建有效的聚合,因此ElasticSearch不允许直接进行此操作。但是,这仍然可以通过在聚合中使用脚本来实现。
CData ODBC驱动程序知道_score字段
CData ODBC驱动程序知道_score
字段:
选择_score列时,将由发出查询上下文请求,该请求对搜索结果。默认情况下,结果按降序返回基于计算的_ 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
识别为一个特殊的关键字,也因为它在请求sum(_score)
时没有尝试生成ES聚合,我认为它通常不允许在_score
上进行聚合,这里的"工作"情况可能是一个错误。