Query.Farm SQL Scan Planning
A Python library for intelligent file filtering using SQL expressions and metadata-based scan planning. This library enables efficient data lake query optimization by determining which files need to be scanned based on their statistical metadata.
Overview
This module provides predicate pushdown capabilities for file-based data storage systems. By maintaining metadata about file contents (min/max values, value sets, null presence), the library can quickly determine which files contain data that could satisfy a given SQL WHERE clause, significantly reducing query execution time.
Features
- SQL Expression Parsing: Parse and evaluate complex
SQL WHEREclauses using SQLGlot - Metadata-Based Filtering: Support for both range-based (min/max) and set-based field metadata
- Null Handling: Comprehensive support for
NULLvalue semantics in SQL expressions - Complex Predicates: Handle
AND,OR,XOR,NOT,IN,BETWEEN,CASEstatements, and more - Multiple Data Types: Support for integers, floats, strings, decimals, and
NULLvalues. Support for casting between Arrow scalar types. - Dialect Support: Configurable SQL dialect support (default: DuckDB)
Installation
pip install query-farm-sql-scan-planning
Or using rye:
rye add query-farm-sql-scan-planning
Quick Start
from query_farm_sql_scan_planning import Planner, RangeFieldInfo, SetFieldInfo
import pyarrow as pa
# Define file metadata
files = [
(
"data_2023_q1.parquet",
{
"sales_amount": RangeFieldInfo(
min_value=pa.scalar(100), max_value=pa.scalar(50000),
has_nulls=False, has_non_nulls=True
),
"region": SetFieldInfo(
values={pa.scalar("US"), pa.scalar("CA"), pa.scalar("MX")},
has_nulls=False, has_non_nulls=True
),
}
),
(
"data_2023_q2.parquet",
{
"sales_amount": RangeFieldInfo(
min_value=pa.scalar(200), max_value=pa.scalar(75000),
has_nulls=False, has_non_nulls=True
),
"region": SetFieldInfo(
values={pa.scalar("US"), pa.scalar("EU"), pa.scalar("UK")},
has_nulls=False, has_non_nulls=True
),
}
),
]
# Create planner
planner = Planner(files)
# Filter files based on SQL expressions
matching_files = set(planner.files("sales_amount > 40000 AND region = 'US'"))
print(matching_files) # {'data_2023_q1.parquet', 'data_2023_q2.parquet'}
# More complex queries
matching_files = set(planner.files("region IN ('EU', 'UK')"))
print(matching_files) # {'data_2023_q2.parquet'}
Field Information Types
RangeFieldInfo
For fields with known minimum and maximum values:
RangeFieldInfo(
min_value=pa.scalar(0),
max_value=pa.scalar(100),
has_nulls=False, # Whether the field contains NULL values
has_non_nulls=True # Whether the field contains non-NULL values
)
SetFieldInfo
For fields with a known set of possible values (useful for categorical data):
SetFieldInfo(
values={pa.scalar("apple"), pa.scalar("banana"), pa.scalar("cherry")},
has_nulls=False,
has_non_nulls=True
)
Note: SetFieldInfo can produce false positives - if a value is in the set, the file might contain it, but the file could contain additional values not in the set.
Supported SQL Operations
Comparison Operators
=,!=,<>(equality and inequality)<,<=,>,>=(range comparisons)IS NULL,IS NOT NULL(null checks)IS DISTINCT FROM,IS NOT DISTINCT FROM(null-safe comparisons)
Logical Operators
AND,OR,XOR(logical connectors)NOT(negation)
Set Operations
IN,NOT IN(membership tests)BETWEEN,NOT BETWEEN(range tests)
Control Flow
CASE WHEN ... THEN ... ELSE ... END(conditional expressions)
Data Types
CAST(type casting)
Literals
- Numeric literals:
123,45.67 - String literals:
'hello' - Boolean literals:
TRUE,FALSE - NULL literal:
NULL
Examples
Range Queries
# Files with sales between 1000 and 5000
planner.files("sales_amount BETWEEN 1000 AND 5000")
# Files with any sales over 10000
planner.files("sales_amount > 10000")
Set Membership
# Files containing specific regions
planner.files("region IN ('US', 'CA')")
# Files not containing specific regions
planner.files("region NOT IN ('UNKNOWN', 'TEST')")
Complex Conditions
# Combination of range and set conditions
planner.files(
"sales_amount > 5000 AND region IN ('US', 'EU') AND customer_id IS NOT NULL"
)
# Case expressions
planner.files(
"CASE WHEN region = 'US' THEN sales_amount > 1000 ELSE sales_amount > 500 END"
)
Null Handling
# Files that might contain null values in sales_amount
planner.files("sales_amount IS NULL")
# Files with non-null sales amounts over 1000
planner.files("sales_amount IS NOT NULL AND sales_amount > 1000")
Performance Considerations
- Metadata Quality: More accurate metadata (tighter ranges, complete value sets) leads to better filtering
- Expression Complexity: Simple expressions evaluate faster than complex nested conditions
- False Positives: The library errs on the side of including files that might match rather than risk excluding files that do match
Use Cases
- Data Lake Query Optimization: Skip irrelevant files in distributed query engines
- ETL Pipeline Optimization: Process only files containing relevant data
- Data Catalog Integration: Enhance metadata catalogs with query planning capabilities
- Columnar Storage: Optimize scans of Parquet, ORC, or similar formats
Development
Setup
git clone https://github.com/query-farm/python-sql-scan-planning.git
cd python-sql-scan-planning
rye sync
Running Tests
rye run pytest
Code Quality
rye run ruff check
rye run pytest --mypy
Dependencies
- sqlglot: SQL parsing and AST manipulation
- Python 3.12+: Required for modern type hints and pattern matching
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Author
This Python module was created by Query.Farm.
License
MIT Licensed.
Metadata
Release files for query-farm-sql-scan-planning 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| query_farm_sql_scan_planning-0.1.6.tar.gz | 10.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| query_farm_sql_scan_planning-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.1 kB
Release files / query_farm_sql_scan_planning-0.1.6.tar.gz
| Download URL | query_farm_sql_scan_planning-0.1.6.tar.gz |
|---|---|
| Size | 10.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6bf50f8efcd57eb7b3f07c1a865e496c98cecf2202f940c94229309d46e9060e
|
|
BLAKE2b-256 checksum How to use checksums |
e451fd95b476383c4dd7eb97112482b8f645c069da2b9b61f980dc1bb92f6a48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.7
|
Release files / query_farm_sql_scan_planning-0.1.6-py3-none-any.whl
| Download URL | query_farm_sql_scan_planning-0.1.6-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
83655ae255940dc170cb9c5b62fc39ab123522cf203d89908ca58744567e0e4d
|
|
BLAKE2b-256 checksum How to use checksums |
b1293bff8754fed41617a13c8f623b814c97d9bf41568d06a131b7b9f078c888
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.7
|