不断学习
才能在竞争中生存

基于 Hadoop 对武侠小说进行词频分析

基于 Hadoop 对武侠小说进行词频分析

一、实验介绍

1.1 实验内容

你知道著名武侠小说《天龙八部》里哪个人物名字出现的次数最多?可能你会说是乔峰,这是真的吗?让我们用 Hadoop MapReduce 的词频分析来做验证吧。

本课程是 Hadoop 的一个非常基础的应用项目,利用实验楼提供的 Hadoop 环境,对一本武侠小说的文集进行简单的 WordCount 词频统计,从而得到该书中出现频次最高的人名。

课程设计部分内容及代码参考了 在 Hadoop 上运行基于 RMM 中文分词算法的 MapReduce 程序 这篇文章,以及 结巴分词 的文档。

实验过程中可以参考文档中提供的完整代码,一步步按照文档介绍完成整个操作过程,从而对 Hadoop 的基本操作及进行词频统计的方法进行学习。

1.2. 实验知识点

本课程完成后,希望在动手实践的过程中,能够达到如下几点实验目标:

  • 熟悉 Hadoop 程序开发及执行流程
  • 熟悉 MapReduce 基本原理
  • 学习结巴分词用法
  • 学习词频统计方法

1.3 实验环境

本课程实验环境使用实验楼提供的 Ubuntu 14.04 64位操作系统,其中安装有 Hadoop 2.6.0 版本,需要使用 su -l hadoop 切换到 hadoop 用户使用,切换过程中需要输入 hadoop 用户的密码:hadoop,默认登录的 shiyanlou 用户无法直接使用 Hadoop。

如果您对 Linux 实验环境不熟悉,推荐您先学习《新手入门之玩转实验楼》。

1.4 适合用户

本课程难度为简单,属于入门级别课程,适合对 Hadoop 刚刚入门的用户,甚至没有接触过 Hadoop 的用户也可以按照步骤一步步做出来。

1.5 代码获取

本实验所有代码可以使用 git clone 命令在 git 服务器下载:

$ git clone http://git.shiyanlou.com/shiyanlou/hadoopwordcount

如果想在实验环境中下载代码,可以打开桌面上的 Xfce 终端,然后输入命令 git clone https://github.com/shiyanlou/hadoopwordcount 进行获取。

如果想进一步了解 Git 命令及操作,可以学习免费教程 《Git 实战教程》

二、实验原理

本节主要讲解 Hadoop 词频统计的原理。

实验中的代码将基于 Hadoop 的 Streaming 工作模式实现,Streaming 模式下 Hadoop 可以使用非 Java 编写的 MapReduce 程序。

MapReduce 是一种编程模型,适用于处理海量的数据,分为 Map(映射)和 Reduce(归约)两个步骤。Mapper 函数将一组 key-value 对映射为一组新的 key-value,然后交给并发的 Reducer 函数。词频统计中,Mapper 接受的 key 是文件名称,值是文件的内容,使用分词后逐个遍历词,每遇到一个词就产生一个中间 key-value 对 (词,1),key 指的是词,value 是 1,表示又找到了一个词。MapReduce 程序将 key 相同(同一个词)的 key-value 对传给 Reducer,这样 Reducer 接收了一系列同一 key 的 key-value 对,然后累加后得到该词出现的次数。最终将计算结果输出到 HDFS 文件系统。

程序运行的步骤如下所示:

  1. 输入《天龙八部》文本文件。
  2. 将输入文件分成 N 片(N 为 Mapper 程序数量)。
  3. 将每一片内容分给一个 Mapper 程序进行计算。
  4. 每个 Mapper 程序计算后将生成的输出作为输入交给 Reducer 程序。
  5. 每个 Reducer 程序汇总 Mapper 的输入后各自输出一份结果。

三、开发准备

3.1 安装分词工具

