1. 程式人生 > >模糊查詢的一種比MySQL的like更好的搜尋引擎

模糊查詢的一種比MySQL的like更好的搜尋引擎

   有的時候,我們一開始不可能準確地知道搜尋的關鍵字在 Solr 中查詢出的結果是什麼,因此,Solr 還提供了幾種型別的模糊查詢

Solr從資料庫中讀取資料並建立索引速度

一次性建立索引

在JVM記憶體配置為256M時,建立索引至1572865時出現Java heap異常;增加JVM記憶體配置至512M,設定系統環境變數:JAVA_OPTS -Xms256m -Xmx512m,能成功建立2112890條(花費2m 46s)。

平均索引建立速度為:12728/s(兩個string欄位,長度大約為20字元)。

增量建立索引

注意:近實時增量索引需要寫資料庫服務的時間與搜尋引擎伺服器時間同步(資料庫服務時間先於搜尋引擎伺服器時間才行)。使用預設的DIH建立增量索引速度較慢(50/s~400/s),不如全索引(1W/s),因為需要從資料庫中讀取多遍(1、要更新的IDs;2、每1ID去資料庫中重取所有列)。故需要更改DIH增量索引程式,以全索引的方式讀資料;或採取全讀出的方式,一次全讀出所有列。

Solr建立索引效率

速度

Solr建立索引速度與Solr機器CPU正相關,一般情況下CPU佔用率能達到接近100%,記憶體佔用率在預設情況下需達到接近100%,網路、磁碟佔用率均小。因此建立索引的效率瓶頸在CPU及記憶體。當記憶體佔用率維持在接近100%,索引大小達到實體記憶體大小時,插入新的資料容易出現OOM錯誤,這時需要使用ulimit –v unlimited命令更改virtual memory配置為unlimited再啟動Solr便不會出現OOM錯誤。在64位機器系統上,官方推薦使用MMapDirectory。

大小

1億索引大小約為13-16GB,2億索引大小約為30GB

Solr搜尋方式

交集:{name:億度 AND address:海淀} {text:海淀 AND 億度}。

聯集:{name:億度 OR address:海淀} {text:海淀 OR 億度}。

排除:{text:海淀 -億度}。

萬用字元:{bank:中國*銀}。

範圍:{num:[30 TO60]}。

分頁:start rows

排序:sort

Group 權重中文分詞 …

可用的函式

