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