[Sparse ANN] Fold sparse vector tokens into the signed-short range - #1926
Conversation
Token IDs are folded into a fixed range via `token % MODULUS_FOR_SHORT` and stored in a signed short[] to keep the memory footprint low. The modulus was 65536, so a token folding into [32768, 65535] was cast to a negative short and, when read back, sign-extended to a negative int: - getToken()/iterator() returned a negative token (e.g. 40000 -> -25536) - toDenseVector() threw NegativeArraySizeException on `maxToken + 1` - dotProduct() mis-scored via a negative index / bad bounds check Those values never produced a usable index, so the effective working range was already [0, 32767]. Set MODULUS_FOR_SHORT to 32768 so every folded token is <= Short.MAX_VALUE and round-trips without sign extension. Because 32768 divides 65536, every token that previously worked folds to the same value, so existing indices are unaffected. Adds unit tests covering the constructor/iterator round-trip, toDenseVector(), and dotProduct() for a token folding to Short.MAX_VALUE. Signed-off-by: Liyun Xiu <xiliyun@amazon.com>
PR Reviewer Guide 🔍(Review updated until commit d0642fb)Here are some key observations to aid the review process:
|
Signed-off-by: Liyun Xiu <xiliyun@amazon.com>
PR Code Suggestions ✨Explore these optional code suggestions:
|
|
Persistent review updated to latest commit d0642fb |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1926 +/- ##
============================================
- Coverage 83.45% 83.41% -0.04%
+ Complexity 3884 3881 -3
============================================
Files 291 291
Lines 13819 13819
Branches 2294 2294
============================================
- Hits 11532 11527 -5
- Misses 1454 1457 +3
- Partials 833 835 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Previously, token id from 65536 to 32768 will cause the |
|
The backport to |
|
The backport to |
|
The backport to |
Description
Token IDs are folded into [0, MODULUS_FOR_SHORT) via
token % 65536and stored in a signed short[] to keep the memory footprint low. Reads went directly through tokens[i], so any token folding into [32768, 65535] was sign-extended back to a negative int, causing:maxToken + 1Route every token read through a getToken(int) helper that widens with Short.toUnsignedInt. Writes are unchanged since the (short) cast is a lossless reinterpretation; only reads needed to treat the value as unsigned. Sorting in processListItems() is by the folded non-negative value, so ascending order and dotProduct()'s early-exit remain valid.
Note this path is reachable only when the pure-Java SEISMIC path runs (segment doc count >= approximate_threshold, default 1M); below that the query falls back to plain neural sparse, and the native engine passes raw ints to C++ where term_t is uint16_t. That gating is why the defect went unnoticed.
Adds unit tests covering the constructor/iterator round-trip, toDenseVector(), and dotProduct() for a token folding to a negative short.
Related Issues
Resolves #1925
Check List
--signoff.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.