二、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实现
【参考: https://blog.csdn.net/laoyang360/article/details/79048455 】
聚合认知前提
桶(Buckets) ——满足特定条件的文档的集合
指标(Metrics)——对桶内的文档进行统计计算
SELECT COUNT(color) FROM table GROUP BY color
COUNT(color) 相当于指标。
GROUP BY color 相当于桶。
一、聚合起步
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聚合后分页深入详解
https://blog.csdn.net/laoyang360/article/details/79112946
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:二次遍历+偏移截取分页实现。