Back to Devoured - September 28, 2026
DEVOURED
ALP: Adaptive Lossless Floating-Point Encoding in Apache Parquet

ALP: Adaptive Lossless Floating-Point Encoding in Apache Parquet

Data Apache Parquet
Apache Parquet's new ALP encoding enables lossless compression for floating-point data with 10x faster decoding speeds compared to ZSTD.
What: Developed by Kosta Tarasov, Andrew Lamb, and Prateek Gaur, the Adaptive Lossless floating-Point (ALP) encoding utilizes exponent/factor scaling and bit-packing to achieve high compression ratios while maintaining fast random access to individual data points.
Why it matters: ALP addresses the long-standing trade-off in analytical storage where heavy compression previously sacrificed decode performance and data accessibility.
Takeaway: If you store large volumes of coordinate or price data in Parquet, update to parquet-format 2.14.0 and enable ALP to improve read performance.
Deep dive
  • Encodes data in vectors (8-32K values) using shared exponent and factor parameters.
  • Stores precision exceptions separately to ensure the encoding remains truly lossless.
  • Enables direct random access by mapping the target index to the offset of bit-packed integers.
  • Outperforms ZSTD compression for decimal-heavy floating-point datasets.
  • Currently supported in Rust's parquet 60.0.0 crate, with C++ and other implementations pending.
Decoder
  • Floating-point encoding: Techniques to compress values like FLOAT or DOUBLE which are difficult to store efficiently due to rounding errors and IEEE 754 precision constraints.
  • SIMD (Single Instruction, Multiple Data): CPU instructions that perform the same operation on multiple data points simultaneously, significantly increasing processing speed.
Original article

ALP: Adaptive Lossless Floating-Point Encoding in Apache Parquet

Apache Parquet has added the Adaptive Lossless floating-Point (ALP) Encoding – a new lightweight floating-point encoding with compression ratios similar to zstd, much faster decompression, random-access support, and GPU- and SIMD-friendly decoding.

ALP works best for decimal values stored as floating-point types (32-bit FLOAT and 64-bit DOUBLE), such as

  • Monetary values (exchange rates, public funds, stocks, prices, etc.) – e.g., 1.2345 or 22.03
  • Geographic coordinates (longitude/latitude) – e.g., 42.3584, -71.0598
  • Scientific measurements (temperature, pressure, speed, degrees, etc.) – e.g., -273.15, 9.81, 3.14159

ALP is not suitable for data that uses a wide range of exponents or a large number of significant digits, such as vector embeddings, which typically span the full floating-point range. Such data can continue to use existing Parquet features such as PLAIN or BYTE_STREAM_SPLIT encoding followed by general-purpose compression like ZSTD.

Decimal values can be stored with Parquet’s DECIMAL logical type, but that type requires the precision and scale to be known and declared up front and cannot store values outside that range. For this reason, systems commonly store decimal values as FLOAT or DOUBLE when the exact shape of their data is not known beforehand. For example, JavaScript’s only number type is DOUBLE, common data science tools such as pandas infer float64 for decimal-looking values, and NumPy has no decimal dtype at all.

Why ALP?

Encoding floating-point data is a complicated engineering problem due to the nature of floating-point values. They do not exactly represent most real numbers. This leads to rounding errors that prevent the use of existing lightweight encodings like Delta and Frame of Reference.

Prior to ALP, BYTE_STREAM_SPLIT was the only non-dictionary alternative to PLAIN for FLOAT/DOUBLE values in Parquet. It does not reduce the size of the data but can improve the compression ratio and speed when a heavyweight compressor is used afterwards.

Heavyweight compression effectively decreases the data size, but at the cost of:

  • Decode speed – decompression speed is often the bottleneck in data access.
  • Random access – reading one value requires decoding an entire data page containing potentially thousands of other values.
  • Data dependence – variable-length compression means that decoding a value requires decoding previous values, making it hard to parallelize with modern hardware such as SIMD instructions and GPUs.

ALP is designed to solve all three of these problems for common data patterns, while achieving a similar compression ratio to heavyweight compression.

Parquet applies an encoding first, then an optional compression codec as a separate step. The charts below compare the PLAIN and BYTE_STREAM_SPLIT encodings followed by ZSTD compression with the ALP encoding and no additional compression. Users can expect ALP to decode 10x faster and retrieve individual values thousands of times faster, with a slightly lower compression ratio and slightly faster compression.

Note that these numbers are for the pre-release Rust implementation of ALP, and we expect performance to improve as implementations are optimized and tuned. Even so, ALP is already faster than zstd in many cases, despite years of optimization work on zstd implementations.

Technical Overview

ALP takes advantage of a common pattern: many values stored as FLOAT or DOUBLE originated as decimal numbers with relatively few digits, such as prices or measurements. This section explains the intuition behind ALP and then covers the encoding and decoding pipelines in more detail.

ALP encodes floating-point values in batches called “vectors”, ranging in size from 8 to 32K values (e.g., 1024). Each value in a vector is encoded as an integer, and the vector stores two integer parameters shared by all its values: an “exponent” (e) and a “factor” (f). Each vector can use a different exponent and factor. The original value is recovered by computing:

value = encoded × 10f × 10-e

This calculation uses floating-point arithmetic, which rounds to the nearest representable value and thus may not reproduce the original value exactly. When that happens, ALP stores the original full-precision value separately as an “exception”, keeping the encoding lossless. Special values such as NaN, ±Infinity, and -0.0 are also stored as exceptions.

Within each vector, the encoded values are stored by subtracting the lowest value (the frame of reference) and then bit-packing to a fixed width. Exceptions are stored directly after the encoded array.

Example

Consider encoding the value 8.0605, which cannot be exactly represented in IEEE 754. It is stored as the 32-bit floating-point number 8.06050014495849609375. It can also be encoded as 80605 with exponent e = 8 and factor f = 4.

Picking the exponent and factor well is key to ALP’s performance. Each Parquet writer is free to choose them for each vector using any algorithm. Typically, the exponent is chosen to capture most decimal digits in the vector while minimizing exceptions, and the factor is chosen to remove as many trailing zeros as possible.

To encode this vector, the parameters e = 4 and f = 3 are chosen first. Then the values are transformed to integers using the formula encoded = round(value × 104 × 10-3). Each integer is checked by reversing the transformation. Values that do not round-trip are stored in the exception array. The minimum value across the vector becomes the frame of reference and is subtracted from each integer, and the resulting deltas are bit-packed.

Decoding a vector requires similar steps, but in reverse. First, the bit-packed deltas are unpacked, and the original values are computed. Then any exceptions are “patched” by overwriting the output array at the exception positions with the exception values.

Acknowledgements

ALP was first published in a SIGMOD 2024 paper by Azim Afroozeh, Leonardo Kuffó, and Peter Boncz from the Database Architectures Group at CWI. The Vortex and Lance formats adopted ALP early, demonstrating its benefits in industrial applications. In late 2025, the community began the standardization process. Along with the authors of this blog post, many community members contributed, including Divjot Arora, Arnav Balyan, Devan Benz, Ryan Blue, Alkis Evlogimenos, Xuwei Fu, Vinoo Ganesh, Adrian Garcia Badaracco, Curt Hagenlocher, Amogh Jahagirdar, Micah Kornfield, Robert Kruszewski, Julien Le Dem, Kevin Liu, Steve Loughran, Ismaël Mejía, Antoine Pitrou, Adam Reeve, Ed Seidl, Russell Spitzer, Matt Topol, Jeffrey Vo, Daniel Weeks, Gang Wu, and Zehua Zou.

Ecosystem Adoption

The encoding was released as part of parquet-format 2.14.0 in September 2026. ALP is already supported in at least one major open-source implementation (the parquet 60.0.0 Rust crate), and we expect other Parquet implementations to add support in the coming months.

Conclusion

ALP brings fast, parallelizable decoding and practical random access to floating-point data in a standard form that any Parquet implementation can read once it adds support for the encoding. Its addition is one more example of Apache Parquet evolving to meet the needs of modern data systems.

Resources

Explore all 67 articles in today's digest

Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi