初步了解ES

一、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.13 ids查询。

ids是相对来说比较简单的一种dsl,类似于mysql的where id in ()的语义,他支持value属性,可以传入一个数组,里面填上你想要查询的ID的文档即可

GET rest_logs-*/_search
{"query": {"ids" : {"values" : ["1", "4", "100"]  # 返回属性_id为14100的文档,如果存在的话}}
}

1.14 exists(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.17 range(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.18 regexp(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进行分组,并且取前20GET 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"}}
}

二、ES查询相关Java的API

1、Java三种操作ES数据库的方式

以下是这三种操作方式(ElasticsearchTemplate、ElasticsearchRepository和ElasticsearchRestTemplate)与Elasticsearch版本的大致对应关系:

  • ElasticsearchTemplate:ElasticsearchTemplate通常与早期版本的Elasticsearch(例如2.x系列和早期的5.x系列)一起使用。这种方式在早期的Spring Data Elasticsearch版本中是常见的。

  • ElasticsearchRepository:ElasticsearchRepository从Spring Data Elasticsearch 3.0版本开始引入,并且在较新的版本中也得到了支持。您可以在3.x版本和4.x版本的Spring Data Elasticsearch中使用ElasticsearchRepository。请注意,具体支持的特性和功能可能会因版本而异。

  • ElasticsearchRestTemplate:ElasticsearchRestTemplate是从Spring Data Elasticsearch 4.0版本开始引入的新特性。它基于Elasticsearch高级REST客户端,这个客户端本身也是从Elasticsearch 6.0版本开始引入的。因此,ElasticsearchRestTemplate主要用于较新版本的Elasticsearch(6.x及更高版本)。

Elasticsearch从6.x升级到7.x改动超级大,ElasticsearchTemplate不建议使用了,改为使用ElasticsearchRestTemplate,ElasticsearchRepository实现复杂查询的方法也不建议使用了。从此我们简单的数据操作可以使用ElasticsearchRepository,而复杂的数据操作只能使用ElasticsearchRestTemplate了。

因此,我们使用SpringBoot集成ES数据库的时候一般采用Elasticsearch 7.x及以上版本。

注意:这三种操作方式都需要集成Spring Data Elasticsearch依赖才能使用。

2、JavaAPI环境准备

新建Maven工程。

添加依赖:

<!-- elasticsearch 的客户端 -->
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.8.0</version>
</dependency><!--整合SpringData,版本是基于SpringBoot的版本来定义的-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

编写配置文件:

spring:application:name: service-search# ES服务地址elasticsearch:rest:# 集群使用逗号分开uris: http://10.11.24.200:9201,http://10.11.24.200:9202,http://10.11.24.200:9203username: elasticpassword: elastic

3、ElasticsearchRepository操作

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "person",createIndex = true)
public class Person implements Serializable {@Id@Field(type = FieldType.Auto)private String id;@Field(type = FieldType.Text,index = true)private String name;@Field(type = FieldType.Integer,index = true)private Integer age;@Field(type = FieldType.Keyword,index = true)private String sex;@Field(type = FieldType.Keyword,index = true)private String tel;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@Field(type = FieldType.Date, format = DateFormat.date_time, pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;
}

接口类:

public interface PersonRepository extends ElasticsearchRepository<Person,String> {}

操作类:

@SpringBootTest(classes = SpringBootApplicationMain.class)
public class ApplicationMainTest {@Resourceprivate PersonRepository personRepository;@Resourceprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Testpublic void test(){System.out.println(personRepository);System.out.println(elasticsearchRestTemplate);}@Testpublic void saveOne(){Person person = new Person();person.setId("1");person.setName("王天龙");person.setAge(30);person.setSex("man");person.setTel("1111111");person.setCreateTime(new Date());Person savePerson = personRepository.save(person);System.out.println(savePerson);}@Testpublic void saveAll(){List<Person> personList = new ArrayList<>(3);Person person2 = new Person();person2.setId("2");person2.setName("王天祥");person2.setAge(26);person2.setSex("男");person2.setTel("222222222222");person2.setCreateTime(new Date());personList.add(person2);Person person3 = new Person();person3.setId("3");person3.setName("王杰");person3.setAge(31);person3.setSex("女");person3.setTel("3333333333");person3.setCreateTime(new Date());personList.add(person3);personRepository.saveAll(personList);}}

3.1、简单操作的接口

在这里插入图片描述

3.2、复杂操作

您可以创建一个BookRepository接口继承自ElasticsearchRepository,并定义一些查询方法:

接口类:

public interface PersonRepository extends ElasticsearchRepository<Person,String> {List<Person> findByName(String name);List<Person> findByTel(String tel);List<Person> findByNameAndTel(String name, String tel);
}

在上面的示例中,PersonRepository继承自ElasticsearchRepository<Person, String>,其中Person是实体类,String是实体类的主键类型。然后,您定义了几个查询方法,如findByNamefindByTelfindByNameAndTel,这些方法的命名规则会被Spring Data Elasticsearch解析为相应的查询操作。

3.2.1、Spring Data JPA写法

Spring Data Elasticsearch能够自动解析您自定义的接口方法,将其转换为相应的Elasticsearch查询。它基于方法的命名规则来生成查询,这些规则与Spring Data JPA类似。以下是一些常见的规律:

  1. 方法名关键字:方法名以findByfindAllBycountBydeleteBy等开头,后面跟着实体属性名,例如findByTitlefindAllByAuthorcountByCategory等。

  2. 属性名和操作符:在方法名中,您可以使用属性名和操作符,如findByTitleAndAuthorfindByPriceGreaterThanfindByPublishedDateBetween等。

  3. 逻辑连接词:您可以在方法名中使用逻辑连接词来组合多个条件,如findByTitleAndAuthorfindByCategoryOrPrice等。

  4. 排序和分页:您可以通过在方法名中添加OrderByPageable来指定排序和分页条件,例如findByTitleOrderByPublishedDateDescfindByAuthorOrderByPriceAsc等。

  5. 限制查询结果数量:使用findFirstfindTop等关键字来限制返回的查询结果数量,例如findTop5ByCategoryfindFirstByAuthorOrderByPublishedDateDesc等。

  6. 使用自定义查询:如果您的需求超出了自动生成的查询,您可以使用@Query注解,在方法上指定自定义的Elasticsearch查询语句。

以下是一个示例,有一个实体类Person,您可以定义一个PersonRepository接口来操作Elasticsearch,并按照命名规则定义一些查询方法:

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List;public interface PersonRepository extends ElasticsearchRepository<Person, String> {List<Person> findByFirstName(String firstName);List<Person> findByLastNameAndAge(String lastName, int age);List<Person> findByAgeGreaterThan(int age);List<Person> findByFirstNameAndLastNameOrAge(String firstName, String lastName, int age);List<Person> findTop5ByAgeOrderByFirstNameAsc(int age);Person findFirstByLastNameOrderByAgeDesc(String lastName);
}

在上述示例中,每个方法名都遵循了Spring Data Elasticsearch的命名规则,可以自动生成相应的查询。如果您需要更复杂的查询,您还可以使用@Query注解来定义自定义的Elasticsearch查询语句。

3.2.2、@Query的写法

当使用Spring Data Elasticsearch中的@Query注解时,您可以自定义Elasticsearch的查询语句,以满足复杂的查询需求。以下是一个使用@Query的操作示例:

假设您有一个实体类Product表示产品信息:

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;@Document(indexName = "products")
public class Product {@Idprivate String id;private String name;private String category;private double price;// Getters and setters
}

然后,您可以创建一个ProductRepository接口,并使用@Query注解来定义自定义查询方法:

import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List;public interface ProductRepository extends ElasticsearchRepository<Product, String> {@Query("{\"bool\": {\"must\": [{\"match\": {\"name\": \"?0\"}}]}}")List<Product> findByNameCustom(String name);@Query("{\"bool\": {\"must\": [{\"term\": {\"category\": \"?0\"}}, {\"range\": {\"price\": {\"gte\": ?1}}}]}}")List<Product> findByCategoryAndPriceRange(String category, double minPrice);
}

在上述示例中,我定义了两个使用@Query注解的自定义查询方法:

  1. findByNameCustom:这个方法使用了Elasticsearch的查询语法,使用match查询来查找指定名称的产品。

  2. findByCategoryAndPriceRange:这个方法使用了更复杂的查询,结合了term查询和range查询,以查找特定类别中价格在指定范围内的产品。

您可以根据自己的需求编写更复杂的查询语句,利用Elasticsearch的强大查询能力来满足各种查询需求。使用@Query注解时,请确保查询语句的语法正确,并且根据实际情况调整查询条件和参数。

在使用Spring Data Elasticsearch的@Query注解中,?0表示方法参数中的第一个参数,?1表示第二个参数,依此类推。这样,您可以在查询语句中引用方法的参数值,以动态地构建查询条件。

4、ElasticsearchRestTemplate操作

4.1、熟悉查询条件的构造

当构建Elasticsearch查询时,QueryBuildersNativeSearchQueryBuilderNativeSearchQuery以及其他类型的Builders(如AggregationBuildersSortBuilders等)是Spring Data Elasticsearch提供的一些工具和类。它们之间的关系如下所示:

                         +----------------+|                ||   QueryBuilders|       |                |         +----------------+|| 组合和构建各种查询|v
+---------------------+       +-------------------------+
|                     |       |                         |
|NativeSearchQueryBuilder|<---|    NativeSearchQuery    |
|                     |       |                         |
+---------------------+       +-------------------------+|                            || 构建和配置查询条件            | 将查询条件传递给|                            | Elasticsearch操作v                            v
+---------------------+       +----------------------------+
|                     |       |  elasticsearchTemplate     |
|    AggregationBuilders|     |    或者                     |
|                     |       | elasticsearchRestTemplate  |
+---------------------+       +----------------------------+|                            || 构建聚合操作                 | 执行各种Elasticsearch操作|                            |v                            v+-----------------+            +-------------------+|                 |            |                   || SortBuilders    |            |       ...         ||                 |            |                   |+-----------------+            +-------------------+|                 ||    ...          ||                 |+-----------------+

(1)、关系1

QueryBuilderQueryBuilders是Elasticsearch Java客户端库提供的两个相关但不同的概念。

  1. QueryBuilder
    QueryBuilder是Elasticsearch Java客户端库中的接口,用于构建Elasticsearch查询。它提供了一种抽象方式来构建查询条件,可以用于构建各种类型的查询,如匹配、范围、布尔逻辑、嵌套查询等。QueryBuilder是一个用于构建查询对象的接口,您可以使用它来创建复杂的查询结构,然后传递给Elasticsearch客户端执行查询。

  2. QueryBuilders
    QueryBuilders是Elasticsearch Java客户端库中的一个工具类,用于创建不同类型的查询。它提供了一组静态方法,每个方法返回一个实现了QueryBuilder接口的查询对象,从而简化了构建查询的过程。通过使用QueryBuilders工具类,您可以直接调用方法来创建各种类型的查询,而无需手动创建QueryBuilder实例。

简而言之,QueryBuilder是一个接口,用于构建Elasticsearch查询对象,而QueryBuilders是一个工具类,用于创建实现了QueryBuilder接口的具体查询对象。您可以根据需要选择使用QueryBuilder接口来手动构建查询,或者使用QueryBuilders工具类来更方便地创建查询。

(2)、关系2

在Spring Data Elasticsearch中,NativeSearchQueryBuilderNativeSearchQuery是用于构建Elasticsearch查询条件的两个关键接口/类。它们之间的关系如下:

  1. NativeSearchQueryBuilderNativeSearchQueryBuilder是一个用于构建NativeSearchQuery的构造器类。它提供了一组方法,可以通过链式调用来配置和定制查询条件,例如添加过滤条件、排序、分页等。NativeSearchQueryBuilder最终会产生一个NativeSearchQuery实例,该实例表示一个完整的Elasticsearch查询。

  2. NativeSearchQueryNativeSearchQuery是用于表示Elasticsearch查询的接口。它包含了查询的各种组成部分,例如查询语句、过滤条件、排序规则、分页信息等。NativeSearchQuery可以被传递给Spring Data Elasticsearch的各种操作,例如查询、聚合等,以执行实际的Elasticsearch操作。

简而言之,NativeSearchQueryBuilder用于构建NativeSearchQuery,而NativeSearchQuery用于表示Elasticsearch查询,并作为参数传递给各种Spring Data Elasticsearch操作。

以下是一个简单的示例,演示如何使用NativeSearchQueryBuilder构建NativeSearchQuery

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;@Service
public class SearchService {private final ElasticsearchTemplate elasticsearchTemplate;@Autowiredpublic SearchService(ElasticsearchTemplate elasticsearchTemplate) {this.elasticsearchTemplate = elasticsearchTemplate;}public List<Product> searchProductsByCategoryAndPriceRange(String category, double minPrice) {NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("category", category)).withFilter(QueryBuilders.rangeQuery("price").gte(minPrice)).build();return elasticsearchTemplate.queryForList(query, Product.class);}
}

在上述示例中,NativeSearchQueryBuilder用于构建一个查询,该查询过滤出特定类别并且价格高于指定最低价格的产品。然后,通过elasticsearchTemplate执行查询操作。

总结:NativeSearchQueryBuilder用于创建NativeSearchQuery,后者用于表示Elasticsearch查询。这两者之间的关系可以看作是构建和执行查询的关系。

注:

NativeSearchQueryBuilder可以使用的方法:

在这里插入图片描述

4.2、具体代码的执行

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootApplicationMain.class)
public class ApplicationMainTest {@Resourceprivate PersonRepository personRepository;@Resourceprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Testpublic void test(){System.out.println(personRepository);System.out.println(elasticsearchRestTemplate);}

(1)创建索引

@Test
public void createIndex(){IndexCoordinates indexCoordinates = IndexCoordinates.of("person");IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);boolean created = indexOperations.create();System.out.println(created);
}

(2)设置mapping

@Test
public void setIndexMappings(){IndexCoordinates indexCoordinates = IndexCoordinates.of("person");IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);boolean created = indexOperations.putMapping(Person.class);System.out.println(created);
}

(3)设置settings

@Test
public void createIndexWithSetSettings(){IndexCoordinates indexCoordinates = IndexCoordinates.of("person");IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);Map<String,Object> settings = new HashMap<>();//----------------------------------------静态设置开始----------------------------------------------// 静态设置:只能在索引创建时或者在状态为 closed index(闭合的索引)上设置//主分片数,默认为5.只能在创建索引时设置,不能修改settings.put("index.number_of_shards",2);//是否应在索引打开前检查分片是否损坏,当检查到分片损坏将禁止分片被打开settings.put("index.shard.check_on_startup","false");//默认值//        settings.put("index.shard.check_on_startup","checksum");//检查物理损坏//        settings.put("index.shard.check_on_startup","true");//检查物理和逻辑损坏,这将消耗大量内存和CPU//        settings.put("index.shard.check_on_startup","fix");//检查物理和逻辑损坏。有损坏的分片将被集群自动删除,这可能导致数据丢失//自定义路由值可以转发的目的分片数。默认为 1,只能在索引创建时设置。此值必须小于index.number_of_shardssettings.put("index.routing_partition_size",1);//默认使用LZ4压缩方式存储数据,也可以设置为 best_compression,它使用 DEFLATE 方式以牺牲字段存储性能为代价来获得更高的压缩比例。settings.put("index.codec","best_compression");//----------------------------------------静态设置结束----------------------------------------------//----------------------------------------动态设置开始----------------------------------------------//每个主分片的副本数。默认为 1。settings.put("index.number_of_replicas",0);//基于可用节点的数量自动分配副本数量,默认为 false(即禁用此功能)settings.put("index.auto_expand_replicas",false);//执行刷新操作的频率,这使得索引的最近更改可以被搜索。默认为 1s。可以设置为 -1 以禁用刷新。settings.put("index.refresh_interval","1s");//用于索引搜索的 from+size 的最大值。默认为 10000settings.put("index.max_result_window",10000);// 在搜索此索引中 rescore 的 window_size 的最大值settings.put("index.max_rescore_window",10000);//设置为 true 使索引和索引元数据为只读,false 为允许写入和元数据更改。settings.put("index.blocks.read_only",false);// 设置为 true 可禁用对索引的读取操作settings.put("index.blocks.read",false);//设置为 true 可禁用对索引的写入操作。settings.put("index.blocks.write",false);// 设置为 true 可禁用索引元数据的读取和写入。settings.put("index.blocks.metadata",false);//索引的每个分片上可用的最大刷新侦听器数settings.put("index.max_refresh_listeners",1000);//----------------------------------------动态设置结束----------------------------------------------boolean created = indexOperations.create(settings);System.out.println(created);
}

