我知道这个文章标题很“学术”化,很俗,让人看起来是一篇很牛B或者很装逼的论文!其实不然,只是一份普通的实验报告,同时本文也不对RMM中文分词算法进行研究。这个实验报告是我做高性能计算课程的实验里提交的。所以,下面的内容是从我的实验报告里摘录出来的,当作是我学习hadoop分享出来的一些个人经验。
实验目标
学习编写 Hadoop 上的 MapReduce 程序。
使用 Hadoop 分布式计算小说《倚天屠龙记》里的中文单词频率,比较张无忌身边的两个女人周芷若与赵敏谁在小说里的热度高。(为什么要提到倚天屠龙记呢?因为我的一位舍友最近把贾静雯演的这部戏看完了,他无时无刻不提到贾静雯演的赵敏,所以这个实验也取材自我的大学生活……)
实验原理
通过自学Hadoop的Streaming工作模式,使用Streaming可以让Hadoop运行非Java的MapReduce程序。
为了减少我们的实验时间,我们使用了以开发效率著名的Python语言来编写我们的mapper.py和reducer.py。其中,我们还使用到了一个小巧的中文分词模块smallseg.py,引用自(http://code.google.com/p/smallseg/,Apache License 2.0)。
对于中文词库,我们使用搜狗实验室提供的中文词库main.dic以及一个字库suffix.dic,均可从smallseg项目中获得。
分布式计算的输入为一个文本文件:倚天屠龙记.txt,我们从网下下载此文本资源,并且转换为utf8文本编码以方便我们在Linux下进行分词计算。
iconv -fgbk -tutf8 倚天屠龙记.txt > 倚天屠龙记utf8.txt
实验环境
NameNode:
OS: Ubuntu11.04
CPU: Intel Core I3
Memory: 512MB
IP: 125.216.244.28
DataNode1:
OS: Ubuntu11.10
CPU: Intel Pentium 4
Memory: 512MB
IP: 125.216.244.21
DataNode2:
OS: Ubuntu11.10
CPU: Intel Pentium 4
Memory: 512MB
IP: 125.216.244.22
Mapper程序
下面是mapper.py的代码。
#!/usr/bin/env python from smallseg import SEG import sys seg = SEG() for line in sys.stdin: wlist = seg.cut(line.strip()) for word in wlist: try: print "%s\t1" % (word.encode("utf8")) except: pass
smallseg为一个使用RMM字符串分割算法的中文分词模块。Mapper程序的过程很简单,对每一行的中文内容进行分词,然后把结果以单词和频率的格式输出。对于所有的中文单词,都是下面的格式,
单词[tab]1
每个单词的频率都为1。Mapper并不统计每一行里的单词出现频率,我们把这个统计频率的工作交给Reducer程序。
Reducer程序
下面是reducer.py的代码.
#!/usr/bin/env python import sys current_word,current_count,word = None, 1, None for line in sys.stdin: try: line = line.rstrip() word, count = line.split("\t", 1) count = int(count) except: continue if current_word == word: current_count += count else: if current_word: print "%s\t%u" % (current_word, current_count) current_count, current_word = count, word if current_word == word: print "%s\t%u" % (current_word, current_count)
从标准输入中读取每一个单词频率,并且统计。因为这些单词已经由Hadoop为我们排好了顺序,所以我们只需要对一个单词的出现次数进行累加,当出现不同的单词的时候,我们就输出这个单词的频率,格式如下
单词[tab]频率
实验步骤
实验使用一个NameNode节点和两个DataNode节点。
首先,把所需要的文件复制到每一台主机上。这些文件都放在/home/hadoop/wc目录下。
scp -r wc [email protected]:.
scp -r wc [email protected]:.
scp -r wc [email protected]:.
运行Hadoop Job
本次任务,使用3个Mapper进程以及2个Reducer进程。因为分词的步骤最为耗时,所以我们尽量分配最多数目的Mapper进程。
hadoop@xiaoxia-vz:~/hadoop-0.20.203.0$ ./bin/hadoop jar contrib/streaming/hadoop-streaming-0.20.203.0.jar -mapper /home/hadoop/wc/mapper.py -reducer /home/hadoop/wc/reducer.py -input 2-in -output 2-out -jobconf mapred.map.tasks=3 -jobconf mapred.reduce.tasks=2 [...] WARN streaming.StreamJob: -jobconf option is deprecated, please use -D instead. packageJobJar: [/tmp/hadoop-unjar2897218480344074444/] [] /tmp/streamjob7946660914041373523.jar tmpDir=null [...] INFO mapred.FileInputFormat: Total input paths to process : 1 [...] INFO streaming.StreamJob: getLocalDirs(): [/tmp/mapred/local] [...] INFO streaming.StreamJob: Running job: job_201112041409_0005 [...] INFO streaming.StreamJob: To kill this job, run: [...] INFO streaming.StreamJob: /home/hadoop/hadoop-0.20.203.0/bin/../bin/hadoop job -Dmapred.job.tracker=http://125.216.244.28:9001 -kill job_201112041409_0005 [...] INFO streaming.StreamJob: Tracking URL: http://localhost:50030/jobdetails.jsp?jobid=job_201112041409_0005 [...] INFO streaming.StreamJob: map 0% reduce 0% [...] INFO streaming.StreamJob: map 9% reduce 0% [...] INFO streaming.StreamJob: map 40% reduce 0% […] INFO streaming.StreamJob: map 67% reduce 12% [...] INFO streaming.StreamJob: map 71% reduce 22% [...] INFO streaming.StreamJob: map 100% reduce 28% [...] INFO streaming.StreamJob: map 100% reduce 100% [...] INFO streaming.StreamJob: Job complete: job_201112041409_0005 [...] INFO streaming.StreamJob: Output: 2-out
Map过程耗时:41s
Reduce过程耗时:21s
总耗时:62s
计算结果
复制计算结果到本地文件系统。
./bin/hadoop dfs -get 2-out/part* ../wc/
查看part*的部分内容:
hadoop@xiaoxia-vz:~/wc$ tail part-00000 龙的 1 龙眼 1 龙虎 2 龙被 1 龙身 2 龙镇 1 龙骨 1 龟寿 2 龟山 1 龟裂 1 hadoop@xiaoxia-vz:~/wc$ tail part-00001 龙门 85 龙飞凤舞 1 龙驾 1 龟 3 龟一 1 龟二 1 龟息 1 龟缩 1 龟蛇 3
下面,对输出的结果进行合并,并按照频率进行排序。该过程比较快,在1秒内就已经完成。
hadoop@xiaoxia-vz:~/wc$ cat part-00000 part-00001 | sort -rnk2,2 > sorted hadoop@xiaoxia-vz:~/wc$ head sorted 的 7157 张无忌 4373 是 4199 道 3465 了 3187 我 2516 他 2454 你 2318 这 1991 那 1776
我们去掉单个字的干扰,因为我们的实验目的只对人名感兴趣。
hadoop@xiaoxia-vz:~/wc$ cat sorted | awk '{if(length($1)>=4) print $0}' | head -n 50 张无忌 4373 说道 1584 赵敏 1227 谢逊 1173 自己 1115 甚么 1034 张翠山 926 武功 867 一个 777 咱们 767 周芷若 756 教主 739 笑道 693 明教 685 一声 670 听得 634 姑娘 612 师父 606 只见 590 无忌 576 少林 555 如此 547 弟子 537 之中 527 殷素素 518 杨逍 496 他们 490 不知 484 如何 466 我们 453 两人 453 叫道 450 二人 445 今日 443 心想 433 张三丰 425 声道 425 义父 412 出来 402 虽然 395 灭绝师太 392 之下 389 这时 381 莲舟 374 心中 374 便是 371 不敢 371 俞莲 369 不能 359 身子 356
统计图表
结论
赵敏以1227票的频率完胜周芷若的756票,由此可知赵敏在《倚天屠龙记》里的热度比周芷若高。
经过本次实验,我们对 Hadoop 原理有了一定程度的了解,并且顺利的完成Mapper函数和Reducer函数的设计和测试。能够运用 Hadoop 进行简单的并行计算的实现。我们也对并行算法和串行算法的区别和设计有了更深一层的了解。此外,实验还增进了我们的合作精神,提高了我们的动手能力。
算这个,蛋疼了。。。
Hadoop!
您也用这个来研究下《红楼》吧。。。
这篇我估计以后用的着,先记下了。。。
俞莲少了一个‘舟’
哈!搜狗的词库里没有俞莲舟。但因为俞是姓氏,所以只匹配了一个人名。其实如果能够把舟字理解为名词,那么可以继续匹配这个舟字。这样分词更加智能。
我看得好疼。。。
话说NameNode这台计算机,感觉有点像好马拉破车的感觉!i3+512内存?这搭配太太浪费了吧
因为我的NameNode是在笔记本的虚拟机里跑的!我笔记本是i3 🙂
小虾程序挺好玩的!
不知道能不能像留言中那样可以把红给匹配一下!
o(∩∩)o…哈哈,不准确的,仅供参考!
除非你能把每个人的名字的不同叫法以及外号都合计在一个人上,不然是不能得到准确的结果。
例如,王熙凤、熙凤、凤姐姐、凤姐儿都统计在一个人上。
还应该应用“贝叶斯”,对“你,我,他”进行分类
有趣!
未试过,求具体方案或例子!!!
正点!现在才知道hadoop可以配python,这下可以玩了!另外,建议为贵站加上google+的+1按钮方便分享XD
推荐个分享插件?
未用过wp,你可以试试这个 http://www.google.com/webmasters/+1/button/
有没有类似的C++代码?
通过标准文件输入输出工作的,转换为C++代码,应该很容易,也不会很多。
好东西!小虾,可以转载吗?
没问题啊。
bin/hadoop jar contrib/streaming/hadoop-streaming-1.0.1.jar -mapper /home/hd-user/mapper.py -reducer /home/hd-user/reducer.py -input /user/hd-user/input1 -output /user/hd-user/output11 -verbose
我用你的例子写了之后,输出文件的part-0000的大小是0,没有内容。还发现一个现象,上面的命令敲入之后,应该map的比例显示100%,然后才是reduce的比例。
但是我这里是reduce先到100%,然后才是map到100%。
您好,博主!打扰了
[http://hanlaiming.freetzi.com/?p=273#comment-719]
上面这个网址的网友,向您学习后,修改了一个java的程序(不是python的脚本),在测试的过程中,虽然都可以正常使用,然而结果却不正确。您可以参看链接下方的留言板块,上面也叙述了为什么这个java程序出现了问题,不知道您有什么好的建议么?(我只是想先用java程序先进行中文分词和词频统计的实验,然后再准备向您学习,学习使用python来做实验)
谢谢!希望百忙能够答复!
不可能帮你找原因哦,可以采用量小的数据进行测试对比,容易看出问题。
牛掰
Pingback引用通告: 基于 Hadoop 对武侠小说进行词频分析-张丽军的博客