maven
<properties>
<elasticsearch.version>7.17.1</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
</dependencies>
es工具类
初学者自己编写的一个es工具类,包括索引库、文档、查询。里面分页是根据前段传入自动识别的你们可以从方法中传入都可以,返回响应处理了his结果处理和高亮处理,全部都是公用的
package com.erligang.framework.elasticsearch;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.erligang.common.exception.CustomException;
import com.erligang.common.utils.StringUtils;
import com.erligang.framework.web.controller.BaseController;
import com.erligang.framework.web.page.TableDataInfo;
import com.erligang.framework.web.page.TableSupport;
import com.erligang.project.admin.domain.MerchantInfoDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.action.DocWriteResponse;
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.*;
import org.elasticsearch.action.index.IndexRequest;
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.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.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
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.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
/**
* li
*
* @Author: li
* DateTime: 2023/9/12 14:26
*/
@Slf4j
@Component
public class ElasticsearchClient extends BaseController {
@Autowired
private RestHighLevelClient client;
//******************************索引操作********************************//
/**
* @param indexNameReq 索引库
* @param indexDataReq
* @return {@link boolean}
* @description 创建索引库
* @date 2023/9/16 20:47
*/
public boolean createIndex(String indexNameReq, String indexDataReq) {
try {
// 是否存在
if (!existsIndex(indexNameReq)) {
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest(indexNameReq);
// 2.准备请求的参数: DSL语句
request.source(indexDataReq, XContentType.JSON);
// 3.发送请求
CreateIndexResponse createResponse = client.indices().create(request, RequestOptions.DEFAULT);
return createResponse.isAcknowledged();
} else {
log.info("{}索引库已存在", indexNameReq);
return true;
}
} catch (IOException e) {
log.error("索引库创建失败时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexNameReq 索引库Req
* @return {@link boolean}
* @description 索引库是否存在
* @date 2023/9/16 20:47
*/
public boolean existsIndex(String indexNameReq) {
try {
GetIndexRequest getRequest = new GetIndexRequest(indexNameReq);
// 是否存在
return client.indices().exists(getRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
log.error("查询es索引库是否存在时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexNameReq 索引库Req
* @return {@link boolean}
* @description 删除索引库
* @date 2023/9/16 20:47
*/
public boolean deleteIndex(String indexNameReq) {
try {
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest(indexNameReq);
// 2.发送请求
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
return delete.isAcknowledged();
} catch (IOException e) {
log.error("删除索引库时出错: {}", e.getMessage(), e);
return false;
}
}
//******************************文档操作********************************//
/**
* @param indexNameReq 索引库Req
* @param obj
* @param id
* @return {@link boolean}
* @description 添加文档
* @date 2023/9/16 20:47
*/
public <T> boolean insertDocument(String indexNameReq, T obj, Long id) {
try {
// 1.创建Request对象
IndexRequest request = new IndexRequest(indexNameReq).id(id.toString());
// 2.准备JSON文档
request.source(JSON.toJSONString(obj), XContentType.JSON);
// 3.发送请求
client.index(request, RequestOptions.DEFAULT);
return true;
} catch (IOException e) {
// 处理异常,这里可以记录日志或者返回false等
log.error("创建文档时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexName 索引库
* @param objList
* @param objFunc
* @return {@link boolean}
* @description 批量添加文档
* @date 2023/9/16 20:46
*/
public <T, R> boolean insertBatchDocument(String indexName, Collection<T> objList, Function<T, R> objFunc) {
// 设置批量处理的大小
return insertBatchDocument(indexName, objList, objFunc, 1000);
}
/**
* 批量添加文档
*
* @param indexName 索引库
* @param objList
* @param objFunc
* @param batchSize 每次处理大小
* @return {@link boolean}
* @description 批量添加文档
* @date 2023/9/16 18:59
*/
public <T, R> boolean insertBatchDocument(String indexName, Collection<T> objList, Function<T, R> objFunc, int batchSize) {
try {
BulkRequest request = new BulkRequest();
int counter = 0;
for (T obj : objList) {
String documentId = objFunc.apply(obj).toString();
IndexRequest indexRequest = new IndexRequest(indexName)
.id(documentId)
.source(JSON.toJSONString(obj), XContentType.JSON);
request.add(indexRequest);
// 当达到批量处理的大小或遍历完成时执行批量操作
if (++counter % batchSize == 0 || counter == objList.size()) {
BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
request = new BulkRequest(); // 重置请求
if (bulk.status() != RestStatus.OK || bulk.hasFailures()) {
log.error("批量创建文档时出错: {}", bulk.buildFailureMessage());
return false;
}
}
}
return true;
} catch (IOException e) {
log.error("批量创建文档时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexNameReq 索引库Req
* @param id
* @return {@link boolean}
* @description 根据Id删除文档
* @date 2023/9/16 20:46
*/
public boolean deleteDocumentById(String indexNameReq, Long id) {
try {
// 1.创建Request对象
DeleteRequest removeRequest = new DeleteRequest(indexNameReq, id.toString());
// 3.发送请求
DeleteResponse deleteResponse = client.delete(removeRequest, RequestOptions.DEFAULT);
if (deleteResponse.getResult() == DocWriteResponse.Result.DELETED) {
// 文档删除成功
return true;
} else if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
// 文档未找到,无法删除
return true;
} else {
// 其他情况,删除失败
return false;
}
} catch (IOException e) {
// 处理异常,这里可以记录日志或者返回false等
log.error("根据Id删除文档时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexName 索引库
* @param documentIds
* @return {@link boolean}
* @description 批量删除文档
* @date 2023/9/16 20:46
*/
public boolean deleteBatchDocument(String indexName, Collection<String> documentIds) {
int batchSize = 1000; // 设置批量处理的大小
return deleteBatchDocument(indexName, documentIds, batchSize);
}
/**
* @param indexName 索引库
* @param documentIds
* @param batchSize 每次处理大小
* @return {@link boolean}
* @description 批量删除文档
* @date 2023/9/16 19:04
*/
public boolean deleteBatchDocument(String indexName, Collection<String> documentIds, int batchSize) {
try {
BulkRequest request = new BulkRequest();
int counter = 0;
for (String documentId : documentIds) {
DeleteRequest deleteRequest = new DeleteRequest(indexName, documentId);
request.add(deleteRequest);
// 当达到批量处理的大小或遍历完成时执行批量操作
if (++counter % batchSize == 0 || counter == documentIds.size()) {
BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
request = new BulkRequest(); // 重置请求
if (bulk.status() != RestStatus.OK || bulk.hasFailures()) {
log.error("批量删除文档时出错: {}", bulk.buildFailureMessage());
return false;
}
}
}
return true;
} catch (IOException e) {
log.error("批量删除文档时出错: {}", e.getMessage(), e);
return false;
}
}
/**
* @param indexNameReq 索引库Req
* @param id
* @param updateMap
* @return {@link boolean}
* @description 局部修改文档(全局修改和添加一样)
* @date 2023/9/16 20:46
*/
public boolean updateDocument(String indexNameReq, Long id, Map<String, Object> updateMap) {
try {
// 1.创建Request对象
UpdateRequest editRequest = new UpdateRequest(indexNameReq, id.toString());
// 2.准备JSON文档
// 嵌套修改
/*Map<String, Object> updateMap = new HashMap<>();
Map<String, Object> enterCommonInfo = new HashMap<>();
enterCommonInfo.put("businessAddress", "河南省洛阳市廛河回族区");
updateMap.put("businessScope", "NO服装");
updateMap.put("enterCommonInfo", enterCommonInfo);*/
editRequest.doc(updateMap);
// 3.发送请求
client.update(editRequest, RequestOptions.DEFAULT);
return true;
} catch (IOException e) {
// 处理异常,这里可以记录日志或者返回false等
log.error("修改文档时出错: {}", e.getMessage(), e);
return false;
}
}
//******************************查询操作********************************//
/**
* @param indexNameReq 索引库Req
* @param id
* @param targetType
* @return {@link T}
* @description 根据ID获取文档
* @date 2023/9/16 20:46
*/
public <T> T getDocument(String indexNameReq, Long id, Class<T> targetType) {
try {
// 获取
GetRequest getRequest = new GetRequest(indexNameReq, id.toString());
GetResponse response = client.get(getRequest, RequestOptions.DEFAULT);
return JSON.parseObject(response.getSourceAsString(), targetType);
} catch (IOException e) {
log.error("查询文档出错: {}", e.getMessage(), e);
}
throw new CustomException("查询文档出错!");
}
/**
* @param indexName 索引库
* @param documentIds
* @param targetType
* @return {@link Map< String,T>}
* @description 根据ids批量查询文档
* @date 2023/9/16 20:46
*/
public <T> Map<String, T> getBatchDocuments(String indexName, Collection<String> documentIds, Class<T> targetType) {
Map<String, T> resultMap = new HashMap<>();
try {
MultiGetRequest multiGetRequest = new MultiGetRequest();
for (String documentId : documentIds) {
multiGetRequest.add(new MultiGetRequest.Item(indexName, documentId));
}
MultiGetResponse multiGetResponse = client.mget(multiGetRequest, RequestOptions.DEFAULT);
for (MultiGetItemResponse itemResponse : multiGetResponse) {
if (!itemResponse.isFailed()) {
GetResponse response = itemResponse.getResponse();
if (response.isExists()) {
String documentId = response.getId();
T document = JSON.parseObject(response.getSourceAsString(), targetType);
resultMap.put(documentId, document);
}
}
}
return resultMap;
} catch (IOException e) {
log.error("批量查询文档时出错: {}", e.getMessage(), e);
return Collections.emptyMap();
}
}
/**
* @param indexName 索引库
* @param fieldName 查询字段
* @param queryText
* @param targetType
* @return {@link List<T>}
* @description match查询
* @date 2023/9/16 19:10
*/
public <T> TableDataInfo<T> matchQuery(String indexName, String fieldName, String queryText, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source()
.query(QueryBuilders.matchQuery(fieldName, queryText))
.from(TableSupport.getEsPageNum())
.size(TableSupport.getEsPageSize());
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Match query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
/**
* @param indexName 索引库
* @param fieldName 查询字段
* @param termValue
* @param targetType
* @return {@link TableDataInfo<T>}
* @description term查询
* @date 2023/9/16 20:46
*/
public <T> TableDataInfo<T> termQuery(String indexName, String fieldName, String termValue, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source()
.query(QueryBuilders.termQuery(fieldName, termValue))
.from(TableSupport.getEsPageNum())
.size(TableSupport.getEsPageSize());
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Term query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
// range查询
public <T> TableDataInfo<T> rangeQuery(String indexName, String fieldName, String gteValue, String lteValue, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(fieldName);
if (gteValue != null) {
rangeQuery.gte(gteValue); // 大于等于 gteValue
}
if (lteValue != null) {
rangeQuery.lte(lteValue); // 小于等于 lteValue
}
sourceBuilder.query(rangeQuery);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Range query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
/**
* @param indexName 索引库
* @param mustQueries
* @param shouldQueries
* @param mustNotQueries
* @param filterQueries
* @param highlightFieldNames
* @param targetType
* @return {@link TableDataInfo<T>}
* @description bool查询
* @date 2023/9/16 20:44
*/
public <T> TableDataInfo<T> boolQuery(String indexName, List<QueryBuilder> mustQueries, List<QueryBuilder> shouldQueries, List<QueryBuilder> mustNotQueries, List<QueryBuilder> filterQueries, List<String> highlightFieldNames, Class<T> targetType) {
return boolQueryHighlight(indexName, mustQueries, shouldQueries, mustNotQueries, filterQueries, null, targetType);
}
/**
* @param indexName 索引库
* @param mustQueries
* @param shouldQueries
* @param mustNotQueries
* @param filterQueries
* @param highlightFieldNames
* @param targetType
* @return {@link TableDataInfo<T>}
* @description bool高亮查询
* @date 2023/9/16 20:44
*/
public <T> TableDataInfo<T> boolQueryHighlight(String indexName, List<QueryBuilder> mustQueries, List<QueryBuilder> shouldQueries, List<QueryBuilder> mustNotQueries, List<QueryBuilder> filterQueries, List<String> highlightFieldNames, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加MUST查询条件
if (CollectionUtil.isNotEmpty(mustQueries)) {
for (QueryBuilder mustQuery : mustQueries) {
boolQuery.must(mustQuery);
}
}
// 添加SHOULD查询条件
if (CollectionUtil.isNotEmpty(shouldQueries)) {
for (QueryBuilder shouldQuery : shouldQueries) {
boolQuery.should(shouldQuery);
}
}
// 添加MUST_NOT查询条件
if (CollectionUtil.isNotEmpty(mustNotQueries)) {
for (QueryBuilder mustNotQuery : mustNotQueries) {
boolQuery.mustNot(mustNotQuery);
}
}
// 添加FILTER查询条件
if (CollectionUtil.isNotEmpty(filterQueries)) {
for (QueryBuilder filterQuery : filterQueries) {
boolQuery.filter(filterQuery);
}
}
// bool查询
sourceBuilder.query(boolQuery);
// 配置高亮
if (CollectionUtil.isNotEmpty(highlightFieldNames)) {
sourceBuilder.highlighter(getHighlightBuilder(highlightFieldNames));
}
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Bool query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
/**
* @param indexName 索引库
* @param fieldName 查询字段
* @param queryText 查询内容
* @param highlightFieldNames 高亮字段
* @param targetType 实体类
* @return {@link TableDataInfo<T>}
* @description highlight高亮查询
* @date 2023/9/16 20:38
*/
public <T> TableDataInfo<T> highlightQuery(String indexName, String fieldName, String queryText, List<String> highlightFieldNames, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 使用链式编程构建查询
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(fieldName, queryText);
// 配置高亮
HighlightBuilder highlightBuilder = getHighlightBuilder(highlightFieldNames);
sourceBuilder.query(matchQuery)
.highlighter(highlightBuilder);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Highlight query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
/**
* @param highlightFieldNames
* @return {@link HighlightBuilder}
* @description 高亮方法
* @date 2023/9/16 20:44
*/
private static HighlightBuilder getHighlightBuilder(List<String> highlightFieldNames) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
if (CollectionUtil.isNotEmpty(highlightFieldNames)) {
for (String highlightFieldName : highlightFieldNames) {
highlightBuilder.field(highlightFieldName).requireFieldMatch(false);
}
}
return highlightBuilder;
}
/**
* @param indexName 索引库
* @param fieldName 查询字段
* @param prefixText
* @param targetType
* @return {@link TableDataInfo<T>}
* @description 前缀查询
* @date 2023/9/16 20:50
*/
public <T> TableDataInfo<T> prefixQuery(String indexName, String fieldName, String prefixText, Class<T> targetType) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 创建前缀查询
PrefixQueryBuilder prefixQuery = QueryBuilders.prefixQuery(fieldName, prefixText);
sourceBuilder.query(prefixQuery);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 处理返回值
return handleEsResponse(searchResponse, targetType);
} catch (IOException e) {
log.error("Prefix query error: {}", e.getMessage(), e);
return getDataTable(Collections.emptyList());
}
}
//******************************聚合查询********************************//
//******************************返回处理********************************//
/**
* @param response
* @return {@link TableDataInfo< MerchantInfoDO>}
* @description es返回值请求处理
* 获取es返回的请求截取his部分
* @date 2023/9/12 14:29
*/
public static <T> TableDataInfo<T> handleEsResponse(SearchResponse response, Class<T> targetType) {
SearchHits hits = response.getHits();
long totalHits = hits.getTotalHits().value;
SearchHit[] hitsArray = hits.getHits();
List<T> objInfoList = new LinkedList<>();
for (SearchHit hit : hitsArray) {
String sourceAsString = hit.getSourceAsString();
T objDO = JSON.parseObject(sourceAsString, targetType);
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (MapUtils.isNotEmpty(highlightFields)) {
// 处理高亮字段
handleDynamicHighlightFields(highlightFields, objDO);
}
objInfoList.add(objDO);
}
return getDataTable(objInfoList, totalHits);
}
/**
* @param highlightFields
* @param targetType
* @return
* @description 处理高亮字段
* @date 2023/9/12 15:00
*/
private static <T> void handleDynamicHighlightFields(Map<String, HighlightField> highlightFields, T
targetType) {
for (Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) {
String fieldName = entry.getKey();
HighlightField highlightField = entry.getValue();
if (StringUtils.isNotNull(highlightField)) {
Text[] fragments = highlightField.getFragments();
if (fragments.length > 0) {
String highlightedText = fragments[0].string();
setFieldUsingReflection(targetType, fieldName, highlightedText);
}
}
}
}
/**
* @param object
* @param fieldName 查询字段
* @param fieldValue
* @return
* @description 反射替换高亮值
* @date 2023/9/12 15:03
*/
private static void setFieldUsingReflection(Object object, String fieldName, String fieldValue) {
try {
// 处理多级嵌套
String[] fieldNames = fieldName.split("\\.");
if (fieldNames.length > 1) {
// 嵌套字段
setFieldValueByFieldName(object, fieldNames, fieldValue);
} else {
// 处理非嵌套字段
setField(object, fieldName, fieldValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param object
* @param fieldValue
* @return
* @description 处理嵌套对象
* @date 2023/9/12 15:03
*/
private static void setFieldValueByFieldName(Object object, String[] fieldNames, String fieldValue) {
Object currentObject = object;
try {
for (int i = 0; i < fieldNames.length - 1; i++) {
currentObject = getField(currentObject, fieldNames[i]);
}
String finalFieldName = fieldNames[fieldNames.length - 1];
setField(currentObject, finalFieldName, fieldValue);
} catch (Exception e) {
e.printStackTrace();
}
}
// 反射获取类
private static Object getField(Object currentObject, String fieldNames) throws
NoSuchMethodException, IllegalAccessException, InvocationTargetException {
try {
String getterMethodName = "get" + fieldNames.substring(0, 1).toUpperCase() + fieldNames.substring(1);
Method getterMethod = currentObject.getClass().getMethod(getterMethodName);
currentObject = getterMethod.invoke(currentObject);
return currentObject;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 反射类赋值
private static void setField(Object object, String fieldName, String fieldValue) {
try {
String setterMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
Method setterMethod = object.getClass().getMethod(setterMethodName, String.class);
setterMethod.invoke(object, fieldValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}