ElasticSearch实现搜索高亮

这里采用 NativeSearchQueryBuilder 进行搜索。

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).withSorts(sortBuilder).build();

如果只需要对一个字段进行高亮,则采用

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
        .withHighlightBuilder(new HighlightBuilder().field("content"))
        .withPageable(pageRequest).withSorts(sortBuilder).build();

若需要对多个字段进行高亮,则

 List<HighlightBuilder.Field> list = new ArrayList<>();
 list.add(new HighlightBuilder.Field("title"));
 list.add(new HighlightBuilder.Field("content"));

 NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
         .withHighlightFields(list)
         .withPageable(pageRequest).withSorts(sortBuilder).build();

再从搜索结果获取数据封装至VO

GET post/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": {
            "query": "1",
            "fields": ["content", "title"]
          }
        }
      ]
    }
  }, 
  "highlight": {
    "fields": {
      "title": {},
      "content": {}
    }
  }
}
"hits" : {
    "total" : {
      "value" : 15,
      "relation" : "eq"
    },
    "max_score" : 3.4328098,
    "hits" : [
      {
        "_index" : "post_v1",
        "_type" : "_doc",
        "_id" : "1722511617964380162",
        "_score" : 3.4328098,
        "_source" : {
          "_class" : "com.yupi.springbootinit.model.dto.post.PostEsDTO",
          "id" : 1722511617964380162,
          "title" : "test1",
          "content" : "test1",
          "tags" : [
            "Java"
          ],
          "userId" : 1722247704249106433,
          "createTime" : "2023-11-09T07:09:07.000Z",
          "updateTime" : "2023-11-09T07:09:07.000Z",
          "isDelete" : 0
        },
        "highlight" : {
          "title" : [
            "test<em>1</em>"
          ],
          "content" : [
            "test<em>1</em>"
          ]
        }
      },
      ...
    ]
  	}

取出第一层hits

SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);

取出第二层hits

List<SearchHit<PostEsDTO>> searchHitList = searchHits.getSearchHits();

使用 “highlight” 中的"title"和"content"

getHighlightField("title");
getHighlightField("content");

完整代码

		List<HighlightBuilder.Field> list = new ArrayList<>();
        list.add(new HighlightBuilder.Field("title"));
        list.add(new HighlightBuilder.Field("content"));
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withHighlightFields(list)
                .withPageable(pageRequest).withSorts(sortBuilder).build();
        SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);
        Page<Post> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        List<Post> resourceList = new ArrayList<>();
        // 查出结果后,从 db 获取最新动态数据(比如点赞数)
        if (searchHits.hasSearchHits()) {
            List<SearchHit<PostEsDTO>> searchHitList = searchHits.getSearchHits();
            List<Long> postIdList = searchHitList.stream().map(searchHit -> searchHit.getContent().getId())
                    .collect(Collectors.toList());
            Map<Long, List<SearchHit<PostEsDTO>>> idEsPostMap =
                    searchHitList.stream().collect(Collectors.groupingBy(searchhit -> searchhit.getContent().getId()));
            List<Post> postList = baseMapper.selectBatchIds(postIdList);
            if (postList != null) {
                Map<Long, List<Post>> idPostMap = postList.stream().collect(Collectors.groupingBy(Post::getId));
                postIdList.forEach(postId -> {
                    if (idPostMap.containsKey(postId)) {
                        Post post = idPostMap.get(postId).get(0);
                        List<String> esTitleList = idEsPostMap.get(postId).get(0).getHighlightField("title");
                        List<String> esContentList = idEsPostMap.get(postId).get(0).getHighlightField("content");
                        if (!esTitleList.isEmpty()) {
                            post.setTitle(esTitleList.get(0));
                        }
                        if (!esContentList.isEmpty()) {
                            post.setContent(esContentList.get(0));
                        }
                        resourceList.add(post);
                    } else {
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(postId), PostEsDTO.class);
                        log.info("delete post {}", delete);
                    }
                });
            }
        }
        page.setRecords(resourceList);
        return page;

这里默认是采用 em 标签
前端部分

<style>
em {
  color: #f73131;
  text-decoration: none;
  font-style: normal;
}
</style>
  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值