【问题标题】:Performance tuning for searching搜索性能调优
【发布时间】:2017-12-22 04:32:02
【问题描述】:

我对 DS 和算法还很陌生,最近在一次工作面试中,我被问到一个关于性能调整和代码的问题。我们有一个包含数十亿条目的数据结构,我们需要在该数据结构中搜索特定的单词。那么我们可以使用哪个 Java 功能/库来尽可能快地进行搜索?

当场我想不出确切的答案,所以我写道:

  1. 我们可以将值存储在 map 中并在 map 中搜索单词(但卡住了如何确定 map 中的键值对)。

我如何才能理解这个问题的确切答案以及最佳解决方案是什么?

【问题讨论】:

  • 我认为你的回答是合理的。地图具有恒定的查找时间,因此拥有大量条目不应影响此性能。如果您查找某个键但找不到任何内容,则它不在地图中。
  • @meriton 我想我忽略了存储数据的大小。但是对于没有这种内存要求的数据集,映射对我来说似乎是合理的。另外,尽量避免称其他人的工作“不好”。
  • @Zachary 不,我可能很沮丧。没想过压得更紧。是的,但现在我可以看到这个问题在某种程度上并不完整。
  • 请始终记得回来并为有帮助的答案投票,并接受您认为总体上最有帮助的答案。这就是我们在这里说“谢谢”的方式:)
  • 当然@ray我的坏:)

标签: java performance data-structures


【解决方案1】:

在阅读问题并在 cmets 中得到澄清后,我认为对我来说显而易见的是:您需要提出后续问题

我会尝试将其分解并提供我希望对您有所帮助的 cmets,因为我也知道“当下”是什么感觉,以及当您最不需要的时候神经会如何刺伤您的背部.

我们有一个包含数十亿条目的数据结构,我们需要在该数据结构中搜索特定的单词。

我认为一个很好的后续问题应该是:

问:什么特定的数据结构被用来包含所有这些数据?

我会一直按,直到他们给我一个实际名称并解释为什么不能命名一个 Java 算法/库。如你所知,数据结构可能是String[]Set<String>,甚至是磁盘上文件的花哨名称(如果他们想把你赶走的话)。他们也可以澄清并说 DS 不相关,您可以选择 认为最好的任何 DS。

措辞还暗示他们实现了该结构,并且它已经填充在一个系统中,并且大概有足够的内存来容纳所有这些。要求确认这是真的案例,本可以为您提供有用的信息。

例如:“根据措辞,这个神秘的数据结构似乎已经实现并完全填充在一个有足够内存的系统的内存中。你能确认我的理解是正确的吗?如果不是,您能否进一步澄清一下?”

考虑到建议的措辞,以及我们没有额外的说明的事实,我将假设,为了这个答案,我的假设确实是正确的。 p>

请注意,如果你被要求设计数据结构来保存所有这些信息,你将不得不问非常不同的问题,考虑内存限制,甚至可能询问字符集/编码(例如 ASCII 与多字节 Unicode)。

此外,如果您被要求设计搜索算法,那么了解 DS 是先决条件,而不知道这一点可能会使这项任务变得不可能。例如,如果您使用数组和二叉搜索树,二叉搜索算法的实现看起来会非常不同,尽管两者都会提供 O(lg n) 时间复杂度。

那么我们可以使用哪个 java 特性/库来尽可能快地进行搜索?

与第一部分一致,此问题仅询问您会选择哪些预先存在/内置的 Java 代码来执行搜索。这里的“可能的最快时间”应该让您考虑 O(1) 中的解决方案,即恒定时间。但是,数据结构可能会为您打开/关闭大门。

Java 中的一些搜索算法适用于泛型,而另一些则适用于其他类型,例如数组。一些算法适用于Maps,而另一些则适用于Lists、Sets,等等。第一部分的后续问题可能有助于回答这个问题。

也就是说,即使你知道DS,但当时想不出具体的方法名称之类的,我也认为提到接口或至少是相关的包并说如果您需要更具体的说明,可以在 Java 文档中查看更多详细信息,因为这就是它的用途。

