频繁更新lucene索引会导致性能下降

时间:2016-01-28 05:06:15

标签: c#-4.0 sql-server-2012 lucene.net

我正在尝试在我的项目中添加lucene.net,搜索更复杂的数据。但事务(或表经常修改,如插入新数据或修改lucene索引中使用的字段)。

在这里使用lucene.net搜索是否很好?

如何找到修改过的字段&更新到已创建的特定lucene索引? Lucene索引包含从表中删除的文档,然后如何从lucene索引中删除它们?

正在加载,

  1. 我删除了基于唯一字段
  2. 的表格中没有的索引
  3. 如果索引不存在则插入,否则更新匹配表唯一字段的所有索引
  4. 在加载页面时,由于我的删除/插入/更新索引方法调用,它比平时花费的时间更长。

    我该如何处理?

2 个答案:

答案 0 :(得分:2)

Lucene非常适合此类功能。它完全是线程安全的......如果你以正确的方式使用它。

解决方案指针

创建一个IndexWriter并将其保存在全局可访问的单例中(全局静态变量或通过依赖注入)。 IW完全是线程安全的。 从不在同一文件夹上打开多个IW。

通过此单例执行所有更新/删除。 (我有一个项目正在做100个操作/秒,没有任何问题,即使在稍微糟糕的硬件上也是如此)。

根据更改的频率和应用程序可接受的延迟,您可以:

  • 每次更新数据库时都会向索引发送更新/删除
  • 保留已更改的行和删除的“事务日志”或队列(可能在同一个数据库中)(否则将跟踪)。然后通过使用日志/队列来更新索引。

要搜索,请使用searcher = new IndexSearcher(writer.GetReader())创建IndexSearcher。这是NRT(近实时)模式的一部分。 从不在由IW打开的索引文件夹上创建单独的IndexReader。

根据您的使用模式,您可能希望在发生的更改和搜索“可见”的更改之间引入一段“延迟”...

IS的实例也是线程安全的。因此,您还可以保留一个IS实例,通过该实例进行所有搜索。然后定期重新创建它(例如使用计时器),然后使用Interlocked.Exchange交换它。

我之前创建了一个小框架,将其与应用程序隔离开来并使其可重用。

<强>买者

话虽如此......在IIS内部托管这确实会引发一些问题。 IIS偶尔会重启您的应用。也是(默认情况下)在停止现有实例之前启动新实例,然后交换它们(这样你就看不到新实例的启动时间了。)

因此,在短时间内会有两个作者实例(这很糟糕!)

您可以告诉IIS禁用“重叠”或增加重新启动之间的时间。但这会引起其他副作用。

因此,您实际上最好创建一个单独的服务来托管您的lucene位。一个简单的自托管WebAPI Windows服务非常理想且非常简单。这也使您可以更好地控制索引文件夹的位置以及在不同计算机上托管它的能力(隔离磁盘IO负载)。并且意味着可以从系统的其他部分访问服务,单独测试等等

为什么这比其他服务建议的“更好”?

这是一个选择问题。我是ElasticSearch的忠实粉丝。它解决了规模和弹性方面的许多问题。它还使用了最新版本的Java Lucene,它在功能和性能方面远远领先于lucene.net。 (其他两个也一样)。

但是,ES和Solr是Java(对您来说可能是也可能不是问题)。 AzureSearch托管在Azure中,这可能也可能不是问题。

这三项都需要攀登学习曲线,并需要基础设施支持或外部第三方SaaS承诺。

如果您将服务保留在内部和c#中,它会保持简单,您可以控制功能,并且可以根据您的需求调整API的形状。

没有“正确”的答案。你必须根据自己的情况做出选择。

答案 1 :(得分:1)

您应该根据某些时间表(定期)优先编制索引。最简单的方法是保留最后一个索引的日期,然后查询此后的所有更改并索引新记录,更新和删除记录。为了跟踪数据库中已删除的条目,您需要记录已删除的记录以及删除的日期。然后,您可以使用该日期查询需要从lucene中删除的内容。

现在每2分钟左右就完成一次这项工作。

也就是说,Lucene.net并不适合Web应用程序,您应该考虑使用ElasticSearch,SOLR或AzureSearch。基本上可以更好地处理负载和多线程的服务器。