声明:本博客内容由本人经过实验楼实验得来。
题目描述
在给定的莎士比亚文集上(多个文件),根据规定的停词表,统计出现频率最高的 100 个单词。所谓的停词表,即在词表中的词语并不统计他的频率。
莎士比亚文集中具有多个章节,因此需要用到并行化的方法,这里使用Spark
进行处理。
数据下载
# 莎士比亚文集:
wget http://labfile.oss.aliyuncs.com/courses/456/shakespear.zip
# 停词表:
wget http://labfile.oss.aliyuncs.com/courses/456/stopword.txt
编程模型
Spark上开发的应用程序都是由一个driver programe
构成,这个所谓的驱动程序在Spark集群通过跑main函数来执行各种并行操作。集群上的所有节点进行并行计算需要共同访问一个分区元素的集合,这就是RDD(RDD resilient distributed dataset)
弹性分布式数据集。RDD可以存储在内存或磁盘中,具有一定的容错性,可以在节点宕机重启后恢复。RDD可以从文件系统或HDFS中的文件创建,也可以从Scala或Python集合中创建。
主要针对RDD进行各种操作,程序中的步骤:
提取数据到RDD中,在本实验中我们将莎士比亚文集和停词表文件转换成RDD
1. 转换(transformations)操作:将已存在的数据集转换成新的数据集,例如map。转换是惰性的,不会立刻计算结果,仅仅记录转换操作应用的目标数据集,当动作需要一个结果时才计算。在本实验中我们需要转换文集RDD和停词表RDD。
2. 动作(actions) :数据集计算后返回一个值给驱动程序,例如reduce。本实验中需要对统计词频map的结果进行reduce操作。
程序实现
读入文件:
# 打开pyspark
[yqtao@localhost ~]$ pyspark
# 读入数据
>>> inputFiles = "/home/yqtao/bigdata/shakespear/*"
>>> stopWordFile = "/home/yqtao/bigdata/stopword.txt"
# 创建RDD文件
>>> inputRDD = sc.textFile(inputFiles)
>>> stopRDD = sc.textFile(stopWordFile)
处理特殊符号
输入的文件内容里除了英文单词之外,还有下面的特殊符号,这些符号不应该计算到统计中。
- 制表符
- 反斜线
- 句号
- 逗号
- 竖线 |
- 中括号
- 问号
- 破折号
- 叹号
- 分号
- 其他英文符号
其策略就是用空格替换这些特出的符号,然后在将其划分为单词。
# targetList是一个列表,包含这些特殊的符号
# 定义一个函数实现此功能
# python真的好强大!!!!
>>> targetList = list('\t\().,?[]!;|') + ['--']
>>>
>>> def replaceAndSplit(s):
... for c in targetList:
... s = s.replace(c, " ")
... return s.split()
# 通过flatMap调用自定义的函数
# 即此时的RDD中没有了这些特殊的符号
>>>inputRDDv1 = inputRDD.flatMap(replaceAndSplit)
处理停词表
将停词表读入列表中:
# 去除空行,获得列表
>>> stopList = stopRDD.map(lambda x: x.strip()).collect()
如果输入的文件中有停词表中的词,则将其去除,采用RDD的filter
方法。
>>>inputRDDv2 = inputRDDv1.filter(lambda x: x not in stopList)
Map操作
所谓的map操作转换操作,这点要深刻理解。
给每个单词组成元组(x,1),表示单词x出现了1次。
>>>inputRDDv3 = inputRDDv2.map(lambda x: (x,1))
Reduce操作
即计算操作,将相同的词进行统计频数。这里是对第二个数进行统计的。
# 导入add
>>>from operator import add
>>>inputRDDv4 = inputRDDv3.reduceByKey(add)
# 保存,可查看结果
# 可以看到他是分布式的存储的
>>>inputRDDv4.saveAsTextFile('/tmp/v4output')
TopK操作
即要统计出现最高频率的100个单词。
# 首先将单词频率与单词进行交换,这样就可以对频率进行排序
>>>inputRDDv5 = inputRDDv4.map(lambda x: (x[1], x[0]))
# 进行降序排列ascending=False表示降序
>>>inputRDDv6 = inputRDDv5.sortByKey(ascending=False)
排完序后,取单词:
# 交换位置,去key值
>>>inputRDDv7 = inputRDDv6.map(lambda x: (x[1], x[0])).keys()
# 取前100个单词
>>>top100 = inputRDDv7.take(100)
# 存储操作
>>>outputFile = "/tmp/result"
>>>result = sc.parallelize(top100)
>>>result.saveAsTextFile(outputFile)
完整的python代码
1 #!/usr/bin/python
2 # coding: utf-8
3 from pyspark import SparkContext,SparkConf
4 from operator import add
5 import sys
6 appName="WordCount"
7 conf=SparkConf().setAppName(appName).setMaster("local")
8 sc=SparkContext(conf=conf)
9 inputFiles = "/home/yqtao/bigdata/shakespear/*"
1 #!/usr/bin/python
2 # coding: utf-8
3 from pyspark import SparkContext,SparkConf
4 from operator import add
5 import sys
6 appName="WordCount"
7 conf=SparkConf().setAppName(appName).setMaster("local")
8 sc=SparkContext(conf=conf)
9 inputFiles = "/home/yqtao/bigdata/shakespear/*"
10 stopWordFile = "/home/yqtao/bigdata/stopword.txt"
11 outputFile = "/tmp/result"
12
13 targetList=list('\t\().,?;|')+['--']
14
15 def replaceAndSplit(s):
16 for c in targetList:
17 s=s.replace(c," ")
18 return s.split()
19
20
21 inputRDD=sc.textFile(inputFiles)
22 stopRDD=sc.textFile(stopWordFile)
23 stopList = stopRDD.map(lambda x:x.strip()).collect()
24
25 inputRDD1=inputRDD.flatMap(replaceAndSplit)
26 inputRDD2=inputRDD1.filter(lambda x: x not in stopList)
27 inputRDD3=inputRDD2.map(lambda x: (x,1))
28 inputRDD4=inputRDD3.reduceByKey(add)
29 inputRDD5=inputRDD4.map(lambda x:(x[1],x[0]))
30 inputRDD6=inputRDD5.sortByKey(ascending=False)
31 inputRDD7=inputRDD6.map(lambda x: (x[1],x[0])).keys()
32 top100=inputRDD7.take(100)
33 result=sc.parallelize(top100)
34 result.saveAsTextFile(outputFile)
运行:
[yqtao@localhost bigdata]$ spark-submit shake.py
打开结果如下所示:
1 I
2 And
3 him
4 thou
5 so
6 The
7 thy
8 all
9 To
10 by
11 thee
12 That
13 we
14 But
15 what
16 good
17 O
18 more
19 they
20 What
21 lord
22 now
23 love
24 them
25 A
26 KING