關(guān)于luncene 內(nèi)層的研究

(飛刀和雨)


  這是很久以前做lucene 時的總結(jié),現(xiàn)在已經(jīng)不用去研究那些代碼,但還是分享出來給大家以幫助。謝謝
1.      
Index開始

無論哪種搜索引擎,都會需要自建一個index,所有的搜詞準確率及快速性很大程度上取決于這類的問題。因此在建索引文件的時候,我們首先要弄清楚lucene建索引的接口及各類參數(shù)。

Fieldlucene的重要組成部分,其引出好些接口

Filed Interf

Namestring

store

index

token

StoreTermVector

Keyword

Y

Y

Y

N

(N)

UnIndexed

Y

Y

N

N

N

Text

Y

*

(Y)

(Y)

N

UnStored

Y

(N)

(Y)

(Y)

*

Text

Y

(Y)

(Y)

(Y)

Y

*()表示多態(tài)隱藏參數(shù),當storeTermVectortrue, Index必須保證true.

對于Keyword來說String 可以是Date型的,具體會通過DateFielddateToString來實現(xiàn)其功能。

下面是Field構(gòu)造所帶的6個參數(shù)。頭兩個是必須。

   * @param name The name of the field

   * @param string The string to process

   * @param store true if the field should store the string

   * @param index true if the field should be indexed

   * @param token true if the field should be tokenized

   * @param storeTermVector true if we should store the Term Vector info

這里就是Field所存儲幾個選項,這些在建索引的時候會有一定的作用

 

Document: DocumentsIndexsearch的單元,也就是Field的集合和組成index的內(nèi)容,提供加入add(), 去除remove(), getField()getFields()的方法。

Document 包括1個參數(shù)boost 默認為1.0f,其作用 (參考cap: java搜索引擎lucene學(xué)習(xí)筆記) lunceneDocumentField提供了一個可以設(shè)置的Boost參數(shù), 這個參數(shù)的用處是告訴lucene 某些記錄更重要,在搜索的時候優(yōu)先考慮他們。 lucene默認的boost參數(shù)是1.0,  如果你覺得這個field重要,你可以把boost設(shè)置為1.5, 1.2....等。這個boost不會直接和DocumentField存放在Index一起,因此在帶Index的時候IndexReader.Documenthit()Hits.hit() 返回中會不同。

 

IndexWrite (參考lucene Doc) 主要用于創(chuàng)建和維護index. 構(gòu)造函數(shù)中第三個參數(shù)用來控制index文件是不是重建(T)還是添加(F) 其他方面 addDocument()用于添加document,當Index結(jié)束添加時close()必須寫上。 如果document不再隨意添加,那么可以在index關(guān)閉時調(diào)用optimize()來對Index進行優(yōu)化。下面來討論一下IndexWrite里的基本方法

我們先可以用個簡單的程序來建個空Index

IndexWriter writer = new IndexWriter(String|Directory|File, Anaylzer, true|false);
 writer.close();

會形成一個索引,這里千萬注意,建索引的指定目錄下的所有文件都會被不可恢復(fù)刪除,做索引的文件和索引不要指定在一個目錄下。

addDocument() 用來把把document添加到Index里,而addIndexes()可以把幾個子索引集合起來,做成一個總索引。addIndexes()會自動調(diào)用optimize()所有使用時不需要再加, close()需要手動加上

 

Directory一個抽象的標示index文件地址的類,有兩個實現(xiàn):FSDirectoryRAMDirectory 前者是基于文件系統(tǒng),后者使用內(nèi)存。 Lucene DocDirectory 還提供一種通過jdbc基于數(shù)據(jù)庫內(nèi)的索引,目前沒有提供實現(xiàn)方法,估計后續(xù)版本的會出。RAM的方式通過stream方式讀到buffer里,速度非常快,但根據(jù)我做程序時的經(jīng)驗,在六千條紀錄的以上,時常出現(xiàn)javamemory low現(xiàn)象.所以大型的索引,采取FS是必須的。FSDirectory的構(gòu)造函數(shù)是私有的,只有通過FSDirectory.GetDirectoty(File|String boolean)來獲得,而RAMDirectory卻可以直接構(gòu)造或者從FSDirectory來得到。

 

2.       Search 這里似乎是lucene的精華,

SearchableSearch的底層接口, lucene提供了單索引,多索引以及遠程的索引3 種方式。

 

QuerySearch的基本單元,實現(xiàn)各種搜索的方法,下面我簡單的列一下他們的作用,

TermQuery,

最基本的Query,TermQuery(new Term(Str filed, Str Text));就可以構(gòu)造, TermQuery把查詢條件視為一個key, 要求和查詢內(nèi)容完全匹配,比如Field.Keyword類型就可以使用TermQuery

 

PhraseQuery

