Technology  /  Apache Spark

โšก Apache Spark 49 guides ยท updated 2026

Distributed data processing at scale โ€” RDDs, DataFrames, Structured Streaming, and the tuning techniques that keep Spark jobs fast and cheap.

Spark aggregateByKey()

aggregateByKey() is the most flexible key-based aggregation in the Spark RDD API. It lets you define two separate combining functions: one for combining values within a partition and one for combining the partition subtotals across partitions. This enables aggregations that reduceByKey canโ€™t express โ€” like computing averages, collecting into sets, or tracking multiple statistics simultaneously.


Syntax

rdd.aggregateByKey(
zeroValue, # Starting accumulator for each key in each partition
seqFunc, # (accumulator, value) โ†’ accumulator [within partition]
combFunc, # (accumulator, accumulator) โ†’ accumulator [across partitions]
numPartitions=None # Optional: output partition count
)

Example 1: Computing Average (Cannot Use reduceByKey)

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("aggregateByKey").getOrCreate()
sc = spark.sparkContext
scores = sc.parallelize([
("Alice", 85), ("Bob", 72), ("Alice", 91),
("Bob", 88), ("Alice", 79), ("Bob", 65),
])
# Accumulator: (sum, count)
zero = (0, 0)
def seq_func(acc, value):
return (acc[0] + value, acc[1] + 1)
def comb_func(acc1, acc2):
return (acc1[0] + acc2[0], acc1[1] + acc2[1])
sum_count = scores.aggregateByKey(zero, seq_func, comb_func)
averages = sum_count.mapValues(lambda sc: sc[0] / sc[1])
averages.collect()
# [("Alice", 85.0), ("Bob", 75.0)]

Example 2: Collect Unique Values per Key

purchases = sc.parallelize([
("C001", "Laptop"), ("C002", "Mouse"), ("C001", "Monitor"),
("C001", "Laptop"), ("C002", "Keyboard"), ("C002", "Mouse"),
])
unique_products = purchases.aggregateByKey(
set(), # zero: empty set per key per partition
lambda acc, v: acc | {v}, # seqFunc: add value to set
lambda a, b: a | b # combFunc: merge sets
)
unique_products.collect()
# [("C001", {"Laptop", "Monitor"}), ("C002", {"Mouse", "Keyboard"})]

Example 3: Min and Max Simultaneously

temperatures = sc.parallelize([
("NYC", 22), ("LA", 28), ("NYC", 18), ("LA", 31), ("NYC", 25), ("LA", 24),
])
stats = temperatures.aggregateByKey(
(float("inf"), float("-inf")), # zero: (min, max)
lambda acc, v: (min(acc[0], v), max(acc[1], v)), # seqFunc
lambda a, b: (min(a[0], b[0]), max(a[1], b[1])) # combFunc
)
stats.collect()
# [("NYC", (18, 25)), ("LA", (24, 31))]

Example 4: Count with Custom Logic (Conditional Count)

clicks = sc.parallelize([
("ad_001", {"clicked": True, "converted": False}),
("ad_001", {"clicked": True, "converted": True}),
("ad_002", {"clicked": True, "converted": False}),
("ad_001", {"clicked": False, "converted": False}),
("ad_002", {"clicked": True, "converted": True}),
])
metrics = clicks.aggregateByKey(
(0, 0), # (impressions, conversions)
lambda acc, v: (acc[0] + 1, acc[1] + (1 if v["converted"] else 0)),
lambda a, b: (a[0] + b[0], a[1] + b[1])
)
cvr = metrics.mapValues(lambda m: (m[0], m[1], m[1] / m[0] if m[0] > 0 else 0))
cvr.collect()
# [("ad_001", (3, 1, 0.333)), ("ad_002", (2, 1, 0.5))]

aggregateByKey vs Other Aggregations

MethodUse When
reduceByKeySimple aggregation (sum, max, min) โ€” same type in and out
groupByKeyNeed full list of values โ€” use sparingly for large data
aggregateByKeyDifferent input/output types, compound accumulators (avg, set, stats)
combineByKeyMost flexible โ€” custom createCombiner, mergeValue, mergeCombiner
DataFrame groupBy().agg()Structured data โ€” almost always preferred for DataFrames