我们可以将值存储在地图中并在地图中搜索单词(但卡住了如何确定地图中的键值对)。

鉴于措辞,我对他们问题的解释是不是“您将使用哪种数据结构?”,而是“您会选择哪种预先存在的搜索算法?”。在我看来,他们似乎需要回答有关 DS 的问题。

也就是说,如果您确实被问到“您将使用哪种数据结构?”,那么 Map 仍然对您不利,因为您实际上并不需要 映射 值的键。您只需要存储一个值(即单词)。因此,Set,特别是HashSet,会是一个更好的选择,因为它还可以避免重复,并且应该在进程中消耗更少的内存,因为它存储奇异值,而不是键/值对。

当然,这仍然是基于我之前所做的假设。如果内存限制被认为是一个问题,那么水平扩展至多台服务器等可能是必要的。

我如何才能理解这个问题的确切答案以及最佳解决方案是什么?

考虑到他们给你的信息不足,他们可能想看看你是否会跟进问题。

【讨论】:

    【解决方案2】:

    假设内存需求不是问题并且数据结构已经填充,有几个数据结构可以实现高效搜索。

    关于时间复杂度,Set#containsMap#containsKey 都是 O(1),假设哈希函数不昂贵并且没有太多冲突。

    因为数据结构存储单词(假设您指的是Strings),那么使用trie(基数树、前缀树等)也可能相对有效,这将允许您按字符搜索(我相信是O(log n))。如果哈希函数很昂贵或有很多冲突,这可能是一个不错的选择!

    你给面试官的答案应该足够了,因为散列是一种有效的搜索方法,即使对于数十亿个条目也是如此。

    【讨论】:

    • 是的,即使我也这么认为,但他拒绝了我,主要原因是这个问题。所以我想在这里问它,然后理解相同。
    • 他们是否进一步解释了您的答案被拒绝的原因?如果碰撞是问题所在,那么他们可能正在寻找一个 trie。
    • @mr.cool 请编辑您的 OP 以提及提供给您的理由,作为他们拒绝您对此问题的回答的理由(如果有)。如果没有给出,也请注意。这可能有助于为其他人指明正确的方向。
    • @ray 没有给出原因是问题所在。他们只是告诉我,我没有资格,因为我无法回答性能调整问题。嗯
    • 虽然散列是一种有效的搜索方法,但SetMap 将整个数据保留在 Java 堆中,它的可扩展性不足以容纳数十亿个条目。
    【解决方案3】:

    您没有提及条目是单词还是文档(多个单词)。在这两种情况下,search index 都可能适合。

    搜索索引从十亿个文档条目中提取单词,并管理这些单词到所使用文档的映射。像 Lucene 之类的框架(例如作为 SOLR 或 ElasticSearch 的一部分)为您管理内存和持久性。

    如果只有数千个条目,一个简单的 HashMap 就足够了,因为那时不需要内存管理。如果所有十亿个条目都是单个单词,那么数据库可能是更好的选择。

    【讨论】:

    • 是的,他确实提到了。 “我们有一个包含数十亿条目的数据结构,我们需要在该数据结构中搜索特定的单词
    • 这不能回答我的问题!很明显,他想搜索单词。可以在一组单词或一组文档中搜索特定单词。而后者更为常见。
    • 您的陈述是:“您没有提及条目是文字还是文档”。我从中得到的是,您不知道是否要求 OP 搜索 wordsdocuments (即条目 are文件本身)。如果这不是您的意思,那么您不应该将文档称为条目。另外,我要说的是 OP 确实 声明他正在数据结构中搜索 words,而不是文档。这些词来自 的来源并不相关,而且这个问题甚至没有暗示我们应该关注它。
    • 请再次阅读我的声明。我希望给定的场景应该搜索包含某个单词的文档(来自给定的数据结构)(一个单词的全文搜索)。这种搜索的结果是一组文档。另一个场景(在一组词中搜索词)没有实际的商业价值。这样的搜索结果是truefalse,它大多毫无价值,所以我强烈怀疑数据结构条目不是单词而是文档。
    • 这真是令人毛骨悚然。我提到了 Lucene、ElasticSarch 和 SOLR(java 框架)。你没有! OP告诉我们采访。我的假设与 Aarishs 相同。你的假设是采访中指定的所有内容都张贴在这里。也许OP遗漏了这个详细信息?因此,请等待 OP 的反馈进行澄清。
    【解决方案4】:

    正如其他人所说,hashmap 解决方案是合理的,但在可扩展性方面存在疑问。

    这是一个可能的解决方案,如下文所述

    1. 子字符串匹配 如果您的条目 blob 是单个字符串或单词(没有任何空格)并且您需要在其中搜索任意子字符串。在这种情况下,您需要解析每个条目以找到匹配的最佳条目。一种使用像 Boyer Moor 算法这样的算法。有关详细信息,请参阅 thisthis。这也等同于 grep - 因为 grep 在内部使用类似的东西

    2. 索引搜索。在这里,您假设条目包含一组单词,并且搜索仅限于固定的单词长度。在这种情况下,条目被索引在所有可能出现的单词上。这通常称为“全文搜索”。有许多算法可以做到这一点,也有许多可以直接使用的开源项目。其中许多还支持通配符搜索、近似搜索等,如下所示: 一种。 Apache Lucene:http://lucene.apache.org/java/docs/index.html 湾。 OpenFTS:http://openfts.sourceforge.net/ C。狮身人面像http://sphinxsearch.com/

    如果您需要“固定词”作为查询,最有可能的是,方法二将非常快速有效

    参考 - https://softwareengineering.stackexchange.com/questions/118759/how-to-quickly-search-through-a-very-large-list-of-strings-records-on-a-databa

    【讨论】:

      【解决方案5】:

      数十亿条目位于可能存储在主内存中的边缘(例如,以每个条目 100 字节存储 100 亿个条目将占用 1000 GB 主内存)。

      虽然将数据存储在主内存中提供了非常高的吞吐量(每秒数千到数百万个请求),但您可能需要特殊的硬件(典型的刀片服务器仅提供 16 GB,但有些商品服务器允许安装高达 3000 GB 的主内存)。此外,在 Java 堆中保留这么多数据可能会导致垃圾收集器暂停数秒或数分钟,除非特别小心。

      因此,除非您的数据结构在主内存中允许非常紧凑的表示(例如,您只需要在 int 之间进行成员资格检查,这对于 512 MB 位集是可能的),否则您不会希望将其存储在 main内存,但在磁盘上。

      因此,您需要坚持不懈。任何关系或 NoSQL 数据库都允许通过键进行高效搜索,并且可以轻松处理如此大量的数据。要与关系数据库通信,请使用 JPAJDBC。要与非关系型数据库通信,您可以使用其专有的 Java API 或抽象层,例如 Spring Data

      如果您愿意,您也可以从头开始实现持久性(即面试官要求这样做)。 B-Tree 是一种针对在外部内存中高效查找而优化的数据结构,这是许多数据库内部使用的 :-)

      【讨论】:

      • 我不认为这篇文章实际上试图回答这个问题。请确保答案与实际问题相关:“那么我们可以使用哪个 Java 功能/库在尽可能快的时间内进行搜索?”
      • 答案是“任何与关系或 NoSQL 数据库对话的库”。你想让我列举一下吗?
      • 我认为您不需要枚举它们,而且我不确定该语句是否保存了这篇文章。此外,只是说这相当于挥手 b/c 它并没有回答太多。顺便说一句,我没有DV。实际上,我在等着看是否在投票前进行了使这篇文章相关的编辑。
      • 好的,我提到了一些库,但关键点仍然存在:这可能是一个棘手的问题,用于确定 OP 是否知道堆内存是有限的。 OP 不是,也没有得到这份工作。也许这个答案向他说明了原因。
      • 我不太确定这个响应究竟是如何向 OP 展示您声称的功能的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-25
      • 2014-03-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      相关资源
      最近更新 更多