数据源(部分),完整数据见:http://blog.fens.me/rhadoop-demo-email/
wolys@21cn.com
zss1984@126.com
294522652@qq.com
simulateboy@163.com
zhoushigang_123@163.com
sirenxing424@126.com
lixinyu23@qq.com
chenlei1201@gmail.com
370433835@qq.com
cxx0409@126.com
viv093@sina.com
q62148830@163.com
65993266@qq.com
summeredison@sohu.com
zhangbao-autumn@163.com
diduo_007@yahoo.com.cn
采用Rhadoop统计每个邮箱域名出现的次数,这里将对程序作注释:
library(rhdfs)
library(rmr2)
data<-read.csv(file="mail.txt",sep='\t',header=F)
d0<-to.dfs(keyval(1, data))#keyval(key,val)创建键值对pair
#这里是key为1,value是data但是通过数据框强制转换时1被循环使用从而data的每个邮箱的key都是1即有41个<key,value>,
#to.dfs(kv)上传数据kv到hdfs
from.dfs(d0)#从hdfs读取数据
mr<-function(input=d0){
map<-function(k,v){
keyval(word(as.character(v$V1), 2, sep = fixed('@')),1)
#word(string,start=1,end=start,sep="")字符串提取函数(包stringr中),string是原始字符串
#start表示以sep分割的第start个串开始,end表示以sep分割的第end个串结束,
#比如word("he#llo##world##c++",2,3,sep='##')返回world##c++,sep可以是个字符串(这点比boost库split都优秀啊)
#这里将以邮箱域名为key,value=1的pair(注意map操作的语义)
}
reduce =function(k, v ) {
keyval(k, sum(v))
#reduce执行规约操作,对value求和
}
d1<-mapreduce(input=input,map=map,reduce=reduce,combine=TRUE)
#mapreduce(input,output=NULL,map,reduce)//input是hdfs上的路径,
#ouput为NULL时返回一个big.data.object(可以理解为一个hdfs上的临时文件可供其它函数使用),
#map接收<key,value>形式的multi-pair执行map操作,返回NULL或者pair。
#reduce接收multi-pair执行reduce操作,返回NULL或pair.
}
d1<-mr(d0)
from.dfs(d1)#从hdfs上获取结果
#按域名出现次数进行排序
sort<-function(input=d1){
map<-function(k,v){
keyval(1,data.frame(k,v))
#这里迫不得已将d1作为value而key全部为1,是为了经过map后d1数据是完整的
}
reduce<-function(k,v){
v2<-v[order(as.integer(v$v),decreasing=TRUE),]#v$v中第一个v是d1,第二个v表示的d1的第二列即次数
#order是用于排序函数返回下标,order返回向量的元素表示排序后该下标处的元素对应未排序向量的哪个位置
keyval(1,v2)#排序后的结果在value中
}
d2<-mapreduce(input=input,map=map,reduce=reduce,combine=TRUE)
}
d2<-sort(d1)
result<-from.dfs(d2)
result$val#获取value即排序后的结果
结果(部分):
k v
3 163.com 14
1 qq.com 9
2 126.com 9
5 sina.com 2