FieldCache经常更新索引

你好
我有经常用新记录更新的lucene索引,我的索引中有5,000,000条记录,并且我使用FieldCache缓存了我的一个数字字段。 但是在更新索引后需要时间再次重新加载FieldCache(重新加载缓存导致文档说DocID不可靠)所以如何通过向FieldCache添加新添加的DocID来最小化这种开销,导致此function转为我的瓶颈应用。

IndexReader reader = IndexReader.Open(diskDir); int[] dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This line takes 4 seconds to load the array dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // this line takes 0 second as we expected // HERE we add some document to index and we need to reload the index to reflect changes reader = reader.Reopen(); dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This takes 4 second again to load the array 

我想要一种机制,通过在我们的数组中只添加新添加的文档到索引来最小化这个时间,有一种技术,如http://invertedindex.blogspot.com/2009/04/lucene-dociduid-mapping-and-payload。 html提高性能,但它仍然加载我们已经拥有的所有文档,我认为如果我们找到一种方法只添加新添加的文档到arrays,则无需重新加载它们

FieldCache使用对索引读取器的弱引用作为其缓存的键。 (通过调用未被废弃的IndexReader.GetCacheKey 。)使用FSDirectoryIndexReader.Open进行标准调用将使用一个读取器池,每个段一个。

您应该始终将最里面的读者传递给FieldCache。 查看ReaderUtil以获取一些帮助程序,以检索包含文档的单个阅读器。 文档ID不会在一个段内发生变化,它们在将其描述为不可预测/不稳定时的含义是它将在两个索引提交之间发生变化。 已删除的文档可能已被删除,段已合并,以及此类操作。

提交需要从磁盘中删除段(合并/优化),这意味着新读者不会拥有池化段读取器,并且垃圾收集将在所有旧读取器关闭后立即将其删除。

永远不要调用FieldCache.PurgeAllCaches() 。 它用于测试,而不是生产用途。

新增2011-04-03; 使用子读取器的示例代码。

 var directory = FSDirectory.Open(new DirectoryInfo("index")); var reader = IndexReader.Open(directory, readOnly: true); var documentId = 1337; // Grab all subreaders. var subReaders = new List(); ReaderUtil.GatherSubReaders(subReaders, reader); // Loop through all subreaders. While subReaderId is higher than the // maximum document id in the subreader, go to next. var subReaderId = documentId; var subReader = subReaders.First(sub => { if (sub.MaxDoc() < subReaderId) { subReaderId -= sub.MaxDoc(); return false; } return true; }); var values = FieldCache_Fields.DEFAULT.GetInts(subReader, "newsdate"); var value = values[subReaderId]; 

这是我解决这个问题的一种方法。 您需要创建一个后台线程来构建IndexSearcher实例,在某个时间间隔内一次创建一个。 继续使用当前的IndexSearcher实例,直到后台线程中的新实例准备好。 然后换掉新的那个作为你当前的那个。 每个实例都充当索引的第一次打开时的快照。 请注意, FieldCache的内存开销加倍,因为您一次需要在内存中有两个实例。 在发生这种情况时,您可以安全地写入IndexWriter

如果您需要,可以通过立即使用索引更改进行搜索来更进一步,尽管它可能会变得棘手。 您需要将RAMDirectory与上面的每个快照实例相关联,以保持内存中的更改。 然后创建指向该RAMDirectory的第二个IndexWriter 。 对于每个索引写入,您需要写入两个IndexWriter实例。 对于搜索,您将在RAMDirectory使用RAMDirectory ,在磁盘上使用普通索引。 一旦与其耦合的IndexSearcher不再使用, RAMDirectory就可以被丢弃。 我在这里讨论一些细节,但这是一般的想法。

希望这可以帮助。