前言:
像百度、360搜索等等,我们输入完搜索条件时,他会自动出来一个提示框,将我们输入的关键词进行自动补全,即搜索推荐。当我们点击搜索后,返回的搜索结果中会将我们搜索的内容进行高亮的显示(不同颜色标记出来),强大的elasticsearch就提供了这些功能。在这里我会使用javaAPI来介绍一下搜索结果Highlight高亮显示和completion suggest搜索推荐的具体实现,方便以后进行查阅。
一、准备开发环境
该项目基于springboot
1.1jdk1.8
1.2elasticsearch需要用到的maven依赖
<!--es-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
1.3elasticsearch的client进行配置,当我们需要用到client的时候直接注入就可以了
@Configuration
public class MyConfig {
@Bean
public TransportClient client() throws UnknownHostException{
//配置节点
InetSocketTransportAddress node = new InetSocketTransportAddress(
InetAddress.getByName("localhost"),
9300
);
//配置settiong
Settings settings = Settings.builder()
.put("cluster.name", "my-application")
.build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(node);
return client;
}
}
二、搜索结果高亮显示
2.1java代码实现Highlight高亮显示
下边的代码中,涉及了项目中分页的一些代码,如果没有需求直接进行删除就可以了。
/**
* 进行搜索
* 将结果进行分页
* @param title
* @return
*/
@RequestMapping("searchItems")
@ResponseBody
public Map<String,Object> goSearch(
@RequestParam(value="title",defaultValue = "") String title,
@RequestParam(value="pageNow",defaultValue = "") String PageNow,
@RequestParam(value="totalCount",defaultValue = "") String totalCount
){
//返回的map,进行数据封装
Map<String,Object> msgMap = new HashMap<String,Object>();
//建立bool查询,如果没有组合查询,直接写QueryBuilder
BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
//使用should实现或者查询
boolBuilder.must(QueryBuilders.matchQuery("title",title));
//查询总记录数和当前页数
long pageSize = 0;
if(totalCount != "" && totalCount != null){
pageSize = new Long(totalCount);
}
long pn = 0;
if(PageNow != "" && PageNow != null){
pn = new Long(PageNow);
}
Page page = new Page(pageSize,pn);
//c查询
SearchRequestBuilder searchRequestBuilder = this.client.prepareSearch("testshop")
.setTypes("item")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH) //设置查询类型:1.SearchType.DFS_QUERY_THEN_FETCH 精确查询; 2.SearchType.SCAN 扫描查询,无序
.setQuery(boolBuilder)
.setFrom(new Long(page.getStartPos()).intValue())
.setSize(10);
//设置高亮显示
HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
highlightBuilder.preTags("<span style=\"color:red\">");
highlightBuilder.postTags("</span>");
searchRequestBuilder.highlighter(highlightBuilder);
//执行结果
SearchResponse response = searchRequestBuilder.get();
//接受结果
List<Map<String,Object>> result = new ArrayList<>();
//遍历结果
for(SearchHit hit:response.getHits()){
Map<String, Object> source = hit.getSource();
//处理高亮片段
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField nameField = highlightFields.get("title");
if(nameField!=null){
Text[] fragments = nameField.fragments();
String nameTmp ="";
for(Text text:fragments){
nameTmp+=text;
}
//将高亮片段组装到结果中去
source.put("title",nameTmp);
}
result.add(source);
}
//封装数据返回
msgMap.put("itemsList",result); //搜索结果
//msgMap.put("page","page"); //分页
msgMap.put("took",response.getTook().getSecondsFrac()); //获取响应需要的时间
msgMap.put("total",totalCount); //获得查询的总记录数
return msgMap;
}
2.2效果展示
实现以下样式,上边的代码是关键,还需要自己写一下前台的js,如果需要源码可以给我留言
三、搜索建议,搜索关键字自动补充
3.1.创建mapping
如果完成搜索建议,需要在mapping中先设置completion
PUT /news_website
{
"mappings": {
"news" : {
"properties" : {
"title" : {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest" : {
"type" : "completion",
"analyzer": "ik_max_word"
}
}
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
使用bulk批量插入一些数据,方便我们进行测试
@RequestMapping("bulk")
@ResponseBody
public String insetDate() throws Exception{
BulkRequestBuilder bulkRequest = client.prepareBulk();
//插入
bulkRequest.add(this.client.prepareIndex("news_website", "news", "1")
.setSource(XContentFactory.jsonBuilder()
.startObject()
.field("title","大话西游电影")
.field("content","大话西游的电影时隔20年即将在2017年4月重映")
.endObject()
)
);
bulkRequest.add(this.client.prepareIndex("news_website", "news", "2")
.setSource(XContentFactory.jsonBuilder()
.startObject()
.field("title","大话西游小说")
.field("content","某知名网络小说作家已经完成了大话西游同名小说的出版")
.endObject()
)
);
bulkRequest.add(this.client.prepareIndex("news_website", "news", "3")
.setSource(XContentFactory.jsonBuilder()
.startObject()
.field("title","大话西游手游")
.field("content","网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中")
.endObject()
)
);
//批量执行
BulkResponse bulkResponse = bulkRequest.get();
//client.close();
return bulkResponse.getTook().toString();
}
3.2javaAPI实现completion suggest搜索推荐
下边的代码是我项目中的一部分代码,我直接将他搬了过来
/**
* 搜索建议
* @param tmptitle
* @return
* @throws UnsupportedEncodingException
*/
@RequestMapping("suggestion")
@ResponseBody
public Map<String,Object> querySuggestion(
@RequestParam(value="tmptitle",defaultValue = "") String tmptitle
) throws UnsupportedEncodingException {
//返回的map,进行数据封装
Map<String,Object> msgMap = new HashMap<String,Object>();
//创建需要搜索的inde和type
SearchRequestBuilder requestBuilder = client.prepareSearch("news_website").setTypes("news");
//设置搜索建议
CompletionSuggestionBuilder completionSuggestionBuilder = new CompletionSuggestionBuilder("title.suggest")
.prefix(tmptitle).size(10);
SuggestBuilder suggestBuilder = new SuggestBuilder().addSuggestion("title.suggest", completionSuggestionBuilder);
requestBuilder.suggest(suggestBuilder);
//进行搜索
SearchResponse suggestResponse = requestBuilder.execute().actionGet();
//用来处理的接受结果
List<String> result = new ArrayList<>();
List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> entries = suggestResponse.getSuggest()
.getSuggestion("title.suggest").getEntries();
//处理结果
for(Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> op:entries){
List<? extends Option> options = op.getOptions();
for(Suggest.Suggestion.Entry.Option pp : options){
result.add(pp.getText().toString());
}
}
msgMap.put("result",result);
return msgMap;
}
3.3查看效果
目前还没有将他整合到页面搜索框中,只是实现了功能,当我们输入 “大话”后,他会自动补全:“大话西游电影”,“大话西游手游”,“大话西游小说”。
以上就是对elasticsearch5.5.2版本的高亮显示和搜索建议的java实现,我的其他文章也讲到了elasticsearch其他的一些知识,如果有需要可以翻阅查看,如果有哪些地方有问题,欢迎大家留言指正,感激不尽!