在介绍solr的使用方法之前,我们需要安装solr的服务端集群。基本上就是安装zookeeper,tomcat,jdk,solr,然后按照需要配置三者的配置文件即可。由于本人并没有具体操作过如何进行solr集群的搭建。所以关于如何搭建solr集群,读者可以去网上查看其它资料,有很多可以借鉴。这里只介绍搭建完solr集群之后,我们客户端是如何访问solr集群的。
之前介绍过,spring封装nosql和sql数据库的使用,都是通过xxxTemplate。solr也不例外。
我们需要引入solr的jar包
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-solr</artifactId> <version>1.0.0.RELEASE</version> </dependency>
然后引入solr在spring中封装的配置
<bean id="orderInfoSolrServer" class="com.xxxx.SolrCloudServerFactoryBean"> <property name="zkHost" value="${solr.zkHost}"/> <property name="defaultCollection" value="orderInfo"/> <property name="zkClientTimeout" value="6000"/> </bean> <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate" scope="singleton"> <constructor-arg ref="orderInfoSolrServer" /> </bean> <bean id="solrService" class="com.xxxx.SolrServiceImpl"> <property name="solrOperations" ref="solrTemplate" /> </bean>
然后重写我们的SolrServiceImpl就可以了。
但是,本文我们不用spring中封装的xxxTemplate这种格式做讲解。个人在使用spring封装solr的方式的时候遇到了各种各样的问题,可能是能力太low架控不了吧。下面我们主要讲解下如何使用solr的原生api进行访问。
首先:
引入solr的原生代码api的jar包
<dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>4.7.2</version> </dependency>
其次:
在spring的配置文件中配置我们solr的FactoryBean类,此类是作为我们编写自己业务service类的属性来操作solr。
<bean id="orderInfoSolrServer" class="com.xxxx.SolrCloudServerFactoryBean"> <property name="zkHost" value="${solr.zkHost}"/> <property name="defaultCollection" value="orderInfo"/> <property name="zkClientTimeout" value="6000"/> </bean>
solr.zkHost是我们配置的zookeeper集群
orderInfo是我们存储在solr中的数据结构bean
再次:
编写我们的SolrCloudServerFactoryBean类,其中使用了spring的FactoryBean<SolrServer>,和InitializingBean。关于这两者的含义读者可以参考其他资料,基本意思是spring容器在注册该bean之前,需要进行的一些初始化操作。通过afterPropertiesSet方法可以看到我们在使用solr之前做的一些初始化操作。
package com.jd.fms.prism.solr.service; import org.apache.http.client.HttpClient; /** * solrj spring integration * * @author bjchenrui */ public class SolrCloudServerFactoryBean implements FactoryBean<SolrServer>, InitializingBean { private CloudSolrServer cloudSolrServer; private String zkHost; private String defaultCollection; private int maxConnections = 1000; private int maxConnectionsPerHost = 500; private int zkClientTimeout = 10000; private int zkConnectTimeout = 10000; private Lock lock = new ReentrantLock(); public SolrServer getObject() throws Exception { return cloudSolrServer; } public Class<SolrServer> getObjectType() { return SolrServer.class; } public boolean isSingleton() { return true; } public void afterPropertiesSet() throws Exception { ModifiableSolrParams params = new ModifiableSolrParams(); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, maxConnections); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, maxConnectionsPerHost); HttpClient client = HttpClientUtil.createClient(params); LBHttpSolrServer lbServer = new LBHttpSolrServer(client); lock.lock(); try { if(cloudSolrServer == null) { cloudSolrServer = new CloudSolrServer(zkHost, lbServer); } } finally { lock.unlock(); } cloudSolrServer.setDefaultCollection(defaultCollection); cloudSolrServer.setZkClientTimeout(zkClientTimeout); cloudSolrServer.setZkConnectTimeout(zkConnectTimeout); } public void setCloudSolrServer(CloudSolrServer cloudSolrServer) { this.cloudSolrServer = cloudSolrServer; } public void setZkHost(String zkHost) { this.zkHost = zkHost; } public void setDefaultCollection(String defaultCollection) { this.defaultCollection = defaultCollection; } public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } public void setMaxConnectionsPerHost(int maxConnectionsPerHost) { this.maxConnectionsPerHost = maxConnectionsPerHost; } public void setZkClientTimeout(int zkClientTimeout) { this.zkClientTimeout = zkClientTimeout; } public void setZkConnectTimeout(int zkConnectTimeout) { this.zkConnectTimeout = zkConnectTimeout; } }
最后:
现在就可以编写我们的service类了,这里就是我们具体如何操作solr的地方。
package com.jd.fms.prism.solr.service.impl; import com.jd.fms.prism.common.utils.DateUtil; @Service("orderInfoSolrService") public class OrderInfoNativeSolrServiceImpl { private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtil.FORMATER11); private static SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat(DateUtil.FORMATER4); @Resource(name = "orderInfoSolrServer") private SolrServer solrServer; /** * 创建索引 * * @param orderInfo */ public void creatIndex(OrderInfo orderInfo) throws IOException, SolrServerException { solrServer.addBean(orderInfo); solrServer.commit(); } /** * 查询条件的生成。支持字段的精确查询,模糊查询,范围查询。 * @param orderIdfilter * @param queryObj * @param queryTimeList * @param sorts * @return * @throws Exception */ public SolrQuery iniFilter(String orderIdfilter,OrderInfo queryObj,List<QueryTime> queryTimeList, Sort... sorts) throws Exception { SolrQuery sQuery = new SolrQuery(); String queryQ = "validTag:1"; sQuery.setQuery(queryQ); StringBuilder filter = new StringBuilder(); if(null != orderIdfilter){ filter.append(orderIdfilter); queryObj.setOrderId(null); } //添加过滤条件 Field[] fields = queryObj.getClass().getDeclaredFields(); String fieldName = ""; String fieldValue = ""; for (Field field:fields){ if(field.isAnnotationPresent(org.apache.solr.client.solrj.beans.Field.class)){ field.setAccessible(true); fieldName = field.getName(); fieldValue = String.valueOf(field.get(queryObj)); if (null != fieldValue && !"null".equals(fieldValue) && !"".equals(fieldValue) && !"0.0".equals(fieldValue)){ //如果是会员类型,则添加模糊查询 if(fieldName.equals("memberId") || fieldName.equals("orderType")){ fieldValue = "*" + fieldValue + "*"; } filter.append(fieldName + ":" + fieldValue).append(" AND "); } } } if(queryTimeList!=null && queryTimeList.size() > 0) { Iterator<QueryTime> iterator = queryTimeList.iterator(); while(iterator.hasNext()) { QueryTime queryTime = iterator.next(); String beginDate = simpleDateFormat.format(queryTime.getBeginTime().getTime()); String endDate = simpleDateFormat.format(queryTime.getEndTime().getTime()); filter.append(queryTime.getFieldName() + ":" + "[" + beginDate + " TO " + endDate + "] AND "); } } if(filter.length()>0){ filter.delete(filter.length()-5, filter.length()); } sQuery.addFilterQuery(filter.toString()); if(sQuery.toString().equals("")){ sQuery.setQuery("*:*"); } return sQuery; } /** * 查询代码,可以看到我们可以在solr中做聚合,做排序。而且整个过程都是秒级的。 * @param map * @param queryObj * @param queryTimeList * @param page * @param sorts * @return * @throws Exception */ public Page<OrderInfo> query(Map map,OrderInfo queryObj, List<QueryTime> queryTimeList, Pageable page, Sort... sorts) throws Exception { SolrQuery sQuery = iniFilter(null,queryObj,queryTimeList); //添加分页 if(page != null){ sQuery.setStart(page.getPageNumber()*page.getPageSize()); sQuery.setRows(page.getPageSize()); } //添加排序 /*if (null != sorts){ sQuery.setSort("orderId",SolrQuery.ORDER.asc); }*/ QueryResponse response = null; sQuery.setGetFieldStatistics("orderPrice"); sQuery.setGetFieldStatistics("duePrice"); sQuery.setGetFieldStatistics("diffPrice"); try { response = solrServer.query(sQuery); } catch (SolrServerException e) { e.printStackTrace(); } SolrDocumentList list = response.getResults(); Map<String, FieldStatsInfo> mapSum = response.getFieldStatsInfo(); String orderPriceSum = null; if(mapSum.get("orderPrice") != null && !mapSum.get("orderPrice").toString().equals("") ){ orderPriceSum = mapSum.get("orderPrice").getSum().toString(); } String duePriceSum = null; if(mapSum.get("duePrice") != null && !mapSum.get("duePrice").toString().equals("") ){ duePriceSum = mapSum.get("duePrice").getSum().toString(); } String diffPriceSum = null; if(mapSum.get("diffPrice") != null && !mapSum.get("diffPrice").toString().equals("") ){ diffPriceSum = mapSum.get("diffPrice").getSum().toString(); } List<OrderInfo> list1 = new ArrayList<OrderInfo>(); DocumentObjectBinder binder = new DocumentObjectBinder(); Iterator iterator = list.iterator(); while(iterator.hasNext()){ OrderInfo orderInfo = binder.getBean(OrderInfo.class, (SolrDocument) iterator.next()); list1.add(orderInfo); } map.put("orderPriceSum", orderPriceSum); map.put("duePriceSum", duePriceSum); map.put("diffPriceSum", diffPriceSum); Page<OrderInfo> pageList = new PageImpl<OrderInfo>(list1,page,list.getNumFound()); return pageList; } /** * 我们可以按照key值进行主键查询。 * @param id * @return * @throws Exception */ public List<OrderInfo> queryByOrderId(String id) throws Exception { SolrQuery sQuery = new SolrQuery(); String filter = "orderId" + ":" + id; sQuery.setQuery(filter); QueryResponse response = null; try { response = solrServer.query(sQuery); } catch (SolrServerException e) { e.printStackTrace(); } SolrDocumentList list = response.getResults(); List<OrderInfo> list1 = new ArrayList<OrderInfo>(); DocumentObjectBinder binder = new DocumentObjectBinder(); Iterator iterator = list.iterator(); while(iterator.hasNext()){ OrderInfo orderInfo = binder.getBean(OrderInfo.class, (SolrDocument) iterator.next()); list1.add(orderInfo); } return list1; } public void deleteAll(OrderInfo orderInfo) throws IOException, SolrServerException { String sQuery = "*:*"; solrServer.deleteByQuery(sQuery); } public void deleteById(String id) { } public void createIndexBatch(List<OrderInfo> orderInfoList) throws IOException, SolrServerException { solrServer.addBeans(orderInfoList); solrServer.commit(); } public void deleteBySolrQuery(String solrQuery) throws IOException, SolrServerException { solrServer.deleteByQuery(solrQuery); solrServer.commit(); } public SolrServer getSolrServer() { return solrServer; } public void setSolrServer(SolrServer solrServer) { this.solrServer = solrServer; } }
当然solr的api不止于此,我们此处只是罗列了一些比较常用的使用方法。对于solr的查询,有以下几点需要注意。
1. solr生成查询语句的时候,是有q查询和fq查询之分的。哪些查询条件放在q查询里,哪些查询条件放在fq查询里,对查询的效率还是有较大的影响的。一般固定不变的查询条件放在q查询里,经常变化的查询条件放在fq里。上述代码中validTag:1就放在了q查询里,循环里的字符串filter则放在了我们的fq查询里。
2. solr查询时,要了解solr服务器集群的配置文件中使用的是什么样的分词器,不同分词器对模糊查询的结果是有影响的。比如常见的IK分词器和标准分词器(如果我们有一个字段的名称为:我是中国人,ik分词器在solr里的存储就成为了“我”,“中国人”,“中国”,“国人”。而标准分词器则会存储为“我”,“是”,“中”,“国”,“人”。如果我们使用全称查询,即查询:我是中国人,两者是没有问题的。但是使用模糊查询,比如查询“*我是*”,则两个分词器分词都查不出来结果,而如果我们的查询条件是“*中国人*”则在ik分词器下可以查询出结果,在标准分词器下查不出结果。)
3. 使用solr的过程中,需要定时执行solr的optimize函数来清理磁盘碎片,否则会影响读写效率。对于optimize的参数建议为(false,false,5)。
4. 写solr数据的时候,尽量使用createIndexBatch方法,这是因为solr在执行写入的时候,写入一条数据和写入多条数据都需要全量建索引,其执行时间是差不多的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍solr在java中的使用实例代码,包括了solr在java中的使用实例代码的使用技巧和注意事项,需要的朋友参考一下 SolrJ是操作Solr的Java客户端,它提供了增加、修改、删除、查询Solr索引的JAVA接口。SolrJ针对 Solr提供了Rest 的HTTP接口进行了封装, SolrJ底层是通过使用httpClient中的方法来完成Solr的操作。 jar包的引用(mave
本文向大家介绍详解spring封装hbase的代码实现,包括了详解spring封装hbase的代码实现的使用技巧和注意事项,需要的朋友参考一下 前面我们讲了spring封装MongoDB的代码实现,这里我们讲一下spring封装Hbase的代码实现。 hbase的简介: 此处大概说一下,不是我们要讨论的重点。 HBase是一个分布式的、面向列的开源数据库,HBase在Hadoop之上提供了类似于B
本文向大家介绍Yii2中事务的使用实例代码详解,包括了Yii2中事务的使用实例代码详解的使用技巧和注意事项,需要的朋友参考一下 前言 一般我们做业务逻辑,都不会仅仅关联一个数据表,所以,会面临事务问题。 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不
本文向大家介绍使用synchronized实现一个Lock代码详解,包括了使用synchronized实现一个Lock代码详解的使用技巧和注意事项,需要的朋友参考一下 刚看到这个题目的时候无从下手,因为觉得synchronized和lock在加锁的方式上有很大不同,比如,看看正常情况下synchronized时如何加锁的。 方式一: 方式二: 从这两种方式来看,锁都是加在{}之间的,我们再来看看L
本文向大家介绍Python heapq使用详解及实例代码,包括了Python heapq使用详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 Python heapq 详解 Python有一个内置的模块,heapq标准的封装了最小堆的算法实现。下面看两个不错的应用。 小顶堆(求TopK大) 话说需求是这样的: 定长的序列,求出TopK大的数据。 大顶堆(求BtmK小) 这次的需求变得更加的
本文向大家介绍spring缓存代码详解,包括了spring缓存代码详解的使用技巧和注意事项,需要的朋友参考一下 本文研究的主要是spring缓存的相关内容,具体介绍如下。 这篇文章是根据谷歌翻译大致修改出来的,由于原文不知道是什么语,所以可能导致翻译的有错误和不准确的地方,但是大致的方向感觉还是蛮不错的,所以在这里整理了一下,希望能够有所帮助。 高速缓存一直是一个非常需要这两个提高应用程序性能并降