(4)删除索引

@Test
public void deleteIndex(){IndexCoordinates indexCoordinates = IndexCoordinates.of("person");IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);boolean isDeleted = indexOperations.delete();System.out.println(isDeleted);
}

(5)更新某条数据

@Test
public void updateOne(){Document document = Document.create();document.setId("1");document.put("name","天龙战神");UpdateQuery.Builder builder = UpdateQuery.builder("1").withDocument(document).withScriptedUpsert(true);UpdateResponse updateResponse = elasticsearchRestTemplate.update(builder.build(), IndexCoordinates.of("person"));System.out.println(updateResponse.getResult());
}

(6)查询所有数据MatchAll

@Test
public void searchMatchAll() throws IOException {BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.getSearchHits().forEach(personSearchHit -> {Person content = personSearchHit.getContent();System.out.println(content);});
}

(7)BoolMust多条件查询

@Test
public void searchBoolMustWhere(){BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.must(QueryBuilders.matchQuery("name","王天龙"));boolQueryBuilder.must(QueryBuilders.matchQuery("age",30));NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.forEach(personSearchHit -> {System.out.println(personSearchHit.getContent());});
}

(8)BoolShould多条件查询

@Test
public void searchShouldWhere(){BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.should(QueryBuilders.matchQuery("name","天龙"));boolQueryBuilder.should(QueryBuilders.matchQuery("age",26));NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.forEach(personSearchHit -> {System.out.println(personSearchHit.getContent());});
}

