系列文章:
从零学Elasticsearch系列——基础概念从零学Elasticsearch系列——环境搭建从零学Elasticsearch系列——使用kibana实现ES基本的操作从零学Elasticsearch系列——深入搜索(Query、Filter、Aggregation)从零学Elasticsearch系列——JAVA API操作从零学Elasticsearch系列——集成中文分词器IK从零学Elasticsearch系列——构建ES集群从零学Elasticsearch系列——搭建ELK Nginx日志分析平台
搜索方式
搜索有两种方式:一种是通过URL
参数进行搜索,另一种是通过DSL(Request Body)
进行搜索
DSL:Domain Specified Language,特定领域语言
使用请求体可以让你的JSON数据以一种更加可读和更加富有展现力的方式发送。
导入测试数据集
# 批量插入测试数据POST /zpark/user/_bulk{"index":{"_id":1}}{"name":"zs","realname":"张三","age":18,"birthday":"-12-27","salary":1000.0,"address":"北京市昌平区沙阳路55号"}{"index":{"_id":2}}{"name":"ls","realname":"李四","age":20,"birthday":"-10-20","salary":5000.0,"address":"北京市朝阳区三里屯街道21号"}{"index":{"_id":3}}{"name":"ww","realname":"王五","age":25,"birthday":"-03-15","salary":4300.0,"address":"北京市海淀区中关村大街新中关商城2楼511室"}{"index":{"_id":4}}{"name":"zl","realname":"赵六","age":20,"birthday":"-04-19","salary":12300.0,"address":"北京市海淀区中关村软件园9号楼211室"}{"index":{"_id":5}}{"name":"tq","realname":"田七","age":35,"birthday":"2001-08-11","salary":1403.0,"address":"北京市海淀区西二旗地铁辉煌国际大厦负一楼"}
查询(Query)
1. 查看所有并按照年龄降序排列
查询所有并排序
URL实现
GET /zpark/user/_search?q=*&sort=age:desc&pretty
DSL实现
GET /zpark/user/_search{"query":{"match_all":{}# 查询所有},"sort":{"age":"desc" # 按年龄倒序排列}}
2. 查询第2页的用户(每页显示2条)
分页查询
URL实现
GET /zpark/user/_search?q=*&sort=_id:asc&from=2&size=2
DSL实现
GET /zpark/user/_search{"query":{"match_all":{}# 查询所有},"sort":{"_id":"asc" # 按年龄倒序排列},"from":2,# 从(nowPage-1)*pageSize检索"size":2 # 查 pageSize条}
3. 查询address
在海淀区的所有用户,并高亮
基于全文检索的查询(分析检索关键词 匹配索引库 返回结果)
DSL实现
GET /zpark/user/_search{"query": {"match": {# 注意: match查询会分词 如:海淀区 会分词为 海 | 淀 | 区"address":"海淀区"}},"highlight": {"fields": {# 需要高亮的字段列表"address": {} }}}
4. 查询name
是zs
关键字的用户
基于Term词元查询
URL实现
GET /zpark/user/_search?q=name:zs
DSL实现
GET /zpark/user/_search{"query":{"term": {"name": {"value": "zs"}}}}
5. 查询年龄在20~30
岁之间的用户
基于范围查询
DSL实现
GET /zpark/user/_search{"query": {"range": {"age": {"gte": 20, # 大于等于 大于用 gt"lte": 30 # 小于等于 小于用 lt}}}}
6. 查询真实姓名以张
开头的用户
基于前缀(prefix)查询
DSL实现
GET /zpark/user/_search{"query": {"prefix": {"realname": {"value": "李"}}}}
7. 查询名字已s
结尾的用户
基于通配符(wildcard)的查询
?
匹配一个字符*
匹配0~n个字符
DSL实现
GET /zpark/user/_search{"query": {"wildcard": {"name": {"value": "*s"}}}}
8. 查询id
为1,2,3的用户
基于Ids的查询
DSL实现
GET /zpark/user/_search{"query": {"ids": {"values": [1,2,3]}}}
9. 模糊查询realname
中包含张
关键字的用户
基于Fuzzy的查询
DSL实现
GET /zpark/user/_search{"query": {"fuzzy": {"realname": {"value": "张"}}}}
10. 查询age
在15-30岁之间并且name
必须通配z*
基于Boolean的查询(多条件查询)
must
:查询结果必须符合该查询条件(列表)。should
:类似于or的查询条件。must_not
:查询结果必须不符合查询条件(列表)。
DSL实现
GET /zpark/user/_search{"query": {"bool": {"must": [ #年龄在15~30岁之间并且必须名字通配z*{"range": {"age": {"gte": 15,"lte": 30}}},{"wildcard": {"name": {"value": "z*"}}}],"must_not": [ # 正则查询 name必须不能以s结尾{"regexp": {"name": ".*s"}}] }}}
过滤器(Filter)
其实准确来说,ES中的查询操作分为2种:查询(query)和过滤(filter)。查询即是之前提到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序。而过滤(filter)只会筛选出符合的文档,并不计算得分,且它可以缓存文档。所以,单从性能考虑,过滤比查询更快。
换句话说,过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。
过滤器使用
GET /zpark/user/_search{"query":{"bool": {"must": [{"match_all": {}}],"filter": {# 过滤年龄大于等于25岁的用户"range": {"age": {"gte": 25}}}}}}
注意: 过滤查询运行时先执行过滤语句,后执行普通查询
过滤器的类型
1.term
、terms
Filter
term、terms的含义与查询时一致。term用于精确匹配、terms用于多词条匹配
GET /zpark/user/_search{"query":{"bool": {"must": [{"match_all": {}}],"filter": {"terms": {"name": ["zs","ls"]}}}}}
2.ranage
filter
3.exists
filter
exists
过滤指定字段没有值的文档
GET /zpark/user/_search{"query": {"bool": {"must": [{"match_all": {}}],"filter": {# 排除salary为null的结果"exists": {"field": "salary"}}}},"sort": [{"_id": {"order": "asc"}}]}
或(相反操作)
GET /zpark/user/_search{"query": {"bool": {"must_not": [{"exists": {"field": "salary"}}]}}}
4.ids
filter
需要过滤出若干指定_id的文档,可使用标识符过滤器(ids)
GET /zpark/user/_search{"query": {"bool": {"must": [{"match": {"address": "昌平区"}}],"filter": {"ids": {# id 过滤器"values": [1,2,3]}}}}}
5. 其余使用方式可查阅官网
Note:
Query和Filter更详细的对比可参考:/laoyang360/article/details/80468757
聚合(Aggregations)
https://www.elastic.co/guide/en/elasticsearch/reference/6.x/search-aggregations.html
聚合提供了功能可以分组并统计你的数据。理解聚合最简单的方式就是可以把它粗略的看做SQL的GROUP BY操作和SQL的聚合函数。
ES中常用的聚合:
metric(度量)聚合:度量类型聚合主要针对的number类型的数据,需要ES做比较多的计算工作,类似于关系型数据库的组函数操作bucketing(桶)聚合:划分不同的“桶”,将数据分配到不同的“桶”里。非常类似sql中的group语句的含义,类似于关系型数据库的分组操作
ES中的聚合API如下:
"aggregations" : {// 表示聚合操作,可以使用aggs替代"<aggregation_name>" : {// 聚合名,可以是任意的字符串。用做响应的key,便于快速取得正确的响应数据。"<aggregation_type>" : {// 聚合类别,就是各种类型的聚合,如min等<aggregation_body>// 聚合体,不同的聚合有不同的body}[,"aggregations" : {[<sub_aggregation>]+ } ]? // 嵌套的子聚合,可以有0或多个}[,"<aggregation_name_2>" : {... } ]* // 另外的聚合,可以有0或多个}
度量(metric)聚合
1. Avg Aggregation
平均值查询,作用于number类型字段上。如:查询用户的平均年龄
POST /zpark/user/_search{"aggs": {"age_avg": {"avg": {"field": "age"}}}}-------------------------------------------------------------------{......"aggregations": {"age_avg": {"value": 23.6}}}
也可以先过滤,再进行统计,如:
POST /zpark/user/_search{"query": {"ids": {"values":[1,2,3]}}, "aggs": {"age_avg": {"avg": {"field": "age"}}}}
2. Max Aggregation
最大值查询。如:查询员工的最高工资
POST /zpark/user/_search{"aggs": {"max_salary": {"max": {"field": "salary"}}}}
3. Min Aggregation
4. Sum Aggregation
5. [Stats Aggregation](Stats Aggregation)
统计查询,一次性统计出某个字段上的常用统计值
POST /zpark/user/_search{"aggs": {"max_salary": {"stats": {"field": "salary"}}}}--------------------------------------------{...."aggregations": {"max_salary": {"count": 4,"min": 1000,"max": 12300,"avg": 5650,"sum": 22600}}}
桶(bucketing)聚合
1. Range Aggregation
自定义区间范围的聚合,我们可以自己手动地划分区间,ES会根据划分出来的区间将数据分配不同的区间上去。
如: 统计0-20岁,20-35岁,35~60岁用户人数
POST /zpark/user/_search{"aggs": {"age_ranges": {"range": {"field": "age","ranges": [{"from": 0,"to": 20},{"from": 20,"to": 35},{"from": 35,"to": 60}]}}}}----------------------------------------------------------{......"aggregations": {"age_ranges": {"buckets": [{"key": "0.0-20.0","from": 0,"to": 20,"doc_count": 1 # 区间范围的文档数量},{"key": "20.0-35.0","from": 20,"to": 35,"doc_count": 3},{"key": "35.0-60.0","from": 35,"to": 60,"doc_count": 1}]}}}
2. Terms Aggregation
自定义分组依据Term,对分组后的数据进行统计
如:根据年龄分组,统计相同年龄的用户
POST /zpark/user/_search{"aggs": {"age_counts":{"terms": {"field": "age","size": 2 // 保留2个统计结果}}}}----------------------------------------------------------{......"aggregations": {"age_counts": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 2,"buckets": [{"key": 20,"doc_count": 2},{"key": 18,"doc_count": 1}]}}}
3. Date Range Aggregation
时间区间聚合专门针对date类型的字段,它与Range Aggregation的主要区别是其可以使用时间运算表达式。
now+10y:表示从现在开始的第。now+10M:表示从现在开始的第10个月。1990-01-10||+20y:表示从1990-01-01开始后的第,即-01-01。now/y:表示在年位上做舍入运算。
如: 统计生日在、、的用户
POST /zpark/user/_search{"aggs": {"date_counts": {"date_range": {"field": "birthday","format": "yyyy-MM-dd", "ranges": [{"from": "now/y", # 当前年的1月1日"to": "now" # 当前时间},{"from": "now/y-1y", # 当前年上一年的1月1日"to":"now/y" # 当前年的1月1日},{"from": "now/y-2y", "to":"now/y-1y"}]}}}}-------------------------------------------------------------------------------{....."aggregations": {"date_counts": {"buckets": [{"key": "-01-01--01-01","from": 1451606400000,"from_as_string": "-01-01","to": 1483228800000,"to_as_string": "-01-01","doc_count": 1},{"key": "-01-01--01-01","from": 1483228800000,"from_as_string": "-01-01","to": 1514764800000,"to_as_string": "-01-01","doc_count": 1},{"key": "-01-01--12-26","from": 1514764800000,"from_as_string": "-01-01","to": 1545847233691,"to_as_string": "-12-26","doc_count": 0}]}}}
4. Histogram Aggregation
直方图聚合,它将某个number类型字段等分成n份,统计落在每一个区间内的记录数。它与前面介绍的Range聚合非常像,只不过Range可以任意划分区间,而Histogram做等间距划分。既然是等间距划分,那么参数里面必然有距离参数,就是interval参数。
如:根据年龄间隔(5岁)统计
POST /zpark/user/_search{"aggs": {"histogram_age": {"histogram": {"field": "age","interval": 5}}}}-------------------------------------------------------------------------------{......"aggregations": {"histogram_age": {"buckets": [{"key": 15,"doc_count": 1},{"key": 20,"doc_count": 2},{"key": 25,"doc_count": 1},{"key": 30,"doc_count": 0},{"key": 35,"doc_count": 1}]}}}
5. Date Histogram Aggregation
日期直方图聚合,专门对时间类型的字段做直方图聚合。这种需求是比较常用见得的,我们在统计时,通常就会按照固定的时间断(1个月或1年等)来做统计。
如:按年统计用户
POST /zpark/user/_search{"aggs": {"date_histogram": {"date_histogram": {"field": "birthday","interval": "year","format": "yyyy-MM-dd"}}}}-------------------------------------------------------------------------------{......"aggregations": {"date_histogram": {"buckets": [{"key_as_string": "2001-01-01","key": 978307200000,"doc_count": 1},{"key_as_string": "2002-01-01","key": 1009843200000,"doc_count": 0},{"key_as_string": "-01-01","key": 1041379200000,"doc_count": 1},{"key_as_string": "-01-01","key": 1072915200000,"doc_count": 0},{"key_as_string": "-01-01","key": 1104537600000,"doc_count": 0},{"key_as_string": "-01-01","key": 1136073600000,"doc_count": 0},{"key_as_string": "-01-01","key": 1167609600000,"doc_count": 0},{"key_as_string": "-01-01","key": 1199145600000,"doc_count": 0},{"key_as_string": "-01-01","key": 1230768000000,"doc_count": 0},{"key_as_string": "-01-01","key": 1262304000000,"doc_count": 0},{"key_as_string": "-01-01","key": 1293840000000,"doc_count": 0},{"key_as_string": "-01-01","key": 1325376000000,"doc_count": 0},{"key_as_string": "-01-01","key": 1356998400000,"doc_count": 0},{"key_as_string": "-01-01","key": 1388534400000,"doc_count": 0},{"key_as_string": "-01-01","key": 140400000,"doc_count": 0},{"key_as_string": "-01-01","key": 1451606400000,"doc_count": 1},{"key_as_string": "-01-01","key": 1483228800000,"doc_count": 1},{"key_as_string": "-01-01","key": 1514764800000,"doc_count": 1}]}}}
嵌套使用
聚合操作是可以嵌套使用的。通过嵌套,可以使得metric类型的聚合操作作用在每一bucket上。我们可以使用ES的嵌套聚合操作来完成稍微复杂一点的统计功能。
如:统计每年中用户的最高工资
POST /zpark/user/_search{"aggs": {"date_histogram": {# bucket聚合 按照年分区"date_histogram": {"field": "birthday","interval": "year","format": "yyyy-MM-dd"},"aggs": {"salary_max": {"max": {# metric聚合 求最大工资"field": "salary"}}}}}}--------------------------------------------------------------------------------------{......"aggregations": {"date_histogram": {"buckets": [......{"key_as_string": "-01-01","key": 1483228800000,"doc_count": 1,"salary_max": {"value": 5000}},{"key_as_string": "-01-01","key": 1514764800000,"doc_count": 1,"salary_max": {"value": 1000}}]}}}