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內的值.