(9)Range查询

@Test
public void searchRange(){BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gte(26).lt(31);boolQueryBuilder.filter(rangeQueryBuilder);NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.forEach(personSearchHit -> {System.out.println(personSearchHit.getContent());});
}

(10)聚合搜索1

/*** 聚合搜索* 聚合搜索,aggs,类似于group by,对age字段进行聚合,*/
@Test
public void aggregations1() {NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withAggregations(AggregationBuilders.terms("count").field("sex")).build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);//取出聚合结果ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();Aggregations aggregations = elasticsearchAggregations.aggregations();Terms terms = (Terms) aggregations.asMap().get("count");for (Terms.Bucket bucket : terms.getBuckets()) {String keyAsString = bucket.getKeyAsString();   // 聚合字段列的值long docCount = bucket.getDocCount();           // 聚合字段对应的数量System.out.println(keyAsString + " " + docCount);}
}

(11)聚合搜索2

@Test
public void aggregations2() {// 设置要聚合的字段TermsAggregationBuilder lyBucket = AggregationBuilders.terms("ly_bucket").field("firstTitleId.keyword").size(2^31-1);TermsAggregationBuilder tableBucket = AggregationBuilders.terms("table_bucket").field("tableId.keyword").size(2^31-1);// 指定聚合器中返回的文档数量,默认返回前3个tableBucket.subAggregation(AggregationBuilders.topHits("table_result").size(2^31-1).highlighter(highlightBuilder));// 合并子聚合lyBucket.subAggregation(tableBucket);// 构建查询对象NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();nativeSearchQueryBuilder.withQuery(queryBuilder);nativeSearchQueryBuilder.addAggregation(lyBucket);SearchHits<ContentEntity> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), ContentEntity.class);Aggregations aggregations = search.getAggregations();if (aggregations != null) {Terms lyBucket1 = aggregations.get("ly_bucket");List<? extends Terms.Bucket> lyBuckets = lyBucket1.getBuckets();for (Terms.Bucket lyBucket2 : lyBuckets) {Terms tableBucket1 = lyBucket2.getAggregations().get("table_bucket");List<? extends Terms.Bucket> tableBuckets = tableBucket1.getBuckets();for (Terms.Bucket table : tableBuckets) {TopHits topHits = table.getAggregations().get("table_result");org.elasticsearch.search.SearchHits hits = topHits.getHits();System.out.println(hits);}}}}
}

