Skip to content

feat: serve sorted integer-array selections through zarrs - #189

Draft
selmanozleyen wants to merge 5 commits into
zarrs:mainfrom
selmanozleyen:feat/integer-array-indexing
Draft

feat: serve sorted integer-array selections through zarrs#189
selmanozleyen wants to merge 5 commits into
zarrs:mainfrom
selmanozleyen:feat/integer-array-indexing

Conversation

@selmanozleyen

@selmanozleyen selmanozleyen commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Hi, @ilan-gold @LDeakin,

I'd like to expose zarrs-python for the case when the integer indices are sorted instead of falling back. This is possible thanks to zarr-developers/zarr-python#4172. This is actually a realistic and a possibly very useful case for anndata and annbatch! It can't be used right away but it doesn't require much changes to utilize it, I linked the branches under the details.

The setup: 14 sharded stores (Tahoe-100M, CSR X, 100.6M rows,
146e9 nnz, ~89.4M-element shards, 64-row inner chunks).

The loader: Per batch: 1024 random rows
drawn across all 14 stores, (chunk_size=1, batch_size=1024, preload_nchunks=8192
in annbatch), 100 batches = 102,400 rows.

Results

arm rows/s total
upstream main 749 136.7 s
integer_array_indexing=True 4,053 25.3 s

Current status: if many runs hit same chunk it regresses due to deduplication of reads. But it might also regress in any local system atm. I only ran these numbers on lustre

Details

After this I will give a shot at #182, and in my AI draft at least it shows some stuff can be improved.

arm rows/s total first batch
integer_array_indexing only (branch A) 4,353 23.5 s 5.92 s
+ shard_index_cache_size=512 4,713 21.7 s 5.45 s
+ plan_reads 5,274 19.4 s 5.15 s
+ plan_reads_fetch_threads=32 5,331 19.2 s 5.15 s

Refs measured:

repo baseline branch (zarrs crate 0.23.6)
zarrs-python zarrs/zarrs-python@3345fd8 selmanozleyen/zarrs-python@07f9326 feat/integer-array-indexing and @1d284db feat/planned-reads-only
anndata scverse/anndata@2b43cc4 selmanozleyen/anndata@a4720ff feat/async-csr-row-read
annbatch scverse/annbatch@19d8b6e selmanozleyen/annbatch@7da8023 feat/anndata-async-csr-fetch

A chunk read is described to zarrs as a rectangular subset, so an integer-array
selection is refused as discontiguous today and served by zarr-python's pipeline
instead. `split_selection_runs` cuts such a selection at its non-consecutive
boundaries and emits one (slices, slices) box per run, which is the form the
existing slice path already carries into `retrieve_chunks_and_apply_index` -- so
this adds no second read path, it makes a refused selection expressible in the
one that exists. A pure-slice selection yields a single box, leaving it untouched.

Behind `codec_pipeline.integer_array_indexing`, off by default: box count is
data-dependent, and a selection whose runs are shorter than an inner chunk decodes
that chunk once per run where zarr-python decodes it once in total. Reads only,
one integer-array axis only, and non-decreasing indices only -- repeats end a run
and are served, while a permutation is refused, since output order and selection
order stop agreeing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant