Lucene NET throwing Fatal Error: AccessViolationException
Lucene NET throwing Fatal Error: AccessViolationException
我正在使用 Lucene NET v4.8 beta,我有一个方法每 5 秒在 SearcherManager 上调用 MaybeRefresh。 99.9% 的时间,一切正常。但是,在 0.1% 的情况下,我会收到致命的 AccessViolationException 错误。我不确定是什么导致了这个致命错误。这是完整的堆栈跟踪:
at System.IO.UnmanagedMemoryAccessor.ReadByte(Int64)
at Lucene.Net.Store.BufferedChecksumIndexInput.ReadByte()
at Lucene.Net.Store.DataInput.ReadInt32()
at Lucene.Net.Index.SegmentInfos+FindSegmentsFile.Run(Lucene.Net.Index.IndexCommit)
at Lucene.Net.Index.SegmentInfos.Read(Lucene.Net.Store.Directory)
at Lucene.Net.Index.StandardDirectoryReader.IsCurrent()
at Lucene.Net.Index.StandardDirectoryReader.DoOpenNoWriter(Lucene.Net.Index.IndexCommit)
at Lucene.Net.Index.DirectoryReader.OpenIfChanged(Lucene.Net.Index.DirectoryReader)
at Lucene.Net.Search.SearcherManager.RefreshIfNeeded(Lucene.Net.Search.IndexSearcher)
at Lucene.Net.Search.ReferenceManager`1[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].DoMaybeRefresh()
at Lucene.Net.Search.ReferenceManager`1[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MaybeRefresh()
...my method that calls MaybeRefresh...```
请注意:
我有 2 个独立的服务。一项服务通过 IndexWriter(服务 A)定期写入索引,另一项服务搜索索引并每 5 秒调用一次 MaybeRefresh(服务 B)。是服务 B 看到了这个致命错误。服务 A 工作正常,没有任何错误。所以我认为这与服务 B 有关,但为了完全透明而提及这一点,以防我遗漏了什么。
如果有人能深入了解这个由 Lucene 方法引起的致命错误,我们将不胜感激!
还请让我知道我应该添加的任何其他详细信息来描述此错误,如果有帮助的话。
首先,错误消息很可能表明您在同一组索引文件上多次打开 MMapDirectory
,并且您遇到异常是因为两个实例都写入同一内存 space。不知道算不算BUG,不过需要注意的是写的时候不需要开RAM-intensiveMMapDirectory
,直接用[=13就可以了=].
Directory dir = new SimpleFSDirectory(filePath);
话虽如此,以下建议将使上述观点变得毫无意义。
选项 1
通常情况下,您应该将打开单个索引的进程数限制为 1。如果您需要在读取发生的同时进行写入,则可以使用 near real-time search feature of Lucene.
执行此操作涉及的步骤是:
- 打开一个
IndexWriter
并保持打开状态(注册为单例)。
- 使用
IndexWriter
作为参数创建一个 SearcherManager
(或者使用 writer.GetReader()
)。
- 使用
SearcherManager
进行搜索。
- 使用
IndexWriter
进行索引操作。
Commit()
索引后。
- 添加文档后调用
searcherManager.MaybeRefresh()
。
正如链接教程中所指出的,您可以使用 ControlledRealTimeReopenThread
在后台定期刷新 IndexReader
。
最后,要解决打开多个 Directory
实例的问题(这是最终导致此问题的原因),请使用单个进程进行写入和读取。由于写入通常比读取发生的频率低,我建议在搜索服务中执行所有这些操作,然后使用网络套接字(TCP、HTTP 等)从写入服务向搜索服务发送消息,以便写入 to/update/delete 来自索引。
选项 2
如果你想在多个进程中打开同一个索引,你可以使用Lucene.Net.Replicator模块用一个服务编写你的索引,然后发布它以复制到其他服务。 Lucene.Net.Replicator
通常推荐用于跨网络场中的多个节点复制相同的索引,但也可用于在一个服务中写入索引并在另一个服务中读取它。本质上,对于您的用例,您的每一项服务都有一个单独的索引目录。
但是,它还需要您构建一个网络服务来发布更新。主要区别是您不需要为 write/update/delete 索引设计专门的网站 API,而是可以使用现有的 API 在编写索引后发布索引。
参考文献:
- Lucene real-time indexing?
我正在使用 Lucene NET v4.8 beta,我有一个方法每 5 秒在 SearcherManager 上调用 MaybeRefresh。 99.9% 的时间,一切正常。但是,在 0.1% 的情况下,我会收到致命的 AccessViolationException 错误。我不确定是什么导致了这个致命错误。这是完整的堆栈跟踪:
at System.IO.UnmanagedMemoryAccessor.ReadByte(Int64)
at Lucene.Net.Store.BufferedChecksumIndexInput.ReadByte()
at Lucene.Net.Store.DataInput.ReadInt32()
at Lucene.Net.Index.SegmentInfos+FindSegmentsFile.Run(Lucene.Net.Index.IndexCommit)
at Lucene.Net.Index.SegmentInfos.Read(Lucene.Net.Store.Directory)
at Lucene.Net.Index.StandardDirectoryReader.IsCurrent()
at Lucene.Net.Index.StandardDirectoryReader.DoOpenNoWriter(Lucene.Net.Index.IndexCommit)
at Lucene.Net.Index.DirectoryReader.OpenIfChanged(Lucene.Net.Index.DirectoryReader)
at Lucene.Net.Search.SearcherManager.RefreshIfNeeded(Lucene.Net.Search.IndexSearcher)
at Lucene.Net.Search.ReferenceManager`1[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].DoMaybeRefresh()
at Lucene.Net.Search.ReferenceManager`1[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MaybeRefresh()
...my method that calls MaybeRefresh...```
请注意:
我有 2 个独立的服务。一项服务通过 IndexWriter(服务 A)定期写入索引,另一项服务搜索索引并每 5 秒调用一次 MaybeRefresh(服务 B)。是服务 B 看到了这个致命错误。服务 A 工作正常,没有任何错误。所以我认为这与服务 B 有关,但为了完全透明而提及这一点,以防我遗漏了什么。
如果有人能深入了解这个由 Lucene 方法引起的致命错误,我们将不胜感激!
还请让我知道我应该添加的任何其他详细信息来描述此错误,如果有帮助的话。
首先,错误消息很可能表明您在同一组索引文件上多次打开 MMapDirectory
,并且您遇到异常是因为两个实例都写入同一内存 space。不知道算不算BUG,不过需要注意的是写的时候不需要开RAM-intensiveMMapDirectory
,直接用[=13就可以了=].
Directory dir = new SimpleFSDirectory(filePath);
话虽如此,以下建议将使上述观点变得毫无意义。
选项 1
通常情况下,您应该将打开单个索引的进程数限制为 1。如果您需要在读取发生的同时进行写入,则可以使用 near real-time search feature of Lucene.
执行此操作涉及的步骤是:
- 打开一个
IndexWriter
并保持打开状态(注册为单例)。 - 使用
IndexWriter
作为参数创建一个SearcherManager
(或者使用writer.GetReader()
)。 - 使用
SearcherManager
进行搜索。 - 使用
IndexWriter
进行索引操作。 Commit()
索引后。- 添加文档后调用
searcherManager.MaybeRefresh()
。
正如链接教程中所指出的,您可以使用 ControlledRealTimeReopenThread
在后台定期刷新 IndexReader
。
最后,要解决打开多个 Directory
实例的问题(这是最终导致此问题的原因),请使用单个进程进行写入和读取。由于写入通常比读取发生的频率低,我建议在搜索服务中执行所有这些操作,然后使用网络套接字(TCP、HTTP 等)从写入服务向搜索服务发送消息,以便写入 to/update/delete 来自索引。
选项 2
如果你想在多个进程中打开同一个索引,你可以使用Lucene.Net.Replicator模块用一个服务编写你的索引,然后发布它以复制到其他服务。 Lucene.Net.Replicator
通常推荐用于跨网络场中的多个节点复制相同的索引,但也可用于在一个服务中写入索引并在另一个服务中读取它。本质上,对于您的用例,您的每一项服务都有一个单独的索引目录。
但是,它还需要您构建一个网络服务来发布更新。主要区别是您不需要为 write/update/delete 索引设计专门的网站 API,而是可以使用现有的 API 在编写索引后发布索引。
参考文献:
- Lucene real-time indexing?