Elaticsearch简称为es, es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。es也使用 Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。 据国际权威的数据库产品评测机构DB Engines的统计,在2016年1月,ElasticSearch已超过Solr等,成 为排名第一的搜索引擎类应用。
ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html
其中的Java Rest Client又包括两种:
下表显示了Spring数据发布系列使用的Elasticsearch版本和其中包含的Spring数据Elasticsearch版本,以及涉及该特定Spring数据发布系列的Spring引导版本
本文记录了Spring Boot与Elasticsearch的整合方式,Spring boot的版本为2.6.4,Elasticsearch的版本为7.6.0。
注意:因为SpringBoot有默认的ES版本,所以我们需要覆盖默认的ES版本:
<!--引入es的RestHighLevelClient依赖:-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.0</version>
</dependency>
在SpringBoot中无需如此,可以直接导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
具体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.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sh</groupId>
<version>3.4.0</version>
<artifactId>sh-common-elasticsearch</artifactId>
<name>hcode-es-api-1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<!--自定义依赖版本-->
<elasticsearch.version>7.6.0</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
elasticsearch:
cluster-nodes: node1`:9200,node2:9200,node3:9200
cluster-name: my-es
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Data
@Configuration
@Component
@ConfigurationProperties("elasticsearch")
public class ESProperties {
/**
* 集群名称
*/
private String clusterName;
/**
* 集群地址
*/
private String clusterNodes;
}
然后编写配置文件,注入到Spring容器中
import lombok.RequiredArgsConstructor;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Configuration
public class ElasticsearchConfig {
@Autowired
private ESProperties esProperties;
@Bean
public RestHighLevelClient restHighLevelClient() {
// 初始化ES客户端的构造器
RestClientBuilder builder = RestClient.builder(httpHostHandlerDev());
return new RestHighLevelClient(builder);
}
private HttpHost[] httpHostHandlerDev() {
String[] hosts = esProperties.getClusterNodes().split(",");
HttpHost[] httpHosts = new HttpHost[hosts.length];
for (int i = 0; i < hosts.length; i++) {
httpHosts[i] = HttpHost.create(hosts[i]);
}
System.out.println();
return httpHosts;
}
}
注入RestHighLevelClient
@Autowired
private RestHighLevelClient esClient;
编写es util
import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.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.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*
* @author: lenovo
* @createTime: 2022/3/30
* @Time: 9:44
* Description: No Description
*/
@Component
public class EsUtils {
@Autowired
private RestHighLevelClient esClient;
/**
* 创建索引库
* @param indexName
* @return
* @throws IOException
*/
public boolean createIndex(String indexName) throws IOException {
CreateIndexRequest request = new CreateIndexRequest(indexName);
CreateIndexResponse response = esClient.indices().create(request, RequestOptions.DEFAULT);
return response.isAcknowledged();
}
/**
* 查看索引是否存在
* @param indexName
* @return
* @throws IOException
*/
public boolean existIndex(String indexName) throws IOException {
GetIndexRequest request = new GetIndexRequest(indexName);
return esClient.indices().exists(request, RequestOptions.DEFAULT);
}
/**
* 删除索引库
* @param indexName
* @throws IOException
*/
public boolean deleteHotelIndex(String indexName) throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
boolean delFlag = false;
// 1.创建Request对象
GetIndexRequest request1 = new GetIndexRequest(indexName);
// 2.发送请求
boolean exists = esClient.indices().exists(request1, RequestOptions.DEFAULT);
// 3.输出
System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
if (exists){
AcknowledgedResponse response = esClient.indices().delete(request, RequestOptions.DEFAULT);
delFlag = response.isAcknowledged();
System.out.println("删除成功");
}
return delFlag;
}
/**
* 新增文档数据
* @param indexName
* @param json
* @param id
* @throws IOException
*/
public void addDocument(String indexName,String json,String id) throws IOException {
// 1.准备Request对象
IndexRequest request = new IndexRequest(indexName).id(id);
// 2.准备Json文档
request.source(json, XContentType.JSON);
// 3.发送请求
IndexResponse response =esClient.index(request, RequestOptions.DEFAULT);
System.out.println(response.status());
}
/**
* 批量新增数据
* @param list
* @param indexName
* @param id
* @throws IOException
*/
public void testBulkDocument(List<String> list,String indexName,String id) throws IOException {
// 1.准备Request
BulkRequest request = new BulkRequest();
// 2.准备数据
for (String json : list){
request.add(new IndexRequest(indexName)
.id(id)
.source(json,XContentType.JSON));
}
// 3.发送请求
BulkResponse bulk = esClient.bulk(request,RequestOptions.DEFAULT);
System.out.println(bulk.status());// ok
}
/**
* 更新文档内容
* @param indexName
* @param json
* @param id
* @throws IOException
*/
public void updateDocument(String indexName,String json,String id) throws IOException {
// 1.准备Request
UpdateRequest request = new UpdateRequest(indexName, id);
// 2.准备请求参数
request.doc(json,XContentType.JSON);
// 3.发送请求
UpdateResponse response = esClient.update(request, RequestOptions.DEFAULT);
System.out.println(response.status()); // OK
}
/**
* 根据id 获取详情
* @param indexName
* @param id
* @return
* @throws IOException
*/
public String getDocumentById(String indexName,String id) throws IOException {
// 1.准备Request
GetRequest request = new GetRequest(indexName, id);
// 2.发送请求,得到响应
GetResponse response = esClient.get(request, RequestOptions.DEFAULT);
// 3.解析响应结果
String json = response.getSourceAsString();
return json;
}
/**
* 根据id删除文档
* @param indexName
* @param id
* @throws IOException
*/
public void deleteDocument(String indexName,String id) throws IOException {
// 1.准备Request
DeleteRequest request = new DeleteRequest(indexName, id);
// 2.发送请求
DeleteResponse response = esClient.delete(request, RequestOptions.DEFAULT);
System.out.println(response.status());// OK
}
/**
* 查询所有
* @param indexName
* @return
* @throws IOException
*/
public SearchHit[] matchAll(String indexName) throws IOException {
// 1 创建request对象
SearchRequest request = new SearchRequest(indexName);
// 2 准备参数 :DSL语句
request.source().query(QueryBuilders.matchAllQuery());
// 3.发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4. 解析
SearchHits searchHits = response.getHits();
// 获取总条数
long total = searchHits.getTotalHits().value;
// 获取文档数组
SearchHit[] hits = searchHits.getHits();
return hits;
}
/**
* 根据名称查询文档数据
* @param indexName
* @param name
* @param text
* @return
* @throws IOException
*/
public SearchHit[] match(String indexName,String name,String text) throws IOException {
// 1 创建request对象
SearchRequest request = new SearchRequest(indexName);
// 2 准备参数 :DSL语句
request.source().query(QueryBuilders.matchQuery(name,text));
// 3.发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4. 解析
SearchHits searchHits = response.getHits();
// 获取总条数
long total = searchHits.getTotalHits().value;
// 获取文档数组
SearchHit[] hits = searchHits.getHits();
return hits;
}
/**
* 排序分页查询
* @param indexName
* @param pageNum
* @param pageSize
* @return
* @throws IOException
*/
public SearchHit[] testPageSort(String indexName,int pageNum,int pageSize) throws IOException {
// 1 创建request对象
SearchRequest request = new SearchRequest(indexName);
// 2 准备参数 :DSL语句
request.source().query(QueryBuilders.matchAllQuery());
// 排序
// request.source().sort("price", SortOrder.ASC);
request.source().from((pageNum-1)*5).size(pageSize);
// 3.发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4. 解析
SearchHits searchHits = response.getHits();
// 获取总条数
long total = searchHits.getTotalHits().value;
// 获取文档数组
SearchHit[] hits = searchHits.getHits();
return hits;
}
/**
*高亮显示
* @param indexName
* @param name
* @param text
* @return
* @throws IOException
*/
public SearchHit[] testHighLight(String indexName,String name,String text) throws IOException {
// 1 创建request对象
SearchRequest request = new SearchRequest(indexName);
// 2 准备参数 :DSL语句
request.source().query(QueryBuilders.matchQuery(name,text));
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
// 3.发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4. 解析
SearchHits searchHits = response.getHits();
// 获取总条数
long total = searchHits.getTotalHits().value;
// 获取文档数组
SearchHit[] hits = searchHits.getHits();
return hits;
}
/**
* 搜索文档内容解析方法
* 其中HotelDoc为json转对象的实体类 需更具实际自定义
* @param response
*/
private void handleResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
// 获取总条数
long total = searchHits.getTotalHits().value;
// 获取文档数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit searchHit : hits) {
// 获取json
String json = searchHit.getSourceAsString();
// json 转对象
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
// 获取高亮结果
Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
if (!CollectionUtils.isEmpty(highlightFieldMap)){
// 更具字段名获取高亮结果
HighlightField highlightField = highlightFieldMap.get("name");
if (highlightField!=null){
// 获取高亮的值
String name = highlightField.getFragments()[0].toString();
// 覆盖高亮结果
hotelDoc.setName(name);
}
}
System.out.println(hotelDoc);
}
}
}
import com.alibaba.fastjson.JSON;
import com.sh.common.elasticsearch.config.ESProperties;
import com.sh.common.elasticsearch.util.EsUtils;
import com.sh.system.api.domain.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import org.junit.jupiter.api.Test;
@SpringBootTest
public class SpringbootTest {
@Autowired
private ESProperties esProperties;
@Autowired
private EsUtils esUtils;
@Test
void testMatchAll() throws IOException {
System.out.println(esUtils.getDocumentById("hotel","47066"));
}
}
需编写spring.factories来加载bean类!!
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sh.common.elasticsearch.config.ElasticsearchConfig,\
com.sh.common.elasticsearch.util.EsUtils,\
com.sh.common.elasticsearch.config.ESProperties
然后在另一个项目中直接加载该包
<dependency>
<groupId>com.sh</groupId>
<artifactId>sh-common-elasticsearch</artifactId>
<version>3.4.0</version>
</dependency>