1、引入依赖
<properties> <java.version>1.8</java.version> <log4j2.version>2.17.0</log4j2.version> <axis1.version>1.4</axis1.version> <elasticsearch.version>7.3.2</elasticsearch.version> </properties> <!-- elasticsearch --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
2、配置文件配置
package com.sinochem.center.elasticsearch.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author : jiagang * @date : Created in 2022/3/25 15:21 */ @Configuration public class ElasticSearchConfig { // 注册 rest高级客户端 @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost",9201,"http") ) ); return client; } }
3、es API工具类实现
package com.sinochem.center.elasticsearch.service.base; import com.alibaba.fastjson.JSON; import com.sinochem.center.elasticsearch.entity.EsPage; import lombok.extern.slf4j.Slf4j; 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.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; /** * elasticSearch api方法 * @author : jiagang * @date : Created in 2022/3/28 10:21 */ @Slf4j @Component public class BaseElasticsearchService { @Autowired private RestHighLevelClient restHighLevelClient; /** * 默认类型 */ public static final String DEFAULT_TYPE = "_doc"; /** * set方法前缀 */ public static final String SET_METHOD_PREFIX = "set"; /** * 返回状态-CREATED */ public static final String RESPONSE_STATUS_CREATED = "CREATED"; /** * 返回状态-OK */ public static final String RESPONSE_STATUS_OK = "OK"; /** * 返回状态-NOT_FOUND */ public static final String RESPONSE_STATUS_NOT_FOUND = "NOT_FOUND"; /** * 需要过滤的文档数据 */ public static final String[] IGNORE_KEY = {"@version","type"}; /** * 超时时间 1s */ public static final TimeValue TIME_VALUE_SECONDS = TimeValue.timeValueSeconds(1); /** * @PostContruct是spring框架的注解 spring容器初始化的时候执行该方法 */ // @PostConstruct // public void init() { // client = this.transportClient; // System.out.println("client*************" + client); // } /** * 创建索引 * @param index * @return */ public boolean createIndex(String index) throws IOException { if (!isIndexExist(index)) { log.info("Index is not exits!"); } CreateIndexRequest indexRequest = new CreateIndexRequest(index); CreateIndexResponse response = restHighLevelClient.indices().create(indexRequest, RequestOptions.DEFAULT); log.info("执行建立成功?" + response.isAcknowledged()); return response.isAcknowledged(); } /** * 删除索引 * * @param index * @return */ public boolean deleteIndex(String index) throws IOException { if (!isIndexExist(index)) { log.info("Index is not exits!"); } DeleteIndexRequest request = new DeleteIndexRequest("mdx_index"); AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT); if (response.isAcknowledged()) { log.info("delete index " + index + " successfully!"); } else { log.info("Fail to delete index " + index); } return response.isAcknowledged(); } /** * 判断索引是否存在 * * @param index * @return */ public boolean isIndexExist(String index) throws IOException { GetIndexRequest request = new GetIndexRequest(index); boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); if (exists) { log.info("Index [" + index + "] is exist!"); } else { log.info("Index [" + index + "] is not exist!"); } return exists; } /** * 指定文档是否存在 * * @param index 索引 * @param id 文档id */ public boolean isExists(String index, String id) { return isExists(index, DEFAULT_TYPE, id); } /** * 指定文档是否存在 * * @param index 索引 * @param type 类型 * @param id 文档id */ public boolean isExists(String index, String type, String id) { GetRequest request = new GetRequest(index, type, id); try { GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT); return response.isExists(); } catch (Exception e) { e.printStackTrace(); } return false; } /** * 根据id查询文档 * @param index 索引 * @param id 文档id * @param clazz 转换目标Class对象 * @return 对象 */ public <T> T selectDocumentById(String index, String id, Class<T> clazz) { return selectDocumentById(index, DEFAULT_TYPE, id, clazz); } /** * 根据id查询文档 * * @param index 索引 * @param type 类型 * @param id 文档id * @param clazz 转换目标Class对象 * @return 对象 */ public <T> T selectDocumentById(String index, String type, String id, Class<T> clazz) { try { type = type == null || type.equals("") ? DEFAULT_TYPE : type; GetRequest request = new GetRequest(index, type, id); GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT); if (response.isExists()) { Map<String, Object> sourceAsMap = response.getSourceAsMap(); return dealObject(sourceAsMap, clazz); } } catch (Exception e) { e.printStackTrace(); } return null; } /** *(筛选条件)获取数据集合 * 如果使用排序则 sourceBuilder.sort("name",SortOrder.DESC) * 如果使用高亮则 : * HighlightBuilder highlightBuilder = new HighlightBuilder(); * highlightBuilder.field(""); * sourceBuilder.highlighter(highlightBuilder); * @param index 索引 * @param sourceBuilder 请求条件 * @param clazz 转换目标Class对象 */ public <T> List<T> selectDocumentList(String index, SearchSourceBuilder sourceBuilder, Class<T> clazz) { try { SearchRequest request = new SearchRequest(index); if (sourceBuilder != null) { // 返回实际命中数 sourceBuilder.trackTotalHits(true); request.source(sourceBuilder); } SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); if (response.getHits() != null) { List<T> list = new ArrayList<>(); SearchHit[] hits = response.getHits().getHits(); for (SearchHit documentFields : hits) { Map<String, Object> sourceAsMap = documentFields.getSourceAsMap(); // 高亮结果集特殊处理 -- 高亮信息会显示在highlight标签下 需要将实体类中的字段进行替换 Map<String, Object> map = this.highlightBuilderHandle(sourceAsMap, documentFields); list.add(dealObject(map, clazz)); } return list; } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 新增/修改文档信息 * @param index 索引 * @param data 数据 */ public String insertDocument(String index, Object data) { try { String id = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); IndexRequest request = new IndexRequest(index); request.timeout(TIME_VALUE_SECONDS); request.id(id); // 文档id request.source(JSON.toJSONString(data), XContentType.JSON); IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT); log.info("insertDocument response status:{},id:{}", response.status().getStatus(), response.getId()); String status = response.status().toString(); if (RESPONSE_STATUS_CREATED.equals(status) || RESPONSE_STATUS_OK.equals(status)) { return response.getId(); } } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 删除文档信息 * * @param index 索引 * @param id 文档id */ public boolean deleteDocument(String index, String id) { try { DeleteRequest request = new DeleteRequest(index, id); DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT); log.info("deleteDocument response status:{},id:{}", response.status().getStatus(), response.getId()); String status = response.status().toString(); if (RESPONSE_STATUS_OK.equals(status)) { return true; } } catch (Exception e) { e.printStackTrace(); } return false; } /** * 更新文档信息 * * @param index 索引 * @param id 文档id * @param data 数据 */ public boolean updateDocument(String index, String id, Object data) { try { UpdateRequest request = new UpdateRequest(index, id); request.doc(data, XContentType.JSON); UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT); log.info("updateDocument response status:{},id:{}", response.status().getStatus(), response.getId()); String status = response.status().toString(); if (RESPONSE_STATUS_OK.equals(status)) { return true; } } catch (Exception e) { e.printStackTrace(); } return false; } /** * 批量操作(新增) * @param index 索引 * @param opType 操作类型 PATCH_OP_TYPE_* * @param dataList 数据集 新增修改需要传递 * @param timeout 超时时间 单位为秒 */ public boolean patch(String index, String opType, List<Object> dataList, long timeout) { try { BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout(TimeValue.timeValueSeconds(timeout)); if (dataList != null && dataList.size() > 0) { if ("insert".equals(opType)) { for (Object obj : dataList) { bulkRequest.add( new IndexRequest(index) .source(JSON.toJSONString(obj), XContentType.JSON) ); } } BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); if (!response.hasFailures()) { return true; } } } catch (Exception e) { e.printStackTrace(); } return false; } /** *(筛选条件)获取数据集合分页 * 如果使用排序则 sourceBuilder.sort("name",SortOrder.DESC) * 如果使用高亮则 : * HighlightBuilder highlightBuilder = new HighlightBuilder(); * highlightBuilder.field(""); * sourceBuilder.highlighter(highlightBuilder); * @param index 索引 * @param sourceBuilder 请求条件 * @param clazz 转换目标Class对象 */ public <T> EsPage selectDocumentPage(String index,SearchSourceBuilder sourceBuilder, int startPage, int pageSize , Class<T> clazz) { try { SearchRequest request = new SearchRequest(index); if (sourceBuilder != null) { // 返回实际命中数 sourceBuilder.from(startPage); sourceBuilder.size(pageSize); sourceBuilder.explain(true); sourceBuilder.trackTotalHits(true); request.source(sourceBuilder); } SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); if (response.getHits() != null) { long totalHits = Arrays.stream(response.getHits().getHits()).count(); long length = response.getHits().getHits().length; List<T> list = new ArrayList<>(); SearchHit[] hits = response.getHits().getHits(); for (SearchHit documentFields : hits) { Map<String, Object> sourceAsMap = documentFields.getSourceAsMap(); // 高亮结果集特殊处理 -- 高亮信息会显示在highlight标签下 需要将实体类中的字段进行替换 Map<String, Object> map = this.highlightBuilderHandle(sourceAsMap, documentFields); list.add(dealObject(map, clazz)); } return new EsPage(startPage, pageSize, (int) totalHits, list); } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 高亮结果集 特殊处理 * @param sourceAsMap * @param documentFields */ private Map<String, Object> highlightBuilderHandle(Map<String, Object> sourceAsMap,SearchHit documentFields){ // 将高亮的字段替换到sourceAsMap中 Map<String, HighlightField> fieldMap = documentFields.getHighlightFields(); Set<Map.Entry<String, Object>> entries = sourceAsMap.entrySet(); entries.forEach(source -> { if (fieldMap.containsKey(source.getKey())){ Text[] fragments = fieldMap.get(source.getKey()).getFragments(); if (fragments != null){ for (Text str : fragments) { source.setValue(str.string()); } } } }); return sourceAsMap; } // /** // * 高亮结果集 特殊处理 // * // * @param searchResponse // * @param highlightField // */ // private List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) { // List<Map<String, Object>> sourceList = new ArrayList<>(); // 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; // } /** * 将文档数据转化为指定对象 * * @param sourceAsMap 文档数据 * @param clazz 转换目标Class对象 * @return */ private static <T> T dealObject(Map<String, Object> sourceAsMap, Class<T> clazz) { try { ignoreSource(sourceAsMap); Iterator<String> keyIterator = sourceAsMap.keySet().iterator(); T t = clazz.newInstance(); while (keyIterator.hasNext()) { String key = keyIterator.next(); String replaceKey = key.replaceFirst(key.substring(0, 1), key.substring(0, 1).toUpperCase()); Method method = null; try { method = clazz.getMethod(SET_METHOD_PREFIX + replaceKey, sourceAsMap.get(key).getClass()); }catch (NoSuchMethodException e) { continue; } method.invoke(t, sourceAsMap.get(key)); } return t; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 剔除指定文档数据,减少不必要的循环 * * @param map 文档数据 */ private static void ignoreSource(Map<String, Object> map) { for (String key : IGNORE_KEY) { map.remove(key); } } }
4、单元测试类
package com.sinochem.center; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.sinochem.center.elasticsearch.entity.EsPage; import com.sinochem.center.elasticsearch.service.base.BaseElasticsearchService; import com.sinochem.center.entity.TaskCenter; import com.sinochem.center.mapper.db1.TaskCenterMapper; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortOrder; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author : jiagang * @date : Created in 2022/3/28 15:40 */ @SpringBootTest @Slf4j public class ElasticSearchDataTest { @Autowired private BaseElasticsearchService elasticsearchService; @Autowired private TaskCenterMapper taskCenterMapper; /** * 创建索引 * @throws IOException */ @Test public void addIndex() throws IOException { boolean b = elasticsearchService.createIndex("hxy_task"); System.out.println(b); } /** * 新增/修改文档信息 * @throws IOException */ @Test public void insertDocument() throws IOException { TaskCenter taskCenter = taskCenterMapper.selectById(100874); String id = elasticsearchService.insertDocument("hxy_task", taskCenter); System.out.println(id); } /** * 根据id查询文档 * @throws IOException */ @Test public void selectDocumentById() throws IOException { TaskCenter taskCenter = elasticsearchService.selectDocumentById("hxy_task", "4B0895F2B2254406B1A83E689E624D41", TaskCenter.class); System.out.println(taskCenter); } /** * 批量操作(新增) * @throws IOException */ @Test public void patch() throws IOException { QueryWrapper<TaskCenter> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("user_code","hhj"); List<TaskCenter> taskCenterList = taskCenterMapper.selectList(queryWrapper); List<Object> objects = new ArrayList<>(); objects.addAll(taskCenterList); boolean b = elasticsearchService.patch("hxy_task","insert",objects,5); System.out.println(b); } /** * (筛选条件)获取数据集合 * @throws IOException */ @Test public void selectDocumentList() throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.sort("createTime", SortOrder.DESC); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags("<font color=\"red\">"); highlightBuilder.postTags("</font>"); highlightBuilder.highlighterType("unified"); highlightBuilder.field("taskItemTitle"); highlightBuilder.field("orgName"); highlightBuilder.requireFieldMatch(false);//多次段高亮需要设置为false searchSourceBuilder.highlighter(highlightBuilder); QueryBuilder qb = QueryBuilders.matchQuery("taskItemTitle","中化塑料有限公司"); searchSourceBuilder.query(qb); List<TaskCenter> taskCenterList = elasticsearchService.selectDocumentList("hxy_task", searchSourceBuilder, TaskCenter.class); System.out.println(taskCenterList); } /** * (筛选条件)获取数据集合分页 * @throws IOException */ @Test public void selectDocumentPage() throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.sort("createTime", SortOrder.DESC); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags("<font color=\"red\">"); highlightBuilder.postTags("</font>"); highlightBuilder.highlighterType("unified"); highlightBuilder.field("taskItemTitle"); highlightBuilder.field("orgName"); highlightBuilder.requireFieldMatch(false);//多次段高亮需要设置为false searchSourceBuilder.highlighter(highlightBuilder); QueryBuilder qb = QueryBuilders.matchQuery("taskItemTitle","中化塑料有限公司"); searchSourceBuilder.query(qb); EsPage page = elasticsearchService.selectDocumentPage("hxy_task", searchSourceBuilder, 1, 5, TaskCenter.class); System.out.println(page); } }
注:工具类参考 https://blog.csdn.net/qq_43077369/article/details/116227967 ,在其之上新增了查询高亮结果集特殊处理,分页查询以及单元测试的调用等。
文章持续更新,可以关注下方公众号或者微信搜一搜「 最后一支迷迭香 」第一时间阅读,获取更完整的链路资料。