ElasticSearch - 如何聚合几何平均值?

时间:2017-12-05 15:21:23

标签: elasticsearch

我目前正在聚合记录以获取返回记录中字段的平均值(算术平均值)。我的用例要求我掌握几何平均值:

  

几何平均值定义为n

乘积的第n个根

我怎样才能获得这个价值?我甚至不知道从哪里开始!

谢谢!

1 个答案:

答案 0 :(得分:1)

这不是微不足道的,但可以做到。想法是使用一个日志总和,然后应用第n个根:

pow(exp((sum of logs)), 1/n)

事实上,GeometricMeanElasticsearch Index Termlist Plugin聚合就是这样做的。 (但是,这是第三方插件,我无法判断它是否足够稳定。)

映射和样本数据

假设我们有以下映射:

PUT geom_mean
{
  "mappings": {
    "nums": {
      "properties": {
        "x": {
          "type": "double"
        }
      }
    }
  }
}

我们插入以下文件:

{"x":33}
{"x":324}
{"x":134}
{"x":0.1}

现在我们可以尝试查询。

ES查询

以下是计算几何平均值的查询:

POST geom_mean/nums/_search
{
  "size": 0,
  "aggs": {
    "aggs_root": {
      "terms": {
        "script": "'Bazinga!'"
      },
      "aggs": {
        "sum_log_x": {
          "sum": {
            "script": {
              "inline": "Math.log(doc.x.getValue())"
            }
          }
        },
        "geom_mean": {
          "bucket_script": {
            "buckets_path": {
              "sum_log_x": "sum_log_x",
              "x_cnt": "_count"
            },
            "script": "Math.pow(Math.exp(params.sum_log_x), 1 / params.x_cnt)"
          }
        }
      }
    }
  }
}

返回值为:

  "aggregations": {
    "aggs_root": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Bazinga!",
          "doc_count": 4,
          "sum_log_x": {
            "value": 11.872505784215674
          },
          "geom_mean": {
            "value": 19.455434622111177
          }
        }
      ]
    }
  }

现在有点解释。聚合sum_log_x计算x的总和。名为geom_mean的聚合是sibling pipeline aggregation,它应用于sum_log_x聚合(其兄弟)的结果。它使用特殊的桶路径_count来获取元素的数量。 (Here您可以阅读更多关于bucket_script聚合的内容。)

最后一个技巧是用一些聚合来包装它们,因为,如this issue中所述,bucket_script不能是顶级聚合。在这里,我对一个始终返回terms

的脚本进行'Bazinga!'聚合

感谢提出此黑客的anhzhi

重要注意事项

由于几何平均值是通过日志计算的,因此所有x值都应大于0.但是:

  • 如果任何值是< 0,结果为"NaN"
  • 如果所有值均为非负数且小于"+Infinity",但至少有一个值为0,则结果为"-Infinity"
  • 如果"+Infinity""-Infinity"都在值中,则结果为"NaN"

使用Elasticsearch 5.4测试查询。未测试大量文档的性能,您可以考虑将x与其日志一起插入,以提高聚合效率。

希望有所帮助!