DDIA Chapter 10: Batch Processing
Part III: Derived Data
Systems fall into three shapes: online (request/response), batch (bounded input → output, often scheduled), and stream (unbounded, near-real-time). Batch processing is the Unix philosophy at datacenter scale.
Unix tools as a design lesson
awk, sort, uniq, pipes: immutable inputs, composable programs, a uniform interface (bytes). You can interrupt a pipeline, materialize intermediate files, and retry. Limited to one machine, hence Hadoop-style systems.
MapReduce
Mappers emit key/value pairs; shuffle groups by key; reducers aggregate. Inputs stay immutable; outputs land on a distributed filesystem (HDFS). Chain jobs into workflows. Joins use sort-merge / broadcast-hash / partitioned-hash patterns, prefer bringing data together over querying remote DBs mid-job. Build derived databases as files; avoid dual-writing live into OLTP from mappers.
Beyond MapReduce
Fully materialized stages waste IO and block pipelines. Dataflow engines (Spark, Flink, …) treat a workflow as one job with richer operators, less redundant materialization, and faster iteration, trading some failure recovery for speed. High-level APIs (Hive, Spark SQL) shrink code and enable interactive use. Arbitrary code in operators is a superpower versus rigid SQL-only engines.
In code
Snippets below use Java, SQL, or plain text as labeled.
Unix pipeline:
gunzip -c events.log.gz \
| awk '{print $1}' \
| sort \
| uniq -c \
| sort -nr \
| head
MapReduce word-count sketch:
void map(String line, Emitter emitter) {
for (String word : line.split("\\s+")) {
emitter.emit(word, 1);
}
}
void reduce(String word, Iterable<Integer> counts, Emitter emitter) {
int sum = 0;
for (int c : counts) sum += c;
emitter.emit(word, sum);
}
Takeaway
Immutable inputs and derived outputs make retries safe. MapReduce scaled the Unix pipeline idea. Dataflow engines keep that idea without materializing every stage.