Lucene基本使用和代码实现
目錄
?
?
?
Lucene:全文檢索技術(shù)
一、Lucene的介紹
1.1背景
1.2優(yōu)點(diǎn)
1.3Lucene的缺點(diǎn)
1.4全文檢索
二、Lucene的基本使用流程
2.1Lucene檢索過程
2.2獲取文檔
2.3分析文檔(分詞)
2.4創(chuàng)建索引
2.5查詢索引
三、Lucene具體實(shí)現(xiàn)
3.1下載
3.2實(shí)際開發(fā)要使用的jar包
3.3代碼實(shí)現(xiàn)
3.4使用Luke工具查看索引文件
3.5分析器
3.6索引庫的維護(hù)(增刪改)
?
?
Lucene:全文檢索技術(shù)
一、Lucene的介紹
1.1背景
Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開放源代碼的全文檢索引擎工具包,但它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是為軟件開發(fā)人員提供一個(gè)簡單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。Lucene是一套用于全文檢索和搜尋的開源程式庫,由Apache軟件基金會(huì)支持和提供。Lucene提供了一個(gè)簡單卻強(qiáng)大的應(yīng)用程式接口,能夠做全文索引和搜尋。在Java開發(fā)環(huán)境里L(fēng)ucene是一個(gè)成熟的免費(fèi)開源工具。就其本身而言,Lucene是當(dāng)前以及最近幾年最受歡迎的免費(fèi)Java信息檢索程序庫。人們經(jīng)常提到信息檢索程序庫,雖然與搜索引擎有關(guān),但不應(yīng)該將信息檢索程序庫與搜索引擎相混淆。
Lucene['lusen]的原作者是Doug Cutting,他是一位資深全文索引/檢索專家,曾經(jīng)是V-Twin搜索引擎的主要開發(fā)者,后在Excite擔(dān)任高級系統(tǒng)架構(gòu)設(shè)計(jì)師,當(dāng)前從事于一些Internet底層架構(gòu)的研究。早先發(fā)布在作者自己的博客上,他貢獻(xiàn)出Lucene的目標(biāo)是為各種中小型應(yīng)用程式加入全文檢索功能。后來發(fā)布在SourceForge,2001年年底成為apache軟件基金會(huì)jakarta的一個(gè)子項(xiàng)目。
1.2優(yōu)點(diǎn)
作為一個(gè)開放源代碼項(xiàng)目,Lucene從問世之后,引發(fā)了開放源代碼社群的巨大反響,程序員們不僅使用它構(gòu)建具體的全文檢索應(yīng)用,而且將之集成到各種系統(tǒng)軟件中去,以及構(gòu)建Web應(yīng)用,甚至某些商業(yè)軟件也采用了Lucene作為其內(nèi)部全文檢索子系統(tǒng)的核心。apache軟件基金會(huì)的網(wǎng)站使用了Lucene作為全文檢索的引擎,IBM的開源軟件eclipse[9]的2.1版本中也采用了Lucene作為幫助子系統(tǒng)的全文索引引擎,相應(yīng)的IBM的商業(yè)軟件Web Sphere[10]中也采用了Lucene。Lucene以其開放源代碼的特性、優(yōu)異的索引結(jié)構(gòu)、良好的系統(tǒng)架構(gòu)獲得了越來越多的應(yīng)用。
Lucene是一個(gè)高性能、可伸縮的信息搜索(IR)庫。它可以為你的應(yīng)用程序添加索引和搜索能力。Lucene是用java實(shí)現(xiàn)的、成熟的開源項(xiàng)目,是著名的Apache Jakarta大家庭的一員,并且基于Apache軟件許可 [ASF, License]。同樣,Lucene是當(dāng)前非常流行的、免費(fèi)的Java信息搜索(IR)庫。
(1)索引文件格式獨(dú)立于應(yīng)用平臺。Lucene定義了一套以8位字節(jié)為基礎(chǔ)的索引文件格式,使得兼容系統(tǒng)或者不同平臺的應(yīng)用能夠共享建立的索引文件。
(2)在傳統(tǒng)全文檢索引擎的倒排索引的基礎(chǔ)上,實(shí)現(xiàn)了分塊索引,能夠針對新的文件建立小文件索引,提升索引速度。然后通過與原有索引的合并,達(dá)到優(yōu)化的目的。
(3)優(yōu)秀的面向?qū)ο蟮南到y(tǒng)架構(gòu),使得對于Lucene擴(kuò)展的學(xué)習(xí)難度降低,方便擴(kuò)充新功能。
(4)設(shè)計(jì)了獨(dú)立于語言和文件格式的文本分析接口,索引器通過接受Token流完成索引文件的創(chuàng)立,用戶擴(kuò)展新的語言和文件格式,只需要實(shí)現(xiàn)文本分析的接口。
(5)已經(jīng)默認(rèn)實(shí)現(xiàn)了一套強(qiáng)大的查詢引擎,用戶無需自己編寫代碼即可使系統(tǒng)可獲得強(qiáng)大的查詢能力,Lucene的查詢實(shí)現(xiàn)中默認(rèn)實(shí)現(xiàn)了布爾操作、模糊查詢(Fuzzy Search[11])、分組查詢等等。
面對已經(jīng)存在的商業(yè)全文檢索引擎,Lucene也具有相當(dāng)?shù)膬?yōu)勢。
首先,它的開發(fā)源代碼發(fā)行方式(遵守Apache Software License[12]),在此基礎(chǔ)上程序員不僅僅可以充分的利用Lucene所提供的強(qiáng)大功能,而且可以深入細(xì)致的學(xué)習(xí)到全文檢索引擎制作技術(shù)和面向?qū)ο缶幊痰膶?shí)踐,進(jìn)而在此基礎(chǔ)上根據(jù)應(yīng)用的實(shí)際情況編寫出更好的更適合當(dāng)前應(yīng)用的全文檢索引擎。在這一點(diǎn)上,商業(yè)軟件的靈活性遠(yuǎn)遠(yuǎn)不及Lucene。
其次,Lucene秉承了開放源代碼一貫的架構(gòu)優(yōu)良的優(yōu)勢,設(shè)計(jì)了一個(gè)合理而極具擴(kuò)充能力的面向?qū)ο蠹軜?gòu),程序員可以在Lucene的基礎(chǔ)上擴(kuò)充各種功能,比如擴(kuò)充中文處理能力,從文本擴(kuò)充到HTML、PDF[13]等等文本格式的處理,編寫這些擴(kuò)展的功能不僅僅不復(fù)雜,而且由于Lucene恰當(dāng)合理的對系統(tǒng)設(shè)備做了程序上的抽象,擴(kuò)展的功能也能輕易的達(dá)到跨平臺的能力。
最后,轉(zhuǎn)移到apache軟件基金會(huì)后,借助于apache軟件基金會(huì)的網(wǎng)絡(luò)平臺,程序員可以方便的和開發(fā)者、其它程序員交流,促成資源的共享,甚至直接獲得已經(jīng)編寫完備的擴(kuò)充功能。最后,雖然Lucene使用Java語言寫成,但是開放源代碼社區(qū)的程序員正在不懈的將之使用各種傳統(tǒng)語言實(shí)現(xiàn)(例如.net framework[14]),在遵守Lucene索引文件格式的基礎(chǔ)上,使得Lucene能夠運(yùn)行在各種各樣的平臺上,系統(tǒng)管理員可以根據(jù)當(dāng)前的平臺適合的語言來合理的選擇。
?
1.3Lucene的缺點(diǎn)
1、Lucene 的內(nèi)建不支持群集。 Lucene是作為嵌入式的工具包的形式出現(xiàn)的,在核心代碼上沒有提供對群集的支持。實(shí)現(xiàn)對Lucene的群集有三種方式:1、繼承實(shí)現(xiàn)一個(gè) Directory;2、使用Solr 3、使用 Nutch+Hadoop;使用Solr你不得不用他的Index Server ,而使用Nutch你又不得不集成抓取的模塊;
2、區(qū)間范圍搜索速度非常緩慢; Lucene的區(qū)間范圍搜索,不是一開始就提供的是后來才加上的。對于在單個(gè)文檔中term出現(xiàn)比較多的情況,搜索速度會(huì)變得很慢。因此作者稱Lucene是一個(gè)高效的全文搜索引擎,其高效僅限于提供基本布爾查詢 boolean queries; 3、排序算法的實(shí)現(xiàn)不是可插拔的;
因?yàn)樨灤㎜ucene的排序算法的tf/idf 的實(shí)現(xiàn),盡管term是可以設(shè)置boost或者擴(kuò)展Lucene的Query類,但是對于復(fù)雜的排序算法定制還是有很大的局限性; 4、Lucene的結(jié)構(gòu)設(shè)計(jì)不好; Lucene的OO設(shè)計(jì)的非常糟,盡管有包package和類class,但是Lucene的設(shè)計(jì)基本上沒有設(shè)計(jì)模式的身影。這是不是c或者c++程序員寫java程序的通病? A、Lucene中沒有使用接口Interface,比如Query 類( BooleanQuery, SpanQuery, TermQuery...) 大都是從超類中繼承下來的; B、Lucene的迭代實(shí)現(xiàn)不自然: 沒有hasNext() 方法, next() 返回一個(gè)布爾值 boolean然后刷新對象的上下文; 5、封閉設(shè)計(jì)的API使得擴(kuò)展Lucene變得很困難; 參考第3點(diǎn); 6、Lucene的搜索算法不適用于網(wǎng)格計(jì)算;
?
1.4全文檢索
1.4.1數(shù)據(jù)分類
我們生活中的數(shù)據(jù)總體分為兩種:結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)。
結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長度的數(shù)據(jù),如數(shù)據(jù)庫,元數(shù)據(jù)等。
非結(jié)構(gòu)化數(shù)據(jù):指不定長或無固定格式的數(shù)據(jù),如郵件,word文檔等磁盤上的文件。
1.4.2結(jié)構(gòu)化數(shù)據(jù)搜索
常見的結(jié)構(gòu)化數(shù)據(jù)也就是數(shù)據(jù)庫中的數(shù)據(jù)。在數(shù)據(jù)庫中搜索很容易實(shí)現(xiàn),通常都是使用sql語句進(jìn)行查詢,而且能很快的得到查詢結(jié)果。
為什么數(shù)據(jù)庫搜索很容易?
因?yàn)閿?shù)據(jù)庫中的數(shù)據(jù)存儲是有規(guī)律的,有行有列而且數(shù)據(jù)格式、數(shù)據(jù)長度都是固定的。
1.4.3非結(jié)構(gòu)化數(shù)據(jù)搜索
(1)順序掃描法
所謂順序掃描,比如要找內(nèi)容包含某一個(gè)字符串的文件,就是一個(gè)文檔一個(gè)文檔的看,對于每一個(gè)文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的文件,接著看下一個(gè)文件,直到掃描完所有的文件。如利用windows的搜索也可以搜索文件內(nèi)容,只是相當(dāng)?shù)穆?/p>
(2)全文檢索
將非結(jié)構(gòu)化數(shù)據(jù)中的一部分信息提取出來,重新組織,使其變得有一定結(jié)構(gòu),然后對此有一定結(jié)構(gòu)的數(shù)據(jù)進(jìn)行搜索,從而達(dá)到搜索相對較快的目的。這部分從非結(jié)構(gòu)化數(shù)據(jù)中提取出的然后重新組織的信息,我們稱之索引。
例如:字典。字典的拼音表和部首檢字表就相當(dāng)于字典的索引,對每一個(gè)字的解釋是非結(jié)構(gòu)化的,如果字典沒有音節(jié)表和部首檢字表,在茫茫辭海中找一個(gè)字只能順序掃描。然而字的某些信息可以提取出來進(jìn)行結(jié)構(gòu)化處理,比如讀音,就比較結(jié)構(gòu)化,分聲母和韻母,分別只有幾種可以一一列舉,于是將讀音拿出來按一定的順序排列,每一項(xiàng)讀音都指向此字的詳細(xì)解釋的頁數(shù)。我們搜索時(shí)按結(jié)構(gòu)化的拼音搜到讀音,然后按其指向的頁數(shù),便可找到我們的非結(jié)構(gòu)化數(shù)據(jù)——也即對字的解釋。
這種先建立索引,再對索引進(jìn)行搜索的過程就叫全文檢索(Full-text Search)。
雖然創(chuàng)建索引的過程也是非常耗時(shí)的,但是索引一旦創(chuàng)建就可以多次使用,全文檢索主要處理的是查詢,所以耗時(shí)間創(chuàng)建索引是值得的。
?
1.4.4全文檢索應(yīng)用
對于數(shù)據(jù)量大、數(shù)據(jù)結(jié)構(gòu)不固定的數(shù)據(jù)可采用全文檢索方式搜索,比如百度、Google等搜索引擎、論壇站內(nèi)搜索、電商網(wǎng)站站內(nèi)搜索等。
?
?
二、Lucene的基本使用流程
2.1Lucene檢索過程
?
2.2獲取文檔
獲取原始內(nèi)容的目的是為了索引,在索引前需要將原始內(nèi)容創(chuàng)建成文檔(Document),文檔中包括一個(gè)一個(gè)的域(Field),域中存儲內(nèi)容。
這里我們可以將磁盤上的一個(gè)文件當(dāng)成一個(gè)document,Document中包括一些Field(file_name文件名稱、file_path文件路徑、file_size文件大小、file_content文件內(nèi)容),如下圖:
?
?注意:每個(gè)Document可以有多個(gè)Field,不同的Document可以有不同的Field,同一個(gè)Document可以有相同的Field(域名和域值都相同)
?
每個(gè)文檔都有一個(gè)唯一的編號,就是文檔id。
?
2.3分析文檔(分詞)
將原始內(nèi)容創(chuàng)建為包含域(Field)的文檔(document),需要再對域中的內(nèi)容進(jìn)行分析。
分析的過程:
原始文檔提取單詞、
將字母轉(zhuǎn)為小寫、
去除標(biāo)點(diǎn)符號、
去除停用詞
等過程生成最終的語匯單元,可以將語匯單元理解為一個(gè)一個(gè)的單詞。
比如下邊的文檔經(jīng)過分析如下:
原文檔內(nèi)容:
Lucene is a Java full-text search engine. Lucene is not a complete
application, but rather a code library and API that can easily be used
to add search capabilities to applications.
分析后得到的語匯單元:
lucene、java、full、search、engine。。。。
每個(gè)單詞叫做一個(gè)Term,不同的域中拆分出來的相同的單詞是不同的term。term中包含兩部分一部分是文檔的域名,另一部分是單詞的內(nèi)容。
例如:文件名中包含apache和文件內(nèi)容中包含的apache是不同的term。
?
2.4創(chuàng)建索引
注意:創(chuàng)建索引是對語匯單元索引,通過詞語找文檔,這種索引的結(jié)構(gòu)叫倒排索引結(jié)構(gòu)。
倒排索引結(jié)構(gòu)也叫反向索引結(jié)構(gòu),包括索引和文檔兩部分,索引即詞匯表,它的規(guī)模較小,而文檔集合較大。
傳統(tǒng)方法是根據(jù)文件找到該文件的內(nèi)容,在文件內(nèi)容中匹配搜索關(guān)鍵字,這種方法是順序掃描方法,數(shù)據(jù)量大、搜索慢。
倒排索引結(jié)構(gòu)是根據(jù)內(nèi)容(詞語)找文檔,如下圖:
?
?
2.5查詢索引
Lucene不提供制作用戶搜索界面的功能,需要根據(jù)自己的需求開發(fā)搜索界面。
搜索索引過程:
根據(jù)查詢語法在倒排索引詞典表中分別找出對應(yīng)搜索詞的索引,從而找到索引所鏈接的文檔鏈表。
比如搜索語法為“fileName:lucene”表示搜索出fileName域中包含Lucene的文檔。
搜索過程就是在索引上查找域?yàn)閒ileName,并且關(guān)鍵字為Lucene的term,并根據(jù)term找到文檔id列表。
?
三、Lucene具體實(shí)現(xiàn)
3.1下載
可以去官網(wǎng)下載:Lucene:https://lucene.apache.org/
?
?
3.2實(shí)際開發(fā)要使用的jar包
lucene-analyzers-common-8.2.0.jar
lucene-core-8.2.0.jar
lucene-queryparser-8.2.0.jar
?
3.3代碼實(shí)現(xiàn)
準(zhǔn)備好要搜索的原始文檔,本博主使用的是本機(jī):
?
?
?
import org.apache.commons.io.FileUtils; import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.search.*; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.RAMDirectory; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File;/*** 使用索引*/ public class TestLucene1 {@Test/*** 創(chuàng)建索引* @throws Exception*/public void createIndex() throws Exception{//1.創(chuàng)建一個(gè)目錄對象指定索引存放位置//把索引存放在內(nèi)存//Directory directory=new RAMDirectory();//把索引存放在硬盤上Directory directory= FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath());//2.基于Directory對象創(chuàng)建一個(gè)IndexWriter對象IndexWriterConfig indexWriterConfig=new IndexWriterConfig(new IKAnalyzer()); //指定使用哪種分析器IndexWriter indexWriter=new IndexWriter(directory,indexWriterConfig);//3.讀取硬盤上的文件,對應(yīng)每個(gè)文件創(chuàng)建一個(gè)文檔對象File fileDir=new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\Lucene\\02.參考資料\\searchsource");File[] files=fileDir.listFiles();for (File file:files) {//讀取文件名String fileName=file.getName();//讀取路徑String filePath=file.getPath();//讀取文件內(nèi)容String fileContent= FileUtils.readFileToString(file,"UTF-8");//讀取文件大小long fileSize=FileUtils.sizeOf(file);//創(chuàng)建Filed//參數(shù):域的名稱、域的內(nèi)容、是否存儲Field fieldName=new TextField("name",fileName,Field.Store.YES);//Field fieldPath=new TextField("path",filePath,Field.Store.YES);Field fieldPath=new StoredField("path",filePath); //默認(rèn)存儲Field fieldContent=new TextField("content",fileContent,Field.Store.YES);//Field fieldSize=new TextField("size",fileSize+"",Field.Store.YES);Field fieldSizeValue=new LongPoint("size",fileSize); //只是作為值使用Field fieldSizeStore=new StoredField("size",fileSize); //存儲//創(chuàng)建文檔對象Document document=new Document();//向文檔對象中添加域document.add(fieldName);document.add(fieldPath);document.add(fieldContent);document.add(fieldSizeValue);document.add(fieldSizeStore);//5.把文檔對象寫入索引庫indexWriter.addDocument(document);}//6.關(guān)閉IndexWriterindexWriter.close();}/*** 查詢索引* @throws Exception*/@Testpublic void searchIndex() throws Exception{//1.創(chuàng)建一個(gè)Directory對象,指定索引庫的位置Directory directory=FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath());//2.創(chuàng)建一個(gè)IndexReader對象IndexReader indexReader= DirectoryReader.open(directory);//3.創(chuàng)建一個(gè)IndexSearcher對象IndexSearcher indexSearcher=new IndexSearcher(indexReader);//4.創(chuàng)建一個(gè)Query對象Query query=new TermQuery(new Term("name","Lucene"));//5.執(zhí)行查詢得到一個(gè)TopDocs對象//參數(shù):查詢對象、返回最大記錄數(shù)TopDocs topDocs=indexSearcher.search(query,10);//6.取查詢結(jié)果總記錄數(shù)System.out.println("查詢結(jié)果總記錄數(shù):"+topDocs.totalHits);//7.取文檔列表ScoreDoc[] scoreDocs=topDocs.scoreDocs;//8.打印文檔內(nèi)容for (ScoreDoc doc:scoreDocs) {//獲取文檔IDint docId=doc.doc;//根據(jù)ID獲取文檔對象Document document=indexSearcher.doc(docId);System.out.println("文件名:"+document.get("name"));System.out.println("文件路徑:"+document.get("path"));System.out.println("文件大小:"+document.get("size"));System.out.println("文件內(nèi)容:"+document.get("content"));System.out.println("-------------------------");}indexReader.close();} }?
?
?
3.4使用Luke工具查看索引文件
?
?
?
3.5分析器
3.5.1標(biāo)準(zhǔn)分析器
StandardAnalyzer:
單字分詞:就是按照中文一個(gè)字一個(gè)字地進(jìn)行分詞。如:“我愛中國”, 效果:“我”、“愛”、“中”、“國”。
SmartChineseAnalyzer:
對中文支持較好,但擴(kuò)展性差,擴(kuò)展詞庫,禁用詞庫和同義詞庫等不好處理
3.5.2中文分析器
IKAnalyzer
使用方法:
第一步:把jar包添加到工程中
第二步:把配置文件和擴(kuò)展詞典和停用詞詞典添加到classpath下
?
注意:hotword.dic和ext_stopword.dic文件的格式為UTF-8,注意是無BOM 的UTF-8 編碼。
也就是說禁止使用windows記事本編輯擴(kuò)展詞典文件
?
?
代碼:
package com.xy;/*** 中文分析器*/import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;public class TestLucene2 {/*** 使用標(biāo)準(zhǔn)分析器* @throws Exception*/@Testpublic void testTokenStream() throws Exception{//1.創(chuàng)建一個(gè)Analyzer對象,使用它的子類StandardAnalyzer對象Analyzer analyzer=new StandardAnalyzer();//2.使用分析器的tokenStream方法,獲得一個(gè)TokenStream對象TokenStream tokenStream=analyzer.tokenStream("","Apache是世界使用排名第一的Web服務(wù)器軟件。它可以運(yùn)行在幾乎所有廣泛使用的計(jì)算機(jī)平臺上,由于其跨平臺和安全性被廣泛使用,是最流行的Web服務(wù)器端軟件之一。它快速、可靠并且可通過簡單的API擴(kuò)充,將Perl/Python等解釋器編譯到服務(wù)器中。同時(shí)Apache音譯為阿帕奇,是北美印第安人的一個(gè)部落,叫阿帕奇族,在美國的西南部。也是一個(gè)基金會(huì)的名稱、一種武裝直升機(jī)等等。");//3.向TokenStream對象中設(shè)置一個(gè)引用,相當(dāng)于一個(gè)指針CharTermAttribute charTermAttribute=tokenStream.addAttribute(CharTermAttribute.class);//4.調(diào)用TokenStream對象的reset方法,如果不調(diào)用會(huì)拋出異常tokenStream.reset();//5.使用while循環(huán)遍歷TokenStream對象while (tokenStream.incrementToken()){System.out.println(charTermAttribute.toString());}//6.關(guān)閉TokenStream對象tokenStream.close();}/*** 使用中文分析器* @throws Exception*/@Testpublic void testIkAnalyzer() throws Exception{//1.創(chuàng)建一個(gè)Analyzer對象,使用它的子類StandardAnalyzer對象Analyzer analyzer=new IKAnalyzer();//2.使用分析器的tokenStream方法,獲得一個(gè)TokenStream對象TokenStream tokenStream=analyzer.tokenStream("","Apache是世界使用排名第一的Web服務(wù)器軟件。它可以運(yùn)行在幾乎所有廣泛使用的計(jì)算機(jī)平臺上,由于其跨平臺和安全性被廣泛使用,是最流行的Web服務(wù)器端軟件之一。它快速、可靠并且可通過簡單的API擴(kuò)充,將Perl/Python等解釋器編譯到服務(wù)器中。同時(shí)Apache音譯為阿帕奇,是北美印第安人的一個(gè)部落,叫阿帕奇族,在美國的西南部。也是一個(gè)基金會(huì)的名稱、一種武裝直升機(jī)等等。");//3.向TokenStream對象中設(shè)置一個(gè)引用,相當(dāng)于一個(gè)指針CharTermAttribute charTermAttribute=tokenStream.addAttribute(CharTermAttribute.class);//4.調(diào)用TokenStream對象的reset方法,如果不調(diào)用會(huì)拋出異常tokenStream.reset();//5.使用while循環(huán)遍歷TokenStream對象while (tokenStream.incrementToken()){System.out.println(charTermAttribute.toString());}//6.關(guān)閉TokenStream對象tokenStream.close();} }3.6索引庫的維護(hù)(增刪改)
3.6.1Field域的屬性
是否分析:是否對域的內(nèi)容進(jìn)行分詞處理。前提是我們要對域的內(nèi)容進(jìn)行查詢。
是否索引:將Field分析后的詞或整個(gè)Field值進(jìn)行索引,只有索引方可搜索到。
比如:商品名稱、商品簡介分析后進(jìn)行索引,訂單號、身份證號不用分析但也要索引,這些將來都要作為查詢條件。
是否存儲:將Field值存儲在文檔中,存儲在文檔中的Field才可以從Document中獲取
比如:商品名稱、訂單號,凡是將來要從Document中獲取的Field都要存儲。
?
?
3.6.2添加文檔代碼
import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.FSDirectory; import org.junit.Before; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File; import java.io.IOException;/*** 維護(hù)索引*/ public class TestLucene3 {private IndexWriter indexWriter;private IndexReader indexReader;private IndexSearcher indexSearcher;@Beforepublic void init() throws IOException {indexReader= DirectoryReader.open(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()));indexSearcher=new IndexSearcher(indexReader);}/*** 聲明IndexWriter對象*/@Beforepublic void indexWriter() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));}/*** 添加文檔*/@Testpublic void addDocument() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器IndexWriter indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));//2.創(chuàng)建一個(gè)Document對象Document document=new Document();//3.向文檔中添加域document.add(new TextField("name","新添加的文件", Field.Store.YES));document.add(new TextField("content","新添加的文件內(nèi)容", Field.Store.NO));document.add(new StoredField("path","D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\temp"));//4.把文檔寫入索引庫indexWriter.addDocument(document);//5.關(guān)閉索引庫indexWriter.close();}}3.6.3刪除索引庫
package com.xy;import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.FSDirectory; import org.junit.Before; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File; import java.io.IOException;/*** 維護(hù)索引*/ public class TestLucene3 {private IndexWriter indexWriter;private IndexReader indexReader;private IndexSearcher indexSearcher;@Beforepublic void init() throws IOException {indexReader= DirectoryReader.open(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()));indexSearcher=new IndexSearcher(indexReader);}/*** 聲明IndexWriter對象*/@Beforepublic void indexWriter() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));}/*** 刪除文檔*/@Testpublic void deleteDocument() throws IOException {//刪除全部文檔indexWriter.deleteAll();//關(guān)閉索引庫indexWriter.close();}/*** 通過查詢刪除文檔* @throws IOException*/@Testpublic void deleteByQuery() throws IOException {indexWriter.deleteDocuments(new Term("name","Lucene"));}@Testpublic void updateDocument() throws IOException {//創(chuàng)建一個(gè)新的文檔對象Document document=new Document();//向文檔中添加域document.add(new TextField("name","更新之后的文檔",Field.Store.YES));document.add(new TextField("name1","更新之后的文檔2",Field.Store.YES));document.add(new TextField("name2","更新之后的文檔3",Field.Store.YES));//更新操作indexWriter.updateDocument(new Term("name","Lucene"),document);//關(guān)閉索引庫indexWriter.close();}private void printResults(Query query) throws IOException {//執(zhí)行查詢TopDocs topDocs=indexSearcher.search(query,10);System.out.println("總記錄數(shù):"+topDocs.totalHits);ScoreDoc[] scoreDocs=topDocs.scoreDocs;//打印文檔內(nèi)容for (ScoreDoc doc:scoreDocs) {//獲取文檔IDint docId=doc.doc;//根據(jù)ID獲取文檔對象Document document=indexSearcher.doc(docId);System.out.println("文件名:"+document.get("name"));System.out.println("文件路徑:"+document.get("path"));System.out.println("文件大小:"+document.get("size"));System.out.println("文件內(nèi)容:"+document.get("content"));System.out.println("-------------------------");}indexReader.close();}}3.6.4索引庫的修改
package com.xy;import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.FSDirectory; import org.junit.Before; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File; import java.io.IOException;/*** 維護(hù)索引*/ public class TestLucene3 {private IndexWriter indexWriter;private IndexReader indexReader;private IndexSearcher indexSearcher;@Beforepublic void init() throws IOException {indexReader= DirectoryReader.open(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()));indexSearcher=new IndexSearcher(indexReader);}/*** 聲明IndexWriter對象*/@Beforepublic void indexWriter() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));}@Testpublic void updateDocument() throws IOException {//創(chuàng)建一個(gè)新的文檔對象Document document=new Document();//向文檔中添加域document.add(new TextField("name","更新之后的文檔",Field.Store.YES));document.add(new TextField("name1","更新之后的文檔2",Field.Store.YES));document.add(new TextField("name2","更新之后的文檔3",Field.Store.YES));//更新操作indexWriter.updateDocument(new Term("name","Lucene"),document);//關(guān)閉索引庫indexWriter.close();}}3.6.5索引庫的查詢
對要搜索的信息創(chuàng)建Query查詢對象,Lucene會(huì)根據(jù)Query查詢對象生成最終的查詢語法,類似關(guān)系數(shù)據(jù)庫Sql語法一樣Lucene也有自己的查詢語法,比如:“name:lucene”表示查詢Field的name為“l(fā)ucene”的文檔信息。
可通過兩種方法創(chuàng)建查詢對象:
1)使用Lucene提供Query子類
2)使用QueryParse解析查詢表達(dá)式
?
1.TermQuery
TermQuery,通過項(xiàng)查詢,TermQuery不使用分析器所以建議匹配不分詞的Field域查詢,比如訂單號、分類ID號等。
指定要查詢的域和要查詢的關(guān)鍵詞。
?
2.數(shù)值范圍查詢
code:
package com.xy;import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.FSDirectory; import org.junit.Before; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File; import java.io.IOException;/*** 維護(hù)索引*/ public class TestLucene3 {private IndexWriter indexWriter;private IndexReader indexReader;private IndexSearcher indexSearcher;@Beforepublic void init() throws IOException {indexReader= DirectoryReader.open(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()));indexSearcher=new IndexSearcher(indexReader);}/*** 聲明IndexWriter對象*/@Beforepublic void indexWriter() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));}private void printResults(Query query) throws IOException {//執(zhí)行查詢TopDocs topDocs=indexSearcher.search(query,10);System.out.println("總記錄數(shù):"+topDocs.totalHits);ScoreDoc[] scoreDocs=topDocs.scoreDocs;//打印文檔內(nèi)容for (ScoreDoc doc:scoreDocs) {//獲取文檔IDint docId=doc.doc;//根據(jù)ID獲取文檔對象Document document=indexSearcher.doc(docId);System.out.println("文件名:"+document.get("name"));System.out.println("文件路徑:"+document.get("path"));System.out.println("文件大小:"+document.get("size"));System.out.println("文件內(nèi)容:"+document.get("content"));System.out.println("-------------------------");}indexReader.close();}/*** 測試查詢*/@Testpublic void searchDocument() throws IOException {//創(chuàng)建一個(gè)Query對象Query query= LongPoint.newRangeQuery("size",0l,10000l);//查詢結(jié)果printResults(query);}}?
3.QueryParser查詢
通過QueryParser也可以創(chuàng)建Query,QueryParser提供一個(gè)Parse方法,此方法可以直接根據(jù)查詢語法來查詢。Query對象執(zhí)行的查詢語法可通過System.out.println(query);查詢。
需要使用到分析器。建議創(chuàng)建索引時(shí)使用的分析器和查詢索引時(shí)使用的分析器要一致。
需要加入queryParser依賴的jar包。
lucene-queryparser-8.2.0.jar
code:
package com.xy;import org.apache.lucene.document.*; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.FSDirectory; import org.junit.Before; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.File; import java.io.IOException;/*** 維護(hù)索引*/ public class TestLucene3 {private IndexWriter indexWriter;private IndexReader indexReader;private IndexSearcher indexSearcher;@Beforepublic void init() throws IOException {indexReader= DirectoryReader.open(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()));indexSearcher=new IndexSearcher(indexReader);}/*** 聲明IndexWriter對象*/@Beforepublic void indexWriter() throws IOException {//1.創(chuàng)建一個(gè)IndexWriter對象,指定分析所用的分析器indexWriter=new IndexWriter(FSDirectory.open(new File("D:\\Java\\2018JavaEE傳智播客IDEA版\\階段4 1.Lucene\\index").toPath()),new IndexWriterConfig(new IKAnalyzer()));}private void printResults(Query query) throws IOException {//執(zhí)行查詢TopDocs topDocs=indexSearcher.search(query,10);System.out.println("總記錄數(shù):"+topDocs.totalHits);ScoreDoc[] scoreDocs=topDocs.scoreDocs;//打印文檔內(nèi)容for (ScoreDoc doc:scoreDocs) {//獲取文檔IDint docId=doc.doc;//根據(jù)ID獲取文檔對象Document document=indexSearcher.doc(docId);System.out.println("文件名:"+document.get("name"));System.out.println("文件路徑:"+document.get("path"));System.out.println("文件大小:"+document.get("size"));System.out.println("文件內(nèi)容:"+document.get("content"));System.out.println("-------------------------");}indexReader.close();}@Testpublic void searchDocumentByQueryParse() throws ParseException, IOException {//創(chuàng)建一個(gè)QueryParse對象//參數(shù):默認(rèn)搜索域、分析器對象QueryParser queryParser=new QueryParser("name",new IKAnalyzer());//使用后一個(gè)QueryParse對象創(chuàng)建一個(gè)Query對象Query query=queryParser.parse("Spring框架");//執(zhí)行查詢printResults(query);} }?
?
?
總結(jié)
以上是生活随笔為你收集整理的Lucene基本使用和代码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「Luogu5395」【模板】第二类斯特
- 下一篇: 07.MyBatis中的关联查询