map-reduce/README.md
To efficiently process large-scale datasets by dividing computation into two phases: map and reduce, which can be executed in parallel and distributed across multiple nodes.
Real-world example
Imagine a large e-commerce company that wants to analyze its sales data across multiple regions. They have terabytes of transaction data stored across hundreds of servers. Using MapReduce, they can efficiently process this data to calculate total sales by product category. The Map function would process individual sales records, emitting key-value pairs of (category, sale amount). The Reduce function would then sum up all sale amounts for each category, producing the final result.
In plain words
MapReduce splits a large problem into smaller parts, processes them in parallel, and then combines the results.
Wikipedia says
MapReduce is a programming model and associated implementation for processing and generating big data sets with a parallel, distributed algorithm on a cluster. MapReduce consists of two main steps: The Map step: The master node takes the input, divides it into smaller sub-problems, and distributes them to worker nodes. A worker node may do this again in turn, leading to a multi-level tree structure. The worker node processes the smaller problem, and passes the answer back to its master node. The Reduce step: The master node then collects the answers to all the sub-problems and combines them in some way to form the output – the answer to the problem it was originally trying to solve. This approach allows for efficient processing of vast amounts of data across multiple machines, making it a fundamental technique in big data analytics and distributed computing.
Flowchart
{word → count} for each input string.Mapper.javapublic class Mapper {
public static Map<String, Integer> map(String input) {
Map<String, Integer> wordCount = new HashMap<>();
String[] words = input.split("\\s+");
for (String word : words) {
word = word.toLowerCase().replaceAll("[^a-z]", "");
if (!word.isEmpty()) {
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}
}
return wordCount;
}
}
Example Input: "Hello world hello"
Output: {hello=2, world=1}
{word → list of counts}.Shuffler.javapublic class Shuffler {
public static Map<String, List<Integer>> shuffleAndSort(List<Map<String, Integer>> mapped) {
Map<String, List<Integer>> grouped = new HashMap<>();
for (Map<String, Integer> map : mapped) {
for (Map.Entry<String, Integer> entry : map.entrySet()) {
grouped.putIfAbsent(entry.getKey(), new ArrayList<>());
grouped.get(entry.getKey()).add(entry.getValue());
}
}
return grouped;
}
}
Example Input:
[
{"hello": 2, "world": 1},
{"hello": 1, "java": 1}
]
Output:
{
"hello": [2, 1],
"world": [1],
"java": [1]
}
Reducer.javapublic class Reducer {
public static List<Map.Entry<String, Integer>> reduce(Map<String, List<Integer>> grouped) {
Map<String, Integer> reduced = new HashMap<>();
for (Map.Entry<String, List<Integer>> entry : grouped.entrySet()) {
reduced.put(entry.getKey(), entry.getValue().stream().mapToInt(Integer::intValue).sum());
}
List<Map.Entry<String, Integer>> result = new ArrayList<>(reduced.entrySet());
result.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));
return result;
}
}
Example Input:
{
"hello": [2, 1],
"world": [1],
"java": [1]
}
Output:
[
{"hello": 3},
{"world": 1},
{"java": 1}
]
MapReduce.javapublic class MapReduce {
public static List<Map.Entry<String, Integer>> mapReduce(List<String> inputs) {
List<Map<String, Integer>> mapped = new ArrayList<>();
for (String input : inputs) {
mapped.add(Mapper.map(input));
}
Map<String, List<Integer>> grouped = Shuffler.shuffleAndSort(mapped);
return Reducer.reduce(grouped);
}
}
Main.java public static void main(String[] args) {
List<String> inputs = Arrays.asList(
"Hello world hello",
"MapReduce is fun",
"Hello from the other side",
"Hello world"
);
List<Map.Entry<String, Integer>> result = MapReduce.mapReduce(inputs);
for (Map.Entry<String, Integer> entry : result) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
Output:
hello: 4
world: 2
the: 1
other: 1
side: 1
mapreduce: 1
is: 1
from: 1
fun: 1
Use MapReduce when:
Benefits:
Trade-offs: