溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

luncence學(xué)習(xí)

發(fā)布時(shí)間:2020-07-16 21:45:26 來源:網(wǎng)絡(luò) 閱讀:212 作者:淺嫣 欄目:開發(fā)技術(shù)

1. 全文檢索基礎(chǔ)

1.1. 我們身邊的搜索功能
1. Windows系統(tǒng)中的有搜索功能:打開“我的電腦”,按“F3”就可以使用查找的功能,查找指定的文件或文件夾。搜索的范圍是整個(gè)電腦中的文件資源。
2. Eclipse中的幫助子系統(tǒng):點(diǎn)擊HelpàHelp Contents,可以查找出相關(guān)的幫助信息。搜索的范圍是Eclipse的所有幫助文件。
3. 在BBS、BLOG等系統(tǒng)中提供的搜索文章的功能,如這里的貼吧的例子。搜索的范圍是系統(tǒng)內(nèi)的文章數(shù)據(jù)(都在數(shù)據(jù)庫中)。
4. 搜索引擎,如Baidu或Google等,可以查詢到互聯(lián)網(wǎng)中的網(wǎng)頁、PDF、DOC、PPT、圖片、音樂、視頻等。下圖是使用百度搜索的效果:
 
 
以上的查詢功能都類似。都是查詢的文本內(nèi)容,都是相同的查詢方式,即找出含有指定字符串的資源,不同的只是查詢范圍(分別為硬盤、所有幫助文件、數(shù)據(jù)庫、互聯(lián)網(wǎng))。
 

1.2. 什么是全文檢索
全文檢索是計(jì)算機(jī)程序通過掃描文章中的每一個(gè)詞,對每一個(gè)詞建立一個(gè)索引,指明該詞在文章中出現(xiàn)的次數(shù)和位置。當(dāng)用戶查詢時(shí)根據(jù)建立的索引查找,類似于通過字典的檢索字表查字的過程。
 
對于搜索,按被搜索的資源類型,分為兩種:可以轉(zhuǎn)為文本的、多媒體類型。我們上一節(jié)提到的搜索功能都是搜索的可以轉(zhuǎn)為文本的資源(第一種)。注意,百度或谷歌提供的音樂或視頻搜索不是多媒體搜索,他們是按文件名搜索。在智能手機(jī)上有一款音樂搜索的軟件,可以讓他聽10秒鐘的音樂,然后他就能上網(wǎng)找出這段音樂的名稱、演奏者等信息。這是多媒體搜索。
按搜索的方式,上一節(jié)提到的搜索功能都是不處理語義,只是找出包含指定詞的所有資源(只對詞進(jìn)行匹配)。下圖就是顯示“中國的首都是哪里”這個(gè)搜索要求對應(yīng)的結(jié)果,可以看到,是沒有“北京”這個(gè)結(jié)果的,結(jié)果頁面都是出現(xiàn)了這些詞的網(wǎng)頁:
 
 
全文檢索(Full-Text Retrieval)是指以文本作為檢索對象,找出含有指定詞匯的文本。全面、準(zhǔn)確和快速是衡量全文檢索系統(tǒng)的關(guān)鍵指標(biāo)。
關(guān)于全文檢索,我們要知道:1,只處理文本。2,不處理語義。3,搜索時(shí)英文不區(qū)分大小寫。4,結(jié)果列表有相關(guān)度排序。
在信息檢索工具中,全文檢索是最具通用性和實(shí)用性的。

1.3. 全文檢索的應(yīng)用場景
我們使用Lucene,主要是做站內(nèi)搜索,即對一個(gè)系統(tǒng)內(nèi)的資源進(jìn)行搜索。如BBS、BLOG中的文章搜索,網(wǎng)上商店中的商品搜索等。使用Lucene的項(xiàng)目有Eclipse、Jira等。一般不做互聯(lián)網(wǎng)中資源的搜索,因?yàn)椴灰撰@取與管理海量資源(專業(yè)搜索方向的公司除外)。
所以,學(xué)完Lucene后我們就可以為自已的系統(tǒng)增加全文檢索的功能。跟這個(gè)學(xué)習(xí)內(nèi)容相關(guān)的練習(xí)為:為“傳智手播客貼吧”增加搜索其中的文章的功能。
 

1.4. 全文檢索不同于數(shù)據(jù)庫搜索
全文檢索不同于數(shù)據(jù)庫的SQL查詢。(他們所解決的問題不一樣,解決的方案也不一樣,所以不應(yīng)進(jìn)行對比)。在數(shù)據(jù)庫中的搜索就是使用SQL,如:SELECT * FROM t WHERE content like ‘%ant%’。這樣會有如下問題:
1. 匹配效果:如搜索ant會搜索出planting。這樣就會搜出很多無關(guān)的信息。
2. 相關(guān)度排序:查出的結(jié)果沒有相關(guān)度排序,不知道我想要的結(jié)果在哪一頁。我們在使用百度搜索時(shí),一般不需要翻頁,為什么?因?yàn)榘俣茸隽讼嚓P(guān)度排序:為每一條結(jié)果打一個(gè)分?jǐn)?shù),這條結(jié)果越符合搜索條件,得分就越高,叫做相關(guān)度得分,結(jié)果列表會按照這個(gè)分?jǐn)?shù)由高到低排列,所以第1頁的結(jié)果就是我們最想要的結(jié)果。
3. 全文檢索的速度大大快于SQL的like搜索的速度。這是因?yàn)椴樵兎绞讲煌斐傻模圆樽值渑e例:數(shù)據(jù)庫的like就是一頁一頁的翻,一行一行的找,而全文檢索是先查目錄,得到結(jié)果所在的頁碼,再直接翻到這一頁。
 
所以數(shù)據(jù)庫搜索不能替代全文檢索。

1.5. Lucene簡介
全文檢索就如同ORM,是一個(gè)概念。ORM的框架有很多種:Hibernate、TopLink、iBatis等,我們之前學(xué)習(xí)的是Hibernate。同樣的,全文檢索領(lǐng)域中也有多種框架,Lucene就是其中的一個(gè)用開源的全文檢索框架。
Lucene的主頁為:http://lucene.apache.org/。本文檔中所使用的Lucene為3.0.1的版本。
 

2. 第一個(gè)Lucene程序

2.1. 準(zhǔn)備Lucene的開發(fā)環(huán)境
搭建Lucene的開發(fā)環(huán)境只需要加入Lucene的Jar包,要加入的jar包至少要有:
l lucene-core-3.0.1.jar(核心包)
l contrib\analyzers\common\lucene-analyzers-3.0.1.jar(分詞器)
l contrib\highlighter\lucene-highlighter-3.0.1.jar(高亮)
l contrib\memory\lucene-memory-3.0.1.jar(高亮)
 

2.2. 實(shí)現(xiàn)建立索引功能(Indexer類)

2.3. 實(shí)現(xiàn)搜索功能(Searcher類)

3. Lucene的核心概念

3.1. 全文檢索程序的工作流程
如果信息檢索系統(tǒng)在用戶發(fā)出了檢索請求后再去互聯(lián)網(wǎng)上找答案,根本無法在有限的時(shí)間內(nèi)返回結(jié)果。所以要先把要檢索的資源集合放到本地,并使用某種特定的結(jié)構(gòu)存儲,稱為索引,這個(gè)索引的集合稱為索引庫。由于索引庫的結(jié)構(gòu)是按照專門為快速查詢設(shè)計(jì)的,所以查詢的速度非???。我們每次搜索都是在本地的索引庫中進(jìn)行,如下圖:
 
從圖片上可以看出,我們不僅要搜索,還要保證數(shù)據(jù)集合與索引庫的一致性。所以對于全文檢索功能的開發(fā),要做的有兩個(gè)方面:索引庫管理(維護(hù)索引庫中的數(shù)據(jù))、在索引庫中進(jìn)行搜索。而Lucene就是操作索引庫的工具。

3.2. 使用Lucene的API操作索引庫
 
索引庫是一個(gè)目錄,里面是一些二進(jìn)制文件,就如同數(shù)據(jù)庫,所有的數(shù)據(jù)也是以文件的形式存在文件系統(tǒng)中的。我們不能直接操作這些二進(jìn)制文件,而是使用Lucene提供的API完成相應(yīng)的操作,就像操作數(shù)據(jù)庫應(yīng)使用SQL語句一樣。
對索引庫的操作可以分為兩種:管理與查詢。管理索引庫使用IndexWriter,從索引庫中查詢使用IndexSearcher。Lucene的數(shù)據(jù)結(jié)構(gòu)為Document與Field。Document代表一條數(shù)據(jù),F(xiàn)ield代表數(shù)據(jù)中的一個(gè)屬性。一個(gè)Document中有多個(gè)Field,F(xiàn)ield的值為String型,因?yàn)長ucene只處理文本。
我們只需要把在我們的程序中的對象轉(zhuǎn)成Document,就可以交給Lucene管理了,搜索的結(jié)果中的數(shù)據(jù)列表也是Document的集合。
有了這些概念,可以寫HelloWorld了,其他的概念可以在寫完HelloWorld后再進(jìn)行說明。
 

3.3. 索引庫結(jié)構(gòu)——倒排序索引
 
我們需要對文檔進(jìn)行預(yù)處理,建立一種便于檢索的數(shù)據(jù)結(jié)構(gòu),以此來提高信息檢索的速度,這種數(shù)據(jù)結(jié)構(gòu)就是索引。目前廣泛使用的一種索引方式是倒排序索引。
倒排序索引的原理就如同查字典。要先查目錄,得到數(shù)據(jù)對應(yīng)的頁碼,在直接翻到指定的頁碼。不是在文章中找詞,而是從目錄中找詞所在的文章。這需要在索引庫中生成一個(gè)詞匯表(目錄),在詞匯表中的每一個(gè)條記錄都是類似于“詞à所在文檔的編號列表”的結(jié)構(gòu),記錄了每一個(gè)出現(xiàn)過的單詞,和單詞出現(xiàn)的地方(哪些文檔)。查詢時(shí)先查詞匯表,得到文檔的編號,再直接取出相應(yīng)的文檔。
 
把數(shù)據(jù)轉(zhuǎn)成指定格式放到索引庫中的操作叫做建立索引。建立索引時(shí),在把數(shù)據(jù)存到索引庫后,再更新詞匯表。進(jìn)行搜索時(shí),先從檢索詞匯表開始,然后找到相對應(yīng)的文檔。如果查詢中僅包含一個(gè)關(guān)鍵詞,則在詞匯表中找到該單詞,并取出他對應(yīng)的文檔就可以了。如果查詢中包含多個(gè)關(guān)鍵詞,則需要將各個(gè)單詞檢索出的記錄進(jìn)行合并再取出相應(yīng)的文檔記錄。
如果詞匯表中有一個(gè)詞“傳智播客”對應(yīng)的文檔編號列表為“1”?,F(xiàn)在又有添加了一個(gè)包含“傳智播客”的文檔,則詞匯表中的“傳智播客”詞后對應(yīng)的編號列表變成了“1,2”。因?yàn)殛P(guān)鍵詞的數(shù)量受實(shí)際語言的限制,所以不用擔(dān)心詞匯表會變的很大。

3.4. 索引文件的檢索與維護(hù),更新是先刪除后創(chuàng)建
維護(hù)倒排索引有三個(gè)操作:添加、刪除和更新文檔。但是更新操作需要較高的代價(jià)。因?yàn)槲臋n修改后(即使是很小的修改),就可能會造成文檔中的很多的關(guān)鍵詞的位置都發(fā)生了變化,這就需要頻繁的讀取和修改記錄,這種代價(jià)是相當(dāng)高的。因此,一般不進(jìn)行真正的更新操作,而是使用“先刪除,再創(chuàng)建”的方式代替更新操作。

3.5. 建立索引的執(zhí)行過程
在建立索引時(shí),先要把文檔存到索引庫中,還要更新詞匯表。如下圖:
 
 
 
1. 我們做的操作:把數(shù)據(jù)對象轉(zhuǎn)成相應(yīng)的Document,其中的屬性轉(zhuǎn)為Field。
2. 我們做的操作:調(diào)用工具IndexWriter的addDocument(doc),把Document添加到索引庫中。
3. Lucene做的操作:把文檔存到索引庫中,并自動(dòng)指定一個(gè)內(nèi)部編號,用來唯一標(biāo)識這條數(shù)據(jù)。內(nèi)部編號類似于這條數(shù)據(jù)的地址,在索引庫內(nèi)部的數(shù)據(jù)進(jìn)行調(diào)整后,這個(gè)編號就可能會改變,同時(shí)詞匯表中引用的編號也會做相應(yīng)改變,以保證正確。但我們?nèi)绻谕饷嬉昧诉@個(gè)編號,前后兩次去取,得到的可能不是同一個(gè)文檔!所以內(nèi)部編號最好只在內(nèi)部用。
4. Lucene做的操作:更新詞匯表。把文本中的詞找出并放到詞匯表中,建立與文檔的對應(yīng)關(guān)系。要把哪些詞放到詞匯表中呢,也就是文本中包含哪些詞呢?這就用到了一個(gè)叫做Analyzer(分詞器)的工具。他的作用是把一段文本中的詞按規(guī)則取出所包含的所有詞。對應(yīng)的是Analyzer類,這是一個(gè)抽象類,切分詞的具體規(guī)則是由子類實(shí)現(xiàn)的,所以對于不同的語言(規(guī)則),要用不同的分詞器。如下圖:
 
在把對象的屬性轉(zhuǎn)為Field時(shí),相關(guān)代碼為:doc.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED))。第三與第四個(gè)參數(shù)的意思為:

枚舉類型


枚舉常量


說明


Store


NO


不存儲屬性的值


YES


存儲屬性的值


Index


NO


不建立索引


ANALYZED


分詞后建立索引


NOT_ANALYZED


不分詞,把整個(gè)內(nèi)容作為一個(gè)詞建立索引

說明:Store是影響搜索出的結(jié)果中是否有指定屬性的原始內(nèi)容。Index是影響是否可以從這個(gè)屬性中查詢(No),或是查詢時(shí)可以查其中的某些詞(ANALYZED),還是要把整個(gè)內(nèi)容作為一個(gè)詞進(jìn)行查詢(NOT_ANALYZED)。
 

3.6. 從索引庫中搜索的執(zhí)行過程
在進(jìn)行搜索時(shí),先在詞匯表中查找,得到符合條件的文檔編號列表。再根據(jù)文檔編號真正的去取出數(shù)據(jù)(Document)。如下圖:
 
 
1, 把要查詢字符串轉(zhuǎn)為Query對象。這就像在Hibernate中使用HQL查詢時(shí),也要先調(diào)用Session.createQuery(hql)轉(zhuǎn)成Hibernate的Query對象一樣。把查詢字符串轉(zhuǎn)換成Query是使用QueryParser,或使用MultiFieldQueryParser。查詢字符串也要先經(jīng)過Analyzer(分詞器)。要求搜索時(shí)使用的Analyzer要與建立索引時(shí)使用的Analzyer要一致,否則可能搜不出正確的結(jié)果。
2, 調(diào)用IndexSearcher.search(),進(jìn)行查詢,得到結(jié)果。此方法返回值為TopDocs,是包含結(jié)果的多個(gè)信息的一個(gè)對象。其中有totalHits 代表決記錄數(shù),ScoreDoc的數(shù)組。ScoreDoc是代表一個(gè)結(jié)果的相關(guān)度得分與文檔編號等信息的對象。
3, 取出要用到的數(shù)據(jù)列表。調(diào)用IndexSearcher.doc(scoreDoc.doc)以取出指定編號對應(yīng)的Document數(shù)據(jù)。在分頁時(shí)要用到:一次只取一頁的數(shù)據(jù)。
 
 

4. Lucene的核心API介紹

4.1. 與建立索引有關(guān)的API

4.1.1. IndexWriter
構(gòu)造方法1:IndexWriter(Directory d, Analyzer a, MaxFieldLength mfl)
 
構(gòu)造方法2:IndexWriter(Directory d, Analyzer a, boolean create, MaxFieldLength mfl),第三個(gè)參數(shù)指定,true表示建立新的索引庫或覆蓋現(xiàn)有的索引庫(刪除后重建);false表示使用已有的索引庫,如果不存在,就報(bào)錯(cuò)。
 
commit()
rollback()
close()
 

4.1.2. Directory--FSDirectory、RAMDirectory

4.1.3. Analyzer--分詞器

4.1.4. Document

4.1.5. Field

4.2. 與搜索有關(guān)的API

4.2.1. IndexSearcher
在索引庫中進(jìn)行搜索是使用類IndexSearcher。創(chuàng)建其實(shí)例的構(gòu)造方法為:IndexSearcher (Directory path)。用完后要調(diào)用IndexSearcher.close()方法釋放資源。
 

4.2.2. Term

4.2.3. Query類及其子類
Query:抽象類,必須通過一系列子類來表述檢索的具體需求。

4.2.4. QueryParser與MultiFieldQueryParser
1, QueryParser與MultiFieldQueryParser
查詢分析器,處理用戶輸入的查詢條件。把用戶輸入的非格式化檢索詞轉(zhuǎn)化成后臺檢索可以理解的Query對象。使用的構(gòu)造方法為:QueryParser(Version matchVersion, String f, Analyzer a)
 
2, MultiFieldQueryParser
是QueryParser的子類。與父類相比,MultiFieldQueryParser可以在多個(gè)屬性中搜索。使用的構(gòu)造方法為:MultiFieldQueryParser(Version matchVersion, String[] fields, Analyzer analyzer)
 

4.2.5. TopDocs

4.2.6. ScoreDoc

5. 維護(hù)索引庫

5.1. 數(shù)據(jù)與Document、Field的轉(zhuǎn)換
我們在應(yīng)用程序中使用對象表示數(shù)據(jù)。在數(shù)據(jù)庫中使用的是表記錄,所以存在來回轉(zhuǎn)換的問題。同樣,要索引庫中使用的是Document,也存在來回轉(zhuǎn)換的問題。如下圖:
 
 
對于一個(gè)要進(jìn)行搜索的實(shí)體對象,我們會寫一個(gè)對應(yīng)的工具類,其中有兩個(gè)方法:
Document Object2Document(Object object); // 對象àDocument
Object Document2Object(Document doc); // Documentà對象
在轉(zhuǎn)換時(shí),對象中的屬性對應(yīng)Document中的Field。由于Lucene只處理文本,所有所有的屬性值在存儲前都要先轉(zhuǎn)成字符串。使用構(gòu)造方法:Field(String name, String value, Store store, Index index)。
 
Store與Index都是枚舉類型。Store:指定是否把當(dāng)前屬性值的原始內(nèi)容存儲到索引庫中。如果存儲(YES),在搜索出相應(yīng)數(shù)據(jù)時(shí)這個(gè)屬性就有原始的值;如果不存儲(NO),得到的數(shù)據(jù)的這個(gè)屬性的值為null。Index:指定是否建立索引(詞匯表)。建立索引才能被搜索到。不可以不存儲也不建立索引(沒有意義)。
// Store 指定當(dāng)前字段的數(shù)據(jù)要不要存到索引庫中
// Index 指定當(dāng)前字段的數(shù)據(jù)是否可以被搜索(是否更新詞匯表)
 
索引設(shè)置的一些建議:
1) 盡量減少不必要的存儲
2) 不需要檢索的內(nèi)容不要建立索引
3) 非文本格式需要提前轉(zhuǎn)化
4)需要整體存放的內(nèi)容不要分詞
 
NumericUtils與DateTools
如果屬性的類型不是字符串,則要先進(jìn)轉(zhuǎn)換:如果是數(shù)字類型,使用NumericUtils。如果是日期類型,則使用DataTools。

5.2. 創(chuàng)建索引

5.3. 刪除索引

5.4. 更新索引

5.5. 索引庫文件的優(yōu)化

5.5.1. 合并索引庫文件
IndexWriter.optimize()
indexWriter.setMergeFactor(int)
 

5.5.2. 使用RAMDirectory
Lucene的API接口設(shè)計(jì)的比較通用,輸入輸出結(jié)構(gòu)都很像數(shù)據(jù)庫的表==>記錄==>字段,所以很多傳統(tǒng)的應(yīng)用的文件、數(shù)據(jù)庫等都可以比較方便的映射到Lucene的存儲結(jié)構(gòu)/接口中。總體上看:可以先把Lucene當(dāng)成一個(gè)支持全文索引的數(shù)據(jù)庫系統(tǒng)。
Lucene的索引存儲位置使用的是一個(gè)接口(抽象類),也就可以實(shí)現(xiàn)各種各樣的實(shí)際存儲方式(實(shí)現(xiàn)類、子類),比如存到文件系統(tǒng)中,存在內(nèi)存中、存在數(shù)據(jù)庫中等等。Lucene提供了兩個(gè)子類:FSDirectory與RAMDirectory。
1, FSDirectory:在文件系統(tǒng)中,是真實(shí)的文件夾與文件。
2, RAMDirectory:在內(nèi)存中,是模擬的文件夾與文件。與FSDirectory相比:1因?yàn)闆]有IO操作,所以速度快。2,因?yàn)樵趦?nèi)存中,所以在程序退出后索引庫數(shù)據(jù)就不存在了。
 
索引庫的相關(guān)操作:
1, 合并索引庫:Directory.addIndexes()
2, 索引的優(yōu)化:IndexWriter.optimize()

6. 從索引庫中搜索

6.1. 兩種查詢方式說明

6.2. 使用查詢字符串+QueryParser的查詢方式
QueryParser:只在一個(gè)字段中查詢
MultiFieldQueryParser:可以在多個(gè)字段查詢

6.3. 使用構(gòu)建Query子類的查詢方式

6.3.1. TermQuery
關(guān)鍵詞查詢

6.3.2. NumericRangeQuery
范圍查詢。使用靜態(tài)方法構(gòu)造實(shí)例:
newIntRange(final String field,
Integer min, Integer max,
final boolean minInclusive, final boolean maxInclusive)
newLongRange(final String field,
Long min, Long max,
final boolean minInclusive, final boolean maxInclusive)
newFloatRange(final String field,
Float min, Float max,
final boolean minInclusive, final boolean maxInclusive)
newDoubleRange(final String field,
Double min, Double max,
final boolean minInclusive, final boolean maxInclusive)

6.3.3. WildcardQuery
通配符查詢

6.3.4. PhraseQuery
短語查詢
public void add(Term term, int position)
public void setSlop(int s)
 
例:add( new Term(“name”, “l(fā)ucene”, 1);
add(new Term(“name”, “教程”, 3);
代表搜索的是“Lucene ? 教程”,?表示中間隔一個(gè)詞。
setSlop(2);
代表這兩個(gè)詞中間可以最多隔2個(gè)詞

6.3.5. BooleanQuery
public void add(Query query, Occur occur)
 
Occur 用于表示布爾查詢子句關(guān)系的類,包括:
Occur.MUST,Occur.MUST_NOT,Occur.SHOULD。
 
1, MUST和MUST:取得連個(gè)查詢子句的交集。
2, MUST和MUST_NOT:包含MUST并且查詢結(jié)果中不包含MUST_NOT的檢索結(jié)果。
3, SHOULD與SHOULD,表示“或”關(guān)系,最終檢索結(jié)果為所有檢索子句的并集。
 
一般不單獨(dú)使用,因?yàn)閱为?dú)就不應(yīng)使用BooleanQuery了。
 
使用時(shí)注意:
1, 單獨(dú)使用MUST_NOT:無意義,檢索無結(jié)果。(也不報(bào)錯(cuò))
2, MUST_NOT和MUST_NOT:無意義,檢索無結(jié)果。(也不報(bào)錯(cuò))
 
3, 單獨(dú)使用SHOULD:結(jié)果相當(dāng)于MUST。
4, SHOULD和MUST_NOT: 此時(shí)SHOULD相當(dāng)于MUST,結(jié)果同MUST和MUST_NOT。
5, MUST和SHOULD:此時(shí)SHOULD無意義,結(jié)果為MUST子句的檢索結(jié)果。
 

6.3.6. 測試各種查詢的代碼模板
// 查詢出所有文檔
@Test
public void testMatchAllDocsQuery () { }
// 關(guān)鍵詞查詢
@Test
public void testTermQuery() { }
// 范圍查詢
@Test
public void testRangeQuery() { }
// 通配符查詢
@Test
public void testWildcardQuery() { }
// 短語查詢
@Test
public void testPhraseQuery() { }
// 布爾查詢
@Test
public void testBooleanQuery() { }
 
 
 

6.4. 排序
通過改變文檔Boost值來改變排序結(jié)果。Boost是指索引建立過程中,給整篇文檔或者文檔的某一特定屬性設(shè)定的權(quán)值因子,在檢索時(shí),優(yōu)先返回分?jǐn)?shù)高的。通過Document對象的setBoost()方法和Field對象的setBoost()方法,可以分別為Document和Field指定Boost參數(shù)。不同在于前者對文檔中每一個(gè)域都修改了參數(shù),而后者只針對指定域進(jìn)行修改。默認(rèn)情值為1F,一般不做修改。
 
使用Sort對象定制排序。Sort支持的排序功能以文檔當(dāng)中的域?yàn)閱挝?,通過這種方法,可以實(shí)現(xiàn)一個(gè)或者多個(gè)不同域的多形式的值排序。時(shí)間類型的屬性采用STRING常量。
 
 

6.4.1. 按相關(guān)度排序
1,相關(guān)度得分是在查詢時(shí)根據(jù)查詢條件實(shí)進(jìn)計(jì)算出來的
2,如果索引庫據(jù)不變,查詢條件不變,查出的文檔得分也不變

6.4.2. 按指定的字段排序
If you want to be able to sort results by a Field value, you must add it as a Field that is indexed but not analyzed, using  Field.Index.NOT_ANALYZED.
 

6.5. 過濾
使用Filter可以對搜索結(jié)果進(jìn)行過濾以獲得更小范圍的結(jié)果。使用Filter對性能的影響很大(有可能會使查詢慢上百倍)。

6.6. 高亮

6.6.1. 高亮所需的jar包
contrib\highlighter\lucene-highlighter-3.0.1.jar
contrib\memory\lucene-memory-3.0.1.jar

