ElasticsearchTemplate实现高亮搜索
1 前言
搜索关键字高亮显示已经变成搜索不可缺少的一个部分,那当然我的搜索肯定也要有这样的功能塞,这样才能够显示我的高端不是吗(ಥ_ಥ)
2 Elasticsearch高亮基础
想要使用elasticsearchTemplate实现高亮搜索,肯定需要了解一下原本elasticsearch怎么高亮搜索,结果又是怎样的。
搜索语句结构
GET /blog/image/_search
{
"query": {
"match": {
"tag": "武器"
}
},
"highlight": {
"fields": {
"tag": {}
}
}
}
结果
3 高亮搜索
3.1 简易版本
public List<Image> searchImageByEs(String search) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//在tag,description域中搜索匹配的内容
//HighlightFields表示高亮设置
//new HighlightBuilder.Field("tag").preTags("<span style=\"color:red\">").postTags("</span>")表示设置高亮域为tag,并加上前置与后置标签
NativeSearchQuery query =
queryBuilder.withQuery(QueryBuilders.multiMatchQuery(search,"tag","description"))
.withHighlightFields(new HighlightBuilder.Field("tag").preTags("<span style=\"color:red\">").postTags("</span>")).build();
//通过elasticsearchTemplate并重写SearchResultMapper方法来实现高亮搜索
AggregatedPage<Image> images = elasticsearchTemplate.queryForPage(query, Image.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
List<Image> imageTemp = new ArrayList<>();
//得到匹配的所有选项
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
if (hits.getHits().length <= 0) {
return null;
}
Image image = new Image();
image.setId(Integer.parseInt(hit.getId()));
image.setUrl(String.valueOf(hit.getSource().get("url")));
image.setDescription(String.valueOf(hit.getSource().get("description")));
image.setType(Integer.parseInt(String.valueOf(hit.getSource().get("type"))));
image.setTag(String.valueOf(hit.getSource().get("tag")));
//扩展性不强,使用反射更好
//防止标签不存在,描述存在的问题
if (hit.getHighlightFields().size()!=0) {
String highlightString = hit.getHighlightFields().get("tag").fragments()[0].toString();
image.setTag(highlightString);
}
imageTemp.add(image);
}
return new AggregatedPageImpl<>((List<T>)imageTemp);
}
});
List<Image> imagesContent = images.getContent();
return imagesContent;
}
注意:
这里的搜索域
不要写错了,是一个常量(你已经创建了的域),不然getHighlightFields一直没有数据
3.2 增强版
public List<Image> highLightQueryPlus(String search) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
NativeSearchQuery query = queryBuilder.withQuery(QueryBuilders.multiMatchQuery(search,"tag","description"))
.withHighlightFields(new HighlightBuilder.Field("tag").preTags("<span style=\"color:red\">").postTags("</span>"),new HighlightBuilder.Field("description").preTags("<span style=\"color:red\">").postTags("</span>")).build();
AggregatedPage<Image> images = elasticsearchTemplate.queryForPage(query, Image.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
List<Image> imageTemp = new ArrayList<>();
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
if (hits.getHits().length <= 0) {
return null;
}
Image image = new Image();
image.setId(Integer.parseInt(hit.getId()));
image.setUrl(String.valueOf(hit.getSource().get("url")));
image.setDescription(String.valueOf(hit.getSource().get("description")));
image.setType(Integer.parseInt(String.valueOf(hit.getSource().get("type"))));
image.setTag(String.valueOf(hit.getSource().get("tag")));
setHighLight(hit,"tag",image);
setHighLight(hit,"description",image);
imageTemp.add(image);
}
return new AggregatedPageImpl<>((List<T>)imageTemp);
}
});
List<Image> imagesContent = images.getContent();
return imagesContent;
}
反射调用属性的set方法设置高亮的内容
public void setHighLight(SearchHit searchHit, String field, Object object) {
Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
HighlightField highlightField = highlightFieldMap.get(field);
if (highlightField != null) {
String highLightMessage = highlightField.fragments()[0].toString();
String capitalize = StringUtils.capitalize(field);
String methodName = "set"+capitalize;
Class<?> clazz = object.getClass();
try {
Method setMethod = clazz.getMethod(methodName, String.class);
setMethod.invoke(object, highLightMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
}