Mock Predicate Pushdown in Python for Big Data Queries

Simulate predicate pushdown by applying filters at the storage layer before materializing rows, showing how big data engines optimize queries.

Medium Python 3.9+ Aug 9, 2026 Big data & Spark 15 views 0 copies

Python code

45 lines
Python 3.9+
class Query:
    def __init__(self, table, rows):
        self.table = table
        self.rows = rows

    def filter(self, predicate):
        return Query(
            self.table,
            [row for row in self.rows if all(predicate(row) for predicate in predicate)]
        )

    def filter_pushdown(self, predicate, column):
        """
        Mock predicate pushdown: apply predicate at the 'storage' level
        before reading full rows. Simulates pushing filter into scan.
        """
        # Simulate storage-level scan returning only matching rows
        # (as if the predicate was applied in the storage engine)
        storage_rows = [row for row in self.rows if predicate(row)]

        # This is where real pushdown would avoid materializing full data
        return Query(self.table, storage_rows)

    def execute(self):
        return self.rows


if __name__ == "__main__":
    # Simulate a table with 5 rows
    rows = [
        {"id": 1, "name": "Alice", "age": 30},
        {"id": 2, "name": "Bob", "age": 25},
        {"id": 3, "name": "Charlie", "age": 35},
        {"id": 4, "name": "Diana", "age": 28},
        {"id": 5, "name": "Eve", "age": 32},
    ]

    q = Query("users", rows)

    # Push predicate into "storage" (simulated)
    pushed = q.filter_pushdown(lambda r: r["age"] > 30, "age")

    print("Rows after predicate pushdown (filter age > 30):")
    for row in pushed.execute():
        print(row)

Output

stdout
Rows after predicate pushdown (filter age > 30):
{'id': 3, 'name': 'Charlie', 'age': 35}
{'id': 5, 'name': 'Eve', 'age': 32}

How it works

Predicate pushdown is a core optimization in databases and big data engines where filters are applied as early as possible during the scan, reducing the amount of data read from storage. This mock demonstrates the concept by applying the predicate to the raw rows list before storing the filtered result in the Query object. The filter_pushdown method simulates what happens at the storage/scan level in engines like Spark or Presto, where the filter is pushed into the file reader or columnar scanner. This contrasts with a naive filter that applies the predicate only after rows are fully materialized, which would waste I/O on non-matching rows.

Common mistakes

  • Confusing the mocked pushdown with actual Spark behavior — this is only a simulation of the concept
  • Forgetting that real pushdown works on columnar formats where only needed columns are read
  • Applying the predicate twice instead of tracking whether pushdown already happened

Variations

  1. Wrap the mock in a function that accepts both a column name and predicate for a more realistic filter_pushdown(column, predicate) signature
  2. Add a `limit` method that also gets pushed down to storage, simulating projection + filter pushdown together

Real-world use cases

  • Optimizing Spark DataFrame queries where filters are pushed into Parquet file scanners to skip irrelevant row groups.
  • Reducing I/O in Presto/Trino queries on partitioned Hive tables by pushing partition predicates to the metastore.
  • Building query planner tools that demonstrate cost savings before implementing pushdown in a custom data engine.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Big data & Spark

Related tutorials and quizzes for this topic.