Lucene教程(四) 索引的更新和刪除


這篇文章是基於上一篇文章來寫的,使用的是IndexUtil類,下面的例子不在貼出整個類的內容,只貼出具體的方法內容。

3.5版本:

先寫了一個check()方法來查看索引文件的變化:

 

  1.  
    /**
  2.  
    * 檢查一下索引文件
  3.  
    */
  4.  
    public static void check() {
  5.  
    IndexReader indexReader = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    indexReader = IndexReader.open(directory);
  9.  
    // 通過reader可以有效的獲取到文檔的數量
  10.  
    // 有效的索引文檔
  11.  
    System.out.println( "有效的索引文檔:" + indexReader.numDocs());
  12.  
    // 總共的索引文檔
  13.  
    System.out.println( "總共的索引文檔:" + indexReader.maxDoc());
  14.  
    // 刪掉的索引文檔,其實不恰當,應該是在回收站里的索引文檔
  15.  
    System.out.println( "刪掉的索引文檔:" + indexReader.numDeletedDocs());
  16.  
    } catch (Exception e) {
  17.  
    e.printStackTrace();
  18.  
    } finally {
  19.  
    try {
  20.  
    if (indexReader != null) {
  21.  
    indexReader.close();
  22.  
    }
  23.  
    } catch (Exception e) {
  24.  
    e.printStackTrace();
  25.  
    }
  26.  
    }
  27.  
    }

 

那么就下來就先跑一下建立索引方法,然后在執行以下check()方法,看看結果:

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :0

接下來我想刪除一個索引,例子如下:

 

 

  1.  
    /**
  2.  
    * 刪除索引
  3.  
    */
  4.  
    public static void delete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * 參數是一個選項,可以是一個Query,也可以是一個term,term是一個精確查找的值
  13.  
    *
  14.  
    * 此時刪除的文檔並不會被完全刪除,而是存儲在一個回收站中的,可以恢復
  15.  
    */
  16.  
     
  17.  
    // 方式一:通過Term刪除
  18.  
     
  19.  
    /**
  20.  
    * 注意Term構造器的意思,第一個參數為Field,第二個參數為Field的值
  21.  
    */
  22.  
    indexWriter.deleteDocuments( new Term("id", "1"));
  23.  
     
  24.  
    // 方式二:通過Query刪除
  25.  
     
  26.  
    /**
  27.  
    * 這里就要造一個Query出來,刪掉查處的索引
  28.  
    */
  29.  
    QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
  30.  
    // 創建Query表示搜索域為content包含Lucene的文檔
  31.  
    Query query = queryParser.parse( "Lucene");
  32.  
     
  33.  
    // indexWriter.deleteDocuments(query);
  34.  
    } catch (Exception e) {
  35.  
    e.printStackTrace();
  36.  
    } finally {
  37.  
    try {
  38.  
    if (indexWriter != null) {
  39.  
    indexWriter.close();
  40.  
    }
  41.  
    } catch (Exception e) {
  42.  
    e.printStackTrace();
  43.  
    }
  44.  
    }
  45.  
    }

看看測試:

 

 

  1.  
    @Test
  2.  
    public void testDelete() {
  3.  
    IndexUtil.delete();
  4.  
    IndexUtil.check();
  5.  
    }

執行過后:

 

 

  1.  
    有效的索引文檔 :2
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :1

此時被刪掉的文檔跑到了回收站中,並沒有被徹底刪除,我們上面使用的是刪term的方式,那么使用query刪行不行呢,那么現在把注釋換一換:

 

 

  1.  
    // indexWriter.deleteDocuments(new Term("id", "1"));
  2.  
     
  3.  
    // 方式二:通過Query刪除
  4.  
     
  5.  
    /**
  6.  
    * 這里就要造一個Query出來,刪掉查處的索引
  7.  
    */
  8.  
    QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
  9.  
    // 創建Query表示搜索域為content包含Lucene的文檔
  10.  
    Query query = queryParser.parse( "Lucene");
  11.  
     
  12.  
    indexWriter.deleteDocuments(query);

再跑一下測試方法:

 

 

  1.  
    有效的索引文檔: 1
  2.  
    總共的索引文檔: 3
  3.  
    刪掉的索引文檔: 2

看看,被刪除的文檔又多了一個,因為我們query查出的文檔和id為1的文檔不是同一個,目前了解了刪除的兩種方式怎么使用了吧。
我現在發現刪錯了,想恢復怎么辦,那么我們就來看看怎么恢復刪除的索引:

 

 

  1.  
    /**
  2.  
    * 恢復刪除的索引
  3.  
    */
  4.  
    public static void unDelete() {
  5.  
    // 使用IndexReader進行恢復
  6.  
    IndexReader indexReader = null;
  7.  
    try {
  8.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  9.  
    // 恢復時,必須把IndexReader的只讀(readOnly)設置為false
  10.  
    // 索引沒有改變可以使用true,但現在是恢復刪除的索引,顯然是改變過的,所以只能是false
  11.  
    indexReader = IndexReader.open(directory, false);
  12.  
    indexReader.undeleteAll();
  13.  
    } catch (Exception e) {
  14.  
    e.printStackTrace();
  15.  
    } finally {
  16.  
    try {
  17.  
    if (indexReader != null) {
  18.  
    indexReader.close();
  19.  
    }
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    }
  23.  
    }
  24.  
    }

跑一下測試:

 

 

  1.  
    @Test
  2.  
    public void testUnDelete() {
  3.  
    IndexUtil.unDelete();
  4.  
    IndexUtil.check();
  5.  
    }

結果為:

 

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :0

全部恢復了吧,很不錯吧

 

但是我現在有發現剛才沒有刪錯,我要把索引徹底刪除,怎么弄呢,我們回過頭來再試,我現在吧刪除索引的兩種方式的注釋都打開,執行一下刪除方法是不是得到這樣的結果啊:

 

  1.  
    有效的索引文檔 :1
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :2

然后看看徹底刪除的代碼:

 

 

  1.  
    /**
  2.  
    * 強制刪除
  3.  
    */
  4.  
    public static void forceDelete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    indexWriter.forceMergeDeletes();
  12.  
    } catch (Exception e) {
  13.  
    e.printStackTrace();
  14.  
    } finally {
  15.  
    try {
  16.  
    if (indexWriter != null) {
  17.  
    indexWriter.close();
  18.  
    }
  19.  
    } catch (Exception e) {
  20.  
    e.printStackTrace();
  21.  
    }
  22.  
    }
  23.  
    }

執行一下測試代碼:

 

 

  1.  
    @Test
  2.  
    public void testForceDelete() {
  3.  
    IndexUtil.forceDelete();
  4.  
    IndexUtil.check();
  5.  
    }

結果如下:

 

 

  1.  
    有效的索引文檔 :1
  2.  
    總共的索引文檔 :1
  3.  
    刪掉的索引文檔 :0

此時兩個索引文檔被徹底的刪掉了。這么長都在講刪除的事,那么Lucene是怎么更新索引的呢,記下來看看是如何更新索引的:

 

注:先把索引文件刪除,重新建索引

 

  1.  
    /**
  2.  
    * 更新索引
  3.  
    */
  4.  
    public static void update() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * Lucene並沒有提供更新,這里的更新操作其實是如下兩個操作的合集 先刪除之后再添加
  13.  
    */
  14.  
    Document document = new Document();
  15.  
    document.add( new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
  16.  
    document.add( new Field("author", authors[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
  17.  
    document.add( new Field("title", titles[0], Field.Store.YES, Field.Index.ANALYZED));
  18.  
    document.add( new Field("content", contents[1], Field.Store.NO, Field.Index.ANALYZED));
  19.  
    indexWriter.updateDocument( new Term("id", "1"), document);
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    } finally {
  23.  
    try {
  24.  
    if (indexWriter != null) {
  25.  
    indexWriter.close();
  26.  
    }
  27.  
    } catch (Exception e) {
  28.  
    e.printStackTrace();
  29.  
    }
  30.  
    }
  31.  
    }

注意上邊這段代碼,我使用的content是id為2的content,它包含“Lucene”,我一會要用它測試,注意比對結果

 

此時執行一下更新索引:

 

  1.  
    @Test
  2.  
    public void testUpdate() {
  3.  
    IndexUtil.update();
  4.  
    IndexUtil.check();
  5.  
    }

結果為:

 

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :4
  3.  
    刪掉的索引文檔 :1

結果是這樣的,驚訝嗎,我們一起來算算,有效的文檔刪掉一個添加一個是不是3個,沒錯吧,總共的文檔數是三個加一個,引文刪掉的文檔也算啊,沒有徹底刪掉,在回收站里,然后我們執行一下search()方法,看看結果:

 

 

  1.  
    /**
  2.  
    * 搜索
  3.  
    */
  4.  
    public static void search() {
  5.  
    IndexReader indexReader = null;
  6.  
    try {
  7.  
    // 1、創建Directory
  8.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  9.  
    // 2、創建IndexReader
  10.  
    indexReader = IndexReader.open(directory);
  11.  
    // 3、根據IndexReader創建IndexSearch
  12.  
    IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  13.  
    // 4、創建搜索的Query
  14.  
    // 使用默認的標准分詞器
  15.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
  16.  
     
  17.  
    // 在content中搜索Lucene
  18.  
    // 創建parser來確定要搜索文件的內容,第二個參數為搜索的域
  19.  
    QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
  20.  
    // 創建Query表示搜索域為content包含Lucene的文檔
  21.  
    Query query = queryParser.parse( "Lucene");
  22.  
     
  23.  
    // 5、根據searcher搜索並且返回TopDocs
  24.  
    TopDocs topDocs = indexSearcher.search(query, 10);
  25.  
    // 6、根據TopDocs獲取ScoreDoc對象
  26.  
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
  27.  
    for (ScoreDoc scoreDoc : scoreDocs) {
  28.  
    // 7、根據searcher和ScoreDoc對象獲取具體的Document對象
  29.  
    Document document = indexSearcher.doc(scoreDoc.doc);
  30.  
    // 8、根據Document對象獲取需要的值
  31.  
    System.out.println( "id : " + document.get("id"));
  32.  
    System.out.println( "author : " + document.get("author"));
  33.  
    System.out.println( "title : " + document.get("title"));
  34.  
    /**
  35.  
    * 看看content能不能打印出來,為什么?
  36.  
    */
  37.  
    System.out.println( "content : " + document.get("content"));
  38.  
    }
  39.  
     
  40.  
    } catch (Exception e) {
  41.  
    e.printStackTrace();
  42.  
    } finally {
  43.  
    try {
  44.  
    if (indexReader != null) {
  45.  
    indexReader.close();
  46.  
    }
  47.  
    } catch (Exception e) {
  48.  
    e.printStackTrace();
  49.  
    }
  50.  
    }
  51.  
    }
  1.  
    @Test
  2.  
    public void testSearch() {
  3.  
    IndexUtil.search();
  4.  
    }
  1.  
    id : 2
  2.  
    author : Tony
  3.  
    title : Hello Lucene
  4.  
    content : null
  5.  
    id : 11
  6.  
    author : Darren
  7.  
    title : Hello World
  8.  
    content : null

查出來了兩條,說明更新成功了

 

我再把id為3的索引也更新一下:

 

  1.  
    Document document = new Document();
  2.  
    document.add( new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
  3.  
    document.add( new Field("author", authors[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
  4.  
    document.add( new Field("title", titles[0], Field.Store.YES, Field.Index.ANALYZED));
  5.  
    document.add( new Field("content", contents[1], Field.Store.NO, Field.Index.ANALYZED));
  6.  
    indexWriter.updateDocument( new Term("id", "3"), document);

執行一下update()方法,看看結果:

 

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :5
  3.  
    刪掉的索引文檔 :2

問題來了,隨着索引文件更新次數的增加,索引文件是不是會越來越多啊,那我們是不是有辦法合並一下優化一下呢,下面來看Lucene是怎么合並索引文件的:

 

 

  1.  
    /**
  2.  
    * 合並索引
  3.  
    */
  4.  
    public static void merge() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    // 會將索引合並為2段,這兩段中的被刪除的數據會被清空
  12.  
    /**
  13.  
    * 特別注意:
  14.  
    *
  15.  
    * 此處Lucene在3.5之后不建議使用,因為會消耗大量的開銷,Lucene會根據情況自動處理的
  16.  
    */
  17.  
     
  18.  
    // 把索引合並為兩段
  19.  
    indexWriter.forceMerge( 2);
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    } finally {
  23.  
    try {
  24.  
    if (indexWriter != null) {
  25.  
    indexWriter.close();
  26.  
    }
  27.  
    } catch (Exception e) {
  28.  
    e.printStackTrace();
  29.  
    }
  30.  
    }
  31.  
    }

執行一下測試:

 

 

  1.  
    @Test
  2.  
    public void testMerge() {
  3.  
    IndexUtil.merge();
  4.  
    IndexUtil.check();
  5.  
    }

結果為:

 

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :0

索引文件數恢復正常了,這里有個問題,Lucene的合並索引方法或優化索引方法不建議人為調用,會消耗很多資源,並且Lucene會自動優化索引,索引不用擔心索引文件一直變大變多這個問題。

 

4.5版本:

首先看看check()方法,和3.5版本一樣:

 

  1.  
    /**
  2.  
    * 檢查一下索引文件
  3.  
    */
  4.  
    public static void check() {
  5.  
    DirectoryReader directoryReader = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    directoryReader = DirectoryReader.open(directory);
  9.  
    // 通過reader可以有效的獲取到文檔的數量
  10.  
    // 有效的索引文檔
  11.  
    System.out.println( "有效的索引文檔:" + directoryReader.numDocs());
  12.  
    // 總共的索引文檔
  13.  
    System.out.println( "總共的索引文檔:" + directoryReader.maxDoc());
  14.  
    // 刪掉的索引文檔,其實不恰當,應該是在回收站里的索引文檔
  15.  
    System.out.println( "刪掉的索引文檔:" + directoryReader.numDeletedDocs());
  16.  
    } catch (Exception e) {
  17.  
    e.printStackTrace();
  18.  
    } finally {
  19.  
    try {
  20.  
    if (directoryReader != null) {
  21.  
    directoryReader.close();
  22.  
    }
  23.  
    } catch (Exception e) {
  24.  
    e.printStackTrace();
  25.  
    }
  26.  
    }
  27.  
    }

接下來看看刪除方法:

 

 

  1.  
    /**
  2.  
    * 刪除索引
  3.  
    */
  4.  
    public static void delete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * 參數是一個選項,可以是一個Query,也可以是一個term,term是一個精確查找的值
  13.  
    *
  14.  
    * 此時刪除的文檔並不會被完全刪除,而是存儲在一個回收站中的,可以恢復
  15.  
    */
  16.  
     
  17.  
    // 方式一:通過Term刪除
  18.  
     
  19.  
    /**
  20.  
    * 注意Term構造器的意思,第一個參數為Field,第二個參數為Field的值
  21.  
    */
  22.  
    indexWriter.deleteDocuments( new Term("id", "1"));
  23.  
     
  24.  
    // 方式二:通過Query刪除
  25.  
     
  26.  
    /**
  27.  
    * 這里就要造一個Query出來,刪掉查處的索引
  28.  
    */
  29.  
    QueryParser queryParser = new QueryParser(Version.LUCENE_45, "content", analyzer);
  30.  
    // 創建Query表示搜索域為content包含Lucene的文檔
  31.  
    Query query = queryParser.parse( "Lucene");
  32.  
     
  33.  
    // indexWriter.deleteDocuments(query);
  34.  
    } catch (Exception e) {
  35.  
    e.printStackTrace();
  36.  
    } finally {
  37.  
    try {
  38.  
    if (indexWriter != null) {
  39.  
    indexWriter.close();
  40.  
    }
  41.  
    } catch (Exception e) {
  42.  
    e.printStackTrace();
  43.  
    }
  44.  
    }
  45.  
    }

然后我們跑一下測試看看結果:記住要跑一下索引方法

 

 

  1.  
    @Test
  2.  
    public void testDelete() {
  3.  
    IndexUtil.delete();
  4.  
    IndexUtil.check();
  5.  
    }
  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :0

沒有刪掉,為什么,經網絡搜索,發現有人遇到了這個問題,解釋是這樣的,我現在是按term刪,但是刪除的term的text類型和建索引時的不一樣,他其實是找不到這個term對應的內容,修改一下建立索引的方法:

 

把這段邏輯

 

  1.  
    FieldType idType = new FieldType();
  2.  
    idType.setStored( true);
  3.  
    idType.setIndexed( false);
  4.  
    idType.setOmitNorms( false);
  5.  
    document.add( new Field("id", ids[i], idType));

改為:

 

 

document.add(new Field("id", ids[i], StringField.TYPE_STORED));

這樣Id就是使用StringField去建立的索引,和我們term里的第二個參數類型一樣了,再來試試

 

 

  1.  
    有效的索引文檔 :2
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :1

現在可以了,但是這里就有問題了,我們使用的預定義的類型,這種類型是不可改的,我就不能對id使用自定義類型了,這不就不如3.5靈活了嗎,不知道有沒有人有什么高見。

 

接下來看看恢復方法:

 

  1.  
    /**
  2.  
    * 恢復刪除的索引
  3.  
    */
  4.  
    public static void unDelete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * 注意:和3.5版本不同,不再使用IndexReader恢復刪除的索引,而是使用IndexWriter的rollback()方法
  13.  
    */
  14.  
    indexWriter.rollback();
  15.  
    } catch (Exception e) {
  16.  
    e.printStackTrace();
  17.  
    } finally {
  18.  
    try {
  19.  
    if (indexWriter != null) {
  20.  
    indexWriter.close();
  21.  
    }
  22.  
    } catch (Exception e) {
  23.  
    e.printStackTrace();
  24.  
    }
  25.  
    }
  26.  
    }

 

這里遇到了另外的問題,無法恢復,暫時還不知道原因

接下來看看強制刪除:

 

  1.  
    /**
  2.  
    * 強制刪除
  3.  
    */
  4.  
    public static void forceDelete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    indexWriter.forceMergeDeletes();
  12.  
    } catch (Exception e) {
  13.  
    e.printStackTrace();
  14.  
    } finally {
  15.  
    try {
  16.  
    if (indexWriter != null) {
  17.  
    indexWriter.close();
  18.  
    }
  19.  
    } catch (Exception e) {
  20.  
    e.printStackTrace();
  21.  
    }
  22.  
    }
  23.  
    }
  1.  
    @Test
  2.  
    public void testForceDelete() {
  3.  
    IndexUtil.forceDelete();
  4.  
    IndexUtil.check();
  5.  
    }
  1.  
    有效的索引文檔 :2
  2.  
    總共的索引文檔 :2
  3.  
    刪掉的索引文檔 :0

結果是正確的

 

我們來看看更新方法:

 

  1.  
    /**
  2.  
    * 更新索引
  3.  
    */
  4.  
    public static void update() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * Lucene並沒有提供更新,這里的更新操作其實是如下兩個操作的合集 先刪除之后再添加
  13.  
    */
  14.  
    Document document = new Document();
  15.  
    document.add( new Field("id", "11", StringField.TYPE_STORED));
  16.  
    document.add( new Field("author", authors[0], StringField.TYPE_STORED));
  17.  
    document.add( new Field("title", titles[0], StringField.TYPE_STORED));
  18.  
    document.add( new Field("content", contents[1], TextField.TYPE_NOT_STORED));
  19.  
    indexWriter.updateDocument( new Term("id", "1"), document);
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    } finally {
  23.  
    try {
  24.  
    if (indexWriter != null) {
  25.  
    indexWriter.close();
  26.  
    }
  27.  
    } catch (Exception e) {
  28.  
    e.printStackTrace();
  29.  
    }
  30.  
    }
  31.  
    }

注意:這里有個問題和刪除是一樣的,就是對id建索引是所使用的類型和刪除時的保持一致,否則就會查不到,就變成了添加索引而不刪除索引

 

這里還是重新建索引再測試

 

  1.  
    @Test
  2.  
    public void testUpdate() {
  3.  
    IndexUtil.update();
  4.  
    IndexUtil.check();
  5.  
    }
  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :4
  3.  
    刪掉的索引文檔 :1

更新了一條,那么我們把id為3的也更新:

 

 

  1.  
    Document document = new Document();
  2.  
    document.add( new Field("id", "33", StringField.TYPE_STORED));
  3.  
    document.add( new Field("author", authors[0], StringField.TYPE_STORED));
  4.  
    document.add( new Field("title", titles[0], StringField.TYPE_STORED));
  5.  
    document.add( new Field("content", contents[1], TextField.TYPE_NOT_STORED));
  6.  
    indexWriter.updateDocument( new Term("id", "3"), document);

再測:

 

 

  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :5
  3.  
    刪掉的索引文檔 :2

結果都是正確的,那么我們合並一下:

 

 

  1.  
    /**
  2.  
    * 合並索引
  3.  
    */
  4.  
    public static void merge() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open( new File("F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    // 會將索引合並為2段,這兩段中的被刪除的數據會被清空
  12.  
    /**
  13.  
    * 特別注意:
  14.  
    *
  15.  
    * 此處Lucene在3.5之后不建議使用,因為會消耗大量的開銷,Lucene會根據情況自動處理的
  16.  
    */
  17.  
     
  18.  
    // 把索引合並為兩段
  19.  
    indexWriter.forceMerge( 2);
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    } finally {
  23.  
    try {
  24.  
    if (indexWriter != null) {
  25.  
    indexWriter.close();
  26.  
    }
  27.  
    } catch (Exception e) {
  28.  
    e.printStackTrace();
  29.  
    }
  30.  
    }
  31.  
    }
  1.  
    @Test
  2.  
    public void testMerge() {
  3.  
    IndexUtil.merge();
  4.  
    IndexUtil.check();
  5.  
    }
  1.  
    有效的索引文檔 :3
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :0

結果和3.5版本的一致

 

5.0版本:

先看刪除方法:

 

  1.  
    /**
  2.  
    * 刪除索引
  3.  
    */
  4.  
    public static void delete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer();
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * 參數是一個選項,可以是一個Query,也可以是一個term,term是一個精確查找的值
  13.  
    *
  14.  
    * 此時刪除的文檔並不會被完全刪除,而是存儲在一個回收站中的,可以恢復
  15.  
    */
  16.  
     
  17.  
    // 方式一:通過Term刪除
  18.  
     
  19.  
    /**
  20.  
    * 注意Term構造器的意思,第一個參數為Field,第二個參數為Field的值
  21.  
    */
  22.  
    indexWriter.deleteDocuments( new Term("id", "1"));
  23.  
     
  24.  
    // 方式二:通過Query刪除
  25.  
     
  26.  
    /**
  27.  
    * 這里就要造一個Query出來,刪掉查處的索引
  28.  
    */
  29.  
    QueryParser queryParser = new QueryParser("content", analyzer);
  30.  
    // 創建Query表示搜索域為content包含Lucene的文檔
  31.  
    Query query = queryParser.parse( "Lucene");
  32.  
     
  33.  
    // indexWriter.deleteDocuments(query);
  34.  
    } catch (Exception e) {
  35.  
    e.printStackTrace();
  36.  
    } finally {
  37.  
    try {
  38.  
    if (indexWriter != null) {
  39.  
    indexWriter.close();
  40.  
    }
  41.  
    } catch (Exception e) {
  42.  
    e.printStackTrace();
  43.  
    }
  44.  
    }
  45.  
    }

跑一下測試:

 

  1.  
    @Test
  2.  
    public void testDelete() {
  3.  
    IndexUtil.delete();
  4.  
    IndexUtil.check();
  5.  
    }
  1.  
    有效的索引文檔 :2
  2.  
    總共的索引文檔 :3
  3.  
    刪掉的索引文檔 :1

她解決了4.5版本中的一個問題,非要建立索引的id的類型和term參數類型一致的問題。

恢復邏輯如下:

 

  1.  
    /**
  2.  
    * 恢復刪除的索引
  3.  
    */
  4.  
    public static void unDelete() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer();
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * 注意:和3.5版本不同,不再使用IndexReader恢復刪除的索引,而是使用IndexWriter的rollback()方法
  13.  
    */
  14.  
    indexWriter.rollback();
  15.  
    } catch (Exception e) {
  16.  
    e.printStackTrace();
  17.  
    } finally {
  18.  
    try {
  19.  
    if (indexWriter != null) {
  20.  
    indexWriter.close();
  21.  
    }
  22.  
    } catch (Exception e) {
  23.  
    e.printStackTrace();
  24.  
    }
  25.  
    }
  26.  
    }

目前和4.5版本有一樣的問題,恢復不了,等待繼續研究去解決這個問題。

其他代碼如下:

 

  1.  
    /**
  2.  
    * 更新索引
  3.  
    */
  4.  
    public static void update() {
  5.  
    IndexWriter indexWriter = null;
  6.  
    try {
  7.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  8.  
    Analyzer analyzer = new StandardAnalyzer();
  9.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  10.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  11.  
    /**
  12.  
    * Lucene並沒有提供更新,這里的更新操作其實是如下兩個操作的合集 先刪除之后再添加
  13.  
    */
  14.  
    Document document = new Document();
  15.  
    document.add( new Field("id", "33", StringField.TYPE_STORED));
  16.  
    document.add( new Field("author", authors[0], StringField.TYPE_STORED));
  17.  
    document.add( new Field("title", titles[0], StringField.TYPE_STORED));
  18.  
    document.add( new Field("content", contents[1], TextField.TYPE_NOT_STORED));
  19.  
    indexWriter.updateDocument( new Term("id", "1"), document);
  20.  
    } catch (Exception e) {
  21.  
    e.printStackTrace();
  22.  
    } finally {
  23.  
    try {
  24.  
    if (indexWriter != null) {
  25.  
    indexWriter.close();
  26.  
    }
  27.  
    } catch (Exception e) {
  28.  
    e.printStackTrace();
  29.  
    }
  30.  
    }
  31.  
    }
  32.  
     
  33.  
    /**
  34.  
    * 檢查一下索引文件
  35.  
    */
  36.  
    public static void check() {
  37.  
    DirectoryReader directoryReader = null;
  38.  
    try {
  39.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  40.  
    directoryReader = DirectoryReader.open(directory);
  41.  
    // 通過reader可以有效的獲取到文檔的數量
  42.  
    // 有效的索引文檔
  43.  
    System.out.println( "有效的索引文檔:" + directoryReader.numDocs());
  44.  
    // 總共的索引文檔
  45.  
    System.out.println( "總共的索引文檔:" + directoryReader.maxDoc());
  46.  
    // 刪掉的索引文檔,其實不恰當,應該是在回收站里的索引文檔
  47.  
    System.out.println( "刪掉的索引文檔:" + directoryReader.numDeletedDocs());
  48.  
    } catch (Exception e) {
  49.  
    e.printStackTrace();
  50.  
    } finally {
  51.  
    try {
  52.  
    if (directoryReader != null) {
  53.  
    directoryReader.close();
  54.  
    }
  55.  
    } catch (Exception e) {
  56.  
    e.printStackTrace();
  57.  
    }
  58.  
    }
  59.  
    }
  60.  
     
  61.  
    /**
  62.  
    * 合並索引
  63.  
    */
  64.  
    public static void merge() {
  65.  
    IndexWriter indexWriter = null;
  66.  
    try {
  67.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  68.  
    Analyzer analyzer = new StandardAnalyzer();
  69.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  70.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  71.  
    // 會將索引合並為2段,這兩段中的被刪除的數據會被清空
  72.  
    /**
  73.  
    * 特別注意:
  74.  
    *
  75.  
    * 此處Lucene在3.5之后不建議使用,因為會消耗大量的開銷,Lucene會根據情況自動處理的
  76.  
    */
  77.  
     
  78.  
    // 把索引合並為兩段
  79.  
    indexWriter.forceMerge( 2);
  80.  
    } catch (Exception e) {
  81.  
    e.printStackTrace();
  82.  
    } finally {
  83.  
    try {
  84.  
    if (indexWriter != null) {
  85.  
    indexWriter.close();
  86.  
    }
  87.  
    } catch (Exception e) {
  88.  
    e.printStackTrace();
  89.  
    }
  90.  
    }
  91.  
    }
  92.  
     
  93.  
    /**
  94.  
    * 強制刪除
  95.  
    */
  96.  
    public static void forceDelete() {
  97.  
    IndexWriter indexWriter = null;
  98.  
    try {
  99.  
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath( "F:/test/lucene/index"));
  100.  
    Analyzer analyzer = new StandardAnalyzer();
  101.  
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  102.  
    indexWriter = new IndexWriter(directory, indexWriterConfig);
  103.  
    indexWriter.forceMergeDeletes();
  104.  
    } catch (Exception e) {
  105.  
    e.printStackTrace();
  106.  
    } finally {
  107.  
    try {
  108.  
    if (indexWriter != null) {
  109.  
    indexWriter.close();
  110.  
    }
  111.  
    } catch (Exception e) {
  112.  
    e.printStackTrace();
  113.  
    }
  114.  
    }
  115.  
    }

這些代碼和4.5版本差別不大,運行結果和4.5版本也是一樣的,就不再一一講解


免責聲明!

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



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