我想就一个好的设计达成一些社区共识,以便能够存储和查询字频数。我正在构建一个应用程序,我必须解析文本输入并存储一个单词出现的次数(随着时间的推移)。所以给出以下输入:
会存储以下值:
Word Count
-------------
To 1
Kill 1
A 2
Mocking 2
Bird 1
Piano 1
Player 1
以后能够快速查询给定任意单词的计数值。
我目前的计划是简单地将单词和计数存储在数据库中,并依赖于缓存单词计数值......但我怀疑我不会获得足够的缓存命中率以使其成为长期可行的解决方案。
任何人都可以建议算法,数据结构或任何其他可能使其成为表现良好的解决方案吗?
答案 0 :(得分:6)
字数统计是MapReduce程序(来自维基百科的伪代码)的规范示例:
void map(String name, String document):
for each word w in document:
EmitIntermediate(w, "1");
void reduce(String word, Iterator partialCounts):
int result = 0;
for each pc in partialCounts:
result += ParseInt(pc);
Emit(AsString(result));
我不说这是 这样做的方式,但如果你需要一些能够在不同单词数量超出的情况下进行扩展的东西,这绝对是一个选择。单个机器上可用的内存。只要你能够保持低于内存限制,更新哈希表的简单循环应该可以解决问题。
答案 1 :(得分:3)
我不明白为什么你觉得数据库不是一个合适的解决方案。您可能只有大约100000行,表的小尺寸意味着它可以完全存储在内存中。将单词作为主键,查找速度非常快。
答案 2 :(得分:2)
如果性能是您的主要目标,您可以仅在RAM中使用基于散列或基于trie的结构。假设您无论如何都要进行一些有用的过滤(不计算带有非单词字符的术语),表格中的最大单词数将在10⁶到10⁷的范围内(即使涉及多种语言),所以这很容易适合当前PC的内存(并完全避免所有数据库处理)。
另一方面,如果你必须自己实现散列表细节,那么只有更多的代码可以做错(而数据库人员希望最大限度地调整它们的代码)。因此,即使您自己实施的细节也可能导致性能再次下降。
因此,这种困境清楚地向我们展示了优化的第一和第二规则: 1.不要过早优化。 2.在优化之前进行测量。
:)
答案 3 :(得分:1)
使用hash table。
答案 4 :(得分:1)
你的解决方案听起来不错。如果缓存基于最近的使用计数,那么它将保留最常用单词的单词计数。 (Word分布类似于前100个单词,涵盖了90%的单词实例),因此您不需要非常大的缓存。
如果要提高性能并删除数据库,可以将单词编码为trie,并将使用计数存储在叶节点中。在本质上,如果您对单词文本进行索引,那就是数据库正在执行的操作,因此您实际上只是避免了数据库延迟。如果这是目标,那么还有其他方法可以避免数据库延迟,例如使用并行查找。