Lucene介紹與入門使用


  Lucene簡介

  Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是為軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此為基礎建立起完整的全文檢索引擎。Lucene是一套用於全文檢索和搜尋的開源程式庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程式接口,能夠做全文索引和搜尋。在Java開發環境里Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是當前以及最近幾年最受歡迎的免費Java信息檢索程序庫。人們經常提到信息檢索程序庫,雖然與搜索引擎有關,但不應該將信息檢索程序庫與搜索引擎相混淆。

  那么先來說一說什么是全文搜索

  說之前先說一說數據的分類: 

    我們生活中的數據總體分為兩種:結構化數據和非結構化數據。

    (1)結構化數據:指具有固定格式或有限長度的數據,如數據庫,元數據等。

    (2)非結構化數據:指不定長或無固定格式的數據,如郵件,word文檔等磁盤上的文件

  結構化數據查詢方法

  數據庫搜索

  數據庫中的搜索很容易實現,通常都是使用sql語句進行查詢,而且能很快的得到查詢結果。

  為什么數據庫搜索很容易?

  因為數據庫中的數據存儲是有規律的,有行有列而且數據格式、數據長度都是固定的。

  非結構化數據查詢方法

  (1)順序掃描法(Serial Scanning)

  所謂順序掃描,比如要找內容包含某一個字符串的文件,就是一個文檔一個文檔的看,對於每一個文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的文件,接着看下一個文件,直到掃描完所有的文件。如利用windows的搜索也可以搜索文件內容,只是相當的慢

  (2)全文檢索(Full-text Search)

  將非結構化數據中的一部分信息提取出來,重新組織,使其變得有一定結構,然后對此有一定結構的數據進行搜索,從而達到搜索相對較快的目的。這部分從非結構化數據中提取出的然后重新組織的信息,我們稱之索引

例如:字典。字典的拼音表和部首檢字表就相當於字典的索引,對每一個字的解釋是非結構化的,如果字典沒有音節表和部首檢字表,在茫茫辭海中找一個字只能順序掃描。然而字的某些信息可以提取出來進行結構化處理,比如讀音,就比較結構化,分聲母和韻母,分別只有幾種可以一一列舉,於是將讀音拿出來按一定的順序排列,每一項讀音都指向此字的詳細解釋的頁數。我們搜索時按結構化的拼音搜到讀音,然后按其指向的頁數,便可找到我們的非結構化數據——也即對字的解釋。

  這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)

  雖然創建索引的過程也是非常耗時的,但是索引一旦創建就可以多次使用,全文檢索主要處理的是查詢,所以耗時間創建索引是值得的。

  全文檢索的應用場景

  對於數據量大、數據結構不固定的數據可采用全文檢索方式搜索,比如百度、Google等搜索引擎、論壇站內搜索、電商網站站內搜索等。

 

  Lucene實現全文檢索的流程

  索引和搜索流程圖

  1、綠色表示索引過程,對要搜索的原始內容進行索引構建一個索引庫,索引過程包括:

    確定原始內容即要搜索的內容采集文檔創建文檔分析文檔索引文檔

  2、紅色表示搜索過程,從索引庫中搜索內容,搜索過程包括:

    用戶通過搜索界面創建查詢執行搜索,從索引庫搜索渲染搜索結果

 

  接下來詳細講解一下這張圖片: 

 1,創建索引

  對文檔索引的過程,將用戶要搜索的文檔內容進行索引,索引存儲在索引庫(index)中。

這里我們要搜索的文檔是磁盤上的文本文件,根據案例描述:凡是文件名或文件內容包括關鍵字的文件都要找出來,這里要對文件名和文件內容創建索引。

  1.1.1.   獲得原始文檔

  原始文檔是指要索引和搜索的內容。原始內容包括互聯網上的網頁、數據庫中的數據、磁盤上的文件等。

  從互聯網上、數據庫、文件系統中等獲取需要搜索的原始信息,這個過程就是信息采集,信息采集的目的是為了對原始內容進行索引。在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的文件內容。 

 

  1.1.2.   創建文檔對象

  獲取原始內容的目的是為了索引,在索引前需要將原始內容創建成文檔(Document),文檔中包括一個一個的域(Field),域中存儲內容。

