【问题标题】:How to delete Documents from a Lucene Index using Term or QueryParser如何使用 Term 或 QueryParser 从 Lucene 索引中删除文档
【发布时间】:2013-09-19 10:30:01
【问题描述】:

我正在尝试从 Lucene 索引中删除文档。 我只想从 lucene index 中删除指定的文件。

我的以下程序正在删除可以使用关键字分析器搜索的索引,但我需要的文件名只能使用 StandardAnalyzer 进行搜索。那么有什么方法可以在我的术语中设置标准分析器,或者我如何使用 QueryParser 从 lucene 索引中删除文档。

 try{
    File INDEX_DIR= new File("D:\\merge lucene\\abc\\");

    Directory directory = FSDirectory.open(INDEX_DIR);

     IndexReader indexReader = IndexReader.open(directory,false);
     Term term= new Term("path","fileindex23005.htm");
    int l=   indexReader.deleteDocuments(term);
                      indexReader.close();

    System.out.println("documents deleted");
  }
  catch(Exception x){x.printStackTrace();}

【问题讨论】:

    标签: lucene indexing


    【解决方案1】:

    我假设您使用的是 Lucene 3.6 或更早版本,否则 IndexReader.deleteDocuments 将不再存在。但是,无论如何,您应该使用 IndexWriter。

    如果您只能使用查询解析器找到文档,则只需运行普通查询,然后遍历返回的文档,并通过 docnum 将其删除,大致如下:

    Query query = queryParser.parse("My Query!");
    ScoreDoc[] docs = searcher.search(query, 100).scoreDocs;
    For (ScoreDoc doc : docs) {
        indexReader.deleteDocument(doc.doc);
    }
    

    或者更好(更简单,使用未失效、未弃用的功能),只需使用IndexWriter,并直接将查询传递给它:

    Query query = queryParser.parse("My Query!");
    writer.deleteDocuments(query);
    

    【讨论】:

    • 它删除了旧文档但索引文件的大​​小没有减少
    • 是的,删除不会立即从文件结构中消除。它们暂时缓冲在内存中(在IndexWriterConfig 中控制),然后有效地标记为已删除。最终删除将从索引中刷新,如您的MergePolicy 中所指定。删除可能是一项代价高昂的操作,我不建议尝试将其设置为每次收到删除时都进行合并,尤其是在删除是相当常见的操作时。
    • @femtoRgon 从索引文件中删除文档后,如果我查询索引,它是否也会返回已删除的记录?
    • @Shankar 如果你删除,然后 index.Commit(),删除会反映在从所述索引创建的任何新读者中 - 删除的记录将不会被返回。
    【解决方案2】:

    为像我这样的人添加以供将来参考,删除文档在 indexWriter 上,您可以使用

    indexWriter.deleteDocuments(Term... terms)

    而不是使用 deleteDocuments(query) 方法;如果您只需要匹配一个字段,则可以减少麻烦。 请注意,如果传递了多个术语,此方法会将术语视为 OR 条件。因此它将匹配任何术语并删除所有记录。下面的代码将匹配存储的文档中的 state=Tx 并删除匹配的记录。

      indexWriter.deleteDocuments(
            new Term("STATE", "Tx")
          );
    

    为了将不同的字段与AND条件组合,我们可以使用以下代码:

     BooleanQuery.Builder builder = new BooleanQuery.Builder();
    
    //note year is stored as int , not as string when document is craeted.
    //if you use Term here which will need 2016 as String, that will not match with documents stored with year as int.
     Query yearQuery = IntPoint.newExactQuery("year", 2016);
     Query stateQuery = new TermQuery(new Term("STATE", "TX"));
     Query cityQuery = new TermQuery(new Term("CITY", "CITY NAME"));
    
     builder.add(yearQuery, BooleanClause.Occur.MUST);
     builder.add(stateQuery, BooleanClause.Occur.MUST);
     builder.add(cityQuery, BooleanClause.Occur.MUST);
    
     indexWriter.deleteDocuments(builder.build());
    

    【讨论】:

    • 我正在添加一个唯一字段为doc.add(new TextField("uid", product.getUid(), Field.Store.YES));,但是当我尝试删除文档时,Term term = new Term("uid", uniqueId); getIndexWriter().deleteDocuments(term); 引发了 NPE,我尝试了 TextFieldStringField,并且都给出了 NPE .请问我哪里错了。使用 Lucene 5.4
    【解决方案3】:

    正如@dillippattnaik 指出的那样,多个术语导致OR。我已经更新了他的代码,使其 AND 使用 BooleanQuery:

    BooleanQuery query = new BooleanQuery
    {
       { new TermQuery( new Term( "year", "2016" ) ), Occur.MUST },
       { new TermQuery( new Term( "STATE", "TX" ) ), Occur.MUST },
       { new TermQuery( new Term( "CITY", "CITY NAME" ) ), Occur.MUST }
    };
    
    indexWriter.DeleteDocuments( query );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      相关资源
      最近更新 更多