设为首页 收藏本站
查看: 1543|回复: 0

[经验分享] ElasticSearch常用操作:查询与聚合篇

[复制链接]

尚未签到

发表于 2019-1-29 09:18:48 | 显示全部楼层 |阅读模式
  [TOC]

0 说明
  基于es 5.4和es 5.6,列举的是个人工作中经常用到的查询(只是工作中使用的是Java API),如果需要看完整的,可以参考官方相关文档
https://www.elastic.co/guide/en/elasticsearch/reference/5.4/search.html。

1 查询
  先使用一个快速入门来引入,然后后面列出的各种查询都是用得比较多的(在我的工作环境是这样),其它没怎么用的这里就不列出了。

1.1 快速入门

1.1.1 查询全部

GET index/type/_search
{
"query":{
"match_all":{}
}
}
  或

GET index/type/_search
1.1.2 分页(以term为例)

GET index/type/_search
{
"from":0,
"size":100,
"query":{
"term":{
"area":"GuangZhou"
}
}
}
1.1.3 包含指定字段(以term为例)

GET index/type/_search
{
"_source":["hobby", "name"],
"query":{
"term":{
"area":"GuangZhou"
}
}
}
1.1.4 排序(以term为例)
  单个字段排序:

GET index/type/_search
{
"query":{
"term":{
"area":"GuangZhou"
}
},
"sort":[
{"user_id":{"order":"asc"}},
{"salary":{"order":"desc"}}
]
}
1.2 全文查询
  查询字段会被索引和分析,在执行之前将每个字段的分词器(或搜索分词器)应用于查询字符串。

1.2.1 match query

{
"query": {
"match": {
"content": {
"query": "里皮恒大",
"operator": "and"
}
}
}
}
  operator默认是or,也就是说,“里皮恒大”被分词为“里皮”和“恒大”,只要content中出现两个之一,都会搜索到;设置为and之后,只有同时出现都会被搜索到。


1.2.2 match_phrase query
  文档同时满足下面两个条件才会被搜索到:


  • (1)分词后所有词项都要出现在该字段中
  • (2)字段中的词项顺序要一致

{
"query": {
"match_phrase": {
"content": "里皮恒大"
}
}
}
1.3 词项查询
  词项搜索时对倒排索引中存储的词项进行精确匹配,词项级别的查询通过用于结构化数据,如数字、日期和枚举类型。

1.3.1 term query

{
"query": {
"term": {
"postdate": "2015-12-10 00:41:00"
}
}
}
1.3.2 terms query
  term的升级版,如上面查询的postdate字段,可以设置多个。

{
"query": {
"terms": {
"postdate": [
"2015-12-10 00:41:00",
"2016-02-01 01:39:00"
]
}
}
}
  因为term是精确匹配,所以不要问,[]中的关系怎么设置and?这怎么可能,既然是精确匹配,一个字段也不可能有两个不同的值。


1.3.3 range query
  匹配某一范围内的数据型、日期类型或者字符串型字段的文档,注意只能查询一个字段,不能作用在多个字段上。
  数值:

{
"query": {
"range": {
"reply": {
"gte": 245,
"lte": 250
}
}
}
}
  支持的操作符如下:
  gt:大于,gte:大于等于,lt:小于,lte:小于等于

  日期:

