1. 概述
Springboot2 对Elasticsearch进行增删改查有多种方式:
通过ES的9300端口使用TCP的方式操作,该种方式已经逐渐被官方废弃,我们不再进行研究
我们主要使用通过ES的9200端口使用HTTP的方式
- JestClient:非官方,更新慢
- RestTemplate:模拟发 HTTP 请求,ES 很多操作需要自己封装,麻烦
- HttpClient:同上
- Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明,上手简单
我们选择使用最佳的方式Elasticsearch-Rest-Client
有两种引入依赖的方式:
- 只引入Elasticsearch-Rest-Client需要的包
- 直接引入Spring-data-elasticsearch,此时自动引入了Elasticsearch-Rest-Client,但是需要注意一下版本对应问题
区别:使用Spring-data-elasticsearch依赖,可采用ElasticsearchRepository方式操作Entity实体对象,如要操作未知固定列的数据,还需要Elasticsearch-Rest-Client操作数据
关于Elasticsearch版本的选择:
关于Elasticsearch与JVM版本的选择:
关于Spring-data-elasticsearch版本的选择:
参考链接:
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.requirements
2. 代码示例
2.1
我以Elasticsearch6.8.21为例:
注:使用什么版本的es服务端,就引入相同版本号的依赖文件
1. 引入依赖文件
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.21</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.21</version>
</dependency>
2. 配置RestHighLevelClient
@Configuration
public class ElasticsearchRestClientConfig {
public static final RequestOptions COMMON_OPTIONS;
static {
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
COMMON_OPTIONS = builder.build();
}
/**
* 创建ES实例
* @return
*/
@Bean
public RestHighLevelClient restHighLevelClient(){
HttpHost httpHost = new HttpHost(
"127.0.0.1",9200,"http"
);
RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
return restHighLevelClient;
}
}
3. 使用RestHighLevelClient操作数据
针对需要存储查询动态属性字段的数据,可采用该种方式;此方式也不需要对Springboot版本进行调整,我使用了Springboot2.6.x版本,依然可行。
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchHighLevelClientTest {
@Resource
private RestHighLevelClient client;
/**
* 判断索引是否存在
*/
@Test
public void testCheckIndex () {
try {
boolean exist = client.indices().exists(new GetIndexRequest("indexName"), RequestOptions.DEFAULT);
System.out.println(exist);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建索引
*/
@Test
public void testCreateIndex (){
try {
CreateIndexRequest request = new CreateIndexRequest("indexName");
CreateIndexResponse createIndexResponse = this.client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse.index());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 删除索引
*/
@Test
public void testDeleteIndex() {
try {
DeleteIndexRequest request = new DeleteIndexRequest("indexName");
AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(response.isAcknowledged());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 写入数据
*/
@Test
public void testInsertMapData (){
try {
// 方法1:
Map<String,Object> dataMap = new HashMap<>();
dataMap.put("test", "test1");
IndexRequest indexRequest = new IndexRequest("xc_course","doc");
indexRequest.source(dataMap);
IndexResponse indexResponse = this.client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(indexResponse.getResult());
//方法2:该发法采用批量插入的方法
Map<String,Object> dataMap2 = new HashMap<>();
dataMap2.put("city", "北京");
IndexRequest indexRequest2 = new IndexRequest("xc_course","doc");
indexRequest2.source(dataMap2);
BulkRequest request = new BulkRequest();
request.add(indexRequest2);
BulkResponse bulkResponse = this.client.bulk(request, RequestOptions.DEFAULT);
System.out.println(JSONObject.toJSONString(bulkResponse));
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 批量写入数据
*/
@Test
public void batchInsertMapData (){
try {
List<Map<String,Object>> userIndexList = new ArrayList<>();
Map<String,Object> map1 = new HashMap<>();
map1.put("test", "test1");
Map<String,Object> map2 = new HashMap<>();
map2.put("test", "test2");
userIndexList.add(map1);
userIndexList.add(map2);
BulkRequest request = new BulkRequest();
for (Map<String,Object> dataMap:userIndexList){
request.add(new IndexRequest("xc_course","doc").source(dataMap));
}
BulkResponse bulkResponse = this.client.bulk(request, RequestOptions.DEFAULT);
System.out.println(JSONObject.toJSONString(bulkResponse));
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 更新数据,可以直接修改索引结构
*/
@Test
public void testUpdateMapData (){
try {
Map<String,Object> dataMap = new HashMap<>();
dataMap.put("test", "test2");
dataMap.put("test1", "test3");
UpdateRequest updateRequest = new UpdateRequest("xc_course","doc", "51zYd38BFz6qlQzXYT56");
updateRequest.doc(dataMap);
UpdateResponse updateResponse = this.client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse.getResult());
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 删除数据
*/
@Test
public void testDeleteMapData (){
try {
//方法1:
DeleteRequest deleteRequest1 = new DeleteRequest("xc_course","doc", "4VwadH8BFz6qlQzXVD5c");
DeleteResponse deleteResponse1 = this.client.delete(deleteRequest1, RequestOptions.DEFAULT);
System.out.println(deleteResponse1.getResult());
//方法2:
DeleteRequest deleteRequest2 = new DeleteRequest();
deleteRequest2.index("xc_course");
deleteRequest2.type("doc");
deleteRequest2.id("41zJd38BFz6qlQzXhj71");
DeleteResponse deleteResponse2 = this.client.delete(deleteRequest2, RequestOptions.DEFAULT);
System.out.println(deleteResponse2.getResult());
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 查询总数
*/
@Test
public void testCount (){
// 指定创建时间
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// queryBuilder.must(QueryBuilders.termQuery("test", "test1"));
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(queryBuilder);
CountRequest countRequest = new CountRequest("xc_course");
countRequest.source(sourceBuilder);
try {
CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
long count = countResponse.getCount();
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询集合
*/
@Test
public void testList () {
// 查询条件,指定时间并过滤指定字段值
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// queryBuilder.must(QueryBuilders.termQuery("test", "test1"));
// queryBuilder.mustNot(QueryBuilders.termQuery("city","北京"));
sourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest("xc_course");
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, RequestOptions.DEFAULT);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
System.out.println(JSONObject.toJSONString(data));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 分页查询
*/
@Test
public void testPage () {
// 查询条件,指定时间并过滤指定字段值
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(1);
sourceBuilder.size(20);
//sourceBuilder.sort("createTime", SortOrder.DESC);
SearchRequest searchRequest = new SearchRequest("xc_course");
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, RequestOptions.DEFAULT);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
System.out.println(JSONObject.toJSONString(data));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2
1. 引入依赖文件
① Springboot2.6.x版本过高,与Elasticsearch6.8.x不一致,使用中代码会出错,需要对Springboot版本进行降级处理
如下图:
② 将Springboot版本降级至2.2.x后
依赖选择 spring-boot-starter-data-elasticsearch
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>-->
或者 spring-data-elasticsearch 3.2.x版本
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.2.13.RELEASE</version>
</dependency>
2. 配置application.yml文件
spring:
elasticsearch:
rest:
connection-timeout: 30s
read-timeout: 60s
uris: 127.0.0.1:9200
3. 使用ElasticsearchRepository操作实体数据
也可以与第一种方式结合使用
官方也给出了相关RestHighLevelClient配置示例
客户端配置: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.rest
可扩充配置项:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration