Lucene入門案例一

1. 配置開發環境

  官方網站:http://lucene.apache.org/java

  Jdk要求:1.7以上git

  建立索引庫必須的jar包(lucene-core-4.10.3.jar,lucene-analyzers-common-4.10.3.jar)github

  其餘jar包(commons-io-2.4.jar , junit-4.9.jar)web

2. 建立索引庫

第一步:建立一個java工程,並導入jar包。算法

第二步:建立一個indexwriter對象。spring

1)指定索引庫的存放位置Directory對象apache

2)指定一個分析器,對文檔內容進行分析。數組

第二步:建立document對象。svn

第三步:建立field對象,將field添加到document對象中。測試

第四步:使用indexwriter對象將document對象寫入索引庫,此過程進行索引建立。並將索引和document對象寫入索引庫。

第五步:關閉IndexWriter對象。

  /*
     * 建立索引庫
     */
    @Test
    public void createIndex() throws Exception {
        //1.指定索引庫存放的位置,能夠存放在內存中,也能夠存放在硬盤中
//        Directory directory = new RAMDirectory();//將索引保存在內存中
        Directory directory = FSDirectory.open(new File("E:\\temp\\index"));
        Analyzer analyzer = new StandardAnalyzer();

  //indexwriterconfig中,第一個參數表明Lucene版本號, 第二個參數表明分析器
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST, analyzer );
        //2.建立IndexWriter對象, 須要在此以前建立一個分析器(分詞)
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        //3.獲取文件,使用io流讀取文件
        File file = new File("E:\\temp\\source_folder");
        for (File f : file.listFiles()) {
            //獲取文件名稱
            String fileName = f.getName();
            //獲取文件大小
            long fileSize = FileUtils.sizeOf(f);
            //獲取文件內容
            String fileContent = FileUtils.readFileToString(f);
            //獲取文件路徑
            String filePath = f.getPath();
            //4.建立文檔對象
            Document document = new Document();
            //5.建立域對象,並添加到文檔中
            //5.1保存文件名 , 須要分析, 須要索引, 須要保存
            StringField nameField = new StringField("name", fileName, Store.YES);
            //5.2保存文件內容, 須要分析, 須要索引, 不須要保存
            TextField contentField = new TextField("content", fileContent, Store.NO);
            //5.3保存文件路徑, 不分析, 不索引, 要保存
            StoredField pathField = new StoredField("path", filePath);
            //5.4 保存文件長度,不索引,不分析,要保存
            LongField sizeField = new LongField("size", fileSize, Store.YES);
            document.add(nameField);
            document.add(contentField);
            document.add(pathField);
            document.add(sizeField);
            //6.把文檔對象寫入索引庫
            indexWriter.addDocument(document);
        }
        //7.釋放資源
        indexWriter.close();
    }

3. 查詢索引

   步驟:

  第一步:建立一個Directory對象,也就是索引庫存放的位置。

  第二步:建立一個indexReader對象,須要指定Directory對象。

  第三步:建立一個indexsearcher對象,須要指定IndexReader對象

  第四步:建立一個TermQuery對象,指定查詢的域和查詢的關鍵詞。

  第五步:執行查詢。

  第六步:返回查詢結果。遍歷查詢結果並輸出。

  第七步:關閉IndexReader對象

  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

頂部匹配記錄

  注意:

  Search方法須要指定匹配記錄數量n:indexSearcher.search(query, n)

  TopDocs.totalHits:是匹配索引庫中全部記錄的數量

  TopDocs.scoreDocs:匹配相關度高的前邊記錄數組,scoreDocs的長度小於等於search方法指定的參數n

 /*
     * 查詢索引庫
     */
    @Test
    public void searchIndex () throws Exception {
        //1.指定索引存放的位置
        Directory directory = FSDirectory.open(new File("E:\\temp\\index"));
        //2.建立IndexReader對象
        IndexReader indexReader = DirectoryReader.open(directory);
        //3.建立IndexSearcher對象, 該對象構造方法須要IndexReader對象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //4.建立一個查詢對象,須要指明查詢關鍵字和域名
        Query query = new TermQuery(new Term("content", "lucene"));
        //5.獲取查詢結果
        TopDocs topDocs = indexSearcher.search(query, 10);
        //打印查詢的總記錄數
        System.out.println("查詢的總記錄數爲: " + topDocs.totalHits);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            //6.便利打印查詢結果
            //獲取document的id
            int docID = scoreDoc.doc;
            System.out.println("文檔id爲: --> " + docID);
            //根據id查詢document對象
            Document document = indexSearcher.doc(docID);
            //根據document對象獲取相應的信息
            System.out.println("文檔名稱: " + document.get("name"));
            System.out.println("文檔路徑: " + document.get("path"));
            System.out.println("文檔大小: " + document.get("size"));
            System.out.println("文檔內容: " + document.get("content"));
        }
        //7.關閉indexreader
        indexReader.close();
    }

 

4. 分析器測試

   4.1 分析器(Analyzer)的執行過程

  以下圖是語彙單元的生成過程:

  

  從一個Reader字符流開始,建立一個基於Reader的Tokenizer分詞器,通過三個TokenFilter生成語彙單元Token。

  要看分析器的分析效果,只須要看Tokenstream中的內容就能夠了。每一個分析器都有一個方法tokenStream,返回一個tokenStream對象。

 

  4.2 分詞器測試

  /*
     * 標準分析器測試
     */
    @SuppressWarnings("resource")
    @Test
    public void testAnalyzer () throws Exception {
        //1.建立一個分析器對象
        Analyzer analyzer = new StandardAnalyzer();
//        Analyzer analyzer = new IKAnalyzer(); //IK-analyzer分詞器
        //2.從分析器對象中獲取tokenStream
        //第一個參數爲fieldname, 域名稱,能夠爲null或者是""
        //第二個參數爲須要解析的字符串
        TokenStream tokenStream = analyzer.tokenStream("", "小新喜歡白富美");
        //3.設置一個引用,引用能夠有多種類型,能夠是關鍵詞引用、偏移量引用等
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
        OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
        //4.調用tokenStream的reset方法,重置指針
        tokenStream.reset();
        //5.使用while循環便利單詞表
        while (tokenStream.incrementToken()) {
            //6.打印單詞
            System.out.println("關鍵詞的起始位置-->" + offsetAttribute.startOffset());
            System.out.println("關鍵詞:-->" + charTermAttribute);
            System.out.println("關鍵詞的結束位置-->" + offsetAttribute.endOffset());
        }
        //7.關閉tokenStream
        tokenStream.close();
    }

 

  4.3 中文分析器

   1.Lucene自帶中文分詞器

  StandardAnalyzer:

  單字分詞:就是按照中文一個字一個字地進行分詞。如:「我愛中國」,
  效果:「我」、「愛」、「中」、「國」。

   CJKAnalyzer

  二分法分詞:按兩個字進行切分。如:「我是中國人」,效果:「我是」、「是中」、「中國」「國人」。

  上邊兩個分詞器沒法知足需求。

  SmartChineseAnalyzer

  對中文支持較好,但擴展性差,擴展詞庫,禁用詞庫和同義詞庫等很差處理

 

  2.第三方中文分析器

  • paoding: 庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代碼在 2008-06-03,在svn中最新也是2010年提交,已通過時,不予考慮。
  • mmseg4j:最新版已從 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代碼是2014年6月,從09年~14年一共有:18個版本,也就是一年幾乎有3個大小版本,有較大的活躍度,用了mmseg算法。
  • 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月後沒有在更新。
  • ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg tags僅有1.1版本,從2012年到2014年更新了大小6次,可是做者本人在2014年10月10日說明:「可能我之後沒有精力來維護ansj_seg了」,如今由」nlp_china」管理。2014年11月有更新。並未說明是否支持Lucene,是一個由CRF(條件隨機場)算法所作的分詞算法。
  • imdict-chinese-analyzer:最新版在 https://code.google.com/p/imdict-chinese-analyzer/ , 最新更新也在2009年5月,下載源碼,不支持Lucene 4.10 。是利用HMM(隱馬爾科夫鏈)算法。
  • Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,做者有較高的活躍度。利用mmseg算法。

  4.4 IK-analyzer中文分析器的使用方法

  使用方法:

  第一步:把jar包添加到工程中

  第二步:把配置文件和擴展詞典和停用詞詞典添加到classpath下

  注意:mydict.dic和ext_stopword.dic文件的格式爲UTF-8,注意是無BOM 的UTF-8 編碼。

  4.5 分詞器的使用時機

  索引時使用Analyzer

        輸入關鍵字進行搜索,當須要讓該關鍵字與文檔域內容所包含的詞進行匹配時須要對文檔域內容進行分析,須要通過Analyzer分析器處理生成語彙單元(Token)。分析器分析的對象是文檔中的Field域。當Field的屬性tokenized(是否分詞)爲true時會對Field值進行分析,以下圖:

  對於一些Field能夠不用分析:

  一、不做爲查詢條件的內容,好比文件路徑

  二、不是匹配內容中的詞而匹配Field的總體內容,好比訂單號、身份證號等。

  搜索時使用Analyzer

        對搜索關鍵字進行分析和索引分析同樣,使用Analyzer對搜索關鍵字進行分析、分詞處理,使用分析後每一個詞語進行搜索。好比:搜索關鍵字:spring web ,通過分析器進行分詞,得出:spring  web拿詞去索引詞典表查找 ,找到索引連接到Document,解析Document內容。

        對於匹配總體Field域的查詢能夠在搜索時不分析,好比根據訂單號、身份證號查詢等。

        注意:搜索使用的分析器要和索引使用的分析器一致。

5. 索引庫的添加

 

向索引庫中添加document對象。

第一步:先建立一個indexwriter對象

第二步:建立一個document對象

第三步:把document對象寫入索引庫

第四步:關閉indexwriter。

  /**
     * 根據索引庫的位置,建立indexwriter
     */
    public static IndexWriter getIndexWriter() throws IOException {
        //1.指定索引庫存放的位置
        Directory directory = FSDirectory.open(new File("E:\\temp\\index"));
        //2.建立IndexWriter對象,須要建立一個解析器和IndexWriterConfig
        Analyzer analyzer = new IKAnalyzer();
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST, analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        return indexWriter;
    }

  //添加文檔
    @Test
    public void addDocument () throws Exception {
        IndexWriter indexWriter = getIndexWriter();
        //3.建立文檔對象
        Document document = new Document();
        //4.建立域對象
        TextField nameField = new TextField("name", "小新文檔", Store.YES);
        TextField contentField = new TextField("content", "小新喜歡白富美", Store.YES);
        //5.將域對象添加到文檔對象中
        document.add(nameField);
        document.add(contentField);
        //6.將文檔對象寫入索引
        indexWriter.addDocument(document);
        //7.關閉IndexWriter
        indexWriter.close();
    }

6. 索引庫的刪除

  6.1 刪除所有

//刪除全部索引
    @Test
    public void deleteAllIndex () throws Exception {
        //獲取IndexWriter對象
        IndexWriter indexWriter = getIndexWriter();
        //調用indexWriter中的方法刪除索引
        indexWriter.deleteAll();
        //釋放資源
        indexWriter.close();
    }

  6.2 根據查詢刪除

//根據查詢條件刪除索引
    @Test
    public void deleteQueryIndex () throws Exception {
        //獲取IndexWriter
        IndexWriter indexWriter = getIndexWriter();
        //制定查詢條件
        Query query = new TermQuery(new Term("content", "小新"));
        //刪除制定查詢條件下的文檔
        indexWriter.deleteDocuments(query);
        //釋放資源
        indexWriter.close();
    }

7. 索引庫的更新

 

//更新索引庫    @Test    public void updateIndex () throws Exception {        //1.獲取indexwriter對象        IndexWriter indexWriter = getIndexWriter();        //2.查詢的過程是,制定要刪除的term的字段及關鍵字,先根據term查詢,而後刪除該查詢結果, 而後添加doucment對象        Document document = new Document();        document.add(new TextField("name", "更新後的文檔", Store.YES));        document.add(new TextField("content", "更新後的文檔內容", Store.YES));        indexWriter.updateDocument(new Term("content", "treat "), document);        //3.釋放資源        indexWriter.close();    }

相關文章
相關標籤/搜索