Repository navigation
Binary-search an integer metadata column's in (...) list - #10
Merged
Merged
Conversation
_cmp returned the i64 difference of its arguments as an int, and it orders the `rowid in (...)` list of a KNN query before each row binary-searches it. Two rowids 2**32 apart narrow to 0 and compare equal, so a row that is not in the list matches: `rowid in (1, 2)` also returned rowid 2**32 + 1. A difference wider than an int also changes sign, so the qsort leaves the list out of order and the search misses rows that are in it: of 150 rowids drawn from +/-2**62, 29 to 54 were missing per run. A difference wider than i64 overflows. _cmp now compares its arguments. test_vec0_knn_rowid_in_far_apart covers both: an extra row 2**32 away, and five rowids 3e9 apart with alternating signs, one of which the old comparator loses. It fails on the old _cmp and passes on this one.
A KNN query's `n in (...)` on an integer metadata column compared every row of every chunk against every value in the list, so its cost grew with rows times list length. The list is now sorted once when vec0Filter_knn reads it, and each row binary-searches it, as `rowid in (...)` already does. test_vtab_in_integer_list checks the rows a 16-value list keeps, with values 2**32 apart; it fails on a build that pairs this search with the comparator _cmp had before the previous commit.
mceachen
added a commit
to photostructure/sqlite-vec
that referenced
this pull request
Oct 8, 2026
…eries A KNN query compared each row's integer metadata value with the entries of an `in (...)` list one by one until one matched. Ported from the unmerged vlasky#10 (asg017#328), with a branchless search in place of its bsearch(), which was slower than the scan on short lists.
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #9: the first commit here is that PR's comparator fix, which this one depends on.
A KNN query with
n in (...)on an integer metadata column compares every row of every chunk with every value in the list, so its cost grows with rows times list length. This sorts the list once whenvec0Filter_knnreads it, and each row binary-searches it, the wayrowid in (...)already works.100,000 rows of
float[8]with an integer metadata column,k = 10,n in (select value from json_each(?)), median of three:On a real index of 116,625 768-dimension cosine vectors, a
k = 50KNN restricted to 112,112 ids through an integer metadata column went from 2.7 s to 178 ms.test_vtab_in_integer_listchecks the rows a 16-value list keeps, with values 2³² apart. It passes on main, which compares each value directly, and fails on a build that pairs this binary search with the comparator main has, which is why this sits on #9. The full suite passes (145 passed, 4 skipped, 259 snapshots).The same change is open upstream as asg017#328.