Lucene初始與簡單應用-Document的增刪改查.


 

Lucene是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎.它提供了一個簡單卻強大的應用程式接口,能夠做全文索引和搜尋。在Java開發環境里Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是很受歡迎的免費Java資訊檢索程式庫。因公司需要,所以開始爬資料學習,希望得到更多大神的指點.然后把這塊做好!

當前版本為4.2, 官方網站: http://lucene.apache.org/

 

在全文索引工具中,都是由3部分組成

1.索引部分

2.分詞部分

3.搜索部分

 

建立索引的步驟

1.創建Directory

2.創建IndexWriter

3.創建Document對象

4.為Document添加Field

/**
 * Description: 建立索引
 *
 */
public void createIndex(){
    
    IndexWriter indexWriter = null;
    try {
    //1.創建Directory
    Directory directory = new RAMDirectory();  //在內存中建立索引
    //2.創建IndexWriter
    IndexWriterConfig indexWiterConfig = new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36));
    indexWriter = new IndexWriter(directory, indexWiterConfig);
    //3.創建Document對象
    Document document = new Document();
    //4.為Document添加Field
    File filePath = new File("luence/example");
    for(File file: filePath.listFiles()){ //為該文件夾下的所有文件建立索引
        document = new Document();
        //傳入文件內容
        document.add(new Field("content",new FileReader(file)));
        //傳入文件名
        document.add(new Field("filename", file.getName(),Field.Store.YES,Field.Index.NOT_ANALYZED));
        //傳入文件路徑
        document.add(new Field("path",file.getAbsolutePath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
        //5.通過IndexWriter添加文檔到索引中
            indexWriter.addDocument(document);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        if(indexWriter!=null){
            try {
                indexWriter.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

上面實例中在內存中創建索引.也可以在硬盤上創建索引:

Directory directory2 = FSDirectory.open(new File("F:/luence/index"));    //在硬盤上的F:/luence/index下建立索引

 

搜索操作的步驟:

1.創建Directory

2.創建IndexReader

3.根據IndexReader創建IndexSearcher

4.創建搜索的Query

5.根據Searcher搜索並且返回TopDocs

6.根據TopDocs獲取ScoreDoc對象

7.根據Seacher和ScoreDoc對象獲取具體的Document對象

8.根據Document對象獲取需要的值

9.關閉IndexReader

public  void searcher(){
        try {
            //1.創建Directory 在硬盤上的F:/luence/index下建立索引
            Directory directory = FSDirectory.open(new File("F:/luence/index"));    
            //2.創建IndexReader
            IndexReader indexReader = IndexReader.open(directory);
            //3.根據IndexReader創建IndexSearcher
            IndexSearcher indexSearcher = new IndexSearcher(indexReader);
            //4.創建搜索的Query 
            //創建parser來確定要搜索文件的內容,第二個參數表示搜索的域, 實例中為"content",表示在內容中查找
            QueryParser queryParser = new QueryParser(Version.LUCENE_36,"content",new StandardAnalyzer(Version.LUCENE_36));
            //創建query,表示搜索域為content中包含Java關鍵字的文檔
            Query query = queryParser.parse("Java");    //搜索包含關鍵字Java的信息
            //5.根據Searcher搜索並且返回TopDocs            
            //查詢,第二個參數表示顯示前10條記錄
            TopDocs topDoc = indexSearcher.search(query, 10);
            //6.根據TopDocs獲取ScoreDoc對象
            ScoreDoc[] scoreDocs = topDoc.scoreDocs;
            for(ScoreDoc scoreDoc : scoreDocs){
                //7.根據Seacher和ScoreDoc對象獲取具體的Document對象
                Document document = indexSearcher.doc(scoreDoc.doc);
                //8.根據Document對象獲取需要的值
                System.out.println(document.get("filename") + "[" + document.get("path") + "]");
            }
            
            //9.關閉IndexReader
            indexReader.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
}

文檔Document和域Field的關系

文檔Document相當於關系表中的每一條記錄,域相當於表中的每一個字段,先創建文檔,之后為文檔添加域.

域存儲選項和域索引選項,均需要在域添加的時候設置

 

存儲域選項

Field.Store.YES表示把這個域中的內容完全存儲到文件中,方便進行文本的還原

Field.Store.NO表示把這個域中的內容不存儲到文件中,但是可以被索引,此時內容無法還原(即無法document.get());

 

索引域選項

Field.Index.ANALYZED:進行分詞和索引,適用於標題和內容等

Field.Index.NOT_ANALYZED:進行索引,但是不進行分詞,像身份證號,姓名,ID等,適用於精確索索

Field.Index.ANALYZED_NO_NORMS:進行分詞但是不存儲norms信息,這個norms中包括了創建索引的時間和權值等信息

Field.Index.NOT_ANALYZED_NO_NORMS:即不進行分詞也不存儲norms信息

Field.Index.NO:不進行索引  

 

最佳實踐

Field.Index.NOT_ANALYZED_NO_NORMS, Field.Store.YES標識符(主鍵,文件名),電話號碼,身份證號,姓名,日期

Field.Index.ANALYZED, Field.Store.YES文檔標題和摘要

Field.Index.ANALYZED, Field.Store.NO文檔正文

Field.Index.NO,Field.Store.YES文檔類型,數據庫主鍵(不進行索引)

Field.Index.NOT_ANALYZED,Field.Store.NO 隱藏關鍵字

 

刪除文檔操作

public void delete(){
        IndexWriter indexWriter = null;
        try {
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,new StandardAnalyzer(Version.LUCENE_36));
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            //參數是一個選項,可以是一個Query,也可以是一個Term,Term是一個精確查找的值
            //此時刪除的文檔並不會完全被刪除,而是存儲在一個回收站中,可以恢復
            //使用Reader可以有效的恢復取到的文檔數
            indexWriter.deleteDocuments(new Term("id","1"));
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(indexWriter!=null){
                try {
                    indexWriter.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

indexWriter.deleteDocuments()文檔並不會完全被刪除,而是存儲在一個回收站中,我們可以編寫查詢類來進行查詢

public void query(){
        try {
            IndexReader indexReader = IndexReader.open(directory);
            System.out.println("存儲的文檔數:" + indexReader.numDocs());
            System.out.println("總存儲量:" + indexReader.maxDoc());
            System.out.println("被刪除的文檔:" + indexReader.numDeletedDocs());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

測試程序

         LuenceIndex luence = new LuenceIndex("F:/luence/index");
        luence.index();
        
        System.out.println("===== 首次建立索引后進行查詢 =====");
        luence.query();
        
        luence.delete();
        System.out.println("===== 調用刪除操作后進行查詢 =====");
        luence.query();

分析程序運行結果

===== 首次建立索引后進行查詢 =====
存儲的文檔數:5
總存儲量:5
被刪除的文檔:0
===== 調用刪除操作后進行查詢 =====
存儲的文檔數:4
總存儲量:5
被刪除的文檔:1

使用IndexReader可以有效的恢復刪除到回收站的文檔

public void recovery(){
        try {
            IndexReader indexReader = IndexReader.open(directory,false);
            //通過IndexReader進行恢復,恢復時,必須把IndexReader的只讀(readOnly)設置為false
            indexReader.undeleteAll();
            indexReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

如果要清空回收站中的內容,需要使用IndexWriter中的forceMergeDeletes()方法

public void forceDelete(){
        IndexWriter indexWriter = null;
        try {
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,new StandardAnalyzer(Version.LUCENE_36));
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            indexWriter.forceMergeDeletes();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(indexWriter!=null){
                try {
                    indexWriter.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
}

這次測試

public static void main(String[] args) {
        LuenceIndex luence = new LuenceIndex("F:/luence/index");
        luence.index();
        
        System.out.println("===== 首次建立索引后進行查詢 =====");
        luence.query();
        
        luence.delete();
        System.out.println("===== 調用刪除操作后進行查詢 =====");
        luence.query();
        
        luence.forceDelete();
        System.out.println("===== 清空回收站內容后進行查詢 =====");
        luence.query();    
}

運行結果

===== 首次建立索引后進行查詢 =====
存儲的文檔數:5
總存儲量:5
被刪除的文檔:0
===== 調用刪除操作后進行查詢 =====
存儲的文檔數:4
總存儲量:5
被刪除的文檔:1
===== 清空回收站內容后進行查詢 =====
存儲的文檔數:4
總存儲量:4
被刪除的文檔:0


Luence更新操作

public void update(){
        IndexWriter indexWriter = null;
        try {
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,new StandardAnalyzer(Version.LUCENE_36));
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            //Luence並沒有提供更新,這里的更新操作其實是先刪除再添加的操作合集
            Document document = new Document();
            document.add(new Field("id","updateId",Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
            document.add(new Field("email","updateEmail",Field.Store.YES,Field.Index.NOT_ANALYZED));
            document.add(new Field("content","updateContent",Field.Store.NO,Field.Index.ANALYZED));
            document.add(new Field("name","updateName",Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
            //更新Id為2的數據
            indexWriter.updateDocument(new Term("id","2"), document);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(indexWriter!=null){
                try {
                    indexWriter.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
}


轉載請注明出處:[http://www.cnblogs.com/dennisit/archive/2013/04/06/3002863.html]

在線交談

 


免責聲明!

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



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