1. 程式人生 > >Solr之分組統計。

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

pythonpandas分組統計

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 排序列表】 二