序列 函式 說明
1 abs 絕對值
2 and true/false, 例and(not(exists(popularity)),exists(price))
3 “constant” 浮點數
4 def 返回欄位值, def(myfield, 1.0): 等價於 if(exists(myfield),myfield,1.0)
5 div div(1,y)
6 dist 返回兩個n維向量(點)間的距離;dist(2, x, y, 0, 0): 計算(0,0)和(x,y)之間的歐式距離; dist(1, x, y, 0, 0)計算Manhattan距離。
序列 函式 說明
7 docfreq(field, val) 返回欄位包含val的文件數;docfreq(text,’solr’)
8 exists 返回true如果欄位存在;exists(author);exists(query(price:5.00))
9 field 返回欄位的數值docValues或索引值。等價的三種形式:myFloatFieldName;field(myFloatFieldName);field(“myFloatFieldName”) ;對multivalued docValues欄位:field(myMultiValuedFloatField,min)field(myMultiValuedFloatField,max)
11 idf 反文件頻率;idf(fieldName,’solr’)
12 if 條件查詢函式:if(test,value1,value2); if(termfreq(cat,’electronics’),popularity,42)
13 linear 實現m*x+c,m和c是常量,等價於sum(product(m,x),c)但更高效; linear(x,m,c)
序列 函式 說明
14 log 10為底數的log
15 map map(x,min,max,target), min和max之間的值轉為target,map(x,min,max,target,default), min和max之間的值轉為target, 其他為default
16 max 選擇最大值;max(myfield,myotherfield,0)
17 min 返回最小值;min(myfield,myotherfield,0)
18 ms 返回引數毫秒數;ms()等價ms(NOW); ms(a); ms(a,b) 為a-b的毫秒數, 例: ms(NOW/DAY) ;ms(2000-01-01T00:00:00Z) ;ms(mydatefield) ;ms(NOW,mydatefield) ;ms(mydatefield,2000-01-01T00:00:00Z);ms(datefield1,datefield2) ;
29 norm(field) 返回索引欄位儲存的”norm”, 這是索引時boost和長度規範化因子的product(點積?)
20 maxdoc 返回索引文件數,包括被標記為刪除但還未被purged
21 numdocs 返回索引文件數,不包括被標記為刪除但還未被purged
序列 函式 說明
22 not not(exists(author)): true/false
23 or or(value1,value2): true/false
24 ord 返回欄位索引值在Lucene索引順序中的序號(ordinal)
25 rord 返回ord的逆序
26 pow
27 product 點積(或mul(…)); product(x,y,…)
28 query 返回給定子查詢的分數。query(subquery,default)列,product(popularity, query({!dismax v=’solr rocks’}); 等價於 q=product(popularity,query($qq))&qq={!dismax}solr rocks
序列 函式 說明
29 recip 倒數(reciprocal); recip(x,m,a,b) = a/(m*x+b),當x為rord(datefield)時,這是一個理想的函式用於boosting更多最新的文件。
30 scale 將x值按比例放入[minTarget, maxTarget]範圍內。 scale(x,1,2)
31 sqedist 歐式距離平方。sqedist(x_td, y_td, 0, 0)
32 sqrt 平方根
33 strdist 字串距離,使用Lucene的StringDistance介面。(string1, string2, distance measure); strdist(“SOLR”,id,edit), distance measure: jw(Jaro-Winkler), edit(Levenstein或編輯距離),ngram(預設2)
34 sub sub(x,y) = x - y
35 sum 求和(或add(…));
序列 函式 說明
36 sumtotaltermfreq 或sttf, 返回欄位索引中所有terms的總頻次。
37 termfreq 返回文件中term出現的次數。 termfreq(text, ‘memory’)
38 tf 返回指定欄位在Similarity中使用的tf因子。 termfreq(text, ‘solr’)
39 top top(query)使查詢從整個索引獲取資料。如一個segment中的值順序與在整個索引中的順序不一樣。ord()和rord()隱身的使用top(); 即ord()=top(ord())
40 totaltermfreq 或ttf,返回term在欄位中的頻次。 ttf(text, ‘memory’)
41 xor 異或

搜尋方式

精確搜尋

如果你想要通過 Solr 的索引查詢公司中所有員工的檔案。一種方法是枚舉出公司中所有可能的職位:



查詢語句:”chief executive officer” OR “chief financial officer” OR “chief

marketing officer” OR “chief technology officer” OR …

當然,這種查詢的前提是你需要知道公司中所有可能的職位,這當然不現實。另外的一種解決方案是單獨搜尋每個關鍵字:

查詢語句: chief AND officer
這將會匹配所有可能的用例,但是同時也會匹配所有包含了這兩個關鍵字的文件。例如:One chief concern arising from the incident was the safety of the police officer on duty。這個文件明顯不符合我們的要求,但是如果使用上面的查詢語句,那麼將會返回這個文件。

模糊搜尋

對於很多搜尋應用來說,很重要的功能是不僅僅需要精確匹配使用者的文字內容。而且還允許一些靈活的變化,比如一些使用者的拼寫錯誤或相同單詞的其它變體。Solr 通過基於 Damerau-Levenshtein 距離的編輯距離測量來支援這個功能,它將容忍 80% 以上的拼寫錯誤。

Solr 提供的模糊編輯距離查詢需要用到波浪符號(~):

查詢語句: administrator~ 匹配: adminstrator, administrater, administratior,等
這個查詢不僅匹配原始的關鍵字(administrator),還有其它與原始關鍵字有 2 個編輯距離的關鍵字。一個編輯距離表示增加,刪除,取代或交換一個任意字元。關鍵字 adminstrator (在第六個字母出少了字元“i”)和原始關鍵字之間相差一個編輯距離,因為它刪除了一個字元。同樣 sadministrator 和原始關鍵字之間也是相差一個編輯距離,因為它在前面添加了一個字元。administratro 也與原始關鍵字有一個編輯距離,因為它將最後兩個字元交換了順序。

在編輯距離查詢中也可以精確指定編輯距離:

查詢語句:administrator~1 匹配一個編輯距離以內的內容。
查詢語句:administrator~2 匹配兩個編輯距離以內的內容(如果沒有提供編輯距離的話,這個就是預設值)。
查詢語句:administrator~N 匹配 N 個編輯距離以內的內容。
注意,任何編輯距離大於 2 的查詢將會使查詢速度變得很慢。如果編輯距離在 2 以內,那麼將會使用很高效率的 Levenshtein 自動機(Levenshtein automaton),但是如果編輯距離大於 2,將會退回到更慢的編輯距離實現。

範圍搜尋

在Solr查詢中,有幾種方式可以使用函式(functions):


* 通過QParser顯示的傳遞function引數,如funcfrange. 
  q={!func}div(popularity,price)&fq={!frange l=1000}customer_ratings 

* 在Sort表示式中。 
  sort=div(popularity,price) desc, score desc 

* 將function結果作為偽欄位新增到查詢結果文件中。 
  &fl=sum(x, y),id,a,b,c,score 

* 使用用於指定函式的引數,如EDisMax的boost引數,或DisMax查詢的bf(boost function)引數. 
  q=dismax&bf="ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3" 

* 在lucene QParser中通過_val_關鍵字使用行內函數。 
  q=_val_:mynumericfield _val_:"recip(rord(myfield),1,2,3)"

結論

範圍越大,結果資料越多,搜尋花費時間越長。
第一次搜尋較慢,後來時間花費較少。