intermediate
Accumulators
8 min readLast updated: 2026-07-08
Overview
Learn how to use Accumulators to count events, track metrics, or debug datasets across your distributed tasks.
What You Will Learn
In this lesson, you will learn:
- Accumulators: Shared variables that are write-only for workers and read-only for the driver.
- Counters: Using accumulators to count records (e.g. error rows).
- Reliable Counts: Avoiding duplicate accumulator updates during task retries.
Detailed Concept Explanation
An Accumulator is a shared variable that worker tasks can only add to (write-only), while the driver program is the only process allowed to read its value. They are commonly used as distributed counters.
Basic Steps
- Initialize: Create the accumulator on the driver using
sc.accumulator(initialValue). - Update: Add to the accumulator inside worker tasks using
.add(value). - Read: Retrieve the final aggregated sum on the driver using
accum.value.
Code Examples
Input Dataset Preview
Below is the dataset containing valid records and corrupt entries:
| log_line |
|---|
| valid_row_1 |
| ERROR: corrupt |
| valid_row_2 |
Python (PySpark) Implementation
python
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("Accumulators").getOrCreate()
sc = spark.sparkContext
# Initialize counter accumulator
error_counter = sc.accumulator(0)
# Function to track corrupt lines
def parse_logs(line):
global error_counter
if "ERROR" in line:
error_counter.add(1)
return False
return True
rdd = sc.parallelize(["valid_row_1", "ERROR: corrupt", "valid_row_2"])
valid_rdd = rdd.filter(parse_logs)
# Trigger Action (must run an action to update accumulator)
print("Valid Logs Count:", valid_rdd.count())
print("Corrupt Logs Count:", error_counter.value)
Expected Output
text
Valid Logs Count: 2
Corrupt Logs Count: 1
Execution Plan Diagram (Python & Scala)
Execution Plan Diagram
SparkContext.accumulator(0)
sc.parallelize
filter(parse_logs) [adds to accum]
count() [Triggers action]
print(accum.value)
Scala Implementation
scala
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder().appName("AccumulatorScala").getOrCreate()
val sc = spark.sparkContext
val errorCounter = sc.longAccumulator("ErrorCounter")
val rdd = sc.parallelize(Seq("valid_row_1", "ERROR: corrupt", "valid_row_2"))
val validRDD = rdd.filter(line => {
if (line.contains("ERROR")) {
errorCounter.add(1)
false
} else {
true
}
})
println(s"Valid Logs Count: ${validRDD.count()}")
println(s"Corrupt Logs Count: ${errorCounter.value}")
Expected Output
text
Valid Logs Count: 2
Corrupt Logs Count: 1
Common Mistakes
- Reading value in Worker Tasks: Trying to read
accumulator.valueinside a map or filter function. Worker tasks can only write (add) to accumulators; the driver is the only process allowed to read the value. - Double Counting on Re-runs: Because of lazy evaluation, if you reference an RDD that updates an accumulator in multiple actions, Spark will recompute the RDD and add to the accumulator again, leading to double-counts. Cache the RDD to prevent this.
Best Practices
- Only Update inside Actions: Apply accumulator updates inside actions (like
foreach) rather than transformations, ensuring they are only run once per record.
Interview Perspective
What are Accumulators and what is their main restriction?
Accumulators are shared variables that workers can only write (add) to, while the driver is the only process allowed to read the value. They are commonly used as distributed counters. Workers cannot read the accumulator's value.