package com.infynova.udi.service.helper; import com.infynova.udi.mapper.UdiMapper; import com.infynova.udi.vo.UdiMatchRateVo; import com.infynova.udi.vo.UdiVo; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; 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.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.*; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; import javax.annotation.Resource; import java.io.IOException; import java.util.*; /** * @author liudong * 2024/4/29 16:16 * @version 1.0 */ @Slf4j @Component public class EsSearchHelper { private static final String INDEX_NAME = "udi"; public static final RestHighLevelClient client; static{ client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost",9200,"http")) ); } @SneakyThrows public CreateIndexResponse createIndex(){ log.info("创建索引"); CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX_NAME); // 设置映射 createIndexRequest.mapping( "{" + " \"properties\": {" + " \"id\": {" + " \"type\": \"long\"" + " }," + " \"companyName\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }," + " \"productFactoryCode\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }," + " \"brandName\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }," + " \"productName\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }," + " \"specification\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }," + " \"model\": {" + " \"type\": \"text\"," + " \"analyzer\": \"ik_max_word\"," + " \"search_analyzer\": \"ik_smart\"" + " }" + " }" + "}" ,XContentType.JSON ); CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT); return createIndexResponse; } @SneakyThrows public AcknowledgedResponse deleteIndex(){ log.info("删除索引"); DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(INDEX_NAME); AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); return delete; } @Resource private UdiMapper udiMapper; @SneakyThrows public void initData(){ log.info("同步数据"); StopWatch stopWatch = new StopWatch("开始"); Integer pageSize = 5000; Long lastId = 0L; int i = 1; try{ while (true){ stopWatch.start("第"+i+"页"); log.info("同步索引:第{}页,lastId:{}",i,lastId); List<UdiVo> records = udiMapper.getUdiIdPage(lastId,pageSize); if(CollectionUtils.isEmpty(records)){ return; } this.indexDocument(records); UdiVo udiVo = records.get(records.size()-1); lastId = udiVo.getId(); i++; stopWatch.stop(); } }catch (Exception e){ log.error(""); log.error("",e); }finally { stopWatch.stop(); log.info(stopWatch.prettyPrint()); log.info("总计耗时:{}",stopWatch.getTotalTimeSeconds()); } } private Map<String,Object> getDoc(UdiVo udiVo){ Map<String,Object> map = new HashMap<>(); map.put("id",udiVo.getId()); map.put("companyName",udiVo.getCompanyName()); map.put("productFactoryCode",udiVo.getProductFactoryCode()); map.put("brandName",udiVo.getBrandName()); map.put("productName",udiVo.getProductName()); map.put("specification",udiVo.getSpecification()); map.put("model",udiVo.getModel()); return map; } public void indexDocument(List<UdiVo> udiVos) throws IOException { BulkRequest bulkRequest = new BulkRequest(); for (UdiVo udiVo : udiVos) { Map<String, Object> doc = getDoc(udiVo); IndexRequest request = new IndexRequest(INDEX_NAME) .id(String.valueOf(udiVo.getId())) .source(doc, XContentType.JSON); bulkRequest.add(request); } BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); if (bulkResponse.hasFailures()) { // 处理失败的情况 log.error("Some documents failed to index: " + bulkResponse.buildFailureMessage()); } else { log.info("Bulk indexing successful."); } } @SneakyThrows public Map<String, Object> getId(String id){ GetRequest getRequest = new GetRequest(INDEX_NAME, id); GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); return getResponse.getSourceAsMap(); } @SneakyThrows public SearchResponse searchThree(String companyName,String productFactoryCode){ if(StringUtils.isBlank(companyName) && StringUtils.isBlank(productFactoryCode)){ return null; } SearchRequest searchRequest = new SearchRequest(INDEX_NAME); // 构建查询条件 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); if(StringUtils.isNotBlank(companyName)){ boolQueryBuilder.should(new MatchQueryBuilder("companyName", companyName)) .should(new TermQueryBuilder("companyName.keyword", companyName)); } // boost 倾向性:查询时倾向于productFactoryCode if(StringUtils.isNotBlank(productFactoryCode)){ boolQueryBuilder.should(new MatchQueryBuilder("productFactoryCode", productFactoryCode).boost(2)) .should(new TermQueryBuilder("productFactoryCode.keyword", productFactoryCode).boost(2)); } // 构建搜索源 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder); // 设置搜索请求的源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); return searchResponse; } /** * 规则三 * @param companyName 企业名称 * @param productFactoryCode 产品厂家编码 */ public List<UdiMatchRateVo> threeQuery(String companyName, String productFactoryCode){ List<UdiMatchRateVo> resultList = new ArrayList<>(); SearchResponse searchResponse = searchThree(companyName, productFactoryCode); if(Objects.isNull(searchResponse)){ return new ArrayList<>(); } // 处理搜索结果 SearchHit[] searchHits = searchResponse.getHits().getHits(); for (SearchHit hit : searchHits) { UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo(); Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString()); String companyNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("companyName")).orElse("").toString(); String productFactoryCodeQuery = Optional.ofNullable(hit.getSourceAsMap().get("productFactoryCode")).orElse("").toString(); udiMatchRateVo.setId(idQuery); udiMatchRateVo.setCompanyName(companyNameQuery); udiMatchRateVo.setProductFactoryCode(productFactoryCodeQuery); resultList.add(udiMatchRateVo); } return resultList; } @SneakyThrows public SearchResponse searchFour(String brandName,String productName,String specification,String model){ if(StringUtils.isBlank(brandName) && StringUtils.isBlank(productName) && StringUtils.isBlank(specification) && StringUtils.isBlank(model) ){ return null; } SearchRequest searchRequest = new SearchRequest(INDEX_NAME); // 构建查询条件 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); if(StringUtils.isNotBlank(brandName)){ boolQueryBuilder.should(new MatchQueryBuilder("brandName", brandName)) .should(new TermQueryBuilder("brandName.keyword", brandName)); } if(StringUtils.isNotBlank(productName)){ boolQueryBuilder.should(new MatchQueryBuilder("productName", productName)) .should(new TermQueryBuilder("productName.keyword", productName)); } if(StringUtils.isNotBlank(specification)){ boolQueryBuilder.should(new MatchQueryBuilder("specification", specification)) .should(new TermQueryBuilder("specification.keyword", specification)); } if(StringUtils.isNotBlank(model)){ boolQueryBuilder.should(new MatchQueryBuilder("model", model)) .should(new TermQueryBuilder("model.keyword", model)); } // 构建搜索源 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder); // 设置搜索请求的源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); return searchResponse; } /** * 规则四 * @param brandName * @param productName * @param specification * @param model * @return */ public List<UdiMatchRateVo> fourQuery(String brandName, String productName, String specification, String model){ List<UdiMatchRateVo> resultList = new ArrayList<>(); SearchResponse searchResponse = searchFour(brandName, productName, specification, model); // 处理搜索结果 SearchHit[] searchHits = searchResponse.getHits().getHits(); for (SearchHit hit : searchHits) { UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo(); Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString()); String brandNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("brandName")).orElse("").toString(); String productNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("productName")).orElse("").toString(); String specificationQuery = Optional.ofNullable(hit.getSourceAsMap().get("specification")).orElse("").toString(); String modelQuery = Optional.ofNullable(hit.getSourceAsMap().get("model")).orElse("").toString(); udiMatchRateVo.setId(idQuery); udiMatchRateVo.setBrandName(brandNameQuery); udiMatchRateVo.setProductName(productNameQuery); udiMatchRateVo.setSpecification(specificationQuery); udiMatchRateVo.setModel(modelQuery); resultList.add(udiMatchRateVo); } return resultList; } }