京东搜索 - 关键字高亮实现
大约 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渲染搜索词高亮

<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>