架构实战篇(十一):Spring Boot 集成企业级搜索引擎 SolrCloud

mulan 2018-05-04 13:30:46 ⋅ 593 阅读


SolrCloud 简介

Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库;

Solr是以Lucene为基础实现的文本检索应用服务。Solr部署方式有单机方式、多机Master-Slaver方式、Cloud方式。

SolrCloud是基于Solr和Zookeeper的分布式搜索方案。当索引越来越大,一个单一的系统无法满足磁盘需求,查询速度缓慢,此时就需要分布式索引。在分布式索引中,原来的大索引,将会分成多个小索引,solr可以将这些小索引返回的结果合并,然后返回给客户端。

准备

环境安装

CentOs7.3 搭建 SolrCloud 集群服务

https://segmentfault.com/a/1190000010836061

测试用例

Github 代码

代码我已放到 Github ,导入 spring-boot-solr-cloud 项目

github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-solr-cloud

添加依赖

 
  1. <dependency>

  2.    <groupId>org.springframework.boot</groupId>

  3.    <artifactId>spring-boot-starter-data-solr</artifactId>

  4. </dependency>

  5. <dependency>

  6.    <groupId>org.springframework.data</groupId>

  7.    <artifactId>spring-data-jpa</artifactId>

  8. </dependency>

启用 Solr

 
  1. @Configuration

  2. @EnableSolrRepositories(basePackages = {"io.ymq.solr"}, multicoreSupport = true)

  3. public class SolrConfig {

  4.    @Value("${spring.data.solr.zk-host}")

  5.    private String zkHost;

  6.    @Bean

  7.    public CloudSolrClient solrClient() {

  8.        return new CloudSolrClient(zkHost);

  9.    }

  10. }

映射的实体类

 
  1. @SolrDocument(solrCoreName = "test_collection")

  2. public class Ymq implements Serializable {

  3.    @Id

  4.    @Field

  5.    private String id;

  6.    @Field

  7.    private String ymqTitle;

  8.    @Field

  9.    private String ymqUrl;

  10.    @Field

  11.    private String ymqContent;

  12.  get 。。。

  13.  set 。。。

  14. }

继承 SolrCrudRepository

 
  1. public interface YmqRepository extends SolrCrudRepository<Ymq, String> {

  2.    /**

  3.     * 通过标题查询

  4.     *

  5.     * @param ymqTitle

  6.     * @return

  7.     */

  8.    @Query(" ymqTitle:*?0* ")

  9.    public List<Ymq> findByQueryAnnotation(String ymqTitle);

  10. }

CloudSolrClient 工具类

 
  1. package io.ymq.solr.utils;

  2. import io.ymq.solr.pagehelper.PageInfo;

  3. import io.ymq.solr.pagehelper.PageInfoFacet;

  4. import io.ymq.solr.pagehelper.RowBounds;

  5. import org.apache.solr.client.solrj.SolrQuery;

  6. import org.apache.solr.client.solrj.SolrServerException;

  7. import org.apache.solr.client.solrj.response.QueryResponse;

  8. import java.io.IOException;

  9. import java.util.Collection;

  10. import java.util.List;

  11. /**

  12. * 描述: CloudSolrClient 工具类

  13. *

  14. * @author yanpenglei

  15. * @create 2017-10-19 10:56

  16. **/

  17. public interface BaseSolr {

  18.    /**

  19.     * 添加数据

  20.     *

  21.     * @param defaultCollection solr 库

  22.     * @param bean              对象

  23.     * @throws IOException

  24.     * @throws SolrServerException

  25.     */

  26.    public void add(String defaultCollection, Object bean) throws IOException, SolrServerException;

  27.    /**

  28.     * 添加一组数据

  29.     *

  30.     * @param defaultCollection solr 库

  31.     * @param beans             list集合数据添加

  32.     * @throws IOException

  33.     * @throws SolrServerException

  34.     */

  35.    public void adds(String defaultCollection, Collection<?> beans) throws IOException, SolrServerException;

  36.    /**

  37.     * 根据多个id删除数据

  38.     *

  39.     * @param defaultCollection

  40.     * @param ids

  41.     * @throws IOException

  42.     * @throws SolrServerException

  43.     */

  44.    public void deleteByIds(String defaultCollection, List<String> ids) throws IOException, SolrServerException;

  45.    /**

  46.     * 根据ID删除数据

  47.     *

  48.     * @param defaultCollection solr 库

  49.     * @param id                要删除的文档的id

  50.     * @throws IOException

  51.     * @throws SolrServerException

  52.     */

  53.    public void deleteById(String defaultCollection, String id) throws IOException, SolrServerException;

  54.    /**

  55.     * 根据指定索引(字段)模糊删除数据

  56.     *

  57.     * @param defaultCollection solr 库

  58.     * @param field

  59.     * @param fieldValue

  60.     * @throws IOException

  61.     * @throws SolrServerException

  62.     */

  63.    public void deleteByField(String defaultCollection, String field, String fieldValue) throws IOException, SolrServerException;

  64.    /**

  65.     * 查询数据

  66.     *

  67.     * @param defaultCollection solr 库

  68.     * @param clazz             对象Po

  69.     * @param query             查询条件

  70.     * @param <T>               返回查询集合

  71.     * @return

  72.     * @throws IOException

  73.     * @throws SolrServerException

  74.     */

  75.    public <T> List<T> query(String defaultCollection, Class<T> clazz, SolrQuery query) throws IOException, SolrServerException;

  76.    /**

  77.     * 查询

  78.     *

  79.     * @param defaultCollection solr 库

  80.     * @param query             查询条件

  81.     * @return 返回response对象

  82.     * @throws IOException

  83.     * @throws SolrServerException

  84.     */

  85.    public QueryResponse query(String defaultCollection, SolrQuery query) throws IOException, SolrServerException;

  86.    /**

  87.     * @param defaultCollection solr 库

  88.     * @param clazz             查询的数据对应的对象

  89.     * @param query             查询条件

  90.     * @param rowBounds         分页参数

  91.     * @param <T>

  92.     * @return

  93.     * @throws IOException

  94.     * @throws SolrServerException

  95.     */

  96.    public <T> PageInfo query(String defaultCollection, Class<T> clazz, SolrQuery query, RowBounds rowBounds) throws IOException, SolrServerException;

  97.    /**

  98.     * 查询数据

  99.     *

  100.     * @param defaultCollection solr 库

  101.     * @param query             查询条件

  102.     * @param rowBounds         分页

  103.     * @return

  104.     * @throws IOException

  105.     * @throws SolrServerException

  106.     */

  107.    public PageInfo query(String defaultCollection, SolrQuery query, RowBounds rowBounds) throws IOException, SolrServerException;

  108.    /**

  109.     * solrj的facet结果集查询

  110.     *

  111.     * @param defaultCollection solr 库

  112.     * @param query             查询条件

  113.     * @param rowBounds         分页数

  114.     * @return

  115.     * @throws IOException

  116.     * @throws SolrServerException

  117.     */

  118.    public PageInfoFacet queryFacet(String defaultCollection, SolrQuery query, RowBounds rowBounds) throws IOException, SolrServerException;

  119. }

参数配置

application.properties

 
  1. #SolrCloud zookeeper

  2. spring.data.solr.zk-host=node1:2181,node2:2181,node3:2181

单元测试

 
  1. package io.ymq.solr.test;

  2. import com.alibaba.fastjson.JSONObject;

  3. import io.ymq.solr.YmqRepository;

  4. import io.ymq.solr.pagehelper.PageInfo;

  5. import io.ymq.solr.pagehelper.RowBounds;

  6. import io.ymq.solr.po.Ymq;

  7. import io.ymq.solr.run.Startup;

  8. import io.ymq.solr.utils.BaseSolr;

  9. import org.apache.solr.client.solrj.SolrQuery;

  10. import org.apache.solr.client.solrj.SolrServerException;

  11. import org.apache.solr.client.solrj.impl.CloudSolrClient;

  12. import org.apache.solr.client.solrj.response.QueryResponse;

  13. import org.junit.Test;

  14. import org.junit.runner.RunWith;

  15. import org.springframework.beans.factory.annotation.Autowired;

  16. import org.springframework.boot.test.context.SpringBootTest;

  17. import org.springframework.test.context.junit4.SpringRunner;

  18. import java.io.IOException;

  19. import java.util.List;

  20. /**

  21. * 描述: 测试 solr cloud

  22. *

  23. * @author yanpenglei

  24. * @create 2017-10-17 19:00

  25. **/

  26. @RunWith(SpringRunner.class)

  27. @SpringBootTest(classes = Startup.class)

  28. public class BaseTest {

  29.    @Autowired

  30.    private YmqRepository ymqRepository;

  31.    @Autowired

  32.    private CloudSolrClient cloudSolrClient;

  33.    @Autowired

  34.    private BaseSolr baseSolr;

  35.    /**

  36.     * 使用 ymqRepository 方式新增

  37.     *

  38.     * @throws Exception

  39.     */

  40.    @Test

  41.    public void testAddYmqRepository() {

  42.        Ymq ymq1 = new Ymq();

  43.        ymq1.setId("1");

  44.        ymq1.setYmqTitle("penglei");

  45.        ymq1.setYmqUrl("www_ymq_io");

  46.        ymq1.setYmqContent("ymqContent");

  47.        Ymq ymq2 = new Ymq();

  48.        ymq2.setId("2");//

  49.        ymq2.setYmqTitle("penglei");

  50.        ymq2.setYmqUrl("www_ymq_io");

  51.        ymq2.setYmqContent("ymqContent");

  52.        ymqRepository.save(ymq1);

  53.        ymqRepository.save(ymq2);

  54.    }

  55.    /**

  56.     * 使用 cloudSolrClient 方式新增

  57.     *

  58.     * @throws Exception

  59.     */

  60.    @Test

  61.    public void testAddCloudSolrClient() throws IOException, SolrServerException {

  62.        Ymq ymq = new Ymq();

  63.        ymq.setId("3");

  64.        ymq.setYmqTitle("penglei");

  65.        ymq.setYmqUrl("www_ymq_io");

  66.        ymq.setYmqContent("ymqContent");

  67.        cloudSolrClient.setDefaultCollection("test_collection");

  68.        cloudSolrClient.connect();

  69.        cloudSolrClient.addBean(ymq);

  70.        cloudSolrClient.commit();

  71.    }

  72.    /**

  73.     * 删除数据

  74.     */

  75.    @Test

  76.    public void testDelete() {

  77.        Ymq ymq = new Ymq();

  78.        ymq.setId("4");

  79.        ymq.setYmqTitle("delete_penglei");

  80.        ymq.setYmqUrl("www_ymq_io");

  81.        ymq.setYmqContent("ymqContent");

  82.        // 添加一条测试数据,用于删除的测试数据

  83.        ymqRepository.save(ymq);

  84.        // 通过标题查询数据ID

  85.        List<Ymq> list = ymqRepository.findByQueryAnnotation("delete_penglei");

  86.        for (Ymq item : list) {

  87.            System.out.println("查询响应 :" + JSONObject.toJSONString(item));

  88.            //通过主键 ID 删除

  89.            ymqRepository.delete(item.getId());

  90.        }

  91.    }

  92.    /**

  93.     * data JPA 方式查询

  94.     *

  95.     * @throws Exception

  96.     */

  97.    @Test

  98.    public void testYmqRepositorySearch() throws Exception {

  99.        List<Ymq> list = ymqRepository.findByQueryAnnotation("penglei");

  100.        for (Ymq item : list) {

  101.            System.out.println(" data JPA 方式查询响应 :" + JSONObject.toJSONString(item));

  102.        }

  103.    }

  104.    /**

  105.     * SolrQuery 语法查询

  106.     *

  107.     * @throws Exception

  108.     */

  109.    @Test

  110.    public void testYmqSolrQuery() throws Exception {

  111.        SolrQuery query = new SolrQuery();

  112.        String ymqTitle = "penglei";

  113.        query.setQuery(" ymqTitle:*" + ymqTitle + "* ");

  114.        cloudSolrClient.setDefaultCollection("test_collection");

  115.        cloudSolrClient.connect();

  116.        QueryResponse response = cloudSolrClient.query(query);

  117.        List<Ymq> list = response.getBeans(Ymq.class);

  118.        for (Ymq item : list) {

  119.            System.out.println("SolrQuery 语法查询响应 :" + JSONObject.toJSONString(item));

  120.        }

  121.    }

  122.    /**

  123.     * 使用 baseSolr 工具类 查询

  124.     *

  125.     * @throws Exception

  126.     */

  127.    @Test

  128.    public void testBaseSolrQuery() throws Exception {

  129.        SolrQuery query = new SolrQuery();

  130.        String ymqTitle = "penglei";

  131.        String defaultCollection = "test_collection";

  132.        query.setQuery(" ymqTitle:*" + ymqTitle + "* ");

  133.        List<Ymq> list = baseSolr.query(defaultCollection, Ymq.class, query);

  134.        for (Ymq item : list) {

  135.            System.out.println("baseSolr 工具类  查询响应 :" + JSONObject.toJSONString(item));

  136.        }

  137.    }

  138.    /**

  139.     * 使用 baseSolr 工具类 分页 查询

  140.     *

  141.     * @throws Exception

  142.     */

  143.    @Test

  144.    public void testBaseSolrPageInfoQuery() throws Exception {

  145.        SolrQuery query = new SolrQuery();

  146.        String ymqTitle = "penglei";

  147.        String defaultCollection = "test_collection";

  148.        query.setQuery(" ymqTitle:*" + ymqTitle + "* ");

  149.        PageInfo pageInfo = baseSolr.query(defaultCollection, Ymq.class, query,new RowBounds(0,2));

  150.        System.out.println("使用 baseSolr 工具类 分页 查询响应 :" + JSONObject.toJSONString(pageInfo));

  151.    }

  152. }

一些查询,响应

 
  1. data JPA 方式查询响应 :{"id":"1","ymqContent":"ymqContent","ymqTitle":"penglei","ymqUrl":"www_ymq_io"}

  2. data JPA 方式查询响应 :{"id":"2","ymqContent":"ymqContent","ymqTitle":"penglei","ymqUrl":"www_ymq_io"}

  3. data JPA 方式查询响应 :{"id":"3","ymqContent":"ymqContent","ymqTitle":"penglei","ymqUrl":"www_ymq_io"}

代码我已放到 Github ,导入 spring-boot-solr-cloud 项目

github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-solr-cloud

关注我们

如果需要源码可以关注“IT实战联盟”公众号并留言也可以加入交流群和作者互撩哦~~~

Contact

  • 作者:鹏磊

  • 出处:http://www.ymq.io/2017/10/18/solr-cloud-spring-boot-example

  • Email:admin@souyunku.com

  • 版权归作者所有,转载请注明出处

  • Wechat:关注公众号,搜云库,专注于开发技术的研究与知识分享



全部评论: 0

    我有话说:

    架构实战七):Spring Boot Assembly 整合 thymeleaf

    如何让服务器上的 sprig boot 项目升级变的方便快捷

    架构实战(九):Spring Boot 集成 RocketMQ

    快速集成阿里开源消息队列 RocketMQ

    架构实战三):Spring Boot Logback 邮件通知

    日志对于应用程序来说是非常重要的,当你的程序报错了,而你又不知道是多么可怕的件事情,本文使用logback把程序报错信息邮件到开发者

    微服务架构实战(六):Spring boot2.x 集成阿里大鱼短信接口详解与Demo

    Spring boot2.x 集成阿里大鱼短信接口,发送短信验证码及短信接口详解。

    架构实战):Spring Boot 集成 Dubbo

    Dubbo是阿里巴巴SOA服务化治理方案的核心框架,一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案。

    架构实战五):Spring Boot 解耦之事件驱动

    通过使用spring 事件来解决业务代码的耦合

    架构实战二):Spring Boot 分布式Session共享Redis

    分布式Web网站一般都会碰到集群session共享问题,小编整理了套解决方案,内附GitHub 源码地址哦~~~

    架构实战)-Spring Boot+MyBatis基础架构搭建

    Spring的追求一定是简单点简单点,让java的开发变得更加简单、容易。瞧瞧的告诉你们直接copy就能用哦~~~

    架构实战(三)-Spring Boot架构搭建RESTful API案例

    之前分享了Spring Boot 整合Swagger 让API可视化和前后端分离架构 受到了大家一致好评 ,本节就接着上节的代码做了详细的查询代码的补充和完善并搭建RESTful API架构案例。

    架构实战(七):Spring Boot Data JPA 快速入门

    Spring Data JPA 是Spring Data 的一个子项目,它通过提供基于JPA的Repository极大了减少了操作JPA的代码。

    架构实战(六):Spring Boot RestTemplate的使用

    RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

    架构实战(四):Spring Boot整合 Thymeleaf

    Thymeleaf 是种模板语言。那模板语言或模板引擎是什么?

    架构实战四):Spring Boot 多缓存实战

    多场景下的不同缓存策略解决方案

    架构实战六):Spring Boot Assembly服务化打包

    使用assembly来打包springboot微服务项目,让发布更简单

    码云推荐:一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合微服务架构

    一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合微服务架构.

    SpringBoot+zk+dubbo架构实践(二):SpringBoot 集成 zookeeper

    不啰嗦,本完成两件事:1、搭建SpringBoot 框架;2、基于spring boot框架访问zookeeper。

    架构实战(八):Spring Boot 集成 Druid 数据源监控

    Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。