zoukankan      html  css  js  c++  java
  • solr整合spring

    说明:solr从整体的开发来讲本身就属于一个NoSQL数据库

    1.先导入需要的依赖包

    2.【solrj】在src/main/profiles/dev/config目录下创建solr.properties资源文件

    # 定义Solr服务器的连接地址
    solr.host.url=http://192.168.144.131/solr/happy-core
    # 设置Solr服务器允许访问的最大连接数量
    solr.host.max.connections=100
    # 每台Solr主机允许连接的最大数量
    solr.host.per.max.connections=10
    # 设置连接的超时时间
    solr.host.connection.timeout=6000
    # 设置创建Socket连接的最大超时时间(网络环境越恶劣越需要加长时间)
    solr.host.socket.timeout=6000
    # 定义Solr服务器的认证信息
    solr.basic.username=lee
    # 定义Solr服务器的密码信息
    solr.basic.password=happy
    

    3.【solrj】创建一个spring/spring-base.xml配置文件,设置相应的扫描路径:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
        <context:component-scan base-package="com.yootk.solrj.config"/><!--在此扫描SolrConfig配置类所在的包-->
        <context:property-placeholder location="classpath:config/solr.properties"/><!--扫描solr.properties资源文件-->
    </beans>
    

    4.【solrj】创建一个SolrConfig配置类,该类主要是获取HttpSolrClient对象

    package com.yootk.solrj.config;
    import org.apache.http.HttpException;
    import org.apache.http.HttpHost;
    import org.apache.http.HttpRequest;
    import org.apache.http.HttpRequestInterceptor;
    import org.apache.http.auth.AuthScope;
    import org.apache.http.auth.AuthState;
    import org.apache.http.auth.ContextAwareAuthScheme;
    import org.apache.http.auth.Credentials;
    import org.apache.http.client.CredentialsProvider;
    import org.apache.http.client.protocol.HttpClientContext;
    import org.apache.http.impl.auth.BasicScheme;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.protocol.HttpContext;
    import org.apache.solr.client.solrj.impl.HttpClientUtil;
    import org.apache.solr.client.solrj.impl.HttpSolrClient;
    import org.apache.solr.common.params.ModifiableSolrParams;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.context.annotation.Scope;
    import java.io.IOException;
    
    @Configuration
    @Scope("prototype") // 取消单例
    @PropertySource("classpath:config/solr.properties")
    public class SolrConfig {
        @Value("${solr.host.url}")
        private String solrHostUrl ;
        @Value("${solr.basic.username}")
        private String username ;
        @Value("${solr.basic.password}")
        private String password ;
        @Value("${solr.host.connection.timeout}")
        private int connectionTimeout ;
        @Value("${solr.host.socket.timeout}")
        private int socketTimeout ;
        @Value("${solr.host.max.connections}")
        private int maxConnection ;
        @Value("${solr.host.per.max.connections}")
        private int preMaxConnection ;
        @Bean("solrClient")//用@Autowired private HttpSolrClient solrClient ;实例化此对象
        public HttpSolrClient getHttpSolrClient() {
            // 定义一个可以保存所有Solr基础配置信息的对象
            ModifiableSolrParams solrParams = new ModifiableSolrParams() ;
            solrParams.set(HttpClientUtil.PROP_BASIC_AUTH_USER,this.username) ;
            solrParams.set(HttpClientUtil.PROP_BASIC_AUTH_PASS,this.password) ;
            solrParams.set(HttpClientUtil.PROP_MAX_CONNECTIONS,this.maxConnection) ; // 允许最大的连接数量
            solrParams.set(HttpClientUtil.PROP_ALLOW_COMPRESSION,true) ; // 允许进行数据的压缩传输
            solrParams.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST,this.preMaxConnection) ;
            solrParams.set(HttpClientUtil.PROP_FOLLOW_REDIRECTS,false) ; // 不进行重定向配置
            // 将拦截器整合在当前的HttpClient创建的工具类之中
            HttpClientUtil.addRequestInterceptor(new AuthRequestInterceptor());
            CloseableHttpClient httpClient = HttpClientUtil.createClient(solrParams);// 设置相关的Solr处理参数
            HttpSolrClient solrClient = new HttpSolrClient.Builder(this.solrHostUrl)
                    .withHttpClient(httpClient).withConnectionTimeout(this.connectionTimeout)
                    .withSocketTimeout(this.socketTimeout).build();
            return solrClient ;
        }
        private class AuthRequestInterceptor implements HttpRequestInterceptor {
            // 对于当前的Solr服务器认证的机制使用的是HttpBase模式完成的
            private ContextAwareAuthScheme authScheme = new BasicScheme() ;
            @Override
            public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {
                // 根据HTTP上下文获取当前目标服务器的认证处理对象
                AuthState authState = (AuthState) httpContext.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
                // 随后需要考虑当前的状态是否存在
                if (authState != null && authState.getAuthScheme() == null) {   // 现在没有具体的认证出合理模式
                    CredentialsProvider credentialsProvider = (CredentialsProvider) httpContext.getAttribute(HttpClientContext.CREDS_PROVIDER) ; // 获取认证提供者
                    HttpHost targetHost = (HttpHost) httpContext.getAttribute(HttpClientContext.HTTP_TARGET_HOST) ;// 获取目标主机
                    // 根据访问的目标主机,通过认证提供者对象创建一个具体的认证信息
                    Credentials credentials = credentialsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
                    if (credentials == null) {  // 没有提供认证处理
                        throw new HttpException("【"+targetHost.getHostName()+"】没有HTTP认证处理支持!") ;
                    }
                    httpRequest.addHeader(authScheme.authenticate(credentials,httpRequest,httpContext));
                }
            }
        }
    }
    

    5.【solrj】创建一个专门测试的类

    package com.yootk.test;
    
    import org.apache.solr.client.solrj.SolrQuery;
    import org.apache.solr.client.solrj.impl.HttpSolrClient;
    import org.apache.solr.client.solrj.response.QueryResponse;
    import org.apache.solr.client.solrj.response.UpdateResponse;
    import org.apache.solr.common.SolrDocument;
    import org.apache.solr.common.SolrDocumentList;
    import org.apache.solr.common.SolrInputDocument;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    @ContextConfiguration(locations = {"classpath:spring/spring-base.xml"})
    @RunWith(SpringJUnit4ClassRunner.class)
    public class TestSolrJ {
        @Autowired
        private HttpSolrClient solrClient ;
        @Test
        public void testAddDocument() throws Exception {
            SolrInputDocument document = new SolrInputDocument() ; // 输入索引
            document.addField("id","989");
            document.addField("solr_s_name","小强王中后火腿");
            document.addField("solr_s_note","德国进口原材料,价格实惠,治疗百病");
            document.addField("solr_s_provider","马老二食品加工");
            document.addField("solr_s_catalog","熟食");
            document.addField("solr_d_price",79.52);
            document.addField("solr_s_photo","qiangqiang.png");
            document.addField("solr_i_isdelete",0);
            document.addField("solr_date_recdate",new Date());
            UpdateResponse response = this.solrClient.add(document);// 向Solr中追加Document
            System.out.println("【花费时间】" + response.getElapsedTime());
            this.solrClient.commit() ;// 提交修改
            this.solrClient.close();
        }
        @Test
        public void testQuery() throws Exception {
            SolrQuery solrQuery = new SolrQuery() ; // 创建查询对象
            solrQuery.setQuery("solr_keywords:*宝*") ; // 查询全部数据
            solrQuery.setSort("solr_d_price", SolrQuery.ORDER.desc) ; // 采用降序排列
            solrQuery.setHighlight(true) ; // 采取高亮配置
            solrQuery.addHighlightField("solr_s_name") ; // 追加高亮显示字段
            solrQuery.setHighlightSimplePre("<strong>") ;   // 高亮标记开始
            solrQuery.setHighlightSimplePost("</strong>") ;  // 高亮标记结束
            // 3、利用SolrClient发出Solr查询命令,随后获取查询响应结果
            QueryResponse queryResponse = this.solrClient.query(solrQuery);
            // 4、所有的HTTP服务器的响应信息都保存在了QueryResponse对象实例之中,根据响应获取数据
            SolrDocumentList results = queryResponse.getResults();// 获取相应的信息
            System.out.println("===================== 普通数据查询 ==================");
            // 5、Document保存的是每一个索引数据,而DocumentList返回的是索引集合
            System.out.println("【数据行数】" + results.getNumFound());
            // 6、所有的数据以List集合的形式出现
            for (SolrDocument document : results) { // 文档迭代输出
                System.out.println("【返回信息】id = " + document.get("id") + "、name = " + document.get("solr_s_name") + "、catalog = " + document.get("solr_s_catalog"));
            }
            System.out.println("===================== 显示高亮数据 ==================");
            Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();// 获取所有的高亮数据
            for (SolrDocument document : results) {
                Map<String,List<String>> resultMap = highlighting.get(document.get("id")) ;
                System.out.println("【高亮显示】" + resultMap.get("solr_s_name"));
            }
            this.solrClient.close();
        }
    }
    

      此时的代码只是简单的将solrj的工具类的操作功能直接交由了Spring负责管理维护,但是对于整体的代码来讲,依然需要用户在每次执行完毕之后手工的进行HttpSolrClient连接的关闭。为了解决此问题,提供了一个新的开发技术:SpringDataSolr。

    采用SpringDataSolr技术(也采用了solrj)

    1.【solr】修改pom.xml配置文件,引入spring-data-solr相关依赖库

    2.【springdatasolr】应用SpringDataSolr技术的时候依然需要SolrConfig类的支持,里面也一定要提供有HttpSolrClient对象实例获取Bean方法(此Bean交由Spring负责管理),这个时候为了方便后续的DAO层的开发,需要设计有一个DAO包名称。

    @Configuration
    @PropertySource("classpath:config/solr.properties")
    @EnableSolrRepositories(basePackages = {"com.yootk.solrj.dao"})//定义IGoodsRepository接口所在的包
    public class SolrConfig {此类的内容与上面的配置类相同,只是类上面的注解不同...}
    

    3.【springdatasolr】修改solr.properties配置文件,在这个配置文件中不再编写core名称

    # 定义Solr服务器的连接地址
    solr.host.url=http://192.168.144.131/solr/
    # 设置Solr服务器允许访问的最大连接数量
    solr.host.max.connections=100
    # 每台Solr主机允许连接的最大数量
    solr.host.per.max.connections=10
    # 设置连接的超时时间
    solr.host.connection.timeout=6000
    # 设置创建Socket连接的最大超时时间(网络环境越恶劣越需要加长时间)
    solr.host.socket.timeout=6000
    # 定义Solr服务器的认证信息
    solr.basic.username=lee
    # 定义Solr服务器的密码信息
    solr.basic.password=happy
    

    4.【springdatasolr】既然要进行Solr数据库的读取,那么对于读取的数据就必须有一个接收的对象类型,创建一个新的VO类

    package com.yootk.solrj.vo;
    
    import org.springframework.data.annotation.Id;
    import org.springframework.data.solr.core.mapping.Indexed;
    import org.springframework.data.solr.core.mapping.SolrDocument;
    
    import java.util.Date;
    
    @SolrDocument(collection = "happy-core")
    public class Goods {    // 描述的是Solr索引结构
        @Id
        @Indexed("id")      // Solr索引结构的名称
        private String id;
        @Indexed("solr_s_name")      // Solr索引结构的名称
        private String name;
        @Indexed("solr_s_catalog")      // Solr索引结构的名称
        private String catalog;
        @Indexed("solr_s_provider")      // Solr索引结构的名称
        private String provider;
        @Indexed("solr_s_note")      // Solr索引结构的名称
        private String note;
        @Indexed("solr_s_photo")      // Solr索引结构的名称
        private String photo;
        @Indexed("solr_d_price")      // Solr索引结构的名称
        private Double price;
        @Indexed("solr_i_isdelete")      // Solr索引结构的名称
        private Integer isdelete;
        @Indexed("solr_date_recdate")      // Solr索引结构的名称
        private Date recdate;
        @Indexed("solr_keywords")      // Solr索引结构的名称
        private String keywords;
    
       setter和getter方法略...
       toString方法略...    
    }
    

    5.【springdatasolr】创建IGoodsRepository接口,但是千万记住其所在的包必须为"com.yootk.solrj.dao"

    强调 :在solr中,不需要覆写IGoodsRepository接口,直接在用的时候实例化此接口对象直接调用其方法即可,因为此接口继承了一个系统内部的接口"SolrCrudRepository"

    package com.yootk.solrj.dao;
    
    import com.yootk.solrj.vo.Goods;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.solr.core.query.result.HighlightPage;
    import org.springframework.data.solr.repository.Highlight;
    import org.springframework.data.solr.repository.SolrCrudRepository;
    
    public interface IGoodsRepository extends SolrCrudRepository<Goods,String> {
        // 此时明确描述了对于当前的关键字的查询使用“keywords”这个属性,“Containing”描述包含
        @Highlight(prefix = "<strong>",postfix = "</strong>")
        public HighlightPage<Goods> findByKeywordsContaining(String keywords, Pageable page) ;
        // 根据名称进行模糊查询
        @Highlight(prefix = "<strong>",postfix = "</strong>")
        public HighlightPage<Goods> findByNameContaining(String keywords, Pageable page) ;
    }
    

    6.src/main/resources这个文件夹里面的内容和上面的相同,只有一个spring-base.xml配置文件,扫描路径也相同。其他的文件和上面的全都相同。

    5.【springdatasolr】编写测试类,进行数据查询的代码测试:

    package com.yootk.test;

    import com.yootk.solrj.dao.IGoodsRepository;
    import com.yootk.solrj.vo.Goods;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.solr.core.query.result.HighlightEntry;
    import org.springframework.data.solr.core.query.result.HighlightPage;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    import java.util.List;

    @ContextConfiguration(locations = {"classpath:spring/spring-base.xml"})
    @RunWith(SpringJUnit4ClassRunner.class)
    public class TestSpringDataSolr {
    @Autowired // 正规的做法是在业务层上注入
    private IGoodsRepository goodsRepository;

    @Test
    public void testKeywords() throws Exception {
    Sort sort = new Sort(Sort.Direction.DESC, "solr_d_price");
    Pageable pageable = PageRequest.of(0, 5, sort); // 分页与排序
    HighlightPage<Goods> result = this.goodsRepository.findByKeywordsContaining("宝", pageable);
    System.out.println("总记录数:" + result.getTotalElements());
    System.out.println("总页数:" + result.getTotalPages());
    List<HighlightEntry<Goods>> entryList = result.getHighlighted();// 得到查询结果
    entryList.forEach((entry) -> {
    System.out.println(entry.getEntity());
    }); // 直接输出最终结果
    }

    @Test
    public void testName() throws Exception {
    Sort sort = new Sort(Sort.Direction.DESC, "solr_d_price");
    Pageable pageable = PageRequest.of(0, 5, sort); // 分页与排序
    HighlightPage<Goods> result = this.goodsRepository.findByNameContaining("小强", pageable);
    System.out.println("总记录数:" + result.getTotalElements());
    System.out.println("总页数:" + result.getTotalPages());
    List<HighlightEntry<Goods>> entryList = result.getHighlighted();// 得到查询结果
    entryList.forEach((entry) -> {
    System.out.println(entry.getEntity());
    }); // 直接输出最终结果
    }

    @Test
    public void testFindAll() throws Exception {
    Iterable<Goods> all = this.goodsRepository.findAll();
    all.forEach(System.out::println); // 直接输出最终结果
    }
    }

      SpringDataSolr最大的好处是可以由Spring容器帮助用户自动的生成一些数据层的处理代码,例如:获取全部数据数量,以及总页数的个数等。

     

  • 相关阅读:
    团队冲刺--第二阶段(五)
    团队冲刺--第二阶段(四)
    团队冲刺--第二阶段(三)
    团队冲刺--第二阶段(二)
    团队冲刺--第二阶段(一)
    第一阶段意见评论
    人月神话阅读笔记02
    基础-定位
    基础-颜色
    标准文档流
  • 原文地址:https://www.cnblogs.com/wxl123/p/11161423.html
Copyright © 2011-2022 走看看