<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.7version>
dependency>
<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>7.8.0version>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
<version>7.8.0version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>2.8.2version>
dependency>
dependencies>
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author:
* @Date: 2022/8/13 10:47
* @Description:
**/
@Configuration
public class ElasticsearchConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(
// 配置ES连接地址
RestClient.builder(new HttpHost("192.168.80.121", 9200, "http"))
);
}
}
为了方便查询操作,创建索引叫做:nba
,并且添加数据,http请求如下:
# 创建索引及映射
# PUT http://192.168.80.121:9200/nba
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word"
},
"team_name": {
"type": "keyword"
},
"position": {
"type": "text",
"analyzer": "ik_max_word"
},
"play_year": {
"type": "integer",
"index": "false"
},
"jerse_no": {
"type": "integer"
}
}
}
}
# 依次创建如下文档
# POST http://192.168.80.121:9200/nba/_doc/1
{
"name": "韦德",
"team_name": "热火",
"position": "得分后卫",
"play_year": 16,
"jerse_no": 3
}
# POST http://192.168.80.121:9200/nba/_doc/2
{
"name": "波什",
"team_name": "热火",
"position": "大前锋",
"play_year": 16,
"jerse_no": 1
}
# POST http://192.168.80.121:9200/nba/_doc/3
{
"name": "詹姆斯",
"team_name": "热火",
"position": "小前锋",
"play_year": 16,
"jerse_no": 6
}
# POST http://192.168.80.121:9200/nba/_doc/4
{
"name": "张三三",
"team_name": "热火",
"position": "大前锋",
"play_year": 16,
"jerse_no": 1
}
# POST http://192.168.80.121:9200/nba/_doc/5
{
"name": "张三四",
"team_name": "热火",
"position": "大前锋",
"play_year": 16,
"jerse_no": 1
}
# POST http://192.168.80.121:9200/nba/_doc/6
{
"name": "是张三四",
"team_name": "热火",
"position": "大前锋",
"play_year": 16,
"jerse_no": 1
}
# POST http://192.168.80.121:9200/nba/_doc/7
{
"name": "张三四五",
"team_name": "热火",
"position": "大前锋",
"play_year": 16,
"jerse_no": 1
}
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 查询全部数据
* @return
* @throws IOException
*/
@GetMapping("/matchAll")
public void addBatch() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引player的所有数据
request.indices("player");
// 查询方式为所有
request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"詹姆斯","team_name":"热火","position":"小前锋","play_year":16,"jerse_no":6},
{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}]
term
查询被用于精确值匹配
,不对查询条件进行分词,这些精确值可以是number、date、bool、keyword,不能是text。
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 词条查询
* @return
* @throws IOException
*/
@GetMapping("/term")
public void term() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 查询方式为 条词查询
request.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("jerse_no", "3")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}]
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* or关系匹配查询
* @return
* @throws IOException
*/
@GetMapping("/match")
public void match() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 查询条件为`大的前锋`的position进行查询,由于进行了分词,会匹配了所有包含`前锋`的文档
request.source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("position", "大的前锋")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
查询条件为
大的前锋
的position进行查询,由于进行了分词,会匹配了所有包含前锋
的文档
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"詹姆斯","team_name":"热火","position":"小前锋","play_year":16,"jerse_no":6}]
match
类型查询,会把查询条件进行分词,然后进行匹配查询,使用operator
设置and
关系,使得多个词条之间是and的关系。
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* and关系匹配查询
* @return
* @throws IOException
*/
@GetMapping("/matchAnd")
public void matchAnd() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 查询条件为`大的前锋`的position进行查询,由于进行了分词,会匹配了所有包含`前锋`的文档
request.source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("position", "前锋大").operator(Operator.AND)));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
将
前锋大
进行分词,并且字段要包含分词后的所有值(不管关键词所在位置)
{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1}
按关键字分词顺序精确查询(忽略空格),结果只会出现"大前锋",不会有其他值;
比如大前锋
会被分词为大、前锋
,如果查询条件为大 前 锋
就不会有数据,因为大 前 锋
是三个词了与大、前锋
不匹配;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 精确短语匹配
* @return
* @throws IOException
*/
@GetMapping("/matchPhrase")
public void matchPhrase() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 按关键字顺序分词精确查询(忽略空格),结果只会出现"大前锋",不会有其他值
request.source(new SearchSourceBuilder().query(QueryBuilders.matchPhraseQuery("position", "大 前锋")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1}]
multi_match与match类似,不同的是它可以在多个字段中查询
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 多字段查询
* @return
* @throws IOException
*/
@GetMapping("/multiMatch")
public void multiMatch() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 按关键字顺序分词精确查询(忽略空格),结果只会出现"大前锋",不会有其他值
request.source(new SearchSourceBuilder().query(QueryBuilders.multiMatchQuery("后卫","name","position")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
name、postion这两个字段会对
后卫
进行分词查询(or关系)
[{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}]
terms
查询和term
查询一样,但它允许指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 多词条精确匹配
* @return
* @throws IOException
*/
@GetMapping("/terms")
public void terms() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 匹配 jerse_no为3或者6的数据
request.source(new SearchSourceBuilder().query(QueryBuilders.termsQuery("jerse_no", "3","6")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
返回球衣号为3或者6的文档数据
[{"name":"詹姆斯","team_name":"热火","position":"小前锋","play_year":16,"jerse_no":6},
{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}
]
不能是text类型的字段
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 前缀条词查询
* @return
* @throws IOException
*/
@ApiOperation(value = "前缀条词查询", notes = "前缀条词查询")
@GetMapping("/prefix")
public void prefix() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 匹配指定前缀的字段(匹配以`大`开头的position字段)
request.source(new SearchSourceBuilder().query(QueryBuilders.prefixQuery("position", "大")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
匹配指定前缀的字段(匹配以
大
开头的position字段)
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1}]
请求参数,查询name包含
韦
的数据;
韦的Unicode码:\u97e6,韶的Unicode码:\u97f6,查询name
字段包含 \u97e6到\u97f6区间的中文;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 正则条词查询
* @return
* @throws IOException
*/
@ApiOperation(value = "正则条词查询", notes = "正则条词查询")
@GetMapping("/regexp")
public void regexp() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 匹配name包含 `韦`的数据
request.source(new SearchSourceBuilder().query(QueryBuilders.regexpQuery("name", "[\u97e6-\u97f6]")));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}
]
高亮查询就是在普通查询的基础上,加上高亮字段
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 高亮查询
* @return
* @throws IOException
*/
@ApiOperation(value = "高亮查询", notes = "高亮查询")
@GetMapping("/highlight")
public void highlight() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 高亮查询就是在普通查询的基础上,加上高亮字段
SearchSourceBuilder builder = new SearchSourceBuilder();
PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("position", "大");
// 将position字段设置为高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("");
highlightBuilder.postTags("");
highlightBuilder.field("position");
builder.highlighter(highlightBuilder);
builder.query(prefixQueryBuilder);
// 执行查询
request.source(builder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
// 高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
System.out.println(highlightFields);
}
}
}
结果:
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{position=[position], fragments[[<font color='red'>大</font>前锋]]}]
模糊查询是指,允许查询结果出现误差,误差范围可以进行手动指定
比如:查询
name
为张三
,误差值为1
,那么可能会查询出张三三
、张三三四
、张三四五
等结果,误差值可以设置为AUTO
;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 模糊查询
* @return
* @throws IOException
*/
@ApiOperation(value = "模糊查询", notes = "模糊查询")
@GetMapping("/fuzzy")
public void fuzzy() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 查询`name`为`张三`,误差值为`2`,那么可能会查询出`张三三`、`张三三四`、`张三四五`等结果
request.source(new SearchSourceBuilder().query(QueryBuilders.fuzzyQuery("name", "张三").fuzziness(Fuzziness.AUTO)));
// request.source(new SearchSourceBuilder().query(QueryBuilders.fuzzyQuery("name", "张三").fuzziness(Fuzziness.TWO)));
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"张三三","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"是张三四","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"张三四","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"张三四五","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1}]
默认情况下,在搜索的结果会把文档的所有字段都返回存入_source
中,如果我们只想获取其中的部分字段,我们可以添加_source
的过滤,也可以指定不返回字段参数,适用于所有的查询请求,示例如下:
# 1、指定返回字段
"_excludes": ["name","team_name"]
# 2、includes:指定想要显示的字段
"_source": {"includes": ["name","nickname"] }
# 3、excludes:指定不想要显示的字段
"_source": {"excludes": ["name","nickname"] }
代码:
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 指定显示字段查询
* @throws IOException
*/
@ApiOperation(value = "指定显示字段查询", notes = "指定显示字段查询")
@GetMapping("/source")
public void source() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 查询条件为`大的前锋`的position进行查询,由于进行了分词,会匹配了所有包含`前锋`的文档
SearchSourceBuilder builder = new SearchSourceBuilder();
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("position", "大的前锋");
builder.query(matchQueryBuilder);
// 设置展示字段,fetchSource的第一个参数为需要展示的字段,第二个参数为不需要展示字段,二者取一即可
// 不展示`team_name`字段
builder.fetchSource(null,"team_name");
// 展示`name`和`team_name`字段
String [] includes = {"team_name","name"};
builder.fetchSource(includes,null);
// 执行查询
request.source(builder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
只展示
name
和team_name
字段
{"name":"波什","team_name":"热火"},
{"name":"詹姆斯","team_name":"热火"},]
bool
把各种其它查询通过must(与)
、must_not(非)
、should(或)
的方式进行组合;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 布尔组合查询
* @throws IOException
*/
@ApiOperation(value = "布尔组合查询", notes = "布尔组合查询")
@GetMapping("/bool")
public void bool() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 布尔组合查询
SearchSourceBuilder builder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
/*
* must:`与`条件
* mustNot:`非`条件
* should:`或`条件
*/
//boolQueryBuilder.must(QueryBuilders.matchQuery("jerse_no", 30));
//boolQueryBuilder.mustNot(QueryBuilders.matchQuery("name", "韦"));
// 查询`name`为`韦`或者`jerse_no`为`6`的数据
boolQueryBuilder.should(QueryBuilders.matchQuery("name", "韦"));
boolQueryBuilder.should(QueryBuilders.matchQuery("jerse_no", 6));
// 执行查询
builder.query(boolQueryBuilder);
request.source(builder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for ( SearchHit hit : hits ) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
查询
name
为韦
或者jerse_no
为6
的数据
[{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3},
{"name":"詹姆斯","team_name":"热火","position":"小前锋","play_year":16,"jerse_no":6}]
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 布尔组合查询
* @throws IOException
*/
@ApiOperation(value = "布尔组合查询", notes = "布尔组合查询")
@GetMapping("/range")
public void range() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 范围查询
SearchSourceBuilder builder = new SearchSourceBuilder();
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("jerse_no");
// 查询jerse_no在1到5的数据
rangeQuery.gte(1);
rangeQuery.lte(5);
builder.query(rangeQuery);
request.source(builder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
查询jerse_no在1到5的数据
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3}]
range
查询允许以下字符:
操作符 | 说明 |
---|---|
gt | 大于 |
gte | 大于等于 |
lt | 小于 |
lte | 小于等于 |
排序查询,是对所有类型查询的结果,进行排序处理;
@RestController
@RequestMapping("/query")
@Slf4j
public class QueryController {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 排序查询
* @throws IOException
*/
@ApiOperation(value = "排序查询", notes = "排序查询")
@GetMapping("/sort")
public void sort() throws IOException {
SearchRequest request = new SearchRequest();
// 查询索引为nba的数据
request.indices("nba");
// 对查询后的数据进行排序
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchAllQuery());
// 对结果排序
// play_year 倒序
builder.sort("play_year", SortOrder.DESC);
// jerse_no 顺序
builder.sort("jerse_no", SortOrder.ASC);
// 执行查询
request.source(builder);
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取数据
SearchHits hits = response.getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
}
结果:
[{"name":"波什","team_name":"热火","position":"大前锋","play_year":16,"jerse_no":1},
{"name":"韦德","team_name":"热火","position":"得分后卫","play_year":16,"jerse_no":3},
{"name":"詹姆斯","team_name":"热火","position":"小前锋","play_year":16,"jerse_no":6}]