Spotify has shipped Random Access Parquet (RAP), an external indexing layer enabling sub-second point queries directly against Parquet files in its GCS-based data lake without copying data into Bigtable, DynamoDB, or other serving stores. The system closes a gap that has forced data teams at scale to choose between storage cost and query latency.

The problem is concrete at scale. Spotify parks petabytes in Bigtable for low-latency serving, but exabytes live in GCS. Replicating even a fraction into a key-value store to make it queryable is economically untenable. Cloud storage now delivers 30–100ms per request; GCS Rapid Storage and S3 Express One Zone drop to single-digit milliseconds. The real bottleneck is query planning overhead. Trino and BigQuery add seconds of scheduling work even for single-row lookups.

SystemTypePer-Request LatencyBottleneck
GCS (standard)Object storage30–100 msPer-request overhead
GCS Rapid StorageLow-latency object storageSingle-digit msReduced tier latency
S3 Express One ZoneLow-latency object storageSingle-digit msReduced tier latency
TrinoDistributed query engineSecondsQuery planning / scheduling
BigQueryDistributed query engineSecondsQuery planning / scheduling
FIG. 02 Per-request latency by system type — the gap RAP is designed to close — Spotify Engineering Blog, 2026

Chain-of-dependent-reads is RAP's core problem. A point query for one user's listening history across 90 days with 1,000 Parquet files per day starts with 90,000 candidate files. Key-based partitioning plus Bloom filters prune to roughly 12 files. Each still requires sequential round-trips: fetch footer, parse row-group metadata, scan the key column, resolve page offsets for each value column. On cloud storage each costs tens of milliseconds. Chained, that is hundreds of milliseconds before a single byte of user data arrives.

Chain-of-dependent-reads for a single point query without RAP — each step costs tens of ms on cloud storage
FIG. 03 Chain-of-dependent-reads for a single point query without RAP — each step costs tens of ms on cloud storage — Spotify Engineering Blog, 2026

RAP collapses the chain to a single O(1) lookup. An external index maps each key directly to file and row numbers. The reader hits the index, resolves row numbers to byte ranges using cached file metadata, and issues parallel ranged reads. No dependent round-trips. Index entries are compact: key, file (dictionary-encoded ordinal), row numbers, and optional value count for pagination. Rule of thumb: indexing a petabyte produces a terabyte of index; terabytes produce gigabytes.

RAP O(1) lookup path — index resolves file + row numbers, enabling fully parallel ranged reads with no dependent round-trips
FIG. 04 RAP O(1) lookup path — index resolves file + row numbers, enabling fully parallel ranged reads with no dependent round-trips — Spotify Engineering Blog, 2026

Write-side layout changes eliminate remaining amplification. Even with a perfect index, readers fetch a full 4MB page to extract maybe 100 bytes of useful data. Spotify sorts Parquet output by lookup key, aligns page boundaries to key transitions, and uses interleaved column layout co-locating related value columns. Covering indexes cache enough value data inside the index itself to satisfy some queries without opening any Parquet file. The trade-off is modest index and file size growth for queries resolving in kilobytes.

Secondary indexes extend the model without pipeline changes. Hash-based indexes serve exact lookups across dimensions; sorted indexes handle range queries. Both are managed at the serving layer, letting teams add access paths—buyer ID, seller ID, session ID—without touching upstream jobs or rewriting data.

Index TypeLookup PatternExample DimensionsManaged At
Hash-basedExact key lookupsBuyer ID, Seller ID, Session IDServing layer
SortedRange queriesDate ranges, ordered keysServing layer
FIG. 05 RAP secondary index types and their query access patterns — Spotify Engineering Blog, 2026

The practical forcing function is AI agents. Agents answering temporal questions like "what was I listening to last summer?" need to page through months of per-user history at interactive speeds. That data volume has always exceeded what key-value stores can economically hold. RAP lets the same Parquet datasets feed batch analytics, ML training, notebooks, and agent context from a single copy.

Evaluation point: if your team maintains a lake-data replica in a KV store purely for point-query latency, RAP warrants direct assessment. Indexing overhead is bounded, Parquet files stay immutable, and write-side layout changes are incremental enough to apply per-table without pipeline rewrites.