Elasticsearch聚合学习之三:范围限定
Posted 程序员欣宸
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch聚合学习之三:范围限定相关的知识,希望对你有一定的参考价值。
欢迎访问我的GitHub
本篇概览
- 在《Elasticsearch聚合学习》系列的前面两篇文章中,我们熟悉了基本聚合操作,但这些操作都是面向索引中的全部数据(例如所有汽车销售记录一共有几种颜色的汽车),今天要学习的是如何对一定范围内的数据做聚合(例如以前是看所有汽车一共有几种颜色,现在只看福特汽车一共有几种颜色);
环境信息
- 以下是本次实战的环境信息,请确保您的Elasticsearch可以正常运行:
- 操作系统:Ubuntu 18.04.2 LTS
- JDK:1.8.0_191
- Elasticsearch:6.7.1
- Kibana:6.7.1
- 实战用的数据依然是一些汽车销售的记录,在第一章有详细的导入步骤,请参考操作,导入后您的es中的数据如下图:
本章概要
- 本篇聚焦查询范围限定,由以下内容构成:
- 不做限定时的默认范围;
- 最简单的查询范围
- 全局桶
- 使用过滤器
- 桶内使用过滤器
不做限定时的默认范围
- 下面是个普通的聚合请求,将文档按照color字段聚合,由于没有做任何范围限定,因此查询的是所有文档:
GET /cars/transactions/_search
"size":0,
"aggs":
"popular_colors":
"terms":
"field": "color"
- 下面请求带上了查询条件match_all ,匹配所有文档,和前面不带查询条件的请求达到了同样效果:
GET /cars/transactions/_search
"size":0,
"query": ------查询条件
"match_all": ------匹配所有文档
,
"aggs":
"popular_colors":
"terms":
"field": "color"
最简单的查询范围
- 前面提出了一个问题:**福特汽车一共分为几种颜色?**这就是最简单的范围限定聚合(限定了汽车品牌),查询DSL如下:
GET /cars/transactions/_search
"size":0,
"query": ---范围限定的查询
"term": ---查询类型是精确匹配
"make": "ford" ---查询条件是品牌为福特
,
"aggs": ---聚合
"popular_colors": ---聚合字段名
"terms": ---桶类型
"field": "color" ---匹配字段是color
- 返回结果如下,只有福特汽车的聚合数据:
"took" : 7,
"timed_out" : false,
"_shards" :
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
,
"hits" :
"total" : 2,
"max_score" : 0.0,
"hits" : [ ]
,
"aggregations" : ---聚合结果
"popular_colors" : ---聚合字段
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [ ---这个数组的元素是所有的桶
"key" : "blue", ---color为blue的文档
"doc_count" : 1 ---文档数为1
,
"key" : "green", ---color为blue的文档
"doc_count" : 1 ---文档数为1
]
全局桶
- 如果想对比福特汽车的销售额和所有汽车的销售额,可以通过全局桶对所有文档做聚合,关键字是global,全局桶的聚合不受范围限定的影响:
GET /cars/transactions/_search
"size": 0,
"query": ---范围限定的查询
"term": ---查询类型是精确匹配
"make": "ford" ---查询条件是品牌为福特
,
"aggs": ---聚合
"ford_sales": ---聚合字段名
"sum": ---直接对范围内的所有文档执行metrics,类型是累加
"field": "price" ---选择price字段的值进行累加
,
"all": ---聚合字段名
"global": , ---全局桶关键字,表示忽略前面term查询的范围限定
"aggs": ---聚合
"all_sales": ---聚合字段名
"sum": ---直接对范围内的所有文档执行metrics,类型是累加
"field": "price" ---选择price字段的值进行累加
- 来看看结果:
......
"aggregations" : ---聚合结果
"all" : ---全局桶的聚合结果(term查询无效)
"doc_count" : 8, ---文档总数
"all_sales" : ---聚合字段名
"value" : 212000.0 ---总销售额
,
"ford_sales" : ---聚合字段名(term查询限定了范围,只有福特汽车的销售记录)
"value" : 55000.0 ---福特汽车销售额
不止是query
- 前面的范围限定用到了query,其实适用于查询的过滤器也能应用在聚合操作中,下面是过滤+聚合的查询,和前面一样,也是统计总销售和和福特汽车的销售额:
GET /cars/transactions/_search
"size": 0,
"query":
"bool": ---布尔查询,里面可以将query和filter组合使用
"filter": ---本例只用到了filter
"term": ---精确匹配
"make": "ford" ---匹配福特品牌
,
"aggs": ---聚合结果
"ford_sales": ---聚合字段名
"sum": ---metrics操作,累加
"field": "price" ---累加字段是price
,
"all": ---聚合字段名
"global": , ---全局桶关键字,表示忽略范围限定
"aggs": ---聚合
"all_sales": ---聚合字段名
"sum": ---metrics操作,累加
"field": "price" ---累加字段是price
- 查询结果如下,和query的一样:
......
"aggregations" :
"all" :
"doc_count" : 8,
"all_sales" :
"value" : 212000.0
,
"ford_sales" :
"value" : 55000.0
- **注意:**虽然query和filter限定范围的结果是一样的,但是filter会忽略评分,并且有可能缓存结果数据,这些都是性能上的优势;
桶内filter
- 学习桶内filter之前,先看看官方的布尔查询DSL,如下所示,查询JSON对象的内部可以加入filter,对查询结果做过滤:
GET /_search
"query":
"bool":
"must": [ ---布尔查询
"match": "title": "Search" ,
"match": "content": "Elasticsearch"
],
"filter": [ ---对查询结果做过滤
"term": "status": "published" ,
"range": "publish_date": "gte": "2015-01-01"
]
- 桶内filter和布尔查询中的filter类似,对进入桶中的数据可以加入filter,这样桶内的数据就是此filter过滤后的数据了;
- 举个例子,统计蓝色的福特汽车销售额,首先限定品牌范围,这个可以直接用之前的限定方式,然后在桶内加入一个filter,只保留颜色为蓝色的文档:
GET /cars/transactions/_search
"size": 0,
"query":
"bool": ---布尔查询,里面可以将query和filter组合使用
"filter": ---本例只用到了filter
"term": ---精确匹配
"make": "ford" ---匹配福特品牌
,
"aggs":
"sales":
"filter": ---桶内filter
"term": ---精确匹配
"color": "blue" ---匹配蓝色
,
"aggs":
"blue_sales":
"sum": ---metrics操作,累加
"field": "price"
- 返回结果如下,可见hits.total等于2,表示查询到了两个文档,但是sales.doc_count等于1,表示桶内filter作用后再桶内只剩下一个文档了:
"hits" :
"total" : 2,
"max_score" : 0.0,
"hits" : [ ]
,
"aggregations" :
"sales" :
"doc_count" : 1,
"green_sales" :
"value" : 25000.0
后过滤器(post_filter)
-
还有一种特殊的filter,名为post_filter,其作用描述如下:
-
正常的聚合:先查询,得到查询结果A,再用A做聚合操作得到结果B,最后返回B和A;
-
带有post_filter的聚合:先查询,得到查询结果A,再用A做聚合操作得到结果B,然后用A做过滤得到C(过滤条件就是post_filter),最后返回B和C;
-
可见无论是否使用post_filter,返回的聚合结果都是根据A生成的B,不同之处在于用了post_filter就不返回A,而是返回A的过滤结果;
-
以下是来自《Elasticsearch 权威指南》的post_filter示例:
GET /cars/transactions/_search
"size" : 0,
"query":
"match":
"make": "ford"
,
"post_filter":
"term" :
"color" : "green"
,
"aggs" :
"all_colors":
"terms" : "field" : "color"
-
**值得注意得是:**如果只做查询不做聚合,post_filter的作用和我们常用的filter是类似的,但由于post_filter是在查询之后才会执行,所以post_filter不具备filter对查询带来的好处(忽略评分、缓存等),因此,在普通的查询中不要用post_filter来替代filter;
-
如果您向进一步了解post_filter,请参考《理解elasticsearch的post_filter》
-
至此,带有范围限定的聚合操作实战就全部完成了,目前所有示例的结果都是默认排序的,接下来的章节将一起学习了解如何对聚合结果做排序。
欢迎关注51CTO博客:程序员欣宸
以上是关于Elasticsearch聚合学习之三:范围限定的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch学习之深入聚合分析三---案例实战
Elasticsearch学习之嵌套聚合,下钻分析,聚合分析
Elasticsearch学习之深入聚合分析二---案例实战