首先要做词频分析,需要安装中文分词的工具。分词的作用是将长句子中出现的中文词语进行切分,从文章中提取一个个中文词语。

实验中我们选择 Python 语言编写 MapReduce 程序,为了快速实现分词过程,Python 分词工具选择优秀的结巴分词。

打开桌面上的 Xfce 终端,目前的默认用户是 shiyanlou 用户,输入下面的 pip 命令安装 jieba 分词,为了加快下载速度,我们使用的是豆瓣的 pip 安装源:

$ sudo pip install -i http://pypi.douban.com/simple/  jieba

操作截图:

此处输入图片的描述

3.2 切换到 hadoop 用户

打开 Xfce 终端,输入截图中所示的命令 su -l hadoop,需要输入 hadoop 用户的密码 hadoop(注意:Linux 上切换用户输入密码是不显示的)

3.3 下载输入文件

《天龙八部》文件可以从网上下载,文件仅用于测试学习,将会随实验结束销毁。使用下述 wget 命令 下载测试的武侠小说文件:

$ wget http://labfile.oss.aliyuncs.com/hadoop/tlbbtestfile.txt

切换用户及下载测试文件的操作截图:

此处输入图片的描述

3.4 添加文件到 HDFS

首先实验楼环境中默认提供的 Hadoop 2.6.0,首先需要配置环境变量,让我们在实验楼的环境中可以使用这个版本的 Hadoop,将 Hadoop 2.6.0 的路径添加到 PATH 中,需要执行下面的命令(此时已经切换到 hadoop 用户):

$ export PATH=$PATH:/opt/hadoop-2.6.0/bin:/opt/hadoop-2.6.0/sbin

注意:Hadoop 的目录在 /opt/hadoop-2.6.0

此时可以直接使用 hadoop version 查看 Hadoop 版本:

此处输入图片的描述

使用 Hadoop 的 hdfs 命令将刚刚下载的文件添加到 HDFS,并重命名为 testinput.txt:

$ hdfs dfs -put tlbbtestfile.txt testinput.txt

此处输入图片的描述

四、实验步骤

4.1 程序编写

/home/hadoop 目录下创建 hadoopwordcount 文件夹及 mapper.pyreducer.py 文件,注意两个文件需要把权限设置为可执行,使用 hadoop 用户在终端中依次执行下面的命令,每个命令的说明见命令上方的注释信息:

# 进入到 hadoop 用户的家目录
$ cd /home/hadoop

# 创建代码文件夹
$ mkdir hadoopwordcount

# 创建 Mapper 程序文件
$ touch hadoopwordcount/mapper.py

# 创建 Reducer 程序文件
$ touch hadoopwordcount/reducer.py

