Elasticsearch 实现博客高亮查询

本篇主要介绍一下 如何使用 es 来实现高亮查询, 应用场景为我的博客系统的搜索, 以前博客服务器内存不够安装es , 现在换了台服务器 勉强够用 并且把高亮搜索集成了


效果如下:

可以看到实现了标题和短描述的多字段高亮

Elasticsearch 实现博客高亮查询


1.准备工作

使用的版本如下:

elasticsearch 版本: 7.17.5

elasticsearch-rest-high-level-client 客户端工具 : 7.4.2

elasticsearch-analysis-ik-7.17.5  分词器


es的安装以及 分词器插件安装 就不介绍了


2.博客项目集成准备

做一些集成 准备工作 包括依赖准备 配置 等

2.1 pom 依赖配置

由于我的springboot依赖的是 6.8.8 , 所以我需要提升一下版本 ,注意springboot的依赖传递问题

<dependency>
   <groupId>org.elasticsearch</groupId>
   <artifactId>elasticsearch</artifactId>
   <version>7.4.2</version>
</dependency>

<dependency>
   <groupId>org.elasticsearch.client</groupId>
   <artifactId>elasticsearch-rest-client</artifactId>
   <version>7.4.2</version>
</dependency>

<dependency>
   <groupId>org.elasticsearch.client</groupId>
   <artifactId>elasticsearch-rest-high-level-client</artifactId>
   <version>7.4.2</version>
   <exclusions>
       <exclusion>
           <artifactId>elasticsearch</artifactId>
           <groupId>org.elasticsearch</groupId>
       </exclusion>
       <exclusion>
           <groupId>org.elasticsearch.client</groupId>
           <artifactId>elasticsearch-rest-client</artifactId>
       </exclusion>
   </exclusions>
</dependency>


2.2 设置blog_info  es 索引

可以通过kibana 或者发送 curl 来创建 索引

curl -XPUT "http://127.0.0.1:9200/blog_info" -H 'Content-Type: application/json' -d'
{
"mappings": {
    "properties": {
      "blogTitle": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "blogShortContent": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}'


2.3 配置 es的地址

springboot的 actuator 会对Elasticsearch 进行健康检查 因为检测到引入了 client 包所以需要设置如下配置, 或者直接关闭健康检查 不建议

spring:
elasticsearch:
rest:
  uris: ["http://172.16.225.111:9200"] # 如果不配置


2.4 配置 RestHighLevelClient

@Component
public class RestHighClientConfig {

   private RestHighLevelClient client;

   @Autowired
   //这里可以直接使用 它会读取上面的配置
   private RestClientProperties restClientProperties;

   @PostConstruct
   public void initClient() {
       //String[] ips = {"172.16.225.111:9200"};
       List<String> ips = restClientProperties.getUris();
       HttpHost[] httpHosts = new HttpHost[ips.size()];
       for (int i = 0; i < ips.size(); i++) {
           httpHosts[i] = HttpHost.create(ips.get(i));
      }
       RestClientBuilder builder = RestClient.builder(httpHosts);
       client = new RestHighLevelClient(builder);
  }

   public RestHighLevelClient getClient() {
       return client;
  }
}


2.5 全量刷新文章到 ES

要想查询 肯定要先把文章刷新到 es 中  , 可以提供一个方法一次性刷新

@Override
public void refreshEsAll() {
   List<BlogInfo> blogInfos = blogInfoRepository.findAll();
   blogInfos.forEach(
           blogInfo -> {
               IndexRequest request = new IndexRequest();
               request.index("blog_info").id(String.valueOf(blogInfo.getId()));
               BlogInfoEs blogInfoEs = new BlogInfoEs();
               blogInfoEs.setBlogTitle(blogInfo.getBlogTitle());
               blogInfoEs.setBlogShortContent(blogInfo.getBlogShortContent());
               String jsonStr = gson.toJson(blogInfoEs);
               request.source(jsonStr, XContentType.JSON);
               try {
                   //使用上面提供的 client
                   IndexResponse index = restHighClientConfig.getClient().index(request, RequestOptions.DEFAULT);
                   log.info("[refreshEsAll index result {}]", index.getResult());
              } catch (IOException e) {
                   e.printStackTrace();
              }
          });
}



3. 高亮查询

高亮查询就是把匹配到的term 前面添加你设置的 标签 然后返回在 高亮节点里, 可以供前端直接展示

Elasticsearch 实现博客高亮查询


multiMatchQuery指定多字段查询

highlighter 指定 高亮的pre post 标签, 并且指定 fragmentSize = 20  限制高亮查询的长度


@Override
public List<BlogInfoVo> queryblogfromessearch(String blogTitle) {
   List<BlogInfoVo> blogInfoVos = new ArrayList<>();
   SearchRequest searchRequest = new SearchRequest("blog_info");

   searchRequest.source()
          .query(QueryBuilders.multiMatchQuery(blogTitle, "blogTitle", "blogShortContent")
                  .operator(Operator.OR))
          .highlighter(new HighlightBuilder().preTags("<font color='red'>")
                  .postTags("</font>")
                    //指定 fragmentSize = 20
                  .field("blogTitle", 20)
                  .field("blogShortContent", 20));

   SearchResponse response = null;
   try {
       response = restHighClientConfig.getClient().search(searchRequest, RequestOptions.DEFAULT);
  } catch (IOException e) {
       e.printStackTrace();
  }
   Optional.ofNullable(response)
          .ifPresent(searchResponse -> {
               searchResponse
                      .getHits()
                      .forEach(p -> {
                           Long id = Long.valueOf(p.getId());
                           String jsonStr = p.getSourceAsString();
                           BlogInfoVo blogInfoVo = gson.fromJson(jsonStr, BlogInfoVo.class);
                           blogInfoVo.setId(id);
                           //由于可能会没有匹配到高亮title , 所以需要先把title设置上 供前端展示
                           blogInfoVo.setBlogHighlightTitle(blogInfoVo.getBlogTitle());
                           Map<String, HighlightField> highlightFields = p.getHighlightFields();
                           Assert.notNull(blogInfoVo, "blogInfoVo is not null");
                           if (!CollectionUtils.isEmpty(highlightFields)) {
                               HighlightField blogTitleHighlight = highlightFields.get("blogTitle");
                               if (blogTitleHighlight != null) {
                                   Text[] fragments = blogTitleHighlight.getFragments();
                                   String highlightValue = fragments[0].toString();
                                   blogInfoVo.setBlogHighlightTitle(highlightValue);
                              }
                               HighlightField blogShortContentHighlight = highlightFields.get("blogShortContent");
                               if (blogShortContentHighlight != null) {
                                   Text[] fragments = blogShortContentHighlight.getFragments();
                                   String highlightValue = fragments[0].toString();
                                 //如果匹配到了短描述的高亮 则替换原有的 内容, 如果没有匹配到则正常展示原有的短描述BlogShortContent
                                   blogInfoVo.setBlogShortContent(highlightValue);
                              }
                          }
                           blogInfoVos.add(blogInfoVo);
                      });
          });
   return blogInfoVos;
}


4. 前端配置

我前端用的vue 所以在vue中要展示 html 则需要 使用 v-html 标签即可

<div style="overflow:auto;max-height:400px">
 <Option
         v-for="item in searchList"
         :value="item.blogTitle"
         :key="item.blogTitle"
         >
   <div style="width: 300px">
      <!--展示标题 -->
     <span class="demo-auto-complete-title" v-html="item.blogHighlightTitle" >
     </span>
   </div>
   <div style="width: 300px">
      <!--展示短描述 -->
     <span class="demo-auto-complete-title_little" v-html="item.blogShortContent" >
     </span>
   </div>
 </Option>
</div>


总结

本篇主要介绍了 ES 高亮查询的一些基本使用方式, 应用场景是自己的博客系统查询, 本篇还是比较简单易懂的, 后续慢慢改进, 最近快过年了 可以稍微打打酱油 祝大家新年快乐!


原文始发于微信公众号(Johnny屋):Elasticsearch 实现博客高亮查询

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/89684.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!