zoukankan      html  css  js  c++  java
  • 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版本也是一样的,就不再一一讲解

  • 相关阅读:
    操作系统原理
    Linux三剑客正则表达式
    Linux通配符知识深度实践详解
    Linux文件属性之时间戳及文件名知识详解
    Linux系统文件权限
    date:显示与设置系统时间
    正则表达式--三剑客简单应用
    Linux习题小结
    Linux系统文件属性知识
    Linux系统目录结构知识
  • 原文地址:https://www.cnblogs.com/fan-yuan/p/9360438.html
Copyright © 2011-2022 走看看