【问题标题】:How to get sum of score column from ElasticSearch如何从 ElasticSearch 中获取分数列的总和
【发布时间】:2017-10-10 02:16:39
【问题描述】:

我是 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: 'ERROR [HY000] '_score' 列不适用于 sum 函数。'

但是下面的查询返回结果:

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

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

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

【问题讨论】:

  • 请告诉我 sum 查询是否适用于其他数字字段?您是否意识到_score 是一个"virtual" field,它是针对每对(查询、结果)计算的?
  • @NikolayVasiliev:是的。 sum 查询适用于其他数字字段。实际上,我的用例是通过 Tableau、Power BI 等应用程序中的 ODBC 驱动程序获取 ElasticSearch 数据。我对 Elasticsearch 了解不多。所以我使用 C# 代码将数据插入到 elasticsearch 中。请告诉我们,有没有可能使用 sql 查询得到分值的总和?
  • @NikolayVasiliev:您能否提供一个使用 _score 字段的示例?
  • 感谢您的回复。 _score 字段是文档与所触发查询的相关性得分。例如,如果您使用 tweetText=google 之类的查询对一组推文进行全文搜索,ElasticSearch 将按相关性顺序返回结果,_score 将包含用于对结果进行排序的实际值。这就是为什么对我来说问题中的用例没有意义——没有查询,这样的sum 并没有提供太多信息。您能否提供对_score 求和的用例?
  • @NikolayVasiliev:非常感谢。

标签: elasticsearch odbc nest cdata cdata-drivers


【解决方案1】:

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

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

简而言之,不要将_score 用于任何GROUP BY,这是ElasticSearch 专门用于相关性排序的一个特殊功能。

一点介绍

正如我在问题的 cmets 中已经提到的那样,ElasticSearch 中的 _score 是衡量文档与给定查询的相关程度的指标(请参阅 docs):

每个文档的相关性分数由正数表示 浮点数称为_score。 _score 越高, 文档更相关。

此字段不是文档的一部分,它是针对每个查询和每个文档计算的。在 ElasticSearch 中,_score 用于sorting。但是,_scoreis not always computed,例如在需要对现有字段进行排序时:

_score 不计算,因为它不用于排序。

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

CData ODBC 驱动程序知道 _score 字段

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

选择_core列时,将请求评分 发出一个查询上下文请求,它对查询的质量进行评分 搜索结果。默认情况下,结果按降序返回 基于计算的_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 上,这里的“工作”案例可能是一个错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多