Lucene入門


參考文檔

一:什么是全文檢索

數據分類

結構化數據:有固定的格式和有限的長度,比如Oracle和mysql數據庫中的數據,可以利用sql語句查詢,如果查詢的數據量大時,可以在數據庫中創建索引,但是此時不支持模糊查詢

非結構化數據:沒有固定的的格式和長度,比如磁盤上的文件如txt,pdf等,順序掃描法(Serial Scanning),全文檢索(Full-text Search)

對數據源創建索引,在索引庫中搜索

二:如何實現全文檢索

使用Lucene

三:什么是Lucene

Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包

四:Lucene實現流程

獲得文檔對象:

應用場景:站內搜索,通過IO流

構建文檔對象:

 獲取原始內容的目的是為了索引,在索引前需要將原始內容創建成文檔(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。

創建索引:

根據不同的term找到對應的Document

 注意:   (1)創建索引是對語匯單元索引,通過詞語找文檔,這種索引的結構叫倒排索引結構

     (2)傳統方法是根據文件找到該文件的內容,在文件內容中匹配搜索關鍵字,這種方法是順序掃描方法,數據量大、搜索慢。

用戶查詢接口:

搜索框輸入關鍵字

五:入門案例

導入相關jar包

IndexWriterTest.java

 1 package com.it.lucene;
 2 
 3 import java.io.File;
 4 import java.io.IOException;
 5 
 6 import org.apache.commons.io.FileUtils;
 7 import org.apache.lucene.analysis.Analyzer;
 8 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 9 import org.apache.lucene.document.Document;
10 import org.apache.lucene.document.Field;
11 import org.apache.lucene.document.Field.Store;
12 import org.apache.lucene.document.TextField;
13 import org.apache.lucene.index.IndexWriter;
14 import org.apache.lucene.index.IndexWriterConfig;
15 import org.apache.lucene.store.Directory;
16 import org.apache.lucene.store.FSDirectory;
17 
18 public class lucene_first {
19     public static void main(String[] args) throws Exception {
20         //1,指定索引庫位置
21         Directory directory =FSDirectory.open(new File("D:\\BaiduNetdiskDownload\\lucene\\indexDatebase").toPath());
22         //指定分詞器
23         Analyzer analyzer=new StandardAnalyzer();
24         IndexWriterConfig config=new IndexWriterConfig(analyzer);
25         
26         //2,創建寫入索引的對象
27         IndexWriter indexWriter=new IndexWriter(directory, config);
28         
29         //3獲取原文檔
30         File scrFile=new File("D:\\BaiduNetdiskDownload\\lucene\\searchSource");
31         //遍歷
32         File[] listFiles = scrFile.listFiles();
33         for (File file : listFiles) {
34             Document doc=new Document();
35             //將域寫入到文檔中
36             //1),文件名稱
37             String name = file.getName();
38             Field fileName=new TextField("name",name, Store.YES);
39             doc.add(fileName);
40             //2),文件大小
41             long size = FileUtils.sizeOf(file);
42             Field fileSize=new TextField("size",size+"", Store.YES);
43             doc.add(fileSize);
44             //3),文件路徑
45             String path = file.getPath();
46             Field filePath=new TextField("path",path+"", Store.YES);
47             doc.add(filePath);
48             //4),文件內容
49             String content = FileUtils.readFileToString(file);
50             Field fileContent=new TextField("content",content, Store.YES);
51             doc.add(fileContent);
52             
53             //4,將文檔寫入索引庫
54             indexWriter.addDocument(doc);
55         }
56         //5關閉資源
57         indexWriter.close();
58     }
59 }

 

運行程序后,在索引庫中可以查看到索引文件,通過luke可視化工具查看到

IndexReaderTest.java 

 

 1 package com.it.lucene;
 2 
 3 import java.io.File;
 4 import java.io.IOException;
 5 
 6 import org.apache.commons.io.FileUtils;
 7 import org.apache.lucene.analysis.Analyzer;
 8 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 9 import org.apache.lucene.document.Document;
10 import org.apache.lucene.document.Field;
11 import org.apache.lucene.document.Field.Store;
12 import org.apache.lucene.document.TextField;
13 import org.apache.lucene.index.DirectoryReader;
14 import org.apache.lucene.index.IndexReader;
15 import org.apache.lucene.index.IndexWriter;
16 import org.apache.lucene.index.IndexWriterConfig;
17 import org.apache.lucene.index.Term;
18 import org.apache.lucene.search.IndexSearcher;
19 import org.apache.lucene.search.Query;
20 import org.apache.lucene.search.ScoreDoc;
21 import org.apache.lucene.search.TermQuery;
22 import org.apache.lucene.search.TopDocs;
23 import org.apache.lucene.store.Directory;
24 import org.apache.lucene.store.FSDirectory;
25 
26 public class IndexReaderTest {
27     public static void main(String[] args) throws Exception {
28         //1,指定索引庫位置
29         Directory directory =FSDirectory.open(new File("D:\\BaiduNetdiskDownload\\lucene\\indexDatebase").toPath());
30         //2,創建索引讀取對象
31         IndexReader indexReader=DirectoryReader.open(directory);
32         //3,創建索引查詢對象
33         IndexSearcher indexSearcher=new IndexSearcher(indexReader);
34         //4,查詢條件
35         Query query=new TermQuery(new Term("content","spring"));
36         //5,返回查詢結果
37         TopDocs result = indexSearcher.search(query, 100);//100指最多返回100個Document
38         System.out.println("總記錄數:"+result.totalHits);
39         ScoreDoc[] scoreDocs = result.scoreDocs;
40         for (ScoreDoc scoreDoc : scoreDocs) {
41             int docId = scoreDoc.doc;
42             //獲取文件
43             Document doc = indexSearcher.doc(docId);
44             System.out.println("文件名"+doc.get("name"));
45             System.out.println("文件路徑"+doc.get("path"));
46         }
47         //6,關閉資源
48         indexReader.close();
49     }
50 }

 

六:分詞器(Aanlyzer)

每個分詞器都有tokenStream()方法

中文一般使用第三方分詞器IK-Aanlyzer(需要導入相應的包)

下載地址: https://pan.baidu.com/s/1BAujr36FozHuwt6JyVFpHQ 提取碼: m3mt 

注意:搜索使用的分析器要和索引使用的分析器一致,不然搜索出來結果可能會錯亂。

七: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的策略.

 

八:索引查詢

1,MatchAllDocsQuery(查詢索引庫中的全部Document)

2,TermQuery(精准查詢)

3,NumericRangeQuery(根據數值范圍查詢)

示例代碼:

 1 //數值范圍查詢
 2     @Test
 3     public void testNumericRangeQuery() throws Exception {
 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         
11         //創建查詢
12         //參數:
13         //1.域名
14         //2.最小值
15         //3.最大值
16         //4.是否包含最小值
17         //5.是否包含最大值
18         Query query = NumericRangeQuery.newLongRange("fileSize", 41L, 2055L, true, true);
19         //執行查詢
20 
21         //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值
22         TopDocs topDocs = indexSearcher.search(query, 10);
23         
24         //查詢結果的總條數
25         System.out.println("查詢結果的總條數:"+ topDocs.totalHits);
26         //遍歷查詢結果
27         //topDocs.scoreDocs存儲了document對象的id
28         //ScoreDoc[] scoreDocs = topDocs.scoreDocs;
29         for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
30             //scoreDoc.doc屬性就是document對象的id
31             //int doc = scoreDoc.doc;
32             //根據document的id找到document對象
33             Document document = indexSearcher.doc(scoreDoc.doc);
34             //文件名稱
35             System.out.println(document.get("fileName"));
36             //文件內容
37             System.out.println(document.get("fileContent"));
38             //文件大小
39             System.out.println(document.get("fileSize"));
40             //文件路徑
41             System.out.println(document.get("filePath"));
42             System.out.println("----------------------------------");
43         }
44         //關閉indexreader對象
45         indexReader.close();
46     }

4,BooleanQuery(組合條件查詢)

示例代碼:

 1 //組合條件查詢
 2  2     @Test
 3  3     public void testBooleanQuery() throws Exception {
 4  4         //創建一個Directory對象,指定索引庫存放的路徑
 5  5         Directory directory = FSDirectory.open(new File("E:\\programme\\test"));
 6  6         //創建IndexReader對象,需要指定Directory對象
 7  7         IndexReader indexReader = DirectoryReader.open(directory);
 8  8         //創建Indexsearcher對象,需要指定IndexReader對象
 9  9         IndexSearcher indexSearcher = new IndexSearcher(indexReader);
10 10         
11 11         //創建一個布爾查詢對象
12 12         BooleanQuery query = new BooleanQuery();
13 13         //創建第一個查詢條件
14 14         Query query1 = new TermQuery(new Term("fileName", "apache"));
15 15         Query query2 = new TermQuery(new Term("fileName", "lucene"));
16 16         //組合查詢條件
17 17      /*
18 18      Occur.MUST:必須滿足此條件,相當於and
19 19
20 20      Occur.SHOULD:應該滿足,但是不滿足也可以,相當於or
21 21
22 22      Occur.MUST_NOT:必須不滿足。相當於not*/
23 23
24 17         query.add(query1, Occur.MUST);
25 18         query.add(query2, Occur.MUST);
26 19         //執行查詢
27 20 
28 21         //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值
29 22         TopDocs topDocs = indexSearcher.search(query, 10);
30 23         
31 24         //查詢結果的總條數
32 25         System.out.println("查詢結果的總條數:"+ topDocs.totalHits);
33 26         //遍歷查詢結果
34 27         //topDocs.scoreDocs存儲了document對象的id
35 28         //ScoreDoc[] scoreDocs = topDocs.scoreDocs;
36 29         for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
37 30             //scoreDoc.doc屬性就是document對象的id
38 31             //int doc = scoreDoc.doc;
39 32             //根據document的id找到document對象
40 33             Document document = indexSearcher.doc(scoreDoc.doc);
41 34             //文件名稱
42 35             System.out.println(document.get("fileName"));
43 36             //文件內容
44 37             System.out.println(document.get("fileContent"));
45 38             //文件大小
46 39             System.out.println(document.get("fileSize"));
47 40             //文件路徑
48 41             System.out.println(document.get("filePath"));
49 42             System.out.println("----------------------------------");
50 43         }
51 44         //關閉indexreader對象
52 45         indexReader.close();
53 46     }

5,queryparser(更具查詢語法查詢)

查詢語法

  1、基礎的查詢語法,關鍵詞查詢:

    域名+“:”+搜索的關鍵字

    例如:content:java

  2、范圍查詢

    域名+“:”+[最小值 TO 最大值]

    例如:size:[1 TO 1000]

    范圍查詢在lucene中支持數值類型,不支持字符串類型。在solr中支持字符串類型。

  3、組合條件查詢

    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

示例代碼:

 1 @Test
 2     public void testQueryParser() 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         //創建queryparser對象
11         //第一個參數默認搜索的域
12         //第二個參數就是分析器對象
13         QueryParser queryParser = new QueryParser("fileName", new IKAnalyzer());
14         //使用默認的域,這里用的是語法,下面會詳細講解一下
15         Query query = queryParser.parse("apache");
16         //不使用默認的域,可以自己指定域
17         //Query query = queryParser.parse("fileContent:apache");
18         //執行查詢
19 
20 
21         //第一個參數是查詢對象,第二個參數是查詢結果返回的最大值
22         TopDocs topDocs = indexSearcher.search(query, 10);
23         
24         //查詢結果的總條數
25         System.out.println("查詢結果的總條數:"+ topDocs.totalHits);
26         //遍歷查詢結果
27         //topDocs.scoreDocs存儲了document對象的id
28         //ScoreDoc[] scoreDocs = topDocs.scoreDocs;
29         for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
30             //scoreDoc.doc屬性就是document對象的id
31             //int doc = scoreDoc.doc;
32             //根據document的id找到document對象
33             Document document = indexSearcher.doc(scoreDoc.doc);
34             //文件名稱
35             System.out.println(document.get("fileName"));
36             //文件內容
37             System.out.println(document.get("fileContent"));
38             //文件大小
39             System.out.println(document.get("fileSize"));
40             //文件路徑
41             System.out.println(document.get("filePath"));
42             System.out.println("----------------------------------");
43         }
44         //關閉indexreader對象
45         indexReader.close();        
46     }

6,MultiFieldQueryParser(指定多個默認域)

示例代碼:

 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     }

7:IndexSearcher.search()查詢方法

方法

說明

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條記錄

 

8:TopDocs(返回的查詢結果)

TopDocs topDocs.totalHits  查詢到的總 條數
TopDocs topDocs.scoreDocs  匹配度較高的Document 集合數組

九:索引庫的修改

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,根據條件刪除索引

 1 //根據查詢條件刪除索引
 2     @Test
 3     public void deleteIndexByQuery() 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         Query query = new TermQuery(new Term("fileContent", "apache"));
10         //根據查詢條件刪除
11         indexWriter.deleteDocuments(query);
12         //關閉indexwriter
13         indexWriter.close();
14     }

3,update索引

 1 //修改索引庫
 2     @Test
 3     public void updateIndex() 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         //創建一個Document對象
 9         Document document = new Document();
10         //向document對象中添加域。
11         //不同的document可以有不同的域,同一個document可以有相同的域。
12         document.add(new TextField("fileXXX", "要更新的文檔", Store.YES));
13         document.add(new TextField("contentYYY", "簡介 Lucene 是一個基於 Java 的全文信息檢索工具包。", Store.YES));
14         indexWriter.updateDocument(new Term("fileName", "apache"), document);
15         //關閉indexWriter
16         indexWriter.close();
17     }

十:相關排序

對域進行打分設置,分數越高,排名越靠前(默認分數是1)

1 Field fileName=new TextField("name","這是該域的內容", Store.YES);
2 fileName.setBoost(10);//設置為10,將提高排名

 

十一:什么是Solr

Solr是基於Lucene開發的一個項目

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM