packagemain//// simple sequential MapReduce.//// go run mrsequential.go wc.so pg*.txt//import"fmt"import"../mr"import"plugin"import"os"import"log"import"io/ioutil"import"sort"// for sorting by key.typeByKey[]mr.KeyValue// for sorting by key.func(aByKey)Len()int{returnlen(a)}func(aByKey)Swap(i,jint){a[i],a[j]=a[j],a[i]}func(aByKey)Less(i,jint)bool{returna[i].Key<a[j].Key}funcmain(){iflen(os.Args)<3{fmt.Fprintf(os.Stderr,"Usage: mrsequential xxx.so inputfiles...\n")os.Exit(1)}mapf,reducef:=loadPlugin(os.Args[1])//// read each input file,// pass it to Map,// accumulate the intermediate Map output.//intermediate:=[]mr.KeyValue{}for_,filename:=rangeos.Args[2:]{file,err:=os.Open(filename)iferr!=nil{log.Fatalf("cannot open %v",filename)}content,err:=ioutil.ReadAll(file)iferr!=nil{log.Fatalf("cannot read %v",filename)}file.Close()kva:=mapf(filename,string(content))intermediate=append(intermediate,kva...)}//// a big difference from real MapReduce is that all the// intermediate data is in one place, intermediate[],// rather than being partitioned into NxM buckets.//sort.Sort(ByKey(intermediate))oname:="mr-out-0"ofile,_:=os.Create(oname)//// call Reduce on each distinct key in intermediate[],// and print the result to mr-out-0.//i:=0fori<len(intermediate){j:=i+1forj<len(intermediate)&&intermediate[j].Key==intermediate[i].Key{j++}values:=[]string{}fork:=i;k<j;k++{values=append(values,intermediate[k].Value)}fmt.Println(intermediate[i].Key)fmt.Println(values)output:=reducef(intermediate[i].Key,values)// this is the correct format for each line of Reduce output.fmt.Fprintf(ofile,"%v %v\n",intermediate[i].Key,output)i=j}ofile.Close()}//// load the application Map and Reduce functions// from a plugin file, e.g. ../mrapps/wc.so//funcloadPlugin(filenamestring)(func(string,string)[]mr.KeyValue,func(string,[]string)string){p,err:=plugin.Open(filename)iferr!=nil{log.Fatalf("cannot load plugin %v",filename)}xmapf,err:=p.Lookup("Map")iferr!=nil{log.Fatalf("cannot find Map in %v",filename)}mapf:=xmapf.(func(string,string)[]mr.KeyValue)xreducef,err:=p.Lookup("Reduce")iferr!=nil{log.Fatalf("cannot find Reduce in %v",filename)}reducef:=xreducef.(func(string,[]string)string)returnmapf,reducef}
packagemain//// a word-count application "plugin" for MapReduce.//// go build -buildmode=plugin wc.go//import"6.824/mr"import"unicode"import"strings"import"strconv"//// The map function is called once for each file of input. The first// argument is the name of the input file, and the second is the// file's complete contents. You should ignore the input file name,// and look only at the contents argument. The return value is a slice// of key/value pairs.//funcMap(filenamestring,contentsstring)[]mr.KeyValue{// function to detect word separators.ff:=func(rrune)bool{return!unicode.IsLetter(r)}// split contents into an array of words.words:=strings.FieldsFunc(contents,ff)kva:=[]mr.KeyValue{}for_,w:=rangewords{kv:=mr.KeyValue{w,"1"}kva=append(kva,kv)}returnkva}//// The reduce function is called once for each key generated by the// map tasks, with a list of all the values created for that key by// any map task.//funcReduce(keystring,values[]string)string{// return the number of occurrences of this word.returnstrconv.Itoa(len(values))}