es基础查询语法
1、es基础查询
1.1 准备数据
# 准备数据
PUT test_index/_doc/1
{
"name":"顾老二",
"age":30,
"from": "gu",
"desc": "皮肤黑、武器长、性格直",
"tags": ["黑", "长", "直"]
}
PUT test_index/_doc/2
{
"name":"大娘子",
"age":18,
"from":"sheng",
"desc":"肤白貌美,娇憨可爱",
"tags":["白", "富","美"]
}
PUT test_index/_doc/3
{
"name":"龙套偏房",
"age":22,
"from":"gu",
"desc":"mmp,没怎么看,不知道怎么形容",
"tags":["造数据", "真","难"]
}
PUT test_index/_doc/4
{
"name":"石头",
"age":29,
"from":"gu",
"desc":"粗中有细,狐假虎威",
"tags":["粗", "大","猛"]
}
PUT test_index/_doc/5
{
"name":"魏行首",
"age":25,
"from":"广云台",
"desc":"仿佛兮若轻云之蔽月,飘飘兮若流风之回雪,mmp,最后竟然没有嫁给顾老二!",
"tags":["闭月","羞花"]
}
1.2 match和term
match 和 term 中必须要加条件,但是我们有时候需要查询所有,不带条件,需要用到 match_all
match:会将查询条件分词,然后进行查询。会先对搜索词进行分词,比如“白雪公主和苹果”,会分成“白雪”“公主”“苹果”。含有相关内容的字段,都会被检索出来。
term:会将查询条件完整的匹配相关字段。在ES中保存的文档,都会对单词进行分词处理,然后建立倒排索引,比如我们存了一个HelloWorld,但是很有可能会被分词成hello和world两个单词,这个时候如果你用term查询,通过HelloWorld是查不到的,因为term是不做分词处理的。这个时候可以通过match或者字段.keyword来代替。
通过term这种查询方式在blogs这个索引中查找title为Quick disjunction的文档,是找不到的,因为Quick disjunction已经做了分词处理
POST blogs/_search
{
"query": {
"term": {
"title": { # 查找的字段
"value": "Quick disjunction" # 查找的数据
}
}
}
}
将上面的语句稍作改动即可
POST blogs/_search
{
"query": {
"term": {
"title.keyword": { # 每个字段都有一个keyword这个属性,是没有分词之前元数据
"value": "Quick disjunction"
}
}
}
}
做查询,返回的结果会给每一个文档做一个相关性算分,用_score来表示,如果一个查询匹配到多条数据,那么_score最高的会排在最前面,表示匹配度最高。这个算分的过程其实是比较消耗性能的,如果我们不关注这个属性的话,可以通过Filter的方式绕过算分这个环节,避免一些开销,并且Filter还可以利用缓存,提升查询效率。
POST blogs/_search
{
"query": {
"constant_score": { # constant:常数,表示跳过算分,返回的_score是一个常数
"filter": {
"term": {
"title.keyword": {
"value": "Quick disjunction"
}
}
}
}
}
}
但是可能大多数情况下,我们还是比较关注score这个分数的,甚至有可能希望为某一次特殊的查询去调整这个分数,比如百度竞价排名的广告。。那么这个时候可以通过另一个参数boost (提高,使增长)这个参数去实现。他是一个浮点类型的数字,默认是1.0,如果我们想去降低分数,只需要把他控制在0.0-1.0之间,越小分数越低,如果我们想提高分数,只需要把他从1.0开始往大调整,越大算出来的分数越高。
POST blogs/_search
{
"query": {
"term": {
"title.keyword": {
"value": "Quick disjunction",
"boost": 2
}
}
}
}
默认情况下,Elasticsearch 将字词查询限制为最多65536个字词。 这包括使用术语查找获取的术语。 你可以使用 index.max_terms_count 设置更改此限制。
1.3 match_all
# 查询所有
GET test_index/_search
{
"query": {
"match_all": {}
}
}
1.4 前缀查询match_phrase_prefix
# 查英文 beautiful --->be开头的---》能查到
GET test_index/_search
{
"query": {
"match_phrase_prefix": {
"name": "顾"
}
}
}
1.5 match_phrase。短语模糊查询,即它会将给定的短语(phrase)当成一个完整的查询条件。match_phrase与slop一起用,能保证分词间的邻近关系,slop参数告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配,默认是0。为0时必须相邻才能被检索出来。
# 会分词,分词完成后,如果写了slop,会按分词之间间隔是slop数字去抽
GET t1/doc/_search
{
"query": {
"match_phrase": {
"title": {
"query": "中国世界",
"slop": 2
}
}
}
}
1.6 多条件查询,或的关系
# 只要name或者desc中带龙套就查出来
GET test_index/_search
{
"query": {
"multi_match": {
"query": "龙套",
"fields": ["name", "desc"]
}
}
}
1.7指定查询字段
GET test_index/_search
{
"query": { "match_all": {} },
"_source": ["id", "createTime"]
}
1.8 wildcard通配符查询。match_phrase与slop一起用,能保证分词间的邻近关系,slop参数告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配,默认是0。为0时 必须相邻才能被检索出来。与mysql中的 Like 是一个套路,可以在查询时,在字符串中指定通配符*和占位符?Wildcard 性能会比较慢。如果非必要,尽量避免在开头加通配符 ? 或者 *,这样会明显降低查询性能
wildcard查询支持下面几个参数:
- value:查询条件,就是我们指定的通配符,目前支持两种:表示可以匹配0到多个字符,?表示匹配任何单个字符。注意在正则表达式中,不能用或者?开头,因为这样可能匹配到大量的数据,导致性能下降严重。
- boost:用来减少或增加查询相关性算分的参数。
- case_insensitive:默认值false,如果设置为true,表示不区分大小写。
- rewrite:可以重写查询方法,目前还没实践到,关于更多说明可以参考:rewrite parameter
{
"wildcard": {
"form_name.keyword": "*very*"
}
}
# 查询的内容非空
{
"wildcard": {
"form_name": "*"
}
}
GET test_index/_search
{
"query": {
"wildcard": {
"user.id": {
"value": "ki*y",
"boost": 1.0,
"rewrite": "constant_score"
}
}
}
}
1.9 查看分词结果
# fieldName可以字段名,也可以是字段名.
http://localhost:9200/{index}/{type}/{id}/_termvectors?fields={fieldName}
# 具体示例
http://localhost:9200/a_index_text/_doc/n1A6ioUBFQ9q5qTUK1mH/_termvectors?fields=phone.short_char
利用该字段的分词器查看分词结果。查看user_addresses索引上address_name字段的分词效果
GET user_addresses/_analyze
{
"field": "address_name",
"text": "山东省青岛市黄岛区"
}
查看指定分词器及filter(GET或者POST都行)
GET _analyze
{
"tokenizer": "standard",
"filter": ["lowercase"],
"text":"Hello WORLD"
}
# 结果
{
"tokens" : [
{
"token" : "hello",
"start_offset" : 0,
"end_offset" : 5,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "world",
"start_offset" : 6,
"end_offset" : 11,
"type" : "<ALPHANUM>",
"position" : 1
}
]
}
1.10查看指定索引总数据量
GET rest_logs-*/_count
# 结果
{
"count" : 12371823,
"_shards" : {
"total" : 631,
"successful" : 631,
"skipped" : 0,
"failed" : 0
}
}
1.11统计总存储空间占用
GET /_cat/shards?v
# 结果
index shard prirep state docs store ip node
rest_logs-2022.08.03 0 r STARTED 8357996 2.6gb *** default-es-default-0
rest_logs-2022.08.03 0 p STARTED 8357996 2.6gb *** default-es-default-3
rest_logs-2022.10.08 0 r STARTED 721722 290.6mb *** default-es-default-4
1.12查看正在数据迁移的索引及进度
GET _cat/recovery
rt_yonghu_serv_hsicrm_wo_userauthenticationbase 0 2.2m peer done 172.16.81.124 es-cn-7pp29cxc0000dlvzw-8e9e6447-0008 172.16.81.119 es-cn-7pp29cxc0000dlvzw-8e9e6447-0006 n/a n/a 159 159 100.0% 159 2658832139 2658832139 100.0% 2658832139 0 0 100.0%
rt_yonghu_serv_hsicrm_wo_userauthenticationbase 0 2.5m peer done 172.16.81.120 es-cn-7pp29cxc0000dlvzw-8e9e6447-0005 172.16.81.121 es-cn-7pp29cxc0000dlvzw-8e9e6447-0002 n/a n/a 150 150 100.0% 150 2659359161 2659359161 100.0% 2659359161 0 0 100.0%
1.13ids查询。ids是相对来说比较简单的一种dsl,类似于mysql的where id in ()的语义,他支持value属性,可以传入一个数组,里面填上你想要查询的ID的文档即可
GET rest_logs-*/_search
{
"query": {
"ids" : {
"values" : ["1", "4", "100"] # 返回属性_id为1、4、100的文档,如果存在的话
}
}
}
1.14exists(Exists Query)
exists是用来匹配文档的mapping中是否包含某一个字段,如果是就返回。比如我有下面两个文档:ID为4的文档有两个字段:title和body,ID为5的文档还有一个字段content。那么如果我们想要查询包含content字段的文档,就可以用exists去做。
POST test_index/_search
{
"query": {
"exists": {"field": "content"}
}
}
还有一点需要注意的是,如果content的value值为null或者[],那么是不会被匹配到的。
1.15 prefix (Prefix Query)
prefix查询很好理解,就是将查询关键字作为一个前缀进行匹配,比如下面的例子,如果title是以Ela作为前缀的都会被匹配到,这里是区分大小写的,如果要设置不区分大小写,可以将case_insensitive设置为true。
POST test_index/_search
{
"query": {
"prefix": { "title.keyword":"Ela"}
}
}
1.16 fuzzy(Fuzzy Query)
上面提到的term查询是一种精确查询,必须要求你输入的查询条件和文档中的数据完全匹配才可以。但是有时候可能用户忘了一个单词怎么写,只记得前3个字母,或者拼写错了,那么如果用term是查不到的。这个时候我们就需要根据用户的输入做一个猜测,进行一个模糊匹配。那么fuzzy正好是为了解决这个问题而出现的。
为了理解fuzzy的用法,这里我们需要先了解一个概念:编辑距离,他是一个单词要变成另一个单词,需要经过几次转换的这个次数。比如java这个单词要变成jbva,只需要将b替换成a,因此这个编辑距离就是1。那么这个转换总共有四种手段
改变其中一个字母,比如box -> fox
删除其中一个字符,比如black -> lack
插入一个新的字母,比如sic -> sick
调整两个相邻字母的位置,比如cat -> act
fuzzy实现模糊查询就是基于这个编辑距离去做的,他会将用户输入的搜索条件,结合一个编辑距离,然后基于我们上面提到的四种手段去做一个扩展和变形,得到一个集合,这个过程我们可以叫做扩展模糊选项,然后将扩展后的模糊选项作为查询条件展开精确匹配,最终将所有的结果进行返回。那么这个编辑距离就需要我们去指定,在es中是通过fuzziness去指定的,他的含义就是最大编辑距离。
POST test_index/_search
{
"query": {
"fuzzy": {
"title.keyword": {
//es中存储的是ElasticSearch,编辑距离是2,那么只要你的输入经过两次转换都变成ElasticSearch,就会匹配到
"value": "ElasticSearh",
"fuzziness": 2
}
}
}
}
fuzzy除了可以指定最大编辑距离之外,还有其他几个参数,这里在做一个总结:
fuzziness:最大编辑距离,值可以是数字类型,也可以是AUTO:[low],[high]这种格式,表示如果查询的单词长度在 [0,low) 这个范围内,编辑距离为0,如果在 [low,high) 这个范围之内,编辑距离为1,如果大于high,则编辑距离为2;除了这两种格式外,还支持AUTO这种写法,等同于AUTO:3,6
max_expansions:最大扩展数量,前面我们提到了扩展模糊选项,假如一个查询扩展了3到5个扩展选项,那么是是很有意义的,如果扩展了1000个模糊选项,其实也就意义不大了,会让我们又迷失在海量的数据中。因此有了max_expansions这个参数,限制最大扩展数量,默认值是50。切记这个值不可以太大,否则会导致性能问题
prefix_length:指定开始多少个字符不可以被模糊
transpositions:boolean值,默认true,表示扩展模糊选项的时候,是否允许两个相邻字符的位置互换。实践过程设置了false,理论上我存储ElasticSearch,检索ElasticSaerch应该搜不到,但是却搜索到了。有点不太理解。
1.17range(Range Query)
range查询,更好理解了,就是范围查询嘛,他的语法可以参考下面的代码。这里呢出现了gte、lte是什么意思呢,其实就是ES中对于范围的描述,这里给大家总结一下:
gt:大于
gte:大于等于
lt:小于
lte:小于等于
GET test_index/_search
{
"query": {
"range": {
"age": {
"gte": 10,
"lte": 20,
"boost": 2.0
}
}
}
}
除了上面说到的表示范围的参数之外,range查询还支持下面的一些参数:
format:string类型,支持对查询的时间进行格式化,如果我们不提供会用默认的格式:"yyyy-MM-dd"
time_zone:用来指定时区,可以是UTC时区的偏移量,比如+01:00,或者IANA时区,比如America/Los_Angeles
relation:用来表示我们指定的范围和文档中数据的关系。一共有三种枚举值:
- INTERSECTS (Default):匹配的文档中的范围字段的值和我们的指定的查询范围是一个交集的关系
- CONTAINS:匹配的文档中的范围字段的值完全包含了我们指定的查询范围
- WITHIN:匹配的文档中的范围字段的值在我们的查询范围之中
range查询也可以用在时间上,并且还可以做时间的计算,在es中,用y表示年,M表示月,d表示天,h表示小时。。。因此可以用+1d、-2h这种方法来进行时间的计算,可以通过/d表示四舍五入到最近的一天。也可以支持now取当前时间。关于时间计算的更多资料可以参考:Date Math
GET test_index/_search
{
"query": {
"range": {
"timestamp": {
"time_zone": "+01:00",
"gte": "2020-01-01T00:00:00",
"lte": "now"
}
}
}
}
1.18regexp(Regexp Query)
通配符查询,功能还是太有限了,如果能支持正则表达式岂不是堪称完美?说曹操曹操到,正则表达式查询,ES也为我们提供了。例如下面的例子,会匹配到user.id是以k开头,y结尾的单词。中间的.*表示匹配任意长度的任意字符像ky、kay、kimchy等都可以被匹配到。
在regexp中,有这么几个参数,需要关注一下,除过value,其他都是可选参数:
- value:查询条件,指定我们输入的正则表达式,关于更多的正则表达式语句可以参考:Regular expression syntax
- flags:可以通过这个参数为正则表达式提供一些更丰富的选项
- ALL:默认值,允许所有的操作符
- COMPLEMENT:允许操作符,用来实现一个求反的效果,例如:abc可以匹配到adc,aec,但是不会匹配到abc。
- INTERVAL:允许操作符<>,用来匹配数字范围,例如:foo<01-100>可以匹配到foo01一直到foo100
- INTERSECTION:允许操作符&,用来and的意思,就是说&符号两遍的表达式都满足才能被匹配到,例如aaa.+&.+bbb可以匹配到aaabbb
- ANYSTRING:允许操作符@,用来匹配任何一个完整的字符串。例如@&~(abc.+)匹配任何字符串,除过以abc开头的
- case_insensitive:默认值false,如果设置为true,表示正则表达式不区分大小写。
- max_determinized_states:据官网介绍,es底层对正则表达式的解析是通过lucene来实现的,那么在lucene解析正则表达式的过程中,会将每个正则表达式转换为包含多个确定状态的状态机,默认值是10000,我们也可以通过这个参数去修改。而且据官网说这个生成状态机的过程是一个很耗时的过程,为了防止资源耗尽,我们应该控制这个参数。如果一个正则表达式特别复杂的话,也可以适当的去把这个参数往大调整。
- rewrite:可以重写查询方法,目前还没实践到,关于更多说明可以参考:rewrite parameter
GET test_index/_search
{
"query": {
"regexp": {
"user.id": {
"value": "k.*y",
"flags": "ALL",
"case_insensitive": true,
"max_determinized_states": 10000,
"rewrite": "constant_score"
}
}
}
}
2、Elasticsearch之排序查询
# 结构化查询
GET test_index/_search
{
"query": {
"match": {
"name": "zz"
}
}
}
# 排序查询---》可以按多个排序条件-->sort的列表中继续加
GET test_index/_search
{
"query": {
"match": {
"from": "gu"
}
},
"sort": [
{
"age": {
"order": "asc"
}
}
]
}
# 不是所有字段都可以排序--->只能是数字字段
3、Elasticsearch之分页查询
# from 和 size,from表示偏移量,从0开始,size表示每页显示的数量
GET test_index/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
}
}
],
"from": 3,
"size": 2
}
4、Elasticsearch之布尔查询
# must(and) should(or) must_not(not) filter
# must条件 and条件
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
# 模糊查询
"from": "sheng"
#精确查询
# "from.keyword": "sheng"
}
},
{
"match": {
"age": 18
}
}
]
}
}
}
"""
# 咱们认为的and查询,但是实际不行
GET test_index/_search
{
"query": {
"match": {
"from": "sheng",
"age":18
}
}
}
"""
# shoud or 条件---》搜索框,就是用它
GET test_index/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"from": "sheng"
}
},
{
"match": {
"age": 22
}
}
]
}
}
}
# must_not 既不是也不是
GET test_index/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"tags": "可爱"
}
},
{
"match": {
"age": 18
}
}
]
}
}
}
# 查询 from为gu,age大于25的数据怎么查 filter /gt> lt< lte=
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"lt": 25
}
}
}
}
}
}
# age字段等于40且state字段不包含ID的文档
GET test_index/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
5、Elasticsearch之查询结果过滤
# 只查某几个字段
GET test_index/_search
{
"query": {
"match": {
"name": "顾老二"
}
},
"_source": ["name", "age"]
}
6、Elasticsearch之高亮查询
# 默认高亮
GET test_index/_search
{
"query": {
"match": {
"name": "石头"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
# 自定义高亮
GET test_index/_search
{
"query": {
"match": {
"from": "gu"
}
},
"highlight": {
"pre_tags": "<b class='key' style='color:red'>",
"post_tags": "</b>",
"fields": {
"from": {}
}
}
}
7、Elasticsearch之聚合函数
# avg max min sum
GET iot_deviceop/_search
{
"aggs": {
"aggs_total": {
"stats": {
"field": "ts"
}
}
},
"size": 0
}
# 结果
{
"took" : 3871,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"aggs_total" : {
"count" : 420275990,
"min" : 1.04328556706E12,
"max" : 1.689223778363E12,
"avg" : 1.6677018684532202E12,
"sum" : 7.008950537890268E20
}
}
}
# avg 求平均年龄
GET test_index/_search
{
"query": {
"match": {
"from": "gu"
}
},
"aggs": {
"my_avg": {
"avg": {
"field": "age"
}
}
},
"_source": ["name", "age"]
}
# 对搜索结果进行聚合,使用aggs来表示,类似于MySql中的group by,例如对name字段进行聚合,统计出相同name的文档数量
GET test_index/_search
{
// 不显示命中(hits)的所有文档信息
"size": 0,
"aggs": {
"group_by_name": {
"terms": {
"field": "name.keyword"
}
}
}
}
# 结果
{
"took" : 170,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"group_by_vin" : {
"doc_count_error_upper_bound" : 33265,
"sum_other_doc_count" : 1767999,
"buckets" : [
{
"key" : "第1天签到",
"doc_count" : 4123788
},
{
"key" : "第2天签到",
"doc_count" : 2237997
},
{
"key" : "第3天签到",
"doc_count" : 1842282
},
{
"key" : "第4天签到",
"doc_count" : 1615952
},
{
"key" : "第5天签到",
"doc_count" : 1466083
},
{
"key" : "第6天签到",
"doc_count" : 1365050
},
{
"key" : "第7天签到",
"doc_count" : 1275374
},
{
"key" : "食材临期即时提醒",
"doc_count" : 321093
},
{
"key" : "解锁多种智能模式",
"doc_count" : 289915
},
{
"key" : "远程操控冰箱温度",
"doc_count" : 282822
}
]
}
}
}
# 嵌套聚合,例如对name字段进行聚合统计出相同name的文档数量,再统计出聚合之后的age的平均值
GET test_index/_search
{
"size": 0,
"aggs": {
"group_by_name": {
"terms": {
"field": "name.keyword"
},
"aggs": {
"average_age": {
"avg": {
"field": "age.keyword"
}
}
}
}
}
}
# 结果
{
"took" : 558,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"group_by_vin" : {
"doc_count_error_upper_bound" : 33265,
"sum_other_doc_count" : 1767999,
"buckets" : [
{
"key" : "第1天签到",
"doc_count" : 4123788,
"average_age" : {
"value" : null
}
},
{
"key" : "第2天签到",
"doc_count" : 2237997,
"average_age" : {
"value" : null
}
},
{
"key" : "第3天签到",
"doc_count" : 1842282,
"average_age" : {
"value" : null
}
},
{
"key" : "第4天签到",
"doc_count" : 1615952,
"average_age" : {
"value" : null
}
},
{
"key" : "第5天签到",
"doc_count" : 1466083,
"average_age" : {
"value" : null
}
},
{
"key" : "第6天签到",
"doc_count" : 1365050,
"average_age" : {
"value" : null
}
},
{
"key" : "第7天签到",
"doc_count" : 1275374,
"average_age" : {
"value" : null
}
},
{
"key" : "食材临期即时提醒",
"doc_count" : 321093,
"average_age" : {
"value" : null
}
},
{
"key" : "解锁多种智能模式",
"doc_count" : 289915,
"average_age" : {
"value" : null
}
},
{
"key" : "远程操控冰箱温度",
"doc_count" : 282822,
"average_age" : {
"value" : null
}
}
]
}
}
}
# 对聚合搜索的结果进行排序,例如对name字段进行聚合统计出相同name的文档数量,再统计出聚合之后的age的平均值,按age的平均值降序排列
GET test_index/_search
{
"size": 0,
"aggs": {
"group_by_vin": {
"terms": {
"field": "name.keyword",
"order": {
"average_age": "desc"
}
},
"aggs": {
"average_age": {
"avg": {
"field": "age.keyword"
}
}
}
}
}
}
# 按字段值的范围进行分段聚合,例如分段范围为age字段的[20,30] [30,40] [40,50],之后按gender统计文档个数和balance的平均值
GET test_index/_search
{
"size": 0,
"aggs": {
"group_by_age": {
"range": {
"field": "age",
"ranges": [
{
"from": 20,
"to": 30
},
{
"from": 30,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance.keyword"
}
}
}
}
}
}
}
}
# 根据name进行分组,并且取前20个
GET test_index/_search
{
"size": 0,
"aggs": {
"group_by_vin": {
"terms": {
"field": "name.keyword",
# 取前20个
"size": 20
}
}
}
}
}
# 多个平行聚合
GET test_index/_search
{
"size": 0,
"aggs": {
"my-agg-name": {
"terms": {
"field": "requestUrl.keyword",
"size": 5
}
},
"my-agg-name2": {
"terms": {
"field": "requestHeader.clientId.keyword",
"size": 5
}
}
}
}
# 结果
{
"took" : 6180,
"timed_out" : false,
"num_reduce_phases" : 2,
"_shards" : {
"total" : 624,
"successful" : 624,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"my-agg-name2" : {
"doc_count_error_upper_bound" : 9661,
"sum_other_doc_count" : 89146934,
"buckets" : [
{
"key" : "callcenter",
"doc_count" : 147486013
},
{
"key" : "duomai",
"doc_count" : 49268821
},
{
"key" : "service_employee",
"doc_count" : 42791694
}
]
},
"my-agg-name" : {
"doc_count_error_upper_bound" : 1819770,
"sum_other_doc_count" : 236828042,
"buckets" : [
{
"key" : "/api/ecoc/v1/kafkaSend/duoMaiExcute",
"doc_count" : 49263156
},
{
"key" : "/api/admin/oauth/token",
"doc_count" : 48386545
},
{
"key" : "/api/dss/userLable/v2/getUserLable",
"doc_count" : 42795064
}
]
}
}
}
# 根据requestUrl进行分组,只取前10个,然后对每个没组里的数据按照@timestamp倒序排列取一条数据(数据里包含requestTime,requestUrl,requestHeader.clientId三个字段),对10条数据分页查询,每页2条;统计所有不同requestUrl的数量
GET rest_logs-*/_search
{
"query": {
"match_all": {}
},
"aggs": {
# 统计所有requestUrl不同的总数
"count": {
"cardinality": {
"field": "requestUrl.keyword"
}
},
"requestUrl_agg": {
"terms": {
# 按照requestUrl分组
"field": "requestUrl.keyword",
# 取10条
"size": 10,
# 按照分组里的数量倒序排列
# 如果是按照分组字段排序,则使用_key
"order": {
"_count": "desc"
}
},
"aggs": {
# 自定义名称
"group_sort": {
"top_hits": {
# 排序
"sort": [
{
# 分组里按照@timestamp倒序排列
"@timestamp": {
"order": "desc"
}
}
],
# 分组里的数据,排序后取值的字段
"_source": {
"includes": [
"requestTime",
"requestUrl",
"requestHeader.clientId"
]
},
# 取一条数据,不取一条会报错
# 报的错:numHits must be > 0; please use TotalHitCountCollector if you just need the total hit count
"size": 1
}
},
# 分页查询
"bucket_sort": {
"bucket_sort": {
"sort": [],
# 从哪个位置开始取,offset
"from": 0,
# 每页的数量
"size": 2
}
}
}
}
},
# 此处的size和from没用了
"size": 0,
"from": 0
}
# 结果
{
"took" : 3719,
"timed_out" : false,
"num_reduce_phases" : 2,
"_shards" : {
"total" : 624,
"successful" : 624,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"count" : {
"value" : 221
},
"requestUrl_agg" : {
"doc_count_error_upper_bound" : 121353,
"sum_other_doc_count" : 57937638,
"buckets" : [
{
"key" : "/api/admin/oauth/token",
"doc_count" : 49542152,
"group_sort" : {
"hits" : {
"total" : {
"value" : 49542152,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "rest_logs-2023.01.05",
"_type" : "_doc",
"_id" : "kxcNgYUBn8gePaBo6-bM",
"_score" : null,
"_source" : {
"requestTime" : "2023-01-05 16:30:51",
"requestUrl" : "/api/admin/oauth/token"
},
"sort" : [
1672907451313
]
}
]
}
}
},
{
"key" : "/api/ecoc/v1/kafkaSend/duoMaiExcute",
"doc_count" : 49333145,
"group_sort" : {
"hits" : {
"total" : {
"value" : 49333145,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "rest_logs-2023.01.05",
"_type" : "_doc",
"_id" : "ghcNgYUBn8gePaBo6-bM",
"_score" : null,
"_source" : {
"requestTime" : "2023-01-05 16:30:51",
"requestUrl" : "/api/ecoc/v1/kafkaSend/duoMaiExcute",
"requestHeader" : {
"clientId" : [
"duomai"
]
}
},
"sort" : [
1672907451132
]
}
]
}
}
}
]
}
}
}
# top_hits查询 查询ts最大的两条信息
GET iot_deviceop/_search
{
"size": 0,
"aggs": {
"top_age_infot": {
"top_hits": {
"size": 2,
"sort": [
{
"ts": {
"order":"desc"
}
}
]
}
}
}
}
# max_bucket查询每个桶的最大值,min_bucket查询每个桶的最小值
GET employee/_search
{
"size": 0,
"aggs": {
"job_info": {
"terms": {
"field": "job"
},
"aggs": {
"job_avg_info": {
"avg": {
"field": "sal"
}
}
}
},
"min_avg_sal_job":{
"max_bucket": {
//查询平均工资最高的岗位
"buckets_path": "job_info>job_avg_info"
}
}
}
}
8、创建更新删除操作
8.1、创建索引并查看
PUT test_index
GET /_cat/indices?v
8.2、删除索引并查看
DELETE test_index
GET /_cat/indices?v
8.3、查看文档类型
GET test_index/_mapping
8.4、在索引中添加文档
PUT test_index/1
{
"vin": "B1293049555"
}
8.5、在索引中查看文档
GET /decode/resolve/1
8.6、在索引中修改文档
POST test_index/1/_update
{
"doc": { "vin": "A1299405555" }
}
8.7、在索引中删除文档
DELETE test_index/1
8.8、在索引中批量操作文档
POST test_index/_bulk
{"index":{"_id":"1"}}
{"name": "aaaa" }
{"index":{"_id":"2"}}
{"name": "bbbb" }
8.9、创建一个数据模型样例(包含index、type、field):
PUT test_index
{
"settings":{
"index":{
"number_of_shards":3,
"number_of_replicas":0
}
},
"mappings":{
"resolve":{
"properties":{
"id":{
"type":"keyword"
},
"name":{
"type":"keyword"
},
"gender":{
"type":"keyword"
},
"carBrandId":{
"type":"text"
},
"balance":{
"type":"int"
},
"age":{
"type":"int"
},
"address":{
"type":"keyword"
},
"craeteTime":{
"type":"date"
},
"statusId":{
"type":"keyword"
},
"enable":{
"type":"boolean"
}
}
}
}
}
8.10、Elasticsearch给type增加一项field
PUT test_index/_mapping
{
"properties": {
"fieldName":{
"type":"boolean"
}
}
}
PUT test_index/_mappings
{
"properties": {
"fieldName":{
"type":"boolean"
}
}
}
https://zhuanlan.zhihu.com/p/521027165
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性