Elasticsearch 术语或基数聚合 - 按不同值的数量排序
Posted
技术标签:
【中文标题】Elasticsearch 术语或基数聚合 - 按不同值的数量排序【英文标题】:Elasticsearch Terms or Cardinality Aggregation - Order by number of distinct values 【发布时间】:2014-10-28 05:53:28 【问题描述】:朋友们,
我正在做一些分析,以从数以亿计的文档中找到唯一的对。模拟示例如下图:
文档字段1 字段2
-
AAA : BBB
AAA : CCC
PPP : QQQ
PPP : QQQ
XXX : YYY
XXX : YYY
嗯:NNN
90% 的文档包含一个唯一的对,如上面文档 3、4、5、6 和 7 中所示,我对我的聚合结果不感兴趣。我有兴趣汇总文档 1 和 2。
术语聚合查询:
“聚合”: “f1”: “条款”: “字段”:“字段1”, “min_doc_count”:2 , “聚合”: “f2”: “条款”: “字段”:“字段 2”词条聚合结果
“聚合”: “f1”: “桶”:[ “关键”:“PPP”, “文档计数”:2, “f2”: “桶”:[ "key": "QQQ", “文档计数”:2 ] , “关键”:“XXX”, “文档计数”:2, “f2”: “桶”:[ "key": "YYY", “文档计数”:2 ] , “钥匙”:“AAA”, “文档计数”:2, “f2”: “桶”:[ “关键”:“BBB”, “文档计数”:1 , “关键”:“CCC”, “文档计数”:1 ] ]我只对聚合结果中的键 AAA 感兴趣。过滤包含不同对的聚合结果的最佳方法是什么?
我尝试了基数聚合,这导致了 unque 值计数。但是我无法从聚合结果中过滤掉我不感兴趣的内容。
基数聚合查询
“聚合”: “f1”: “条款”: “字段”:“字段1”, “min_doc_count”:2 , “聚合”: “f2”: “基数”: “字段”:“字段 2”基数聚合结果
“聚合”: “f1”: “桶”:[ “关键”:“PPP”, “文档计数”:2, “f2”: “价值”:1 , “关键”:“XXX”, “文档计数”:2, “f2”: “价值”:1 , “钥匙”:“AAA”, “文档计数”:2, “f2”: “价值”:2 ]至少如果我可以按基数排序,那将有助于我找到一些解决方法。请在这方面帮助我。
P.S:编写 spark/mapreduce 程序来后处理/过滤聚合结果不是此问题的预期解决方案。
【问题讨论】:
如果你想对从第二个聚合中得到的基值应用排序,你可以通过在第一个聚合中应用order
来做到这一点,就像这样 "terms":"field":"field1","min_doc_count":2,"order":"f2":"desc/asc"
【参考方案1】:
我建议将过滤查询与聚合一起使用,因为您只对 field1=AAA 感兴趣。
我这里有一个类似的例子。
例如,我有一个包含我医院所有患者的索引。我将他们的药物使用情况存储在一个嵌套对象 DRUG 中。每个患者可以服用不同的药物,每个患者可以多次服用一种药物。
现在,如果我想查找至少服用一次阿司匹林的患者数量,查询可能是:
"size": 0,
"_source": false,
"query":
"filtered":
"query":
"match_all":
,
"filter":
"nested":
"path": "DRUG",
"filter":
"bool":
"must": [ "term": "DRUG.NAME": "aspirin" ]
,
"aggs":
"DRUG_FACETS":
"nested":
"path": "DRUG"
,
"aggs":
"DRUG_NAME_FACETS":
"terms": "field": "DRUG.NAME", "size": 0 ,
"aggs":
"DISTINCT": "cardinality": "field": "DRUG.PATIENT"
示例结果:
"took": 6,
"timed_out": false,
"_shards":
"total": 5,
"successful": 5,
"failed": 0
,
"hits":
"total": 6,
"max_score": 0,
"hits": []
,
"aggregations":
"DRUG_FACETS":
"doc_count": 11,
"DRUG_NAME_FACETS":
"buckets": [
"key": "aspirin",
"doc_count": 6,
"DISTINCT":
"value": 6
,
"key": "vitamin-b",
"doc_count": 3,
"DISTINCT":
"value": 2
,
"key": "vitamin-c",
"doc_count": 2,
"DISTINCT":
"value": 2
]
第一个是阿司匹林。但是你可以看到另外2名患者在服用阿司匹林的同时也服用了维生素b。
如果您将 DRUG.NAME 的字段值更改为另一个药物名称,例如“vitamin-b”,我想您会在存储桶的第一个位置获得维生素 b。
希望这对您的问题有所帮助。
【讨论】:
与其使用 query,后者最终会使用查询上下文并计算分数,不如在聚合中定义一个 filter,然后定义子聚合。【参考方案2】:有点晚了,希望对其他人有所帮助。
一种简单的方法是只过滤***聚合中的“AAA”记录:
"size": 0,
"aggregations":
"filterAAA":
"filter":
"term":
"FIELD1": "AAA"
,
"aggregations":
"f1":
"terms":
"field": "FIELD1",
"min_doc_count": 2
,
"aggregations":
"f2":
"terms":
"field": "FIELD2"
【讨论】:
以上是关于Elasticsearch 术语或基数聚合 - 按不同值的数量排序的主要内容,如果未能解决你的问题,请参考以下文章
具有高基数字段的 ElasticSearch 术语和基数性能