Elasticsearch版本:7.9.3
ps:这里不使用springboot封装好类似与jpa的框架是因为在elasticsearch官方文档中并不推荐,并且在将来将会移除。
准备工作
1.设计好ES索引库,写好自己的Mode来接收elasticsearch返回的结果(也可以用String或JSON)
整合
1.引入依赖 (PS:因为Springboot自封装开箱的elasticsearch版本过低需要自己指定内部版本)
<!--指定springboot封装的es版本-->
<properties>
<elasticsearch.version>7.9.3</elasticsearch.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.编写Springboot配置类(PS:目的从配置文件中获取配置ES信息)
/**
* @description:
* @create: 2021/4/11
* @auther: twx 3094508274@qq.com
**/
@Data
//说明配置文件前缀
@ConfigurationProperties(prefix = "es")
//配置类注解
@Configuration
@Slf4j
public class ElasticsearchConfig {
//索引库
private String index;
//ES服务ip
private String ip;
//ES服务端口
private String port;
//ES请求 Http/Https
private String schema;
}
3.编写elasticsearchClient(PS:封装ES的Client,因为其底层是长连接可以初始化后无需关闭一直使用,所以可以在项目中初始化后一直使用)
@Component
@Slf4j
public class ElasticClient {
//注入配置文件读取到的信息
@Resource
ElasticsearchConfig config;
//初始化 RestHighLevelClient
private static RestHighLevelClient client = null;
//声明bean
@Bean
public RestHighLevelClient getClient() {
if (client != null) {
return client;
} else {
//保证长连接唯一
synchronized (ElasticClient.class) {
//初始化client连接
RestClientBuilder clientBuilder = RestClient.builder(new HttpHost(config.getIp(), Integer.parseInt(config.getPort()), config.getSchema()));
client = new RestHighLevelClient(clientBuilder);
log.info("创建ES连接成功");
return client;
}
}
}
}
4.封装Elasticsearch实体(PS:用于工具类的插入)
/**
* @description: elastic实体类
* @create: 2021/4/11
* @auther: twx 3094508274@qq.com
**/
@Data
public class ElasticEntity<T> {
private String id;
private T data;
}
5.封装Elasticsearch工具类(只做简单的封装,如分页返回,实体返回)
/**
* @description: es工具类封装
* @create: 2021/4/11
* @auther: twx 3094508274@qq.com
*
* 入参解释
* QueryBuilder 查询构造
* SortBuilder 排序构造
* elementType 转换实体
**/
@Component
@Slf4j
public class EsUtil {
private static ElasticsearchConfig config;
private static ElasticClient elasticClient;
@Autowired
public void setConfig(ElasticsearchConfig config) {
EsUtil.config = config;
}
@Autowired
public void setClient(ElasticClient elasticClient) {
EsUtil.elasticClient = elasticClient;
}
/** 默认索引库插入数据(单记录插入)
* @param entity
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:20
**/
@SneakyThrows
public static boolean insertOrUpdateOne(ElasticEntity entity) {
return insertOrUpdateOne(entity,config.getIndex());
}
/** 自定义索引库插入数据(单条)
* @param entity
* @param index
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:20
**/
@SneakyThrows
public static boolean insertOrUpdateOne(ElasticEntity entity,String index) {
IndexRequest request = new IndexRequest(index);
log.warn("Data: id={},entity={}", entity.getId(), entity.getData());
if (StrUtil.isNotEmpty(entity.getId())) {
request.id(entity.getId());
}
request.source(JSONObject.toJSONString(entity.getData(), SerializerFeature.WriteDateUseDateFormat), XContentType.JSON);
if (StrUtil.isNotEmpty(entity.getId())) {
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
}
IndexResponse indexResponse = elasticClient.getClient().index(request, RequestOptions.DEFAULT);
int status = indexResponse.status().getStatus();
if ((status == RestStatus.CREATED.getStatus()) || (status == RestStatus.OK.getStatus())) {
return true;
}
return false;
}
/** 默认索引库分页查询
* @param pageNum
* @param pageSize
* @param queryBuilder
* @param sortBuilderList
* @param elementType
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:22
**/
@SneakyThrows
public static <T> EsPage<T> queryPage(int pageNum, int pageSize, QueryBuilder queryBuilder, List<SortBuilder<?>> sortBuilderList, Class<T> elementType) {
return queryPage(pageNum,pageSize,queryBuilder,sortBuilderList,elementType,config.getIndex());
}
/** 使用自定义索引库分页查询(可多个索引库查询)
* @param pageNum
* @param pageSize
* @param queryBuilder
* @param sortBuilderList
* @param elementType
* @param values
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:23
**/
@SneakyThrows
public static <T> EsPage<T> queryPage(int pageNum, int pageSize, QueryBuilder queryBuilder, List<SortBuilder<?>> sortBuilderList,Class<T> elementType, String... values){
if (pageNum <= 1) {
pageNum = 0;
} else {
pageNum = pageNum - 1;
}
//构建Source字段
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder).from(pageNum * pageSize).size(pageSize);
if (CollUtil.isNotEmpty(sortBuilderList)) {
sortBuilderList.forEach(sortBuilder -> {
searchSourceBuilder.sort(sortBuilder);
});
}
//查询请求
SearchRequest request = new SearchRequest(values);
request.source(searchSourceBuilder);
//查询响应
SearchResponse searchResponse = elasticClient.getClient().search(request, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
List<String> list = new ArrayList<>();
for (SearchHit hit : hits) {
list.add(hit.getSourceAsString());
}
List<T> dataList = new ArrayList<>();
list.forEach(s -> {
T data = JSONObject.parseObject(s, elementType);
dataList.add(data);
});
EsPage<T> esPage = new EsPage<>();
esPage.setTotal(searchResponse.getHits().getTotalHits().value);
esPage.setPage(pageNum);
esPage.setData(dataList);
return esPage;
}
/** 使用默认索引库查询 非分页查询
* @param queryBuilder
* @param sortBuilderList
* @param elementType
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:24
**/
@SneakyThrows
public static <T> List<T> queryList(QueryBuilder queryBuilder, List<SortBuilder<?>> sortBuilderList, Class<T> elementType,int size) {
return queryList(queryBuilder,sortBuilderList,elementType,size,config.getIndex());
}
/** 自定义索引库查询 非分页查询(可多个索引库查询)
* @param queryBuilder
* @param sortBuilderList
* @param elementType
* @param size
* @param values
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:26
**/
@SneakyThrows
public static <T> List<T> queryList(QueryBuilder queryBuilder, List<SortBuilder<?>> sortBuilderList, Class<T> elementType,int size, String... values) {
//构建Source字段
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder).size(size);
if (CollUtil.isNotEmpty(sortBuilderList)) {
sortBuilderList.forEach(sortBuilder -> {
searchSourceBuilder.sort(sortBuilder);
});
}
//查询请求
SearchRequest request = new SearchRequest(values);
request.source(searchSourceBuilder);
//查询响应
SearchResponse searchResponse = elasticClient.getClient().search(request, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
List<String> list = new ArrayList<>();
for (SearchHit hit : hits) {
list.add(hit.getSourceAsString());
}
List<T> dataList = new ArrayList<>();
list.forEach(s -> {
T data = JSONObject.parseObject(s, elementType);
dataList.add(data);
});
return dataList;
}
/** 查询单个数据
* @param queryBuilder
* @param elementType
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:26
**/
@SneakyThrows
public static <T> EsOne<T> selectOne(QueryBuilder queryBuilder, Class<T> elementType) {
return selectOne(queryBuilder,elementType,config.getIndex());
}
/** 查询单个数据(可多个索引库)如有多条只返回第一个
* @param queryBuilder
* @param elementType
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:26
**/
@SneakyThrows
public static <T> EsOne<T> selectOne(QueryBuilder queryBuilder, Class<T> elementType, String... values) {
//构建Source字段
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
//查询请求
SearchRequest request = new SearchRequest(values);
request.source(searchSourceBuilder);
//查询响应
SearchResponse searchResponse = elasticClient.getClient().search(request, RequestOptions.DEFAULT);
SearchHit[] hit = searchResponse.getHits().getHits();
EsOne<T> one = new EsOne<>();
if (hit.length <= 0) {
return null;
}
one.setId(hit[0].getId());
T data = JSONObject.parseObject(hit[0].getSourceAsString(), elementType);
one.setData(data);
return one;
}
/** 默认索引库中删除
* @param id
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:30
**/
@SneakyThrows
public static void deleteById(String id) {
deleteById(id,config.getIndex());
}
/** 自定义索引库中删除
* @param id
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:30
**/
@SneakyThrows
public static void deleteById(String id,String index) {
DeleteRequest request = new DeleteRequest(index, id);
DeleteResponse deleteResponse = elasticClient.getClient().delete(request, RequestOptions.DEFAULT);
String result = deleteResponse.getResult().name();
if (!DocWriteResponse.Result.DELETED.name().equals(result)) {
throw new RuntimeException("删除失败,请联系管理员");
}
}
/** 默认索引库统计数量
* @param queryBuilder
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:30
**/
public static Long count(QueryBuilder queryBuilder) {
return count(queryBuilder,config.getIndex());
}
/** 自定义索引库
* @param queryBuilder
* @param values
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:31
**/
@SneakyThrows
public static Long count(QueryBuilder queryBuilder,String... values) {
CountRequest countRequest = new CountRequest(values);
countRequest.query(queryBuilder);
CountResponse countResponse = elasticClient.getClient().count(countRequest, RequestOptions.DEFAULT);
return countResponse.getCount();
}
/**
* 查询范围构造器 gte 大于等于 lte 小于等于 gt 大于 lt 小于
*
* @param fieldKey 查询字段
* @param start 大于值
* @param end 小于值
* @param e 是否开启等于条件 true开启
* @return
*/
public static RangeQueryBuilder rangeQueryBuilder(String fieldKey, String start, String end, boolean e) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(fieldKey);
if (e) {
if (StrUtil.isNotEmpty(start)) {
rangeQueryBuilder.gte(start);
}
if (StrUtil.isNotEmpty(end)) {
rangeQueryBuilder.lte(end);
}
} else {
if (StrUtil.isNotEmpty(start)) {
rangeQueryBuilder.gt(start);
}
if (StrUtil.isNotEmpty(end)) {
rangeQueryBuilder.lt(end);
}
}
return rangeQueryBuilder;
}
/** 带评分查询(尚未测试)
* @param suggestionBuilder
* @param num
* @author: twx 3094508274@qq.com
* @date: 2021/6/17 11:42
**/
@SneakyThrows
public static List<String> suggestSelect(SuggestionBuilder suggestionBuilder, int num) {
//查询构造
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
String name = RandomUtil.randomStringUpper(4);
//suggest构造
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion(name, suggestionBuilder);
searchSourceBuilder.suggest(suggestBuilder);
//查询请求
SearchRequest request = new SearchRequest(config.getIndex());
request.source(searchSourceBuilder);
//查询响应
SearchResponse response = elasticClient.getClient().search(request, RequestOptions.DEFAULT);
//suggest实体
Suggest suggest = response.getSuggest();
Set<String> result = new HashSet<>();
int maxSuggest = 0;
//获取suggest,name任意string
if (suggest != null) {
Suggest.Suggestion data = suggest.getSuggestion(name);
for (Object term : data.getEntries()) {
if (term instanceof CompletionSuggestion.Entry) {
CompletionSuggestion.Entry item = (CompletionSuggestion.Entry) term;
if (!item.getOptions().isEmpty()) {
//若item的option不为空,循环遍历
for (CompletionSuggestion.Entry.Option option : item.getOptions()) {
String s = option.getText().toString();
//没重复则加入
if (!result.contains(s)) {
result.add(s);
++maxSuggest;
}
}
}
}
if (maxSuggest >= num) {
break;
}
}
}
return new ArrayList<>(result);
}
}
6.工具类所需要的VO类
//单个查询VO封装 ID属性是为了区分ES自生成Id 与业务ID不为同一个(也可以设置ESid为业务id)
/**
* @author twx
* @description:
* @create: 2021/4/11
**/
@Data
public class EsOne<T> implements Serializable {
private static final long serialVersionUID = -3928293688231914175L;
private String id;
private T data;
}
/**
* @author twx
* @description: es分页返回实体
* @create: 2021/4/11
**/
@Data
public class EsPage<T> implements Serializable {
private static final long serialVersionUID = 8426920253860658973L;
private long total;
private long page;
private List<T> data;
}
7.调用示例
public class Test {
public static void main(String[] args) {
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("title","111");
EsOne<自己的实体类> one = EsUtil.selectOne(matchQueryBuilder,自己的实体类.class);
one.getData();
}
}