(12)分页实现

/*** 分页实现*/
@Test
public void searchWithPageable(){BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)//分页实现 可以传递活值在PageRequest.of(0,2)里面.withPageable(PageRequest.of(0,2));NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.getSearchHits().forEach(personSearchHit -> {Person content = personSearchHit.getContent();System.out.println(content);});
}

(13)排序实现

/*** 排序实现*/
@Test
public void searchWithSort(){BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)//分页实现.withPageable(PageRequest.of(0,10))//排序.withSorts(SortBuilders.fieldSort("createTime").order(SortOrder.DESC),SortBuilders.fieldSort("age").order(SortOrder.DESC));NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);searchHits.getSearchHits().forEach(personSearchHit -> {Person content = personSearchHit.getContent();System.out.println(content);});
}
}

4.3、高亮操作

详情查看该网址:https://www.cnblogs.com/eternityz/p/17039582.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/117902.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【100天精通Python】Day52:Python 数据分析_Numpy入门基础与数组操作

目录 1 NumPy 基础概述 1.1 NumPy的主要特点和功能 1.2 NumPy 安装和导入 2 Numpy 数组 2.1 创建NumPy数组 2.2 数组的形状和维度 2.3 数组的数据类型 2.4 访问和修改数组元素 3 数组操作 3.1 数组运算 3.2 数学函数 3.3 统计函数 4 数组形状操作 4.1 重塑数组形…

nvm安装electron开发与编译环境

electron总是安装失败&#xff0c;下面说一下配置办法 下载软件 nvm npmmirror 镜像站 安装nvm 首先最好卸载node&#xff0c;不卸载的话&#xff0c;安装nvm会提示是否由其接管&#xff0c;保险起见还是卸载 下载win中的安装包 配置加速节点nvm node_mirror https://npmmi…

Java 中数据结构LinkedList的用法

LinkList 链表&#xff08;Linked list&#xff09;是一种常见的基础数据结构&#xff0c;是一种线性表&#xff0c;但是并不会按线性的顺序存储数据&#xff0c;而是在每一个节点里存到下一个节点的地址。 链表可分为单向链表和双向链表。 一个单向链表包含两个值: 当前节点…

PATH系统环境变量配置教程【图文步骤】

开发Java程序&#xff0c;需要使用JDK提供的开发工具(比如javac.exe、java.exe等命令)&#xff0c;而这些工具在JDK的安装目录的 bin目录下&#xff0c;如果不配置环境变量&#xff0c;那么这些命令只可以在该目录下执行。我们不可能把所有的java文件都放到JDK 的bin目录下&…

​7.3 项目3 贪吃蛇(控制台版) (A)​

C自学精简实践教程 目录(必读) 主要考察 模块划分 / 文本文件读取 UI与业务分离 / 模块划分 控制台交互 / 数据抽象 需求 用户输入字母表示方向&#xff0c;实现贪吃蛇游戏 规则&#xff1a;碰到边缘和碰到蛇自己都算游戏结束 输入文件 data.txt data.txt 内容如下&am…

