如何从 ElasticSearch 获取分数列的总和

How to get sum of score column from ElasticSearch

我是 Elasticsearch 的新手。我尝试使用 CData Elasticsearch ODBC 驱动程序从 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: '错误 [HY000] '_score' 列不适用于求和函数。'

但是下面的查询 returns 结果:

"select _id, sum(_score) from ordersdetails group by _id"

有人知道,为什么我在尝试获取单个列的结果时出现异常?

如果您知道解决方案,请与我分享。

在使用 pyodbc 和 ElasticSearch 进行了几次实验后,我得出以下结论:

  1. CData ODBC 驱动程序知道无法在 _score 上进行聚合并且不允许用户这样做
  2. 它实际通过 _score 计算聚合的行为很可能是一个错误,不是由 ElasticSearch 而是由驱动程序执行的。

总之,任何GROUP BY都不要使用_score,这是ElasticSearch的一个专门用于相关性排序的特性。

一些介绍

正如我在问题的评论中提到的,ElasticSearch 中的 _score 是衡量文档与给定查询的相关程度的指标(参见 docs):

The relevance score of each document is represented by a positive floating-point number called the _score. The higher the _score, the more relevant the document.

此字段不是文档的一部分,并且是为每个查询和每个文档计算的。在 ElasticSearch 中,_score 用于 sorting. However, _score is not always computed,例如当需要对现有字段进行排序时:

The _score is not calculated, because it is not being used for sorting.

由于此字段是即时计算的,因此无法创建有效的聚合,因此 ElasticSearch 不允许直接这样做。但是,这仍然可以通过 using scripts in the aggregations.

来实现

CData ODBC 驱动程序知道 _score 字段

CData ODBC 驱动程序is aware of _score field:

When the _score column is selected, scoring will be requested by issuing a query context request, which scores the quality of the search results. By default, results are returned in descending order based on the calculated _score. An ORDER BY clause can be specified to change the order of the returned results.

When the _score column is not selected, a filter context will be sent, in which case Elasticsearch will not compute scores. The results for these queries will be returned in arbitrary order unless an ORDER BY clause is explicitly specified.

基本上,这意味着通过在查询中明确提及 _score 将使 ODBC return 这样的字段(默认情况下可能存在)。

实验

我在我的本地主机上安装了 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 上进行聚合,这里的 "working" 情况可能是一个错误。