Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎創建起完整的全文檢索引擎。Lucene是一套用於全文檢索和搜尋的開源程式庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程式接口,可以作全文索引和搜尋。在Java開發環境裏Lucene是一個成熟的免費開源工具。就其自己而言,Lucene是當前以及最近幾年最受歡迎的免費Java信息檢索程序庫。人們常常提到信息檢索程序庫,雖然與搜索引擎有關,但不該該將信息檢索程序庫與搜索引擎相混淆。java
說以前先說一說數據的分類: web
咱們生活中的數據整體分爲兩種:結構化數據和非結構化數據。算法
(1)結構化數據:指具備固定格式或有限長度的數據,如數據庫,元數據等。sql
(2)非結構化數據:指不定長或無固定格式的數據,如郵件,word文檔等磁盤上的文件數據庫
數據庫中的搜索很容易實現,一般都是使用sql語句進行查詢,並且能很快的獲得查詢結果。apache
爲何數據庫搜索很容易?windows
由於數據庫中的數據存儲是有規律的,有行有列並且數據格式、數據長度都是固定的。數組
(1)順序掃描法(Serial Scanning)網絡
所謂順序掃描,好比要找內容包含某一個字符串的文件,就是一個文檔一個文檔的看,對於每個文檔,從頭看到尾,若是此文檔包含此字符串,則此文檔爲咱們要找的文件,接着看下一個文件,直到掃描完全部的文件。如利用windows的搜索也能夠搜索文件內容,只是至關的慢。數據結構
(2)全文檢索(Full-text Search)
將非結構化數據中的一部分信息提取出來,從新組織,使其變得有必定結構,而後對此有必定結構的數據進行搜索,從而達到搜索相對較快的目的。這部分從非結構化數據中提取出的而後從新組織的信息,咱們稱之索引。
例如:字典。字典的拼音表和部首檢字表就至關於字典的索引,對每個字的解釋是非結構化的,若是字典沒有音節表和部首檢字表,在茫茫辭海中找一個字只能順序掃描。然而字的某些信息能夠提取出來進行結構化處理,好比讀音,就比較結構化,分聲母和韻母,分別只有幾種能夠一一列舉,因而將讀音拿出來按必定的順序排列,每一項讀音都指向此字的詳細解釋的頁數。咱們搜索時按結構化的拼音搜到讀音,而後按其指向的頁數,即可找到咱們的非結構化數據——也即對字的解釋。
這種先創建索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。
雖然建立索引的過程也是很是耗時的,可是索引一旦建立就能夠屢次使用,全文檢索主要處理的是查詢,因此耗時間建立索引是值得的。
對於數據量大、數據結構不固定的數據可採用全文檢索方式搜索,好比百度、Google等搜索引擎、論壇站內搜索、電商網站站內搜索等。
一、綠色表示索引過程,對要搜索的原始內容進行索引構建一個索引庫,索引過程包括:
肯定原始內容即要搜索的內容→採集文檔→建立文檔→分析文檔→索引文檔
二、紅色表示搜索過程,從索引庫中搜索內容,搜索過程包括:
用戶經過搜索界面→建立查詢→執行搜索,從索引庫搜索→渲染搜索結果
接下來詳細講解一下這張圖片:
對文檔索引的過程,將用戶要搜索的文檔內容進行索引,索引存儲在索引庫(index)中。
這裏咱們要搜索的文檔是磁盤上的文本文件,根據案例描述:凡是文件名或文件內容包括關鍵字的文件都要找出來,這裏要對文件名和文件內容建立索引。
原始文檔是指要索引和搜索的內容。原始內容包括互聯網上的網頁、數據庫中的數據、磁盤上的文件等。
從互聯網上、數據庫、文件系統中等獲取須要搜索的原始信息,這個過程就是信息採集,信息採集的目的是爲了對原始內容進行索引。在Internet上採集信息的軟件一般稱爲爬蟲或蜘蛛,也稱爲網絡機器人,爬蟲訪問互聯網上的每個網頁,將獲取到的網頁內容存儲起來。
Lucene不提供信息採集的類庫,須要本身編寫一個爬蟲程序實現信息採集,也能夠經過一些開源軟件實現信息採集,以下:
(1)Nutch(http://lucene.apache.org/nutch), Nutch是apache的一個子項目,包括大規模爬蟲工具,可以抓取和分辨web網站數據。
(2)jsoup(http://jsoup.org/ ),jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套很是省力的API,可經過DOM,CSS以及相似於jQuery的操做方法來取出和操做數據。
(3)heritrix(http://sourceforge.net/projects/archive-crawler/files/),Heritrix 是一個由 java 開發的、開源的網絡爬蟲,用戶可使用它來從網上抓取想要的資源。其最出色之處在於它良好的可擴展性,方便用戶實現本身的抓取邏輯。
本案例咱們要獲取磁盤上文件的內容,能夠經過文件流來讀取文本文件的內容,對於pdf、doc、xls等文件可經過第三方提供的解析工具讀取文件內容,好比Apache POI讀取doc和xls的文件內容。
獲取原始內容的目的是爲了索引,在索引前須要將原始內容建立成文檔(Document),文檔中包括一個一個的域(Field),域中存儲內容。
這裏咱們能夠將磁盤上的一個文件當成一個document,Document中包括一些Field(file_name文件名稱、file_path文件路徑、file_size文件大小、file_content文件內容),以下圖:
注意:(1)每一個Document能夠有多個Field
(2)不一樣的Document能夠有不一樣的Field
(3)同一個Document能夠有相同的Field(域名和域值都相同)
(4)每一個文檔都有一個惟一的編號,就是文檔id。
將原始內容建立爲包含域(Field)的文檔(document),須要再對域中的內容進行分析,分析的過程是通過對原始文檔提取單詞、將字母轉爲小寫、去除標點符號、去除停用詞等過程生成最終的語彙單元,能夠將語彙單元理解爲一個一個的單詞。
好比下邊的文檔通過分析以下:
原文檔內容:
Lucene is a Java full-text search engine.
分析後獲得的語彙單元:
lucene、java、full、search、engine
每一個單詞叫作一個Term,不一樣的域中拆分出來的相同的單詞是不一樣的term。term中包含兩部分一部分是文檔的域名,另外一部分是單詞的內容。
例如:文件名中包含apache和文件內容中包含的apache是不一樣的term。
對全部文檔分析得出的語彙單元進行索引,索引的目的是爲了搜索,最終要實現只搜索被索引的語彙單元從而找到Document(文檔)。
注意:(1)建立索引是對語彙單元索引,經過詞語找文檔,這種索引的結構叫倒排索引結構。
(2)傳統方法是根據文件找到該文件的內容,在文件內容中匹配搜索關鍵字,這種方法是順序掃描方法,數據量大、搜索慢。
(3)倒排索引結構是根據內容(詞語)找文檔,以下圖:
倒排索引結構也叫反向索引結構,包括索引和文檔兩部分,索引即詞彙表,它的規模較小,而文檔集合較大。
建立索引代碼實例:
新建一個Java工程,導入相關的jar包
編寫建立索引代碼
使用indexwriter對象建立索引
具體步驟:
第一步:建立一個indexwriter對象。
1)指定索引庫的存放位置Directory對象
2)指定一個分析器,對文檔內容進行分析。
第二步:建立document對象。
第三步:建立field對象,將field添加到document對象中。
第四步:使用indexwriter對象將document對象寫入索引庫,此過程進行索引建立。並將索引和document對象寫入索引庫。
第五步:關閉IndexWriter對象。
1 //建立索引 2 public void testCreateIndex() throws IOException{ 3 //指定索引庫的存放位置Directory對象 4 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); 5 //索引庫還能夠存放到內存中 6 //Directory directory = new RAMDirectory(); 7 8 //指定一個標準分析器,對文檔內容進行分析 9 Analyzer analyzer = new StandardAnalyzer(); 10 11 //建立indexwriterCofig對象 12 //第一個參數: Lucene的版本信息,能夠選擇對應的lucene版本也可使用LATEST 13 //第二根參數:分析器對象 14 IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); 15 16 //建立一個indexwriter對象 17 IndexWriter indexWriter = new IndexWriter(directory, config); 18 19 //原始文檔的路徑 20 File file = new File("E:\\programme\\searchsource"); 21 File[] fileList = file.listFiles(); 22 for (File file2 : fileList) { 23 //建立document對象 24 Document document = new Document(); 25 26 //建立field對象,將field添加到document對象中 27 28 //文件名稱 29 String fileName = file2.getName(); 30 //建立文件名域 31 //第一個參數:域的名稱 32 //第二個參數:域的內容 33 //第三個參數:是否存儲 34 Field fileNameField = new TextField("fileName", fileName, Store.YES); 35 36 //文件的大小 37 long fileSize = FileUtils.sizeOf(file2); 38 //文件大小域 39 Field fileSizeField = new LongField("fileSize", fileSize, Store.YES); 40 41 //文件路徑 42 String filePath = file2.getPath(); 43 //文件路徑域(不分析、不索引、只存儲) 44 Field filePathField = new StoredField("filePath", filePath); 45 46 //文件內容 47 String fileContent = FileUtils.readFileToString(file2); 48 //String fileContent = FileUtils.readFileToString(file2, "utf-8"); 49 //文件內容域 50 Field fileContentField = new TextField("fileContent", fileContent, Store.YES); 51 52 document.add(fileNameField); 53 document.add(fileSizeField); 54 document.add(filePathField); 55 document.add(fileContentField); 56 //使用indexwriter對象將document對象寫入索引庫,此過程進行索引建立。並將索引和document對象寫入索引庫。 57 indexWriter.addDocument(document); 58 } 59 //關閉IndexWriter對象。 60 indexWriter.close(); 61 }
是否分析:是否對域的內容進行分詞處理。前提是咱們要對域的內容進行查詢。
是否索引:將Field分析後的詞或整個Field值進行索引,只有索引方可搜索到。
好比:商品名稱、商品簡介分析後進行索引,訂單號、身份證號不用分析但也要索引,這些未來都要做爲查詢條件。
是否存儲:將Field值存儲在文檔中,存儲在文檔中的Field才能夠從Document中獲取
好比:商品名稱、訂單號,凡是未來要從Document中獲取的Field都要存儲。
是否存儲的標準:是否要將內容展現給用戶
Field類 |
數據類型 |
Analyzed 是否分析 |
Indexed 是否索引 |
Stored 是否存儲 |
說明 |
StringField(FieldName, FieldValue,Store.YES)) |
字符串 |
N |
Y |
Y或N |
這個Field用來構建一個字符串Field,可是不會進行分析,會將整個串存儲在索引中,好比(訂單號,姓名等) 是否存儲在文檔中用Store.YES或Store.NO決定 |
LongField(FieldName, FieldValue,Store.YES) |
Long型 |
Y |
Y |
Y或N |
這個Field用來構建一個Long數字型Field,進行分析和索引,好比(價格) 是否存儲在文檔中用Store.YES或Store.NO決定 |
StoredField(FieldName, FieldValue) |
重載方法,支持多種類型 |
N |
N |
Y |
這個Field用來構建不一樣類型Field 不分析,不索引,但要Field存儲在文檔中 |
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName, reader)
|
字符串 或 流 |
Y |
Y |
Y或N |
若是是一個Reader, lucene猜想內容比較多,會採用Unstored的策略. |
查詢索引也是搜索的過程。搜索就是用戶輸入關鍵字,從索引(index)中進行搜索的過程。根據關鍵字搜索索引,根據索引找到對應的文檔,從而找到要搜索的內容(這裏指磁盤上的文件)。
對要搜索的信息建立Query查詢對象,Lucene會根據Query查詢對象生成最終的查詢語法,相似關係數據庫Sql語法同樣Lucene也有本身的查詢語法,好比:「name:lucene」表示查詢Field的name爲「lucene」的文檔信息。
全文檢索系統提供用戶搜索的界面供用戶提交搜索的關鍵字,搜索完成展現搜索結果。
好比: 百度搜索
Lucene不提供製做用戶搜索界面的功能,須要根據本身的需求開發搜索界面。
用戶輸入查詢關鍵字執行搜索以前須要先構建一個查詢對象,查詢對象中能夠指定查詢要搜索的Field文檔域、查詢關鍵字等,查詢對象會生成具體的查詢語法,
例如: 語法 「fileName:lucene」表示要搜索Field域的內容爲「lucene」的文檔
搜索索引過程:
根據查詢語法在倒排索引詞典表中分別找出對應搜索詞的索引,從而找到索引所連接的文檔鏈表。
好比搜索語法爲「fileName:lucene」表示搜索出fileName域中包含Lucene的文檔。
搜索過程就是在索引上查找域爲fileName,而且關鍵字爲Lucene的term,並根據term找到文檔id列表。
可經過兩種方法建立查詢對象:
1)使用Lucene提供Query子類
Query是一個抽象類,lucene提供了不少查詢對象,好比TermQuery項精確查詢,NumericRangeQuery數字範圍查詢等。
以下代碼:
Query query = new TermQuery(new Term("name", "lucene"));
2)使用QueryParse解析查詢表達式
QueryParse會將用戶輸入的查詢表達式解析成Query對象實例。
以下代碼:
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
Query query = queryParser.parse("name:lucene");
首先,演示第一種方法,使用query的子類查詢
實現步驟
第一步:建立一個Directory對象,也就是索引庫存放的位置。
第二步:建立一個indexReader對象,須要指定Directory對象。
第三步:建立一個indexsearcher對象,須要指定IndexReader對象
第四步:建立一個Query的子類對象,指定查詢的域和查詢的關鍵詞。
第五步:執行查詢。
第六步:返回查詢結果。遍歷查詢結果並輸出。
第七步:關閉IndexReader對象
使用MatchAllDocsQuery查詢索引目錄中的全部文檔
具體代碼:
@Test public void testMatchAllDocsQuery() throws Exception { //建立一個Directory對象,指定索引庫存放的路徑 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); //建立IndexReader對象,須要指定Directory對象 IndexReader indexReader = DirectoryReader.open(directory); //建立Indexsearcher對象,須要指定IndexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立查詢條件 //使用MatchAllDocsQuery查詢索引目錄中的全部文檔 Query query = new MatchAllDocsQuery(); //執行查詢 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 TopDocs topDocs = indexSearcher.search(query, 10); //查詢結果的總條數 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); //遍歷查詢結果 //topDocs.scoreDocs存儲了document對象的id //ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //scoreDoc.doc屬性就是document對象的id //int doc = scoreDoc.doc; //根據document的id找到document對象 Document document = indexSearcher.doc(scoreDoc.doc); //文件名稱 System.out.println(document.get("fileName")); //文件內容 System.out.println(document.get("fileContent")); //文件大小 System.out.println(document.get("fileSize")); //文件路徑 System.out.println(document.get("filePath")); System.out.println("----------------------------------"); } //關閉indexreader對象 indexReader.close(); }
TermQuery,經過項查詢,TermQuery不使用分析器因此建議匹配不分詞的Field域查詢,好比訂單號、分類ID號等。
指定要查詢的域和要查詢的關鍵詞。
具體代碼:
1 //搜索索引 2 @Test 3 public void testSearchIndex() throws IOException{ 4 //建立一個Directory對象,指定索引庫存放的路徑 5 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); 6 //建立IndexReader對象,須要指定Directory對象 7 IndexReader indexReader = DirectoryReader.open(directory); 8 //建立Indexsearcher對象,須要指定IndexReader對象 9 IndexSearcher indexSearcher = new IndexSearcher(indexReader); 10 //建立一個TermQuery(精準查詢)對象,指定查詢的域與查詢的關鍵詞 11 //建立查詢 12 Query query = new TermQuery(new Term("fileName", "apache")); 13 //執行查詢 14 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 15 TopDocs topDocs = indexSearcher.search(query, 10); 16 //查詢結果的總條數 17 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); 18 //遍歷查詢結果 19 //topDocs.scoreDocs存儲了document對象的id 20 //ScoreDoc[] scoreDocs = topDocs.scoreDocs; 21 for (ScoreDoc scoreDoc : topDocs.scoreDocs) { 22 //scoreDoc.doc屬性就是document對象的id 23 //int doc = scoreDoc.doc; 24 //根據document的id找到document對象 25 Document document = indexSearcher.doc(scoreDoc.doc); 26 //文件名稱 27 System.out.println(document.get("fileName")); 28 //文件內容 29 System.out.println(document.get("fileContent")); 30 //文件大小 31 System.out.println(document.get("fileSize")); 32 //文件路徑 33 System.out.println(document.get("filePath")); 34 System.out.println("----------------------------------"); 35 } 36 //關閉indexreader對象 37 indexReader.close(); 38 } 39 }
能夠根據數值範圍查詢。
具體代碼:
//數值範圍查詢 @Test public void testNumericRangeQuery() throws Exception { //建立一個Directory對象,指定索引庫存放的路徑 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); //建立IndexReader對象,須要指定Directory對象 IndexReader indexReader = DirectoryReader.open(directory); //建立Indexsearcher對象,須要指定IndexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立查詢 //參數: //1.域名 //2.最小值 //3.最大值 //4.是否包含最小值 //5.是否包含最大值 Query query = NumericRangeQuery.newLongRange("fileSize", 41L, 2055L, true, true); //執行查詢 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 TopDocs topDocs = indexSearcher.search(query, 10); //查詢結果的總條數 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); //遍歷查詢結果 //topDocs.scoreDocs存儲了document對象的id //ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //scoreDoc.doc屬性就是document對象的id //int doc = scoreDoc.doc; //根據document的id找到document對象 Document document = indexSearcher.doc(scoreDoc.doc); //文件名稱 System.out.println(document.get("fileName")); //文件內容 System.out.println(document.get("fileContent")); //文件大小 System.out.println(document.get("fileSize")); //文件路徑 System.out.println(document.get("filePath")); System.out.println("----------------------------------"); } //關閉indexreader對象 indexReader.close(); }
能夠組合查詢條件。
具體代碼:
//組合條件查詢 @Test public void testBooleanQuery() throws Exception { //建立一個Directory對象,指定索引庫存放的路徑 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); //建立IndexReader對象,須要指定Directory對象 IndexReader indexReader = DirectoryReader.open(directory); //建立Indexsearcher對象,須要指定IndexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一個布爾查詢對象 BooleanQuery query = new BooleanQuery(); //建立第一個查詢條件 Query query1 = new TermQuery(new Term("fileName", "apache")); Query query2 = new TermQuery(new Term("fileName", "lucene")); //組合查詢條件 query.add(query1, Occur.MUST); query.add(query2, Occur.MUST); //執行查詢 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 TopDocs topDocs = indexSearcher.search(query, 10); //查詢結果的總條數 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); //遍歷查詢結果 //topDocs.scoreDocs存儲了document對象的id //ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //scoreDoc.doc屬性就是document對象的id //int doc = scoreDoc.doc; //根據document的id找到document對象 Document document = indexSearcher.doc(scoreDoc.doc); //文件名稱 System.out.println(document.get("fileName")); //文件內容 System.out.println(document.get("fileContent")); //文件大小 System.out.println(document.get("fileSize")); //文件路徑 System.out.println(document.get("filePath")); System.out.println("----------------------------------"); } //關閉indexreader對象 indexReader.close(); }
Occur.MUST:必須知足此條件,至關於and
Occur.SHOULD:應該知足,可是不知足也能夠,至關於or
Occur.MUST_NOT:必須不知足。至關於not
接着,演示第二種方法:使用queryparser查詢
經過QueryParser也能夠建立Query,QueryParser提供一個Parse方法,此方法能夠直接根據查詢語法來查詢。Query對象執行的查詢語法可經過System.out.println(query);查詢。
這個操做須要使用到分析器。建議建立索引時使用的分析器和查詢索引時使用的分析器要一致。
queryparser
具體代碼:
@Test public void testQueryParser() throws Exception { //建立一個Directory對象,指定索引庫存放的路徑 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); //建立IndexReader對象,須要指定Directory對象 IndexReader indexReader = DirectoryReader.open(directory); //建立Indexsearcher對象,須要指定IndexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立queryparser對象 //第一個參數默認搜索的域 //第二個參數就是分析器對象 QueryParser queryParser = new QueryParser("fileName", new IKAnalyzer()); //使用默認的域,這裏用的是語法,下面會詳細講解一下 Query query = queryParser.parse("apache"); //不使用默認的域,能夠本身指定域 //Query query = queryParser.parse("fileContent:apache"); //執行查詢 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 TopDocs topDocs = indexSearcher.search(query, 10); //查詢結果的總條數 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); //遍歷查詢結果 //topDocs.scoreDocs存儲了document對象的id //ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //scoreDoc.doc屬性就是document對象的id //int doc = scoreDoc.doc; //根據document的id找到document對象 Document document = indexSearcher.doc(scoreDoc.doc); //文件名稱 System.out.println(document.get("fileName")); //文件內容 System.out.println(document.get("fileContent")); //文件大小 System.out.println(document.get("fileSize")); //文件路徑 System.out.println(document.get("filePath")); System.out.println("----------------------------------"); } //關閉indexreader對象 indexReader.close(); }
一、基礎的查詢語法,關鍵詞查詢:
域名+「:」+搜索的關鍵字
例如:content:java
二、範圍查詢
域名+「:」+[最小值 TO 最大值]
例如:size:[1 TO 1000]
範圍查詢在lucene中支持數值類型,不支持字符串類型。在solr中支持字符串類型。
三、組合條件查詢
1)+條件1 +條件2:兩個條件之間是而且的關係and
例如:+filename:apache +content:apache
2)+條件1 條件2:必須知足第一個條件,應該知足第二個條件
例如:+filename:apache content:apache
3)條件1 條件2:兩個條件知足其一便可。
例如:filename:apache content:apache
4)-條件1 條件2:必須不知足條件1,要知足條件2
例如:-filename:apache content:apache
Occur.MUST 查詢條件必須知足,至關於and |
+(加號) |
Occur.SHOULD 查詢條件可選,至關於or |
空(不用符號) |
Occur.MUST_NOT 查詢條件不能知足,至關於not非 |
-(減號) |
第二種寫法:
條件1 AND 條件2
條件1 OR 條件2
條件1 NOT 條件2
能夠指定多個默認搜索域
具體代碼:
1 @Test 2 public void testMultiFiledQueryParser() throws Exception { 3 //建立一個Directory對象,指定索引庫存放的路徑 4 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); 5 //建立IndexReader對象,須要指定Directory對象 6 IndexReader indexReader = DirectoryReader.open(directory); 7 //建立Indexsearcher對象,須要指定IndexReader對象 8 IndexSearcher indexSearcher = new IndexSearcher(indexReader); 9 10 //能夠指定默認搜索的域是多個 11 String[] fields = {"fileName", "fileContent"}; 12 //建立一個MulitFiledQueryParser對象 13 MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer()); 14 Query query = queryParser.parse("apache"); 15 System.out.println(query); 16 //執行查詢 17 18 19 //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值 20 TopDocs topDocs = indexSearcher.search(query, 10); 21 22 //查詢結果的總條數 23 System.out.println("查詢結果的總條數:"+ topDocs.totalHits); 24 //遍歷查詢結果 25 //topDocs.scoreDocs存儲了document對象的id 26 //ScoreDoc[] scoreDocs = topDocs.scoreDocs; 27 for (ScoreDoc scoreDoc : topDocs.scoreDocs) { 28 //scoreDoc.doc屬性就是document對象的id 29 //int doc = scoreDoc.doc; 30 //根據document的id找到document對象 31 Document document = indexSearcher.doc(scoreDoc.doc); 32 //文件名稱 33 System.out.println(document.get("fileName")); 34 //文件內容 35 System.out.println(document.get("fileContent")); 36 //文件大小 37 System.out.println(document.get("fileSize")); 38 //文件路徑 39 System.out.println(document.get("filePath")); 40 System.out.println("----------------------------------"); 41 } 42 //關閉indexreader對象 43 indexReader.close(); 44 }
方法 |
說明 |
indexSearcher.search(query, n) |
根據Query搜索,返回評分最高的n條記錄 |
indexSearcher.search(query, filter, n) |
根據Query搜索,添加過濾策略,返回評分最高的n條記錄 |
indexSearcher.search(query, n, sort) |
根據Query搜索,添加排序策略,返回評分最高的n條記錄 |
indexSearcher.search(booleanQuery, filter, n, sort) |
根據Query搜索,添加過濾策略,添加排序策略,返回評分最高的n條記錄 |
Lucene搜索結果可經過TopDocs遍歷,TopDocs類提供了少許的屬性,以下:
方法或屬性 |
說明 |
totalHits |
匹配搜索條件的總記錄數 |
scoreDocs |
頂部匹配記錄 |
注意:
(1)Search方法須要指定匹配記錄數量n:indexSearcher.search(query, n)
(2)TopDocs.totalHits:是匹配索引庫中全部記錄的數量
(3)TopDocs.scoreDocs:匹配相關度高的前邊記錄數組,scoreDocs的長度小於等於search方法指定的參數n
中文分詞器 :
首先,看一看Lucene自帶的中文分詞器
(1)StandardAnalyzer:(標準分詞器,也是前面例子中使用的分詞器)
單字分詞:就是按照中文一個字一個字地進行分詞。
如:「我愛中國」,
效果:「我」、「愛」、「中」、「國」。
(2)CJKAnalyzer
二分法分詞:按兩個字進行切分。
如:「我是中國人」,
效果:「我是」、「是中」、「中國」「國人」。
但上邊兩個分詞器沒法知足需求。
(3)SmartChineseAnalyzer
對中文支持較好,但擴展性差,擴展詞庫,禁用詞庫和同義詞庫等很差處理
而後,看一看咱們開發真正使用的第三方中文分詞器:
咱們今天介紹IK-analyzer這款第三方中文分詞器
IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10從2006年12月推出1.0版開始, IKAnalyzer已經推出了4個大版本。最初,它是以開源項目Luence爲應用主體的,結合詞典分詞和文法分析算法的中文分詞組件。從3.0版本開 始,IK發展爲面向Java的公用分詞組件,獨立於Lucene項目,同時提供了對Lucene的默認優化實現。在2012版本中,IK實現了簡單的分詞 歧義排除算法,標誌着IK分詞器從單純的詞典分詞向模擬語義分詞衍化。 可是也就是2012年12月後沒有在更新。
使用方法:
第一步:把jar包添加到工程中
第二步:把配置文件和擴展詞詞典和停用詞詞典添加到classpath下(停用詞詞典與擴展詞詞典名稱可自行定義,只要在配置文件中配置好就能夠了)
注意:擴展詞詞典和停用詞詞典文件的格式爲UTF-8,注意是無BOM 的UTF-8 編碼。
配置文件詳情
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 擴展配置</comment> <!--用戶能夠在這裏配置本身的擴展字典 --> <entry key="ext_dict">ext.dic;</entry> <!--用戶能夠在這裏配置本身的擴展中止詞字典--> <entry key="ext_stopwords">stopword.dic;</entry> </properties>
停用詞詞典與擴展詞詞典樣例:
這樣,建立分析器時,用一下代碼就行了
Analyzer analyzer = new IKAnalyzer();
注意:搜索使用的分析器要和索引使用的分析器一致,否則搜索出來結果可能會錯亂。
(1)刪除所有索引
說明:將索引目錄的索引信息所有刪除,直接完全刪除,沒法恢復。此方法慎用!!
1 //刪除所有索引 2 @Test 3 public void testDeleteAllIndex() throws Exception { 4 Directory directory = FSDirectory.open(new File("E:\\programme\\test")); 5 Analyzer analyzer = new IKAnalyzer(); 6 IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); 7 IndexWriter indexWriter = new IndexWriter(directory, config); 8 //刪除所有索引 9 indexWriter.deleteAll(); 10 //關閉indexwriter 11 indexWriter.close(); 12 }
(2)指定查詢條件刪除
//根據查詢條件刪除索引 @Test public void deleteIndexByQuery() throws Exception { Directory directory = FSDirectory.open(new File("E:\\programme\\test")); Analyzer analyzer = new IKAnalyzer(); IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); IndexWriter indexWriter = new IndexWriter(directory, config); //建立一個查詢條件 Query query = new TermQuery(new Term("fileContent", "apache")); //根據查詢條件刪除 indexWriter.deleteDocuments(query); //關閉indexwriter indexWriter.close(); }
更新的原理就是先刪除在添加
//修改索引庫 @Test public void updateIndex() throws Exception { Directory directory = FSDirectory.open(new File("E:\\programme\\test")); Analyzer analyzer = new IKAnalyzer(); IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); IndexWriter indexWriter = new IndexWriter(directory, config); //建立一個Document對象 Document document = new Document(); //向document對象中添加域。 //不一樣的document能夠有不一樣的域,同一個document能夠有相同的域。 document.add(new TextField("fileXXX", "要更新的文檔", Store.YES)); document.add(new TextField("contentYYY", "簡介 Lucene 是一個基於 Java 的全文信息檢索工具包。", Store.YES)); indexWriter.updateDocument(new Term("fileName", "apache"), document); //關閉indexWriter indexWriter.close(); }
這樣,Lucene的簡單介紹使用就完成了。