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版本也是一样的,就不再一一讲解

原文地址:https://www.cnblogs.com/fan-yuan/p/9360438.html