【问题标题】:ElasticSearch: Is it possible to do a "Weighted Avg Aggregation" weighted by the score?ElasticSearch:是否可以按分数加权进行“加权平均聚合”?
【发布时间】:2020-08-10 17:54:02
【问题描述】:

我正在尝试对价格字段 (price.avg) 执行平均。但我希望查询的最佳匹配对平均值的影响比最新的影响更大,因此平均值应由计算的分数字段加权。这是我正在实施的聚合。

{
    "query": {...},
    "size": 100,
    "aggs": {
        "weighted_avg_price": {
            "weighted_avg": {
                "value": {
                    "field": "price.avg"
                },
                "weight": {
                    "script": "_score"
                }
            }
        }
    }
}

它应该给我我想要的。但相反,我收到一个空值:

{...
    "hits": {...},
    "aggregations": {
        "weighted_avg_price": {
            "value": null
        }
    }
}

我有什么遗漏的吗?这个聚合查询可行吗?有什么解决办法吗?

【问题讨论】:

    标签: elasticsearch elasticsearch-aggregation elasticsearch-query


    【解决方案1】:

    当您调试 script 中的可用内容时

    GET prices/_search
    {
      "size": 0,
      "aggs": {
        "weighted_avg_price": {
          "weighted_avg": {
            "value": {
              "field": "price"
            },
            "weight": {
              "script": "Debug.explain(new ArrayList(params.keySet()))"
            }
          }
        }
      }
    }
    

    以下内容被吐出

    [doc, _source, _doc, _fields]
    

    这些都不包含有关您尝试访问的查询_score 的信息,因为聚合在与查询级别评分不同的上下文中运行。这意味着weight 值需要

    • 存在于文档中或
    • 存在于文档中 + 为 modifiable
    • 是一个查询时间常数(如420.1

    解决方法可能是将数学函数应用于检索到的price,例如

    "script": "Math.pow(doc.price.value, 0.5)"

    【讨论】:

    • 非常感谢。不知道调试选项。我猜我只能使用 doc 值,但我无法确认。如果文档按平均价格评分,您的解决方法将有效,但事实并非如此。简化也对我有用:仅在前 N 个结果中计算聚合(N 个得分最高)。但我也无法做到这一点,我想这也是因为分数在聚合级别不可用。
    • 没错。您可以在查询中编写自定义评分函数,然后按自定义脚本/函数进行排序。据我了解,您对文档级别的指标更感兴趣,而不是基于 agg。我说的对吗?
    • 我认为没有。因为我想要所有文档(价格)中一个字段的平均值,但是计算它更重要的是查询中的更好结果。这应该比常规平均值更现实/更相关,因为应用用户更有可能会选择评分查询的最高结果(不是按价格评分,而是按其他条件评分)
    • 如果此分数与查询无关,您可以在文档中添加一个单独的 score_weight 字段,然后在您的 weighted_avg 中使用该常量。我认为没有其他方法可以解决它。
    • 不,不是,因为_score是查询时查询计算出来的
    【解决方案2】:

    @jzzfs 我正在尝试使用“前 N 个结果的平均值(按 _score 排序)”的方法,使用 top hits aggregation

    {
        "query": {
            "bool": {
                "should": [
                    ...
                ],
                "minimum_should_match": 0
            }
        },
        "size": 0,
        "from": 0,
        "sort": [
            {
                "_score": {
                    "order": "desc"
                }
            }
        ],
        "aggs": {
            "top_avg_price": {
                "avg": {
                    "field": "price.max"
                }
            },
            "aggs": {
                "top_hits": {
                    "size": 10, // N: Changing the number of results doesn't change the top_avg_price 
                    "_source": {
                        "includes": [
                            "price.max"
                        ]
                    }
                }
            }
        },
        "explain": "false"
    }
    

    avg 聚合是针对主要结果进行的,而不是 top_hits 聚合。 我猜top_avg_rpice 应该是top_hits 的子聚合。但我认为那是不可能的 ATM。

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      • 2010-09-21
      • 2014-08-09
      相关资源
      最近更新 更多