?
快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

和記娛棒h88285:在應用中加入全文檢索功能基于Java的全文索引引擎Lucene簡介

?

在利用中加入全文檢索功能

??基于Java的全文索引引擎Lucene簡介

作者: 車東 [email protected]

著末更新: 02/13/2003 12:48:05

版權聲明:可以隨意率性轉載,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明

http://www.chedong.com/tech/lucene.html

關鍵詞:Lucene java full-text search engine Chinese word segment

內容擇要:

Lucene是一個基于Java的全文索引對象包。

基于Java的全文索引引擎Lucene簡介:關于作者和Lucene的歷史

全文檢索的實現:Luene全文索引和數據庫索引的對照

中文切分詞機制簡介:基于詞庫和自動切分詞算法的對照

詳細的安裝和應用簡介:系統布局先容和演示

Hacking Lucene:簡化的查詢闡發器,刪除的實現,定制的排序,利用接口的擴展

從Lucene我們還可以學到什么

基于Java的全文索引/檢索引擎??Lucene

Lucene不是一個完備的全文索引利用,而是是一個用Java寫的全文索引引擎對象包,它可以方便的嵌入到各類利用中實現針對利用的全文索引/檢索功能。

Lucene的作者:Lucene的供獻者Doug Cutting是一位資深全文索引/檢索專家,曾經是V-Twin搜索引擎(Apple的Copland操作系統的成績之一)的主要開拓者,后在Excite擔負高檔系統架構設計師,今朝從事于一些INTERNET底層架構的鉆研。他供獻出的Lucene的目標是為各類中小型利用法度榜樣加入全文檢索功能。

Lucene的成長過程:起初宣布在作者自己的www.lucene.com,后來宣布在SourceForge,2001年事尾成為APACHE基金會jakarta的一個子項目:http://jakarta.apache.org/lucene/

已經有很多Java項目都應用了Lucene作為其后臺的全文索引引擎,對照聞名的有:

Jive:WEB論壇系統;

Eyebrows:郵件列表HTML歸檔/瀏覽/查詢系統,本文的主要參考文檔“The Lucene search engine: Powerful, flexible, and free”作者便是EyeBrows系統的主要開拓者之一,而EyeBrows已經成為今朝APACHE和記娛棒h88285項目的主要郵件列表歸檔系統。

Cocoon: 基于XML的web宣布框架,全文檢索部分應用了Lucene

Eclipse: 基于Java的開攤開拓平臺,贊助部分的全文索引應用了Lucene

對付中文用戶來說,最關心的問題是其是否支持中文的全文檢索。但經由過程后面對付Lucene的布局的先容,你會懂得到因為Lucene優越架構設計,對中文的支持只需對其說話詞法闡發接口進行擴展就能實現對中文檢索的支持。

全文檢索的實現機制

Lucene的API接口設計的對照通用,輸入輸出布局都很像數據庫的表==>記錄==>字段,以是很多傳統的利用的文件、數據庫等都可以對照方便的映射到Lucene的存儲布局/接口中??傮w上看:可以先把Lucene當成一個支持全文索引的數據庫系統。

對照一下Lucene和數據庫:

Lucene 數據庫

索引數據源:doc(field1,field2...) doc(field1,field2...) indexer / _____________ | Lucene Index| -------------- / searcher 結果輸出:Hits(doc(field1,field2) doc(field1...))

索引數據源:record(field1,field2...) record(field1..) SQL: insert/ _____________ | DB Index | ------------- / SQL: select 結果輸出:results(record(field1,field2..) record(field1...))

Document:一個必要進行索引的“單元”

一個Document由多個字段組成 Record:記錄,包孕多個字段

Field:字段 Field:字段

Hits:查詢結果集,由匹配的Document組成 RecordSet:查詢結果集,由多個Record組成

全文檢索 ≠ like "%keyword%"

平日對照厚的冊本后面經常附關鍵詞索引表(比如:北京:12, 34頁, 上海:3, 77頁……),它能夠贊助讀者對照快地找到相關內容的頁碼。而數據庫索引能夠大年夜大年夜前進查詢的速率道理也是一樣,想像一下經由過程書后面的索引查找的速率要比一頁一頁地翻內容高若干倍……而索引之以是效率高,別的一個緣故原由是它是排好序的。對付檢索系統來說核心是一個排序問題。

因為數據庫索引不是為全文索引設計的,是以,應用like "%keyword%"時,數據庫索引是不起感化的,在應用like查詢時,搜索歷程又變成類似于一頁頁翻書的遍歷歷程了,以是對付含有隱隱查詢的數據庫辦事來說,LIKE對機能的迫害是極大年夜的。假如是必要對多個關鍵詞進行隱隱匹配:like "%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。

以是建立一個高效檢索系統的關鍵是建立一個類似于科技索引一樣的反向索引機制,將數據源(比如多篇文章)排序順序存儲的同時,有別的一個排好序的關鍵詞列表,用于存儲關鍵詞==>文章映射關系,使用這樣的映射關系索引:[關鍵詞==>呈現關鍵詞的文章編號,呈現次數(以致包括位置:肇端偏移量,停止偏移量),呈現頻率],檢索歷程便是把隱隱查詢變成多個可以使用索引的正確查詢的邏輯組合的歷程。從而大年夜大年夜前進了多關鍵詞查詢的效率,以是,全文檢索問題歸結到著末是一個排序問題。

由此可以看出隱隱查詢相對數據庫的正確查詢是一個異常不確定的問題,這也是大年夜部分數據庫對全文檢索支持有限的緣故原由。Lucene最核心的特性是經由過程特殊的索引布局實現了傳統數據庫不長于的全文索引機制,并供給了擴展接口,以方便針對不合利用的定制。

可以經由過程一下表格比較一下數據庫的隱隱查詢:

Lucene全文索引引擎 數據庫

索引 將數據源中的數據都經由過程全文索引逐一建立反向索引 對付LIKE 查詢來說,數據傳統的索引是根本用不上的。數據必要逐個便利記錄進行GREP式的隱隱匹配,比有索引的搜索速率要有多個數量級的下降。

匹配效果 經由過程詞元(term)進行匹配,經由過程說話闡發接口的實現,可以實現對中文等非英語的支持。 應用:like "%net%" 會把netherlands也匹配出來,

多個關鍵詞的隱隱匹配:應用like "%com%net%":就不能匹配詞序倒置的xxx.net..xxx.com

匹配度 有匹配度算法,將匹配程度(相似度)對照高的結果排在前面。 沒有匹配程度的節制:比如有記錄中net呈現5詞和呈現1次的,結果是一樣的。

結果輸出 經由過程特其余算法,將最匹配度最高的頭100條結果輸出,結果集是緩沖式的小批量讀取的。 返回所有的結果集,在匹配條款異常多的時刻(比如上萬條)必要大年夜量的內存寄放這些臨時結果集。

可定制性 經由過程不合的說話闡發接口實現,可以方便的定制出相符利用必要的索引規則(包括對中文的支持) 沒有接口或接口繁雜,無法定制

結論 高負載的隱隱查詢利用,必要認真的隱隱查詢的規則,索引的資料量對照大年夜 應用率低,隱隱匹配規則簡單或者必要隱隱查詢的資料量少

全文檢索和數據庫利用最大年夜的不合在于:讓最相關的頭100條結果滿意98%以上用戶的需求

Lucene的立異之處:

大年夜部分的搜索(數據庫)引擎都是用B樹布局來掩護索引,索引的更新會導致大年夜量的IO操作,Lucene在實現中,對此輕細有所改進:不是掩護一個索引文件,而是在擴展索引的時刻賡續創建新的索引文件,然后按期的把這些新的小索引文件合并到本來的大年夜索引中(針對不合的更新策略,批次的大年夜小可以調劑),這樣在不影響檢索的效率的條件下,前進了索引的效率。

Lucene和其他一些全文檢索系統/利用的對照:

Lucene 其他開源全文檢索系統

增量索引和批量索引 可以進行增量的索引(Append),可以對付大年夜量數據進行批量索引,并且接口設計用于優化批量索引和小批量的增量索引。 很多系統只支持批量的索引,無意偶爾數據源有一點增添也必要重修索引。

數據源 Lucene沒有定義詳細的數據源,而是一個文檔的布局,是以可以異常機動的適應各類利用(只要前端有相宜的轉換器把數據源轉換成響應布局), 很多系統只針對網頁,短缺其他款式文檔的機動性。

索引內容抓取 Lucene的文檔是由多個字段組成的,以致可以節制那些字段必要進行索引,那些字段不必要索引,近一步索引的字段也分為必要分詞和不必要分詞的類型:

必要進行分詞的索引,比如:標題,文章內容字段

不必要進行分詞的索引,比如:作者/日期字段 短缺通用性,每每將文檔全部索引了

說話闡發 經由過程說話闡發器的不合擴展實現:

可以過濾掉落不必要的詞:an the of 等,

西文語法闡發:將jumps jumped jumper都歸結成jump進行索引/檢索

非英文支持:對亞洲說話,阿拉伯說話的索引支持 短缺通用接口實現

查詢闡發 經由過程查詢闡發接口的實現,可以定制自己的查詢語律例則:

比如: 多個關鍵詞之間的 + - and or關系等

并發造訪和記娛棒h88285 能夠支持多用戶的應用

關于亞洲說話的的切分詞問題(Word Segment)

對付中文來說,全文索引首先還要辦理一個說話闡發的問題,對付英文來說,語句中單詞之間是天然經由過程空格分開的,但亞洲說話的中日韓文語句中的字是一個字挨一個,所有,首先要把語句中按“詞”進行索引的話,這個詞若何切分出來便是一個很大年夜的問題。

首先,肯定不能用單個字符作(si-gram)為索引單元,否則查“上海&和記娛棒h88285rdquo;時,不能讓含有“海上”也匹配。

但一句話:“北京天安門”,謀略機若何按照中文的說話習氣進行切分呢?

“北京 天安門” 照樣“北 京 天安門”?讓謀略性能夠按照說話習氣進行切分,每每必要機械有一個對照和記娛棒h88285富厚的詞庫才能夠對照準確的識別出語句中的單詞。

別的一個辦理的法子是采納自動切分算法:將單詞按照2元語法(bigram)要領切分出來,比如:

"北京天安門" ==> "北京 京天 天安 安門"。

這樣,在查詢的時刻,無論是查詢"北京" 照樣查詢"天安門",將查詢詞組按同樣的規則進行切分:"北京","天安安門",多個關鍵詞之間按與"and"的關系組合,同樣能夠精確地映射到響應的索引中。這種要領對付其他亞洲說話:韓文,日文都是通用的。

基于自動切分的最大年夜優點是沒有詞表掩護資源,實現簡單,毛病是索引效率低,但對付中小型利用來說,基于2元語法的切分照樣夠用的?;?元切分后的索引一樣平常大年夜小和源文件差不多,而對付英文,索引文件一樣平常只有原文件的30%-40%不合,

自動切分 詞表切分

實現 實現異常簡單 實現繁雜

查詢 增添了查詢闡發的繁雜程度, 適于實現對照繁雜的查詢語律例則

存儲效率 索引冗余大年夜,索引險些和原文一樣大年夜 索引效率高,為原文大年夜小的30%閣下

掩護資源 無詞表掩護資源 詞表掩護資源異常高:中日韓等說話必要分手掩護。

還必要包括詞頻統計等內容

適用領域 嵌入式系統:運行情況資本有限

散播式系統:無詞表同步問題

多說話情況:無詞表掩護資源 對查詢和存儲效率要求高的專業搜索引擎

今朝對照大年夜的搜索引擎的說話闡發算法一樣平常是基于以上2個機制的結合。關于中文的說話闡發算法,大年夜家可以在Google查關鍵詞"word segment search"能找到更多相關的資料。

