var index int for _, kv := range kva { index = ihash(kv.Key) % nReduce err = encoders[index].Encode(&kv) if err != nil { log.Fatalf("cannot encode %v", kv) } }
// atomically rename for i := 0; i < nReduce; i++ { filename_tmp := fmt.Sprintf("mr-%d-%d", task_no, i) err := os.Rename(files[i].Name(), filename_tmp) if err != nil { log.Fatalf("cannot rename %v to %v", files[i].Name(), filename_tmp) } } }
var index int for _, kv := range kva { index = ihash(kv.Key) % nReduce err = encoders[index].Encode(&kv) if err != nil { log.Fatalf("cannot encode %v", kv) } }
funcDoReduce(filenames []string, task_no int, reducef func(string, []string)string) { // read data from mid-file kva := make([]KeyValue, 0) for _, filename := range filenames { file, err := os.Open(filename) if err != nil { log.Fatalf("cannot open %v", filename) } defer file.Close() dec := json.NewDecoder(file) for { var kv KeyValue if err := dec.Decode(&kv); err != nil { break } kva = append(kva, kv) } }
sort.Sort(ByKey(kva))
// call Reduce on each distinct key in kva[], // and print the result to mr-out-0. ofile, err := ioutil.TempFile("", "mr-out-tmp*") if err != nil { log.Fatalf("cannot create temp file") } defer ofile.Close()
i := 0 for i < len(kva) { j := i + 1 for j < len(kva) && kva[j].Key == kva[i].Key { j++ } values := []string{} for k := i; k < j; k++ { values = append(values, kva[k].Value) } output := reducef(kva[i].Key, values)
// this is the correct format for each line of Reduce output. fmt.Fprintf(ofile, "%v %v\n", kva[i].Key, output)
// // 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(filename string, contents string) []mr.KeyValue { // function to detect word separators. ff := func(r rune)bool { return !unicode.IsLetter(r) }
// split contents into an array of words. words := strings.FieldsFunc(contents, ff)
kva := []mr.KeyValue{} for _, w := range words { kv := mr.KeyValue{w, "1"} kva = append(kva, kv) } return kva }
// // 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(key string, values []string)string { // return the number of occurrences of this word. return strconv.Itoa(len(values)) }