{
"query": {
"range": {
"postdate": {
"gte": "2016-09-01 00:00:00",
"lte": "2016-09-30 23:59:59",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
  format不加也行,如果写的时间格式正确。


1.3.4 exists query
  返回对应字段中至少有一个非空值的文档,也就是说,该字段有值(待会会说明这个概念)。

{
"query": {
"exists": {
"field": "user"
}
}
}
  参考《从Lucene到Elasticsearch:全文检索实战》中的说明。
  以下文档会匹配上面的查询:


文档
说明




{"user":"jane"}
有user字段,且不为空


{"user":""}
有user字段,值为空字符串


{"user":"-"}
有user字段,值不为空


{"user":["jane"]}
有user字段,值不为空


{"user":["jane",null]}
有user字段,至少一个值不为空即可
  下面的文档不会被匹配:


文档
说明




{"user":null}
虽然有user字段,但是值为空


{"user":[]}
虽然有user字段,但是值为空


{"user":[null]}
虽然有user字段,但是值为空


{"foo":"bar"}
没有user字段

1.3.5 ids query
  查询具有指定id的文档。

{
"query": {
"ids": {
"type": "news",
"values": "2101"
}
}
}
  类型是可选的,也可以以数据的方式指定多个id。


{
"query": {
"ids": {
"values": [
"2101",
"2301"
]
}
}
}
1.4 复合查询

1.4.1 bool query
  因为工作中接触到关于es是做聚合、统计、分类的项目,经常要做各种复杂的多条件查询,所以实际上,bool query用得非常多,因为查询条件个数不定,所以处理的逻辑思路时,外层用一个大的bool query来进行承载。(当然,项目中是使用其Java API)
  bool query可以组合任意多个简单查询,各个简单查询之间的逻辑表示如下:


属性
说明




must
文档必须匹配must选项下的查询条件,相当于逻辑运算的AND


should
文档可以匹配should选项下的查询条件,也可以不匹配,相当于逻辑运算的OR


must_not
与must相反,匹配该选项下的查询条件的文档不会被返回


filter
和must一样,匹配filter选项下的查询条件的文档才会被返回,但是filter不评分,只起到过滤功能
  一个例子如下:

{
"query": {
"bool": {
"must": {
"match": {
"content": "里皮"
}
},
"must_not": {
"match": {
"content": "中超"
}
}
}
}
}
  需要注意的是,同一个bool下,只能有一个must、must_not、should和filter。

  如果希望有多个must时,比如希望同时匹配"里皮"和"中超",但是又故意分开这两个关键词(因为事实上,一个must,然后使用match,并且operator为and就可以达到目的),怎么操作?注意must下使用数组,然后里面多个match对象就可以了:

{
"size": 1,
"query": {
"bool": {
"must": [
{
"match": {
"content": "里皮"
}
},
{
"match": {
"content": "恒大"
}
}
]
}
},
"sort": [
{
"id": {
"order": "desc"
}
}
]
}
  当然must下的数组也可以是多个bool查询条件,以进行更加复杂的查询。

  上面的查询等价于:

{
"query": {
"bool": {
"must": {
"match": {
"content": {
"query": "里皮恒大",
"operator": "and"
}
}
}
}
},
"sort": [
{
"id": {
"order": "desc"
}
}
]
}
1.5 嵌套查询
  先添加下面一个索引:

PUT /my_index
{
"mappings": {
"my_type": {
"properties": {
"user":{
"type": "nested",
"properties": {
"first":{"type":"keyword"},
"last":{"type":"keyword"}
}
},
"group":{
"type": "keyword"
}
}
}
}
}
  添加数据:

PUT my_index/my_type/1
{
"group":"GuangZhou",
"user":[
{
"first":"John",
"last":"Smith"
},
{
"first":"Alice",
"last":"White"
}
]
}
PUT my_index/my_type/2
{
"group":"QingYuan",
"user":[
{
"first":"Li",
"last":"Wang"
},
{
"first":"Yonghao",
"last":"Ye"
}
]
}
  查询:
  较简单的查询:

{
"query": {
"nested": {
"path": "user",
"query": {
"term": {
"user.first": "John"
}
}
}
}
}
  较复杂的查询:

{
"query": {
"bool": {
"must": [
{"nested": {
"path": "user",
"query": {
"term": {
"user.first": {
"value": "Li"
}
}
}
}},
{
"nested": {
"path": "user",
"query": {
"term": {
"user.last": {
"value": "Wang"
}
}
}
}
}
]
}
}
}
1.6 补充:数组查询与测试
  添加一个索引:

PUT my_index2
{
"mappings": {
"my_type2":{
"properties": {
"message":{
"type": "text"
},
"keywords":{
"type": "keyword"
}
}
}
}
}
  添加数据:

PUT /my_index2/my_type/1
{
"message":"keywords test1",
"keywords":["美女","动漫","电影"]
}
PUT /my_index2/my_type/2
{
"message":"keywords test2",
"keywords":["电影","美妆","广告"]
}
  搜索:

{
"query": {
"term": {
"keywords": "广告"
}
}
}
  Note1:注意设置字段类型时,keywords设置为keyword,所以使用term查询可以精确匹配,但设置为text,则不一定——如果有添加分词器,则可以搜索到;如果没有,而是使用默认的分词器,只是将其分为一个一个的字,就不会被搜索到。这点尤其需要注意到。
  Note2:对于数组字段,也是可以做桶聚合的,做桶聚合的时候,其每一个值都会作为一个值去进行分组,而不是整个数组进行分组,可以使用上面的进行测试,不过需要注意的是,其字段类型不能为text,否则聚合会失败。
  Note3:所以根据上面的提示,一般纯数组比较适合存放标签类的数据,就像上面的案例一样,同时字段类型设置为keyword,而不是text,搜索时进行精确匹配就好了。


1.7 滚动查询scroll
  如果一次性要查出来比如10万条数据,那么性能会很差,此时一般会采取用scoll滚动查询,一批一批的查,直到所有数据都查询完处理完(es返回的scrollId,可以理解为是es进行此次查询的操作句柄标识,每发送一次该scrollId,es都会操作一次,或者说循环一次,直到时间窗口到期)。
  使用scoll滚动搜索,可以先搜索一批数据,然后下次再搜索一批数据,以此类推,直到搜索出全部的数据来,scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的,每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内能完成就可以了(也就是说,该scrollId只在这个时间窗口内有效,视图快照也是)。

GET spnews/news/_search?scroll=1m
{
"query": {
"match_all": {}
},
"size": 10,
"_source": ["id"]
}
GET _search/scroll
{
"scroll":"1m",
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoAwAAAAAAADShFmpBMjJJY2F2U242RFU5UlAzUzA4MWcAAAAAAAA0oBZqQTIySWNhdlNuNkRVOVJQM1MwODFnAAAAAAAANJ8WakEyMkljYXZTbjZEVTlSUDNTMDgxZw=="
}
2 聚合

2.1 指标聚合
  相当于MySQL的聚合函数。

max

{
"size": 0,
"aggs": {
"max_id": {
"max": {
"field": "id"
}
}
}
}
  size不设置为0,除了返回聚合结果外,还会返回其它所有的数据。


min

{
"size": 0,
"aggs": {
"min_id": {
"min": {
"field": "id"
}
}
}
}
avg

{
"size": 0,
"aggs": {
"avg_id": {
"avg": {
"field": "id"
}
}
}
}
sum

{
"size": 0,
"aggs": {
"sum_id": {
"sum": {
"field": "id"
}
}
}
}
stats

{
"size": 0,
"aggs": {
"stats_id": {
"stats": {
"field": "id"
}
}
}
}
2.2 桶聚合
  相当于MySQL的group by操作,所以不要尝试对es中text的字段进行桶聚合,否则会失败。

Terms
  相当于分组查询,根据字段做聚合。

{
"size": 0,
"aggs": {
"per_count": {
"terms": {
"size":100,
"field": "vtype",
"min_doc_count":1
}
}
}
}
  在桶聚合的过程中还可以进行指标聚合,相当于mysql做group by之后,再做各种max、min、avg、sum、stats之类的:

{
"size": 0,
"aggs": {
"per_count": {
"terms": {
"field": "vtype"
},
"aggs": {
"stats_follower": {
"stats": {
"field": "realFollowerCount"
}
}
}
}
}
}
Filter
  相当于是MySQL根据where条件过滤出结果,然后再做各种max、min、avg、sum、stats操作。

{
"size": 0,
"aggs": {
"gender_1_follower": {
"filter": {
"term": {
"gender": 1
}
},
"aggs": {
"stats_follower": {
"stats": {
"field": "realFollowerCount"
}
}
}
}
}
}
  上面的聚合操作相当于是:查询gender为1的各个指标。


Filters
  在Filter的基础上,可以查询多个字段各自独立的各个指标,即对每个查询结果分别做指标聚合。

{
"size": 0,
"aggs": {
"gender_1_2_follower": {
"filters": {
"filters": [
{
"term": {
"gender": 1
}
},
{
"term": {
"gender": 2
}
}
]
},
"aggs": {
"stats_follower": {
"stats": {
"field": "realFollowerCount"
}
}
}
}
}
}
Range

{
"size": 0,
"aggs": {
"follower_ranges": {
"range": {
"field": "realFollowerCount",
"ranges": [
{
"to": 500
},
{
"from": 500,
"to": 1000
},
{
"from": 1000,
"to": 1500
},
{
"from": "1500",
"to": 2000
},
{
"from": 2000
}
]
}
}
}
}
  to:小于,from:大于等于


Date Range
  跟上面一个类似的,其实只是字段为日期类型的,然后范围值也是日期。

Date Histogram Aggregation
  这个功能十分有用,可以根据年月日来对数据进行分类。
索引下面的文档:

DELETE my_blog
PUT my_blog
{
"mappings": {
"article":{
"properties": {
"title":{"type": "text"},
"postdate":{
"type": "date"
, "format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
PUT my_blog/article/1
{
"title":"Elasticsearch in Action",
"postdate":"2014-09-23 23:34:12"
}
PUT my_blog/article/2
{
"title":"Spark in Action",
"postdate":"2015-09-13 14:12:22"
}
PUT my_blog/article/3
{
"title":"Hadoop in Action",
"postdate":"2016-08-23 23:12:22"
}
  按年对数据进行聚合:

GET my_blog/article/_search
{
"size": 0,
"aggs": {
"agg_year": {
"date_histogram": {
"field": "postdate",
"interval": "year",
"order": {
"_key": "asc"
}
}
}
}
}
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"agg_year": {
"buckets": [
{
"key_as_string": "2014-01-01 00:00:00",
"key": 1388534400000,
"doc_count": 1
},
{
"key_as_string": "2015-01-01 00:00:00",
"key": 1420070400000,
"doc_count": 1
},
{
"key_as_string": "2016-01-01 00:00:00",
"key": 1451606400000,
"doc_count": 1
}
]
}
}
}
  按月对数据进行聚合:

GET my_blog/article/_search
{
"size": 0,
"aggs": {
"agg_year": {
"date_histogram": {
"field": "postdate",
"interval": "month",
"order": {
"_key": "asc"
}
}
}
}
}
  这样聚合的话,包含的年份的每一个月的数据都会被分类,不管其是否包含文档。

  按日对数据进行聚合:

GET my_blog/article/_search
{
"size": 0,
"aggs": {
"agg_year": {
"date_histogram": {
"field": "postdate",
"interval": "day",
"order": {
"_key": "asc"
}
}
}
}
}
  这样聚合的话,包含的年份的每一个月的每一天的数据都会被分类,不管其是否包含文档。





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-668993-1-1.html 上篇帖子: Elasticsearch 6.0.0 正式发布 下篇帖子: Elasticsearch analysis & 自定义 analyzers
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表