安裝和應用

下載:http://jakarta.apache.org/lucene/

留意:Lucene中的一些對照繁雜的詞法闡發是用JavaCC天生的(JavaCC:Java Compiler Compiler,純Java的詞法闡產天生器),以是假如從源代碼編譯或必要改動此中的QueryParser、定制自己的詞法闡發器,還必要從http://www.webgain.com/products/java_cc/下載javacc。

lucene的組成布局:對付外部利用來說索引模塊(index)和檢索模塊(search)是主要的外部利用進口

org.apache.Lucene.search/ 搜索進口

org.apache.Lucene.index/ 索引進口

org.apache.Lucene.analysis/ 說話闡發器

org.apache.Lucene.queryParser/ 查詢闡發器

org.apache.Lucene.document/ 存儲布局

org.apache.Lucene.store/ 底層IO/存儲布局

org.apache.Lucene.util/ 一些公用的數據布局

簡單的例子演示一下Lucene的應用措施:

索引歷程:從敕令行讀取文件名(多個),將文件分路徑(path字段)和內容(body字段)2個字段進行存儲,并對內容進行全文索引:索引的單位是Document工具,每個Document工具包孕多個字段Field工具,針對不合的字段屬性和數據輸出的需求,對字段還可以選擇不合的索引/存儲字段規則,列表如下: 措施 切詞 索引 存儲 用途

Field.Text(String name, String value) Yes Yes Yes 切分詞索引并存儲,比如:標題,內容字段

Field.Text(String name, Reader value) Yes Yes No 切分詞索引不存儲,比如:META信息,

不用于返回顯示,但必要進行檢索內容

Field.Keyword(String name, String value) No Yes Yes 不切分索引并存儲,比如:日期字段

Field.UnIndexed(String name, String value) No No Yes 不索引,只存儲,比如:文件路徑

Field.UnStored(String name, String value) Yes Yes No 只全文索引,不存儲

