在main/wc.go中有空的mapF()和reduceF()函数,Part II的内容就是实现这两个函数,以统计每一个单词出现的次数,区分大小写。替换掉Part I中的MapFunc和ReduceFunc。
在~/6.824/src/main中有一些名称相似pg-*.txt的文件,这即是Part II要处理的输入文件,运行下列命令来测试程序bash
cd 6.824
export "GOPATH=$PWD"
cd "$GOPATH/src/main"
go run wc.go master sequential pg-*.txtapp
最终的输出文件是mrtmp.wcseq,若程序编写正确,最终读取mrtmp.wcseq能够获得以下结果函数
sort -n -k2 mrtmp.wcseq | tail -10
that: 7871
it: 7987
in: 8415
was: 8578
a: 13382
of: 13536
I: 14296
to: 16079
and: 23612
the: 29748测试
对每一个输入文件会调用一次mapF,第一个参数是文件名,第二个参数是文件的内容,最后返回键值对切片。ui
func mapF(filename string, contents string) []mapreduce.KeyValue {
// Your code here (Part II).
}
复制代码
返回的键值对切片中,Kay存放的是单词,Value存放的是这个单词在这篇文章中出现的次数。使用strings.Fields方法对输入文件的内容进行分割.还有须要注意的一点是,须要将标点符号进行替换,以避免在按间隔符分割获得单词后,因为存在标点符号问题不能匹配成功。实现以下(ps.比较好的方式是使用strings.FieldsFunc):spa
func mapF(filename string, contents string) []mapreduce.KeyValue {
//删除,.?等等标点符号
re, _ := regexp.Compile("[^a-z^A-Z]")
contents = re.ReplaceAllString(contents, " ")
var kv map[string]int
kv = make(map[string]int)
words := strings.Fields(contents)
for _, w := range words {
if _,ok := kv[w];ok {//word已经存在,计数累加
kv[w] +=1
}else {
kv[w] =1
}
}
//转换为[]mapreduce.KeyValue
var res []mapreduce.KeyValue
for k,v := range kv {
res = append(res,mapreduce.KeyValue{k,strconv.Itoa(v)})
}
return res
}
复制代码
reduceF()对map tasks产生的每个key都调用一次,values存放的是key在不一样输入文件中出现的次数.在reduceF将values都相加而后返回就是每一个单词在全部文件中出现的次数。code
func reduceF(key string, values []string) string {
// Your code here (Part II).
}
复制代码
实现以下regexp
func reduceF(key string, values []string) string {
total := 0
for _,v := range values {
i, err := strconv.Atoi(v)
if err!=nil {
fmt.Println(err)
}
total += i
}
return strconv.Itoa(total)
}
复制代码
cd "$GOPATH/src/main"
time go run wc.go master sequential pg-*.txtcdn
出现相似下面结果运行成功blog
sort -n -k2 mrtmp.wcseq | tail -10
that: 7871
it: 7987
in: 8415
was: 8578
a: 13382
of: 13536
I: 14296
to: 16079
and: 23612
the: 29748
或者直接运行这个脚本测试
bash ./test-wc.sh