solrj 開發solr查詢統計方法
java、solrj API開發solr查詢統計方法
solr常用的查詢統計,通過solrj API實現, 有一般的條件過濾查詢、分組查詢、聚合查詢等
import java.util.List; import java.util.Map; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery.ORDER; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.impl.XMLResponseParser; import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.FieldStatsInfo; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.FacetField.Count; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; public class SolrQueryUtil { //solr服務 static HttpSolrServer solr = getServer(); //刪除索引資料 public static void del() throws Exception{ solr.deleteByQuery("*:*", 1000);//刪除全部索引資料 solr.deleteById("myid",1000);//根據id刪除單個索引(可以傳入id的list,刪除多個id) solr.commit(); } //查詢 public static void query() throws Exception{ SolrQuery query; QueryResponse rsp = null; query = new SolrQuery(); query.set("start", "0"); query.set("q", "*:*"); //query.set("start", "0"); //query.set("rows", "10");//設定每頁查詢條數,可用於分頁處理 String outputField = "";//solr的索引欄位設定值 // outputField 對應的索引欄位 query.addFilterQuery("sz_areacode:" + outputField);//新增查詢限定條件,如果沒有FilterQuery欄位,即查詢全部資訊 //範圍查詢,注意TO和空格分隔!*表示萬用字元,[]表示閉包括界限,{}表示開包括界限 query.addFilterQuery("sz_age:" + "[18 "+"TO"+" *");// >=18 query.addFilterQuery("sz_age:" + "[18 "+"TO"+" 30]");// >=18 <=30 query.addFilterQuery("sz_age:" + "{18 "+"TO"+" 30}");// >18 <30 //多個欄位設定,表示並集,相當sql的and query.addFilterQuery("sz_age:" + "18" +" OR "+"sz_address:"+"福田");//表示或查詢 //通配查詢,*表示通配所有字元 ?表示通配一個字元 query.addFilterQuery("sz_address:" + "南山區"+"*");//南山區 後面所有通配 query.addFilterQuery("sz_address:" + "*"+"南山區"+"*");//模糊查詢,包含 南山區 的所有資訊 query.addFilterQuery("sz_address:" + "*"+"南山區");//南山區 前面所有通配 query.addFilterQuery("sz_areacode:" +"4403"+"??");//4403 後面通配兩個字元 query.addSort("sz_age", ORDER.desc); //desc 降序 asc 升序 rsp = solr.query(query); SolrDocumentList docs = rsp.getResults(); long num = docs.getNumFound();//資料總條數 if (docs.size() != 0) { for (SolrDocument doc : docs) { String age = doc.getFieldValue("sz_age").toString();//獲取欄位的字元資訊 } } } //分組查詢(可用於查詢分組、欄位去重) public static void queryFacet() throws Exception { SolrQuery query; QueryResponse rsp = null; List<FacetField> facets = null; query = new SolrQuery(); query.set("start", "0"); query.set("q", "*:*"); query.setFacet(true); //query.setFacetMinCount(1);//設定為分組只統計分組資料大於等於1的,即分組統計count欄位為0的不顯示 //query.setFacetMissing(false);//count欄位為null的不統計 //query.setFacetLimit(10);//返回的統計數量條數,預設按count降序。可用facet.sort 修改 query.addFacetField("sz_areacode"); //query.addFacetField("sz_repyear");//多個欄位可以同時分組,相互不影響,通過facet.getName()區分 rsp = solr.query(query); facets = rsp.getFacetFields(); for (FacetField facet : facets) { //System.out.println(facet.getName());//區分不同欄位的分組 List<Count> counts = facet.getValues();//獲取分組後的統計資訊 System.out.println(counts); int fileds = counts.size();//分組的數量 for (Count count : counts) { long num = count.getCount();//每一個分組所包含的條數,跟getName對應 String name = count.getName();//每一個分組的名稱 } } } //聚合查詢(可用查詢欄位數值總和,注意只有資料型別的欄位,才能使用) public static void queryFields() throws Exception { SolrQuery query; QueryResponse rsp = null; FieldStatsInfo fieldStatsInfo = null; Map<String,FieldStatsInfo> fieldMap = null; query = new SolrQuery(); query.set("start", "0"); query.set("q", "*:*"); query.setGetFieldStatistics(true); query.setGetFieldStatistics("sz_areacode");//設定要聚合查詢的欄位,可以同時設定多個,相互不影響 //query.setGetFieldStatistics("sz_address"); rsp = solr.query(query); fieldMap = rsp.getFieldStatsInfo(); if (!fieldMap.isEmpty()) { for( String key :fieldMap.keySet()) { if (key=="sz_areacode" || "sz_areacode".equals(key)) { fieldStatsInfo = fieldMap.get(key); long allNum = fieldStatsInfo.getCount();//查詢的資料表的總條數 long numSum = Math.round((double)fieldStatsInfo.getSum());//聚合欄位的總和 fieldStatsInfo.getMax();//欄位最大數 fieldStatsInfo.getMin();//欄位最小數 fieldStatsInfo.getStddev();//欄位的平均數 fieldStatsInfo.getName();//聚合的欄位,也可用來判斷不同的聚合 } else if (key=="sz_address" || "sz_address".equals(key)) { fieldStatsInfo = fieldMap.get(key); //通過判斷key區分不同的聚合欄位 } } } } public static HttpSolrServer getServer() { solr = new HttpSolrServer("http://master:8983/solr/sz_grid"); solr.setParser(new XMLResponseParser()); solr.setConnectionTimeout(3000); solr.setDefaultMaxConnectionsPerHost(100); solr.setMaxTotalConnections(100); return solr; } }
最後再附上網上一些關於分組查詢的設定:
1、facet.prefix
表示Facet欄位值的字首.比如facet.field=cpu&facet.prefix=Intel,那麼對cpu欄位進行Facet查詢,返回的cpu都是以“Intel”開頭的。
2、facet.sort
表示Facet欄位值以哪種順序返回.可接受的值為true(count)|false(index,lex). true(count)表示按照count降序; false(index,lex)表示按照欄位值升序(字母,數字的順序)排列.預設情況下為true(count).當facet.limit值為負數時,預設facet.sort= false(index,lex).
3、facet.limit
限制Facet欄位返回的結果條數.預設值為100.如果此值為負數,表示不限制.
4、facet.offset
返回結果集的偏移量,預設為0.它與facet.limit配合使用可以達到分頁的效果.
5、facet.mincount
限制了Facet欄位值的最小count,預設為0.合理設定該引數可以將使用者的關注點集中在少數比較熱門的領域.相當於group by having
6、facet.missing
預設為””,如果設定為true或者on,那麼將統計那些該Facet欄位值為null的記錄.
7、facet.method
取值為enum或fc,預設為fc.該欄位表示了兩種Facet的演算法,與執行效率相關.
enum適用於欄位值比較少的情況,比如欄位型別為布林型,或者欄位表示中國的所有省份.Solr會遍歷該欄位的所有取值,並從filterCache裡為每個值分配一個filter(這裡要求solrconfig.xml裡對filterCache的設定足夠大).然後計算每個filter與主查詢的交集.
fc(表示Field Cache)適用於欄位取值比較多,但在每個文件裡出現次數比較少的情況.Solr會遍歷所有的文件,在每個文件內搜尋Cache內的值,如果找到就將Cache內該值的count加1.
8、facet.enum.cache.minDf
當facet.method=enum時,此引數其作用,minDf表示minimum document frequency.也就是文件內出現某個關鍵字的最少次數.該引數預設值為0.設定該引數可以減少filterCache的記憶體消耗,但會增加總的查詢時間(計算交集的時間增加了).如果設定該值的話,官方文件建議優先嚐試25-50內的值.