当前位置:   article > 正文

一文看懂ES的R,查询与聚合_es bool查询 聚合

es bool查询 聚合

es查询的索引的company,其有如下字段,下面是一个示例数据

  1. "id": "1", //id
  2. "name": "张三",//姓名
  3. "sex": "男",//性别
  4. "age": 49,//年龄
  5. "birthday": "1970-01-01",//生日
  6. "position": "董事长",//职位
  7. "joinTime": "1990-01-01",//入职时间,日期格式
  8. "modified": "1562167817000",//修改时间,毫秒
  9. "created": "1562167817000" //创建时间,毫秒

下面的搜索都会将关系型数据库语句转换成es的搜索api以及参数。

主要是用post方式,用DSL(结构化查询)语句进行搜索。

一、查询

  • 1、简单搜索
  1. 【sql】
  2.   select * from company
  3. 【ES】有两种方式
  4.   1GET http://192.168.197.100:9200/company/_search
  5.   2、POST http://192.168.197.100:9200/company/_search
  6.     {
  7.         "query":{"match_all":{}}
  8.     }
  • 2、精确匹配(不对查询文本进行分词)
  1. 【sql】
  2.   select * from company where name='张三'
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.     {
  6.       "query":{
  7.         "term":{"name.keyword":"张三"}
  8.       }
  9.     }

term是用于精确匹配的,类似于sql语句中的“=”,因为“name”字段用的是standard默认分词器,其会将“张三”分成“张”和“三”,并不会匹配姓名为“张三”的人,而name.keyword可以让其不会进行分词。

也可以是terms,这个可以用多个值去匹配一个字段,例如

  1. 【sql】
  2.   select * from company where name in ('张三','李四')
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.     {
  6.       "query": {
  7.         "terms": {
  8.           "name.keyword": ["张三", "李四"]
  9.         }
  10.       }
  11.     }
  • 3、模糊匹配
  1. 【sql】
  2.   select * from company where name like '%张%'
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.     {
  6.       "query": {
  7.         "match": {
  8.           "name": "张"
  9.         }
  10.       }
  11.     }

上述查询会查出姓名中带有“张”字的文档

  • 4、分页查询
  1. 【sql】
  2.   select * from company limit 0,10
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.     {
  6.       "from":0,
  7.       "size":10
  8.     }

【注意】from+size不能大于10000,也可以进行修改,但不建议这么操作,因为es主要分片模式,其会在每个分片都会执行一样的查询,然后再进行汇总排序,如果数据太大,会撑爆内存。例如每个分片都查询出10000条,总共5个分片,最后就会进行50000条数据的排序,最后再取值。

  • 5、范围查询并进行排序
  1. 【sql】
  2.   select * from company where age>=10 and age<=50
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.     {
  6.       "query":{
  7.         "range":{
  8.           "age":{
  9.             "gte":10,
  10.             "lte":50
  11.           }
  12.         }
  13.       },
  14.       "sort":{
  15.         "age":{
  16.           "order":"desc"
  17.         }
  18.       }
  19.     }

范围查询是range,有四种参数

  1. (1)gte:大于等于
  2. (2)gt:大于
  3. (3)lte:小于等于
  4. (4)lt:小于

排序是sort,降序是desc,升序是asc,可以有多个排序字段

6、多字段匹配查询

  1. 【sql】
  2.   select * from company where sex like '%男%' or name like '%男%'
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.   {
  6.       "query":{
  7.         "multi_match":{
  8.           "query":"男",
  9.           "fields":["name","sex"]
  10.         }
  11.       }
  12.     }

7、bool查询(结构化查询)

结构化查询主要有三块,分别是must,should,must_not,filter

(1)must:里面的条件都是“并”关系,都匹配

(2)should:里面的条件都是“或”关系,有一个条件匹配就行

(3)must_not:里面的条件都是“并”关系,都不能匹配

(4)filter:过滤查询,不像其它查询需要计算_score相关性,它不进行此项计算,故比query查询快

例如:

