Repository navigation
Conversation
|
Ported only the argument checks from vlasky#14 |
A join that supplied k from another table failed with "A LIMIT or 'k = ?' constraint is required on vec0 knn queries.", and one that supplied the query vector through a lookup could return no rows. xBestIndex skipped an unusable constraint, and when a KNN argument reads another table of the query, SQLite also weighs plans that scan vec0 before that table, in which the argument is unusable. Six points on a line and a one-row table w: `select v.rowid from v, w where v.embedding match '[0,0]' and v.k = w.n` failed in either FROM order. When a MATCH on a vector column is present, xBestIndex now returns SQLITE_CONSTRAINT for a plan in which the MATCH, k or a hidden parameter column declared after k is unusable, the way json_each refuses a plan that cannot supply its argument, so the planner takes one that gives vec0 every argument. Filters on rowid, partition key, metadata and distance columns are left to the plan. vec0 cannot tell a lookup join from a filter join, and refusing the plans without such a filter turned the lookup `select v.rowid, c.name from v join categories c on c.id = v.cat where v.embedding match '[0,0]' and v.k = 3` from the 3 nearest rows into 3 rows per category, as Matthew McEachen measured on SQLite 3.54.1 and 3.50.4 (vlasky#14 (comment)) and as it measures here on 3.46.1. ARCHITECTURE.md's idxStr section says when such a filter applies before the k all the same. The scope and the tests follow his port, photostructure@64db37c tests/test-knn-joined-constraints.py takes the query vector and k from another table in both FROM orders, checks that a table that supplies one of them filters before the k, and that a lookup join returns k rows in either FROM order. Six of its twelve cases fail on 04d28bd.
MayCXC
force-pushed
the
knn-plan-refusal
branch
from
October 21, 2026 14:40
9630b38 to
141abec
Compare
Author
|
This now carries only the argument checks, as in your port (141abec): |
This was referenced Oct 22, 2026
This branch has not been deployed
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.
A KNN query whose
kcomes from another table fails, and one whose query vector comes from it can return no rows:vec0BestIndexskips an unusable constraint, and when a KNN argument reads another table of the query, SQLite also weighs plans that scanvec0before that table, in which the argument is unusable. Aktaken from a one-row table fails the same way in either FROM order.When a MATCH on a vector column is present,
vec0BestIndexnow returnsSQLITE_CONSTRAINTfor a plan in which the MATCH,kor any hidden parameter column declared afterkis unusable, the wayjson_eachrefuses a plan that cannot supply its argument, so the planner takes one that givesvec0every argument. Both queries above then return the 2 nearest in each category,(1, 1), (1, 2), (2, 4), (2, 5): withcategoriesread first,v.tag = c.idis usable too.Filters on rowid, partition key, metadata and distance columns are left to the plan, as in @mceachen's port, photostructure/sqlite-vec@64db37c.
vec0cannot tell a lookup join from a filter join, and refusing the plans without such a filter turns his lookup from the 3 nearest rows into 3 rows per category. ARCHITECTURE.md's idxStr section says when a filter applies before the k all the same: the other table supplies a KNN argument, aCROSS JOINnames it first,vec0is on the right of aLEFT JOINwith the filter inON, or the KNN is a correlated subquery whose filter reads the outer query's columns.tests/test-knn-joined-constraints.pytakes the query vector andkfrom another table in both FROM orders, checks that a table that supplies one of them filters before the k, and that a lookup join returns k rows in either FROM order. 6 of its 12 cases fail on main and all pass here. The full suite passes (251 passed, 66 skipped, 204 snapshots).The same change for vlasky/sqlite-vec is vlasky#14.