Repository navigation
Read Parquet files via Parquet2.jl - #43
Merged
Merged
Conversation
ParquetFiles was pinned to Parquet.jl 0.2-0.4, which depends on Thrift.jl
<=0.6 and therefore BinaryProvider. That chain is no longer installable, so
the package could not be resolved at all on a current Julia.
Parquet2.jl is a pure Julia implementation (Thrift2 plus the ChunkCodec
stack) and exposes the file as a Tables.jl column source. That replaces the
whole row-cursor machinery: the generated iterator, and the row struct that
was gensym'd and eval'd into the module on every read, are gone in favour of
reading the columns and handing them to TableTraitsUtils.create_tableiterator,
which already maps Union{Missing,T} columns to DataValue.
The old API this was written against (ParFile, RecCursor, JuliaBuilder,
JuliaConverter) was removed from Parquet.jl years ago, so a rewrite was
needed regardless of the backend. Parquet.jl's own README now points at
Parquet2.jl, which also has much lighter dependencies and more recent
releases. This supersedes the stale #25.
Because Parquet2 is columnar, the package can now also implement the
TableTraits column interface, so sinks such as DataFrame no longer have to
go row by row.
Byte array columns with no UTF8 annotation still come back as Vector{UInt8}
and are decoded to String, preserving how this package has always presented
them.
Parquet2 memory maps by default and its string columns are views onto that
buffer, so the columns are materialized before the dataset is closed. Without
that the mapping outlives the read and keeps the file locked on Windows;
there is a test item covering it.
The tests no longer reach into Parquet.jl's own test directory to git clone
parquet-compatibility for a fixture. That file is vendored instead, so the
suite no longer depends on another package's test layout or on network access.
julia compat moves to 1.10, which is what Parquet2 0.2.28+ requires.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Parquet2 does not precompile on 32 bit. Its own precompilation workload
reads a bundled sample file and throws while loading an INT64 backed
DateTime column:
BoundsError: attempt to access 80-element view(::Vector{UInt8}, 1:80)
with eltype UInt8 at index [1:160]
@ Parquet2 src/read.jl:368
That is 20 rows at sizeof(Int64), against a buffer holding 20 rows at
sizeof(Int), so INT64 backed columns get half the space they need when Int
is 32 bits. Every index in the stack is an Int32.
Because this happens during precompilation of the dependency, no amount of
care in ParquetFiles can work around it: `using ParquetFiles` cannot succeed
on 32 bit. Our own fixture only has Int32 and byte array columns and would
not trip the bug, but it never gets the chance to load.
No support is lost in practice. Before the move to Parquet2 the package
could not be installed on any architecture at all.
All eight failing CI legs were the 32 bit ones; every x64 and aarch64 leg
passes. IterableTables already disables these same two legs with the same
surrounding settings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ParquetFiles was pinned to
Parquet = "0.2, 0.3, 0.4". Parquet.jl in that range depends on Thrift.jl ≤0.6, which depends on BinaryProvider, so the package could not be installed at all on a current Julia —Pkg.resolve()failed before any code ran.This moves the backend to Parquet2.jl, a pure Julia implementation (Thrift2 plus the ChunkCodec stack — no BinaryProvider), and the package works again.
Why Parquet2 rather than a newer Parquet.jl
The old API this was written against (
ParFile,RecCursor,JuliaBuilder,JuliaConverter, the codegen form ofschema) was removed from Parquet.jl around 0.5/0.6, so a rewrite was required regardless of the backend. Given that, Parquet2 costs nothing extra and buys:Parquet.jl keeps the better bus factor (JuliaIO org) and a lower Julia floor, and neither project is adding features — both authors point at DuckDB.jl. DuckDB was considered and set aside as a large binary dependency for what is a thin FileIO loader.
This supersedes #25, which attempted the same rewrite against Parquet.jl's
RecordCursorand has been blocked on an upstream release since 2020.What changed
Parquet2 exposes the file as a Tables.jl column source, so the row-cursor machinery is gone: the
@generatediterator and the row struct that wasgensym'd andeval'd into the module on every read (a world-age hazard) are replaced by reading columns and handing them toTableTraitsUtils.create_tableiterator, which already mapsUnion{Missing,T}toDataValue. Net 78 lines changed insrc, and the file is shorter than before despite doing more.Because Parquet2 is columnar, the package now also implements the TableTraits column interface, so sinks such as
DataFrameno longer go row by row.Base.collectis forwarded too, matching CSVFiles.Two behaviours are deliberately preserved:
Vector{UInt8}and are decoded toString, as this package has always presented them. The vendored fixture is written by Impala 1.1.1 and predates the annotation, so it covers this path.Tests
The suite previously reached into Parquet.jl's own package directory and
included itstest/get_parcompat.jl, which git-clones theparquet-compatibilityrepo for a fixture. That depended on another package's internal test layout, on network access, and on the depot being writable. The 3 KB file is now vendored undertest/data/with its Apache-2.0 provenance recorded.Three test items pass locally on Julia 1.11. Row values are unchanged; they are now
DataValue-wrapped because Impala writes these columns asoptional. Theshowprefix assertions moved froms[1:100]tofirst(s, 100)— the byte slice now splits a multibyte box-drawing character.juliacompat moves to 1.10, which Parquet2 0.2.28+ requires.Queryverse needs a matching floor bump: queryverse/Queryverse.jl#65.
32-bit is excluded
CI does not run the 32-bit legs, because Parquet2 does not precompile there. Its own precompilation workload reads a bundled sample file and throws while loading an INT64-backed
DateTimecolumn:That is 20 rows at
sizeof(Int64)against a buffer holding 20 rows atsizeof(Int)— INT64-backed columns get half the space they need whenIntis 32 bits, and every index in the stack is anInt32.Since the failure is in the dependency's precompilation, nothing in ParquetFiles can work around it:
using ParquetFilescannot succeed on 32-bit regardless of how this package is written. (The vendored fixture has only Int32 and byte-array columns and would not trip the bug, but it never gets the chance to load.)No support is lost in practice — before this PR the package could not be installed on any architecture. The bug is not yet reported upstream; once it is fixed and released, the two
include-*-x86lines can be dropped and aParquet2compat floor raised in a follow-up.