使用ElasticSearch的多个aggs

时间:2016-10-04 16:49:49

标签: elasticsearch

我是ES的菜鸟,我不知道如何解决这个简单的场景:

dataType value

    1 A
    1 A
    1 B
    2 B
    3 A
    3 A
    4 A
    4 B

我需要知道有多少数据类型只有' A'价值,有多少人只有' B'价值,以及有多少。此示例的预期结果是:

Only A = 1 (dataType 3)
Only B = 1 (dataType 2)
Both = 2 (dataTypes 1 and 4)

Only A = 1 (dataType 3) Only B = 1 (dataType 2) Both = 2 (dataTypes 1 and 4)

你可以帮帮我吗?感谢。

ChintanShah25嗨,非常感谢您的快速回复。我尝试了你开发的代码,但似乎没有正常工作:

"Aggregations": {
           "Datatypes": {
                "Value": {
                "Both": 0,
                "Onlya": 1,
                "OnlyB": 1
            }
        }
    }

如果我删除" reduce_script"我可以调试,获得:


    "Aggregations": {
        "Datatypes": {
        "Value": [
                    [
                        [
                            "1"
                        ],
                        []
                    ],
                    [
                        []
                        []
                    ],
                    [
                        [
                            "1"
                        ],
                        [
                            "1",
                            "2"
                        ]
                    ],
                    [
                        [
                            "4"
                        ],
                        []
                    ],
                    [
                        [
                            "3"
                        ],
                        [
                            "4"
                        ]
                    ]
                ]
            }
        }

数据类型被正确分组,但似乎它们被分成不同的桶或锐利,最后一步是" reduce_script"失败。

文档"脚本度量标准"很差,虽然测试没有达到预期的效果。

问候。

2 个答案:

答案 0 :(得分:2)

我想这很棘手,可以由scripted metric aggregation来完成。我创建了一个测试索引并插入了您提供的示例数据。以下查询提供了您想要的结果

{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "Datatypes": {
      "scripted_metric": {
        "init_script": "_agg['onlya'] = [];_agg['onlyb'] = [];",
        "map_script": "if (doc['value'].value == \"A\")
                         { _agg.onlya.add(doc['datatype'].value) };
                       if (doc['value'].value == \"B\")
                         { _agg.onlyb.add(doc['datatype'].value) };",
        "combine_script": "onlya = _agg['onlya'].unique();
                           onlyb = _agg['onlyb'].unique();
                           return[onlya, onlyb]",
        "reduce_script": "both_bucket=[];a_bucket=[];b_bucket=[];
                          for(a in _aggs)
                            {both_bucket=a[0].intersect(a[1]); 
                             a_bucket=a[0]-a[1];
                             b_bucket=a[1]-a[0]};
                             return ['Both' : both_bucket.size(),
                                     'OnlyA' : a_bucket.size(),
                                     'OnlyB' : b_bucket.size()];"
      }
    }
  },
  "size": 0
}

这是我得到的输出

"aggregations": {
      "Datatypes": {
         "value": {
            "Both": 2,
            "OnlyA": 1,
            "OnlyB": 1
         }
      }
   }

您需要enable dynamic scripting才能使用此功能或将这些脚本放在scripts folder中。

init_script 期间,我声明了两个将保存 datatype 值的变量。

map_script 遍历每个文档,并将数据类型添加到 onlya ,如果值为" A"或者 onlyb 。如果您确定要有A或B

,则可以用else替换第二个if

combine_script 将列表转换为唯一值,以便[1,1,3,3,4]变为[1,3,4]

reduce_script 从所有分片中获取结果。 交集会为您提供包含数据类型值和减法的存储区,只会为您提供 部分。size()为您提供列表的长度。删除size方法以获取匹配的数据类型值。

请浏览documentation以了解有关所有这些不同聚合阶段的工作原理的更多信息

答案 1 :(得分:0)

我最终让它按照我的意愿工作。非常感谢你的帮助。

  "aggs": {
    "Datatypes": {
      "scripted_metric": {
        "init_script": "_agg['onlya'] = [];_agg['onlyb'] = [];",
        "map_script": "valueAdd=doc['datatype'].value; if (doc['value'].value == \"a\") { _agg['onlya'].add(valueAdd) }; if (doc['value'].value == \"b\") { _agg['onlyb'].add(valueAdd) };",
        "combine_script": "onlya = _agg['onlya'].unique();                           onlyb = _agg['onlyb'].unique();                           return[onlya, onlyb]",
        "reduce_script": "a_bucket=[];b_bucket=[];for(a in _aggs){ a_bucket+=a[0]; b_bucket+=a[1];}; return ['Both' : a_bucket.intersect(b_bucket).size(), 'OnlyA' : (a_bucket-b_bucket).size(), 'OnlyB' : (b_bucket-a_bucket).size()];"

      }
    }
  }