简体   繁体   中英

Use some datatype as input for a MapReduce job.

I am working on a set of MapReduce jobs that convert a list of plot summaries into an index of every word mapping to the movieID and how many times it was used. I have one job that takes the input and creates a linked list of Nodes with the word, the movie it came from, and the number of times. My second job takes this LinkedList and uses the word as the key and the movieID and number of occurrences as the value and spits out an index of every word mapped to every movie it was used in as well as the number of occurrences.

When calling FileInputFormat.addInputPath() I can either use a Path() or a String with each element separated with a comma. It wouldn't be hard to just have a massive string with all the data my LinkedList holds but it would be nicer to just have the mapper use the LinkedList as input.

I have read about chaining MapReduce jobs so please don't give me a link to the Yahoo Developer page.

You don't need two MapReduce jobs (or therefore a LinkedList) here. We can instead treat this as a variant of word count, but with a list of movie IDs added into the output.

Map input:

354757\tToys come alive
432984\tMore toys

Map code:

String[] idAndWords = input.split("\\t");

for(String word : idAndWords[1].split(" ")) {
    //Do whatever cleansing you want here - remove punctuation, lowercase etc.
    output.write(word,idAndWords[0]);
}

Map output:

("toys","354757")
("come","354757")
("alive","354757")
("more","432984")
("toys","432984")

Reducer code:

//Maps movie IDs to occurrences
Map<String,Int> movieMap = new HashMap<>();
//In here is the list of movie IDs for each word
for(String val : values) {
    if(!movieMap.contains(val)) {
        movieMap.put(val,1);
    } else {
        movieMap.put(val,movieMap.get(val)+1);
    }
}
output.write(NullWritable.get(),key+"\t"+movieMap);

Reducer output:

toys\t[(3547571),(432984,1)]
come\t[(354757,1)]
alive\t[(354757,1)]
more\t[(432984,1)]

Now you have no need for a custom Writable , and it's fewer than a dozen lines of logic as opposed to what I think would be a pretty complex set of two chained MR jobs.

Efficiency extension:

You could make it more efficient by adding a count into the mapper output - with the current implementation then the plotline "dog eat dog" would result in the map output:

("dog","354757")
("eat","354757")
("dog","354757")

whereas you could reduce it to two records by adding a counter and scanning the whole line before outputting:

("dog","354757\t2")
("eat","354757\t1")

I didn't want to make my example more complex and less-readable by including this, but it should be trivial to implement and should give good performance savings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM