Elasticsearch 多个聚合或术语和同一列上的聚合
Posted
技术标签:
【中文标题】Elasticsearch 多个聚合或术语和同一列上的聚合【英文标题】:Elasticsearch multiple aggregation or terms and aggregation on a same column 【发布时间】:2022-01-19 07:17:53 【问题描述】:我想在 Elasticsearch 中实现 SQL 的功能。考虑下表:
我想要实现的是聚合列的不同值,SQL 等效:
select product,min(distinct price) from test group by product;
Expected output:
聚合可以是任何标准聚合,例如min
、max
、sum
、avg
、count
等。
我已经尝试过使用无痛脚本,我可以通过无痛脚本实现所需的输出,但是以编程方式生成无痛脚本非常困难。
我正在寻找可以以编程方式生成的 EQL 查询或可以以编程方式生成无痛脚本的一些 java 插件。
Edit:
我试过的无痛脚本:
"aggs":
"terms":
"scripted_metric":
"init_script": "state.rawMap = [:];",
"map_script": "def product = doc['product'].value;state.rawMap.putIfAbsent(product, new ArrayList());def price = doc['price'].value;if(!state.rawMap.get(product).contains(price))state.rawMap.get(product).add(price);",
"combine_script": "List outputList=new ArrayList();for (entry in state.rawMap.entrySet()) def map=[:]; def min=entry.getValue().get(0); for(price in entry.getValue())if(price<min)min=price;map.product=(entry.getKey()); map.min_price=min;outputList.add(map);return outputList;"
【问题讨论】:
你能展示你到目前为止尝试过的查询吗...我看不出这与简单的术语聚合+最小子聚合有什么不同...好奇... 我使用了无痛脚本。我无法使用 EQL 实现这一点。 请显示查询,否则我们在黑暗中拍摄 @Val 我已经添加了我尝试过的无痛脚本。 【参考方案1】:无需无痛脚本!您想要的可以通过以下聚合查询来实现:
"size": 0,
"aggs":
"products":
"terms":
"field": "product"
,
"aggs":
"distinct_price":
"terms":
"field": "price"
,
"aggs":
"price_stats":
"stats":
"field": "price"
【讨论】:
感谢您的回答,如何找到价格的计数而不是最小值? 您可以使用stats
聚合,然后您就拥有了一切:最小值、最大值、计数等
上面的 EQL 不负责找出每个产品的不同价格。它考虑了所有的值。
它返回的结果与您的第二个屏幕截图完全相同
distinct 在这种情况下毫无意义:min(distinct price)
产生与 min(price)
相同的结果【参考方案2】:
以下查询将为您提供预期的结果:
POST test/_search
"size": 0,
"aggs":
"Fruites":
"terms":
"field": "product.keyword",
"size": 10
,
"aggs":
"min_price":
"min":
"field": "price"
样本结果:
"took" : 3,
"timed_out" : false,
"_shards" :
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
,
"hits" :
"total" :
"value" : 5,
"relation" : "eq"
,
"max_score" : null,
"hits" : [ ]
,
"aggregations" :
"Fruites" :
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
"key" : "apple",
"doc_count" : 2,
"min_price" :
"value" : 120.0
,
"key" : "pears",
"doc_count" : 2,
"min_price" :
"value" : 150.0
,
"key" : "banana",
"doc_count" : 1,
"min_price" :
"value" : 70.0
]
您可以像下面这样创建索引映射:
PUT test
"mappings":
"properties":
"price":
"type": "integer"
,
"product":
"type": "text",
"fields":
"keyword":
"type": "keyword",
"ignore_above": 256
示例数据索引如下:
POST _bulk
"index":"_index":"test","_id":"1"
"product":"apple","price":"120"
"index":"_index":"test","_id":"2"
"product":"banana","price":"70"
"index":"_index":"test","_id":"3"
"product":"pears","price":"150"
"index":"_index":"test","_id":"4"
"product":"apple","price":"220"
"index":"_index":"test","_id":"5"
"product":"apple","price":"120"
"index":"_index":"test","_id":"5"
"product":"pears","price":"180"
【讨论】:
上面的 EQL 不负责找出每个产品的不同价格。它考虑了所有的值。以上是关于Elasticsearch 多个聚合或术语和同一列上的聚合的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch 术语或基数聚合 - 按不同值的数量排序