二、Elasticsearch进阶篇

2.1 Elasitcsearch数据同步

    2.1.1 ES与关系型数据库同步

    2.1.2 ES与非关系型数据库同步

    2.1.3 ES与Kafka同步

    2.1.4 ES文件同步

    2.1.5 ES同步小结

 

2.2 Elasticsearch检索进阶

2.3 Elasitcsearch聚合进阶

    39、 Elasticsearch聚合深入详解——对比Mysql实现


聚合认知前提
    桶(Buckets)  ——满足特定条件的文档的集合 
    指标(Metrics)——对桶内的文档进行统计计算

    SELECT COUNT(color)  FROM table  GROUP BY color

        COUNT(color) 相当于指标。 
        GROUP BY color 相当于桶。

es multi_terms聚合 es的聚合_ES

一、聚合起步

1、创建索引

1.1 创建索引DSL实现

put cars
POST /cars/transactions/_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" }

1.2 创建mysql库表sql实现

CREATE TABLE `cars` (
  `id` int(11) NOT NULL,
  `price` int(11) DEFAULT NULL,
  `color` varchar(255) DEFAULT NULL,
  `make` varchar(255) DEFAULT NULL,
  `sold` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2、统计不同颜色车的数目

2.1 统计不同颜色车的DSL实现【ES】 

GET /cars/transactions/_search
{
  "size":0,
  "aggs":{
      "popular_colors" : {
          "terms":{
              "field": "color.keyword"
           }
       }
   }
}

过滤条件: 
聚合条件 aggs:颜色 Color; 【相当于group by】
排序条件:

返回结果:lve

2.2 统计不同颜色的mysql实现

select color, count(color) as cnt from cars group by color order by cnt desc;

返回结果:

red 4
green 2
blue 2

 

3、统计不同颜色车的平均价格

3.1 统计不同颜色车的平均价格DSL实现:aggs -- avg_price -- avg -- "field": "price"

3.2 统计不同颜色车的平均价格sql实现:

select 
    color, 
    count(color) as cnt, 
    avg(price) as avg_price 
from cars group by color order by cnt desc;

返回结果:
     color   cnt      avg_price
     red       4      32500.0000
     green   2      21000.0000
     blue     2      20000.0000

 

4、每种颜色汽车制造商的分布

4.1 统计每种颜色汽车制造商的分布dsl实现: aggs -- colors;aggs -- make。

4.2 统计每种颜色汽车制造商的分布sql实现

select color, make from cars order by color;

说明:和dsl的实现不严格对应

     color make

     blue toyota

     blue ford

     green ford

     green toyota

     red honda

     red honda

5、统计每个制造商的最低价格、最高价格

5.1 统计每个制造商的最低、最高价格的DSL实现

5.2 统计每个制造商的最低、最高价格的sql实现

select
    make, 
    min(price) as min_price, 
    max(price) as max_price 
from cars 
group by make;

          make       min_price        max_price
          bmw        80000                80000
          ford         25000                30000
          honda     10000                20000
          toyota     12000                15000

 

二、聚合进阶

1、条形图聚合

1.1 分段统计每个区间的汽车销售价格总和

GET /cars/transactions/_search
{
  "size":0,
  "aggs":{
      "price" : {
          "histogram":{
              "field": "price",
              "interval": 20000
          },
          "aggs":{
              "revenue":{
                  "sum":{
                      "field": "price"
                  }
              }
          }
      }
  }
}

过滤条件: 价格区间
聚合条件 aggs:价格总和; 【相当于group by】
排序条件:

汽车销售价格区间:定义为20000; 
分段统计price和用sum统计。

1.2 多维度度量不同制造商的汽车指标

GET /cars/transactions/_search
{
  "size" : 0,
  "aggs": {
      "makes": {
          "terms": {
              "field": "make.keyword",
              "size": 10
          },
          "aggs": {
              "stats": {
                  "extended_stats": {
                      "field": "price"
                  }
               }
          }
      }
  }
}

 

2、按时间统计聚合

2.1 按月份统计制造商汽车销量dsl实现

2.2 按月份统计制造商汽车销量sql实现

SELECT 
    make, 
    count(make) as cnt, 
    CONCAT(YEAR(sold),  ',',  MONTH(sold)) AS data_time
FROM `cars`
GROUP BY YEAR(sold) DESC,MONTH(sold)

查询结果如下:
       make      cnt        data_time
       bmw        1               2014,1
       ford         1               2014,2
       ford         1               2014,5
       toyota     1               2014,7
       toyota     1               2014,8
       honda     1               2014,10
       honda     2               2014,11

 

2.3 包含12月份的处理DSL实现

以上2.1 中没有12月份的统计结果显示。

2.4 以季度为单位统计DSL实现

 

 

2.5 基于搜索的(范围限定)聚合操作

2.5.1 基础查询聚合

GET /cars/transactions/_search
{
  "query" : {
      "match" : {
          "make.keyword" : "ford"
      }
  },
  "aggs" : {
      "colors" : {
          "terms" : {
              "field" : "color.keyword"
          }
      }
  }
}

对应的sql实现:

select 
    make, color 
from cars
where make = "ford";

结果返回如下: make      color

                          ford         green

                         ford         blue

 

三、过滤聚合

1. 过滤操作

统计全部汽车的平均价钱以及单品平均价钱;

select avg(price) from cars;

select make, color, avg(price) from cars
where make = "ford" ;

 

2、范围限定过滤(过滤桶)

我们可以指定一个过滤桶,当文档满足过滤桶的条件时,我们将其加入到桶内。

mysql的实现如下:

select *, avg(price) 
from cars 
where period_diff(date_format(now() , '%Y%m') , date_format(sold, '%Y%m')) > 30
and make = "ford";

mysql查询结果如下:

              id         price        color        make        sold                avg

             3           30000      green       ford        2014-05-18      27500.0000

3、后过滤器

只过滤搜索结果,不过滤聚合结果——post_filter实现

GET /cars/transactions/_search
{
  "query": {
      "match": {
          "make": "ford"
      }
   },
  "post_filter": {
      "term" : {
          "color.keyword" : "green"
      }
  },
  "aggs" : {
      "all_colors": {
          "terms" : { "field" : "color.keyword" }
      }
  }
}

post_filter 会过滤搜索结果,只展示绿色 ford 汽车。这在查询执行过 后 发生,所以聚合不受影响。

 

小结 
选择合适类型的过滤(如:搜索命中、聚合或两者兼有)通常和我们期望如何表现用户交互有关。

选择合适的过滤器(或组合)取决于我们期望如何将结果呈现给用户。

在 filter 过滤中的 non-scoring 查询,同时影响搜索结果和聚合结果。
filter 桶影响聚合。
post_filter 只影响搜索结果。

 

四、多桶排序

4.1 内置排序 -- order

4.2 按照度量排序

以下是按照汽车平均售价的升序进行排序。 
过滤条件:汽车颜色; 
聚合条件:平均价格; 
排序条件:汽车的平均价格升序。

GET /cars/transactions/_search
{
  "size" : 0,
  "aggs" : {
      "colors" : {
          "terms" : {
              "field" : "color.keyword",
              "order": {
                  "avg_price" : "asc"
               }
           },
          "aggs": {
              "avg_price": {
                  "avg": {"field": "price"}
               }
           }
      }
    }
}

 

4.3 基于“深度”的度量排序

太复杂,不推荐!

五、近似聚合

cardinality的含义是“基数”;

5.1 统计去重后的数量

类似于:

SELECT COUNT(DISTINCT color)  FROM cars;

六、doc values解读

 

 

Elasticsearch聚合后分页深入详解


1、Elasticsearch支持聚合后分页吗,为什么?

不支持,看看Elasticsearch员工如何解读。 

 

2、Elasticsearch要实现聚合后分页,该怎么办?

方案:需要展示满足条件的全部数据条数,即需要全量聚合,且按照某规则排序。 
记住,如果数据基数大(十万、百万甚至千万级),这必然会很慢。

步骤1:全量聚合,size设置为: 2147483647。 
ES5.X/6.X版本设置为2147483647 ,它等于2^31-1, 
是32位操作系统中最大的符号型整型常量;ES1.X 2.X版本设置为0。

步骤2:将聚合结果存入内存中,可以考虑list或map存储。 
这里存入list的_id是基于某种规则排序过的,如:基于插入时间。

步骤3:内存内分页,基于list中存储值结合偏移值进行筛选。 
如每页10条数据,取第一页就是:取list中第0到第9个元素,以此类推。

步骤4:基于筛选出的值进行二次查询获取详情。 
此处的筛选条件已经能唯一确定一篇document。

 

3、“聚合后不能分页,但能分区来取”,是什么鬼?

貌似,没有起到分页的作用。此处没有深入研究。

 

4、聚合后分页实战

步骤1:建立索引 

put book_index

步骤2:导入数据

举例原因,假设后来导入百万甚至千万级别数据。

POST book_index/book_type/1

步骤3:聚合

要求:按照以下条件聚合 
1)相同作者出书量;(聚合) 
2)相同作者的书,取时间最大的返回。(聚合后排序)

步骤4:获取关键信息存入list。

步骤5:二次遍历+偏移截取分页实现。