6.6.2. 實(shí)現(xiàn)高亮效果的代碼
// 生成高亮器
Formatter formatter = new SimpleHTMLFormatter("<span class='kw'>", "</span>");
Scorer scorer = new QueryScorer(query);
Highlighter highlighter = new Highlighter(formatter, scorer);
highlighter.setTextFragmenter(new SimpleFragmenter(20));
 
// 使用高亮器:對content屬性值進(jìn)行摘要并高亮
String text = highlighter.getBestFragment(LuceneUtils.getAnalyzer(), "content", doc.get("content"));
// 如果進(jìn)行高亮的屬性值中沒有要搜索的關(guān)鍵字,則返回null
if (text != null) {
doc.getField("content").setValue(text);
}
 
 

7. 分詞器

7.1. 分詞器的作用
在創(chuàng)建索引時(shí)會用到分詞器,在使用字符串搜索時(shí)也會用到分詞器,這兩個(gè)地方要使用同一個(gè)分詞器,否則可能會搜索不出結(jié)果。
 
Analyzer(分詞器)的作用是把一段文本中的詞按規(guī)則取出所包含的所有詞。對應(yīng)的是Analyzer類,這是一個(gè)抽象類,切分詞的具體規(guī)則是由子類實(shí)現(xiàn)的,所以對于不同的語言(規(guī)則),要用不同的分詞器。如下圖:
 
 

7.2. 分詞器的工作流程
(英文)分詞器的一般工作流程:
1, 切分關(guān)鍵詞
2, 去除停用詞
3,對于英文單詞,把所有字母轉(zhuǎn)為小寫(搜索時(shí)不區(qū)分大小寫)
 
說明:有的分詞器還對英文進(jìn)行形態(tài)還原,就是去除單詞詞尾的形態(tài)變化,將其還原為詞的原形。這樣做可以搜索出更多有意義的結(jié)果。如搜索sutdent時(shí),也可以搜索出students,這是很有用的。

7.3. 停用詞
有些詞在文本中出現(xiàn)的頻率非常高,但是對文本所攜帶的信息基本不產(chǎn)生影響,例如英文的“a、an、the、of”,或中文的“的、了、著”,以及各種標(biāo)點(diǎn)符號等,這樣的詞稱為停用詞(stop word)。文本經(jīng)過分詞之后,停用詞通常被過濾掉,不會被進(jìn)行索引。在檢索的時(shí)候,用戶的查詢中如果含有停用詞,檢索系統(tǒng)也會將其過濾掉(因?yàn)橛脩糨斎氲牟樵冏址惨M(jìn)行分詞處理)。排除停用詞可以加快建立索引的速度,減小索引庫文件的大小。
 

7.4. 常用的中文分詞器
中文的分詞比較復(fù)雜,因?yàn)椴皇且粋€(gè)字就是一個(gè)詞,而且一個(gè)詞在另外一個(gè)地方就可能不是一個(gè)詞,如在“帽子和服裝”中,“和服”就不是一個(gè)詞。對于中文分詞,通常有三種方式:單字分詞、二分法分詞、詞典分詞。
l 單字分詞:就是按照中文一個(gè)字一個(gè)字地進(jìn)行分詞。如:“我們是中國人”,效果:“我”、“們”、“是”、“中”、“國”、“人”。(StandardAnalyzer就是這樣)。
l 二分法分詞:按兩個(gè)字進(jìn)行切分。如:“我們是中國人”,效果:“我們”、“們是”、“是中”、“中國”、“國人”。(CJKAnalyzer就是這樣)。
l 詞庫分詞:按某種算法構(gòu)造詞,然后去匹配已建好的詞庫集合,如果匹配到就切分出來成為詞語。通常詞庫分詞被認(rèn)為是最理想的中文分詞算法。如:“我們是中國人”,效果為:“我們”、“中國人”。(使用極易分詞的MMAnalyzer??梢允褂谩皹O易分詞”,或者是“庖丁分詞”分詞器、IKAnalyzer)。
 
 
其他的中文分詞器有:
1, 極易分詞:MMAnalyzer,最后版本是1.5.3,更新時(shí)間是2007-12-05,不支持Lucene3.0
2, 庖丁分詞:PaodingAnalzyer,最后版本是2.0.4,更新時(shí)間是2008-06-03,不支持Lucene3.0
 
 
中文分詞器使用IKAnalyzer,主頁:http://www.oschina.net/p/ikanalyzer。
實(shí)現(xiàn)了以詞典為基礎(chǔ)的正反向全切分,以及正反向最大匹配切分兩種方法。IKAnalyzer是第三方實(shí)現(xiàn)的分詞器,繼承自Lucene的Analyzer類,針對中文文本進(jìn)行處理。具體的使用方式參見其文檔。
注意:擴(kuò)展的詞庫與停止詞文件要是UTF-8的編碼,并且在要文件頭部加一空行。
 

7.5. 測試分詞器的代碼
/**
 * 使用指定的分詞器對指定的文本進(jìn)行分詞,并打印出分出的詞
 * @param analyzer
 * @param text
 * @throws Exception
 */
private void testAnalyzer(Analyzer analyzer, String text) throws Exception {
System.out.println("當(dāng)前使用的分詞器:" + analyzer.getClass());
TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text));
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(termAttribute.term());
}
System.out.println();
}

8. Lucene應(yīng)用

8.1. 使用IndexDao封裝對索引庫的增刪改查

8.1.1. IndexDao說明
提出問題:所有的數(shù)據(jù)(對象),我們都要存到數(shù)據(jù)庫中。對于要進(jìn)行搜索的數(shù)據(jù),還要存到索引庫中,以供搜索。一份數(shù)據(jù)同時(shí)存到數(shù)據(jù)庫與索引庫中(格式不同),就要想辦法保證他們的狀態(tài)一致。否則,就會影響搜索結(jié)果。
 
解決思路:對于上一段提出的問題:保證索引庫中與數(shù)據(jù)庫中的數(shù)據(jù)一致(只要針對要進(jìn)行搜索的數(shù)據(jù))。我們采用的方法是,在數(shù)據(jù)庫中做了相應(yīng)的操作后,在索引庫中也做相應(yīng)的操作。具體的索引庫操作,是通過調(diào)用相應(yīng)的IndexDao方法完成的。IndexDao類似于數(shù)據(jù)庫層的Dao。
我們目前只關(guān)注IndexDao中的每個(gè)方法的作用(怎么用起來方便就怎么設(shè)計(jì))?,F(xiàn)在不需要關(guān)心IndexDao的每個(gè)方法怎么實(shí)現(xiàn),因?yàn)槟鞘窍乱徊降氖虑?。設(shè)計(jì)IndexDao如下:
 
 
IndexDao的使用:
PublishAction.execute(){ // 發(fā)表文章
actionForm à article對象
articleDao.save( article ); // 保存到數(shù)據(jù)庫
articleIndexDao.save( article ); // 保存到索引庫
}
DeleteAction.execute(){ // 刪除文章
articleDao.delete( id ); // 從數(shù)據(jù)庫中刪除
articleIndex.delete( id ); // 從索引庫中刪除
}
UpdateAction.execute(){ // 更新文章
actionForm à article對象
articleDao.update( article ); // 更新數(shù)據(jù)庫中的相應(yīng)數(shù)據(jù)
articleIndexDao.update( article ); // 更新索引庫中的相應(yīng)數(shù)據(jù)
}
 

8.1.2. 實(shí)現(xiàn)IndexDao中的方法:建立、刪除、更新索引
 
索引庫的管理操作操作是通過類IndexWriter完成的。創(chuàng)建實(shí)例是使用構(gòu)造方法:IndexWriter(Directory d, Analyzer a, MaxFieldLength mfl)。用完后要調(diào)用IndexWriter.close()方法釋放資源。
 
1, 建立索引:保存文檔到索引庫中。
a) 把數(shù)據(jù)轉(zhuǎn)成Document對象的形式。
b) 調(diào)用方法IndexWriter.addDocument(Document doc)
 
2, 刪除索引:刪除所有包含指定Term的文檔。
a) 生成用于確定要?jiǎng)h除的文檔的Term
b) 調(diào)用方法IndexWriter.deleteDocuments(Term term)
說明:在生成Term時(shí),一般。如果有多個(gè)文檔含有指定的Term,則都會被刪掉。
 
3, 更新索引:實(shí)際執(zhí)行的是先刪除,后創(chuàng)建的操作。(參見前面的 索引文件的檢索與維護(hù))
a) 把要更新后的對象轉(zhuǎn)為Document對象
b) 生成用于確定要更新的文檔的Term
c) 調(diào)用方法IndexWriter.updateDocument(Term term, Document doc)
說明:如果有多個(gè)文檔含有指定的Term,更新后就只有一條記錄(刪掉所有,再創(chuàng)建一個(gè))。如果沒有文檔含有指定的記錄,不會報(bào)錯(cuò),更新后有一條(新創(chuàng)建的)記錄。
 
 


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI