pqfilt
Generic Parquet filtering tool (CLI and Python API).
- Originally developed while dealing with large Parquet files in SPHEREx mission (GitHub).
Main Purpose
pqfilt wraps pyarrow.dataset to let you filter Parquet files before they
are fully read into memory, using row-group-level filtering. This is very efficient/fast.
An image generated by GPT 5.6:
Moreover, pqfilt provides a simple CLI tool that the user can simply filter a large (GB-TB order) Parquet to a smaller CSV file for interactive use (see below).
- Using
pqfilt.read()with filters is faster thanpd.read_parquet()on the measured SPHEREx datasets.- ~50× faster on the SPHEREx SSO ephemeris database (110 files, 139M
rows; a 10-day
jd_tdbwindow selects 4 files, 56 ms vs 2.957 s); - ~2× faster on a 3.6M-row SPHEREx source catalog (single row group, compound filter, all/four columns). Gains are larger when files have many row groups or the filter excludes whole files.
- ~50× faster on the SPHEREx SSO ephemeris database (110 files, 139M
rows; a 10-day
- The syntax is designed to be intuitive and flexible
- e.g., "a > 5 & ~(b in 1,2) & v is not null" is much simpler than the equivalent
pyarrowexpression syntax or chaining multiple DataFrame filters together.
- e.g., "a > 5 & ~(b in 1,2) & v is not null" is much simpler than the equivalent
- Even if you already loaded a DataFrame, you can use
pqfilt.filter_df(df, 'a > 5 & ~(b in 1,2) & v is not null')to apply the same filter syntax to it.
Installation
pip install pqfilt
# or
uv add pqfilt
Python API
import pqfilt
# Simple filter
df = pqfilt.read("data.parquet", filters="vmag < 20")
# AND + OR with expression syntax
df = pqfilt.read("data.parquet", filters="(a < 30 & b > 50) | c == 1")
# Negation with ~ prefix
df = pqfilt.read("data.parquet", filters="~(a > 5)")
df = pqfilt.read("data.parquet", filters="a > 5 & ~(b in 1,2,'1','2')")
# Null checks
df = pqfilt.read("data.parquet", filters="v is null")
df = pqfilt.read("data.parquet", filters="v is not null")
# Boolean columns
df = pqfilt.read("data.parquet", filters="is_comet == True")
df = pqfilt.read("data.parquet", filters="is_comet != false")
# Membership filter (explicit quotes preserve string types, e.g., to prevent Parquet type errors)
# Supported array formats: "val1, val2", "(val1, val2)", "[val1, val2]"
df = pqfilt.read("data.parquet", filters="desig in '1', '2', '3'")
df = pqfilt.read("data.parquet", filters="desig in ('1', '2', '3')")
df = pqfilt.read("data.parquet", filters="desig in ['1', '2', '3']")
# Tuple syntax (flat AND)
df = pqfilt.read("data.parquet", filters=[("a", "<", 30), ("b", ">", 50)])
# Tuple syntax with null checks
df = pqfilt.read("data.parquet", filters=[("v", "is null", None)])
# DNF syntax (OR of ANDs)
df = pqfilt.read("data.parquet", filters=[
[("a", "<", 30)],
[("b", ">", 50)],
])
# Column selection + output
df = pqfilt.read("data/*.parquet", columns=["a", "b"], output="out.parquet")
# Arrow scanner: materialize a table or consume record batches yourself
scanner = pqfilt.scan("data/*.parquet", filters="vmag < 20")
table = scanner.to_table()
# Out-of-core write: stream filtered batches directly to an output file
rows_written = pqfilt.write_filtered(
"data/*.parquet",
"filtered.parquet",
filters="vmag < 20",
)
# Filter an already-loaded DataFrame (same syntax)
df = pd.read_csv("data.csv")
filtered = pqfilt.filter_df(df, "a > 5 & ~(b in 1,2) & v is not null")
CLI
# Basic filter
pqfilt data/*.parquet -f "vmag < 20" -o filtered.parquet
# AND + OR expression
pqfilt data/*.parquet -f "(a < 30 & b > 50) | c == 1" -o filtered.parquet
# Multiple -f flags (AND-ed together)
pqfilt data/*.parquet -f "vmag < 20" -f "dec > 30" -o filtered.parquet
# Column selection
pqfilt data/*.parquet -f "vmag < 20" --columns vmag,ra,dec -o filtered.parquet
# Membership filter (enclosing brackets [] or () are automatically stripped)
pqfilt data/*.parquet -f "desig in [1, 2, 3]" -o filtered.parquet
Column names with special characters
Columns containing operator characters can be backtick-quoted. Say you have a column named "alpha*360". Wrap it with backticks to avoid misinterpretation as a multiplication operator:
pqfilt.read("data.parquet", filters="`alpha*360` > 100")
Word operators (in, not in, is null, and is not null) must
be preceded by whitespace. This grammar rule keeps an unquoted column name
ending in in (such as spin or margin) from being misread as an
operator. Symbolic operators do not have this requirement:
pqfilt.read("data.parquet", filters="spin > 3")
pqfilt.read("data.parquet", filters="margin in 1,2")
License
MIT
Release files for pqfilt 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pqfilt-0.3.1.tar.gz | 107.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pqfilt-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:125.2 kB
Release files / pqfilt-0.3.1.tar.gz
| Download URL | pqfilt-0.3.1.tar.gz |
|---|---|
| Size | 107.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
828a6a9a7b58bb189e28d10a5e70215e7399a48efed259a186d982b6085d8d2b
|
|
BLAKE2b-256 checksum How to use checksums |
d3ab90fd5c5a04c12547b26da9b90c93fb880f80972254a701c536d1a3958033
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency logRelease files / pqfilt-0.3.1-py3-none-any.whl
| Download URL | pqfilt-0.3.1-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fbf7a43a38af586102c620762bcb6dbcfede92bae4dafc3247758fa720f7bd03
|
|
BLAKE2b-256 checksum How to use checksums |
e289cb8ca5a5d1032c7a22c82e4be777ffea1b4ee00f642e8f59a0f7c162a1ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency log