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容器帮助用户自动的生成一些数据层的处理代码,例如:获取全部数据数量,以及总页数的个数等。

 

原文地址:https://www.cnblogs.com/wxl123/p/11161423.html