ElasticSearch

一、引入依赖

Elasticsearch_v7.10为基础开发,采用高级REST客户端,详请参考:官网

1
2
3
4
5
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.10.0</version>
</dependency>

二、相关概念

Mysql Elasticsearch
数据库(database) 索引(indices)
表(tables) types
行(rows) documents
字段(columns) fields

三、 API

使用时注入高版本client

1
2
@Autowired
private RestHighLevelClient esClient;

1. 索引API

1.1. 创建索引

1
2
3
4
5
6
7
8

CreateIndexRequest request = new CreateIndexRequest(ES_INDEX);
CreateIndexResponse createIndexResponse = esClient.indices().create(request, RequestOptions.DEFAULT);
if (createIndexResponse.equals(ES_INDEX)) {
System.out.println("创建索引成功");
} else {
System.out.println("创建索引失败");
}

1.2. 判断索引是否存在

1
2
3
4
5
6
7
GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX);
boolean exists = esClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
if (exists) {
System.out.println("索引存在");
} else {
System.out.println("索引不存在");
}

1.3. 获取索引

1
2
3
GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX);
GetIndexResponse getIndexResponse = esClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);
System.out.println(getIndexResponse.getAliases());

1.4. 删除索引

1
2
3
4
5
6
7
DeleteIndexRequest deleteRequest = new DeleteIndexRequest(ES_INDEX);
AcknowledgedResponse acknowledgedResponse = esClient.indices().delete(deleteRequest, RequestOptions.DEFAULT);
if (acknowledgedResponse.isAcknowledged()) {
System.out.println("删除索引成功");
} else {
System.out.println("删除索引失败");
}

2. 文档API

2.1. 添加文档

1
2
3
4
5
User user = new User().setUserName("李四").setAge(21);
IndexRequest indexRequest = new IndexRequest(ES_INDEX);
indexRequest.id("1").source(JSON.toJSONString(user), XContentType.JSON);
IndexResponse indexResponse = esClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());

2.2. 判断文档是否存在

1
2
3
4
5
6
7
GetRequest getRequest = new GetRequest(ES_INDEX, "1");
boolean exists = esClient.exists(getRequest, RequestOptions.DEFAULT);
if (exists) {
System.out.println("存在");
} else {
System.out.println("不存在");
}

2.3. 获取文档

1
2
3
GetRequest getRequest = new GetRequest(ES_INDEX, "1");
GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
System.out.println(documentFields.getSourceAsString());

2.4. 更新文档

1
2
3
4
5
6
7
8
9
UpdateRequest updateRequest = new UpdateRequest(ES_INDEX, "1");
User user = new User().setUserName("李四").setAge(21);
updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT);
if (updateResponse.status().getStatus() == 200) {
System.out.println("更新文档成功");
} else {
System.out.println("更新文档失败");
}

2.5. 删除文档

1
2
3
4
5
6
7
DeleteRequest deleteRequest = new DeleteRequest(ES_INDEX, "1");
DeleteResponse deleteResponse = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
if (deleteResponse.status().getStatus() == 200) {
System.out.println("删除文档成功");
} else {
System.out.println("删除文档失败");
}

3. 复杂查询API

3.1. 精准查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SearchRequest searchRequest = new SearchRequest(ES_INDEX);
// 精准查询
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword", "李四");
searchSourceBuilder.query(termQueryBuilder);
// 超时设置
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// 分页设置
searchSourceBuilder.from(1);
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
// 解析结果
List<User> userList = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));
}
userList.forEach(item -> System.out.println(item));

3.2. 多字段查询同一结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//从userName、userNameEN中搜索search
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(1);
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("search", "userName", "userNameEN");
searchSourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest("ES_INDEX").source(searchSourceBuilder);
SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
List<User> userList = new ArrayList<>();
// 解析结果
for (SearchHit hit : searchResponse.getHits().getHits()) {
userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));
}
// 解析结果
userList.forEach(item -> System.out.println(item));

3.3. 多字段查询不同结果

1
2
3
4
5
6
7
8
9
10
//查询userName等于张三且userNameEN等于ZhangSan
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//构建查询条件
QueryBuilder userName= QueryBuilders.matchPhraseQuery("userName","张三");
QueryBuilder userNameEN= QueryBuilders.matchPhraseQuery("userNameEN", "ZhangSan");

//查
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(userName).must(userNameEN);
searchSourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest("ES_INDEX").source(searchSourceBuilder);

3.4. 高亮查询(需安装插件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
SearchRequest searchRequest = new SearchRequest(ES_INDEX);
// 精准查询
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword", "李四");
searchSourceBuilder.query(termQueryBuilder);
// 超时
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// 分页
searchSourceBuilder.from(1);
searchSourceBuilder.size(10);
//根据某字段降排
searchSourceBuilder.sort("age", SortOrder.DESC);
// 高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("userName");
highlightBuilder.preTags("<span style='color: red;'>");
highlightBuilder.postTags("</span>");
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
List<User> userList = new ArrayList<>();
// 解析结果
for (SearchHit hit : searchResponse.getHits().getHits()) {
userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));
}
// 解析结果
userList.forEach(item -> System.out.println(item));

四、HTTP请求

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:

    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、float
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • fields:多字段属性(让一个字段拥有多个子字段类型,使得一个字段能够被多个不同的索引方式进行索引)
  • index:是否创建索引(此索引非前面所说的索引库,),默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段

1. 索引请求

1.1. 创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
PUT /{索引名}
{
"mappings": {
"properties": {
"comic_id": {
"type": "keyword"
},
"comic_source": {
"type": "keyword"
},
"comic_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256 #表示最大的字段值长度,*超出这个长度的字段将不会被索引,但是会存储,ignore_above一般设置为256
}
}
},
"author_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"comic_label": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"comic_cover": {
"type": "keyword"
},
"comic_status": {
"type": "keyword"
}
}
}
}

1.2. 查询索引

1
GET /{索引名}

1.3. 修改索引库

索引库一旦创建,无法修改mapping

1.4. 添加索引库

1
2
3
4
5
6
7
8
PUT /{索引名}/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}

1.4. 删除索引库(删表)

1
DELETE /{索引名}

2. 文档请求

2.1. 添加文档

没有指定文档id的话,es会随机给你生成一个新的id(是不规则的随机字符串,例:wXxbyYuBVgHo5bYKF1Jc)

1
2
3
4
5
6
7
8
9
10
POST /{索引名}/_doc/{文档id}
{
"字段1": "值1",
"字段1": "值2",
"字段1": {
"子属性1": "值3"
"子属性1": "值4",
},
//....
}

2.2. 获取文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /{索引名}/_doc/{文档id} 
{
"_index" : "comic", # 表面文档所在索引库
"_type" : "_doc",
"_id" : "1",
"_version" : 1, #版本控制,每做一次版本修改就会自增
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : { #插入原始文档
"info" : "大天才是小瘦子",
"number" : "123456",
"name" : {
"firstName" : "瘦子",
"lastName" : "小"
}
}
}

2.3. 删除文档

1
DELETE /{索引名}/_doc/{文档id} 

2.4. 修改文档

全量修改,若PUT命令的文档 id不存在则会进行文档创建,且只修改个别字段,其余未修改的字段数据会被删除

1
2
3
4
5
6
7
8
9
10
PUT /{索引名}/_doc/{文档id} 
{
"字段1": "值1",
"字段1": "值2",
"字段1": {
"子属性1": "值3"
"子属性1": "值4",
},
//....
}

增量修改,修改指定字段则不会有以上的问题

1
2
3
4
5
6
POST  /{索引名}/_update/{文档id} 
{
"doc":{
"字段名":"新的值",
}
}

3. 复杂请求

3.1. 模糊查询

指定查询类型 描述
match 等同于like模糊查询,match查询的字段如果是text类型,那么text会被分词查询,否则为精准查询
match_all 查询所有的数据,ES默认分页为10条数据,这个关键字不能写查询条件
match_phrase 匹配短语,match是会查询所有包含分词的doc文档,而match_phrase则是匹配整个短语,才会返回对应的doc文档
match_phrase_prefix 匹配短语前缀部分,且只能使用在text类型字段
1
2
3
4
5
6
7
8
9
10
GET /{索引名}/_search
{
"query": {
"match": {
"name": "张三"
}
},
"_source": ["查询字段1", "查询字段2"]//可为:"_source": false --全部字段都不返回
}

过滤字段

  • _source: [“查询字段1”, “查询字段2”] 只返回指定的字段
  • source=false 所有字段都不返回

3.2. 布尔查询

指定条件类型 描述
must 等同于and,所有条件为must中的数组->[a,b]=a and b
should 等同于or,所有条件为must中的数组->[a,b]=a or b
must_not 等同于!not->where not 查询字段=值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /{索引名}/_search
{
"query": {
"bool": {
"must": [
"match": {
"name": "张三"
},
"查询类型": {
"查询字段": "查询值"
}
]
}
}
}

3.3. 范围查询

  • 条件:
    • gt:大于
    • lt:小于
    • gte:大于等于
    • lte:小于等于
    • eq:等于
    • ne:不等于
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /{索引名}/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"指定字段": {
"条件": "范围值",
"条件": "范围值"
}
}
}
]
}
}
}

3.4. 判断文档字段值是否为空

exists是否存在exists用在filter里面时候,表示过滤掉不存在指定字段的doc文档,等同于is null

注意:exists会返回指定字段存在的doc文档,只有当字段等于null,即:不存在时候才会匹配成功,如果字段等于空字符串不会匹配成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /{索引名}/_search
{
"query": {
"bool": {
"filter": [
{
"exists": {
"查询字段": "查询值"
}
}
]
}
}
}

3.5. 文档ids过滤查询

ids过滤查询,只能够对doc文档的id进行多个值查询,等同于ids in(”2022001”,”2022005”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /{索引名}/_search
{
"query": {
"bool": {
"filter": [
{
"ids": {
"values": [
"2022001", "2022005"
]
}
}
]
}
}
}

3.6. term精准关键词查询

term关键词查询,等同于like “字段值%”,用于精准查询,不会像math一样分词拆解来查询

注意:term每次只能够匹配一个关键字,但terms允许多个关键字匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
GET /{索引名}/_search
{
"query": {
"bool": {
"filter": [
{
// "term": {
// "查询字段": "查询值"
// }
"terms": {
"查询字段": [
"查询值1",
"查询值2",
"查询值3",
]
}
}
]
}
}
}