基础命令
查看索引列表
GET /_cat/indices?v=true&pretty
查看分片情况
GET /_cat/shards?v=true&pretty
创建索引(Create Index)
PUT /<index_name>
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
查看索引是否存在( 结果是200 和 404)
HEAD /<index_name>
获取索引(Get Index)
GET /<index_name>
更新索引设置(Update Index Settings)
PUT /<index_name>/_settings
{
"settings": {
"number_of_replicas": 2
}
}
删除索引(Delete Index)
DELETE /<index_name>
Document核心操作
查询文档
GET /<index_name>/_doc/1
新增文档(需要指定ID)
PUT /<index_name>/_doc/1
{
"id":5555,
"title":"ES索引",
"pv":144
}
新增文档(不指定ID或者指定ID都可以),会自动生成id
POST /<index_name>/_doc
{
"id":123,
"title":"ES索引",
"pv":244
}
修改(put和post都行,需要指定id)
PUT /<index_name>/_doc/1
{
"id":999,
"title":"ES索引v2",
"pv":999,
"uv":55
}
POST /<index_name>/_doc/1
{
"id":999,
"title":"ES索引v3",
"pv":999,
"uv":559
}
搜索
GET /<index_name>/_search
字段解释
took字段表示该操作的耗时(单位为毫秒)。
timed_out字段表示是否超时。
hits字段表示搜到的记录,数组形式。
total:返回记录数,本例是1条。
max_score:最高的匹配程度,本例是1.0
删除数据
DELETE /<index_name>/_doc/1
Mapping和常见字段类型
Dynamic Mapping(动态映射)
用于在索引文档时自动检测和定义字段的数据类型
当我们向索引中添加新文档时,Elasticsearch会自动检测文档中的各个字段,并根据它们的值来尝试推断字段类型
常见的字段类型包括文本(text)、关键词(keyword)、日期(date)、数值(numeric)等
动态映射具备自动解析和创建字段的便利性,但在某些情况下,由于字段类型的不确定性,动态映射可能会带来一些问题
例如字段解析错误、字段类型不一致等,如果对字段类型有明确的要求,最好在索引创建前通过显式映射定义来指定字段类型
ElasticSearch常见的数据类型
在 ES 7.X后有两种字符串类型:Text 和 Keyword
-
Text类型:用于全文搜索的字符串类型,支持分词和索引建立
-
Keyword类型:用于精确匹配的字符串类型,不进行分词,适合用作过滤和聚合操作。
Numeric类型:包括整数类型(long、integer、short、byte)和浮点数类型(double、float)。
Date类型:用于存储日期和时间的类型。
Boolean类型:用于存储布尔值(true或false)的类型。
Binary类型:用于存储二进制数据的类型。
Array类型:用于存储数组或列表数据的类型。
Object类型:用于存储复杂结构数据的类型
最高频使用的数据类型
text字段类型
-
text类型主要用于全文本搜索,适合存储需要进行全文本分词的文本内容,如文章、新闻等。
-
text字段会对文本内容进行分词处理,将文本拆分成独立的词项(tokens)进行索引
-
分词的结果会建立倒排索引,使搜索更加灵活和高效。
-
text字段在搜索时会根据分词结果进行匹配,并计算相关性得分,以便返回最佳匹配的结果。
keyword字段类型
-
keyword类型主要用于精确匹配和聚合操作,适合存储不需要分词的精确值,如ID、标签、关键字等。
-
keyword字段不会进行分词处理,而是将整个字段作为一个整体进行索引和搜索
-
这使得搜索只能从精确的值进行匹配,而不能根据词项对内容进行模糊检索。
-
keyword字段适合用于过滤和精确匹配,同时可以进行快速的基于精确值的聚合操作。
总结
-
在选择text字段类型和keyword字段类型时,需要根据具体的需求进行权衡和选择:
-
如果需要进行全文本检索,并且希望根据分词结果计算相关性得分,以获得最佳的匹配结果,则选择text字段类型。
-
如果需要进行精确匹配、排序或聚合操作,并且不需要对内容进行分词,则选择keyword字段类型
查看索引库的字段类型
GET /<index_name>/_mapping
指定索引库字段类型mapping
PUT /<index_name>
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "text"
},
"price": {
"type": "float"
}
}
}
}
查询匹配关键词的文档一
GET /<index_name>/_search
{
"query": {
"match": {
"title": "Elasticsearch"
}
}
}
查询匹配关键词的文档二
GET /<index_name>/_search
{
"query": {
"match": {
"tags": "data"
}
}
}
分词器相关
查看分词效果
- 使用
analyzeAPI 来对文本进行分词处理并查看分词结果,基本语法如下
GET /_analyze
{
"analyzer": "分词器名称",
"text": "待分析的文本"
}
案例
#字段是text类型
POST /<index_name>/_analyze
{
"field": "title",
"text": "This is some text to analyze"
}
#字段是text类型
POST /<index_name>/_analyze
{
"field": "title",
"text": ""This is some text to analyze"
}
每个分词结果对象包含
分词后的单词(token)
开始位置(start_offset)
结束位置(end_offset)
类型(type)
-
ALPHANUM是一种数据类型,表示一个字符串字段只包含字母和数字,并且不会进行任何其他的分词或处理
-
它会忽略字段中的任何非字母数字字符(如标点符号、空格等),只保留字母和数字字符
单词在原始文本中的位置(position)
查询DSL语法
基本语法
GET /索引库名/_search
{
"query":{
"查询类型":{
}
}
常见Query DSL查询语句和功能
match 查询:用于执行全文搜索,它会将搜索查询与指定字段中的文本进行匹配
match,对查询内容进行分词, 然后进行查询,多个词条之间是 **or的关系 **
然后在与文档里面的分词进行匹配,匹配度越高分数越高越前面
{
"query": {
"match": {
"title": "elasticsearch"
}
}
}
match高级用法之多字段匹配和短语搜索实战
业务查询,需要在多个字段上进行文本搜索,用 multi_match
在 match的基础上支持对多个字段进行文本查询匹配
语法格式
GET /<index_name>/_search
{
"query": {
"multi_match": {
"query": "要搜索的文本",
"fields": ["字段1", "字段2", ...]
}
}
}
# query:需要匹配的查询文本。
# fields:一个包含需要进行匹配的字段列表的数组。
短语搜索匹配
是Elasticsearch中提供的一种高级匹配查询类型,用于执行精确的短语搜索
相比于match查询,match_phrase会在匹配时考虑到单词之间的顺序和位置
语法格式
GET /<index_name>/_search
{
"query": {
"match_phrase": {
"field_name": {
"query": "要搜索的短语"
}
}
}
}
# field_name:要进行匹配的字段名。
# query:要搜索的短语。
term 查询:用于精确匹配一个指定字段的关键词,不进行分词处理。
term查询,不会将查询条件分词,直接与文档里面的分词进行匹配
虽然match也可以完成,但是match查询会多一步进行分词,浪费资源
{
"query": {
"term": {
"category": "books"
}
}
}
- 查询全部数据(match_all):是一种简单的查询,匹配索引中的所有文档
GET /<index_name>/_search
{
"query": {
"match_all": {}
}
}
获取指定字段
某些情况场景下,不需要返回全部字段,太废资源,可以指定source返回对应的字段
GET /<index_name>/_search
{
"_source":["price","title"],
"query": {
"term": {
"title": {
"value": "Spring Boot"
}
}
}
}
总结
match在匹配时会对所查找的关键词进行分词,然后分词匹配查找;term会直接对关键词进行查找
一般业务里面需要模糊查找的时候,更多选择match,而精确查找时选择term查询
范围查询
range查询
用于根据范围条件进行查询,例如指定价格在一定区间内的商品
范围符号
-
gte:大于等于
-
gt:大于
-
lte:小于等于
-
lt:小于
GET /<index_name>/_search
{
"query": {
"range": {
"price": {
"gte": 5,
"lte": 100
}
}
}
}
分页查询
可以使用 from 和 size 参数进行分页查询
可以指定要跳过的文档数量(from)和需要返回的文档数量(size)
GET /<index_name>/_search
{
"size": 10,
"from": 0,
"query": {
"match_all": {}
}
}
查询结果排序
sort字段可以进行排序 desc 和 asc
GET /<index_name>/_search
{
"size": 10,
"from": 0,
"sort": [
{
"price": "asc"
}
],
"query": {
"match_all": {}
}
}
bool查询
通过组合多个查询条件,使用布尔逻辑(与、或、非)进行复杂的查询操作
语法格式
-
“must“关键字用于指定必须匹配的条件,即所有条件都必须满足
-
“must_not“关键字指定必须不匹配的条件,即所有条件都不能满足
-
“should“关键字指定可选的匹配条件,即至少满足一个条件
{
"query": {
"bool": {
"must": [
// 必须匹配的条件
],
"must_not": [
// 必须不匹配的条件
],
"should": [
// 可选匹配的条件
],
"filter": [
// 过滤条件
]
}
}
}
案例
GET /<index_name>/_search
{
"query": {
"bool": {
"must": [
{ "match": { "summary": "Cloud" }},
{ "range": { "price": { "gte": 5 }}}
]
}
}
}
**
filter**查询
来对搜索结果进行筛选和过滤,仅返回符合特定条件的文档,而不改变搜索评分
Filter查询对结果进行缓存,提高查询性能,用于数字范围、日期范围、布尔逻辑、存在性检查等各种过滤操作。
语法格式
-
“filter"关键字用于指定一个过滤条件,可以是一个具体的过滤器,如term、range等,也可以是一个嵌套的bool过滤器
{
"query": {
"bool": {
"filter": {
// 过滤条件
}
}
}
}
案例一 :使用 term 过滤器查询 category 为 books 的产品:
GET /<index_name>/_search
{
"query": {
"bool": {
"filter": {
"term": {
"category": "books"
}
}
}
}
}
案例二:使用 range 过滤器查询价格 price 在 30 到 50 之间的产品:
GET /<index_name>/_search
{
"query": {
"bool": {
"filter": {
"range": {
"price": {
"gte": 30,
"lte": 50
}
}
}
}
}
}
总结
过滤条件通常用于对结果进行筛选,并且比查询条件更高效
而bool查询可以根据具体需求组合多个条件、过滤器和查询子句
日常单词拼写错误-fuzzy模糊查询案例实战
fuzzy查询是Elasticsearch中提供的一种模糊匹配查询类型,用在搜索时容忍一些拼写错误或近似匹配
使用fuzzy查询,可以根据指定的编辑距离(即词之间不同字符的数量)来模糊匹配查询词
拓展:编辑距离
-
是将一个术语转换为另一个术语所需的一个字符更改的次数。
-
比如
-
更改字符(box→fox)
-
删除字符(black→lack)
-
插入字符(sic→sick)
-
转置两个相邻字符(dgo→dog)
fuzzy模糊查询是拼写错误的简单解决方案,但具有很高的 CPU 开销和非常低的精准度
用法和match基本一致,Fuzzy query的查询不分词
基本语法格式
GET /<index_name>/_search
{
"query": {
"fuzzy": {
"field_name": {
"value": "要搜索的词",
"fuzziness": "模糊度"
}
}
}
}
解析
-
field_name:要进行模糊匹配的字段名。
-
value:要搜索的词
-
fuzziness参数指定了模糊度,常见值如下
-
0,1,2
-
指定数字,表示允许的最大编辑距离,较低的数字表示更严格的匹配,较高的数字表示更松散的匹配
-
fuziness的值,表示是针对每个词语而言的,而不是总的错误的数值
-
AUTO:Elasticsearch根据词的长度自动选择模糊度
-
如果字符串的长度大于5,那 funziness 的值自动设置为2
-
如果字符串的长度小于2,那么 fuziness 的值自动设置为 0
高亮显示多案例
在 ES 中,高亮语法用于在搜索结果中突出显示与查询匹配的关键词
高亮显示是通过标签包裹匹配的文本来实现的,通常是 <em> 或其他 HTML 标签
基本用法:在 highlight 里面填写要高亮显示的字段,可以填写多个
单条件查询高亮显示
GET /<index_name>/_search
{
"query": {
"match": {
"content": "电影"
}
},
"highlight": {
"fields": {
"content": {}
}
}
}
组合多条件查询,highlight里面填写需要高亮的字段
GET /<index_name>/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "课堂"
}
},
{
"match": {
"content": "老王"
}
}
]
}
},
"highlight": {
"fields": {
"title": {},
"content": {}
}
}
}
match查询,使用highlight属性,可以增加属性,修改高亮样式
-
pre_tags:前置标签
-
post_tags:后置标签
-
fields:需要高亮的字段
GET /<index_name>/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "张三"
}
},
{
"match": {
"content": "老王"
}
}
]
}
},
"highlight": {
"pre_tags": "<font color='yellow'>",
"post_tags": "</font>",
"fields": [{"title":{}},{"content":{}}]
}
}
搜索聚合查询(报表类搜索)
什么是聚合查询
对大量数据聚合统计处理,类似Mysql数据库操作里面的group by 分组、sum、avg、max等函数处理
是 Elasticsearch 中强大的功能之一,根据数据进行分组、过滤、计算和统计,提取有关数据集信息,进行数据分析
数据可视化大屏里面的饼状图、柱状图、折线图、仪表盘数据等都是聚合查询的关键应用

