You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After #299 (and PR #302, FSST child cascade), vortex-java is now 30 MB smaller than the vortex-jni reference on nyc-311 (1731 vs 1762 MB). The largest remaining cluster where java is bigger is three high-cardinality street columns — pure upside to close.
~54 MB combined. All three are now admitted to the global dictionary (the #299 type-aware Utf8 cap of 32768 works — they round-trip as vortex.dict layouts), and their values pool is FSST-compressed (#299 Finding 2). But jni's layout is ~36% smaller.
Hypothesis
Two likely, non-exclusive causes — both worth checking before fixing:
Dict codes stored raw, not bitpacked. The global-dict codes are per-chunk U16 arrays (18.49M rows × 2 B ≈ 37 MB just for codes). jni tags these columns fastlanes.bitpacked. A dict of ~27k values needs only 15 bits, and finer per-chunk cardinality needs fewer — so bitpacking (or FoR) the codes could recover several MB per column. This is the same class of issue PR Cascade FSST offset/length children (#299) #302 fixed for the FSST offset/length children: a child left as raw vortex.primitive instead of cascaded. Check whether writeGlobalDictUtf8Column's code segments actually bitpack (they route through writeSegment → cascade; a nullable-masked wrapper may be blocking the inner bitpack).
Global vs per-chunk dict tradeoff. jni appears to use a per-chunk dict (dict encoding, not a global dict layout) with its finer 32k–64k chunking, so each chunk's code width tracks that chunk's (smaller) local cardinality rather than the global 27k. At this cardinality the per-chunk approach may simply win.
Summary
After #299 (and PR #302, FSST child cascade), vortex-java is now 30 MB smaller than the vortex-jni reference on nyc-311 (1731 vs 1762 MB). The largest remaining cluster where java is bigger is three high-cardinality street columns — pure upside to close.
Evidence — per-column bytes (java re-encode vs vortex-jni, nyc-311, chunk 65536)
fastlanes.bitpacked, vortex.fsstfastlanes.bitpacked, vortex.fsstfastlanes.bitpacked, vortex.fsst~54 MB combined. All three are now admitted to the global dictionary (the #299 type-aware Utf8 cap of 32768 works — they round-trip as
vortex.dictlayouts), and their values pool is FSST-compressed (#299 Finding 2). But jni's layout is ~36% smaller.Hypothesis
Two likely, non-exclusive causes — both worth checking before fixing:
Dict codes stored raw, not bitpacked. The global-dict codes are per-chunk U16 arrays (18.49M rows × 2 B ≈ 37 MB just for codes). jni tags these columns
fastlanes.bitpacked. A dict of ~27k values needs only 15 bits, and finer per-chunk cardinality needs fewer — so bitpacking (or FoR) the codes could recover several MB per column. This is the same class of issue PR Cascade FSST offset/length children (#299) #302 fixed for the FSST offset/length children: a child left as rawvortex.primitiveinstead of cascaded. Check whetherwriteGlobalDictUtf8Column's code segments actually bitpack (they route throughwriteSegment→ cascade; a nullable-maskedwrapper may be blocking the inner bitpack).Global vs per-chunk dict tradeoff. jni appears to use a per-chunk dict (dict encoding, not a global dict layout) with its finer 32k–64k chunking, so each chunk's code width tracks that chunk's (smaller) local cardinality rather than the global 27k. At this cardinality the per-chunk approach may simply win.
Where
writer/src/main/java/io/github/dfa1/vortex/writer/VortexWriter.java—writeGlobalDictUtf8Column(code segment emission),emitCodesFbsArrayNodechildren under the codes Flat segment, as done for the FSST children in Close the vortex-java vs vortex-jni file-size gap on real-world data (nyc-311: 1.62x) #299)Context
Follow-up to #299 / PR #302. Measured on the hydrated Raincloud nyc-311 corpus (18.49M rows × 42 cols). Not started — analysis only.