【问题标题】:Lucene : very slow NRT performanceLucene:NRT 性能非常慢
【发布时间】:2014-06-05 17:01:27
【问题描述】:

我正在我的应用程序中测试 NRT(近乎实时)搜索的性能,我得到了非常奇怪的结果。我将此查询用作获取所有元素的示例(测试集非常小,因此获取所有元素不应该成为问题,这是仅索引 250 个文件,仅文本文件,总索引大小 = 1.5MB,我需要支持的真正集合是用于多 GB 索引的数百个文件)

这是让我担心的示例查询:

    public static List<IndexableItem> GetAllElements()
    {
        var qp = new Lucene.Net.QueryParsers.QueryParser(Lucene.Net.Util.Version.LUCENE_29, "ProviderPath", analyzer);
        qp.AllowLeadingWildcard = true;
        var query = qp.Parse("*");

        var searcher = new Lucene.Net.Search.IndexSearcher(reader);
        List<IndexableItem> docs = new List<IndexableItem>();
        searcher.Search(query, new SimpleHitCollector(docId =>
        {
            docs.Add(reader.Document(docId).ToIndexable());
        }));
        return docs;
    }

如您所见,它非常简单。此查询的运行时间约为 0.1 秒,而索引未运行,但如果我同时运行索引,它会上升到 . . . . 45 秒或更长时间!

reader 变量是这样定义的属性:

    public static IndexReader reader 
    {
        get 
        {
            return writer.GetReader();
        }
    }

作家:

    static SearchIndexManager()
    {
        writer = new IndexWriter(FSDirectory.Open(@"C:\MyFolder"), analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
    }

性能问题肯定在 lucene 内(它在 hitcollector 内,每个 docs.Add 行之间最多需要 1 秒)。 ToIndexable 也不是问题(这是一种微不足道的方法,完全不依赖于索引器可以使用的任何东西(磁盘 io 等)。

我很确定那里出了点问题,因为显然 NRT 的目标不是减速 450 倍,关于我应该在哪里寻找提示的任何建议?

更多信息:我不会在减速期间调用优化,并且“偶尔”即使在建立索引时我也会得到一个快速的答案,但当这种情况发生时它似乎很随机。我确实偶尔会调用一次提交(每 100 次插入)。

【问题讨论】:

  • 如果您在运行索引时得到不同的响应时间,那么我怀疑您是否在 NRT 中。
  • 实际上我发现了一些非常时髦的东西,如果我删除所有优化/提交的调用,那么索引会保留在 1 个文件中并不断增长(这是预期的行为),但是一旦我启动搜索,它分裂了,好像提交被强制了,有什么可能导致这种情况的线索吗?只有我链接的代码在搜索过程中被调用,它所做的一切都是由作者使用阅读器提供程序读取的,建议执行 NRT
  • 这段代码是否适合确定与索引同时进行的搜索性能?它将读取索引中的每个文档,以及每个文档的每个字段;在您的应用程序中可能永远不需要这些。许多场景只需要最多说 50 个搜索结果。如果索引未更改,则文档可能位于 I/O 缓存中并且可用速度非常快(first 搜索速度较慢)。如果更改了索引,则必须从磁盘重新加载文档 - 比缓存慢得多。
  • 它是相关的,是的,我确实显示了 1000 个搜索结果(它不是用于搜索引擎分页的 web 应用程序,而是用于具有高级预览的完整搜索客户端,人们可能想看看几百个结果)
  • 虽然我没有给你一个规范的答案,但有一些建议。您的测试代码为搜索找到的每个 docID 调用 IndexReader.Document:尝试加载 only docID 的列表(例如,IndexSearcher.Search 的另一个重载返回 ScoreDoc[])。然后只加载足够的IndexableItem 对象以填满您的高级预览的一屏(或两屏);对此进行测试以查看“按需加载”策略是否产生所需的性能。如果是这样,您可以延迟加载剩余的IndexableItem 对象,或者将高级预览实现为虚拟列表,即。 “按需加载”。

标签: c# .net lucene lucene.net


【解决方案1】:

据我了解,近实时搜索适用于已更改但尚未提交更改的索引,搜索时不会发生进一步更改。这是 NRT 的最佳用法,我并不是说搜索不能索引同时进行。如果搜索或阅读与索引同时发生,则它们是次优的。

考虑方法IndexReader.Reopen。它的目的是获得一个新的读者,如果索引正在改变或自从获得IndexReader 的旧实例以来已经改变。因此,如果您继续使用旧实例,您可能会错过您应该找到的文档,并且您正在从“移动目标”读取,因此性能缓慢。

你写道:

索引保留在 1 个文件中并不断增长(这是预期的行为),但一旦我启动搜索,它就会分裂,就像强制提交一样

当您从 IndexWriter 获得 IndexReader 时,它将刷新所有缓冲的更改 - 请注意,这不是提交。

【讨论】:

  • NRT 是为了让您可以一直搜索并从作者那里获取数据(无论是否提交),在我的情况下,当它没有索引时没有时间搜索,我总是索引,24/7,365/年,所以 NRT 听起来像是提供最近变化的明显选择。
  • 当我得到阅读器时,有什么办法让它根本不刷新磁盘的更改? (或者如果我这样做而不是让另一个读者重新打开会阻止这种情况吗?)
  • 是的,NRT 是显而易见的选择,也是我推荐的选择。 AFAIK 在调用GetReaderReopen 时无法阻止刷新(如果索引已更改)。我认为长时间的延迟是由于您经常致电Commit,这是一个缓慢的操作。为了加快搜索/显示结果,您可以减少提交或避免与索引同时进行的搜索,例如。如果搜索/显示处于活动状态,则延迟索引。为了加快搜索/显示结果,您可以减少提交或避免与索引同时进行的搜索,例如。如果搜索/显示处于活动状态,则延迟索引。
  • 如果我从不提交,我会找到完全相同的结果,因此即使我根本不提交,也不会因为问题发生而减少提交。无法单独对搜索/索引进行计时,索引始终运行,我无法控制人们何时搜索以及搜索频率,完全可以预期同一秒可能有几十个搜索,如果我执行得很好m 没有索引,但这不是一个选项
猜你喜欢
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 2012-06-15
  • 2018-06-07
相关资源
最近更新 更多