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