這里我們可以將磁盤上的一個文件當成一個document,Document中包括一些Field(file_name文件名稱、file_path文件路徑、file_size文件大小、file_content文件內容),如下圖:

 

  注意:(1)每個Document可以有多個Field

     (2)不同的Document可以有不同的Field

     (3)同一個Document可以有相同的Field(域名和域值都相同)

     (4)每個文檔都有一個唯一的編號,就是文檔id。

 

  1.1.3.   分析文檔

  將原始內容創建為包含域(Field)的文檔(document),需要再對域中的內容進行分析,分析的過程是經過對原始文檔提取單詞、將字母轉為小寫、去除標點符號、去除停用詞等過程生成最終的語匯單元,可以將語匯單元理解為一個一個的單詞。

  比如下邊的文檔經過分析如下:

  原文檔內容:

  Lucene is a Java full-text search engine.  

  分析后得到的語匯單元

  lucene、java、full、search、engine

 

  每個單詞叫做一個Term,不同的域中拆分出來的相同的單詞是不同的term。term中包含兩部分一部分是文檔的域名,另一部分是單詞的內容。

  例如:文件名中包含apache和文件內容中包含的apache是不同的term。

 

  1.1.4.   創建索引

  對所有文檔分析得出的語匯單元進行索引,索引的目的是為了搜索,最終要實現只搜索被索引的語匯單元從而找到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值存儲在文檔中,存儲在文檔中的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的策略.

 

  2. 查詢索引

  查詢索引也是搜索的過程。搜索就是用戶輸入關鍵字,從索引(index)中進行搜索的過程。根據關鍵字搜索索引,根據索引找到對應的文檔,從而找到要搜索的內容(這里指磁盤上的文件)。

       對要搜索的信息創建Query查詢對象,Lucene會根據Query查詢對象生成最終的查詢語法,類似關系數據庫Sql語法一樣Lucene也有自己的查詢語法,比如:“name:lucene”表示查詢Field的name為“lucene”的文檔信息。

  2.1.   用戶查詢接口

  全文檢索系統提供用戶搜索的界面供用戶提交搜索的關鍵字,搜索完成展示搜索結果。

  比如: 百度搜索

  Lucene不提供制作用戶搜索界面的功能,需要根據自己的需求開發搜索界面。

  2.2.   創建查詢

  用戶輸入查詢關鍵字執行搜索之前需要先構建一個查詢對象,查詢對象中可以指定查詢要搜索的Field文檔域、查詢關鍵字等,查詢對象會生成具體的查詢語法,

  例如: 語法 “fileName:lucene”表示要搜索Field域的內容為“lucene”的文檔

  2.3.   執行查詢

  搜索索引過程:

  根據查詢語法在倒排索引詞典表中分別找出對應搜索詞的索引,從而找到索引所鏈接的文檔鏈表。

  比如搜索語法為“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

  使用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,通過項查詢,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 }

 

  NumericRangeQuery

  可以根據數值范圍查詢。

  具體代碼:

    //數值范圍查詢
    @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();
    }

 

 

  BooleanQuery

  可以組合查詢條件。

  具體代碼:

    //組合條件查詢
    @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();        
    }

 

  查詢語法

  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

Occur.MUST 查詢條件必須滿足,相當於and

+(加號)

Occur.SHOULD 查詢條件可選,相當於or

空(不用符號)

Occur.MUST_NOT 查詢條件不能滿足,相當於not非

-(減號)

 

  第二種寫法:

  條件1 AND 條件2

  條件1 OR 條件2

  條件1 NOT 條件2

 

  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     }

 

 

 IndexSearcher搜索方法

方法

說明

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

 

 

  TopDocs

  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();

 

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

 

  3. 刪除索引

   (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();
    }

 

  4 索引庫的修改

  更新的原理就是先刪除在添加

    //修改索引庫
    @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的簡單介紹使用就完成了。


免責聲明!

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



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