springboot 2.0集成elasticsearch 7.6.2 (集群)关键字高亮显示(下)

简介: springboot 2.0集成elasticsearch 7.6.2 (集群)关键字高亮显示(下)

正文


四、filter


查询在老寇云交流群发了关于生日快乐的内容(两种方式)


GET /message/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "data": "生日快乐"
          }
        },
        {
          "match": {
            "remark": "老寇云交流群"
          }
        }
      ]
    }
  }
}


GET /message/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "data": "生日快乐"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "remark": "老寇云交流群"
          }
        }
      ]
    }
  }
}


query 与 filter 对比


filter:只会按照搜索条件过滤出所需要的数据,不会计算相关度分数,因此对相关度没有影响,同时内置自动缓存最常使用filter的数据


query:会计算每个文档对搜索条件的相关度,并按相关度排序,然而需要计算相关度,所以无法缓存结果


应用场景:在进行搜索时,需要根据一些条件筛选部分数据,而且不关注其排序,建议使用filter,反之,使用query


五、定制排序规则


constant_score - 举个栗子


GET /message/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "data": "生日快乐"
        }
      },
      "boost": 1.2
    }
  },
  "sort": [
    {
      "createDate": {
        "order": "desc"
      }
    }
  ]
}


六、代码实现


1.引入依赖


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency> 
       <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.6.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.elasticsearch.client</groupId>
                    <artifactId>elasticsearch-rest-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.6.2</version>
        </dependency>


2.增加实体类


@Data
@ApiModel(description = "查询表单实体类")
public class QueryForm implements Serializable {
    /**
     * 页码
     */
    private Integer pageNum = 1;
    /**
     * 条数
     */
    private Integer pageSize = 10;
    /**
     * 是否分页
     */
    private boolean needPage = false;
    /**
     * 查询索引名称
     */
    private String[] indexNames;
    /**
     * 分词搜索
     */
    private List<SearchDTO> queryStringList;
    /**
     * 排序
     */
    private List<SearchDTO> sortFieldList;
    /**
     * 高亮搜索字段
     */
    private List<String> highlightFieldList;
    /**
     * or搜索-精准匹配
     */
    private List<SearchDTO> orSearchList;
}


/**
 * 搜索DTO
 * @author Kou Shenhai 2413176044@leimingtech.com
 * @version 1.0
 * @date 2022/3/15 0015 上午 9:45
 */
@Data
public class SearchDTO implements Serializable {
    private String field;
    private String value;
}


3.分词查询


@Slf4j
@Component
public class ElasticsearchUtil {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    private static final String HIGHLIGHT_PRE_TAGS = "<span class='highlight'>";
    private static final String HIGHLIGHT_POST_TAGS = "</span>";
    private static final String PINYIN_SUFFIX = ".pinyin";
    /**
     * 关键字高亮显示
     * @param queryForm 查询实体类
     * @return
     * @throws IOException
     */
    public HttpResultUtil<SearchVO> search(QueryForm queryForm) throws IOException {
        long startTime = System.currentTimeMillis();
        final String[] indexName = queryForm.getIndexNames();
        final List<SearchDTO> orSearchList = queryForm.getOrSearchList();
        final List<SearchDTO> sortFieldList = queryForm.getSortFieldList();
        final List<String> highlightFieldList = queryForm.getHighlightFieldList();
        final List<SearchDTO> queryStringList = queryForm.getQueryStringList();
        final Integer pageNum = queryForm.getPageNum();
        final Integer pageSize = queryForm.getPageSize();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //用于搜索文档,聚合,定制查询有关操作
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);
        //or查询
        BoolQueryBuilder orQuery = QueryBuilders.boolQuery();
        for (SearchDTO dto : orSearchList) {
            orQuery.should(QueryBuilders.termQuery(dto.getField(),dto.getValue()));
        }
        boolQueryBuilder.must(orQuery);
        //分词查询
        BoolQueryBuilder analysisQuery = QueryBuilders.boolQuery();
        for (SearchDTO dto : queryStringList) {
            final String field = dto.getField();
            //清除左右空格
            String keyword = dto.getValue().trim();
            //处理特殊字符
            keyword = QueryParser.escape(keyword);
            analysisQuery.should(QueryBuilders.queryStringQuery(keyword).field(field).field(field.concat(PINYIN_SUFFIX)));
        }
        boolQueryBuilder.must(analysisQuery);
        //高亮显示数据
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置关键字显示颜色
        highlightBuilder.preTags(HIGHLIGHT_PRE_TAGS);
        highlightBuilder.postTags(HIGHLIGHT_POST_TAGS);
        //设置显示的关键字
        for (String field : highlightFieldList) {
            highlightBuilder.field(field, 0, 0).field(field.concat(PINYIN_SUFFIX), 0, 0);
        }
        highlightBuilder.requireFieldMatch(false);
        //分页
        int start = 0;
        int end = 10000;
        if (queryForm.isNeedPage()) {
            start = (pageNum - 1) * pageSize;
            end = pageSize;
        }
        //设置高亮
        searchSourceBuilder.highlighter(highlightBuilder);
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(end);
        //追踪分数开启
        searchSourceBuilder.trackScores(true);
        //注解
        searchSourceBuilder.explain(true);
        //排序
        for (SearchDTO dto : sortFieldList) {
            SortOrder sortOrder;
            final String desc = "desc";
            final String value = dto.getValue();
            final String field = dto.getField();
            if (desc.equalsIgnoreCase(value)) {
                sortOrder = SortOrder.DESC;
            } else {
                sortOrder = SortOrder.ASC;
            }
            searchSourceBuilder.sort(field,sortOrder);
        }
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchHits hits = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT).getHits();
        List<Map<String,Object>> data = new ArrayList<>();
        for (SearchHit hit : hits){
            Map<String,Object> sourceData = hit.getSourceAsMap();
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            for (String key : highlightFields.keySet()){
                sourceData.put(key,highlightFields.get(key).getFragments()[0].string());
            }
            data.add(sourceData);
        }
        long endTime = System.currentTimeMillis();
        HttpResultUtil<SearchVO> result = new HttpResultUtil();
        SearchVO vo = new SearchVO();
        final String searchData = queryStringList.stream().map(i -> i.getValue()).collect(Collectors.joining(","));
        final List<String> searchFieldList = queryStringList.stream().map(i -> i.getField()).collect(Collectors.toList());
        vo.setRecords(handlerData(data,searchFieldList));
        vo.setTotal(hits.getTotalHits().value);
        vo.setPageNum(queryForm.getPageSize());
        vo.setPageSize(queryForm.getPageSize());
        result.setMsg("搜索 <span class='highlight'>" + searchData + "</span> 找到 " + vo.getTotal() + " 个与之相关的内容,耗时:" + (endTime - startTime) +"ms");
        //处理数据
        result.setData(vo);
        return result;
    }
    /**
     * 处理高亮后的数据
     * @param data ES查询结果集
     */
    private List<Map<String,Object>> handlerData(List<Map<String,Object>> data,List<String> fieldList) {
        log.info("查询结果:{}",data);
        if (CollectionUtils.isEmpty(data)) {
            return Lists.newArrayList();
        }
        if (CollectionUtils.isEmpty(fieldList)) {
            return data;
        }
        for (Map<String, Object> map : data) {
            for (String field : fieldList) {
                if (map.containsKey(field.concat(PINYIN_SUFFIX))) {
                    String result1 = map.get(field).toString();
                    String result2 = map.get(field.concat(PINYIN_SUFFIX)).toString();
                    //将同义词合并
                    for (;;) {
                        int start = result1.indexOf(HIGHLIGHT_PRE_TAGS);
                        int end = result1.indexOf(HIGHLIGHT_POST_TAGS);
                        if (start == -1 || end == -1) {
                            break;
                        }
                        String replaceKeyword = result1.substring(start, end).replace(HIGHLIGHT_PRE_TAGS, "");
                        result2 = result2.replaceAll(replaceKeyword, HIGHLIGHT_PRE_TAGS + replaceKeyword + HIGHLIGHT_POST_TAGS);
                        result1 = result1.substring(end + 1);
                    }
                    map.put(field, result2);
                    map.remove(field.concat(PINYIN_SUFFIX));
                }
            }
        }
        return data;
    }
}


