京东搜索 - 关键字高亮实现

HeJin大约 1 分钟数据库技术ElasticSearch

service层

public List<Map<String, Object>> searchPageHighLighter(String keywords, int pageNo, int pageSize) throws IOException {
    if (pageNo <= 1){
        pageNo = 1;
    }

    SearchRequest searchRequest = new SearchRequest("jd_goods");
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.from(pageNo).size(pageSize);
    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keywords);
    sourceBuilder.query(matchQueryBuilder);
    sourceBuilder.timeout(TimeValue.timeValueSeconds(5));

    // 高亮
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field("title");
    // 关闭多个高亮
    highlightBuilder.requireFieldMatch(false);
    highlightBuilder.preTags("<span style='color:red'>");
    highlightBuilder.postTags("</span>");
    sourceBuilder.highlighter(highlightBuilder);

    searchRequest.source(sourceBuilder);
    SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    List<Map<String, Object>> list = new ArrayList<>();
    Arrays.stream(response.getHits().getHits()).forEach((hit -> {
        // 解析高亮字段
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        HighlightField title = highlightFields.get("title");
        // 原来的结果
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        // 将原来的字段替换为高亮的字段
        if (title != null){
            Text[] texts = title.fragments();
            StringBuilder newTitle = new StringBuilder();
            for (Text text : texts) {
                newTitle.append(text);
            }
            // 高亮字段替换原来的字段
            sourceAsMap.put("title", newTitle);
        }
        list.add(sourceAsMap);
    }));

    return list;
}

controller层

@GetMapping("/search/{keywords}/{pageNo}/{pageSize}")
public List<Map<String, Object>> search(@PathVariable("keywords") String keywords,
                                        @PathVariable("pageNo") int pageNo,
                                        @PathVariable("pageSize") int pageSize) throws IOException {
    return contentService.searchPageHighLighter(keywords, pageNo, pageSize);
}

前端页面使用vue渲染搜索词高亮

image-20210320114310027
image-20210320114310027
<div class="product-iWrap">
    <!--商品封面-->
    <div class="productImg-wrap">
        <a class="productImg">
            <img :src="result.img">
        </a>
    </div>
    <!--价格-->
    <p class="productPrice">
        <em>{{result.price}}</em>
    </p>
    <!--标题-->
    <p class="productTitle">
        <a v-html="result.title"></a>	// vue渲染
    </p>
    <!-- 店铺名 -->
    <div class="productShop">
        <span>店铺: 狂神说Java </span>
    </div>
    <!-- 成交信息 -->
    <p class="productStatus">
        <span>月成交<em>999</em></span>
        <span>评价 <a>3</a></span>
    </p>
</div>