Skip to content

perf: optionally dictionary-encode geog_id in the Arrow mapping output - #39

Merged
mailletf merged 1 commit into
mainfrom
perf/arrow-geog-id-dictionary
Sep 16, 2026
Merged

mailletf merged 1 commit into
mainfrom
perf/arrow-geog-id-dictionary

Conversation

@mailletf

@mailletf mailletf commented Aug 25, 2026 •

Copy link
Copy Markdown
Member

Problem

expand_geohash_mapping_arrow emits one row per (geog_id, geohash) pair, so every row of a group repeats that group's id. The geog_id column is almost entirely duplicate bytes.

Fix

Add dictionary_geog_id, which emits Dictionary<Int32, Utf8> instead: one copy of each id in the dictionary, 4 bytes of index per row.

Defaults to false, so the existing schema is unchanged for current callers.

Benchmarks

20,000 geographies × 300 cells = 6M rows, with short 11-character ids:

plain dictionary
geog_id column 114.0 MB 24.3 MB 4.7×
whole batch 204.0 MB 114.3 MB 1.8×
call 362 ms 294 ms 1.2×

Longer ids widen the gap — the dictionary column's size does not depend on id length beyond the one stored copy.

Considered

Run-end encoding would compress far harder still (the rows are already grouped, so 6M rows is really 20,000 runs), but support outside pyarrow is patchier than for dictionaries, so it is not offered here.

Also

Stops threading the geog_id String through the parallel expansion, which never needed it: results come back in input order, so results[i] belongs to geog_ids[i].

@mailletf

mailletf commented Aug 25, 2026 •

Copy link
Copy Markdown
Member Author

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an optional dictionary_geog_id flag to expand_geohash_mapping_arrow to reduce Arrow output size by dictionary-encoding the geog_id column while preserving the existing default schema for current callers.

Changes:

  • Added dictionary_geog_id (default false) to optionally emit geog_id as Dictionary<Int32, Utf8> in the Arrow RecordBatch output.
  • Refactored the parallel expansion path to avoid threading geog_id through Rayon work items (re-associating via preserved result order).
  • Added Python tests and updated the Python type stub to cover/describe the new optional argument and schema behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/lib.rs Implements optional dictionary encoding for geog_id and refactors parallel expansion result handling.
tests/test_arrow_ops.py Adds test coverage for dictionary-encoded geog_id equivalence, schema typing, size reduction, and edge cases.
geohash_polygon/__init__.pyi Updates the Python stub signature and docstring to include dictionary_geog_id.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/lib.rs
Comment on lines +1337 to +1340
let mut keys: Vec<i32> = Vec::with_capacity(total_out);
for (i, group) in expanded.iter().enumerate() {
keys.extend(std::iter::repeat_n(i as i32, group.len()));
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in bbd2a02. expand_geohash_mapping_arrow now checks the group count against i32::MAX before building the keys and raises a ValueError naming the limit and the way out (dictionary_geog_id=False, or split the input). A wrapped negative key would silently repoint rows at the wrong geog_id, which is the worst kind of failure here.

@mailletf
mailletf force-pushed the perf/arrow-codec-coords branch from 07381ea to f53ff32 Compare August 25, 2026 14:45
@mailletf
mailletf force-pushed the perf/arrow-geog-id-dictionary branch from e3e88de to bbd2a02 Compare August 25, 2026 14:45
@mailletf
mailletf force-pushed the perf/arrow-geog-id-dictionary branch from bbd2a02 to d532897 Compare September 1, 2026 18:19
@mailletf
mailletf force-pushed the perf/arrow-codec-coords branch 2 times, most recently from a33d93a to d27b1ce Compare September 1, 2026 18:33
@mailletf
mailletf force-pushed the perf/arrow-geog-id-dictionary branch 2 times, most recently from 71f3a5b to cae83cd Compare September 1, 2026 18:54
@mailletf
mailletf force-pushed the perf/arrow-codec-coords branch from d27b1ce to f43b43f Compare September 1, 2026 18:54
@mailletf
mailletf changed the base branch from perf/arrow-codec-coords to perf/hierarchical-descent September 16, 2026 18:58
@mailletf
mailletf force-pushed the perf/arrow-geog-id-dictionary branch from cae83cd to 3cfb8b4 Compare September 16, 2026 19:13
@mailletf
mailletf changed the base branch from perf/hierarchical-descent to main September 16, 2026 19:14
expand_geohash_mapping_arrow emits one row per (geog_id, geohash) pair, so
every row of a group repeats that group's id. The geog_id column is almost
entirely duplicate bytes.

Add dictionary_geog_id, which emits Dictionary<Int32, Utf8> instead: one copy
of each id in the dictionary, 4 bytes of index per row. On 20,000 geographies
of 300 cells each — 6M rows, with short 11-character ids:

  geog_id column   114.0 MB  ->   24.3 MB    4.7x
  whole batch      204.0 MB  ->  114.3 MB    1.8x
  call                362 ms ->     294 ms   1.2x

Longer ids widen the gap; the dictionary column's size does not depend on the
id length at all beyond the one stored copy.

Defaults to false, so the existing schema is unchanged for current callers.

Run-end encoding would compress this far harder still — the rows are already
grouped, so 6M rows would reduce to 20,000 runs — but support outside pyarrow
is patchier than for dictionaries, so it is not offered here.

Also stops threading the geog_id String through the parallel expansion, which
never needed it: results come back in input order, so results[i] belongs to
geog_ids[i]. Both output paths are built from that.

Squashed with:
- fix: refuse a dictionary too large for its Int32 keys
- fix: deduplicate the geog_id dictionary values

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mailletf
mailletf force-pushed the perf/arrow-geog-id-dictionary branch from 3cfb8b4 to b82dda3 Compare September 16, 2026 19:15
@mailletf
mailletf merged commit 4b4c7f8 into main Sep 16, 2026
2 checks passed
@mailletf
mailletf deleted the perf/arrow-geog-id-dictionary branch September 16, 2026 20:02
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.

2 participants