SpringBoot整合ElasticSearch
ElasticSearch
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。
本文基于 Elasticsearch7.8.0。
目录
- ElasticSearch的安装使用
- 相关配套设施的安装使用
- 基本概念简介
- SpringBoot整合Elasticsearch的两种方案
1. 自定义封装RestHighLevelClient
- 基于JPA规范开发
1. ElasticSearch的安装使用
基于window 解压运行
基于docker(参见 常用docker环境运维)
2. 相关配套设施的安装使用
elasticsearch-head : 类似Navicat的elasticseach的数据可视化查询工具(Chrome商店安装)
Kibana:ElasticSearch官方配套可视化组件,可组成ELK日志处理可视化体系
安装:下载解压
修改配置文件 config/kibana.yml :
1
2
3
4
5
6# 端口
server.port: 5601
# elasticsearch 地址
elasticsearch.hosts: ["http://localhost:9200"]
# 语言设置
i18n.locale: "zh-CN"
- ./bin/kibana.bat 运行
3. 基本概念简介
- 索引 index(名词)
一个 索引 类似于传统关系数据库中的一个 数据库 ,是一个存储关系型文档的地方,是ES对逻辑数据的逻辑存储,索引的结构是为快速有效的全文检索做准备。 索引 (index) 的复数词为 indices 或 indexes 。
- 索引 index(动词)
索引一个文档 就是存储一个文档到一个 索引 (名词)中以便它可以被检索和查询到。这非常类似于 SQL 语句中的 INSERT 关键词,除了文档已存在时新chaj文档会替换旧文档情况之外。
- 倒排索引
倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。
- 文档 document
存储在ES上的主要实体叫文档
- 文档类型 type(废弃)
在ES中,一个索引对象可以存储很多不同用途的对象。
- 映射
存储有关字段的信息,每一个文档类型都有自己的映射。
- 面向文档
在应用程序中对象很少只是一个简单的键和值的列表。通常,它们拥有更复杂的数据结构,可能包括日期、地理信息、其他对象或者数组等。
也许有一天你想把这些对象存储在数据库中。使用关系型数据库的行和列存储,这相当于是把一个表现力丰富的对象挤压到一个非常大的电子表格中:你必须将这个对象扁平化来适应表结构—通常一个字段>对应一列—而且又不得不在每次查询时重新构造对象。
Elasticsearch 是 面向文档 的,意味着它存储整个对象或 文档。Elasticsearch 不仅存储文档,而且 _索引 每个文档的内容使之可以被检索。在 Elasticsearch 中,你 对文档进行索引、检索、排序和过滤—而不是对行列数据。这是一种完全不同的思考数据的方式,也是 Elasticsearch 能支持复杂全文检索的原因。
API参考 elasticsearch的常用restful api
主要是index和document的api
用的最多的是document的复合查询
如:
1 | 插入index : emp |
4. SpringBoot整合Elasticsearch的两种方案
基于官方的 RestHighLevelClient
- 配置RestHighLevelClient 此处使用Restful 高级 API
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
28package io.kid1999.esystem.config;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
/**
* @author kid1999
* @create 2021-01-27 16:16
* @description ES 客服端配置
**/
public class ESRestTemplateConfig {
private String ES_HOST;
public RestHighLevelClient ESClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(ES_HOST)
.build();
return RestClients.create(clientConfiguration).rest();
}
}- 封装工具类
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143package io.kid1999.esystem.utils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* @author kid1999
* @create 2021-01-27 18:37
* @description elasticsearch 工具类
**/
public class ESUtil {
private RestHighLevelClient client;
private static final String INDEX = "test";
//创建索引
public CreateIndexResponse createIndex(String index) throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
CreateIndexResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
return response;
}
/**
* 测试索引是否存在
*/
public boolean existIndex(String index) throws IOException {
GetIndexRequest request = new GetIndexRequest(index);
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
return exists;
}
/**
* 删除索引
*/
public AcknowledgedResponse deleteIndex(String index) throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
return delete;
}
/**
* 添加文档
*/
public IndexResponse createDocument(String index,Object object) throws IOException {
IndexRequest request = new IndexRequest(index);
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.timeout("1s");
request.source(object);
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
return response;
}
/**
* 判断是否存在文档
*/
public void isExist() throws IOException {
GetRequest getRequest = new GetRequest(INDEX, "1");
//不获取返回的source的上下文
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
//获取文档信息
public void getDocument() throws IOException {
GetRequest getRequest = new GetRequest(INDEX, "1");
GetResponse response = client.get(getRequest, RequestOptions.DEFAULT);
//打印文档信息
System.out.println(response.getSourceAsString());
System.out.println(response);
}
//更新文档信息
public void updateDocument() throws IOException {
UpdateRequest request = new UpdateRequest(INDEX, "1");
request.timeout("1s");
HashMap<String,String> map = new HashMap<>();
map.put("name","kid");
map.put("password","asdasd");
request.doc(map);
UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
System.out.println(update);
System.out.println(update.status());
}
//删除文档
public void deleteDocument() throws IOException {
DeleteRequest request = new DeleteRequest(INDEX, "1");
request.timeout("10s");
DeleteResponse update = client.delete(request, RequestOptions.DEFAULT);
System.out.println(update.status());
}
//批量插入数据
public void BulkRequest() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
ArrayList<HashMap<String,String>> maps = new ArrayList<>();
HashMap<String,String> map = new HashMap<>();
map.put("name","kid");
map.put("pass","dasda");
for (int i = 0; i < maps.size(); i++) {
bulkRequest.add(
new IndexRequest(INDEX)
.id("" + i + 1)
.source(maps.get(i))
);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk);
}
}
基于JPA规范开发
- application.yml 配置es
1
2
3
4
5
6# jpa elasticsearch 配置
# 不同于 spring.data.elasticsearch.cluster-nodes的老式配置,已被废弃,此为restful高级api的配置
spring:
elasticsearch:
rest:
uris: kid1999.top:9200- 创建es的entry实体对象
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
27package io.kid1999.esystem.es;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* @author kid1999
* @create 2021-01-28 11:12
* @description TODO
**/
public class ElasticsearchDto {
private Long id;
private String title;
private String category;
private BigDecimal price;
private String content;
}@Document
加在类上
| 类型 | 属性名 | 默认值 | 说明 |
| :——: | :——————-: | :——: | ————————————————— |
| String | indexName | 无 | 索引库的名称,建议以项目的名称命名 |
| String | type | “” | 类型,建议以实体的名称命名 |
| short | shards | 5 | 默认分区数 |
| short | replica | 1 | 每个分区默认的备份数 |
| String | refreshInterval | “1s” | 刷新间隔 |
| String | indexStoreType | “fs” | 索引文件存储类型 |@Field
属性上加的,相当于@Column
,可以不写,默认全部添加到ES中。主键上是@Id
。
| 类型 | 属性名 | 默认值 | 说明 |
| :————: | :——————: | :————————-: | ——————————————— |
| FieldType | type | FieldType.Auto | 自动检测属性的类型 |
| FieldIndex | index | FieldIndex.analyzed | 默认情况下分词 |
| boolean | store | false | 默认情况下不存储原文 |
| String | searchAnalyzer | “” | 指定字段搜索时使用的分词器 |
| String | indexAnalyzer | “” | 指定字段建立索引时指定的分词器 |
| String[] | ignoreFields | {} | 如果某个字段需要被忽略 |- 创建es的JPA规范的Repository
1
2
3
4
5
6
7package com.uwith.springbootelasticsearch;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
public interface ElasticsearchRepository extends ElasticsearchCrudRepository<ElasticsearchDto, Long> {
}- 其他用法雷同 JPA操作