如何通过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 来展示高亮文本,通常会将匹配的关键词用特殊样式标记(例如使用 标签添加背景颜色),以使用户能够直观地看到匹配的部分,最后实现高亮效果。

相关推荐
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨2 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows
我不是星海3 小时前
1.集合体系补充(1)
java·数据结构
P.H. Infinity3 小时前
【RabbitMQ】07-业务幂等处理
java·rabbitmq·java-rabbitmq
爱吃土豆的程序员4 小时前
java XMLStreamConstants.CDATA 无法识别 <![CDATA[]]>
xml·java·cdata
2401_857610034 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端