条件:年龄在10到50,性别是男,性别一定不能是女,id是1~8的或者职位带有“董”字的

  1. 【sql】
  2.   select * from company where (age>=10 and age=50 and sex="男")
  3.    and (sex!="女"
  4.    and (id in (1,2,3,4,5,6,7,8) or position like '%董%')
  5.    and departments in ('市场部')
  6. 【ES】
  7.   POST http://192.168.197.100:9200/company/_search
  8.    {
  9.       "query":{
  10.         "bool":{
  11.           "must":[
  12.             {"term":{"sex":"男"}},
  13.             {"range":{
  14.               "age":{
  15.                 "gte":10,
  16.                 "lt":50
  17.               }
  18.             }}
  19.           ],
  20.           "must_not":[
  21.             {"term":{"sex":"女"}}  
  22.           ],
  23.           "should":[
  24.             {"terms":{"id":[1,2,3,4,5,6,7,8]}},
  25.             {"match":{"position":"董"}}
  26.           ],
  27.           "filter":[
  28.             {"match":{"departments.keyword":"市场部"}}  
  29.           ]
  30.         }
  31.       }
  32.     }


另外,bool查询是可以嵌套的,也就是must、must_not、should、filter里面还可以嵌套一个完整的bool查询。

  • 8、通配符查询

?:只匹配一个字符

*:匹配多个字符

  1. 【sql】
  2.   select * from company where departments like '%部'
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.   {
  6.       "query":{
  7.         "wildcard":{
  8.                 "departments.keyword":"*部"
  9.             }
  10.       }
  11.     }
  • 9、前缀查询
  1. 【sql】
  2.   select * from company where departments like '市%'
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.   {
  6.       "query":{
  7.         "match_phrase_prefix":{
  8.                 "departments.keyword":"市"
  9.             }
  10.       }
  11.     }
  • 10、查询空值(null)

比如我添加一个文档,里面没有sex字段或者添加的时候sex字段为null,这种情况该怎么进行查询呢?

//添加文档

POST http://192.168.197.100:9200/company/_doc

//没有sex字段的文档

  1.  {
  2.   "id": "1",
  3.     "name": "张十",
  4.     "age": 54,
  5.     "birthday": "1960-01-01",
  6.     "position": "程序员",
  7.     "joinTime": "1980-01-01",
  8.     "modified": "1562167817000",
  9.     "created": "1562167817000"
  10. }

//sex字段值为null的文档

  1.  {
  2.   "id": "1",
  3.     "name": "张十一",
  4.     "age": 64,
  5.     "sex":null,
  6.     "birthday": "1960-01-01",
  7.     "position": "程序员",
  8.     "joinTime": "1980-01-01",
  9.     "modified": "1562167817000",
  10.     "created": "1562167817000"
  11. }

这两种情况的查询是一样的,都是用exists查询匹配,例如:下面的查询会匹配出上述添加的两个文档。

  1. 【sql】
  2.   select * from company where sex is null 
  3. 【ES】
  4.   POST http://192.168.197.100:9200/company/_search
  5.   {
  6.     "query":{
  7.       "bool":{
  8.         "must_not":[
  9.           {"exists":
  10.             {"field":"sex"}
  11.           }
  12.         ]
  13.       }
  14.     }
  15.   }

二、过滤(在es5之后被去除了)

过滤跟查询很相似,都是用来查询数据,只不过过滤会维系一个缓存数组,数组里面记录了匹配的文档,比如一个索引下面有两个文档,进行过滤,一个匹配,一个不匹配,那么数组是这样的[1,0],匹配的文档为1。

在频繁查询的时候,建议用过滤而不是索引。

过滤跟查询的请求体基本相似,只不过多嵌套了一层filtered。

例如:

【sql】

  select * from company where departments like '%市%'

【ES】
 

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.       "query":{
  4.         "filtered":{
  5.           "filter":{
  6.              "match":{
  7.                 "departments.keyword":"市"
  8.             }
  9.           }
  10.         }
  11.       }
  12.     }

三、聚合

聚合允许使用者对es文档进行统计分析,类似与关系型数据库中的group by,当然还有很多其他的聚合,例如取最大值、平均值等等。

语法如下:

POST http://192.168.197.100:9200/company/_search
  1. {
  2.   "aggs": {
  3.     "NAME": { //指定结果的名称
  4.       "AGG_TYPE": { //指定具体的聚合方法,
  5.         TODO:  //# 聚合体内制定具体的聚合字段
  6.       }
  7.     }
  8.     TODO:  //该处可以嵌套聚合
  9.   }
  10. }

聚合分析功能主要有指标聚合、桶聚合、管道聚合和矩阵聚合,常用的有指标聚合和桶聚合,本文主要看一下指标聚合和桶聚合怎么使用。

1、指标聚合

(1)对某个字段取最大值max

【sql】
 

select max(age) from company 

【ES】
 

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.     "aggs":{
  4.       "max_age":{
  5.         "max":{"field":"age"}
  6.       }
  7.     },
  8.     "size":0 //size=0是为了只看聚合结果
  9.   }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "max_age": {
  4.             "value": 64
  5.         }
  6.     }
  7. }


(2)对某个字段取最小值min

【sql】

  select min(age) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.       "aggs":{
  4.         "min_age":{
  5.           "min":{"field":"age"}
  6.         }
  7.       },
  8.       "size":0
  9.     }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "min_age": {
  4.             "value": 1
  5.         }
  6.     }
  7. }

(3)对某个字段计算总和sum

【sql】