MySQL数据库备份及恢复

数据备份的重要性 1、备份的主要目的是灾难恢复 2、在生产环境中&#xff0c;数据的安全性至关重要 3、任何数据的丢失都可能产生严重的后果 4、造成数据丢失的原因 备份类型(重点) 1、物理备份 数据库备份可以分为物理备份和逻辑备份。物理备份是对数据库操作系统的物…

kafka详解一

kafka详解一 1、消息引擎背景 根据维基百科的定义&#xff0c;消息引擎系统是一组规范。企业利用这组规范在不同系统之间传递语义准确的消息&#xff0c;实现松耦合的异步式数据传递. 即&#xff1a;系统 A 发送消息给消息引擎系统&#xff0c;系统 B 从消息引擎系统中读取 A…

城市白模三维重建

收费工具&#xff0c;学生党勿扰&#xff0c;闹眼子当勿扰 收费金额&#xff1a;2000元&#xff0c;不能开发票 1 概述 几个月前&#xff0c;一家小公司找我帮忙给他们开发一个程序&#xff0c;可以将一个城市进行白模的三维重建。 报酬大约5K。经过不懈的努力&#xff0c;终于…

分布式集群——搭建Hadoop环境以及相关的Hadoop介绍

系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 前言 一 hadoop的相关概念 1.1 Hadoop概念 补充&#xff1a;块的存储 1.2 HDFS是什么 1.3 三种节点的功能 I、NameNode节点 II、fsimage与edits…

国产工业软件的挑战与机遇:风口是否还在燃烧?

随着智能制造与数字化转型等新型工业理念的推广&#xff0c;工业软件在工业领域中的地位日益重要。在这个过程中&#xff0c;国产工业软件也迎来了新的发展机遇。然而&#xff0c;对于国产工业软件而言&#xff0c;是否存在着发展的“风口”&#xff1f;今天&#xff0c;我们将…