术语一:对数据集求最大、最小、和、平均值等指标的聚合,称为 指标聚合 metric
基本语法格式如下
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"aggregation_name": {
"aggregation_type": {
"aggregation_field": "field_name"
// 可选参数
}
}
// 可以添加更多的聚合
}
}
# 解析
index:要执行聚合查询的索引名称。
size: 设置为 0 来仅返回聚合结果,而不返回实际的搜索结果,这里将hits改为0表示返回的原始数据变为0
aggs:指定聚合操作的容器。
aggregation_name:聚合名称,可以自定义。
aggregation_type:聚合操作的类型,例如 terms、avg、sum 等。
aggregation_field:聚合操作的目标字段,对哪些字段进行聚合
术语二:对数据集进行分组group by,然后在组上进行指标聚合,在 ES 中称为分桶,桶聚合bucketing
- 基本语法格式如下
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"aggregation_name": {
"bucket_type": {
"bucket_options": {
"bucket_option_name": "bucket_option_value",
...
},
"aggs": {
"sub_aggregation_name": {
"sub_aggregation_type": {
"sub_aggregation_options": {
"sub_aggregation_option_name": "sub_aggregation_option_value",
...
}
}
}
}
}
}
}
}
#解析
index: 替换为要执行聚合查询的索引名称。
aggregation_name: 替换为自定义的聚合名称。
bucket_type: 替换为特定的桶聚合类型(如 terms、date_histogram、range 等)。
bucket_option_name 和 bucket_option_value: 替换为特定桶聚合选项的名称和值。
sub_aggregation_name: 替换为子聚合的名称。
sub_aggregation_type: 替换为特定的子聚合类型(如 sum、avg、max、min 等)。
sub_aggregation_option_name 和 sub_aggregation_option_value: 替换为特定子聚合选项的名称和值
常见聚合用途和应用场景案例
聚合指标(Aggregation Metrics):
Avg Aggregation:计算文档字段的平均值。
Sum Aggregation:计算文档字段的总和。
Min Aggregation:找到文档字段的最小值。
Max Aggregation:找到文档字段的最大值。
聚合桶(Aggregation Buckets):
Terms Aggregation:基于字段值将文档分组到不同的桶中。
Date Histogram Aggregation:按日期/时间字段创建时间间隔的桶。
Range Aggregation:根据字段值的范围创建桶。
嵌套聚合(Nested Aggregations)、聚合过滤(Aggregation Filtering)
- 案例
-- 创建索引
PUT /sales
{
"mappings": {
"properties": {
"product": {
"type": "keyword"
},
"sales": {
"type": "integer"
}
}
}
}
-- 批量插入数据
POST /sales/_bulk
{"index": {}}
{"product": "iPhone", "sales": 4}
{"index": {}}
{"product": "Samsung", "sales": 60}
{"index": {}}
{"product": "iPhone", "sales": 100}
{"index": {}}
{"product": "Samsung", "sales": 80}
{"index": {}}
-- 执行聚合查询:分别按照商品名称(product)进行分组
GET /sales/_search
{
"aggs":{//聚合操作
"product_group":{//名称,随意起名
"terms":{//分组
"field":"product"//分组字段
}
}
}
}
计算每组的销售总量,使用了 terms 聚合和 sum 聚合来实现
查询结果将返回每个产品的名称和销售总量
GET /sales/_search
{
"size": 0,
"aggs": {
"product_sales": {
"terms": {
"field": "product"
},
"aggs": {
"total_sales": {
"sum": {
"field": "sales"
}
}
}
}
}
}
什么是指标聚合
对数据集求最大、最小、和、平均值等指标的聚合,称为 **指标聚合 metric **
比如 max、min、avg、sum等函数使用
聚合查询
max应用案例:- 案例说明:使用
max聚合查询来获取产品价格的最高值
- 案例说明:使用
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"max_price": {
"max": {
"field": "price"
}
}
}
}
聚合查询 -
min应用案例:
案例说明:使用 min 聚合查询来获取学生的最低考试分数
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"min_score": {
"min": {
"field": "score"
}
}
}
}
聚合查询 -
avg应用案例:- 案例说明:使用
sum聚合查询来计算销售记录的总销售数量。
- 案例说明:使用
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"total_sales": {
"sum": {
"field": "sales_count"
}
}
}
}
桶聚合语法和Terms案例实战
什么桶bucket聚合
对数据集进行分组group by,然后在组上进行指标聚合,在 ES 中称为分桶,桶聚合bucketing
基本语法格式如下
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"aggregation_name": {
"bucket_type": {
"bucket_options": {
"bucket_option_name": "bucket_option_value",
...
},
"aggs": {
"sub_aggregation_name": {
"sub_aggregation_type": {
"sub_aggregation_options": {
"sub_aggregation_option_name": "sub_aggregation_option_value",
...
}
}
}
}
}
}
}
}
#解析
index: 替换为要执行聚合查询的索引名称。
aggregation_name: 替换为自定义的聚合名称。
bucket_type: 替换为特定的桶聚合类型(如 terms、date_histogram、range 等)。
bucket_option_name 和 bucket_option_value: 替换为特定桶聚合选项的名称和值。
sub_aggregation_name: 替换为子聚合的名称。
sub_aggregation_type: 替换为特定的子聚合类型(如 sum、avg、max、min 等)。
sub_aggregation_option_name 和 sub_aggregation_option_value: 替换为特定子聚合选项的名称和值
案例说明:使用 terms 聚合查询将图书按销售数量进行分桶,并获取每个分桶内的销售数量总和。
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"book_buckets": {
"terms": {
"field": "book_title",
"size": 10
},
"aggs": {
"total_sales": {
"sum": {
"field": "sales_count"
}
}
}
}
}
}
桶聚合Date Histogram介绍和案例实战
分桶聚合查询 - Date Histogram
将日期类型的字段按照固定的时间间隔进行分桶,并对每个时间间隔内的文档进行进一步的操作和计算
基本语法如下
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"date_histogram_name": {
"date_histogram": {
"field": "date_field_name",
"interval": "interval_expression"
},
"aggs": {
"sub_aggregation": {
"sub_aggregation_type": {}
}
}
}
}
}
#解析
index:替换为要执行聚合查询的索引名称。
date_histogram_name:替换为自定义的 date_histogram 聚合名称。
date_field_name:替换为要聚合的日期类型字段名。
interval_expression:指定用于分桶的时间间隔。时间间隔可以是一个有效的日期格式(如 1d、1w、1M),也可以是一个数字加上一个时间单位的组合(如 7d 表示 7 天,1h 表示 1 小时)。
sub_aggregation:指定在每个日期桶内进行的子聚合操作。
sub_aggregation_type:替换单独子聚合操作的类型,可以是任何有效的子聚合类型。
案例说明:使用 date_histogram 聚合查询将订单按日期进行分桶,并计算每个分桶内的订单金额总和。
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"sales_per_month": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month",
"format": "yyyy-MM"
},
"aggs": {
"total_sales": {
"sum": {
"field": "amount"
}
}
}
}
}
}
桶聚合Range介绍和案例实战
分桶聚合查询 - Range
将字段的值划分为不同的范围,并将每个范围内的文档分配给相应的桶,对这些范围进行各种操作和计算。
语法介绍
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"range_name": {
"range": {
"field": "field_name",
"ranges": [
{ "key": "range_key_1", "from": from_value_1, "to": to_value_1 },
{ "key": "range_key_2", "from": from_value_2, "to": to_value_2 },
...
]
},
"aggs": {
"sub_aggregation": {
"sub_aggregation_type": {}
}
}
}
}
}
#解析
index:替换为要执行聚合查询的索引名称。
range_name:替换为自定义的 range 聚合名称。
field_name:替换为要聚合的字段名。
ranges:指定范围数组,每个范围使用 key、from 和 to 参数进行定义。
key:范围的唯一标识符。
from:范围的起始值(包含)。
to:范围的结束值(不包含)。
sub_aggregation:指定在每个范围内进行的子聚合操作。
sub_aggregation_type:替换单独子聚合操作的类型,可以是任何有效的子聚合类型。
案例说明:使用 range 聚合查询将商品按价格范围进行分桶,并计算每个分桶内的商品数量。
如果没写key,则会默认生成
GET /<index_name>/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 200 },
{ "from": 200 }
]
}
}
}
}
SpringBoot整合ES
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置文件
# 添加配置
spring.elasticsearch.uris=http://112.74.167.42:9200
什么是ElasticsearchTemplate
是 Spring Data Elasticsearch 提供的一个核心类,是 ElasticsearchClient 的一个具体实现
用于在 Spring Boot 中操作 Elasticsearch 进行数据的存取和查询
提供了一组方法来执行各种操作,如保存、更新、删除和查询文档,执行聚合操作等
ElasticsearchTemplate 的一些常用方法
save(Object): 保存一个对象到 Elasticsearch 中。
index(IndexQuery): 使用 IndexQuery 对象执行索引操作。
delete(String, String): 删除指定索引和类型的文档。
get(String, String): 获取指定索引和类型的文档。
update(UpdateQuery): 使用 UpdateQuery 对象执行更新操作。
search(SearchQuery, Class): 执行搜索查询,并将结果映射为指定类型的对象。
count(SearchQuery, Class): 执行搜索查询,并返回结果的计数
ElasticsearchTemplate 常见注解配置(都是属于spring data elasticsearch)
@Id 指定主键
@Document指定实体类和索引对应关系
indexName:索引名称
- @Field指定普通属性
type 对应Elasticsearch中属性类型,使用FiledType枚举快速获取。
text 类型能被分词
keywords 不能被分词
index 是否创建索引,作为搜索条件时index必须为true
analyzer 指定分词器类型。
案例实战
创建DTO
@Document(indexName = "video")
public class VideoDTO {
@Id
@Field(type = FieldType.Text, index = false)
private Long id;
@Field(type = FieldType.Text)
private String title;
@Field(type = FieldType.Text)
private String description;
@Field(type = FieldType.Keyword)
private String category;
@Field(type = FieldType.Integer)
private Integer duration;
@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
private LocalDateTime createTime;
public VideoDTO(){}
public VideoDTO(Long id, String title, String description, Integer duration,String category) {
this.id = id;
this.title = title;
this.description = description;
this.duration = duration;
this.createTime = LocalDateTime.now();
this.category = category;
}
}
单元测试
@Autowired
private ElasticsearchTemplate restTemplate;
/**
* 判断索引是否存在索引
*/
@Test
void existsIndex() {
IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class);
boolean exists = indexOperations.exists();
System.out.println(exists);
}
/**
* 创建索引
*/
@Test
void createIndex() {
// spring data es所有索引操作都在这个接口
IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class);
// 是否存在,存在则删除
if(indexOperations.exists()){
indexOperations.delete();
}
// 创建索引
indexOperations.create();
//设置映射: 在正式开发中,几乎不会使用框架创建索引或设置映射,这是架构或者管理员的工作,不适合使用代码实现
restTemplate.indexOps(VideoDTO.class).putMapping();
}
/**
* 删除索引
*/
@Test
void deleteIndex() {
IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class);
boolean delete = indexOperations.delete();
System.out.println(delete);
}
CRUD操作
@Test
void insert(){
VideoDTO videoDTO = new VideoDTO();
videoDTO.setId(1L);
VideoDTO saved = restTemplate.save(videoDTO);
System.out.println(saved);
}
@Test
void update(){
VideoDTO videoDTO = new VideoDTO();
videoDTO.setId(1L);
VideoDTO saved = restTemplate.save(videoDTO);
System.out.println(saved);
}
@Test
void batchInsert() {
List<VideoDTO> list = new ArrayList<>();
Iterable<VideoDTO> result = restTemplate.save(list);
System.out.println(result);
}
@Test
void searchById(){
VideoDTO videoDTO = restTemplate.get("3", VideoDTO.class);
assert videoDTO != null;
System.out.println(videoDTO);
}
@Test
void deleteById() {
String delete = restTemplate.delete("2", VideoDTO.class);
System.out.println(delete);
}
其他多案例搜索
Query是Spring Data Elasticsearch的接口,有多种具体实现
CriteriaQuery
创建Criteria来搜索数据,而无需了解 Elasticsearch 查询的语法或基础知识
允许用户通过简单地连接和组合,指定搜索文档必须满足的对象来构建查询
StringQuery
将Elasticsearch查询作为JSON字符串,更适合对Elasticsearch查询的语法比较了解的人
也更方便使用kibana或postman等客户端工具行进调试
NativeQuery
复杂查询或无法使用CriteriaAPI 表达的查询时使用的类,例如在构建查询和使用聚合的场景
案例一:搜索全部
/**
* 查询所有
*/
@Test
void searchAll(){
SearchHits<VideoDTO> search = restTemplate.search(Query.findAll(), VideoDTO.class);
List<SearchHit<VideoDTO>> searchHits = search.getSearchHits();
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
案例二:匹配搜索
/**
* match查询
*/
@Test
void matchQuery(){
Query query = NativeQuery.builder().withQuery(q -> q
.match(m -> m
.field("description") //字段
.query("spring") //值
)).build();
SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class);
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
案例三:分页搜索
/**
* 分页查询
*/
@Test
void pageSearch() {
Query query = NativeQuery.builder().withQuery(Query.findAll())
.withPageable(Pageable.ofSize(3).withPage(0)).build();
SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class);
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
案例四:搜索排序,withSort() 需要传入 Sort 对象,.by代表根据一个字段进行排序
.ascending() 方法:默认的,正序排序
.descending()方法:倒叙排序
/**
* 排序查询,根据时长降序排列
*/
@Test
void sortSearch() {
Query query = NativeQuery.builder().withQuery(Query.findAll())
.withPageable(Pageable.ofSize(10).withPage(0))
.withSort(Sort.by("duration").descending()).build();
SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class);
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
什么是StringQuery
将Elasticsearch查询作为JSON字符串,更适合对Elasticsearch查询的语法比较了解的人
也更方便使用kibana或postman等客户端工具行进调试
- 案例一:布尔must查询,搜索标题有 架构 关键词,描述有 spring关键字,时长范围是 10~6000之间的
@Test
void stringQuery() {
//搜索标题有 架构 关键词,描述有 spring关键字,时长范围是 10~6000之间的
String dsl = """
{"bool":{"must":[{"match":{"title":"架构"}},{"match":{"description":"spring"}},{"range":{"duration":{"gte":10,"lte":6000}}}]}}
""";
Query query = new StringQuery(dsl);
List<SearchHit<VideoDTO>> searchHitList = restTemplate.search(query, VideoDTO.class).getSearchHits();
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHitList.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
原始DSL查询
GET /video/_search
{
"query": {
"bool": {
"must": [{
"match": {
"title": "架构"
}
}, {
"match": {
"description": "spring"
}
}, {
"range": {
"duration": {
"gte": 10,
"lte": 6000
}
}
}]
}
}
}
聚合搜索案例
方案一:可以使用原始DSL进行处理
方案二:使用NativeQuery完成聚合搜索
/**
* 聚合查询
*/
@Test
void aggQuery() {
Query query = NativeQuery.builder()
.withAggregation("category_group", Aggregation.of(a -> a
.terms(ta -> ta.field("category").size(2))))
.build();
SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class);
//获取聚合数据
ElasticsearchAggregations aggregationsContainer = (ElasticsearchAggregations) searchHits.getAggregations();
Map<String, ElasticsearchAggregation> aggregations = Objects.requireNonNull(aggregationsContainer).aggregationsAsMap();
//获取对应名称的聚合
ElasticsearchAggregation aggregation = aggregations.get("category_group");
Buckets<StringTermsBucket> buckets = aggregation.aggregation().getAggregate().sterms().buckets();
//打印聚合信息
buckets.array().forEach(bucket -> {
System.out.println("组名:"+bucket.key().stringValue() + ", 值" + bucket.docCount());
});
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}