【问题标题】:Can ElasticSearch aggregations do what SQL can do?ElasticSearch 聚合可以做 SQL 可以做的事情吗?
【发布时间】:2018-07-02 23:03:10
【问题描述】:

在 Elasticsearch 中,我需要从最高到最低获取最频繁出现的颜色的频率和数量。 如果我有这样的数据:

id|name
----------
1|blue
----------
2|blue
----------
3|green
----------
4|yellow
----------
5|blue
----------
6|yellow
----------
7|purple
----------
8|purple
----------
9|purple

我需要获取每种颜色的计数,然后按计数分组。所以最后,我希望所有出现相同次数的颜色都在一个组内。 这就是我在 sql 中的做法。

select 
  count(*) as 'Number of Colors', 
  i.c as 'Seen times' 
from 
    (
      select
        name as 'n', 
        count(*) as 'c'
      from
        colors
      group by name
   ) i 
group by i.c
order by i.c desc;

这将返回:

Number of Colors | Seen times
------------------------------
2                | 3
------------------------------
1                | 2
------------------------------
1                | 1

如何在 Elasticsearch 查询中编写它?我使用的是 5.5 版。

【问题讨论】:

标签: elasticsearch elasticsearch-aggregation


【解决方案1】:

您可以将scripted_metric aggregation 与无痛脚本一起使用

查询

下面我会详细解释。

POST index/type/_search
{
  "size": 0, 
  "aggs": {
    "colorgroups": {
"scripted_metric": {
"init_script" : "params._agg.transactions = [:]",
"map_script": "params.key = doc['colorname'].value; if(params._agg.transactions[params.key] == null){   params._agg.transactions[params.key] = 1; }else{   params._agg.transactions[params.key] ++ }",
"combine_script": "return params._agg.transactions;",
"reduce_script": "params.color_counters =[:]; params.groups_counters =[:]; for(shard_result in params._aggs){   for(color_name in shard_result.keySet()){     if(params.color_counters[color_name] == null){       params.color_counters[color_name] = shard_result[color_name]     }else{       params.color_counters[color_name] = params.color_counters[color_name] + shard_result[color_name]     }    } }  for(color_name in params.color_counters.keySet()){   params.group_counter = params.color_counters[color_name].toString();   if(params.groups_counters[params.group_counter] == null){     params.groups_counters[params.group_counter] = 1   }else{     params.groups_counters[params.group_counter] ++   } }  return params.groups_counters"
      }
    }
  }
}

结果

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "colorgroups": {
      "value": {
        "2": 3,
        "1": 2,
        "1": 1
     }
    }
  }
}

init_script

初始化一些值以保留中间结果

params._agg.transactions = [:]

地图脚本

每个文档的计算。在这一步尽量保持小并减少尽可能多的数据。

params.key = doc['colorname'].value;
if(params._agg.transactions[params.key] == null){
  params._agg.transactions[params.key] = 1;
}else{
  params._agg.transactions[params.key] ++
}

combine_script

每个分片的计算。我们已经在 map_script 中做了所有事情,只需返回 hash map

return params._agg.transactions

reduce_script

使用来自每个分片的部分聚合。我们需要先将它们合并到一个 HashMap 中。然后按计数器值分组

params.color_counters =[:];
params.groups_counters =[:];
//merging all partial aggregations to params.color_counters
for(shard_result in params._aggs){
  for(color_name in shard_result.keySet()){
    if(params.color_counters[color_name] == null){
      params.color_counters[color_name] = shard_result[color_name]
    }else{
      params.color_counters[color_name] = params.color_counters[color_name] + shard_result[color_name]
    } 
  }
}

//Grouping by color counter to params.groups_counters
for(color_name in params.color_counters.keySet()){
  params.group_counter = params.color_counters[color_name].toString();
  if(params.groups_counters[params.group_counter] == null){
    params.groups_counters[params.group_counter] = 1
  }else{
    params.groups_counters[params.group_counter] ++
  }
}

return params.groups_counters

你可以打电话

Debug.explain(variable);

在无痛脚本中的任何位置调试变量并根据需要调整脚本。

【讨论】:

    【解决方案2】:

    默认情况下,弹性搜索不提供任何聚合类型 一些聚合结果,以提供新聚合集的输出,如 SQL 所具有的。

    1. 一种方法是聚合术语,然后将它们分组 使用脚本
    2. 如果您想在单个查询中实现这一点,您可以使用 Scripted Metric Aggregation 来实现这一点,使用以下链接获取更多详细信息:

    https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-scripted-metric-aggregation.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 1970-01-01
      • 2013-06-26
      • 1970-01-01
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多