在 C# 中使用非常大的 Dictionary<>

Posted

技术标签:

【中文标题】在 C# 中使用非常大的 Dictionary<>【英文标题】:Working with very large Dictionary<> in C# 【发布时间】:2014-01-02 16:46:00 【问题描述】:

我正在实现一种搜索类型 (TF-IDF),其中每个单词的计算分数都与正在搜索的所有文档成正比。我有 100GB 的文档要搜索。

如果我使用 1GB 的文档,我会使用:

Dictionary<string, List<Document>>

..其中string 是单词,List&lt;Document&gt; 是所有文档,按顺序排列,包含该单词。这不会扩大规模。我使用的是Dictionary&lt;&gt;,因为查找时间是 O(1)(理论上)。

我想要的解决方案是一个 SQLServer 数据库,其中单词被列在一个表中,相关的 List 对象被序列化存储。我担心的是每次读取数据库并重建到List&lt;&gt; 效率会非常低。

我是不是走错了方向?处理庞大字典的正常解决方案是什么?

【问题讨论】:

我会考虑使用磁盘支持的存储机制:请参阅各种 Hash/Hierarchial “NoSQL”选项。 我会让其他人回答你的问题,但我建议使用 MongoDB 来解决这个问题。它的创建正是考虑到了这种类型的东西。它有一个 .net 驱动程序,它的工作方式与实体框架大致相同。 【参考方案1】:

您说得对,使用List 效率低下,平均而言,List 将实现线性输出 (O(n))。

就个人而言,我会使用Concurrent Dictionary,它保证是O(1)。在我参与的一个项目中,我正在处理 100MB 文本文件的大文件,我发现 Concurrent Dictionary 可以充分地对信息进行分类和搜索,每秒完成大约 10,000 条记录。

看看这个整洁的cheat sheet。对于 Big-Oh 算法,它为最好和最坏的情况提供了一些简洁的细节。在处理海量数据集时,牢记AbstractionDecomposition 的概念很重要。

抽象专注于最重要的元素 - 忽略不相关的细节

只存储重要的信息,我非常怀疑你是否需要一个完整的 1GB 文件才能在内存中。

分解分而治之

确保运行您的应用程序的桌面对您的数据库具有良好的延迟。我建议仅将您需要的内容存储在内存中,并使用 LINQ 仅检索您需要的确切信息,一旦您拥有与您的任务相关的信息......然后您可以进一步过滤它。

【讨论】:

谢谢,我会看看那个数据结构。我的基本问题仍然存在;在内存/虚拟内存中存储 100GB 是不可行的。 如果我的回答有助于解决您的问题,如果您将其标记为正确答案,我们将不胜感激。问候。【参考方案2】:

如果内存不是问题,我会使用您的代码。如果列表是性能问题,那么也将其作为字典。将内容保存在 DB 中很好,因为它速度快且不需要大量内存。

这只是直觉的问题。我的选择是数据库和良好的索引。每次调用数据库。如果性能至关重要,请像您一样将其保存在内存中,并以某种方式将列表替换为字典。

【讨论】:

【参考方案3】:

我同意你的观点,我曾经做过像你这样的任务,但我的数据比你的少得多。我认为字典对您的单词搜索及其相关文档很有用,因为它可以保持单词与文档的关系,并且您可以轻松查询和排序单词。关于您的问题,我认为读取数据库并重建到 List 效率并不低,但是如果您非常频繁地重建和更新列表,则可能需要通过其他方式进行优化,例如服务器磁盘中的文件缓存,而不是经常将长文本值更新到数据库。 祝你好运!

【讨论】:

【参考方案4】:

我只是在讨论您应该如何存储/检索数据。我会尝试 Dictionary 之类的东西,其中 List 保存您所指文档的 ID。您的数据库将有一个 Word 表、一个 WordToDocument 表和一个 Document 表。

如果您正在构建网站,则没有理由返回每个文档的全部内容。您只需要返回文档的名称,因为用户可以选择他们想要阅读的文档。

【讨论】:

以上是关于在 C# 中使用非常大的 Dictionary<>的主要内容,如果未能解决你的问题,请参考以下文章

使用 Dllimport 将一个非常大的字符串作为字节数组从 C++ 传递到 C#

C#中Dictionary的用法 [转载]

如何在 C# 中解析非常大的 XML 文件? [复制]

在非常大的文件C#的所有行上循环[重复]

C#在Dictionary中使用枚举作为键

C# Hashtable和Dictionary区别