详解spring中使用solr的代码实现
在介绍solr的使用方法之前,我们需要安装solr的服务端集群。基本上就是安装zookeeper,tomcat,jdk,solr,然后按照需要配置三者的配置文件即可。由于本人并没有具体操作过如何进行solr集群的搭建。所以关于如何搭建solr集群,读者可以去网上查看其它资料,有很多可以借鉴。这里只介绍搭建完solr集群之后,我们客户端是如何访问solr集群的。
之前介绍过,spring封装nosql和sql数据库的使用,都是通过xxxTemplate。solr也不例外。
我们需要引入solr的jar包
org.springframework.data spring-data-solr 1.0.0.RELEASE
然后引入solr在spring中封装的配置
然后重写我们的SolrServiceImpl就可以了。
但是,本文我们不用spring中封装的xxxTemplate这种格式做讲解。个人在使用spring封装solr的方式的时候遇到了各种各样的问题,可能是能力太low架控不了吧。下面我们主要讲解下如何使用solr的原生api进行访问。
首先:
引入solr的原生代码api的jar包
org.apache.solr solr-solrj 4.7.2
其次:
在spring的配置文件中配置我们solr的FactoryBean类,此类是作为我们编写自己业务service类的属性来操作solr。
solr.zkHost是我们配置的zookeeper集群
orderInfo是我们存储在solr中的数据结构bean
再次:
编写我们的SolrCloudServerFactoryBean类,其中使用了spring的FactoryBean
packagecom.jd.fms.prism.solr.service; importorg.apache.http.client.HttpClient; /** *solrjspringintegration * *@authorbjchenrui */ publicclassSolrCloudServerFactoryBeanimplementsFactoryBean,InitializingBean{ privateCloudSolrServercloudSolrServer; privateStringzkHost; privateStringdefaultCollection; privateintmaxConnections=1000; privateintmaxConnectionsPerHost=500; privateintzkClientTimeout=10000; privateintzkConnectTimeout=10000; privateLocklock=newReentrantLock(); publicSolrServergetObject()throwsException{ returncloudSolrServer; } publicClass getObjectType(){ returnSolrServer.class; } publicbooleanisSingleton(){ returntrue; } publicvoidafterPropertiesSet()throwsException{ ModifiableSolrParamsparams=newModifiableSolrParams(); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS,maxConnections); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST,maxConnectionsPerHost); HttpClientclient=HttpClientUtil.createClient(params); LBHttpSolrServerlbServer=newLBHttpSolrServer(client); lock.lock(); try{ if(cloudSolrServer==null){ cloudSolrServer=newCloudSolrServer(zkHost,lbServer); } }finally{ lock.unlock(); } cloudSolrServer.setDefaultCollection(defaultCollection); cloudSolrServer.setZkClientTimeout(zkClientTimeout); cloudSolrServer.setZkConnectTimeout(zkConnectTimeout); } publicvoidsetCloudSolrServer(CloudSolrServercloudSolrServer){ this.cloudSolrServer=cloudSolrServer; } publicvoidsetZkHost(StringzkHost){ this.zkHost=zkHost; } publicvoidsetDefaultCollection(StringdefaultCollection){ this.defaultCollection=defaultCollection; } publicvoidsetMaxConnections(intmaxConnections){ this.maxConnections=maxConnections; } publicvoidsetMaxConnectionsPerHost(intmaxConnectionsPerHost){ this.maxConnectionsPerHost=maxConnectionsPerHost; } publicvoidsetZkClientTimeout(intzkClientTimeout){ this.zkClientTimeout=zkClientTimeout; } publicvoidsetZkConnectTimeout(intzkConnectTimeout){ this.zkConnectTimeout=zkConnectTimeout; } }
最后:
现在就可以编写我们的service类了,这里就是我们具体如何操作solr的地方。
packagecom.jd.fms.prism.solr.service.impl; importcom.jd.fms.prism.common.utils.DateUtil; @Service("orderInfoSolrService") publicclassOrderInfoNativeSolrServiceImpl{ privatestaticSimpleDateFormatsimpleDateFormat=newSimpleDateFormat(DateUtil.FORMATER11); privatestaticSimpleDateFormatsimpleDateFormat1=newSimpleDateFormat(DateUtil.FORMATER4); @Resource(name="orderInfoSolrServer") privateSolrServersolrServer; /** *创建索引 * *@paramorderInfo */ publicvoidcreatIndex(OrderInfoorderInfo)throwsIOException,SolrServerException{ solrServer.addBean(orderInfo); solrServer.commit(); } /** *查询条件的生成。支持字段的精确查询,模糊查询,范围查询。 *@paramorderIdfilter *@paramqueryObj *@paramqueryTimeList *@paramsorts *@return *@throwsException */ publicSolrQueryiniFilter(StringorderIdfilter,OrderInfoqueryObj,ListqueryTimeList,Sort...sorts)throwsException{ SolrQuerysQuery=newSolrQuery(); StringqueryQ="validTag:1"; sQuery.setQuery(queryQ); StringBuilderfilter=newStringBuilder(); if(null!=orderIdfilter){ filter.append(orderIdfilter); queryObj.setOrderId(null); } //添加过滤条件 Field[]fields=queryObj.getClass().getDeclaredFields(); StringfieldName=""; StringfieldValue=""; for(Fieldfield: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 iterator=queryTimeList.iterator(); while(iterator.hasNext()){ QueryTimequeryTime=iterator.next(); StringbeginDate=simpleDateFormat.format(queryTime.getBeginTime().getTime()); StringendDate=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("*:*"); } returnsQuery; } /** *查询代码,可以看到我们可以在solr中做聚合,做排序。而且整个过程都是秒级的。 *@parammap *@paramqueryObj *@paramqueryTimeList *@parampage *@paramsorts *@return *@throwsException */ publicPage query(Mapmap,OrderInfoqueryObj,List queryTimeList,Pageablepage,Sort...sorts)throwsException{ SolrQuerysQuery=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); }*/ QueryResponseresponse=null; sQuery.setGetFieldStatistics("orderPrice"); sQuery.setGetFieldStatistics("duePrice"); sQuery.setGetFieldStatistics("diffPrice"); try{ response=solrServer.query(sQuery); }catch(SolrServerExceptione){ e.printStackTrace(); } SolrDocumentListlist=response.getResults(); Map mapSum=response.getFieldStatsInfo(); StringorderPriceSum=null; if(mapSum.get("orderPrice")!=null&&!mapSum.get("orderPrice").toString().equals("")){ orderPriceSum=mapSum.get("orderPrice").getSum().toString(); } StringduePriceSum=null; if(mapSum.get("duePrice")!=null&&!mapSum.get("duePrice").toString().equals("")){ duePriceSum=mapSum.get("duePrice").getSum().toString(); } StringdiffPriceSum=null; if(mapSum.get("diffPrice")!=null&&!mapSum.get("diffPrice").toString().equals("")){ diffPriceSum=mapSum.get("diffPrice").getSum().toString(); } List list1=newArrayList (); DocumentObjectBinderbinder=newDocumentObjectBinder(); Iteratoriterator=list.iterator(); while(iterator.hasNext()){ OrderInfoorderInfo=binder.getBean(OrderInfo.class,(SolrDocument)iterator.next()); list1.add(orderInfo); } map.put("orderPriceSum",orderPriceSum); map.put("duePriceSum",duePriceSum); map.put("diffPriceSum",diffPriceSum); Page pageList=newPageImpl (list1,page,list.getNumFound()); returnpageList; } /** *我们可以按照key值进行主键查询。 *@paramid *@return *@throwsException */ publicList queryByOrderId(Stringid)throwsException{ SolrQuerysQuery=newSolrQuery(); Stringfilter="orderId"+":"+id; sQuery.setQuery(filter); QueryResponseresponse=null; try{ response=solrServer.query(sQuery); }catch(SolrServerExceptione){ e.printStackTrace(); } SolrDocumentListlist=response.getResults(); List list1=newArrayList (); DocumentObjectBinderbinder=newDocumentObjectBinder(); Iteratoriterator=list.iterator(); while(iterator.hasNext()){ OrderInfoorderInfo=binder.getBean(OrderInfo.class,(SolrDocument)iterator.next()); list1.add(orderInfo); } returnlist1; } publicvoiddeleteAll(OrderInfoorderInfo)throwsIOException,SolrServerException{ StringsQuery="*:*"; solrServer.deleteByQuery(sQuery); } publicvoiddeleteById(Stringid){ } publicvoidcreateIndexBatch(List orderInfoList)throwsIOException,SolrServerException{ solrServer.addBeans(orderInfoList); solrServer.commit(); } publicvoiddeleteBySolrQuery(StringsolrQuery)throwsIOException,SolrServerException{ solrServer.deleteByQuery(solrQuery); solrServer.commit(); } publicSolrServergetSolrServer(){ returnsolrServer; } publicvoidsetSolrServer(SolrServersolrServer){ 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在执行写入的时候,写入一条数据和写入多条数据都需要全量建索引,其执行时间是差不多的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。