posts - 40,  comments - 7,  trackbacks - 0

          Lucene提供了方便您創(chuàng)建自建查詢的API,也通過QueryParser提供了強(qiáng)大的查詢語(yǔ)言。

          本文講述Lucene的查詢語(yǔ)句解析器支持的語(yǔ)法,Lucene的查詢語(yǔ)句解析器是使用JavaCC工

          具生成的詞法解析器,它將查詢字串解析為L(zhǎng)ucene Query對(duì)象。
          項(xiàng)(Term)
          一條搜索語(yǔ)句被拆分為一些項(xiàng)(term)和操作符(operator)。項(xiàng)有兩種類型:?jiǎn)为?dú)項(xiàng)和

          短語(yǔ)。
          單獨(dú)項(xiàng)就是一個(gè)單獨(dú)的單詞,例如"test" , "hello"。
          短語(yǔ)是一組被雙引號(hào)包圍的單詞,例如"hello dolly"。
          多個(gè)項(xiàng)可以用布爾操作符連接起來(lái)形成復(fù)雜的查詢語(yǔ)句(接下來(lái)您就會(huì)看到)。
          注意:Analyzer建立索引時(shí)使用的解析器和解析單獨(dú)項(xiàng)和短語(yǔ)時(shí)的解析器相同,因此選擇

          一個(gè)不會(huì)受查詢語(yǔ)句干擾的Analyzer非常重要。luence1.4的StandardAnalyzer的解析器已

          經(jīng)支持中文等亞洲國(guó)家的文字了,可以直接。標(biāo)準(zhǔn)的解析其不支持中文。

          域(Field)
          Lucene支持域。您可以指定在某一個(gè)域中搜索,或者就使用默認(rèn)域。域名及默認(rèn)域是具體

          索引器實(shí)現(xiàn)決定的。(怎么定制默認(rèn)域?)
          您可以這樣搜索域:域名+":"+搜索的項(xiàng)名。
          舉個(gè)例子,假設(shè)某一個(gè)Lucene索引包含兩個(gè)域,title和text,text是默認(rèn)域。如果您想查

          找標(biāo)題為"The Right Way"且含有"don't go this way"的文章,您可以輸入:
          title:"The Right Way" AND text:go
          或者
          title:"Do it right" AND right
          因?yàn)閠ext是默認(rèn)域,所以這個(gè)域名可以不行。
          注意:域名只對(duì)緊接于其后的項(xiàng)生效,所以
          title:Do it right
          只有"Do"屬于title域。"it"和"right"仍將在默認(rèn)域中搜索(這里是text域)。

          項(xiàng)修飾符(Term Modifiers)
          Lucene支持項(xiàng)修飾符以支持更寬范圍的搜索選項(xiàng)。
          用通配符搜索
          Lucene支持單個(gè)與多個(gè)字符的通配搜索。
          使用符號(hào)"?"表示單個(gè)任意字符的通配。
          使用符號(hào)"*"表示多個(gè)任意字符的通配。
          單個(gè)任意字符匹配的是所有可能單個(gè)字符。例如,搜索"text或者"test",可以這樣:

          te?t
          多個(gè)任意字符匹配的是0個(gè)及更多個(gè)可能字符。例如,搜索test, tests 或者 tester,可

          以這樣: test*
          您也可以在字符竄中間使用多個(gè)任意字符通配符。 te*t
          注意:您不能在搜索的項(xiàng)開始使用*或者?符號(hào)。

          模糊查詢
          Lucene支持基于Levenshtein Distance與Edit Distance算法的模糊搜索。要使用模糊搜索

          只需要在單獨(dú)項(xiàng)的最后加上符號(hào)"~"。例如搜索拼寫類似于"roam"的項(xiàng)這樣寫:
          roam~
          這次搜索將找到形如foam和roams的單詞。
          注意:使用模糊查詢將自動(dòng)得到增量因子(boost factor)為0.2的搜索結(jié)果.

          鄰近搜索(Proximity Searches)
          Lucene還支持查找相隔一定距離的單詞。鄰近搜索是在短語(yǔ)最后加上符號(hào)"~"。例如在文檔

          中搜索相隔10個(gè)單詞的"apache"和"jakarta",這樣寫: "jakarta apache"~10

          Boosting a Term
          Lucene provides the relevance level of matching documents based on the terms

          found. To boost a term use the caret, "^", symbol with a boost factor (a

          number) at the end of the term you are searching. The higher the boost factor,

          the more relevant the term will be.
          Lucene可以設(shè)置在搜索時(shí)匹配項(xiàng)的相似度。在項(xiàng)的最后加上符號(hào)"^"緊接一個(gè)數(shù)字(增量值

          ),表示搜索時(shí)的相似度。增量值越高,搜索到的項(xiàng)相關(guān)度越好。
          Boosting allows you to control the relevance of a document by boosting its

          term. For example, if you are searching for jakarta apache and you want the

          term "jakarta" to be more relevant boost it using the ^ symbol along with the

          boost factor next to the term. You would type:
          通過增量一個(gè)項(xiàng)可以控制搜索文檔時(shí)的相關(guān)度。例如如果您要搜索jakarta apache,同時(shí)

          您想讓"jakarta"的相關(guān)度更加好,那么在其后加上"^"符號(hào)和增量值,也就是您輸入:
          jakarta^4 apache
          This will make documents with the term jakarta appear more relevant. You can

          also boost Phrase Terms as in the example:
          這將使得生成的doucment盡可能與jakarta相關(guān)度高。您也可以增量短語(yǔ),象以下這個(gè)例子

          一樣:
          "jakarta apache"^4 "jakarta lucene"

          By default, the boost factor is 1. Although, the boost factor must be positive,

          it can be less than 1 (i.e. .2)
          默認(rèn)情況下,增量值是1。增量值也可以小于1(例如0.2),但必須是有效的。

          布爾操作符
          布爾操作符可將項(xiàng)通過邏輯操作連接起來(lái)。Lucene支持AND, "+", OR, NOT 和 "-"這些操

          作符。(注意:布爾操作符必須全部大寫)

          OR
          OR操作符是默認(rèn)的連接操作符。這意味著如果兩個(gè)項(xiàng)之間沒有布爾操作符,就是使用OR操

          作符。OR操作符連接兩個(gè)項(xiàng),意味著查找含有任意項(xiàng)的文檔。這與集合并運(yùn)算相同。符號(hào)

          ||可以代替符號(hào)OR。
          搜索含有"jakarta apache" 或者 "jakarta"的文檔,可以使用這樣的查詢:
          "jakarta apache" jakarta 或者 "jakarta apache" OR jakarta

          AND
          AND操作符匹配的是兩項(xiàng)同時(shí)出現(xiàn)的文檔。這個(gè)與集合交操作相等。符號(hào)&&可以代替符號(hào)

          AND。
          搜索同時(shí)含有"jakarta apache" 與 "jakarta lucene"的文檔,使用查詢:
          "jakarta apache" AND "jakarta lucene"

          +
          "+"操作符或者稱為存在操作符,要求符號(hào)"+"后的項(xiàng)必須在文檔相應(yīng)的域中存在。
          搜索必須含有"jakarta",可能含有"lucene"的文檔,使用查詢:
          +jakarta apache

          NOT
          NOT操作符排除那些含有NOT符號(hào)后面項(xiàng)的文檔。這和集合的差運(yùn)算相同。符號(hào)!可以代替

          符號(hào)NOT。
          搜索含有"jakarta apache",但是不含有"jakarta lucene"的文檔,使用查詢:
          "jakarta apache" NOT "jakarta lucene"
          注意:NOT操作符不能單獨(dú)與項(xiàng)使用構(gòu)成查詢。例如,以下的查詢查不到任何結(jié)果:
          NOT "jakarta apache"

          -
          "-"操作符或者禁止操作符排除含有"-"后面的相似項(xiàng)的文檔。
          搜索含有"jakarta apache",但不是"jakarta lucene",使用查詢:
          "jakarta apache" -"jakarta lucene"

          分組(Grouping)
          Lucene支持使用圓括號(hào)來(lái)組合字句形成子查詢。這對(duì)于想控制查詢布爾邏輯的人十分有用


          搜索含有"jakarta"或者"apache",同時(shí)含有"website"的文檔,使用查詢:
          (jakarta OR apache) AND website
          這樣就消除了歧義,保證website必須存在,jakarta和apache中之一也存在。
          轉(zhuǎn)義特殊字符(Escaping Special Characters)
          Lucene支持轉(zhuǎn)義特殊字符,因?yàn)樘厥庾址遣樵冋Z(yǔ)法用到的。現(xiàn)在,特殊字符包括
          + - && || ! ( ) { } [ ] ^ " ~ * ? : \
          轉(zhuǎn)義特殊字符只需在字符前加上符號(hào)\,例如搜索(1+1):2,使用查詢
          \(1\+1\)\:2??
          (李宇翻譯,來(lái)自Lucene的幫助文檔)上面這段看了之后很有幫助,解除了使用中的不少

          疑惑,謝謝翻譯者,同時(shí)應(yīng)該看到,有的時(shí)候詳細(xì)查看使用幫助文檔是非常有用的。
          ------------------------------------------------------------------------------
          索引文件格式

          本文定義了Lucene(版本1.3)用到的索引文件的格式。
          Jakarta Lucene是用Java寫成的,同時(shí)有很多團(tuán)體正在默默的用其他的程序語(yǔ)言來(lái)改寫它

          。如果這些新的版本想和Jakarta Lucene兼容,就需要一個(gè)與具體語(yǔ)言無(wú)關(guān)的Lucene索引

          文件格式。本文正是試圖提供一個(gè)完整的與語(yǔ)言無(wú)關(guān)的Jakarta Lucene 1.3索引文件格式

          的規(guī)格定義。
          隨著Lucene不斷發(fā)展,本文也應(yīng)該更新。不同語(yǔ)言寫成的Lucene實(shí)現(xiàn)版本應(yīng)當(dāng)盡力遵守文

          件格式,也必須產(chǎn)生本文的新版本。
          本文同時(shí)提供兼容性批注,描述文件格式上與前一版本不同的地方。

          定義
          Lucene中最基礎(chǔ)的概念是索引(index),文檔(document),域(field)和項(xiàng)(term)

          。
          索引包含了一個(gè)文檔的序列。
          · 文檔是一些域的序列。
          · 域是一些項(xiàng)的序列。
          · 項(xiàng)就是一個(gè)字串。
          存在于不同域中的同一個(gè)字串被認(rèn)為是不同的項(xiàng)。因此項(xiàng)實(shí)際是用一對(duì)字串表示的,第一

          個(gè)字串是域名,第二個(gè)是域中的字串。

          倒排索引
          為了使得基于項(xiàng)的搜索更有效率,索引中項(xiàng)是靜態(tài)存儲(chǔ)的。Lucene的索引屬于索引方式中

          的倒排索引,因?yàn)閷?duì)于一個(gè)項(xiàng)這種索引可以列出包含它的文檔。這剛好是文檔與項(xiàng)自然聯(lián)

          系的倒置。

          域的類型
          Lucene中,域的文本可能以逐字的非倒排的方式存儲(chǔ)在索引中。而倒排過的域稱為被索引

          過了。域也可能同時(shí)被存儲(chǔ)和被索引。
          域的文本可能被分解許多項(xiàng)目而被索引,或者就被用作一個(gè)項(xiàng)目而被索引。大多數(shù)的域是

          被分解過的,但是有些時(shí)候某些標(biāo)識(shí)符域被當(dāng)做一個(gè)項(xiàng)目索引是很有用的。

          段(Segment)
          Lucene索引可能由多個(gè)子索引組成,這些子索引成為段。每一段都是完整獨(dú)立的索引,能

          被搜索。索引是這樣作成的:
          1. 為新加入的文檔創(chuàng)建新段。
          2. 合并已經(jīng)存在的段。
          搜索時(shí)需要涉及到多個(gè)段和/或者多個(gè)索引,每一個(gè)索引又可能由一些段組成。

          文檔號(hào)(Document Number)
          內(nèi)部的來(lái)說(shuō),Lucene用一個(gè)整形(interger)的文檔號(hào)來(lái)指示文檔。第一個(gè)被加入到索引

          中的文檔就是0號(hào),順序加入的文檔將得到一個(gè)由前一個(gè)號(hào)碼遞增而來(lái)的號(hào)碼。
          注意文檔號(hào)是可能改變的,所以在Lucene外部存儲(chǔ)這些號(hào)碼時(shí)必須小心。特別的,號(hào)碼的

          改變的情況如下:
          · 只有段內(nèi)的號(hào)碼是相同的,不同段之間不同,因而在一個(gè)比段廣泛的上下文環(huán)境中使用

          這些號(hào)碼時(shí),就必須改變它們。標(biāo)準(zhǔn)的技術(shù)是根據(jù)每一段號(hào)碼多少為每一段分配一個(gè)段號(hào)

          。將段內(nèi)文檔號(hào)轉(zhuǎn)換到段外時(shí),加上段號(hào)。將某段外的文檔號(hào)轉(zhuǎn)換到段內(nèi)時(shí),根據(jù)每段中

          可能的轉(zhuǎn)換后號(hào)碼范圍來(lái)判斷文檔屬于那一段,并減調(diào)這一段的段號(hào)。例如有兩個(gè)含5個(gè)文

          檔的段合并,那么第一段的段號(hào)就是0,第二段段號(hào)5。第二段中的第三個(gè)文檔,在段外的

          號(hào)碼就是8。
          · 文檔刪除后,連續(xù)的號(hào)碼就出現(xiàn)了間斷。這可以通過合并索引來(lái)解決,段合并時(shí)刪除的

          文檔相應(yīng)也刪掉了,新合并而成的段并沒有號(hào)碼間斷。

          緒論
          索引段維護(hù)著以下的信息:
          · 域集合。包含了索引中用到的所有的域。
          · 域值存儲(chǔ)表。每一個(gè)文檔都含有一個(gè)“屬性-值”對(duì)的列表,屬性即為域名。這個(gè)列表

          用來(lái)存儲(chǔ)文檔的一些附加信息,如標(biāo)題,url或者訪問數(shù)據(jù)庫(kù)的一個(gè)ID。在搜索時(shí)存儲(chǔ)域的

          集合可以被返回。這個(gè)表以文檔號(hào)標(biāo)識(shí)。
          · 項(xiàng)字典。這個(gè)字典含有所有文檔的所有域中使用過的的項(xiàng),同時(shí)含有使用過它的文檔的

          文檔號(hào),以及指向使用頻數(shù)信息和位置信息的指針。
          · 項(xiàng)頻數(shù)信息。對(duì)于項(xiàng)字典中的每個(gè)項(xiàng),這些信息包含含有這個(gè)項(xiàng)的文檔的總數(shù),以及每

          個(gè)文檔中使用的次數(shù)。
          · 項(xiàng)位置信息。對(duì)于項(xiàng)字典中的每個(gè)項(xiàng),都存有在每個(gè)文檔中出現(xiàn)的各個(gè)位置。
          · Normalization factors. For each field in each document, a value is stored

          that is multiplied into the score for hits on that field. 標(biāo)準(zhǔn)化因子。對(duì)于文檔

          中的每一個(gè)域,存有一個(gè)值,用來(lái)以后乘以這個(gè)這個(gè)域的命中數(shù)(hits)。
          · 被刪除的文檔信息。這是一個(gè)可選文件,用來(lái)表明那些文檔已經(jīng)刪除了。
          接下來(lái)的各部分部分詳細(xì)描述這些信息。

          文件的命名(File Naming)
          同屬于一個(gè)段的文件擁有相同的文件名,不同的擴(kuò)展名。擴(kuò)展名由以下討論的各種文件格

          式確定。
          一般來(lái)說(shuō),一個(gè)索引存放一個(gè)目錄,其所有段都存放在這個(gè)目錄里,盡管我們不要求您這

          樣做。

          基本數(shù)據(jù)類型(Primitive Types)

          Byte
          最基本的數(shù)據(jù)類型就是字節(jié)(byte,8位)。文件就是按字節(jié)順序訪問的。其它的一些數(shù)據(jù)

          類型也定義為字節(jié)的序列,文件的格式具有字節(jié)意義上的獨(dú)立性。

          UInt32
          32位無(wú)符號(hào)整數(shù),由四個(gè)字節(jié)組成,高位優(yōu)先。

          UInt32 --> <Byte>4
          Uint64
          64位無(wú)符號(hào)整數(shù),由八字節(jié)組成,高位優(yōu)先。

          UInt64 --> <Byte>8
          VInt
          可變長(zhǎng)的正整數(shù)類型,每字節(jié)的最高位表明還剩多少字節(jié)。每字節(jié)的低七位表明整數(shù)的值

          。因此單字節(jié)的值從0到127,兩字節(jié)值從128到16,383,等等。

          VInt 編碼示例
          Value
          First byte
          Second byte
          Third byte

          0
          00000000
          1
          00000001
          2
          00000010
          ...
          127
          01111111
          128
          10000000
          00000001
          129
          10000001
          00000001
          130
          10000010
          00000001
          ...
          16,383
          11111111
          01111111
          16,384
          10000000
          10000000
          00000001
          16,385
          10000001
          10000000
          00000001
          ...

          這種編碼提供了一種在高效率解碼時(shí)壓縮數(shù)據(jù)的方法。

          Chars
          Lucene輸出UNICODE字符序列,使用標(biāo)準(zhǔn)UTF-8編碼。

          String
          Lucene輸出由VINT和字符串組成的字串,VINT表示字串長(zhǎng),字符串緊接其后。
          String --> VInt, Chars

          索引包含的文件(Per-Index Files)
          這部分介紹每個(gè)索引包含的文件。

          Segments文件
          索引中活動(dòng)的段存儲(chǔ)在Segments文件中。每個(gè)索引只能含有一個(gè)這樣的文件,名

          為"segments".這個(gè)文件依次列出每個(gè)段的名字和每個(gè)段的大小。
          Segments --> SegCount, <SegName, SegSize>SegCount
          SegCount, SegSize --> UInt32
          SegName --> String
          SegName表示該segment的名字,同時(shí)作為索引其他文件的前綴。
          SegSize是段索引中含有的文檔數(shù)。

          Lock文件
          有一些文件用來(lái)表示另一個(gè)進(jìn)程在使用索引。
          · 如果存在"commit.lock"文件,表示有進(jìn)程在寫"segments"文件和刪除無(wú)用的段索引文

          件,或者表示有進(jìn)程在讀"segments"文件和打開某些段的文件。在一個(gè)進(jìn)程在讀

          取"segments"文件段信息后,還沒來(lái)得及打開所有該段的文件前,這個(gè)Lock文件可以防止

          另一個(gè)進(jìn)程刪除這些文件。
          · 如果存在"index.lock"文件,表示有進(jìn)程在向索引中加入文檔,或者是從索引中刪除文

          檔。這個(gè)文件防止很多文件同時(shí)修改一個(gè)索引。

          Deleteable文件
          名為"deletetable"的文件包含了索引不再使用的文件的名字,這些文件可能并沒有被實(shí)際

          的刪除。這種情況只存在與Win32平臺(tái)下,因?yàn)閃in32下文件仍打開時(shí)并不能刪除。
          Deleteable --> DelableCount, <DelableName>DelableCount
          DelableCount --> UInt32
          DelableName --> String

          段包含的文件(Per-Segment Files)
          剩下的文件是每段中包含的文件,因此由后綴來(lái)區(qū)分。
          域(Field)
          域集合信息(Field Info)
          所有域名都存儲(chǔ)在這個(gè)文件的域集合信息中,這個(gè)文件以后綴.fnm結(jié)尾。
          FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount
          FieldsCount --> VInt
          FieldName --> String
          FieldBits --> Byte
          目前情況下,F(xiàn)ieldBits只有使用低位,對(duì)于已索引的域值為1,對(duì)未索引的域值為0。
          文件中的域根據(jù)它們的次序編號(hào)。因此域0是文件中的第一個(gè)域,域1是接下來(lái)的,等等。

          這個(gè)和文檔號(hào)的編號(hào)方式相同。
          域值存儲(chǔ)表(Stored Fields)
          域值存儲(chǔ)表使用兩個(gè)文件表示:

          1. 域索引(.fdx文件)。
          如下,對(duì)于每個(gè)文檔這個(gè)文件包含指向域值的指針:
          FieldIndex (.fdx) --> <FieldValuesPosition>SegSize
          FieldValuesPosition --> Uint64
          FieldValuesPosition指示的是某一文檔的某域的域值在域值文件中的位置。因?yàn)橛蛑滴募?/p>

          含有定長(zhǎng)的數(shù)據(jù)信息,因而很容易隨機(jī)訪問。在域值文件中,文檔n的域值信息就存在n*8

          位置處(The position of document n's field data is the Uint64 at n*8 in this

          file.)。

          2. 域值(.fdt文件)。
          如下,每個(gè)文檔的域值信息包含:
          FieldData (.fdt) --> <DocFieldData>SegSize
          DocFieldData --> FieldCount, <FieldNum, Bits, Value>FieldCount
          FieldCount --> VInt
          FieldNum --> VInt
          Bits --> Byte
          Value --> String
          目前情況下,Bits只有低位被使用,值為1表示域名被分解過,值為0表示未分解過。

          項(xiàng)字典(Term Dictionary)
          項(xiàng)字典用以下兩個(gè)文件表示:
          1. 項(xiàng)信息(.tis文件)。
          TermInfoFile (.tis)--> TermCount, TermInfos
          TermCount --> UInt32
          TermInfos --> <TermInfo>TermCount
          TermInfo --> <Term, DocFreq, FreqDelta, ProxDelta>
          Term --> <PrefixLength, Suffix, FieldNum>
          Suffix --> String
          PrefixLength, DocFreq, FreqDelta, ProxDelta
          --> VInt
          項(xiàng)信息按項(xiàng)排序。項(xiàng)信息排序時(shí)先按項(xiàng)所屬的域的文字順序排序,然后按照項(xiàng)的字串的文

          字順序排序。
          項(xiàng)的字前綴往往是共同的,與字的后綴組成字。PrefixLength變量就是表示與前一項(xiàng)相同

          的前綴的字?jǐn)?shù)。因此,如果前一個(gè)項(xiàng)的字是"bone",后一個(gè)是"boy"的話,PrefixLength值

          為2,Suffix值為"y"。

          FieldNum指明了項(xiàng)屬于的域號(hào),而域名存儲(chǔ)在.fdt文件中。
          DocFreg表示的是含有該項(xiàng)的文檔的數(shù)量。
          FreqDelta指明了項(xiàng)所屬TermFreq變量在.frq文件中的位置。詳細(xì)的說(shuō),就是指相對(duì)于前一

          個(gè)項(xiàng)的數(shù)據(jù)的位置偏移量(或者是0,表示文件中第一個(gè)項(xiàng))。
          ProxDelta指明了項(xiàng)所屬的TermPosition變量在.prx文件中的位置。詳細(xì)的說(shuō),就是指相對(duì)

          于前一個(gè)項(xiàng)的數(shù)據(jù)的位置偏移量(或者是0,表示文件中第一個(gè)項(xiàng))。

          2. 項(xiàng)信息索引(.tii文件)。
          每個(gè)項(xiàng)信息索引文件包含.tis文件中的128個(gè)條目,依照條目在.tis文件中的順序。這樣設(shè)

          計(jì)是為了一次將索引信息讀入內(nèi)存能,然后使用它來(lái)隨機(jī)的訪問.tis文件。
          這個(gè)文件的結(jié)構(gòu)和.tis文件非常類似,只在每個(gè)條目記錄上增加了一個(gè)變量IndexDelta。
          TermInfoIndex (.tii)--> IndexTermCount, TermIndices
          IndexTermCount --> UInt32
          TermIndices --> <TermInfo, IndexDelta>IndexTermCount
          IndexDelta --> VInt
          IndexDelta表示該項(xiàng)的TermInfo變量值在.tis文件中的位置。詳細(xì)的講,就是指相對(duì)于前

          一個(gè)條目的偏移量(或者是0,對(duì)于文件中第一個(gè)項(xiàng))。

          項(xiàng)頻數(shù)(Frequencies)
          .frq文件包含每一項(xiàng)的文檔的列表,還有該項(xiàng)在對(duì)應(yīng)文檔中出現(xiàn)的頻數(shù)。
          FreqFile (.frq) --> <TermFreqs>TermCount
          TermFreqs --> <TermFreq>DocFreq
          TermFreq --> DocDelta, Freq?
          DocDelta,Freq --> VInt
          TermFreqs序列按照項(xiàng)來(lái)排序(依據(jù)于.tis文件中的項(xiàng),即項(xiàng)是隱含存在的)。
          TermFreq元組按照文檔號(hào)升序排列。
          DocDelta決定了文檔號(hào)和頻數(shù)。詳細(xì)的說(shuō),DocDelta/2表示相對(duì)于前一文檔號(hào)的偏移量(

          或者是0,表示這是TermFreqs里面的第一項(xiàng))。當(dāng)DocDelta是奇數(shù)時(shí)表示在該文檔中頻數(shù)

          為1,當(dāng)DocDelta是偶數(shù)時(shí),另一個(gè)VInt(Freq)就表示在該文檔中出現(xiàn)的頻數(shù)。
          例如,假設(shè)某一項(xiàng)在文檔7中出現(xiàn)一次,在文檔11中出現(xiàn)了3次,在TermFreqs中就存在如下

          的VInts序列: 15, 22, 3

          項(xiàng)位置(Position)
          .prx文件包含了某文檔中某項(xiàng)出現(xiàn)的位置信息的列表。
          ProxFile (.prx) --> <TermPositions>TermCount
          TermPositions --> <Positions>DocFreq
          Positions --> <PositionDelta>Freq
          PositionDelta --> VInt
          TermPositions按照項(xiàng)來(lái)排序(依據(jù)于.tis文件中的項(xiàng),即項(xiàng)是隱含存在的)。
          Positions元組按照文檔號(hào)升序排列。
          PositionDelta是相對(duì)于前一個(gè)出現(xiàn)位置的偏移位置(或者為0,表示這是第一次在這個(gè)文

          檔中出現(xiàn))。
          例如,假設(shè)某一項(xiàng)在某文檔第4項(xiàng)出現(xiàn),在另一個(gè)文檔中第5項(xiàng)和第9項(xiàng)出現(xiàn),將存在如下的

          VInt序列: 4, 5, 4

          標(biāo)準(zhǔn)化因子(Normalization Factor)
          .nrm文件包含了每個(gè)文檔的標(biāo)準(zhǔn)化因子,標(biāo)準(zhǔn)化因子用來(lái)以后乘以這個(gè)這個(gè)域的命中數(shù)。
          Norms (.nrm) --> <Byte>SegSize
          每個(gè)字節(jié)記錄一個(gè)浮點(diǎn)數(shù)。位0-2包含了3位的尾數(shù)部分,位3-8包含了5位的指數(shù)部分。
          按如下規(guī)則可將這些字節(jié)轉(zhuǎn)換為IEEE標(biāo)準(zhǔn)單精度浮點(diǎn)數(shù):
          1. 如果該字節(jié)是0,就是浮點(diǎn)0;
          2. 否則,設(shè)置新浮點(diǎn)數(shù)的標(biāo)志位為0;
          3. 將字節(jié)中的指數(shù)加上48后作為新的浮點(diǎn)數(shù)的指數(shù);
          4. 將字節(jié)中的尾數(shù)映射到新浮點(diǎn)數(shù)尾數(shù)的高3位;并且
          5. 設(shè)置新浮點(diǎn)數(shù)尾數(shù)的低21位為0。

          被刪除的文檔(Deleted Document)
          .del文件是可選的,只有在某段中存在刪除操作后才存在:
          Deletions (.del) --> ByteCount,BitCount,Bits
          ByteSize,BitCount --> Uint32
          Bits --> <Byte>ByteCount
          ByteCount表示的是Bits列表中Byte的數(shù)量。典型的,它等于(SegSize/8)+1。
          BitCount表示Bits列表中多少個(gè)已經(jīng)被設(shè)置過了。
          Bits列表包含了一些位(bit),順序表示一個(gè)文檔。當(dāng)對(duì)應(yīng)于文檔號(hào)的位被設(shè)置了,就標(biāo)

          志著這個(gè)文檔已經(jīng)被刪除了。位的順序是從低到高。因此,如果Bits包含兩個(gè)字節(jié),0x00

          和0x02,那么表示文檔9已經(jīng)刪除了。

          局限性(Limitations)
          在以上的文件格式中,好幾處都有限制項(xiàng)和文檔的最大個(gè)數(shù)為32位數(shù)的極限,即接近于40

          億。今天看來(lái),這不會(huì)造成問題,但是,長(zhǎng)遠(yuǎn)的看,可能造成問題。因此,這些極限應(yīng)該

          或者換為UInt64類型的值,或者更好的,換為VInt類型的值(VInt值沒有上限)。
          有兩處地方的代碼要求必須是定長(zhǎng)的值,他們是:
          1. FieldValuesPosition變量(存儲(chǔ)于域索引文件中,.fdx文件)。它已經(jīng)是一個(gè)UInt64

          型,所以不會(huì)有問題。
          2. TermCount變量(存儲(chǔ)于項(xiàng)信息文件中,.tis文件)。這是最后輸出到文件中的,但是

          最先被讀取,因此是存儲(chǔ)于文件的最前端 。索引代碼先在這里寫入一個(gè)0值,然后在其他

          文件輸出完畢后覆蓋這個(gè)值。所以無(wú)論它存儲(chǔ)在什么地方,它都必須是一個(gè)定長(zhǎng)的值,它

          應(yīng)該被變成UInt64型。
          除此之外,所有的UInt值都可以換成VInt型以去掉限制
          ------------------------------------------------------------------------------

          ---------
          下面是lucene組成結(jié)構(gòu)中的類說(shuō)明:
          org.apache.Lucene.search/ 搜索入口
          org.apache.Lucene.index/ 索引入口
          org.apache.Lucene.analysis/ 語(yǔ)言分析器
          org.apache.Lucene.queryParser/ 查詢分析器
          org.apache.Lucene.document/ 存儲(chǔ)結(jié)構(gòu)
          org.apache.Lucene.store/? 底層IO/存儲(chǔ)結(jié)構(gòu)
          org.apache.Lucene.util/ 一些公用的數(shù)據(jù)結(jié)構(gòu)

          域存儲(chǔ)字段規(guī)則
          方法 切詞 索引 存儲(chǔ) 用途
          Field.Text(String name, String value) 切分詞索引并存儲(chǔ),比如:標(biāo)題,內(nèi)容字段
          Field.Text(String name, Reader value)? 切分詞索引不存儲(chǔ),比如:META信息,
          不用于返回顯示,但需要進(jìn)行檢索內(nèi)容
          Field.Keyword(String name, String value)? 不切分索引并存儲(chǔ),比如:日期字段
          Field.UnIndexed(String name, String value)? 不索引,只存儲(chǔ),比如:文件路徑
          Field.UnStored(String name, String value)? 只全文索引,不存儲(chǔ)

          建立索引的例子:
          public class IndexFiles {??
          //使用方法:: IndexFiles [索引輸出目錄] [索引的文件列表] ...??
          public static void main(String[] args) throws Exception {???
          String indexPath = args[0];??? IndexWriter writer;???
          //用指定的語(yǔ)言分析器構(gòu)造一個(gè)新的寫索引器(第3個(gè)參數(shù)表示是否為追加索引)???

          writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);???
          for (int i=1; i<args.length; i++) {?????
          System.out.println("Indexing file " + args[i]);?????
          InputStream is = new FileInputStream(args[i]);?????
          //構(gòu)造包含2個(gè)字段Field的Document對(duì)象?????
          //一個(gè)是路徑path字段,不索引,只存儲(chǔ)?????
          //一個(gè)是內(nèi)容body字段,進(jìn)行全文索引,并存儲(chǔ)?????
          Document doc = new Document();?????
          doc.add(Field.UnIndexed("path", args[i]));?????
          doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));?????
          //將文檔寫入索引????
          ?writer.addDocument(doc);?????
          is.close();??? };???
          //關(guān)閉寫索引器???
          writer.close();? }
          }
          索引過程中可以看到:

          語(yǔ)言分析器提供了抽象的接口,因此語(yǔ)言分析(Analyser)是可以定制的,雖然lucene缺省

          提供了2個(gè)比較通用的分析器SimpleAnalyser和StandardAnalyser,這2個(gè)分析器缺省都不

          支持中文,所以要加入對(duì)中文語(yǔ)言的切分規(guī)則,需要修改這2個(gè)分析器。
          Lucene并沒有規(guī)定數(shù)據(jù)源的格式,而只提供了一個(gè)通用的結(jié)構(gòu)(Document對(duì)象)來(lái)接受索

          引的輸入,因此輸入的數(shù)據(jù)源可以是:數(shù)據(jù)庫(kù),WORD文檔,PDF文檔,HTML文檔……只要能

          夠設(shè)計(jì)相應(yīng)的解析轉(zhuǎn)換器將數(shù)據(jù)源構(gòu)造成成Docuement對(duì)象即可進(jìn)行索引。
          對(duì)于大批量的數(shù)據(jù)索引,還可以通過調(diào)整IndexerWrite的文件合并頻率屬性(mergeFactor

          )來(lái)提高批量索引的效率。
          檢索過程和結(jié)果顯示:

          搜索結(jié)果返回的是Hits對(duì)象,可以通過它再訪問Document==>Field中的內(nèi)容。

          假設(shè)根據(jù)body字段進(jìn)行全文檢索,可以將查詢結(jié)果的path字段和相應(yīng)查詢的匹配度(score)

          打印出來(lái),

          public class Search {??
          public static void main(String[] args) throws Exception {???
          String indexPath = args[0], queryString = args[1];???
          //指向索引目錄的搜索器???
          Searcher searcher = new IndexSearcher(indexPath);???
          //查詢解析器:使用和索引同樣的語(yǔ)言分析器???
          Query query = QueryParser.parse(queryString, "body",???????????????????????????

          ?? new SimpleAnalyzer());???
          //搜索結(jié)果使用Hits存儲(chǔ)???
          Hits hits = searcher.search(query);???
          //通過hits可以訪問到相應(yīng)字段的數(shù)據(jù)和查詢的匹配度???
          for (int i=0; i<hits.length(); i++) {?????
          System.out.println(hits.doc(i).get("path") + "; Score: " +?????????????????????

          ??? hits.score(i));??? };? }
          }
          添加修改刪除指定記錄(Document)

          Lucene提供了索引的擴(kuò)展機(jī)制,因此索引的動(dòng)態(tài)擴(kuò)展應(yīng)該是沒有問題的,而指定記錄的修

          改也似乎只能通過記錄的刪除,然后重新加入實(shí)現(xiàn)。如何刪除指定的記錄呢?刪除的方法

          也很簡(jiǎn)單,只是需要在索引時(shí)根據(jù)數(shù)據(jù)源中的記錄ID專門另建索引,然后利用

          IndexReader.delete(Termterm)方法通過這個(gè)記錄ID刪除相應(yīng)的Document。

          根據(jù)某個(gè)字段值的排序功能
          根據(jù)某個(gè)字段值的排序功能

          lucene缺省是按照自己的相關(guān)度算法(score)進(jìn)行結(jié)果排序的,但能夠根據(jù)其他字段進(jìn)行

          結(jié)果排序是一個(gè)在LUCENE的開發(fā)郵件列表中經(jīng)常提到的問題,很多原先基于數(shù)據(jù)庫(kù)應(yīng)用都

          需要除了基于匹配度(score)以外的排序功能。而從全文檢索的原理我們可以了解到,任

          何不基于索引的搜索過程效率都會(huì)導(dǎo)致效率非常的低,如果基于其他字段的排序需要在搜

          索過程中訪問存儲(chǔ)字段,速度回大大降低,因此非常是不可取的。

          但這里也有一個(gè)折中的解決方法:在搜索過程中能夠影響排序結(jié)果的只有索引中已經(jīng)存儲(chǔ)

          的docID和score這2個(gè)參數(shù),所以,基于score以外的排序,其實(shí)可以通過將數(shù)據(jù)源預(yù)先排

          好序,然后根據(jù)docID進(jìn)行排序來(lái)實(shí)現(xiàn)。這樣就避免了在LUCENE搜索結(jié)果外對(duì)結(jié)果再次進(jìn)行

          排序和在搜索過程中訪問不在索引中的某個(gè)字段值。

          這里需要修改的是IndexSearcher中的HitCollector過程:

          ... scorer.score(new HitCollector() {?
          private float minScore = 0.0f;?
          public final void collect(int doc, float score) {??
          if (score > 0.0f &&???? // ignore zeroed buckets??????

          (bits==null || bits.get(doc))) {?? // skip docs not in bits????

          totalHits[0]++;???? if (score >= minScore) {????????????? /* 原先:Lucene將

          docID和相應(yīng)的匹配度score例入結(jié)果命中列表中:??????? * hq.put(new ScoreDoc

          (doc, score));?? // update hit queue?????????????? * 如果用doc 或 1/doc 代替

          score,就實(shí)現(xiàn)了根據(jù)docID順排或逆排?????????????? * 假設(shè)數(shù)據(jù)源索引時(shí)已經(jīng)按照某個(gè)

          字段排好了序,而結(jié)果根據(jù)docID排序也就實(shí)現(xiàn)了?????????????? * 針對(duì)某個(gè)字段的排序

          ,甚至可以實(shí)現(xiàn)更復(fù)雜的score和docID的擬合。?????????????? */?????????????

          hq.put(new ScoreDoc(doc, (float) 1/doc )); ??????
          if (hq.size() > nDocs) {??? // if hit queue overfull??

          hq.pop();???? // remove lowest in hit queue??

          minScore = ((ScoreDoc)hq.top()).score; // reset minScore?????? }???? }?

          ? }?}????? }, reader.maxDoc());

          Lucene面向全文檢索的優(yōu)化在于首次索引檢索后,并不把所有的記錄(Document)具體內(nèi)

          容讀取出來(lái),而起只將所有結(jié)果中匹配度最高的頭100條結(jié)果(TopDocs)的ID放到結(jié)果集

          緩存中并返回,這里可以比較一下數(shù)據(jù)庫(kù)檢索:如果是一個(gè)10,000條的數(shù)據(jù)庫(kù)檢索結(jié)果集

          ,數(shù)據(jù)庫(kù)是一定要把所有記錄內(nèi)容都取得以后再開始返回給應(yīng)用結(jié)果集的。所以即使檢索

          匹配總數(shù)很多,Lucene的結(jié)果集占用的內(nèi)存空間也不會(huì)很多。對(duì)于一般的模糊檢索應(yīng)用是

          用不到這么多的結(jié)果的,頭100條已經(jīng)可以滿足90%以上的檢索需求。

          如果首批緩存結(jié)果數(shù)用完后還要讀取更后面的結(jié)果時(shí)Searcher會(huì)再次檢索并生成一個(gè)上次

          的搜索緩存數(shù)大1倍的緩存,并再重新向后抓取。所以如果構(gòu)造一個(gè)Searcher去查1-120條

          結(jié)果,Searcher其實(shí)是進(jìn)行了2次搜索過程:頭100條取完后,緩存結(jié)果用完,Searcher重

          新檢索再構(gòu)造一個(gè)200條的結(jié)果緩存,依此類推,400條緩存,800條緩存。由于每次

          Searcher對(duì)象消失后,這些緩存也訪問那不到了,你有可能想將結(jié)果記錄緩存下來(lái),緩存

          數(shù)盡量保證在100以下以充分利用首次的結(jié)果緩存,不讓Lucene浪費(fèi)多次檢索,而且可以分

          級(jí)進(jìn)行結(jié)果緩存。

          Lucene的另外一個(gè)特點(diǎn)是在收集結(jié)果的過程中將匹配度低的結(jié)果自動(dòng)過濾掉了。這也是和

          數(shù)據(jù)庫(kù)應(yīng)用需要將搜索的結(jié)果全部返回不同之處。

          posted on 2006-11-08 14:58 Lansing 閱讀(1368) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2006年11月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          歡迎探討,努力學(xué)習(xí)Java哈

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          Lansing's Download

          Lansing's Link

          我的博客

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 从化市| 红桥区| 民县| 安溪县| 武强县| 仁寿县| 柳州市| 报价| 东兴市| 湘西| 龙南县| 自贡市| 恩施市| 沁源县| 福泉市| 邛崃市| 封开县| 扶沟县| 温州市| 琼海市| 松滋市| 静乐县| 疏勒县| 慈利县| 故城县| 琼海市| 临江市| 曲靖市| 淳安县| 土默特左旗| 分宜县| 民丰县| 资兴市| 拉孜县| 兴安盟| 扶余县| 新建县| 蒙城县| 淮阳县| 苍山县| 镇远县|