表示可用于非嚴格語句的查詢,匹配包含的指定連續(xù)Term, 比如"one five"可以匹配"one two three four five", PhraseQuery提供了一個重要的setSlop()參數(shù), 這個參數(shù)主要用于設(shè)置phrase query中詞之間的允許間隔數(shù)目,在默認情況下slop的值是0, 就相當于TermQuery的精確匹配, 通過設(shè)置slop參數(shù)(比如"one five"匹配"one two three four five"就需要slop=3,如果slop=2就無法得到結(jié)果。這里我們可以認為slope是單詞移動得次數(shù),可以左移或者右移。這里特別提醒,PhraseQuery不保證前后單詞的次序,在上面的例子中,"two one"就需要2slop,也就是認為one 向左邊移動2, 就是能夠匹配的”one two”如果是“five three one” 就需要slope=6才能匹配。還有一點要注意,就是如果碰到stopword,(會在stopAnalyzer中細說),則stopword不用把slop算在內(nèi)。

 

BooleanQuery

是一個組合的Query, 可以把各種Query添加進去(主要是TernQueryPhraseQuery)并標明他們的邏輯關(guān)系,添加條件用public void add(Query query, boolean required, boolean prohibited)方法, 后兩個boolean變量分別表示不匹配子Query將不匹配booleanQuery和匹配子Query將不匹配booleanQuery。估計類似google的(+-)功能。這兩個參數(shù)不允許同時為true, 否則報錯。但兩個參數(shù)可以都為false,而且必須保證匹配至少一個子query才能用來匹配booleanQuery 一個BooleanQuery中可以添加多個Query, 但不能超過setMaxClauseCount(int)的值(默認1024),否則拋出TooManyClauses錯誤. BooleanQuery可以完成各種邏輯的組合,如and, or not的組合。

 

RangeQuery

RangeQuery表示一個范圍的搜索條件,RangeQuery query = new RangeQuery(begin, end, included);最后一個boolean值表示是否包含邊界條件本身, beginend必須滿足至少有一個不為null及兩者都在同一個field. 這里的Range是以StringcompareTo (Str)進行比較。所以熟悉j2se的應(yīng)該很容易確定Range的范圍。

 

PrefixQuery

表示匹配是以指定字符串開頭的匹配查詢, 可以用于Keyword形式的查詢。一般的在suggestion里對于single word可以使用的,也可用于查詢網(wǎng)絡(luò)結(jié)構(gòu)目錄樹的數(shù)目。

 

PhrasePrefixQuery

由于PhraseQuery不能很靈活的適應(yīng)各種的phrase的匹配。比如要搜索”Sony Cam*”, 先可以把add(Term)Sony放在Term.,然后把使用IndexReader.Terms(Term)匹配以Cam為前綴的詞,最后使用PhrasePrefixQuery.add(Term[] terms)把兩者加在Query中。這里slopephraseQuery雷同,仍然起著對phrase的定位作用,addTerm(Term[] terms)內(nèi)使用ArrayList來保存Term數(shù)據(jù),而Phrase使用的是Vector.

 

WildcardQuery

WildcardQueryFuzzyQuery是繼承MultiTermQuery的,這是他們區(qū)別的其他的幾種常規(guī)Query. Query包含自身全部的匹配,TermFilteredTermEnum提供,而MultiQuery則是不完全自身的匹配。Term的提供者也不同。

WildcardQuery主要使用?*來表示一個或多個字母的匹配,值得注意的是,wildcard,empty對于?*也是匹配的,Query的開頭不允許用使用?*.

注:當使用WildcardQuery時,搜索性能會有很大的下降

 

FuzzyQuery

能模糊匹配英文單詞,這個功能非常有用,大小寫敏感。可以使用其構(gòu)造方法FuzzyQuery(Term term, float minimumSimilarity, int prefixLength)方法,還提供2種默認的0.5相似度,和0的前綴狀態(tài)。相似度比較時要減去非比較的前綴。然后再比。

例如,”soni”匹配”sony”設(shè)置相似度前綴為0,則相似度為75%,如果前綴為1,則相似度為66.7%.只要高于最小相似度,便能找到。如果詞長度不一致,則以Query減去前綴的為準,例如設(shè)前綴為1,用”della”來匹配”dell”,相似度75%, 如果”del”來匹配”dell”則相似度只有50%

 

3Analyse

下面是幾種analyse的分詞舉例。

"The quick brown fox jumped over the lazy dogs"

WhitespaceAnalyzer:

[The] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]

SimpleAnalyzer:

[the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]

StopAnalyzer:

[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]

StandardAnalyzer:

[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]

 

"XY&Z Corporation - xyz@example.com"

WhitespaceAnalyzer:

[XY&Z] [Corporation] [-] [xyz@example.com]

SimpleAnalyzer:

[xy] [z] [corporation] [xyz] [example] [com]

StopAnalyzer:

[xy] [z] [corporation] [xyz] [example] [com]

StandardAnalyzer:

[xy&z] [corporation] [xyz@example.com]

 

Token

  Token其實就是一個Field里面包含的term,一般的token就是獨立的word.

TokenStreamtoken做依次的列舉

它有2個子類,TokenizerTokenFilter,他們的子類如圖所示

 

幾種analyzer的區(qū)別

WhitespaceAnalyzer 由空格進行分詞

SimpleAnalyzer 由非字母的處分詞,并置小寫

StopAnalyzer  由非字母處分詞,置小寫,去除Stopword

StandardAnalyzer  由特定的語法進行分詞,包括e-mail,addresses, acronyms, Chinese-Japanese-Korean characters, alphanumerics, and more; 置小寫,去除Stopword

 

StopWord 可以根據(jù)內(nèi)部的代碼可以得到 有以下的一些

"a", "an", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "no", "not", "of", "on", "or", "s", "such", "t", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"

當然,你也可以通過你自己的接口去來改變上述默認的值。