Lucene 源碼剖析
1 目錄
2 Lucene是什麼
2.1.1 強大特性
2.1.2 API組成-
2.1.3 Hello World!
2.1.4 Lucene roadmap
3 索引文件結構
3.1 索引數據術語和約定 -
3.1.1 術語定義
3.1.2 倒排索引(inverted indexing)
3.1.3 Fields的種類
3.1.4 片斷(segments)
3.1.5 文檔編號(document numbers)
3.1.6 索引結構概述
3.1.7 索引文件中定義的數據類型 -
3.2 索引文件結構
3.2.1 索引文件概述
3.2.2 每個Index包含的文件
3.2.2.1 Segments文件
3.2.2.2 Lock文件
3.2.2.3 Deletable文件
3.2.2.4 Compound文件(.cfs)
3.2.3 每個Segment包含的文件
3.2.3.1 Field信息(.fnm)
3.2.3.2 Field數據(.fdx和.fdt)
3.2.3.3 Term字典(.tii和.tis)
3.2.3.4 Term頻率數據(.frq)
3.2.3.5 Positions位置信息數據(.prx)
3.2.3.6 Norms調節因子文件(.nrm)-
3.2.3.7 Term向量文件 -
3.2.3.8 刪除的文檔 (.del)
3.3 局限性(Limitations)
4 索引是如何創建的
4.1 索引創建示例
4.2 索引創建類IndexWriter
4.2.1 org.apache.lucene.index.IndexWriter
4.2.2 org.apache.lucene.index.DocumentsWriter
4.2.3 org.apache.lucene.index.SegmentMerger -
5 數據是如何存儲的
5.1 數據存儲類Directory
5.1.1 org.apache.lucene.store.Directory
5.1.2 org.apache.lucene.store.FSDirectory
5.1.3 org.apache.lucene.store.RAMDirectory
5.1.4 org.apache.lucene.store.IndexInput
5.1.5 org.apache.lucene.store.IndexOutput
6 文檔內容是如何分析的
6.1 文檔分析類Analyzer
6.1.1 org.apache.lucene.store.Analyzer
6.1.2 org.apache.lucene.store.StandardAnalyzer -
7 如何給文檔評分
7.1 文檔評分類Similarity
7.1.1 org.apache.lucene.search.Similarity
7.2 Similarity評分公式
Apache Lucene是一個高性能(high-performance)的全能的全文檢索(full-featured text search engine)的搜索引擎框架庫,完全(entirely)使用Java開發。它是一種技術(technology),適合於(suitable for)幾乎(nearly)任何一種需要全文檢索(full-text search)的應用,特別是跨平台(cross-platform)的應用。
數據類型
所占字節長度(字節)
說明
Byte
1
基本數據類型,其他數據類型以此為基礎定義
UInt32
4
32位無符號整數,高位優先
UInt64
8
64位無符號整數,高位優先
VInt
不定,最少1字節
動態長度整數,每字節的最高位表明還剩多少字節,每字節的低七位表明整數的值,高位優先。可以認為值可以為無限大。其示例如下
值
字節1
字節2
字節3
0
00000000
1
00000001
2
00000010
127
01111111
128
10000000
00000001
129
10000001
00000001
130
10000010
00000001
16383
10000000
10000000
00000001
16384
10000001
10000000
00000001
16385
10000010
10000000
00000001
Chars
不定,最少1字節
采用UTF-8編碼[20]的Unicode字符序列
String
不定,最少2字節
由VInt和Chars組成的字符串類型,VInt表示Chars的長度,Chars則表示了String的值
Lucene使用文件擴展名標識不同的索引文件,文件名標識不同版本或者代(generation)的索引片段(segment)。如.fnm文件存儲域Fields名稱及其屬性,.fdt存儲文檔各項域數據,.fdx存儲文檔在fdt中的偏移位置即其索引文件,.frq存儲文檔中term位置數據,.tii文件存儲term字典,.tis文件存儲term頻率數據,.prx存儲term接近度數據,.nrm存儲調節因子數據,另外segments_X文件存儲當前最新索引片段的信息,其中X為其最新修改版本,segments.gen存儲當前版本即X值,這些文件的詳細介紹上節已說過了。
下面的圖描述了一個典型的lucene索引文件列表:
版本
包含的項
數目
類型
描述
2.1之前版本
Format
1
Int32
在Lucene1.4中為-1,而在Lucene 2.1中為-3(SegmentsInfos.FORMAT_SINGLE_NORM_FILE)
Version
1
Int64
統計在刪除和添加文檔時,索引被更改了多少次。
NameCounter
1
Int32
用於為新的片斷文件生成新的名字。
SegCount
1
Int32
片斷的數目
SegName
SegCount
String
片斷的名字,用於所有構成片斷索引的文件的文件名前綴。
SegSize
SegCount
Int32
包含在片斷索引中的文檔的數目。
2.1及之後版本
Format
1
Int32
在Lucene 2.1和Lucene 2.2中為-3(SegmentsInfos.FORMAT_SINGLE_NORM_FILE)
Version
1
Int64
同上
NameCounter
1
Int32
同上
SegCount
1
Int32
同上
SegName
SegCount
String
同上
SegSize
SegCount
Int32
同上
DelGen
SegCount
Int64
為分離的刪除文件的代的數目(generation count of the separate deletes file),如果值為-1,表示沒有分離的刪除文件。如果值為0,表示這是一個2.1版本之前的片斷,這時你必須檢查文件是否存在_X.del這樣的文件。任意大於0的值,表示有分離的刪除文件,文件名為_X_N.del。
HasSingleNormFile
SegCount
Int8
該值如果為1,表示Norm域(field)被寫為一個單一連接的文件(single joined file)中(擴展名為.nrm),如果值為0,表示每一個field的norms被存儲為分離的.fN文件中,參考下面的“標准化因素(Normalization Factors)”
NumField
SegCount
Int32
表示NormGen數組的大小,如果為-1表示沒有NormGen被存儲。
NormGen
SegCount * NumField
Int64
記錄分離的標准文件(separate norm file)的代(generation),如果值為-1,表示沒有normGens被存儲,並且當片斷文件是2.1之前版本生成的時,它們全部被假設為0(assumed to be 0)。而當片斷文件是2.1及更高版本生成的時,它們全部被假設為-1。這時這個代(generation)的意義與上面DelGen的意義一樣。
IsCompoundFile
SegCount
Int8
記錄是否該片斷文件被寫為一個復合的文件,如果值為-1表示它不是一個復合文件(compound file),如果為1則為一個復合文件。另外如果值為0,表示我們需要檢查文件系統是否存在_X.cfs。
2.3
Format
1
Int32
在Lucene 2.3中為-4 (SegmentInfos.FORMAT_SHARED_DOC_STORE)
Version
1
Int64
同上
NameCounter
1
Int32
同上
SegCount
1
Int32
同上
SegName
SegCount
String
同上
SegSize
SegCount
Int32
同上
DelGen
SegCount
Int64
同上
DocStoreOffset
1
Int32
如果值為-1則該segment有自己的存儲文檔的fields數據和term vectors的文件,並且DocStoreSegment, DocStoreIsCompoundFile不會存儲。在這種情況下,存儲fields數據(*.fdt和*.fdx文件)以及term vectors數據(*.tvf和*.tvd和*.tvx文件)的所有文件將存儲在該segment下。另外,DocStoreSegment將存儲那些擁有共享的文檔存儲文件的segment。DocStoreIsCompoundFile值為1如果segment存儲為compound文件格式(如.cfx文件),並且DocStoreOffset值為那些共享文檔存儲文件中起始的文檔編號,即該segment的文檔開始的位置。在這種情況下,該segment不會存儲自己的文檔數據文件,而是與別的segment共享一個單一的數據文件集。
[DocStoreSegment]
1
String
如上
[DocStoreIsCompoundFile]
1
Int8
如上
HasSingleNormFile
SegCount
Int8
同上
NumField
SegCount
Int32
同上
NormGen
SegCount * NumField
Int64
同上
IsCompoundFile
SegCount
Int8
同上
2.4及以上
Format
1
Int32
在Lucene 2.4中為-7 (SegmentInfos.FORMAT_HAS_PROX)
Version
1
Int64
同上
NameCounter
1
Int32
同上
SegCount
1
Int32
同上
SegName
SegCount
String
同上
SegSize
SegCount
Int32
同上
DelGen
SegCount
Int64
同上
DocStoreOffset
1
Int32
同上
[DocStoreSegment]
1
String
同上
[DocStoreIsCompoundFile]
1
Int8
同上
HasSingleNormFile
SegCount
Int8
同上
NumField
SegCount
Int32
同上
NormGen
SegCount * NumField
Int64
同上
IsCompoundFile
SegCount
Int8
同上
DeletionCount
SegCount
Int32
記錄該segment中刪除的文檔數目
HasProx
SegCount
Int8
值為1表示該segment中至少一個fields的omitTf設置為false,否則為0
Checksum
1
Int64
存儲segments_N文件中直到checksum的所有字節的CRC32 checksum數據,用來校驗打開的索引文件的完整性(integrity)。
寫鎖(write lock)文件名為“write.lock”,它缺省存儲在索引目錄中。如果鎖目錄(lock directory)與索引目錄不一致,寫鎖將被命名為“XXXX-write.lock”,其中“XXXX”是一個唯一的前綴(unique prefix),來源於(derived from)索引目錄的全路徑(full path)。當這個寫鎖出現時,一個writer當前正在修改索引(添加或者清除文檔)。這個寫鎖確保在一個時刻只有一個writer修改索引。
需要注意的是在2.1版本之前(prior to),Lucene還使用一個commit lock,這個鎖在2.1版本裡被刪除了。
在Lucene 2.1版本之前,有一個“deletable”文件,包含了那些需要被刪除文檔的詳細資料。在2.1版本後,一個writer會動態地(dynamically)計算哪些文件需要刪除,因此,沒有文件被寫入文件系統。
從Lucene 1.4版本開始,compound文件格式成為缺省信息。這是一個簡單的容器(container)來服務所有下一章節(next section)描述的文件(除了.del文件),格式如下:
版本
包含的項
數目
類型
描述
1.4之後版本
FileCount
1
VInt
DataOffset
FileCount
Long
FileName
FileCount
String
FileData
FileCount
raw
Raw文件數據是上面命名的所有單個的文件數據(the individual named above)。
結構如下圖所示:
文件
包含的項
數目
類型
版本
描述
FieldsInfo(.fnm)
FieldsCount
1
VInt
FieldName
FieldsCount
String
FieldBits
FieldsCount
Byte
最低階的bit位(low-order bit)值為1表示是被索引的Fields,0表示非索引的Fields。
第二個最低階的bit位(second lowest-order bit)值為1表示該Field有term向量存儲(term vectors stored),0表示該field沒有term向量。
>=1.9
如果第三個最低階的bit位(third lowest-order bit)設置(0×04),term的位置(term positions)將和term向量一起被存儲(stored with term vectors)。
>=1.9
如果第四個最低階的bit位(fourth lowest-order bit)設置(0×08),term的偏移(term offsets)將和term向量一起被存儲(stored with term vectors)。
>=1.9
如果第五個最低階的bit位(fifth lowest-order bit)設置(0×10),norms將對索引的field忽略掉(norms are omitted for the indexed field)。
>=1.9
如果第六個最低階的bit位(sixth lowest-order bit)設置(0×20),payloads將為索引的field存儲(payloads are stored for the indexed field)。
注明:payloads概念:
詞條載荷(payloads)――允許用戶將任意二進制數據和索引中的任意詞條(term)相關聯。
詞條載荷是一個允許信息在索引中按逐詞條儲存的新特性。例如,當索引Web頁面時,儲存某個關鍵詞的額外信息可能會很有用,例如這個關鍵詞關聯的URL或者經過文字分析後得出的權重系數。在更高級的應用中,為了突出語句中的名次成分相對於其它成分的重要性,儲存語句中這個關鍵詞出現的部分可能會很有幫助。我今年在ApacheCon Europe會議上的演講中就有幾張講述詞條載荷的幻燈片,感興趣的讀者可以去看看。
Fields將使用它們在這個文件中的順序來編號(fields are numbered by their order in this file)。需要注意的是,就像文檔編號(document numbers)一樣,field編號(field numbers)與片斷是相關的(are segment relative)。結構如下圖所示:
文件
包含的項
父項
數目
類型
版本
描述
Fields Index(.fdx) 對每個文檔來說,存儲指向它的fields數據的指針(pointer)
FieldValuesPosition
SegSize
UInt64
用於找詳細文檔(a particular document)的所有fields的field數據文件中的位置(position),因為它包含的(contains)是固定長度的數據(fixed-length data),這個文件可以很容易地進行隨機訪問(randomly accessed)。
文檔n的field數據的位置是在該文件中n*8的位置中(UInt64類型)。
Fields Data(.fdt)這個文件存儲每個文檔的field數據
DocFieldData
SegSize
FieldCount
DocFieldData
1
VInt
FieldNum
DocFieldData
FieldCount
VInt
Bits
DocFieldData
FieldCount
Byte
<=1.4
只有最低階的bit位(low-order bits of Bits)被使用,值為1表示tokenized field(分解過的field),0表示non-tokenized field。
Byte
>=1.9
最低階的bit位表示tokenized field
>=1.9
第二個bit(second bit)用於表示該field存儲binary數據。
>=1.9
第三個bit(third bit)表示該field的壓縮選項被開啟(field with compression enabled),如果壓縮選項開啟,采用的壓縮算法(algorithm)是ZLIB
Value
DocFieldData
FieldCount
String
<=1.4
String | BinaryValue
>=1.9
依賴於Bits的值
BinaryValue
>=1.9
ValueSize,<Byte>^ValueSize
ValueSize
Value
1
VInt
>=1.9
結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TIVersion
1
UInt32
記錄該文件的版本,1.4版本中為-2
TermCount
1
UInt64
IndexInterval
1
UInt32
SkipInterval
1
UInt32
MaxSkipLevels
1
UInt32
TermInfos
1
TermInfo…
TermInfos->TermInfo
TermCount
TermInfo
TermInfo->Term
TermCount
Term
Term->PrefixLength
TermCount
VInt
Term文本的前綴可以共享,該項的值表示根據前一個term的文本來初始化的字符串前綴長度,前一個term必須已經預設成後綴文本以便構成該term的文本。比如,如果前一個term為“bone”,而當前term為“boy”,則該PrefixLength值為2,suffix值為“y”
Term->Suffix
TermCount
String
如上
Term->FieldNum
TermCount
VInt
用來確定term的field,它們存儲在.fdt文件中。
TermInfo->DocFreq
TermCount
VInt
包含該term的文檔數目
TermInfo->FreqDelta
TermCount
VInt
用來確定包含在.frq文件中該term的TermFreqs的位置。特別指出,它是該term的數據在文件中位置與前一個term的位置的差值,當為第一個term時,該值為0
TermInfo->ProxDelta
TermCount
VInt
用來確定包含在.prx文件中該term的TermPositions的位置。特別指出,它是該term的數據在文件中的位置與前一個term的位置地差值,當為第一個term時,該值為0。如果fields的omitTF設置為true,該值也為0,因為prox信息沒有被存儲。
TermInfo->SkipDelta
TermCount
VInt
用來確定包含在.frq文件中該term的SkipData的位置。特別指出,它是TermFreqs之後即SkipData開始的字節數目,換句話說,它是TermFreq的長度。SkipDelta只有在DocFreq不比SkipInteval小的情況下才會存儲。
TermInfoFile文件按照Term來排序,排序方法首先按照Term的field名稱(按照UTF-16字符編碼)排序,然後按照Term的Text字符串(UTF-16編碼)排序。 結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TIVersion
1
UInt32
同tis
IndexTermCount
1
UInt64
同tis
IndexInterval
1
UInt32
同tis
SkipInterval
1
UInt32
是TermDocs存儲在skip表中的分數(fraction),用來加速(accelerable)TermDocs.skipTo(int)的調用。在更小的索引中獲得更大的結果值(larger values result),將獲得更高的速度,但卻更小開銷?(fewer accelerable cases while smaller values result in bigger indexes, less acceleration (in case of a small value for MaxSkipLevels)
MaxSkipLevels
1
UInt32
是.frq文件中為每一個term存儲的skip levels的最大數目,A low value results in smaller indexes but less acceleration, a larger value results in slighly larger indexes but greater acceleration.參見.frq文件格式中關於skip levels的詳細介紹。
TermIndices
IndexTermCount
TermIndice
同tis
TermIndice->TermInfo
IndexTermCount
TermInfo
同tis
TermIndice->IndexDelta
IndexTermCount
VLong
用來確定該Term的TermInfo在.tis文件中的位置,特別指出,它是該term的數據的位置與前一個term位置的差值。
結構如下圖所示:
版本
包含的項
父類型
類型
描述
全部版本
TermFreqs
TermCount
TermFreq
按照term順序排序,term是隱含的(?implicit),來自.tis文件。TermFreq按文檔編號遞增的順序排序。
SkipData
TermCount
SkipData
TermFreq->DocDelta
TermCount
VInt
如果omitTf設置為false,要同時檢測文檔編號和頻率,特別指出,DocDelta/2時該文檔編號與上一個文檔編號的差值(如果是第一個文檔值為0)。當DocDelta為單數時頻率為1,當DocDelta為偶數時頻率為讀取下一個VInt的值。如果omitTf設置為true,DocDelta為文檔編號之間的差值(gap,不用乘以2,multiplited),頻率信息則不被存儲。
TermFreq->[Freq?]
TermCount
VInt
SkipData->SkipLevelLength
NumSkipLevels-1
VInt
SkipData->SkipLevel
TermCount
SkipDatums
SkipLevel->SkipDatum
DocFreq/(SkipInterval^(Level + 1))
SkipDatum
SkipData->SkipDatum
TermCount
SkipDatum
SkipDatum->DocSkip
1
VInt
SkipDatum->PayloadLength?
1
VInt
SkipDatum->FreqSkip
1
VInt
SkipDatum->ProxSkip
1
VInt
SkipDatum->SkipChildLevelPointer?
1
VLong
結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TermPositions
TermCount
TermPositions
按照term順序排序,term是隱含的(?implicit),來自.tis文件。
TermPositions->Positions
DocFreq
Positions
按文檔編號遞增的順序排序。
Positions->PositionDelta
Freq
VInt
如果term的fields中payloads被禁用,則取值為term出現在該文檔中當前位置與前一個位置的差值(第一個位置取值0)。如果payloads被啟用,則取值為當前位置與上一個位置之間差值的2倍。如果payloads啟用並且PositionDelta為單數,則PayloadLength被存儲,表示當前位置的payloads的長度。
Positions->Payload?
Freq
Payload
Payload->PayloadLength?
1
VInt
Payload->PayloadData
PayloadLength
byte
結構如下圖所示:
版本
包含的項
數目
類型
描述
2.1及之後版本
NormsHeader
1
raw
‘N’,'R’,'M’,Version:4個字節,最後字節表示該文件的格式版本,當前為-1
Norms
NumFieldsWithNorms
Norms
Norms->Byte
SegSize
Byte
每一個字節編碼了一個float指針數值,bits 0-2 容納 3-bit 尾數(mantissa),bits 3-8容納 5-bit 指數(exponent),這些被轉換成一個IEEE單獨的float數值,如圖所示
NormsHeader->Version
1
Byte
結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TVXVersion
1
Int
在Lucene 2.4中為3 (TermVectorsReader.FORMAT_VERSION2)
DocumentPosition
NumDocs
UInt64
在.tvd文件中的偏移
FieldPosition
NumDocs
UInt64
在.tvf文件中的偏移
結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TVDVersion
1
Int
在Lucene 2.4中為3 (TermVectorsReader.FORMAT_VERSION2)
NumFields
NumDocs
VInt
FieldNums
NumDocs
FieldNums
FieldNums->FieldNumDelta
NumFields
VInt
FieldPositions
NumDocs
FieldPositions
FieldPositions->FieldPositionDelta
NumField-1
VLong
結構如下圖所示:
版本
包含的項
數目
類型
描述
全部版本
TVFVersion
1
Int
在Lucene 2.4中為3 (TermVectorsReader.FORMAT_VERSION2)
NumTerms
NumFields
VInt
Position/Offset
NumFields
Byte
TermFreqs
NumFields
TermFreqs
TermFreqs->TermText
NumTerms
TermText
TermText->PrefixLength
NumTerms
VInt
TermText->Suffix
NumTerms
String
TermFreqs->TermFreq
NumTerms
VInt
TermFreqs->Positions?
NumTerms
Positions
Positions->Position
TermFreq
VInt
TermFreqs->Offsets?
NumTerms
Offsets
Offsets->StartOffset
TermFreq
VInt
Offsets->EndOffset
TermFreq
VInt
結構如下圖所示:
版本
包含的項
數目
類型
描述
2.2之後版本
[Format]
1
UInt32
可選,-1表示為DGaps,非負數(negative)值表示為Bit,並且此時不存儲Format
ByteCount
1
UInt32
代表Bit裡的字節數目,而且一般值為(SegSize/8)+1
BitCount
1
UInt32
表示Bit裡當前設置的字節數目
Bit|DGaps
1
Bit還是DGaps取決於Format。Bits中對每一個索引的文檔均包含一個字節,當一個bit對應的一個文檔編號被設置時,表示該文檔被刪除。Bit從最低(least)到最重要(significant)的文檔排序。所以Bits包含兩個字節,0×00和0×02,則文檔9被標記為刪除。DGaps表示松散(sparse)的bit-vector向量比Bits更有效率(efficiently)。DGaps由索引中非0的Bits位生成,以及非0的字節數據本身。Bits中非0字節數目(NonzeroBytesCoun)不會存儲。
Bit->Byte
ByteCount
Byte
DGaps->DGap
NonzeroBytesCount
VInt
DGaps-> NonzeroBytes
NonzeroBytesCount
Byte
結構如下圖所示:
文檔域
內容
是否索引
title
Lucene 源碼分析
true
url
http://javenstudio.org
false
content
索引是如何創建的
true
content
索引的創建過程
true
下圖描述處理後fields數組的數據結構
Lucene 源碼剖析
Directory及相關類負責文檔索引的存儲。
一個Directory對象是一系列統一的文件列表(a flat list of files)。文件可以在它們被創建的時候一次寫入,一旦文件被創建,它再次打開後只能用於讀取(read)或者刪除(delete)操作。並且同時在讀取和寫入的時候允許隨機訪問(random access)。
在這裡並不直接使用Java I/O API,但是更確切地說,所有I/O操作都是通過這個API處理的。這使得讀寫操作方式更統一起來,如基於內存的索引(RAM-based indices)的實現(即RAMDirectory)、通過JDBC存儲在數據庫中的索引、將一個索引存儲為一個文件的實現(即FSDirectory)。
Directory的鎖機制是一個LockFactory的實例實現的,可以通過調用Directory實例的setLockFactory()方法來更改。
FSDirectory類直接實現Directory抽象類為一個包含文件的目錄。目錄鎖的實現使用缺省的SimpleFSLockFactory,但是可以通過兩種方式修改,即給getLockFactory()傳入一個LockFactory實例,或者通過調用setLockFactory()方法明確制定LockFactory類。
目錄將被緩存(cache)起來,對一個指定的符合規定的路徑(canonical path)來說,同樣的FSDirectory實例通常通過getDirectory()方法返回。這使得同步機制(synchronization)能對目錄起作用。
RAMDirectory類是一個駐留內存的(memory-resident)Directory抽象類的實現。目錄鎖的實現使用缺省的SingleInstanceLockFactory,但是可以通過setLockFactory()方法修改。
IndexInput類是一個為了從一個目錄(Directory)中讀取文件的抽象基類,是一個隨機訪問(random-access)的輸入流(input stream),用於所有Lucene讀取Index的操作。BufferedIndexInput是一個實現了帶緩沖的IndexInput的基礎實現。
IndexOutput類是一個為了寫入文件到一個目錄(Directory)中的抽象基類,是一個隨機訪問(random-access)的輸出流(output stream),用於所有Lucene寫入Index的操作。BufferedIndexOutput是一個實現了帶緩沖的IndexOutput的基礎實現。RAMOuputStream是一個內存駐留(memory-resident)的IndexOutput的實現類。
Analyzer類負責分析文檔結構並提取內容。
Analyzer類構建用於分析文本的TokenStream對象,因此(thus)它表示(represent)用於從文本中分解(extract)出組成索引的terms的一個規則器(policy)。典型的(typical)實現首先創建一個Tokenizer,它將那些從Reader對象中讀取字符流(stream of characters)打碎為(break into)原始的Tokens(raw Tokens)。然後一個或更多的TokenFilters可以應用在這個Tokenizer的輸出上。警告:你必須在你的子類(subclass)中覆寫(override)定義在這個類中的其中一個方法,否則的話Analyzer將會進入一個無限循環(infinite loop)中。
StandardAnalyzer類是使用一個English的stop words列表來進行tokenize分解出文本中word,使用StandardTokenizer類分解詞,再加上StandardFilter以及LowerCaseFilter以及StopFilter這些過濾器進行處理的這樣一個Analyzer類的實現。
Lucene 源碼剖析
Similarity類負責給文檔評分。
Similarity類實現算分(scoring)的API,它的子類實現了檢索算分的算法。DefaultSimilarity類是缺省的算分的實現,SimilarityDelegator類是用於委托算分(delegating scoring)的實現,在Query.getSimilarity(Searcher)}的實現裡起作用,以便覆寫(override)一個Searcher中Similarity實現類的僅有的確定方法(certain methods)。
查詢q相對於文檔d的分數與在文檔和查詢向量(query vectors)之間的余弦距離(cosing-distance)或者點乘積(dot-product)有關系(correlates to),文檔和查詢向量存於一個信息檢索(Information Retrieval)的向量空間模型(Vector Space Model (VSM))之中。一篇文檔的向量與查詢向量越接近(closer to),它的得分也越高(scored higher),這個分數按如下公式計算:
其中:
1. tf(t in d) 與term的出現次數(frequency)有關系(correlate to),定義為(defined as)term t在當前算分(currently scored)的文檔d中出現(appear in)的次數(number of times)。對一個給定(gived)的term,那些出現此term的次數越多(more occurences)的文檔將獲得越高的分數(higher score)。缺省的tf(t in d)算法實現在DefaultSimilarity類中,公式如下:
2. idf(t) 代表(stand for)反轉文檔頻率(Inverse Document Frequency)。這個分數與反轉(inverse of)的docFreq(出現過term t的文檔數目)有關系。這個分數的意義是越不常出現(rarer)的term將為最後的總分貢獻(contribution)更多的分數。缺省idff(t in d)算法實現在DefaultSimilarity類中,公式如下:
3. coord(q,d) 是一個評分因子,基於(based on)有多少個查詢terms在特定的文檔(specified document)中被找到。通常(typically),一篇包含了越多的查詢terms的文檔將比另一篇包含更少查詢terms的文檔獲得更高的分數。這是一個搜索時的因子(search time factor)是在搜索的時候起作用(in effect at search time),它在Similarity對象的coord(q,d)函數中計算。
4. queryNorm(q) 是一個修正因子(normalizing factor),用來使不同查詢間的分數更可比較(comparable)。這個因子不影響文檔的排名(ranking)(因為搜索排好序的文檔(ranked document)會增加(multiplied)相同的因數(same factor)),更確切地說只是(but rather just)為了嘗試(attempt to)使得不同查詢條件(甚至不同索引(different indexes))之間更可比較性。這是一個搜索時的因子是在搜索的時候起作用,由Similarity對象計算。缺省queryNorm(q)算法實現在DefaultSimilarity類中,公式如下:
sumOfSquaredWeights(查詢的terms)是由查詢Weight對象計算的,例如一個布爾(boolean)條件查詢的計算公式為:
5. t.getBoost() 是一個搜索時(search time)的代表查詢q中的term t的boost數值,具體指定在(as specified in)查詢的文本中(參見查詢語法),或者由應用程序調用setBoost()來指定。需要注意的是實際上(really)沒有一個直接(direct)的API來訪問(accessing)一個多個term的查詢(multi term query)中的一個term 的boost值,更確切地說(but rather),多個terms(multi terms)在一個查詢裡的表示形式(represent as)是多個TermQuery對象,所以查詢裡的一個term的boost值的訪問是通過調用子查詢(sub-query)的getBoost()方法實現的。
6. norm(t,d) 是提煉取得(encapsulate)一小部分boost值(在索引時間)和長度因子(length factor):
ú document boost – 在添加文檔到索引之前通過調用doc.setBoost()來設置。
ú Field boost – 在添加Field到文檔之前通過調用field.setBoost()來設置。
ú lengthNorm(field) – 在文檔添加到索引的時候,根據(in accordance with)文檔中該field的tokens數目計算得出,所以更短(shorter)的field會貢獻更多的分數。lengthNorm是在索引的時候起作用,由Similarity類計算得出。
當一篇文檔被添加到索引的時候,所有上面計算出的因子將相乘起來(multiplied)。如果文檔擁有多個相同名字的fields(multiple fields with same name),所有這些fields的boost值也會被一起相乘起來(multiplied together):
然而norm數值的結果在被存儲(stored)之前被編碼成(encoded as)一個單獨的字節(single byte)。在檢索的時候,這個norm字節值從索引目錄(index directory)中讀取出來,並解碼回(decoded back)一個norm浮點數值(float value)。這個編/解碼(encoding/decoding)行為,會縮減(reduce)索引的大小(index size),這得自於(come with)精度損耗的代價(price of precision loss)- 它不保證decode(encode(x))=x,舉例來說decode(encode(0.89))=0.75。還有需要注意的是,檢索的時候再修改評分(scoring)的這個norm部分已近太遲了,例如,為檢索使用不同的Similarity。
以前收集的關於lucene分析的資料,版本有點老,已經忘了是在哪找到的了,如果你是文檔作者,侵犯了你的版權,@我即可