如何通过Elasticsearch实现搜索的关键词达到高亮的效果

高亮

首先介绍一下什么是搜索的关键词达到高亮的效果,如图所示

当在百度里面搜索elasticsearch 的时候,可以看到出现的搜索结果里面elasticsearch 这个关键词明显与其他的条文不一样,用红颜色凸显了"高亮效果"。当我们想要在自己的项目里面也实现相同的高亮效果,可以借助ES来帮助我们实现。

通过ES实现高亮效果

现在有一个场景:输入相关的面试题题目返回的结果中题目出现高亮效果,类似这样的效果

那么后端的逻辑应该怎么写呢?(只说明核心逻辑)

首先在查询ES的时候就设置好相应的高亮属性

dart 复制代码
    private EsSearchRequest createSearchListQuery(SubjectInfoES req){
        EsSearchRequest esSearchRequest = new EsSearchRequest();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
		
		//构造查询条件-根据题目名字查询
        MatchQueryBuilder matchNameQueryBuilder =
                QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_NAME,req.getSubjectName());
        boolQueryBuilder.should(matchNameQueryBuilder);
        //设置优先级
        matchNameQueryBuilder.boost(2);

		//其他的代码逻辑...

        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder().field("+").requireFieldMatch(false);
        highlightBuilder.preTags("<span style = \"color:red\">");
        highlightBuilder.postTags("</span>");

        //设置高亮和条件
        esSearchRequest.setHighlightBuilder(highlightBuilder);
        esSearchRequest.setBoolQueryBuilder(boolQueryBuilder);
		
		//其他的代码逻辑...

        return esSearchRequest;
    }

这里通过
HighlightBuilder highlightBuilder = new HighlightBuilder().field("+").requireFieldMatch(false);

构造了一个ES的高亮器

在这里,field("+") 表示要对所有字段进行高亮处理
requireFieldMatch(false) 表示不需要确切字段匹配,即如果任何字段中包含查询的关键字 ,都会被高亮显示

如果设置为requireFieldMatch(true)的话 即查询出来的字段中要完全包含查询的关键字才会被高亮处理

java 复制代码
        highlightBuilder.preTags("<span style = \"color:red\">");
        highlightBuilder.postTags("</span>");

这两段代码的意思是要实现高亮的字段在返回给前端的时候会被"<span style = \"color:red\">""</span>"囊括起来,举个例子:<span style = \"color:red\"> elasticsearch倒排索引为什么快 </span>

java 复制代码
        //设置高亮和条件
        esSearchRequest.setHighlightBuilder(highlightBuilder);
        esSearchRequest.setBoolQueryBuilder(boolQueryBuilder);

这两段代码的作用是设置搜索关键词实现高亮和实现高亮的关键词是哪些关键词

在设置好高亮的相关条件以后,就得从ES中查询相关的数据了并且处理相关的数据

java 复制代码
    public PageResult<SubjectInfoES> querySubjectList(SubjectInfoES req) {
		PageResult<SubjectInfoES> pageResult = new PageResult<>();
		//设置相关条件
        EsSearchRequest esSearchRequest = createSearchListQuery(req);
        //搜索
        SearchResponse searchResponse = EsRestClient.searchWithTermQuery(getEsIndexInfo(),esSearchRequest);

        //获取Elasticsearch搜索响应中包含的搜索结果
        SearchHits searchHits = searchResponse.getHits();
        SearchHit[] hits = searchHits.getHits();
        //遍历响应结果
        for (SearchHit hit : hits) {
            //将ES返回的结果映射到返回的实体中的代码....
			
			//开始处理高亮
			
			//高亮的字段
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();

        //处理name的高亮字段
        HighlightField nameHighlightField = highlightFields.get(EsSubjectFields.SUBJECT_NAME);
        if (ObjectUtils.isNotEmpty(nameHighlightField)){
            Text[] fragments = nameHighlightField.fragments();
            StringBuilder stringBuilder = new StringBuilder();
            for (Text fragment : fragments){
                stringBuilder.append(fragment.string());
            }
            result.setSubjectName(stringBuilder.toString());
        }
        //处理内容中的高亮字段
        HighlightField answerHighlightField = highlightFields.get(EsSubjectFields.SUBJECT_ANSWER);
        if (ObjectUtils.isNotEmpty(answerHighlightField)){
            Text[] fragments = answerHighlightField.fragments();
            StringBuilder stringBuilder = new StringBuilder();
            for (Text fragment : fragments){
                stringBuilder.append(fragment.string());
            }
            result.setSubjectAnswer(stringBuilder.toString());
        }
            
            //将ES返回的结果映射到返回的实体中的代码....
        }

		//其他的代码逻辑

        return pageResult;
    }

这段代码展现了如何处理高亮,核心代码实际上是这一段

java 复制代码
        //高亮的字段
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();

        //处理name的高亮字段
        HighlightField nameHighlightField = highlightFields.get(EsSubjectFields.SUBJECT_NAME);
        if (ObjectUtils.isNotEmpty(nameHighlightField)){
            Text[] fragments = nameHighlightField.fragments();
            StringBuilder stringBuilder = new StringBuilder();
            for (Text fragment : fragments){
                stringBuilder.append(fragment.string());
            }
            result.setSubjectName(stringBuilder.toString());
        }

首先调用hit.getHighlightFields()方法返回一个包含文档中高亮字段的映射,然后从高亮字段映射中获取名为 "SUBJECT_NAME" 的高亮字段(也就是题目名字),从高亮字段中提取相关的文本片段,fragments() 方法返回一个 Text 对象数组,每个 Text 对象表示高亮字段中的一个文本片段。

这里解释一下:

现在假设用户搜索了关键词 "Elasticsearch",而搜索结果中包含了一篇文章的标题和摘要,其中标题和摘要分别是两个字段。搜索结果如下:

标题:Introduction to Elasticsearch

如果我们对标题和摘要字段都进行了高亮处理,那么可能会得到以下的高亮结果:

高亮标题:Introduction to <span style="background-color: yellow;"> Elastic </span>search

这个时候fragment(段落)的内容是Introduction to <span style="background-color: yellow;"> Elastic </span>search

最后将每个高亮的文本拼接成一个完整的字符串并存储在结果对象的相应属性中,交给前端进行相应的处理,前端可以使用 HTML 和 CSS 来展示高亮文本,通常会将匹配的关键词用特殊样式标记(例如使用 标签添加背景颜色),以使用户能够直观地看到匹配的部分,最后实现高亮效果。

相关推荐
JAVA面经实录91715 小时前
操作系统(面试全覆盖)
java·计算机网络·面试
编程的一拳超人15 小时前
Maven 国内高速镜像推荐(按速度排序)
java·maven
云烟成雨TD16 小时前
Spring AI 1.x 系列【61】Spring AI 2.0 升级指南
java·人工智能·spring
lulu121654407816 小时前
OpenRouter Fusion 多模型融合架构深度拆解:预算级模型组团打平 Fable 5,多模型协作才是 AGI 的正确打开方式?
java·人工智能·架构·ai编程·agi
雨辰AI16 小时前
生产级实测:SpringBoot3 + 达梦数据库接口从 200ms 优化至 20ms 完整调优指南
java·数据库·spring boot·后端·政务
(Charon)17 小时前
【C++ 面试高频:内存管理、RAII 和智能指针详解】
java·开发语言·word
凡人叶枫17 小时前
Effective C++ 条款39:明智而审慎地使用 private 继承
java·数据库·c++·嵌入式开发
轻刀快马18 小时前
跨越软硬件的共鸣(二):从 Cache 写策略看 Redis 与 DB 的一致性博弈
java·开发语言·redis·计算机组成原理
折哥的程序人生 · 物流技术专研18 小时前
Java 23 种设计模式:从踩坑到精通 | 装饰器模式 —— 比继承更灵活的扩展方式,你用过吗?
java·装饰器模式·java面试·结构型模式·java设计模式·javaio·从踩坑到精通