【C++技能树】继承概念与解析

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法&#xff0c;Linux与ROS…感兴趣就关注我bua&#xff01; 继承 0. 继承概念0.1 继承访问限定符 1. 基类和派生类对象赋值兼容转换2. 继承中的作用域3. 派生类中的默认成员函数4.友元5.继承中的静态成员6.菱…

如何飞速成为开源贡献者(Contributor)

如何飞速成为开源贡献者Contributor 一、环境信息1.1 硬件信息1.2 软件信息 二、Git安装2.1 Git介绍2.2 Git下载安装 三、开源项目选定四、GitHub参与开源流程4.1 Fork项目4.2 SSH配置4.2.1 为什么要配置SSH4.2.2 如何配置SSH 4.3 Clone项目4.4 IDEA关联4.5 PR生成4.6 PR提交 一…

STM32f103入门(9)编码器接口测速

TIM3 PA6 PA7 上拉输入 原理上也是PWM捕获输入 捕获两个输入 我们用中断处理读取CNT的值 读取完将CNT置0 这样我们就得到了旋转编码器的速度/s 中断配置代码 #include "stm32f10x.h" // Device headervoid Timer_Init(void) {RCC_APB1PeriphClockC…

SWAT-MODFLOW地表水与地下水耦合

耦合模型被应用到很多科学和工程领域来改善模型的性能、效率和结果&#xff0c;SWAT作为一个地表水模型可以较好的模拟主要的水文过程&#xff0c;包括地表径流、降水、蒸发、风速、温度、渗流、侧向径流等&#xff0c;但是对于地下水部分的模拟相对粗糙&#xff0c;考虑到SWAT…

com.google.guava:guava 组件安全漏洞及健康分析

组件简介 维护者google组织许可证类型Apache-2.0首次发布2010 年 4 月 26 日最新发布时间2023 年 8 月 1 日GitHub Star48189GitHub Fork10716依赖包28,694依赖存储库219,576 Guava 是 Google 的一组核心 Java 库&#xff0c;其中包括新的集合类型&#xff08;例如 multimap 和…

Web安全——穷举爆破上篇(仅供学习)

Web安全 一、概述二、常见的服务1、burpsuite 穷举后台密码2、burpsuite 对 webshell 穷举破解密码3、有 token 防御的网站后台穷举破解密码3.1 burpsuite 设置宏获取 token 对网站后台密码破解3.2 编写脚本获取token 对网站后台密码破解 4、针对有验证码后台的穷举方法4.1 coo…

ElasticSearch安装为Win11服务

在windows的环境下操作是Elasticsearch,并且喜欢使用命令行 &#xff0c;启动时通过cmd直接在elasticsearch的bin目录下执行elasticsearch ,这样直接启动的话集群名称会默elasticsearch&#xff0c;节点名称会随机生成。 停止就直接在cmd界面按CtrlC 其实我们也可以将elasticse…

一篇文章教会你什么是二叉搜索树

二叉搜索树 二叉搜索树概念二叉搜索树操作1.二叉搜索树的查找2.二叉搜索树的插入3.二叉搜索树的删除4.二叉搜索树的遍历 二叉搜索树的实现1.二叉搜索树节点结构2.二叉搜索树类3.二叉搜索树的构造及析构4.二叉搜索树的拷贝构造及赋值重载5.二叉搜索树插入6.二叉搜索树查找7.二叉…

必读干货!独立站新手卖家常见十大问题解答

新手卖家入局跨境电商独立站&#xff0c;会考虑到很多问题&#xff0c;从网站到产品再到售卖最终的发货。而且卖家普遍对独立站存在认知不全的问题&#xff0c;门槛高、推广难、转化难是最初印象。 那独立站该怎么开始&#xff0c;如何下手&#xff1f;今天整理并解答独立站新…

数据结构--树4.2.2(二叉树--遍历)

目录 一、二叉树的建立 二、二叉树的遍历算法 一、二叉树的建立 CreateBitree(Bitree *t){char c;scanf("%c",&c);if( c){*t NULL;}else{*t(Bitnode*)malloc(sizeof(Bitnode));(*t)->data c;CreateBitree(&(*t)->lchild);CreateBitree(&(*t)-&…