4.api测试


@RestController
@RequestMapping("/api")
@Api(tags = "Elasticsearch API 服务")
public class ElasticsearchController {
    @Autowired
    private ElasticsearchUtil elasticsearchUtil;
    @PostMapping("/search")
    @ApiOperation("ES关键字搜索-高亮显示")
    @ResponseBody
    public HttpResultUtil<SearchVO> search(@RequestBody @Validated final QueryForm queryForm, BindingResult bindingResult) throws IOException {
        if (bindingResult.hasErrors()) {
            return new HttpResultUtil<SearchVO>().error(bindingResult.getFieldError().getDefaultMessage());
        }
        return elasticsearchUtil.search(queryForm);
    }
}


大功告成

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
25天前
|
人工智能 运维 自然语言处理
Elasticsearch AI Assistant 集成 DeepSeek,1分钟搭建智能运维助手
Elasticsearch 新支持 DeepSeek 系列模型,使用 AI 助手,通过自然语言交互,为可观测性分析、安全运维管理及数据智能处理提供一站式解决方案。
401 3
Elasticsearch AI Assistant 集成 DeepSeek,1分钟搭建智能运维助手
|
5月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
5月前
|
JSON Java 网络架构
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
这篇文章介绍了如何使用Spring Boot整合REST方式来搭建和操作Elasticsearch服务。
188 4
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
|
4月前
|
JSON Java API
springboot集成ElasticSearch使用completion实现补全功能
springboot集成ElasticSearch使用completion实现补全功能
78 1
|
4月前
|
消息中间件 监控 Java
您是否已集成 Spring Boot 与 ActiveMQ?
您是否已集成 Spring Boot 与 ActiveMQ?
94 0
|
5月前
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
347 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
5月前
|
自然语言处理 Java Maven
elasticsearch学习二:使用springboot整合TransportClient 进行搭建elasticsearch服务
这篇博客介绍了如何使用Spring Boot整合TransportClient搭建Elasticsearch服务,包括项目创建、Maven依赖、业务代码和测试示例。
204 0
elasticsearch学习二:使用springboot整合TransportClient 进行搭建elasticsearch服务
|
5月前
|
开发框架 监控 搜索推荐
GoFly快速开发框架集成ZincSearch全文搜索引擎 - Elasticsearch轻量级替代为ZincSearch全文搜索引擎
本文介绍了在项目开发中使用ZincSearch作为全文搜索引擎的优势,包括其轻量级、易于安装和使用、资源占用低等特点,以及如何在GoFly快速开发框架中集成和使用ZincSearch,提供了详细的开发文档和实例代码,帮助开发者高效地实现搜索功能。
331 0
|
5月前
|
自然语言处理 搜索推荐 Java
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(一)
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图
95 0
|
5月前
|
存储 自然语言处理 搜索推荐
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(二)
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(二)
84 0