ElasticSearch聚合可以执行SQL可以执行的操作吗?

时间:2018-01-24 01:10:19

标签: elasticsearch elasticsearch-aggregation

在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版本。

2 个答案:

答案 0 :(得分:0)

您可以使用The "AdjustJavacVersionArguments" task failed unexpectedly无痛脚本

查询

我将在下面详细解释。

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 = [:]

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

每个分片的计算。我们已经在map_script中做了所有事情,只返回哈希映射

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);

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

答案 1 :(得分:0)

默认情况下,弹性搜索不提供任何使用的聚合类型  一些聚合结果给出了一组新的聚合输出,比如SQL。

  1. 这样做的一种方法是让术语聚合,然后对它们进行分组 使用脚本
  2. 如果您想在单个查询中实现此目的,可以使用脚本度量标准聚合来实现此目的,请使用以下链接获取更多详细信息:
  3. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-scripted-metric-aggregation.html