专用写进程,在另一个进程中只有读取器

本文关键字:进程 读取 另一个 专用 | 更新日期: 2023-09-27 18:02:56

我正在做一个ASP。. Net MVC 5应用程序,使用Lucene.net实现全文搜索。

由于在ASP中托管后台任务的潜在问题。在网上,我正在考虑以下场景是否可行:

  1. 将唯一的Lucene写入器移动到一个专门的进程,该进程定期检查数据库中未索引的行并相应地更新Lucene索引
  2. 将阅读器保存在ASP中。. NET工作进程

使用FSDirectory是否有效?

专用写进程,在另一个进程中只有读取器

我认为这是可能的。你可以同时拥有多个indexreader,这应该没问题,它甚至有一个外部锁特性(基于文件系统)用于多进程锁定。

记住,IndexReader会从创建时开始搜索当前的"快照",所以当索引发生变化时,你应该找到一种方法来"转储"IndexReader。当然,您可以为每个搜索创建一个IndexReader,但可能不建议这样做,如果您当前正在写入索引,则会失败。出于这些目的,您可以从当前的写入器中检索读取器,但这不是您的选择,因为它们将驻留在不同的进程中。

您可能也会觉得这篇文章很有趣:

http://devlearnings.wordpress.com/2010/04/26/lucene-reuse-indexsearcher-rather-creating-new-everytime/

在我为这个项目编写的一个小助手类的帮助下,我已经设法使这个工作很好。下面的工厂类与任意数量的线程共享一个indexReader,并确保从GetCurrentReader()返回的reader与索引的状态保持同步。

class IndexReaderFactory :
  IDisposable
{
  public IndexReaderFactory(bool isReadonly)
  {
    this.isReadonly = isReadonly;
  }
  IndexReader reader;
  readonly ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
  private readonly bool isReadonly;
  /// <summary>
  /// Returns a reader that isCurrent
  /// </summary>
  public IndexReader GetUpToDateReader()
  {
    rwl.EnterUpgradeableReadLock();
    try
    {
      if (reader == null)
      {
        rwl.EnterWriteLock();
        try
        {
          if (logger.IsInfoEnabled)
            logger.Info("Creating IndexReader on directory {0}", AppSettingsBase.LucenePostIndexLocation);
          reader = IndexReader.Open(FSDirectory.Open(AppSettingsBase.LucenePostIndexLocation), isReadonly);
        }
        finally
        {
          rwl.ExitWriteLock();
        }
      }
      else if(!reader.IsCurrent())
      {
        rwl.EnterWriteLock();
        try
        {
          if (logger.IsInfoEnabled)
            logger.Info("IndexReader is not current. Re-opening");
          reader = reader.Reopen();
        }
        finally
        {
          rwl.ExitWriteLock();
        }
      }
    }
    finally 
    {
      rwl.ExitUpgradeableReadLock();
    }
    return reader;
  }
  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
  public void Dispose(bool disposing)
  {
    if (disposing)
    {
      // get rid of managed resources
    }
    if(reader != null)
      reader.Dispose();
  }
}