public class IndexFiles { //應用措施:: IndexFiles [索引輸出目錄] [索引的文件列表] ... public static void main(String[] args) throws Exception { String indexPath = args[0]; IndexWriter writer; //用指定的說話闡發器構造一個新的寫索引器(第3個參數表示是否為追加索引) writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false); for (int i=1; iField中的內容。

假設根據body字段進行全文檢索,可以將查詢結果的path字段和響應查詢的匹配度(score)打印出來,

public class Search { public static void main(String[] args) throws Exception { String indexPath = args[0], queryString = args[1]; //指向索引目錄的搜索器 Searcher searcher = new IndexSearcher(indexPath); //查詢解析器:應用和索引同樣的說話闡發器 Query query = QueryParser.parse(queryString, "body", new SimpleAnalyzer()); //搜索結果應用Hits存儲 Hits hits = searcher.search(query); //經由過程hits可以造訪到響應字段的數據和查詢的匹配度 for (int i=0; i ":"] (| "(和記娛棒h88285" Query ")" )

中心的邏輯包括:and or + - && ||等符號,而且還有"短語查詢"和針對西文的前綴/隱隱查詢等,小我感到對付一樣平常利用來說,這些功能有一些華而不實,著實能夠實現今朝類似于Google的查詢語句闡發功能著實對付大年夜多半用戶來說已經夠了。以是,Lucene早期版本的QueryParser仍是對照好的選擇。

添加改動刪除指定記錄(Document)

Lucene供給了索引的擴展機制,是以索引的動態擴展應該是沒有問題的,而指定記錄的改動也彷佛只能經由過程記錄的刪除,然后從新加入實現。若何刪除指定的記錄呢?刪除的措施也很簡單,只是必要在索引時根據數據源中的記錄ID專門另建索引,然后使用IndexReader.delete(Term term)措施經由過程這個記錄ID刪除響應的Document。

根據某個字段值的排序功能

lucene缺省是按照自己的相關度算法(score)進行結果排序的,但能夠根據其他字段進行結果排序是一個在LUCENE的開拓郵件列表中常常提到的問題,很多本來基于數據庫利用都必要除了基于匹配度(score)以外的排序功能。而從全文檢索的道理我們可以懂得到,任何不基于索引的搜索歷程效率都邑導致效率異常的低,假如基于其他字段的排序必要在搜索歷程中造訪存儲字段,速率回大年夜大年夜低落,是以異常是弗成取的。

但這里也有一個折中的辦理措施:在搜索歷程中能夠影響排序結果的只有索引中已經存儲的docID和score這2個參數,以是,基于score以外的排序,著實可以經由過程將數據源預先排好序,然后根據docID進行排序來實現。這樣就避免了在LUCENE搜索結果外對結果再次進行排序和在搜索歷程中造訪不在索引中的某個字段值。

這里必要改動的是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和響應的匹配度score例入結果射中列表中: * hq.put(new ScoreDoc(doc, score)); // update hit queue * 假如用doc 或 1/doc 代替 score,就實現了根據docID順排或逆排 * 假設數據源索引時已經按照某個字段排好了序,而結果根據docID排序也就實現了 * 針對某個字段的排序,以致可以實現更繁雜的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沒有定義一個確定的輸入文檔款式,但越來越多的人想到應用一個標準的中心款式作為Lucene的數據導入接口,然后其他數據,比如PDF只必要經由過程解析器轉換成標準的中心款式就可以進行數據索引了。這其中心款式主要以XML為主,類似實現已經不下4,5個:

數據源: WORD PDF HTML DB other | | | / XML中心款式 | Lucene INDEX

索引歷程優化

索引一樣平常分2種環境,一種是小批量的索引擴展,一種是大年夜批量的索引重修。在索引歷程中,并不是每次新的DOC加入進去索引都從新進行一次索引文件的寫入操作(文件I/O是一件異常耗損資本的工作)。

Lucene先在內存中進行索引操作,并根據必然的批量進行文件的寫入。這個批次的距離越大年夜,文件的寫入次數越少,但占用內存會很多。反之占用內存少,但文件IO操作頻繁,索引速率會很慢。在IndexWriter中有一個MERGE_FACTOR參數可以贊助你在構造索引器后根據利用情況的環境充分使用內存削減文件的操作。根據我的應用履歷:缺省Indexer是每20筆記錄索引后寫入一次,每將MERGE_FACTOR增添50倍,索引速率可以前進1倍閣下。

檢索緩存優化

Lucene面向全文檢索的優化在于首次索引檢索后,并不把所有的記錄(Document)詳細內容讀掏出來,而起只將所有結果中匹配度最高的頭100條結果(TopDocs)的ID放到結果集緩存中并返回,這里可以對照一下數據庫檢索:假如是一個10,000條的數據庫檢索結果集,數據庫是必然要把所有記錄內容都取得今后再開始返回給利用結果集的。以是縱然檢索匹配總數很多,Lucene的結果集占用的內存空間也不會很多。對付一樣平常的隱隱檢索利用是用不到這么多的結果的,頭100條已經可以滿意90%以上的檢索需求。

假如首批緩存結果數用完后還要讀取更后面的結果時Searcher會再次檢索并天生一個上次的搜索緩存數大年夜1倍的緩存,并再從新向后抓取。以是假如構造一個Searcher去查1-120條結果,Searcher著實是進行了2次搜索歷程:頭100條取完后,緩存結果用完,Searcher從新檢索再構造一個200條的結果緩存,依此類推,400條緩存,800條緩存。因為每次Searcher工具消掉后,這些緩存也造訪那不到了,你有可能想將結果記錄緩存下來,緩存數只管即便包管在100以下以充分使用首次的結果緩存,不讓Lucene揮霍多次檢索,而且可以分級進行結果緩存。

Lucene的別的一個特征是在網絡結果的歷程中將匹配度低的結果自動過濾掉落了。這也是和數據庫利用必要將搜索的結果整個返回不合之處。

我的一些考試測驗:

支持中文的Tokenizer:這里有2個版本,一個是經由過程JavaCC天生的,對CJK部分按一個字符一個TOKEN索引,別的一個是從SimpleTokenizer改寫的,對英文支持數字和字母TOKEN,對中文按迭代索引。

基于XML數據源的索引器:XMLIndexer,是以所稀有據源只要能夠按照DTD轉換成指定的XML,就可以用XMLIndxer進行索引了。

根據某個字段排序:按記錄索引順序排序結果的搜索器:IndexOrderSearcher,是以假如必要讓搜索結果根據某個字段排序,可以讓數據源先按某個字段排好序(比如:PriceField),這樣索引后,然后在使用這個按記錄的ID順序檢索的搜索器,結果便是相稱于是那個字段排序的結果了。

從Lucene學到更多

Luene切實著實是一個面對工具設計的典范

所有的問題都經由過程一個額外抽象層來方便今后的擴展和重用:你可以經由過程從新實現來達到自己的目的,而對其他模塊而不必要;

簡單的利用進口Searcher, Indexer,并調用底層一系列組件協同的完成搜索義務;

所有的工具的義務都異常埋頭:比如搜索歷程:QueryParser闡發將查詢語句轉換成一系列的正確查詢的組合(Query), 經由過程底層的索引讀取布局IndexReader進行索引的讀取,并用響應的打分器給搜索結果進行打分/排序等。所有的功能模塊原子化程度異常高,是以可以經由過程從新實現而不必要改動其他模塊。

除了機動的利用接口設計,Lucene還供給了一些得當大年夜多半利用的說話闡發器實現(SimpleAnalyser, StandardAnalyser),這也是新用戶能夠很快上手的緊張緣故原由之一。

這些優點都是異常值得在今后的開拓中進修借鑒的。作為一個通用對象包,Lunece切實著實給予了必要將全文檢索功能嵌入到利用中的開拓者很多的便利。

此外,經由過程對Lucene的進修和應用,我也更深刻地輿解了為什么很多半據庫優化設計中要求,比如:

盡可能對字段進行索引來前進查詢速率,但過多的索引會對數據庫表的更新操作變慢,而對結果過多的排序前提,實際上每每也是機能的殺手之一。

很多商業數據庫對大年夜批量的數據插入操作會供給一些優化參數,這個感化和索引器的merge_factor的感化是類似的,

20%/80%原則:查的結果多并不即是質量好,尤其對付返回結果集很大年夜,若何優化這頭幾十條結果的質量每每才是最緊張的。

盡可能讓利用從數據庫中得到對照小的結果集,由于縱然對付大年夜型數據庫,對結果集的隨機造訪也是一個異常耗損資本的操作。

參考資料:

Apache: Lucene Project

http://jakarta.apache.org/lucene/

Lucene郵件列表歸檔

[email protected]

[email protected]

The Lucene search engine: Powerful, flexible, and free

http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html

Lucene Tutorial

http://www.darksleep.com/puff/lucene/lucene.html

Notes on distributed searching with Lucene

http://home.clara.net/markharwood/lucene/

中文說話的切分詞

http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment

搜索引擎對象先容

http://searchtools.com/

搜索引擎行業鉆研

http://www.searchenginewatch.com/

Lucene作者Cutting的幾篇論文:

http://lucene.sourceforge.net/publications.html

Lucene的.NET實現:

http://sourceforge.net/projects/nlucene

Lucene作者Cutting的別的一個項目:基于Java的索引引擎Nutch

http://www.nutch.org/ http://sourceforge.net/projects/notch/

關于基于詞表和N-Gram的切分詞對照

http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html

原文出處:;http://www.chedong.com/tech/lucene.html

免責聲明:以上內容源自網絡,版權歸原作者所有,如有侵犯您的原創版權請告知,我們將盡快刪除相關內容。

您可能還會對下面的文章感興趣:

快三平台开户