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 术语

Elasticsearch 多个聚合或术语和同一列上的聚合

具有高基数字段的 ElasticSearch 术语和基数性能

Elasticsearch:从聚合中的存储桶访问值

Elasticsearch 中的术语聚合返回单词而不是完整字段值的存储桶

Elasticsearch 分组聚合查询(bucket) --- 2022-04-03