SpringBoot2.5.6整合Elasticsearch7.12.1
下面将通过SpringBoot
整合Elasticseach
,SpringBoot的版本是2.5.6
,Elasticsearch的版本是7.12.1
。
SpringBoot整合Elasticsearch主要有三种方式,一种是通过elasticsearch-rest-high-level-client
,另一
种是通过spring-boot-starter-data-elasticsearch
,最后一种是通过transport
。
RestHighLevelClient
更强大,更灵活,但是不能友好的操作对象,ElasticSearchRepository
对象操作友
好。
官方文档:
https://docs.spring.io/spring-data/elasticsearch/docs/4.0.1.RELEASE/reference/html/#preface
https://spring.io/projects/spring-data-elasticsearch/#learn
https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java-docs.html
1、elasticsearch-rest-high-level-client方式
使用RestHighLevelClient
操作
官网地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
1.1 引入Pom文件的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring-boot-elasticsearch1</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-elasticsearch1</name><description>spring-boot-elasticsearch1</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
1.2 添加配置文件EsConfig
package com.example.springbootelasticsearch1.config;import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author zhangshixing* @date 2021年11月09日 21:57*/
@Configuration
public class EsConfig {@Value("${elasticsearch.hostname}")private String hostname;@Value("${elasticsearch.port}")private int port;/*** HighLevelRestConfig*/@Beanpublic RestHighLevelClient restHighLevelClient() {// 如果有多个从节点可以持续在内部new多个HttpHost,参数1是IP,参数2是端口,参数3是通信协议return new RestHighLevelClient(RestClient.builder(new HttpHost(hostname, port, "http")));}
}
1.3 配置yml文件
# es配置
elasticsearch.hostname=127.0.0.1
elasticsearch.port=9200# 默认配置,在本地启动的时候可以不配置
# spring.elasticsearch.rest.uris=http://127.0.0.1:9200
1.4 service
package com.example.springbootelasticsearch1.service;import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.index.reindex.BulkByScrollResponse;import java.io.IOException;/*** @author zhangshixing* @date 2021年11月09日 22:05*/
public interface IRestHighLevelClientService {// 创建索引CreateIndexResponse createIndex() throws IOException;// 删除索引AcknowledgedResponse deleteIndex() throws IOException;// 查看索引是否存在boolean existIndex() throws IOException;// 更新索引的settings配置AcknowledgedResponse updateIndexSettings() throws IOException;// 更新索引的mapping配置AcknowledgedResponse updateIndexMapping() throws IOException;// 新增文档IndexResponse addDocument() throws IOException;// 修改文档UpdateResponse updateDocument() throws IOException;// 根据id删除文档DeleteResponse deleteDocumentById() throws IOException;// 根据条件删除文档BulkByScrollResponse deleteDocumentByCon() throws IOException;// 批量操作文档BulkResponse bulkDocument() throws IOException;// 查询操作SearchResponse searchDocument1() throws IOException;// 查询操作2SearchResponse searchDocument2() throws IOException;// 高亮查询SearchResponse searchDocument3() throws IOException;
}
1.5 serviceImpl
package com.example.springbootelasticsearch1.service.impl;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.bulk.BulkItemResponse;
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.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
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.client.indices.PutMappingRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;/*** @author zhangshixing* @date 2021年11月09日 22:06*/
@Service
public class RestHighLevelClientServiceImpl implements IRestHighLevelClientService {// 引入RestHighLevelClient@Autowiredprivate RestHighLevelClient restHighLevelClient;// 新建索引@Overridepublic CreateIndexResponse createIndex() throws IOException {String indexName = "student";CreateIndexRequest request = new CreateIndexRequest(indexName.toLowerCase());request.settings(Settings.builder().put("index.number_of_shards", 5).put("index.number_of_replicas", 0));// mapping部分,除了用json字符串来定义外,还可以使用Map或者XContentBuilder// 这里使用XContentBuilderXContentBuilder builder = XContentFactory.jsonBuilder();builder.startObject();{builder.startObject("properties");{builder.startObject("id");{builder.field("type", "integer");}builder.endObject();builder.startObject("name");{builder.field("type", "text");}builder.endObject();builder.startObject("age");{builder.field("type", "integer");}builder.endObject();builder.startObject("description");{builder.field("type", "text");builder.field("analyzer", "ik_max_word");}builder.endObject();builder.startObject("birthday");{builder.field("type", "date");}builder.endObject();}builder.endObject();}builder.endObject();request.mapping(builder);// 同步的方式执行CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);// 异步的方式执行restHighLevelClient.indices().createAsync(request, RequestOptions.DEFAULT, new ActionListener<CreateIndexResponse>() {@Overridepublic void onResponse(CreateIndexResponse createIndexResponse1) {System.out.println("执行情况:" + createIndexResponse1);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});return createIndexResponse;}// 删除索引@Overridepublic AcknowledgedResponse deleteIndex() throws IOException {String indexName = "student";DeleteIndexRequest indexRequest = new DeleteIndexRequest(indexName);// 同步执行AcknowledgedResponse delete = restHighLevelClient.indices().delete(indexRequest, RequestOptions.DEFAULT);// 异步执行/*restHighLevelClient.indices().deleteAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<AcknowledgedResponse>() {@Overridepublic void onResponse(AcknowledgedResponse acknowledgedResponse) {System.out.println("执行情况:" + acknowledgedResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return delete;}// 查看索引是否存在@Overridepublic boolean existIndex() throws IOException {String indexName = "student";GetIndexRequest request = new GetIndexRequest(indexName);// 同步执行boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);// 异步执行/*restHighLevelClient.indices().existsAsync(request, RequestOptions.DEFAULT, new ActionListener<Boolean>() {@Overridepublic void onResponse(Boolean aBoolean) {System.out.println("执行情况:" + aBoolean);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return exists;}// 更新索引的settings配置@Overridepublic AcknowledgedResponse updateIndexSettings() throws IOException {String indexName = "student";UpdateSettingsRequest request = new UpdateSettingsRequest(indexName);String settingKey = "index.number_of_replicas";int settingValue = 2;Settings.Builder settingsBuilder = Settings.builder().put(settingKey, settingValue);request.settings(settingsBuilder);// 是否更新已经存在的settings配置默认falserequest.setPreserveExisting(true);// 更新settings配置(同步)AcknowledgedResponse updateSettingsResponse = restHighLevelClient.indices().putSettings(request, RequestOptions.DEFAULT);// 更新settings配置(异步)/*restHighLevelClient.indices().putSettingsAsync(request, RequestOptions.DEFAULT, new ActionListener<AcknowledgedResponse>() {@Overridepublic void onResponse(AcknowledgedResponse acknowledgedResponse) {System.out.println("执行情况:" + acknowledgedResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return updateSettingsResponse;}// 更新索引的mapping配置@Overridepublic AcknowledgedResponse updateIndexMapping() throws IOException {String indexName = "student";PutMappingRequest request = new PutMappingRequest(indexName);XContentBuilder builder = XContentFactory.jsonBuilder();builder.startObject();{builder.startObject("properties");{// 会在以前索引的基础上新增sex字段builder.startObject("sex");{builder.field("type", "integer");}builder.endObject();}builder.endObject();}builder.endObject();request.source(builder);// 新增mapping配置(同步)AcknowledgedResponse putMappingResponse = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);// 新增mapping配置(异步)/*restHighLevelClient.indices().putMappingAsync(request, RequestOptions.DEFAULT, new ActionListener<AcknowledgedResponse>() {@Overridepublic void onResponse(AcknowledgedResponse acknowledgedResponse) {System.out.println("执行情况:" + acknowledgedResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return putMappingResponse;}// 新增文档@Overridepublic IndexResponse addDocument() throws IOException {String indexName = "student";IndexRequest request = new IndexRequest(indexName);// id为1的数据request.id("1");Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("id", 1);jsonMap.put("name", "tom");jsonMap.put("age", 24);jsonMap.put("description", "tom是一个好学生");jsonMap.put("birthday", new Date());jsonMap.put("sex", 1);request.source(jsonMap);request.routing("routing");// 同步方式IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);// 异步方式/*restHighLevelClient.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {@Overridepublic void onResponse(IndexResponse indexResponse) {System.out.println("执行情况: " + indexResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return indexResponse;}// 修改文档@Overridepublic UpdateResponse updateDocument() throws IOException {String indexName = "student";// 传入索引名称和需要更新的Document的idUpdateRequest request = new UpdateRequest(indexName, "1");// 更新的内容会与数据本身合并,若存在则更新,不存在则新增// 组装更新内容的数据结构有四种: json字符串、Map、XContentBuilder、Key-Value// json字符串/*String jsonString = "{" +"\"updated\":\"2020-03-29\"," +"\"reason\":\"daily update\"" +"}";request.doc(jsonString);*/// Map/*Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("updated", new Date());jsonMap.put("reason", "daily update");request.doc(jsonMap);*/// XContentBuilder/*XContentBuilder builder = XContentFactory.jsonBuilder();builder.startObject();builder.timeField("updated", new Date());builder.timeField("reason", "daily update");builder.endObject();request.doc(builder);*/// Key-Value,可以包含多个键值对request.doc("description", "tom是一个好学生,考上大学肯定没有问题!");// 同步的方式发送更新请求UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);// 异步方式/*restHighLevelClient.updateAsync(request, RequestOptions.DEFAULT, new ActionListener<UpdateResponse>() {@Overridepublic void onResponse(UpdateResponse updateResponse) {System.out.println("执行情况: " + updateResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return updateResponse;}// 根据id删除文档@Overridepublic DeleteResponse deleteDocumentById() throws IOException {String indexName = "student";DeleteRequest deleteRequest = new DeleteRequest(indexName, "1");// 同步方式DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);// 异步方式/*restHighLevelClient.deleteAsync(deleteRequest, RequestOptions.DEFAULT, new ActionListener<DeleteResponse>() {@Overridepublic void onResponse(DeleteResponse deleteResponse) {System.out.println("执行情况: " + deleteResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return deleteResponse;}// 根据条件删除文档@Overridepublic BulkByScrollResponse deleteDocumentByCon() throws IOException {String indexName = "student";DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(indexName);// 待删除的数据需要满足的条件deleteByQueryRequest.setQuery(new TermQueryBuilder("name", "tom"));// 忽略版本冲突deleteByQueryRequest.setConflicts("proceed");// 同步的方式删除BulkByScrollResponse deleteResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);// 异步的方式/*restHighLevelClient.deleteByQueryAsync(deleteByQueryRequest, RequestOptions.DEFAULT, new ActionListener<BulkByScrollResponse>() {@Overridepublic void onResponse(BulkByScrollResponse bulkByScrollResponse) {System.out.println("执行情况: " + deleteResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return deleteResponse;}// 批量操作文档@Overridepublic BulkResponse bulkDocument() throws IOException {String indexName = "student";BulkRequest request = new BulkRequest();// 普通的PUT操作,相当于全量替换或新增request.add(new IndexRequest(indexName).id("2").source(XContentType.JSON, "name", "zsx", "age", "25"));// 更新操作request.add(new UpdateRequest(indexName, "2").doc(XContentType.JSON, "sex", 1));// 删除操作request.add(new DeleteRequest(indexName, "2"));// 同步操作BulkResponse bulkResponse = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);boolean hasFailures = bulkResponse.hasFailures();System.out.println("批量操作是否失败:" + hasFailures);BulkItemResponse[] items = bulkResponse.getItems();for (BulkItemResponse item : items) {System.out.println(item.status());}// 异步操作/*restHighLevelClient.bulkAsync(request, RequestOptions.DEFAULT, new ActionListener<BulkResponse>() {@Overridepublic void onResponse(BulkResponse bulkItemResponses) {System.out.println("执行情况: " + bulkItemResponses);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return bulkResponse;}// 查询操作1@Overridepublic SearchResponse searchDocument1() throws IOException {String indexName = "student";SearchRequest searchRequest = new SearchRequest(indexName);BoolQueryBuilder booleanQueryBuilder = QueryBuilders.boolQuery();// 过滤出年龄在15~40岁之间的documentbooleanQueryBuilder.filter(QueryBuilders.rangeQuery("age").from(15).to(40));// bool must条件, 找出description字段中包含学生的documentbooleanQueryBuilder.must(QueryBuilders.matchQuery("description", "学生"));SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();// 执行查询条件// sourceBuilder.query(QueryBuilders.matchAllQuery());sourceBuilder.query(booleanQueryBuilder);MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "tom");sourceBuilder.query(matchQueryBuilder);//聚合年龄分布TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age");sourceBuilder.aggregation(ageAgg);//聚合平均年龄AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("ageAvg").field("age");sourceBuilder.aggregation(balanceAvg);// 分页查询sourceBuilder.from(0);sourceBuilder.size(5);// 排序sourceBuilder.sort("age", SortOrder.DESC);sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));searchRequest.source(sourceBuilder);// 同步的方式发送请求SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHit[] hits = searchResponse.getHits().getHits();for (SearchHit hit : hits) {String hitString = hit.getSourceAsString();System.out.println(hitString);}// 异步方式发送请求/*restHighLevelClient.searchAsync(searchRequest, RequestOptions.DEFAULT, new ActionListener<SearchResponse>() {@Overridepublic void onResponse(SearchResponse searchResponse) {System.out.println("执行情况: " + searchResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return searchResponse;}// 查询操作2@Overridepublic SearchResponse searchDocument2() throws IOException {String indexName = "student";SearchRequest searchRequest = new SearchRequest(indexName);//构建搜索条件SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()// 在student索引的description和name字段中都查询“tom”.query(QueryBuilders.multiMatchQuery("tom", "description", "name"))// matchQuery是模糊查询,会对key进行分词// searchSourceBuilder.query(QueryBuilders.matchQuery(key,value));// termQuery是精准查询// searchSourceBuilder.query(QueryBuilders.termQuery(key,value));.sort(SortBuilders.fieldSort("age").order(SortOrder.DESC))// 一个可选项,用于控制允许搜索的时间// searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));// 指定从哪条开始查询.from(0)// 需要查出的总记录条数.size(10);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHit[] hits = searchResponse.getHits().getHits();for (SearchHit hit : hits) {String hitString = hit.getSourceAsString();System.out.println(hitString);}// 异步方式发送请求/*restHighLevelClient.searchAsync(searchRequest, RequestOptions.DEFAULT, new ActionListener<SearchResponse>() {@Overridepublic void onResponse(SearchResponse searchResponse) {System.out.println("执行情况: " + searchResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return searchResponse;}// 高亮查询@Overridepublic SearchResponse searchDocument3() throws IOException {String indexName = "student";SearchRequest searchRequest = new SearchRequest(indexName);// 高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("name");highlightBuilder.field("description");highlightBuilder.requireFieldMatch(false);highlightBuilder.preTags("<span style='color:red'>");highlightBuilder.postTags("</span>");// 构建搜索条件SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(QueryBuilders.multiMatchQuery("tom", "description", "name")).sort(SortBuilders.fieldSort("age").order(SortOrder.DESC))// 指定从哪条开始查询.from(0)// 需要查出的总记录条数.size(10)//高亮.highlighter(highlightBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHit[] hits = searchResponse.getHits().getHits();for (SearchHit hit : hits) {String hitString = hit.getSourceAsString();System.out.println(hitString);// 处理高亮显示的结果HighlightField titleField = hit.getHighlightFields().get("name");if (titleField != null) {// 新建一个对象,把该属性的值重新覆盖System.out.println(titleField.getFragments()[0].toString());}HighlightField contentField = hit.getHighlightFields().get("description");if (contentField != null) {System.out.println(contentField.getFragments()[0].toString());}}// 异步方式发送请求/*restHighLevelClient.searchAsync(searchRequest, RequestOptions.DEFAULT, new ActionListener<SearchResponse>() {@Overridepublic void onResponse(SearchResponse searchResponse) {System.out.println("执行情况: " + searchResponse);}@Overridepublic void onFailure(Exception e) {System.out.println("执行失败的原因:" + e.getMessage());}});*/return searchResponse;}
}
1.6 测试类
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 新建索引@Testvoid createIndex() throws IOException {CreateIndexResponse createIndexResponse = iRestHighLevelClientService.createIndex();System.out.println("新建的索引是:" + createIndexResponse.index());}// 删除索引@Testvoid deleteIndex() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.deleteIndex();System.out.println("删除索引是否成功:" + acknowledgedResponse.isAcknowledged());}// 查看索引是否存在@Testvoid existIndex() throws IOException {Boolean aBoolean = iRestHighLevelClientService.existIndex();System.out.println("索引是否存在:" + aBoolean);}// 更新索引的settings配置@Testvoid updateIndexSettings() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.updateIndexSettings();System.out.println("是否更新settings配置成功:" + acknowledgedResponse.isAcknowledged());}// 更新索引的mapping配置@Testvoid updateIndexMapping() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.updateIndexMapping();System.out.println("是否更新mapping配置成功:" + acknowledgedResponse.isAcknowledged());}// 新增文档@Testvoid addDocument() throws IOException {IndexResponse indexResponse = iRestHighLevelClientService.addDocument();System.out.println("新增文档是否成功:" + indexResponse.status());}// 修改文档@Testvoid addDocumentByCon() throws IOException {UpdateResponse updateResponse = iRestHighLevelClientService.updateDocument();System.out.println("修改文档是否成功:" + updateResponse.status());}// 根据id删除文档@Testvoid deleteDocumentById() throws IOException {DeleteResponse deleteResponse = iRestHighLevelClientService.deleteDocumentById();System.out.println("删除文档是否成功:" + deleteResponse.status());}// 根据条件删除文档@Testvoid deleteDocumentByCon() throws IOException {BulkByScrollResponse bulkByScrollResponse = iRestHighLevelClientService.deleteDocumentByCon();System.out.println("删除文档是否成功:" + bulkByScrollResponse.getDeleted());}// 批量操作文档@Testvoid bulkDocument() throws IOException {BulkResponse bulkItemResponses = iRestHighLevelClientService.bulkDocument();System.out.println("批量操作文档是否成功:" + bulkItemResponses.status());}// 查询操作1@Testvoid searchDocument1() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument1();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}// 查询操作2@Testvoid searchDocument2() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument2();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}// 高亮查询@Testvoid searchDocument3() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument3();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}
}
1.7 启动类
package com.example.springbootelasticsearch1;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootElasticsearch1Application {public static void main(String[] args) {SpringApplication.run(SpringBootElasticsearch1Application.class, args);}}
1.8 测试
1.8.1创建索引
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 新建索引@Testvoid createIndex() throws IOException {CreateIndexResponse createIndexResponse = iRestHighLevelClientService.createIndex();System.out.println("新建的索引是:" + createIndexResponse.index());}
}
1.8.2 删除索引
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 删除索引@Testvoid deleteIndex() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.deleteIndex();System.out.println("删除索引是否成功:" + acknowledgedResponse.isAcknowledged());}
}
1.8.3 查看索引是否存在
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 查看索引是否存在@Testvoid existIndex() throws IOException {Boolean aBoolean = iRestHighLevelClientService.existIndex();System.out.println("索引是否存在:" + aBoolean);}
}
我们再次新建索引:
1.8.4 更新索引的settings配置
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 更新索引的settings配置@Testvoid updateIndexSettings() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.updateIndexSettings();System.out.println("是否更新settings配置成功:" + acknowledgedResponse.isAcknowledged());}
}
1.8.5 更新索引的mapping配置
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 更新索引的mapping配置@Testvoid updateIndexMapping() throws IOException {AcknowledgedResponse acknowledgedResponse = iRestHighLevelClientService.updateIndexMapping();System.out.println("是否更新mapping配置成功:" + acknowledgedResponse.isAcknowledged());}
}
1.8.6 新增文档
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.index.IndexResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 新增文档@Testvoid addDocument() throws IOException {IndexResponse indexResponse = iRestHighLevelClientService.addDocument();System.out.println("新增文档是否成功:" + indexResponse.status());}
}
1.8.7 修改文档
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.update.UpdateResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 修改文档@Testvoid addDocumentByCon() throws IOException {UpdateResponse updateResponse = iRestHighLevelClientService.updateDocument();System.out.println("修改文档是否成功:" + updateResponse.status());}
}
1.8.8 根据id删除文档
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.delete.DeleteResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 根据id删除文档@Testvoid deleteDocumentById() throws IOException {DeleteResponse deleteResponse = iRestHighLevelClientService.deleteDocumentById();System.out.println("删除文档是否成功:" + deleteResponse.status());}
}
1.8.9 根据条件删除文档
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 根据条件删除文档@Testvoid deleteDocumentByCon() throws IOException {BulkByScrollResponse bulkByScrollResponse = iRestHighLevelClientService.deleteDocumentByCon();System.out.println("删除文档是否成功:" + bulkByScrollResponse.getDeleted());}
}
新增一条文档,然后再进行测试:
1.8.10 批量操作文档
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.bulk.BulkResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 批量操作文档@Testvoid bulkDocument() throws IOException {BulkResponse bulkItemResponses = iRestHighLevelClientService.bulkDocument();System.out.println("批量操作文档是否成功:" + bulkItemResponses.status());}
}
1.8.11 查询操作1
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.search.SearchResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 查询操作1@Testvoid searchDocument1() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument1();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}
}
1.8.12 查询操作2
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.search.SearchResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 查询操作2@Testvoid searchDocument2() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument2();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}
}
1.8.13 高亮查询
package com.example.springbootelasticsearch1;import com.example.springbootelasticsearch1.service.IRestHighLevelClientService;
import org.elasticsearch.action.search.SearchResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTest
class SpringBootElasticsearch1ApplicationTests {@Autowiredprivate IRestHighLevelClientService iRestHighLevelClientService;// 高亮查询@Testvoid searchDocument3() throws IOException {SearchResponse searchResponse = iRestHighLevelClientService.searchDocument3();System.out.println("查询数据的总数:" + searchResponse.getHits().getHits().length);System.out.println("符合条件的文档最大得分: " + searchResponse.getHits().getMaxScore());}
}
1.9 自定义查询
-
matchQuery
:词条匹配,先分词然后在调用termQuery进行匹配 -
termQuery
:词条匹配,不分词 -
wildcardQuery
:通配符匹配 -
fuzzyQuery
:模糊匹配 -
rangeQuery
:范围匹配 -
booleanQuery
:布尔查询
match query (词条匹配,先分词然后在调用termQuery进行匹配)
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("title", "小米手机"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
termQuery (词条匹配,不分词)
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery("title", "小米"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
fuzzyQuery (模糊匹配)
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.fuzzyQuery("title", "小米"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
booleanQuery (布尔查询)
BooleanClause
用于表示布尔查询子句关系的类,包括:BooleanClause.Occur.MUST
,
BooleanClause.Occur.MUST_NOT
,BooleanClause.Occur.SHOULD
。
必须包含,不能包含,可以包含三种。
有以下6种组合:
1.MUST
和MUST
:交集。
2.MUST
和MUST_NOT
:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
3.SHOULD
与MUST_NOT
:连用时,功能同MUST和MUST_NOT。
4.SHOULD
与MUST
连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD
:并集。
6.MUST_NOT
和MUST_NOT
:无意义,检索无结果。
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("title", "手机")).must(QueryBuilders.termQuery("brand", "小米")));searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
RangeQuery 范围查找
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.rangeQuery("price").from(3000).to(4000));
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
wildcardQuery 通配符匹配
String indexName = "student";
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.wildcardQuery("title", "%小米%"));
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
2、spring-boot-starter-data-elasticsearch方式
使用ElasticsearchRepository
进行操作,ElasticSearchRepository
方式主要通过注解和对接口实现的方式
来实现ES的操作,我们在实体类上通过注解配置ES索引的映射关系后,当实现了ElasticSearchRepository接口的
类第一次操作ES进行插入文档的时候,ES会自动生成所需要的一切。但是该种方式无法实现高亮查询,想要实现
高亮查询只能使用RestHighLevelClient
。
想要使用高版本,在创建实体的@Document
属性中不可以加入type = "_doc"
2.1 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring-boot-elasticsearch2</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-elasticsearch2</name><description>spring-boot-elasticsearch2</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2.2 配置类和配置文件
package com.example.springbootelasticsearch2.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;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;@Configuration
public class EsConfig extends AbstractElasticsearchConfiguration {@Value("${elasticsearch.hostname}")private String hostname;@Value("${elasticsearch.port}")private int port;@Override@Beanpublic RestHighLevelClient elasticsearchClient() {final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo(hostname + ":" + port).build();return RestClients.create(clientConfiguration).rest();}
}
# es配置
elasticsearch.hostname=127.0.0.1
elasticsearch.port=9200# 默认配置,在本地启动的时候可以不配置
# spring.elasticsearch.rest.uris=http://127.0.0.1:9200
2.3 创建实体类
package com.example.springbootelasticsearch2.entity;import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;import java.util.Date;@Document(indexName = "book", createIndex = true)
public class Book {@Id@Field(type = FieldType.Text)private String id;@Field(type = FieldType.Text, analyzer = "ik_max_word")private String title;@Field(type = FieldType.Text, analyzer = "ik_max_word")private String author;@Field(type = FieldType.Double)private Double price;@Field(type = FieldType.Date, format = DateFormat.basic_date_time)private Date createTime;@Field(type = FieldType.Date, format = DateFormat.basic_date_time)private Date updateTime;public Book() {}public Book(String id, String title, String author, Double price, Date createTime, Date updateTime) {this.id = id;this.title = title;this.author = author;this.price = price;this.createTime = createTime;this.updateTime = updateTime;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}
}
createIndex = true
:无需手动创建Book索引,SpringBoot启动自动创建。
@Document
: 作用在类,标记实体类为文档对象,一般有四个属性:
indexName
:对应索引库名称shards
:分片数量,默认5replicas
:副本数量,默认1type
:用来指定索引类型,7.x以后的版本移除了
@Id
:作用在成员变量,标记一个字段作为id主键,用来将对象中id和ES中_id映射。
@Field
:作用在成员变量,标记为文档的字段,并指定字段映射属性:
type
:字段类型,取值是枚举:FieldType,具体的数据类型有:text、keyword、long、short、
date、integer、object、byte、double、float、half_float、scaled_float
index
:是否索引,布尔类型,默认是true
store
:是否存储,布尔类型,默认是false
analyzer
:分词器名称,用来指定使用哪种分词器
format
:时间格式
fielddata
:聚类的时候使用
@Transient
:默认情况下,存储或检索文档时,所有字段都映射到文档,此注释不包括该字段。
2.4 创建Repository仓库
package com.example.springbootelasticsearch2.repository;import com.example.springbootelasticsearch2.entity.Book;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.HighlightField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List;public interface ESBookRepository extends ElasticsearchRepository<Book, String> {List<Book> findByTitleOrAuthor(String title, String author);@Highlight(fields = {@HighlightField(name = "title"),@HighlightField(name = "author")})@Query("{\"match\":{\"title\":\"?0\"}}")SearchHits<Book> find(String keyword);
}
2.5 Service
package com.example.springbootelasticsearch2.service;public interface BookService {
}
package com.example.springbootelasticsearch2.service.impl;import com.example.springbootelasticsearch2.repository.ESBookRepository;
import com.example.springbootelasticsearch2.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Service;@Service
public class BookServiceImpl implements BookService {@Autowiredprivate ESBookRepository esBookRepository;@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;
}
2.6 测试类
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 创建索引*/@Testpublic void testCreateIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);Document mapping = indexOperations.createMapping();indexOperations.putMapping(mapping);}/*** 删除索引*/@Testpublic void testDeleteIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);indexOperations.delete();}/*** 索引是否存在*/@Testpublic void testExistsIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);indexOperations.exists();}/*** 新增文档*/@Testvoid addDocument() {Book book1 = new Book("1", "《西游记》", "吴承恩", 49.9, new Date(), new Date());esBookRepository.save(book1);Book book2 = new Book("2", "《红楼梦》", "曹雪芹", 59.9, new Date(), new Date());esBookRepository.save(book2);Book book3 = new Book("3", "《三国演义》", "罗贯中", 39.9, new Date(), new Date());esBookRepository.save(book3);Book book4 = new Book("4", "《水浒传》", "施耐庵", 69.9, new Date(), new Date());esBookRepository.save(book4);}/*** 一次新增多条文档*/@Testpublic void addManyDocument() {List<Book> books = new ArrayList<Book>();Book book1 = new Book("1", "《西游记》", "吴承恩", 49.9, new Date(), new Date());Book book2 = new Book("2", "《红楼梦》", "曹雪芹", 59.9, new Date(), new Date());Book book3 = new Book("3", "《三国演义》", "罗贯中", 39.9, new Date(), new Date());Book book4 = new Book("4", "《水浒传》", "施耐庵", 69.9, new Date(), new Date());books.add(book1);books.add(book2);books.add(book3);books.add(book4);esBookRepository.saveAll(books);}/*** 判断某id的文档是否存在*/@Testvoid documentExist() {boolean exists = esBookRepository.existsById("2");System.out.println(exists);}/*** 修改文档*/@Testvoid updateDocument() {Book book = new Book("1", "《西游记》", "吴承恩", 149.9, new Date(), new Date());esBookRepository.save(book);}/*** 删除文档*/@Testvoid deleteDocument() {esBookRepository.deleteById("1");}/*** 删除所有文档*/@Testvoid deleteAllDocument() {esBookRepository.deleteAll();}/*** 根据id查询文档*/@Testvoid queryDocumentByID() {Optional<Book> book = esBookRepository.findById("1");System.out.println(book.get());}/*** 查询所有文档*/@Testvoid queryAllDocument() {Iterable<Book> all = esBookRepository.findAll();all.forEach(System.out::println);}/*** 排序文档*/@Testvoid sortAllDocument() {Iterable<Book> all = esBookRepository.findAll(Sort.by(Sort.Order.asc("price")));all.forEach(System.out::println);}// 分页@Testvoid pageDocument() {// SpringBoot2.5.6已经移除了ElasticsearchRepository里的search()方法,只剩了一些特别基础的增删改查,基本上是不能用的。// 官方明显是想让开发者用ElasticsearchRestTemplate去做。MatchAllQueryBuilder matchQueryBuilder = QueryBuilders.matchAllQuery();NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchQueryBuilder);nativeSearchQuery.setPageable(PageRequest.of(2, 1));SearchHits<Book> search = elasticsearchRestTemplate.search(nativeSearchQuery, Book.class);for (SearchHit<Book> hit : search.getSearchHits()) {System.out.println(hit.getContent().getTitle());}}// 自定义查询@Testvoid query1() {List<Book> book = esBookRepository.findByTitleOrAuthor("《红楼梦》", "曹雪芹");book.forEach(System.out::println);}// 自定义json规则查询@Testvoid query2() {SearchHits<Book> book = esBookRepository.find("《红楼梦》");// SearchHit{id='2', score=3.1789374, sortValues=[], content=com.example.springbootelasticsearch2.entity.Book@48cb2d73,// highlightFields={title=[《<em>红楼梦</em>》]}}book.forEach(System.out::println);}}
2.7 启动类
package com.example.springbootelasticsearch2;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootElasticsearch2Application {public static void main(String[] args) {SpringApplication.run(SpringBootElasticsearch2Application.class, args);}}
2.8 测试
2.8.1 新建索引
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.document.Document;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 创建索引*/@Testpublic void testCreateIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);Document mapping = indexOperations.createMapping();indexOperations.putMapping(mapping);}
}
2.8.2 删除索引
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 删除索引*/@Testpublic void testDeleteIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);indexOperations.delete();}
}
2.8.3 索引是否存在
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 索引是否存在*/@Testpublic void testExistsIndex() {IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);indexOperations.exists();}
}
2.8.4 新增文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;import java.util.Date;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 新增文档*/@Testvoid addDocument() {Book book1 = new Book("1", "《西游记》", "吴承恩", 49.9, new Date(), new Date());esBookRepository.save(book1);Book book2 = new Book("2", "《红楼梦》", "曹雪芹", 59.9, new Date(), new Date());esBookRepository.save(book2);Book book3 = new Book("3", "《三国演义》", "罗贯中", 39.9, new Date(), new Date());esBookRepository.save(book3);Book book4 = new Book("4", "《水浒传》", "施耐庵", 69.9, new Date(), new Date());esBookRepository.save(book4);}
}
2.8.5 判断某id的文档是否存在
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 判断某id的文档是否存在*/@Testvoid documentExist() {boolean exists = esBookRepository.existsById("2");System.out.println(exists);}}
2.8.6 修改文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import java.util.Date;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 修改文档*/@Testvoid updateDocument() {Book book = new Book("1", "《西游记》", "吴承恩", 149.9, new Date(), new Date());esBookRepository.save(book);}
}
2.8.7 删除文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 删除文档*/@Testvoid deleteDocument() {esBookRepository.deleteById("1");}
}
2.8.8 刪除所有文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 删除所有文档*/@Testvoid deleteAllDocument() {esBookRepository.deleteAll();}}
2.8.9 一次新增多条文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import java.util.ArrayList;
import java.util.Date;
import java.util.List;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 一次新增多条文档*/@Testpublic void addManyDocument() {List<Book> books = new ArrayList<Book>();Book book1 = new Book("1", "《西游记》", "吴承恩", 49.9, new Date(), new Date());Book book2 = new Book("2", "《红楼梦》", "曹雪芹", 59.9, new Date(), new Date());Book book3 = new Book("3", "《三国演义》", "罗贯中", 39.9, new Date(), new Date());Book book4 = new Book("4", "《水浒传》", "施耐庵", 69.9, new Date(), new Date());books.add(book1);books.add(book2);books.add(book3);books.add(book4);esBookRepository.saveAll(books);}}
2.8.10 根据id查询文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import java.util.Optional;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 根据id查询文档*/@Testvoid queryDocumentByID() {Optional<Book> book = esBookRepository.findById("2");System.out.println(book.get());}
}
2.8.11 查询所有文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import java.util.Optional;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 查询所有文档*/@Testvoid queryAllDocument() {Iterable<Book> all = esBookRepository.findAll();all.forEach(System.out::println);}
}
2.8.12 排序文档
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;/*** 排序文档*/@Testvoid sortAllDocument() {Iterable<Book> all = esBookRepository.findAll(Sort.by(Sort.Order.asc("price")));all.forEach(System.out::println);}}
2.8.13 分页
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;// 分页@Testvoid pageDocument() {// SpringBoot2.5.6已经移除了ElasticsearchRepository里的search()方法,只剩了一些特别基础的增删改查,基本上是不能用的。// 官方明显是想让开发者用ElasticsearchRestTemplate去做。MatchAllQueryBuilder matchQueryBuilder = QueryBuilders.matchAllQuery();NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchQueryBuilder);nativeSearchQuery.setPageable(PageRequest.of(2, 1));SearchHits<Book> search = elasticsearchRestTemplate.search(nativeSearchQuery, Book.class);for (SearchHit<Book> hit : search.getSearchHits()) {System.out.println(hit.getContent().getTitle());}}}
2.8.14 自定义查询
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;import java.util.List;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;// 自定义查询@Testvoid query1() {List<Book> book = esBookRepository.findByTitleOrAuthor("《红楼梦》", "曹雪芹");book.forEach(System.out::println);}}
2.8.15 自定义json规则查询
package com.example.springbootelasticsearch2;import com.example.springbootelasticsearch2.entity.Book;
import com.example.springbootelasticsearch2.repository.ESBookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;@SpringBootTest
class SpringBootElasticsearch2ApplicationTests {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate ESBookRepository esBookRepository;// 自定义json规则查询@Testvoid query2() {SearchHits<Book> book = esBookRepository.find("《红楼梦》");// SearchHit{id='2', score=3.1789374, sortValues=[], content=com.example.springbootelasticsearch2.entity.Book@48cb2d73, // highlightFields={title=[《<em>红楼梦</em>》]}}book.forEach(System.out::println);}}
2.9 自定义查询规则
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
LessThanEqual | findByPriceLessThan | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
GreaterThanEqual | findByPriceGreaterThan | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
Contains/Containing | findByNameContaining | {"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}} |
In | findByNameIn (Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn (Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
Near | findByStoreNear | Not Supported Yet ! |
True | findByAvailableTrue | {"bool" : {"must" : {"field" : {"available" : true}}}} |
False | findByAvailableFalse | {"bool" : {"must" : {"field" : {"available" : false}}}} |
OrderBy | findByAvailable TrueOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}} |
我们只要按照上面的定义在接口中定义相应的方法,无须写实现就可实现我们想要的功能。
系统提供的查询方法中findBy
是一个固定写法,像上面我们定义的方法findByTitle
,其中Title
是我们实体
类中的属性名,这个必须对应上。findByTitle
是下面这样定义的:
{"bool" : {"must" : {"field" : {"title" : "?"}}}}
假如我们现在有个需求需要按照作者查询书籍,我们可以在BookRepository
中定义一个方法,如下:
// 根据作者查询书籍
List<User> findByAuthor(String author);
那么我们可以使用该方法:
@Test
public void testFindBookByAuthor(){List<Book> bookList = bookRepository.findByAuthor("曹雪芹");bookList.forEach(System.out::println);
}
其实就是框架底层直接使用下面的命令帮我们实现的查询:
GET /book/_search
{"query": {"bool": {"must": [{"term": {"author":"曹雪芹"}}]}}
}
ElasticSearchRepository
实现不了高亮查询,想要实现高亮查询还是需要使用RestHighLevelClient
方式。
3、transport方式(7.x开始弃用)
使用TransportClient
进行操作
3.1 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring-boot-elasticsearch3</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-elasticsearch3</name><description>spring-boot-elasticsearch3</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>7.12.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
3.2 配置文件
elasticsearch.cluster-name = elasticsearch
elasticsearch.ip = 127.0.0.1
elasticsearch.port = 9300
elasticsearch.pool = 5
3.3 创建配置类
package com.example.springbootelasticsearch3.config;import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.net.InetAddress;/*** @author zhangshixing* @date 2021年11月11日 12:28*/
@Slf4j
@Configuration
public class ElasticSearchConfig {@Value("${elasticsearch.ip}")private String hostName;/*** 端口*/@Value("${elasticsearch.port}")private String port;/*** 集群名称*/@Value("${elasticsearch.cluster-name}")private String clusterName;/*** 连接池*/@Value("${elasticsearch.pool}")private String poolSize;/*** Bean name default 函数名字** @return*/@Bean(name = "transportClient")public TransportClient transportClient() {log.info("Elasticsearch初始化开始。。。。。");TransportClient transportClient = null;try {// 配置信息Settings esSetting = Settings.builder()//集群名字.put("cluster.name", clusterName)//增加嗅探机制,找到ES集群.put("client.transport.sniff", true)//增加线程池个数,暂时设为5.put("thread_pool.search.size", Integer.parseInt(poolSize)).build();//配置信息Settings自定义transportClient = new PreBuiltTransportClient(esSetting);TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(hostName), Integer.valueOf(port));transportClient.addTransportAddresses(transportAddress);} catch (Exception e) {log.error("elasticsearch TransportClient create error!!", e);}return transportClient;}
}
3.4 创建工具类
package com.example.springbootelasticsearch3.utils;import java.util.List;
import java.util.Map;/*** @author zhangshixing* @date 2021年11月11日 12:42*/
public class EsPage {/*** 当前页*/private int currentPage;/*** 每页显示多少条*/private int pageSize;/*** 总记录数*/private int recordCount;/*** 本页的数据列表*/private List<Map<String, Object>> recordList;/*** 总页数*/private int pageCount;/*** 页码列表的开始索引(包含)*/private int beginPageIndex;/*** 页码列表的结束索引(包含)*/private int endPageIndex;/*** 只接受前4个必要的属性,会自动的计算出其他3个属性的值** @param currentPage* @param pageSize* @param recordCount* @param recordList*/public EsPage(int currentPage, int pageSize, int recordCount, List<Map<String, Object>> recordList) {this.currentPage = currentPage;this.pageSize = pageSize;this.recordCount = recordCount;this.recordList = recordList;// 计算总页码pageCount = (recordCount + pageSize - 1) / pageSize;// 计算 beginPageIndex 和 endPageIndex// >> 总页数不多于10页,则全部显示if (pageCount <= 10) {beginPageIndex = 1;endPageIndex = pageCount;}// >> 总页数多于10页,则显示当前页附近的共10个页码else {// 当前页附近的共10个页码(前4个 + 当前页 + 后5个)beginPageIndex = currentPage - 4;endPageIndex = currentPage + 5;// 当前面的页码不足4个时,则显示前10个页码if (beginPageIndex < 1) {beginPageIndex = 1;endPageIndex = 10;}// 当后面的页码不足5个时,则显示后10个页码if (endPageIndex > pageCount) {endPageIndex = pageCount;beginPageIndex = pageCount - 10 + 1;}}}public int getCurrentPage() {return currentPage;}public void setCurrentPage(int currentPage) {this.currentPage = currentPage;}public int getPageSize() {return pageSize;}public void setPageSize(int pageSize) {this.pageSize = pageSize;}public int getRecordCount() {return recordCount;}public void setRecordCount(int recordCount) {this.recordCount = recordCount;}public List<Map<String, Object>> getRecordList() {return recordList;}public void setRecordList(List<Map<String, Object>> recordList) {this.recordList = recordList;}public int getPageCount() {return pageCount;}public void setPageCount(int pageCount) {this.pageCount = pageCount;}public int getBeginPageIndex() {return beginPageIndex;}public void setBeginPageIndex(int beginPageIndex) {this.beginPageIndex = beginPageIndex;}public int getEndPageIndex() {return endPageIndex;}public void setEndPageIndex(int endPageIndex) {this.endPageIndex = endPageIndex;}}
package com.example.springbootelasticsearch3.utils;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;/*** @author zhangshixing* @date 2021年11月11日 12:39*/
@Component
@Slf4j
public class ElasticsearchUtil {@Autowiredprivate TransportClient transportClient;private static TransportClient client;/*** @PostContruct是spring框架的注解 spring容器初始化的时候执行该方法*/@PostConstructpublic void init() {client = this.transportClient;}/*** 创建索引** @param index* @return*/public static boolean createIndex(String index) {if (!isIndexExist(index)) {log.info("Index is not exits!");}CreateIndexResponse indexResponse = client.admin().indices().prepareCreate(index).execute().actionGet();log.info("执行建立成功?" + indexResponse.isAcknowledged());return indexResponse.isAcknowledged();}/*** 删除索引** @param index* @return*/public static boolean deleteIndex(String index) {if (!isIndexExist(index)) {log.info("Index is not exits!");}AcknowledgedResponse dResponse = client.admin().indices().prepareDelete(index).execute().actionGet();if (dResponse.isAcknowledged()) {log.info("delete index " + index + " successfully!");} else {log.info("Fail to delete index " + index);}return dResponse.isAcknowledged();}/*** 判断索引是否存在** @param index* @return*/public static boolean isIndexExist(String index) {IndicesExistsResponse inExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(index)).actionGet();if (inExistsResponse.isExists()) {log.info("Index [" + index + "] is exist!");} else {log.info("Index [" + index + "] is not exist!");}return inExistsResponse.isExists();}/*** 数据添加,正定ID** @param jsonObject 要增加的数据* @param index 索引,类似数据库* @param type 类型,类似表* @param id 数据ID* @return*/public static String addData(JSONObject jsonObject, String index, String type, String id) {IndexResponse response = client.prepareIndex(index, type, id).setSource(jsonObject).get();log.info("addData response status:{},id:{}", response.status().getStatus(), response.getId());return response.getId();}/*** 数据添加** @param jsonObject 要增加的数据* @param index 索引,类似数据库* @param type 类型,类似表* @return*/public static String addData(JSONObject jsonObject, String index, String type) {return addData(jsonObject, index, type, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());}/*** 通过ID删除数据** @param index 索引,类似数据库* @param type 类型,类似表* @param id 数据ID*/public static void deleteDataById(String index, String type, String id) {DeleteResponse response = client.prepareDelete(index, type, id).execute().actionGet();log.info("deleteDataById response status:{},id:{}", response.status().getStatus(), response.getId());}/*** 通过ID 更新数据** @param jsonObject 要增加的数据* @param index 索引,类似数据库* @param type 类型,类似表* @param id 数据ID* @return*/public static void updateDataById(JSONObject jsonObject, String index, String type, String id) {UpdateRequest updateRequest = new UpdateRequest();updateRequest.index(index).type(type).id(id).doc(jsonObject);client.update(updateRequest);}/*** 通过ID获取数据** @param index 索引,类似数据库* @param type 类型,类似表* @param id 数据ID* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)* @return*/public static Map<String, Object> searchDataById(String index, String type, String id, String fields) {GetRequestBuilder getRequestBuilder = client.prepareGet(index, type, id);if (StringUtils.isNotEmpty(fields)) {getRequestBuilder.setFetchSource(fields.split(","), null);}GetResponse getResponse = getRequestBuilder.execute().actionGet();return getResponse.getSource();}/*** 使用分词查询,并分页** @param index 索引名称* @param type 类型名称,可传入多个type逗号分隔* @param startPage 当前页* @param pageSize 每页显示条数* @param query 查询条件* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)* @param sortField 排序字段* @param highlightField 高亮字段* @return*/public static EsPage searchDataPage(String index, String type, int startPage, int pageSize, QueryBuilder query, String fields, String sortField, String highlightField) {SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index);if (StringUtils.isNotEmpty(type)) {searchRequestBuilder.setTypes(type.split(","));}searchRequestBuilder.setSearchType(SearchType.QUERY_THEN_FETCH);// 需要显示的字段,逗号分隔(缺省为全部字段)if (StringUtils.isNotEmpty(fields)) {searchRequestBuilder.setFetchSource(fields.split(","), null);}//排序字段if (StringUtils.isNotEmpty(sortField)) {searchRequestBuilder.addSort(sortField, SortOrder.DESC);}// 高亮(xxx=111,aaa=222)if (StringUtils.isNotEmpty(highlightField)) {HighlightBuilder highlightBuilder = new HighlightBuilder();//highlightBuilder.preTags("<span style='color:red' >");//设置前缀//highlightBuilder.postTags("</span>");//设置后缀// 设置高亮字段highlightBuilder.field(highlightField);searchRequestBuilder.highlighter(highlightBuilder);}//searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());searchRequestBuilder.setQuery(query);// 分页应用searchRequestBuilder.setFrom(startPage).setSize(pageSize);// 设置是否按查询匹配度排序searchRequestBuilder.setExplain(true);//打印的内容 可以在 Elasticsearch head 和 Kibana 上执行查询log.info("\n{}", searchRequestBuilder);// 执行搜索,返回搜索响应信息SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();TotalHits totalHits = searchResponse.getHits().getTotalHits();long length = searchResponse.getHits().getHits().length;log.debug("共查询到[{}]条数据,处理数据条数[{}]", totalHits.value, length);if (searchResponse.status().getStatus() == 200) {// 解析对象List<Map<String, Object>> sourceList = setSearchResponse(searchResponse, highlightField);return new EsPage(startPage, pageSize, (int) totalHits.value, sourceList);}return null;}/*** 使用分词查询** @param index 索引名称* @param type 类型名称,可传入多个type逗号分隔* @param query 查询条件* @param size 文档大小限制* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)* @param sortField 排序字段* @param highlightField 高亮字段* @return*/public static List<Map<String, Object>> searchListData(String index, String type, QueryBuilder query, Integer size, String fields, String sortField, String highlightField) {SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index);if (StringUtils.isNotEmpty(type)) {searchRequestBuilder.setTypes(type.split(","));}if (StringUtils.isNotEmpty(highlightField)) {HighlightBuilder highlightBuilder = new HighlightBuilder();// 设置高亮字段highlightBuilder.field(highlightField);searchRequestBuilder.highlighter(highlightBuilder);}searchRequestBuilder.setQuery(query);if (StringUtils.isNotEmpty(fields)) {searchRequestBuilder.setFetchSource(fields.split(","), null);}searchRequestBuilder.setFetchSource(true);if (StringUtils.isNotEmpty(sortField)) {searchRequestBuilder.addSort(sortField, SortOrder.DESC);}if (size != null && size > 0) {searchRequestBuilder.setSize(size);}//打印的内容 可以在 Elasticsearch head 和 Kibana 上执行查询log.info("\n{}", searchRequestBuilder);SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();TotalHits totalHits = searchResponse.getHits().getTotalHits();long length = searchResponse.getHits().getHits().length;log.info("共查询到[{}]条数据,处理数据条数[{}]", totalHits.value, length);if (searchResponse.status().getStatus() == 200) {// 解析对象return setSearchResponse(searchResponse, highlightField);}return null;}/*** 高亮结果集 特殊处理** @param searchResponse* @param highlightField*/private static List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {List<Map<String, Object>> sourceList = new ArrayList<Map<String, Object>>();StringBuffer stringBuffer = new StringBuffer();for (SearchHit searchHit : searchResponse.getHits().getHits()) {searchHit.getSourceAsMap().put("id", searchHit.getId());if (StringUtils.isNotEmpty(highlightField)) {System.out.println("遍历 高亮结果集,覆盖 正常结果集" + searchHit.getSourceAsMap());Text[] text = searchHit.getHighlightFields().get(highlightField).getFragments();if (text != null) {for (Text str : text) {stringBuffer.append(str.string());}//遍历 高亮结果集,覆盖 正常结果集searchHit.getSourceAsMap().put(highlightField, stringBuffer.toString());}}sourceList.add(searchHit.getSourceAsMap());}return sourceList;}
}
3.5 启动类
package com.example.springbootelasticsearch3;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootElasticsearch3Application {public static void main(String[] args) {SpringApplication.run(SpringBootElasticsearch3Application.class, args);}}
3.6 测试类
package com.example.springbootelasticsearch3;import com.alibaba.fastjson.JSONObject;
import com.example.springbootelasticsearch3.utils.ElasticsearchUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;/*** @author zhangshixing* @date 2021年11月11日 12:43*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class GoodsResiportyTest {/*** 类型*/private String esType = "external";/*** 索引*/private String indexName = "test_index";/*** 创建索引*/@Testpublic void createIndex() {if (!ElasticsearchUtil.isIndexExist(indexName)) {ElasticsearchUtil.createIndex(indexName);} else {System.out.print("索引已经存在");}System.out.print("索引创建成功");}/*** 删除索引*/@Testpublic void deleteIndex() {if (!ElasticsearchUtil.isIndexExist(indexName)) {System.out.print("索引不存在");} else {ElasticsearchUtil.deleteIndex(indexName);}System.out.print("索引删除成功");}/*** 索引是否存在*/@Testpublic void cexistsIndex() {if (!ElasticsearchUtil.isIndexExist(indexName)) {System.out.print("索引不存在");} else {System.out.print("索引存在");}}/*** 指定索引插入数据*/@Testpublic void insertJson() {JSONObject jsonObject = new JSONObject();jsonObject.put("id", DateUtils.formatDate(new Date()));jsonObject.put("age", 25);jsonObject.put("name", "j-" + new Random(100).nextInt());jsonObject.put("createTime", new Date());String id = ElasticsearchUtil.addData(jsonObject, indexName, esType, jsonObject.getString("id"));}@Testpublic void delete() {String id = "12";if (StringUtils.isNotBlank(id)) {ElasticsearchUtil.deleteDataById(indexName, esType, id);System.out.print("删除id=" + id);} else {System.out.print("id为空");}}@Testpublic void queryMatchData() {BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolean matchPhrase = false;if (matchPhrase == Boolean.TRUE) {boolQuery.must(QueryBuilders.matchPhraseQuery("name", "j"));} else {boolQuery.must(QueryBuilders.matchQuery("name", "j"));}List<Map<String, Object>> list = ElasticsearchUtil.searchListData(indexName, esType, boolQuery, 10, null, null, null);System.out.print(JSONObject.toJSONString(list));}
}
{"size":10,"query":{"bool":{"must":[{"match":{"name":{"query":"j","operator":"OR","prefix_length":0,"max_expansions":50,"fuzzy_transpositions":true,"lenient":false,"zero_terms_query":"NONE","auto_generate_synonyms_phrase_query":true,"boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":[],"excludes":[]}}
2022-06-23 10:59:36.190 INFO 18272 --- [ main] c.e.s.utils.ElasticsearchUtil : 共查询到[1]条数据,处理数据条数[1]
[{"createTime":"2022-06-23T02:56:35.337Z","name":"j--1193959466","id":"Thu, 23 Jun 2022 02:56:35 GMT","age":25}]