Java 为什么Lucene DirectoryReader在任何写入之前打开时看不到IndexWriter所做的任何更改?

Java 为什么Lucene DirectoryReader在任何写入之前打开时看不到IndexWriter所做的任何更改?,java,lucene,Java,Lucene,我正在尝试创建LuceneIndexWriter和DirectoryReader,并保持这两个版本的开放性,以备将来使用。如果在提交之前实例化了DirectoryReader,则故障-DirectoryReader不会看到提交到索引的任何更改 请参阅下面的代码: public class SearchLayer1 { private final RAMDirectory directory; private final IndexWriter indexWriter; pri

我正在尝试创建Lucene
IndexWriter
DirectoryReader
,并保持这两个版本的开放性,以备将来使用。如果在提交之前实例化了DirectoryReader,则故障-DirectoryReader不会看到提交到索引的任何更改

请参阅下面的代码:

public class SearchLayer1 {

   private final RAMDirectory directory;
   private final IndexWriter indexWriter;
   private final DirectoryReader directoryReader;

   public SearchLayer1() throws IOException {
      this.directory = new RAMDirectory();
      IndexWriterConfig config = new IndexWriterConfig(new SimpleAnalyzer());
      this.indexWriter = new IndexWriter(directory, config);
      this.directoryReader = DirectoryReader.open(indexWriter, false);
   }

   public void add() throws IOException, InterruptedException {
      Document doc = new Document();
      String text = "This is the text to be indexed.";
      doc.add(new StringField("fieldname", text, Field.Store.YES));
      indexWriter.addDocument(doc);
      indexWriter.commit();

      doc = new Document();
      doc.add(new StringField("fieldname", text, Field.Store.YES));
      indexWriter.addDocument(doc);
      indexWriter.commit();
   }


   public void experiment() throws IOException, ParseException {
      //IT WORKS IF THE DirectoryReader IS OPENED AFTER SOME DOCUMENTS ARE ADDED TO THE INDEX 
      //DirectoryReader directoryReader = DirectoryReader.open(indexWriter, false);
      IndexSearcher isearcher = new IndexSearcher(directoryReader);
      Query query = new TermQuery(new Term("fieldname", "This is the text to be indexed."));
      ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;

      for (int i = 0; i < hits.length; i++) {
         Document hitDoc = isearcher.doc(hits[i].doc);
         System.out.println("==========> " + hitDoc.get("fieldname"));
      }
      directoryReader.close();
   }

   public void close() throws IOException {
      indexWriter.close();

      directory.close();
   }
}
我希望“==========>这是要索引的文本。”打印两次,但除非我将DirectoryReader实例化向下移动到
experiment()
方法,否则不会打印

那么为什么DirectoryReader看不到任何提交?? 我正在使用lucene 5.3.1

附言
是的,我知道有些方法被弃用以及QueryParser的存在,请不要对此发表评论。

基本上,Lucene就是这样工作的。 如果您打开IndexReader(例如,通过
DirectoryReader.open
),您将获得在该特定时刻存在的索引的时间点视图,并且无论IndexWriter上的索引活动如何,该视图在再次打开IndexReader之前不会更改。 但不要只是关闭和打开然后再打开IndexReader。您要做的是重新打开现有的读卡器。这样,只打开新的段,可以重用现有段,而不是总是读取完整的索引(这是一个昂贵的操作)。 重新打开的代码如下所示(提示未更改的代码):

在每次搜索之前进行刷新,确保您始终可以看到 最新的更改,但刷新操作的成本可能相当高,尤其是在发生合并且必须打开大型段的情况下。 通常,您会有一个按一定间隔(例如每秒)运行刷新的调度线程

此外,处理刷新操作本身也是相当低级的。 在这种情况下,我建议的代码不涉及任何异常处理 必须关闭旧读取器或新读取器的正确实例 如果您有一个专用的刷新线程,您可以不关闭,而是
decRef
。建议使用
SearcherManager
来代替:

import org.apache.lucene.search.SearcherManager;
// ...

public class SearchLayer1 {
  // ...
  private final SearcherManager searcherManager;

  public SearchLayer1() throws IOException {
    // ...
    this.searcherManager = new SearcherManager(indexWriter, false, null);
  }

  // ...

  public void experiment() throws IOException {
    searcherManager.maybeRefresh();
    IndexSearcher isearcher = searcherManager.acquire();
    try {
      // ...
    } finally {
      searcherManager.release(isearcher);
    }
  }

  public void close() throws IOException {
    searcherManager.close();
    // ...
  }
}
同样,最好使用单独的线程进行定期刷新。
无论哪种方式,都能提供您所期望的输出。

在开始使用框架时,在任何常规参考资料中都没有提到SearcherManager的存在,这一点很有意思-非常感谢,这可能为我节省了很多时间
public class SearchLayer1 {
  // ...
  private DirectoryReader directoryReader;
  private IndexSearcher indexSearcher;

  public SearchLayer1() throws IOException {
    // ...
    this.directoryReader = DirectoryReader.open(indexWriter, false);
    this.indexSearcher = new IndexSearcher(directoryReader);
  }

  // ...

  private void refreshReader() throws IOException {
    DirectoryReader newReader = DirectoryReader.openIfChanged(this.directoryReader);
    if (newReader != null && newReader != this.directoryReader) {
      this.directoryReader.close();
      this.directoryReader = newReader;
      this.indexSearcher = new IndexSearcher(this.directoryReader);
    }
  }

  public void experiment() throws IOException {
    refreshReader();
    IndexSearcher isearcher = this.indexSearcher;
    // ...
  }

  public void close() throws IOException {
    directoryReader.close();
    // ...
  }
}
import org.apache.lucene.search.SearcherManager;
// ...

public class SearchLayer1 {
  // ...
  private final SearcherManager searcherManager;

  public SearchLayer1() throws IOException {
    // ...
    this.searcherManager = new SearcherManager(indexWriter, false, null);
  }

  // ...

  public void experiment() throws IOException {
    searcherManager.maybeRefresh();
    IndexSearcher isearcher = searcherManager.acquire();
    try {
      // ...
    } finally {
      searcherManager.release(isearcher);
    }
  }

  public void close() throws IOException {
    searcherManager.close();
    // ...
  }
}