# 给所有 Python 脚本增加可执行权限
$ chmod a+x hadoopwordcount/*.py

4.1.1 mapper 程序

注意: 编辑代码文件推荐使用 vim,桌面上的 gedit 因为启动是 shiyanlou 用户,不具备编辑 hadoop 用户目录下文件的权限。

首先我们实现 Mapper 程序,Mapper 程序的作用就是:

  1. 从 stdin 标准输入中依次读取每一行。
  2. 对每一行使用 jieba 分词进行分词。
  3. 对分词得到的词汇列表进行 Map 操作:每个词都映射成(word,1)这样的二元组,并输出到标准输出 stdout 中。

这个程序较简单,请尽量按照上述的逻辑描述自己实现。下方提供了详细的代码实现和注释信息,以供参考:

#!/usr/bin/env python

# 引入 jieba 分词模块
import jieba
import sys

# 从 stdin 标准输入中依次读取每一行
for line in sys.stdin:

     # 对每一行使用 jieba 分词进行分词
    wlist = jieba.cut(line.strip())

    # 对分词得到的词汇列表进行 Map 操作
    for word in wlist:
        try:
              # 每个词都映射成(word,1)这样的二元组
              # 输出到标准输出 stdout 中
            print "%s\t1" % (word.encode("utf8"))
        except:
            pass

4.1.2 reducer 程序

Reducer 程序比 Mapper 要复杂些,基本逻辑如下步骤:

  1. 从标准输入读取单词和词频。
  2. 对每个词出现的频次进行叠加,直到不再出现该词。
  3. 输出词和词频。

参考代码和注释信息如下:

#!/usr/bin/env python
import sys

# 定义临时变量存储中间数据
current_word, current_count, word=None,1,None

# 依次从标准输入读取每一行
for line in sys.stdin:
    try:
          # 每一行都是一个(word,count)的二元组,从中提取信息词语和数量
        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)

4.2 运行 MapReduce

4.2.1 运行命令

命令中我们使用到了 Hadoop streaming 来运行 python 程序,并指定 mapper 和 reducer 程序及输入文件的位置,同时运行了4个 mapper 实例和2个 reducer 实例。

需要运行的命令如下:

$ hadoop jar /opt/hadoop-2.6.0/share/hadoop/tools/lib/hadoop-streaming-2.6.0.jar -mapper /home/hadoop/hadoopwordcount/mapper.py -reducer /home/hadoop/hadoopwordcount/reducer.py -input testinput.txt -output wordcountout -jobconf mapred.map.tasks=4 -jobconf mapred.reduce.tasks=2

由于实验楼的环境比较慢,所以我们可以慢慢查看整个 MapReduce 的过程,一直到最后输出结果。

过程中的截图如下所示。如果感兴趣的话,可以分析下每条日志信息。

此处输入图片的描述

4.2.2 成功后的结果

此处输入图片的描述

4.3 查看结果

4.3.1 将结果从 HDFS 导出

虽然我们使用的 Hadoop 是单机模式,结果文件直接存放在 /home/hadoop 目录,但我们也需要了解下如何从一个真正的 HDFS 系统中导出结果。

使用下面的命令可以从 HDFS 导出文件到指定的目录 /tmp/output

$ mkdir /tmp/output
$ hdfs dfs -get wordcountout/part-0000* /tmp/output
$ ls /tmp/output/

导出及查看文件列表:

此处输入图片的描述

4.3.2 处理输出文件

两个 reducer 得到两个输出文件 part-00000part-00001,对输出的处理将按照下面的步骤进行:

  1. 筛选去除少于两个汉字的词,因为我们只关心姓名,而小于两个字必然不是姓名,此处使用 awk 脚本。
  2. 对输出结果进行按照第二列词频进行倒叙排序,此处使用 sort 命令。
  3. 输出排序后最顶部的数据,即出现频次最高的十个词,此处使用 head 命令。

整个操作过程如下图所示,每个命令的详细参数可以查看 man 文档获得,在此不再赘述:

此处输入图片的描述

结果是不是很显而易见了?段誉的出镜率最高,不过不要过早下结论,思考下萧峰还有个名字叫乔峰,如果这两个名字的频率加起来是不是会超过段誉呢?答案需要你自己去实验揭晓了。实验中有任何问题欢迎到 讨论区 提问。

五、实验总结

词频统计是 Hadoop 最基本的一个应用。通过这个简单的应用熟悉 MapReduce 的原理,及 Python 实现 MapReduce 程序的方法。有兴趣的同学可以找其他的文档(需要注意 UTF8 的编码问题)来进行词频检测,也可以扩展改写当前的程序实现其他应用,比如每个章节的主角都分别是谁?

实验中有任何问题欢迎到 讨论区 提问。

六、课后习题

那么,根据你的实验结果,在《天龙八部》中,是段誉的出现频次高还是乔峰(萧峰)呢?

可以将截图和实验过程写入实验报告,并发布到 讨论区 跟同学们一起交流。

未经允许不得转载:张丽军的博客 » 基于 Hadoop 对武侠小说进行词频分析

分享到:更多 ()

相关推荐

  • 暂无文章

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址