elasticsearch aggregations 之一:引入buckets、metrics

今天聊聊elasticsearch的聚合aggregation功能。

在解释elasticsearch的时候,都喜欢将es与关系数据库做对比参照,一来大部分coder对关系数据库都有或多或少了解,基本的关系模型、select功能都清楚;二来忽略内部实现如何,就表现出来的功能而言,两者也有可比之处。将两者作对比,可以帮助es新人更好的了解、使用es。接下来就看看两者的aggregation对比如何。

假定有es有一个index,存储了某家汽车经销商的销售信息:包括车的售价、销售时间、车身颜色、生产厂商等。结构如下:

PUT cars
{
  "mappings": {
    "properties": {
      "price":{
        "type": "long"
      },
      "color":{
        "type": "keyword"
      },
      "make":{
        "type": "keyword"
      },
      "sold":{
        "type": "date"
      }
    }
  }
}

那这个index在mysql中可能就对应下面的表结构:

create table cars(price integer,color  varchar(20),make  varchar(50),sold datetime);

往es中写入数据:

POST /cars/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }

mysql也写入数据:

insert into cars values(10000,'red','honda','2014-10-28'),(20000,'red','honda','2014-11-05'),(30000,'green','ford','2014-05-18'),(15000,'blue','toyota','2014-07-02'),(12000,'green','toyota','2014-08-19'),(20000,'red','honda','2014-11-05'),(80000,'red','bmw','2014-01-01'),(25000,'blue','ford','2014-02-12')

现在,假设我们要做个aggregation,要统计下每种颜色的车子都卖了多少。mysql里,我们可以这样写:

mysql> select count(1) from cars group by color;
+----------+
| count(1) |
+----------+
|        4 |
|        2 |
|        2 |
+----------+
3 rows in set (0.00 sec)

那么,在es中需要如何写呢?请看下面:

GET cars/_search
{
  "size": 0, 
  "aggs": {
    "cts_by_color": {
      "terms": {
        "field": "color",
        "size": 10
      }
    }
  }
}

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "cts_by_color" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "red",
          "doc_count" : 4
        },
        {
          "key" : "blue",
          "doc_count" : 2
        },
        {
          "key" : "green",
          "doc_count" : 2
        }
      ]
    }
  }
}

es中通过qsl来实现。我们来一步一步分解这个qsl:

GET cars/_search  ①
{
  "size": 0,  ②
  "aggs": { ③
    "cts_by_color": { ④
      "terms": { ⑤
        "field": "color",  ⑥
        "size": 10  ⑦
      }
    }
  }
}

①:aggregation处于search检索上下文中,表明aggregation是一个search  request;
②:size 0表示结果集中不显示满足条件的document记录。这里实际上是所有文档。省略了match_all的部分;

"query": {
    "match_all": {}
  }

③:aggs 这是一个顶层的关键字,表示是aggregation操作;
④:这是自定义的名称,目前用不到。但是不能省略;
⑤:term aggregation_type,聚合的一种类型,用于keyword类型以及其他适合buckets aggregations的类型。如果用于index的text类型的话,需要启用fielddata;
⑥:以字段color来动态生成buckets,每一个unique的值生成一个buckets;
⑦:显示前10个。

这个qsl的功能是:在所有的document上,以字段color的不同值动态的生成buckets,然后以相同color的document记录数metrics从高到低倒序,取前10个值。

这里来看看aggregation的语法图:

"aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

与mysql的sql语句对照起来,这里的buckets就相当于sql中的group by,省略的默认document计数metrics就相当于sql中的count(1)。

这就引入了es总的两个重要概念:buckets、metrics。

buckets:一个buckets是满足特定条件的document的集合,简而言之,就是对documents按照条件进行分组,属于相同组的document落入一个buckets。当进行aggregation的时候,如果document上对应field的值满足对应的条件,则此document会落入这个buckets。buckets之间可以嵌套,以形成层次关系。

metrics:就是我们的最终目的,在buckets对文档分组后,取响应的指标值。例如avg,sum,max,min等。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章