有一个文本文件(大约300M),我需要计算最常出现的十个单词(不包括一些停用词)。测试机有8核Linux系统,欢迎任何编程语言,只能使用开源框架(hadoop不是选项),我没有任何多线程编程经验,我可以从哪里开始以及如何给出一个解决方案花费尽可能少的时间?
4 回答
300M 不是什么大问题,对你的任务来说只是几秒钟的事情,如果你做得对的话,即使是在像 python 这样的高级解释语言中的单核处理。与许多低级语言相比,Python 的优势在于它可以使您的字数统计编程非常容易编码和调试。如果您仍然想要并行化(即使在 python 中运行单核只需几秒钟),我相信有人可以发布一个快速简便的方法来做到这一点。
假设您每行有 1 个单词,您可以在python中执行以下操作
from collections import Counter
FILE = 'test.txt'
count = Counter()
with open(FILE) as f:
for w in f.readlines():
count[w.rstrip()] += 1
print count.most_common()[0:10]
读取文件并创建所有出现的单词的映射 [Word, count]作为键,值是您阅读时单词出现的次数。
任何语言都应该完成这项工作。
阅读文件一次后,您就有了地图。
然后遍历map,记住count值最高的十个词
如何以良好的可扩展性解决此问题:
该问题可以通过 2 个map-reduce步骤来解决:
步骤1:
map(word):
emit(word,1)
Combine + Reduce(word,list<k>):
emit(word,sum(list))
在这一步之后,你有一个列表(word,#occurances)
第2步:
map(word,k):
emit(word,k):
Combine + Reduce(word,k): //not a list, because each word has only 1 entry.
find top 10 and yield (word,k) for the top 10. //see appendix1 for details
在第 2 步中,您必须使用单个减速器,该问题仍然是可扩展的,因为它(单个减速器)只有10*#mappers
条目作为输入。
300 MB 文件的解决方案:
实际上,300MB 并不是一个大文件,因此您可以创建一个直方图(在内存上,使用基于树/散列的映射),然后从中输出前 k 个值。
使用支持并发的映射,您可以将文件拆分为多个部分,并让每个线程在需要时进行修改。请注意,如果它实际上被有效分割是依赖于 FS 的,有时一个线程的线性扫描是强制性的。
附录1:
如何获得top k:
使用最小堆并迭代元素,最小堆将始终包含最高 K 个元素。
Fill the heap with first k elements.
For each element e:
If e > min.heap():
remove the smallest element from the heap, and add e instead.
此外,此线程中的更多详细信息