今天就跟大家聊聊有關(guān)solr語(yǔ)法如何在spring中使用,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括鹽津網(wǎng)站建設(shè)、鹽津網(wǎng)站制作、鹽津網(wǎng)頁(yè)制作以及鹽津網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,鹽津網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到鹽津省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
在介紹solr的使用方法之前,我們需要安裝solr的服務(wù)端集群?;旧暇褪前惭bzookeeper,tomcat,jdk,solr,然后按照需要配置三者的配置文件即可。由于本人并沒(méi)有具體操作過(guò)如何進(jìn)行solr集群的搭建。所以關(guān)于如何搭建solr集群,讀者可以去網(wǎng)上查看其它資料,有很多可以借鑒。這里只介紹搭建完solr集群之后,我們客戶端是如何訪問(wèn)solr集群的。
之前介紹過(guò),spring封裝NOSQL和sql數(shù)據(jù)庫(kù)的使用,都是通過(guò)xxxTemplate。solr也不例外。
我們需要引入solr的jar包
org.springframework.data spring-data-solr 1.0.0.RELEASE
然后引入solr在spring中封裝的配置
然后重寫我們的SolrServiceImpl就可以了。
但是,本文我們不用spring中封裝的xxxTemplate這種格式做講解。個(gè)人在使用spring封裝solr的方式的時(shí)候遇到了各種各樣的問(wèn)題,可能是能力太low架控不了吧。下面我們主要講解下如何使用solr的原生api進(jìn)行訪問(wèn)。
首先:
引入solr的原生代碼api的jar包
org.apache.solr solr-solrj 4.7.2
其次:
在spring的配置文件中配置我們solr的FactoryBean類,此類是作為我們編寫自己業(yè)務(wù)service類的屬性來(lái)操作solr。
solr.zkHost是我們配置的zookeeper集群
orderInfo是我們存儲(chǔ)在solr中的數(shù)據(jù)結(jié)構(gòu)bean
再次:
編寫我們的SolrCloudServerFactoryBean類,其中使用了spring的FactoryBean
package com.jd.fms.prism.solr.service; import org.apache.http.client.HttpClient; /** * solrj spring integration * * @author bjchenrui */ public class SolrCloudServerFactoryBean implements FactoryBean, 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 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; } }
最后:
現(xiàn)在就可以編寫我們的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; /** * 創(chuàng)建索引 * * @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,ListqueryTimeList, 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); } //添加過(guò)濾條件 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)){ //如果是會(huì)員類型,則添加模糊查詢 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()) { 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中做聚合,做排序。而且整個(gè)過(guò)程都是秒級(jí)的。 * @param map * @param queryObj * @param queryTimeList * @param page * @param sorts * @return * @throws Exception */ public Page query(Map map,OrderInfo queryObj, List queryTimeList, Pageable page, Sort... sorts) throws Exception { SolrQuery sQuery = iniFilter(null,queryObj,queryTimeList); //添加分頁(yè) 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 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 list1 = new ArrayList (); 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 pageList = new PageImpl (list1,page,list.getNumFound()); return pageList; } /** * 我們可以按照key值進(jìn)行主鍵查詢。 * @param id * @return * @throws Exception */ public List 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 list1 = new ArrayList (); 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 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; } }
當(dāng)然solr的api不止于此,我們此處只是羅列了一些比較常用的使用方法。對(duì)于solr的查詢,有以下幾點(diǎn)需要注意。
1. solr生成查詢語(yǔ)句的時(shí)候,是有q查詢和fq查詢之分的。哪些查詢條件放在q查詢里,哪些查詢條件放在fq查詢里,對(duì)查詢的效率還是有較大的影響的。一般固定不變的查詢條件放在q查詢里,經(jīng)常變化的查詢條件放在fq里。上述代碼中validTag:1就放在了q查詢里,循環(huán)里的字符串filter則放在了我們的fq查詢里。
2. solr查詢時(shí),要了解solr服務(wù)器集群的配置文件中使用的是什么樣的分詞器,不同分詞器對(duì)模糊查詢的結(jié)果是有影響的。比如常見的IK分詞器和標(biāo)準(zhǔn)分詞器(如果我們有一個(gè)字段的名稱為:我是中國(guó)人,ik分詞器在solr里的存儲(chǔ)就成為了“我”,“中國(guó)人”,“中國(guó)”,“國(guó)人”。而標(biāo)準(zhǔn)分詞器則會(huì)存儲(chǔ)為“我”,“是”,“中”,“國(guó)”,“人”。如果我們使用全稱查詢,即查詢:我是中國(guó)人,兩者是沒(méi)有問(wèn)題的。但是使用模糊查詢,比如查詢“*我是*”,則兩個(gè)分詞器分詞都查不出來(lái)結(jié)果,而如果我們的查詢條件是“*中國(guó)人*”則在ik分詞器下可以查詢出結(jié)果,在標(biāo)準(zhǔn)分詞器下查不出結(jié)果。)
3. 使用solr的過(guò)程中,需要定時(shí)執(zhí)行solr的optimize函數(shù)來(lái)清理磁盤碎片,否則會(huì)影響讀寫效率。對(duì)于optimize的參數(shù)建議為(false,false,5)。
4. 寫solr數(shù)據(jù)的時(shí)候,盡量使用createIndexBatch方法,這是因?yàn)閟olr在執(zhí)行寫入的時(shí)候,寫入一條數(shù)據(jù)和寫入多條數(shù)據(jù)都需要全量建索引,其執(zhí)行時(shí)間是差不多的。
看完上述內(nèi)容,你們對(duì)solr語(yǔ)法如何在spring中使用有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。