使用elasticsearch和springboot开发博客搜索服务

标签:

本文出自jvm123.com-java技术分享站:http://jvm123.com/2019/12/shi-yong.html

使用elasticsearch和springboot开发博客搜索服务,可分为两个部分:

  1. 将博客数据同步到elasticsearch:包括全量同步和增量同步
  2. springboot整合elasticsearch开发搜索功能

elasticsearch 数据同步

先将mysql中的数据同步到es中,才能进行搜索。es的数据同步,一般有一些工具可以完成,其中官方推荐的logstash,通过配置 input、filter 和output,再使用logstash就可以进行数据的同步。

但是,我们也可以手动实现这个功能,通过从mysql中读取数据,再写入elasticsearch中,完成同步。

初次全量同步

将历史数据一次性同步到mysql中。

    /**
    * 全量同步
    */
   public boolean syncAll() {
       int page = 0, size = 10;
       List<Post> postList;
       do {
           postList = postsClient.page(page, size);
           postList.forEach(this::parse);
           postRepository.saveAll(postList);
           page++;
      } while (postList.size() >= size);
       return true;
  }

后续增量同步

以后新增的博客数据,陆续进行同步。设置定时器,每天定时自动同步新增的博客。

    /**
    * 将博客定时同步到elasticsearch中(增量同步)
    */
   @Scheduled(cron = "0 0 0 3 * *")
   public void syncBlog() {
       long maxPostId = postService.maxPostId();
       List<Post> postList = postsClient.page(maxPostId);
       if (postList.isEmpty()) {
           return;
      }
       postList.forEach(this::parse);
       postRepository.saveAll(postList);
  }

Springboot整合elasticsearch搜索

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
* @author yawn http://jvm123.com
* 2019/12/1 10:17
*/
@Service
public class PostService {

   private final Logger logger = LoggerFactory.getLogger(PostService.class);
   private static final Pageable DEFAULT_PAGE = PageRequest.of(0, 24);

   @Autowired
   ElasticsearchTemplate esTemplate;
   @Autowired
   PostRepository postRepository;


   /**
    * 根据标题和内容搜索
    * @param t 标题
    * @param c 内容
    */
   public List<Post> search(String t, String c) {
       BoolQueryBuilder queryBuilder = boolQuery();
       if (StringUtils.isNotBlank(t)) {
           // .boost(2) 表示权重是2
           // matchPhraseQuery 如果查询词是‘java excel’ 会把整体作为一个词来查询
           // matchQuery 如果查询词是‘java excel’ 不会作为一个整体词来查询,默认是or关系
//           queryBuilder.must(matchPhraseQuery("postTitle", t).boost(2));
           queryBuilder.must(matchQuery("postTitle", t).operator(Operator.AND).boost(1.5F));
//           queryBuilder.must(termQuery("postTitle", t));
      }
       if (StringUtils.isNotBlank(c)) {
           queryBuilder.must(matchQuery("postContent", c).boost(1));
      }
       logger.debug("查询:\n{}", queryBuilder.toString());
       Page<Post> posts = postRepository.search(queryBuilder, DEFAULT_PAGE);
       return posts.getContent();
  }

   /**
    * 根据关键词搜索
    * @param wd 关键词
    */
   public List<Post> search(String wd) {
       if (StringUtils.isBlank(wd)) {
           return null;
      }
//       SearchQuery sQuery = new NativeSearchQueryBuilder()
//               .withQuery(
//                       queryStringQuery(wd)
//               )
//               .build();
//       return esTemplate.queryForList(sQuery, Post.class);
       BoolQueryBuilder boolQueryBuilder = boolQuery()
              .should(matchQuery("postTitle", wd))
              .should(matchQuery("postContent", wd));
       logger.debug("查询:{}", boolQueryBuilder.toString());
       Page<Post> posts = postRepository.search(boolQueryBuilder, DEFAULT_PAGE);
       return posts.getContent();
  }

   public long maxPostId() {
       BoolQueryBuilder boolQueryBuilder = boolQuery().must(matchAllQuery());
       FieldSortBuilder sortBuilder = SortBuilders.fieldSort("id").order(SortOrder.DESC);

       NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
              .withQuery(boolQueryBuilder)
              .withSort(sortBuilder)
              .withPageable(PageRequest.of(0, 1))
              .build();
       Page<Post> page = postRepository.search(searchQuery);
       List<Post> posts = page.getContent();
       if (posts.isEmpty()) {
           return 0L;
      }
       Post post = posts.get(0);
       return post.getId();
  }
}

最终文章内容的模糊搜索,也可以很快出现结果。

线上地址: https://blog.jvm123.com/s.html

发表评论