Solr之分組統計。
本文實現分組統計的方法是使用了Solr的Facet元件,Facet元件是Solr預設整合的一個元件,Facet元件是Solr預設整合的一個元件。
Facet簡介
Facet是solr的高階搜尋功能之一,可以給使用者提供更友好的搜尋體驗。在搜尋關鍵字的同時,能夠按照Facet的欄位進行分組並統計。
Facet欄位
- 適宜被Facet的欄位
一般代表了實體的某種公共屬性,如商品的分類,商品的製造廠家,書籍的出版商等等。
- Facet欄位的要求
Facet的欄位必須被索引,一般來說該欄位無需分詞,無需儲存。
無需分詞是因為該欄位的值代表了一個整體概念,如電腦的品牌“聯想”代表了一個整體概念,如果拆成“聯”、“想”兩個字都不具有實際意義,另外該欄位的值無需進行大寫轉換等處理,保持其原貌即可。
無需儲存是因為一般而言使用者所關心的並不是該欄位的具體值,而是作為對查詢結果進行分組的一種手段,使用者一般會沿著這個分組進一步深入搜尋。
- 特殊情況
對於一般查詢而言,分詞和儲存都是必要的,比如CPU型別“Intel 酷睿 2 雙核 P7570”,拆分成“Intel”、“酷睿”、“P7570”這樣一些關鍵字並分別索引,可能提供更好的搜尋體驗,但是如果將CPU作為Facet欄位,最好不進行分詞,這樣就造成了矛盾,解決方法為,將CPU欄位設定為不分詞不儲存,然後建立另外一個欄位為它的COPY,對這個COPY的欄位進行分詞和儲存。
<types>
<fieldType name = "string" class = "solr.StrField" omitNorms = "true" />
<fieldType name = "tokened" class = "solr.TextField">
<analyzer>
.......
</analyzer>
</fieldType>
</types>
<fields>
<field name = "cpu" type = "string" indexed = "true" stored = "false" />
<field name = "cpuCopy" type = "tokened" indexed = "true" stored = "true" />
</fields>
<copyField source = "cpu" dest = "cpuCopy" />
Facet元件
Solr的預設requestHandler已經包含了Fact元件(solr.FacetComponent)。如果自定義requestHandler或者對預設的requestHandler自定義元件列表,那麼需要將Facet加入到元件列表中。
<requestHandler name = "standard" class = "solr.SearchHandler" default = "true">
......
<arr name = "components">
<str>自定義元件名</str>
<str>facet</str>
......
</arr>
Facet查詢
進行Facet查詢需要在請求引數中加入facet=on或者facet=true只有這樣Facet元件才起作用。
Field Facet
Facet欄位通過在請求中加入facet.field引數加以宣告,如果需要對多個欄位進行Facet查詢,那麼將該引數宣告多次,例如:
http://localhost:8080/solr/collection1/select?q=*%3A*&start=0&rows=1&wt=xml&indent=true&facet=true&facet.field=category_s&facet.field=modified_1
返回結果:
<?xml version = "1.0" encoding = "UTF-8"?>
<response>
<lst name = "responseHeader">
<int name = "status">0</int>
<int name = "QTime">1</int>
<lst name = "params">
<str name = "facet">true</str>
<str name = "indent">true</str>
<str name = "start">0</str>
<str name = "q">*:*</str>
<arr name = "facet.field">
<str>category_s</str>
<str>modified_l</str>
</arr>
<str name = "wt">xml</str>
<str name = "rows">0</str>
</lst>
</lst>
<result name = "response" numFound = "17971" start = "0"></result>
<lst name = "facet_counts">
<lst name = "facet_queries" />
<lst name = "facet_fields">
<lst name = "category_l">
<int name = "0">5991</int>
<int name = "1">5990</int>
<int name = "2">5990</int>
</lst>
<lst name = "modified_l">
<int name = "1162438554000">951</int>
<int name = "1162438556000">917</int>
<int name = "1162438548000">902</int>
<int name = "1162438546000">674</int>
</lst>
</lst>
<lst name = "facet_dates" />
<lst name = "facet_ranges" />
</lst>
</response>
各個Facet欄位互不影響,且可以針對每個Facet欄位設定查詢引數,以下介紹的引數既可以應用於所有的Facet欄位,也可以應用於每個單獨的Facet欄位,應用於單獨的欄位時通過。
f.欄位名.引數名=引數值。
這種方式呼叫,比如facet.prefix引數應用於cpu欄位,可以採用如下形式:
f.cpu.facet.prefix=Intel
- facet.prefix
表示Facet欄位值的字首,比如facet.field=cpu&facet.prefix=Intel,那麼對cpu欄位進行Facet查詢,返回的cpu都是以Inter開頭的,AMD開頭的cpu型號將不會被統計在內。
- facet.sort
表示Facet欄位值以哪種順序返回,可接受的值為 true(count)|false(index , lex)。true(count)表示按照count值從大到小排列。false(index , lex)標識按照欄位值的自然順序排列(字母,數字的順序)。預設情況下為 true(count)。當facet.limit值為負數時,預設facet.sort=false(index , lex)。
- facet.limit
限制Facet欄位返回的結果條數。預設值為100,如果此值為負數,表示不限制。
- facet.offset
返回結果集的偏移量,預設為0,它與facet.limit配合使用可以達到分頁的效果。
- facet.mincount
限制了Facet欄位值的最小count,預設為0。合理設定該引數可以將使用者的關注點集中在少數比較熱門的領域。
- facet.missing
預設為“ ”。如果設定為true或者on,那麼將統計那些該Facet欄位值為null的記錄。
- facet.method
取值為enum或fc,預設為fc,該欄位表示了兩種facet的演算法,與執行效率相關。
enum適用於欄位值比較少的情況,比如欄位型別為布林型,或者欄位表示中國的所有省份。Solr會遍歷該欄位的所有取值,並從filterCache裡為每個值分配一個filter(這裡要求solrconfig.xml裡對filterCache的設定足夠大)。然後計算每個filter與主查詢的交集。
fc(表示Field Cache)適用於欄位取值比較多,但在每個文件裡出現次數比較少的情況。SOlr會遍歷所有的文件,在每個文件內搜尋Cache內的值,如果找到就將Cache內該值的count加1.
- facet.enum.cache.minDf
當facet.method=enum時,此引數其作用,minDf表示minimum document frequency,也就是文件內出現某個關鍵字的最少次數。該引數預設值為0.設定該引數可以減少filterCache的記憶體消耗,但會增加總的查詢時間(計算交集的時間增加了),如果設定該值的話,官方文件建議優先嚐試25-50內的值。
Date Facet
日期型別的欄位在文件中很常見,如商品上市時間,貨物出倉時間,書籍上架時間等等。某些情況下需要針對這些欄位進行Facet。不過時間欄位的取值無限性,使用者往往關心的不是某個時間點,而是某個時間段內的查詢統計結果。Solr為日期欄位提供了更為方便的查詢統計方式。當然,欄位的型別必須是DateField(或其子型別)。
需要注意的是,使用Date Facet時,欄位名,起始時間,結束時間,時間間隔這4個引數都必須提供。與Field Facet類似,Date Facet也可以對多個欄位進行Facet,並且針對每個欄位都可以單獨設定引數。
facet.date:該引數表示需要進行Date Facet的欄位名,與facet.field一樣,該引數可以被設定多次,表示對多個欄位進行Date Facet。
facet.date.start:起始時間,時間的一般格式為1995-12-31T23:59:59Z,另外可以使用NOW\YEAR\MONTH等等,具體格式可以參考DateField的java doc。
facet.date.end:結束時間。
facet.date.gap:時間間隔。如果start為2009-1-1,end為2010-1-1,gap設定為+1 MONTH表示間隔1個月,那麼將會把這段時間劃分為12個間隔段。
注意:+因為是特殊字元所以應該用%2B代替。
facet.date.hardend:取值可以為true|false,預設為false。它表示gap迭代到end處採用何種處理。
舉例說明:start為2009-1-1,end為2009-12-25,gap為+1 MONTH,
hardend為false的話,最後一個時間段為2009-12-1至2010-1-1;
hardend為true的話,最後一個時間段為2009-12-1至2009-12-25。
facet.date.other:取值範圍為before|after|between|none|all,預設為none。before會對start之前的值做統計,after會對end之後的值做統計。between會對start至end之間所有值做統計。如果hardend為true的話,那麼該值就是各個時間段統計值的和。none表示該項禁用。all表示before,after,all都會統計。
舉例:
&facet=on
&facet.date=date
&facet.date.end=2009-1-1T0:0:0Z
&facet.date.end=2010-1-1T0:0:0Z
&facet.date.gap=%2B1MONTH
&facet.date.other=all
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries" />
<lst name = "facet_fields" />
<lst name = "facet_dates" >
<int name = "2009-01-01T00:00:00Z">5</int>
<int name = "2009-02-01T00:00:00Z">7</int>
<int name = "2009-03-01T00:00:00Z">4</int>
<int name = "2009-04-01T00:00:00Z">3</int>
<int name = "2009-05-01T00:00:00Z">7</int>
<int name = "2009-06-01T00:00:00Z">3</int>
<int name = "2009-07-01T00:00:00Z">6</int>
<int name = "2009-08-01T00:00:00Z">7</int>
<int name = "2009-09-01T00:00:00Z">2</int>
<int name = "2009-10-01T00:00:00Z">4</int>
<int name = "2009-11-01T00:00:00Z">1</int>
<int name = "2009-12-01T00:00:00Z">5</int>
<str name = "gap">+1 MONTH</str>
<date name = "end">2010-01-01T00:00:00Z</date>
<int name = "before">180</int>
<int name = "after">5</int>
<int name = "between">54</int>
</lst>
</lst>
Facet Query
Facet Query利用類似於filter query 的語法提供了更為靈活的Facet。通過facet.query引數,可以對任意欄位進行篩選。
- 例1
&facet=on
&facet.query=date:[2009-1-1T0:0:0 TO 2009-2-1T0:0:0Z]
&facet.query=date:[2009-4-1T0:0:0 TO 2009-5-1T0:0:0Z]
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries">
<int name = "date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]">5</int>
<int name = "date:[2009-4-1T0:0:0Z TO 2009-5-1T0:0:0Z]">3</int>
</lst>
<lst name = "facet_fields" />
<lst name = "facet_dates" />
</lst>
- 例2
&facet=on
&facet.query=date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]
&facet.query=price:[* TO 5000]
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries">
<int name = "date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]">5</int>
<int name = "price:[* TO 5000]">116</int>
</lst>
<lst name = "facet_fields" />
<lst name = "facet_dates" />
</lst>
- 例3:
&facet=on
&facet.query=cpu:[A TO G]
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries">
<int name = "cpu:[A TO G]">11</int>
</lst>
<lst name = "facet_fields" />
<lst name = "facet_dates" />
</lst>
key 操作符
可以用key操作符為Facet欄位取一個別名。
例:
&facet=on
&facet.field={!key=中央處理器}cpu
&facet.field={!key=顯示卡}videoCard
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries" />
<lst name = "facet_fields" />
<lst name = "中央處理器">
<int name = "Inter 酷睿 2雙核 T6600">48</int>
<int name = "Inter 奔騰雙核 T4300">28</int>
<int name = "Intel 酷睿 2雙核 P8700">18</int>
<int name = "Intel 賽揚雙核 T3000">7</int>
</lst>
<lst name = "顯示卡">
<int name = "ATI Mobility Radeon HD 4">63</int>
<int name = "NVIDIA GeForce G 105M">24</int>
<int name = "NVIDIA GeForce GT 240M">21</int>
</lst>
</lst>
tag操作符和ex操作符
當查詢使用filter query的時候,如果filter query的欄位正好是Facet欄位,那麼查詢結果往往被限制在某一個值內。
例:
&fq=screenSize:14
&facet=on
&facet.field=screenSize
返回結果:
<lst name = "facet_counts">
<lst name = "facet_queries" />
<lst name = "facet_fields" >
<lst name = "screenSize">
<int name = "14.0">107</int>
<int name = "10.2">0</int>
<int name = "11.1">0</int>
</lst>
</lst>
<lst name = "facet_dates" />
</lst>
可以看到,螢幕尺寸(screenSize)為14寸的產品共有107件,其他尺寸的產品的數目都是0,這是因為在filter裡已經限制了screenSize:14,這樣,查詢結果中,除了screenSize的這一項之外,其他專案沒有實際的意義。有些時候,使用者希望把結果限制在某一範圍內,又希望查詢該範圍外的概況。比如上述情況,既要把查詢結果限制在14寸屏的筆記本,又想檢視一下其他螢幕尺寸的筆記本有多少產品。這個時候需要用到tag和ex操作符。tag就是把一個filter標記起來,ex(exclude)是在Facet的時候把標記過得filter排除在外。
例:
&fq={!tag=aa}screenSize:44
&facet=on
&facet.field={!ex=aa}screenSize
返回結果:
<lst name = "facet_count" >
<lst name = "facet_queries" />
<lst name = "facet_fields">
<lst name = "screenSize">
<int name = "14.0">107</int>
<int name = "14.1">40</int>
<int name = "13.3">34</int>
<int name = "15.6">22</int>
</lst>
</lst>
<lst name = "facet_dates" />
</lst>
這樣其他螢幕尺寸的統計資訊就有意義了。
SolrJ對Facet的支援
// 初始化查詢物件
String q = "*.*";
SolrQuery query = new SolrQuery(q);
query.setIncludeScore(false); // 是否按每組數量高低排序
query.setFacet(true); // 是否分組查詢
query.setRows(0); // 設定返回結果條數,如果你是分組查詢,你就設定為0
query.addFacetField("modified_l"); // 增加分組欄位
query.addFacetQuery("category_s[0 TO 1]");
QueryResponse rsp = server.query(query);
......
// 取出結果
List<FacetField.Count> list =rsp.getFacetField("modified_l").getValues();
Map<String, Integer> list = rsp.getFacetQuery();
相關推薦
Solr之分組統計。
本文實現分組統計的方法是使用了Solr的Facet元件,Facet元件是Solr預設整合的一個元件,Facet元件是Solr預設整合的一個元件。 Facet簡介 Facet是solr的高階搜尋功能之一,可以給使用者提供更友好的搜尋體驗。在搜尋
oracle資料庫學習筆記(二)之分組統計查詢
統計函式(分組函式) 在oracle裡面對於統計函式提供有很多種,下面主要介紹標準的五個統計函式: - 統計表中的資料量:COUNT(* | 欄位 | DISTINCT 欄位) - 統計平均值: AVG(列) - 求和:SUM(列) - 最大值 :MAX(列) -
Solr之查詢索引。
Solr在不修改任務配置的情況下就可以使用查詢功能,在web專案中應用可以直接URL進行訪問Solr伺服器例如: http://localhost:8080/solr/collection1/select?q=*%3A*&wt=xml&in
python之pandas分組統計
Pandas分組統計佔比 資料例如: 美贊臣標籤 2017-11-15 MOB 女性 110548715660 美贊臣標籤 2017-11-15 MOB 男性 104342715471 美贊臣標籤 2017-11-15
Dubbo之服務分組、分組聚合。
服務分組 當一個介面有多種實現時,可以用group區分。 <dubbo:service group="feedback" interface="com.xxx.IndexService" /> <dubbo:service group="
正則表達式之分組
表達式 字符串 假設有如下幾行文本:"xxx" : {"name" : "123"} "yyy" : {"name" : "456"} "zzz" : {"name" : "789"} 如果匹配出第1條和第3條,那麽可以使用以下的正則表達式:"((xxx)|(zzz))".* 其中,最外層的括
mysql之分組
images sql 技術 src col ron products from tro 1、創建分組 group by SELECT vend_id, COUNT(*) AS num_prods FROM productsGROUP BY vend_id; 在where字
SQL腳本去重分組統計
數據 values name var logs 記錄 寫入 varchar 分享 需求:首先有一張表記錄學生姓名、科目和成績,然後模擬插入幾條數據,腳本如下: create table score ( Name nvarchar(20),--姓名
每天一個JS 小demo之郵件刪除。主要知識點:事件應用
inline order else ont math tee tom seo onchange <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><ti
半小時分組統計個數sql
date insert http minute case src sql com mage select count(1), trunc(a.refund_insert_time, ‘hh24‘) + case when to_char(refund_insert_time
dubbo之分組聚合
XML add ava als iba merge name 所有 comm 按組合並返回結果 ,比如菜單服務,接口一樣,但有多種實現,用group區分,現在消費方需從每種group中調用一次返回結果,合並結果返回,這樣就可以實現聚合菜單項。 相關代碼可以參考 dubbo
R中利用apply、tapply、lapply、sapply、mapply、table等函數進行分組統計--轉載
tor ant 變換 true post 1.0 指定 ntile lec apply() apply(m,dimcode,f,fargs) m 是一個矩陣。 dimcode是維度編號,取1則為對行應用函數,取2則為對列運用函數。 f是函數 fargs是f的可選參數集
shell編程入門之成績統計
童鞋 elif and bin 裏的 ech 文章 找到 -a 備註:如果你是廠裏的童鞋,寫作業找到了這篇文章,希望你不要直接copy^_^,其實試著自己敲一遍會對你幫助很大。 題目要求是把student.txt內的成績進行各個階段的統計,文本格式都是"學號:成績"。 下面
sql server 以10分鐘分組 統計人數
它的 請問 nbsp .com 顯示 當前時間 利用 bubuko where 請問針對時間段從每天早上7點開始統計每十分鐘人 解決思路: 我以前做過一個關於月份的,是說每3個月以分組,其實是一樣的。不過可能啊,整體數據量大會有問題。如果你只是求一天的,那絕對沒問題。【1】
統計思維:程序員數學之概率統計(1)
隨機 解決問題 第一章 個數字 檢驗 對象 特點 總結 clas 第一章: 經驗之談: 觀察的數量太少、選擇偏差、確認偏差、不準確 更好的做法-統計方法: 收集數據,使用大型全國性調查的數據 描述性統計,計算能總結數據的統計量 探索性數據分析,尋找模式、差異和其他能解決問題
第一次個人作業之詞頻統計
前期準備 設計文檔 估計 splay 行處理 字符流 report -- 傳遞 實驗要求 對源文件(*.txt,*.cpp,*.h,*.cs,*.html,*.js,*.java,*.py,*.php等,文件夾內的所有文件)統計字符數、單詞數、行數、詞頻,統計結果以指定格
一:unittest框架配合selenium工具之CSS_selector定位。
fix path unittest xpath itl ace send css max 做了自動化測試這麽久了,一直沒有梳理到元素定位這一塊的內容,其重要性不言而喻。趁著周末有時間,梳理一下。 1,通過id定位 driver.find_element_by_css_sel
linux 之 du 統計文件大小命令使用
dudu 統計文件大小命令使用 [root@10-3-150-16 app]# du --max-depth=1 -h /app/ 1.3G /app/backup 13G /app/workplus 1.1G /app/bak2 4.0K /app/nginx 1.2G
洛谷 P1757 通天之分組背包 【分組背包】
() 發現 由於 problem max mes ble 分組 DC 題目鏈接:https://www.luogu.org/problemnew/show/P1757#sub 題目描述 自01背包問世之後,小A對此深感興趣。一天,小A去遠遊,卻發現他的背包不同於01背包,他
MySQL(七)DQL之分組查詢
員工 location _id cimage width SQ 結果 order by rom 一、語法 select 分組函數,分組後的字段from 表【where 篩選條件】group by 分組的字段【having 分組後的篩選】【order by 排序列表】 二