SpringBoot 整合ElasticSearch,实现站内搜索,高亮关键字
ElasticSearch 是目前最风靡的开源框架之一,常用于站内搜索和日志分析。上一篇文章介绍了 ES 和 MySQL 数据同步,本文就介绍 ES 如何集成到 SpringBoot 中,实现基本的查询。 本文主要用于站内搜索,可实现智能分词,高亮关键字等功能,查询速度也很快。 本文采用 ElasticSearch 6.5.0,客户端是 Rest Client
一、整合 SpringBoot
1.pom.xml
<!-- ElasticSearch --> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>6.5.0</version> </dependency> <!-- Java High Level REST Client --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.5.0</version> <exclusions> <exclusion> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </exclusion> </exclusions> </dependency>
2.配置类 ESConfig.java
package com.liuyanzhao.sens.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * ElasticSearch 配置类 * 实例化 client * * @author 言曌 * @date 2019/2/2 下午3:55 */ @Configuration public class ESConfig { @Bean public RestHighLevelClient client() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost", 9200, "http"))); return client; } }
主要用于创建 client,然后要用的地方只需要注入,而不是在方法里,每次 new 一个。 3. Controller 层
@Autowired private RestHighLevelClient client; /** * 搜索 * * @param model model * @param page 当前页码 * @return 模板路径/themes/{theme}/index */ @GetMapping(value = "/search/page/{page}") public String searchPage(Model model, @PathVariable(value = "page") Integer page, @RequestParam("keyword") String keyword) { //默认显示20条 Integer size = 20; //所有日志数据,分页 Page posts = new Page(page, size); // Page<Post> posts = postService.searchByKeywords(HtmlUtil.escape(keyword), pageable); page = page > 0 ? page : 0; //search request SearchRequest searchRequest = new SearchRequest("blog"); //search builder SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.matchQuery("postTitle", keyword)); sourceBuilder.from((page - 1) * size); sourceBuilder.size(size); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //sort sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); //highlight HighlightBuilder highlightBuilder = new HighlightBuilder(); HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("postTitle"); highlightTitle.preTags("<span class=\"highlight\">"); highlightTitle.postTags("</span>"); highlightBuilder.field(highlightTitle); sourceBuilder.highlighter(highlightBuilder); // add builder into request searchRequest.indices("blog"); searchRequest.source(sourceBuilder); //response SearchResponse searchResponse = null; try { searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } TimeValue took = searchResponse.getTook(); //search hits SearchHits hits = searchResponse.getHits(); long totalHits = hits.getTotalHits(); SearchHit[] searchHits = hits.getHits(); List<EsPost> postList = new ArrayList<>(); posts.setTotal((int) totalHits); for (SearchHit hit : searchHits) { String str = hit.getSourceAsString(); EsPost esPost = JSONObject.parseObject(str, EsPost.class); Map<String, HighlightField> highlightFields = hit.getHighlightFields(); HighlightField highlight = highlightFields.get("postTitle"); if (highlight != null) { Text[] fragments = highlight.fragments(); String fragmentString = fragments[0].string(); esPost.setPostTitle(fragmentString); } postList.add(esPost); } posts.setRecords(postList); model.addAttribute("is_index", true); model.addAttribute("posts", posts); model.addAttribute("prefix", "/search"); model.addAttribute("suffix", "?keyword=" + keyword); model.addAttribute("time", took); return this.render("search"); }
没有停止的脚步,只有倒下去的脚步