select sum(age) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.       "aggs":{
  4.         "sum_age":{
  5.           "sum":{"field":"age"}
  6.         }
  7.       },
  8.       "size":0
  9.     }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "sum_age": {
  4.             "value": 315
  5.         }
  6.     }
  7. }

(4)对某个字段的值计算平均值

【sql】

select avg(sex) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.  {
  3.     "aggs":{
  4.       "age_avg":{
  5.         "avg":{"field":"age"}
  6.       }
  7.     },
  8.     "size":0
  9.   }

结果如下: 

  1. {
  2.     "aggregations": {
  3.         "age_avg": {
  4.             "value": 35
  5.         }
  6.     }
  7. }

(5)对某个字段的值进行去重之后再取总数
【sql】
 

select count(distinct(sex)) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.  {
  3.     "aggs":{
  4.       "sex_distinct":{
  5.         "cardinality":{"field":"sex"}
  6.       }
  7.     },
  8.     "size":0
  9.   }

结果如下: 

  1. {
  2.     "aggregations": {
  3.         "sex_distinct": {
  4.             "value": 2
  5.         }
  6.     }
  7. }

(6)stats聚合,对某个字段一次性返回count,max,min,avg和sum五个指标
【sql】

select count(distinct age),sum(age),avg(age),max(age),min(age) from company

【ES】
 

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.       "aggs":{
  4.         "age_stats":{
  5.           "stats":{"field":"age"}
  6.         }
  7.       },
  8.       "size":0
  9. }

结果如下: 

  1. {
  2.    "aggregations": {
  3.         "age_stats": {
  4.             "count": 9,
  5.             "min": 1,
  6.             "max": 64,
  7.             "avg": 35,
  8.             "sum": 315
  9.         }
  10.     }
  11. }

(7)extended stats聚合,比stats聚合高级一点,多返回平方和、方差、标准差、平均值加/减两个标准差的区间

 
【sql】
  --这个的sql不会写,数学专业的人公式都忘了,耻辱  
【ES】
 

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.       "aggs":{
  4.         "age_extended_stats":{
  5.           "extended_stats":{"field":"age"}
  6.         }
  7.       },
  8.       "size":0
  9. }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "age_extended_stats": {
  4.             "count": 9,
  5.             "min": 1,
  6.             "max": 64,
  7.             "avg": 35,
  8.             "sum": 315,
  9.             "sum_of_squares": 13857,
  10.             "variance": 314.6666666666667,
  11.             "std_deviation": 17.73884626086676,
  12.             "std_deviation_bounds": {
  13.                 "upper": 70.47769252173353,
  14.                 "lower": -0.4776925217335233
  15.             }
  16.         }
  17.     }
  18. }

(8)percentiles聚合,对某个字段的值进行百分位统计 
【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "age_percentiles":{
  5.         "percentiles":{"field":"age"}
  6.       }
  7.     },
  8.     "size":0
  9. }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "age_percentiles": {
  4.             "values": {
  5.                 "1.0": 1,
  6.                 "5.0": 1,
  7.                 "25.0": 26,
  8.                 "50.0": 29,
  9.                 "75.0": 50.25,
  10.                 "95.0": 64,
  11.                 "99.0": 64
  12.             }
  13.         }
  14.     }
  15. }

(9)value count聚合,统计文档中有某个字段的文档数量 
【sql】

select sum(case when sex is null then 0 else 1 end) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "sex_value_count":{
  5.         "value_count":{"field":"sex"}
  6.       }
  7.     },
  8.     "size":0
  9. }


结果如下:总共有8个文档,我在之前添加了两个没有sex字段的文档
【sql】

select sum(case when sex is null then 0 else 1 end) from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "sex_value_count":{
  5.         "value_count":{"field":"sex"}
  6.       }
  7.     },
  8.     "size":0
  9. }

2、桶聚合

桶聚和相当于sql中的group by语句。

(1)terms聚合,分组统计

【sql】

select sex,count(1) from company group by sex

【ES】
 

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "sex_groupby":{
  5.         "terms":{"field":"sex"}
  6.       }
  7.     },
  8.     "size":0
  9. }

结果如下:

  1. {    
  2.   "aggregations": {
  3.         "sex_groupby": {
  4.             "doc_count_error_upper_bound": 0,
  5.             "sum_other_doc_count": 0,
  6.             "buckets": [
  7.                 {
  8.                     "key": "男",
  9.                     "doc_count": 5
  10.                 },
  11.                 {
  12.                     "key": "女",
  13.                     "doc_count": 1
  14.                 }
  15.             ]
  16.         }
  17.     }
  18. }

(2)可以在terms分组下再对其他字段进行其他聚合
【sql】

SELECT name,count(1),AVG(age) from company group by name

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "sex_groupby":{
  5.         "terms":{"field":"sex"},
  6.         "aggs":{
  7.           "avg_age":{
  8.             "avg":{"field":"age"}
  9.           }
  10.         }
  11.       }
  12.     },
  13.     "size":0
  14. }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "sex_groupby": {
  4.             "doc_count_error_upper_bound": 0,
  5.             "sum_other_doc_count": 0,
  6.             "buckets": [
  7.                 {
  8.                     "key": "男",
  9.                     "doc_count": 5,
  10.                     "avg_age": {
  11.                         "value": 33.8
  12.                     }
  13.                 },
  14.                 {
  15.                     "key": "女",
  16.                     "doc_count": 1,
  17.                     "avg_age": {
  18.                         "value": 27
  19.                     }
  20.                 }
  21.             ]
  22.         }
  23.     }
  24. }

(3)filter聚合,过滤器聚合,对符合过滤器中条件的文档进行聚合
【sql】
 

select sum(age) from company where sex = '男'

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2. {
  3.     "aggs":{
  4.       "sex_filter":{
  5.         "filter":{"term":{"sex":"男"}},
  6.         "aggs":{
  7.           "sum_age":{
  8.             "sum":{"field":"age"}
  9.           }
  10.         }
  11.       }
  12.     },
  13.     "size":0
  14. }

结果如下: 

  1. {
  2.     "aggregations": {
  3.         "sex_filter": {
  4.             "doc_count": 5,
  5.             "sum_age": {
  6.                 "value": 169
  7.             }
  8.         }
  9.     }
  10. }

(4)filters多过滤器聚合 
【sql】
 

SELECT name,count(1),sum(age) from company group by name

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.   "aggs":{
  4.     "sex_filter":{
  5.       "filters":{
  6.         "filters":[{"term":{"sex":"男"}},{"term":{"sex":"女"}}]
  7.       },
  8.       "aggs":{
  9.         "sum_age":{
  10.           "sum":{"field":"age"}
  11.         }
  12.       }
  13.     }
  14.   },
  15.   "size":0
  16. }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "sex_filter": {
  4.             "buckets": [
  5.                 {
  6.                     "doc_count": 5,
  7.                     "sum_age": {
  8.                         "value": 169
  9.                     }
  10.                 },
  11.                 {
  12.                     "doc_count": 1,
  13.                     "sum_age": {
  14.                         "value": 27
  15.                     }
  16.                 }
  17.             ]
  18.         }
  19.     }
  20. }

(6)range范围聚合,用于反映数据的分布情况
【sql】

  1. SELECT sum(case when age<=30 then 1 else 0 end), 
  2.        sum(case when age>30 and age<=50 then 1 else 0 end),
  3.        sum(case when age>50 then 1 else 0 end)
  4.   from company 

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.     "aggs":{
  4.       "age_range":{
  5.         "range":{
  6.           "field":"age",
  7.           "ranges":[
  8.             {"to":30},
  9.             {"from":30,"to":50},
  10.             {"from":50}
  11.           ]
  12.         }
  13.       }
  14.     },
  15.     "size":0
  16. }

结果如下:

  1. {
  2.     "aggregations": {
  3.         "age_range": {
  4.             "buckets": [
  5.                 {
  6.                     "key": "*-30.0",
  7.                     "to": 30,
  8.                     "doc_count": 5
  9.                 },
  10.                 {
  11.                     "key": "30.0-50.0",
  12.                     "from": 30,
  13.                     "to": 50,
  14.                     "doc_count": 2
  15.                 },
  16.                 {
  17.                     "key": "50.0-*",
  18.                     "from": 50,
  19.                     "doc_count": 2
  20.                 }
  21.             ]
  22.         }
  23.     }
  24. }

(7)missing聚合,空值聚合,可以统计缺少某个字段的文档数量
【sql】

  SELECT count(1) from company where sex is null

【ES】

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.   "aggs":{
  4.     "missing_sex":{
  5.       "missing":{"field":"sex"}
  6.     }
  7.   },
  8.   "size":0
  9. }

结果如下: 

  1. {
  2.     "aggregations": {
  3.         "missing_sex": {
  4.             "doc_count": 4
  5.         }
  6.     }
  7. }

这个也可以用filter过滤器查询,例如:得到的结果是一样的 

  1. POST http://192.168.197.100:9200/company/_search
  2.   {
  3.   "aggs":{
  4.     "missing_sex":{
  5.       "filter":{
  6.         "bool":{
  7.           "must_not":[
  8.             {"exists":{"field":"sex"}  }
  9.           ]
  10.         }
  11.       }
  12.     }
  13.   },
  14.   "size":0
  15. }

ok,上述就是ES常用的查询和聚合操作。(看来要深入研究一下es了)
原文链接:https://blog.csdn.net/weixin_37337210/article/details/108783727

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/409878
推荐阅读
相关标签
  

闽ICP备14008679号