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