|
@@ -0,0 +1,319 @@
|
|
|
|
|
+package com.storlead.es.server.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
|
+import com.storlead.es.server.BaseSearchService;
|
|
|
|
|
+import com.storlead.common.object.Page;
|
|
|
|
|
+import org.elasticsearch.action.search.SearchRequest;
|
|
|
|
|
+import org.elasticsearch.common.unit.Fuzziness;
|
|
|
|
|
+import org.elasticsearch.index.query.QueryBuilder;
|
|
|
|
|
+import org.elasticsearch.index.query.QueryBuilders;
|
|
|
|
|
+import org.elasticsearch.index.query.QueryStringQueryBuilder;
|
|
|
|
|
+import org.elasticsearch.script.Script;
|
|
|
|
|
+import org.elasticsearch.script.ScriptType;
|
|
|
|
|
+import org.springframework.data.elasticsearch.core.SearchHit;
|
|
|
|
|
+import org.springframework.data.elasticsearch.core.SearchHits;
|
|
|
|
|
+import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
|
|
|
|
+import org.elasticsearch.search.sort.SortBuilders;
|
|
|
|
|
+import org.elasticsearch.search.sort.SortOrder;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.springframework.data.domain.PageRequest;
|
|
|
|
|
+import org.springframework.data.domain.Pageable;
|
|
|
|
|
+import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
|
|
|
|
+import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
|
|
|
|
+import org.springframework.data.elasticsearch.core.query.*;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+import java.lang.reflect.Field;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @program: sp-tems-gotr
|
|
|
|
|
+ * @description:
|
|
|
|
|
+ * @author: chenkq
|
|
|
|
|
+ * @create: 2023-06-16 16:42
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class BaseSearchServiceImpl<T> implements BaseSearchService<T> {
|
|
|
|
|
+
|
|
|
|
|
+ private Logger logger = LoggerFactory.getLogger(getClass());
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ElasticsearchRestTemplate elasticsearchTemplate;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ public void save(Class<T> clazz) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ elasticsearchTemplate.save(clazz);
|
|
|
|
|
+ }catch (Exception e) {
|
|
|
|
|
+ logger.error("");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void save(Class<T> clazz,String indexId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ T info = elasticsearchTemplate.get(indexId, clazz);
|
|
|
|
|
+ if (Objects.nonNull(info)) {
|
|
|
|
|
+ elasticsearchTemplate.delete(indexId,clazz);
|
|
|
|
|
+ elasticsearchTemplate.save(clazz);
|
|
|
|
|
+ }
|
|
|
|
|
+ }catch (Exception e) {
|
|
|
|
|
+ logger.error("");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> query(Class<T> clazz,String keyword, String indexName) {
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(new QueryStringQueryBuilder(keyword))
|
|
|
|
|
+ .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
|
|
|
|
|
+ // .withSort(new FieldSortBuilder("createTime").order(SortOrder.DESC))
|
|
|
|
|
+ .build();
|
|
|
|
|
+ // 使用 IndexCoordinates 指定索引
|
|
|
|
|
+ IndexCoordinates indexCoordinates = IndexCoordinates.of(indexName);
|
|
|
|
|
+ List<T> infos = elasticsearchTemplate.search(searchQuery,clazz,indexCoordinates)
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public IPage<T> queryPage(Class<T> clazz, String keyword, Page page, String indexName) {
|
|
|
|
|
+ Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(new QueryStringQueryBuilder(keyword))
|
|
|
|
|
+ .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
|
|
|
|
|
+ .withPageable(pageable)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz);
|
|
|
|
|
+ long totalHits = searchHits.getTotalHits();
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(org.springframework.data.elasticsearch.core.SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ IPage<T> res = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page.getPageIndex(),page.getPageSize());
|
|
|
|
|
+ res.setTotal(totalHits);
|
|
|
|
|
+ res.setRecords(infos);
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public IPage<T> queryHitPage(Class<T> clazz, String keyword, Page page,String ... hightFields) {
|
|
|
|
|
+ Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
|
|
|
|
|
+
|
|
|
|
|
+ HighlightBuilder highlightBuilder = builderHighlightField(hightFields);
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(new QueryStringQueryBuilder(keyword))
|
|
|
|
|
+ .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
|
|
|
|
|
+ .withPageable(pageable)
|
|
|
|
|
+ .withHighlightBuilder(highlightBuilder)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ SearchHits<T> searchHit = elasticsearchTemplate.search(searchQuery,clazz);
|
|
|
|
|
+ List<SearchHit<T>> searchHits = searchHit.getSearchHits();
|
|
|
|
|
+ List<T> infos = new ArrayList<>();
|
|
|
|
|
+ for(SearchHit<T> hit :searchHits) {
|
|
|
|
|
+ T info = hit.getContent();
|
|
|
|
|
+ Map<String, List<String>> maps = hit.getHighlightFields();
|
|
|
|
|
+ for (String key : maps.keySet()) {
|
|
|
|
|
+ List<String> vals = maps.get(key);
|
|
|
|
|
+ if (!CollectionUtils.isEmpty(vals)) {
|
|
|
|
|
+ String fieldValue = vals.get(0);
|
|
|
|
|
+ try {
|
|
|
|
|
+ Field field = info.getClass().getDeclaredField(key);
|
|
|
|
|
+ field.setAccessible(true);
|
|
|
|
|
+ field.set(info,fieldValue);
|
|
|
|
|
+ }catch (Exception e) {
|
|
|
|
|
+ logger.error("---",e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ infos.add(hit.getContent());
|
|
|
|
|
+ }
|
|
|
|
|
+ long totalHits = searchHit.getTotalHits();
|
|
|
|
|
+ IPage<T> res = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page.getPageIndex(),page.getPageSize());
|
|
|
|
|
+ res.setTotal(totalHits);
|
|
|
|
|
+ res.setRecords(infos);
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private HighlightBuilder builderHighlightField(String ... hightFields) {
|
|
|
|
|
+ HighlightBuilder highlightBuilder = new HighlightBuilder();
|
|
|
|
|
+ highlightBuilder.preTags("<em>").postTags("</em>");
|
|
|
|
|
+ //设置高亮的方法
|
|
|
|
|
+ highlightBuilder.highlighterType("plain");
|
|
|
|
|
+ //设置分段的数量不做限制
|
|
|
|
|
+ highlightBuilder.numOfFragments(0);
|
|
|
|
|
+ if (Objects.isNull(hightFields) || hightFields.length == 0) {
|
|
|
|
|
+ return highlightBuilder;
|
|
|
|
|
+ }
|
|
|
|
|
+ for(String hightField : hightFields) {
|
|
|
|
|
+ highlightBuilder.field(hightField);
|
|
|
|
|
+ }
|
|
|
|
|
+ return highlightBuilder;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> queryHit(Class<T> clazz,String keyword,String fieldName,String indexName) {
|
|
|
|
|
+
|
|
|
|
|
+ HighlightBuilder highlightBuilder = new HighlightBuilder()
|
|
|
|
|
+ .field("title")
|
|
|
|
|
+ .preTags("<em>")
|
|
|
|
|
+ .postTags("</em>");
|
|
|
|
|
+ // 构建查询条件
|
|
|
|
|
+ QueryBuilder queryBuilder = QueryBuilders.matchQuery(fieldName,keyword);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建搜索查询
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(queryBuilder)
|
|
|
|
|
+ .withHighlightBuilder(highlightBuilder)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 使用 IndexCoordinates 指定索引
|
|
|
|
|
+ IndexCoordinates indexCoordinates = IndexCoordinates.of(indexName);
|
|
|
|
|
+ // 执行搜索查询
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz,indexCoordinates);
|
|
|
|
|
+// for (HighlightField highlightField : highlightFields) {
|
|
|
|
|
+// String fieldName = highlightField.getName();
|
|
|
|
|
+// String highlightedText = highlightField.getSnippets().get(0);
|
|
|
|
|
+// System.out.println("Highlighted field: " + fieldName + ", Text: " + highlightedText);
|
|
|
|
|
+// }
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> queryHitByPage(Class<T> clazz,Page page,String keyword,String fieldName,String indexName) {
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件
|
|
|
|
|
+ Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
|
|
|
|
|
+ QueryBuilder queryBuilder = QueryBuilders.matchQuery(fieldName,keyword);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建搜索查询
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(queryBuilder)
|
|
|
|
|
+ .withPageable(pageable)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行搜索查询
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(org.springframework.data.elasticsearch.core.SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 高亮显示
|
|
|
|
|
+ * @auther:
|
|
|
|
|
+ * @date:
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> queryHit(Class<T> clazz,String keyword,String indexName,String ... fieldNames) {
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件
|
|
|
|
|
+ QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建搜索查询
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(queryBuilder)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行搜索查询
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz);
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> queryHitByPage(Class<T> clazz,Page page,String keyword,String indexName,String ... fieldNames) {
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件
|
|
|
|
|
+ Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
|
|
|
|
|
+ QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建搜索查询
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(queryBuilder)
|
|
|
|
|
+ .withPageable(pageable)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行搜索查询
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<T> querySimilarityPage(Class<T> clazz,Page page,String keyword,String indexName,String ... fieldNames) {
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件
|
|
|
|
|
+ Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
|
|
|
|
|
+ QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建搜索查询
|
|
|
|
|
+ NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(queryBuilder)
|
|
|
|
|
+ .withPageable(pageable)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行搜索查询
|
|
|
|
|
+ SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
|
|
|
|
|
+ List<T> infos = searchHits
|
|
|
|
|
+ .stream()
|
|
|
|
|
+ .map(SearchHit::getContent)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ return infos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<Map<String, Object>> searchByNameSimilarity(String inputName) {
|
|
|
|
|
+
|
|
|
|
|
+ SearchRequest searchRequest = new SearchRequest("customer_data");
|
|
|
|
|
+ searchRequest.source().query(QueryBuilders.termQuery("customer_name", "sear"));
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ NativeSearchQuery query = new NativeSearchQueryBuilder()
|
|
|
|
|
+ .withQuery(QueryBuilders.fuzzyQuery("customer_name", inputName).fuzziness(Fuzziness.AUTO))
|
|
|
|
|
+ .withPageable(PageRequest.of(0, 10)) // 设置分页,最大返回 10 个结果
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+// Query query = new NativeSearchQueryBuilder()
|
|
|
|
|
+// .withQuery(QueryBuilders.fuzzyQuery("customer_name", inputName)
|
|
|
|
|
+// .fuzziness("AUTO")) // 使用 fuzziness 设置模糊度
|
|
|
|
|
+// .withPageable(PageRequest.of(0, 10)) // 设置分页,最多返回 10 个结果
|
|
|
|
|
+// .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行查询并返回结果
|
|
|
|
|
+ SearchHits<Map> searchHits = elasticsearchTemplate.search(query, Map.class, IndexCoordinates.of("customer_data"));
|
|
|
|
|
+
|
|
|
|
|
+ // 处理查询结果并返回包含 id、customer_name 和 score 的列表
|
|
|
|
|
+ return searchHits.getSearchHits().stream().map(hit -> {
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("id", hit.getId());
|
|
|
|
|
+ result.put("customer_name", ((Map<String, Object>) hit.getContent()).get("customer_name"));
|
|
|
|
|
+ result.put("similarity_score", hit.getScore());
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }).collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|