Repository navigation
Conversation
MayCXC
force-pushed
the
rescore-index-photostructure
branch
from
October 23, 2026 03:33
1c20031 to
cdfef02
Compare
This was referenced Oct 23, 2026
Closed
MayCXC
force-pushed
the
rescore-index-photostructure
branch
from
October 23, 2026 05:34
cdfef02 to
347729b
Compare
This was referenced Oct 23, 2026
Open
MayCXC
force-pushed
the
rescore-index-photostructure
branch
from
October 23, 2026 17:03
347729b to
c0a7ab3
Compare
A vector column can name the index that answers its KNN queries, as in asg017/sqlite-vec@0de765f. flat() is the exhaustive search a column without the clause gets. The scanner reads '(', ')' and ',' for the index's options, and the clause's keywords match exactly even when an old table's definition is parsed leniently, since no old table has one.
A float vector column declared `indexed by rescore(quantizer=bit)` or `indexed by rescore(quantizer=int8)`, with an optional `oversample=N` from 1 to 128 (8 by default), also keeps its vectors quantized in _rescore_chunksNN, in the layout of _vector_chunksNN, and its float32 vectors by rowid in _rescore_vectorsNN. A KNN query scans the quantized vectors for the k * oversample nearest rows, then ranks those candidates by the distances of their float32 vectors. The `oversample=N` command sets the oversample of a connection's queries. A full scan reads a rescore column's vectors row by row through vec0_get_vector_data(), and a flat column's by chunk as before. Ported from asg017#276 (ba0db0b) as asg017's main has it at 04d28bd: with the int8 quantizer that 575371d fixed, the fixes 5e4c557, 82f4eb0 and 5522e86, auxiliary columns (b7fc459), the oversample=N command and its unknown-command message (6e2c4c6), and the distance constraints of the unmerged asg017#309. SQLITE_VEC_ENABLE_RESCORE=0 builds without it. Where this port differs from upstream: - rescore_knn() takes vec0Filter_knn_chunks_iter()'s arguments and results, so vec0Filter_knn() picks between the two and the MMR rerank runs after either. It reports errors as the chunk scan does, so an interrupt stays an interrupt. It picks each chunk's candidates with this fork's min_idx(), whose heap needs no bitmap of taken slots. - Distance constraints with a NULL, TEXT or BLOB value act as they do for a flat column. - optimize, which upstream lacks, writes a moved row's quantized vectors to its new slot and leaves its row of _rescore_vectorsNN, whose rowid does not change, and deletes the old _rescore_chunksNN rows with the old chunks. A DELETE that empties a chunk deletes its _rescore_chunksNN row too. - A point query for a rowid the table does not have returns no row, since vec0_get_vector_data() finds the row's position first, as for a flat column; upstream fails with "Could not fetch vector data". - _rescore_chunksNN declares "rowid INTEGER PRIMARY KEY", as this fork's new tables do, and an oversample=N value must be all digits. The tests are upstream's test-rescore.py and test-rescore-mutations.py, the rescore cases of its test-auxiliary.py and test-rename.py, its rescore fuzz targets, and test-unit.c's bit quantizer, byte size and parser cases. Upstream's int8 quantizer unit tests, and the uniform-vector case of rescore-quantize-edge.c, test the min/max quantizer that 575371d replaced, so they are written here for the current one. Modes 1 and 2 of rescore-quantize-edge.c copy the fuzz bytes out to float alignment before reading them as floats, as asg017#343 has them; upstream's read floats one byte past the mode byte, a misaligned load UBSan reports. New tests check that each row's quantized slot holds the quantized form of its vector through inserts, updates, deletes that empty chunks, and optimize, and rescore-optimize.c fuzzes optimize. test-fullscan.py reads a rescore column beside a flat one, and runs its delete and optimize cases on a rescore column too; read by chunk, a rescore column fails all three with "Could not fetch vector data".
test_interrupt_is_reported_as_interrupt runs a statement on a copy of a database, interrupted at each progress handler call, and expects SQLITE_INTERRUPT. A rescore table joins its database, with a KNN query, a full scan, a point query, an insert, an update, a delete, a delete that empties a chunk, and optimize, so the rescore code's internal statements are interrupted too. A build whose rescore insert returns SQLITE_ERROR in place of vec0_error_rc()'s code fails the insert case.
MayCXC
force-pushed
the
rescore-index-photostructure
branch
from
October 24, 2026 01:58
c0a7ab3 to
9c26f6c
Compare
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.
Ports asg017's rescore index (asg017#276), the first of its approximate-nearest-neighbour indexes, as asg017's main has it at 04d28bd. It is rebased onto main at f6a3244, which has #7.
What it adds. A
floatvector column can be declaredindexed by rescore(quantizer=bit)orindexed by rescore(quantizer=int8), withoversample=Nfrom 1 to 128 (8 by default). It also keeps each vector quantized, 1 bit or 8 bits per dimension, in_rescore_chunksNN, and itsfloatvectors by rowid in_rescore_vectorsNN. A KNN query scans the quantized vectors for thek * oversamplenearest rows, then ranks those candidates by the distances of theirfloatvectors, so the distances it returns are exact:A full scan reads a rescore column's vectors row by row through
vec0_get_vector_data(), and a flat column's by chunk as main does, since only a flat column keeps its vectors in_vector_chunksNN.The first commit adds
indexed by flat(), the exhaustive search a column without the clause gets, with the scanner's(,)and,tokens (asg017@0de765f).SQLITE_VEC_ENABLE_RESCORE=0builds without rescore, as upstream.What it ports. asg017@ba0db0b with the fixes 5e4c557, 82f4eb0 and 5522e86; auxiliary columns (b7fc459); the
oversample=Ncommand and itsunknown vec0 commandmessage (6e2c4c6); the int8 quantizer of 575371d, which maps [-1, 1] onto [-128, 127]; and the distance constraints of the unmerged asg017#309.Where it differs from upstream.
rescore_knn()takes the chunk scan's arguments and results, sovec0Filter_knn()picks between the two and the MMR rerank runs after either:mmr_lambdaworks on rescore columns. Its errors go throughvec0_error_rc(), so an interrupted query reportsinterrupted. It picks each chunk's candidates with this fork'smin_idx(), whose heap (Select each chunk's k nearest rows with a heap #2) needs no bitmap of taken slots, as asg017#337 does for upstream's rescore KNN.optimize, which upstream lacks, writes a moved row's quantized vectors to its new slot, keeps its row of_rescore_vectorsNN, whose rowid does not change, and deletes the old_rescore_chunksNNrows with the old chunks. With Port the rest of asg017#268: delete a chunk once DELETE empties it #7, a DELETE that empties a chunk deletes its_rescore_chunksNNrow too._rescore_chunksNNdeclaresrowid INTEGER PRIMARY KEY, as this fork's new tables do, andoversample=Ntakes only digits, where upstream'satoi()readsoversample=8xas 8.The table names are upstream's, so files stay compatible; ARCHITECTURE.md lists them with the other backing tables. As upstream, a table with a rescore column refuses metadata and partition key columns. Distance constraints apply to the exact distances of the
k * oversamplecandidates, sodistance > xcan return fewer thankrows when most candidates are nearer; the README's new section says so, since it describes cursor-based pagination just above.Tests.
_rescore_chunks00holds the quantized form of its vector through inserts, updates, deletes that empty chunks, andoptimize(test_quantized_slots_follow_writes, which a corrupted slot fails); a KNN with an oversample of 1, where the quantized vectors decide the candidates, returns the same rows before and afteroptimize; MMR; non-numeric distance constraints; the missing-rowid point query; the fuzz target rescore-optimize.c.Could not fetch vector data.test_interrupt_is_reported_as_interrupt: a KNN, a full scan, a point query, an insert, an update, a delete, a delete that empties a chunk, andoptimize, each interrupted at every progress handler call. A build whose rescore insert returnsSQLITE_ERRORin place ofvec0_error_rc()'s code fails it.make test-loadable(559 passed, 3 skipped),make test-unitandmake testpass, and so does the Python suite against an AddressSanitizer and UndefinedBehaviorSanitizer build. The build has no warnings, clang-format 21 leavessqlite-vec.cunchanged, and each of the eight rescore fuzz targets ran 60 seconds without a finding.git diff --histogramshows thesqlite-vec.cchange as the insertion it is; the default algorithm pairs lines ofvec0Filter_knn()with look-alike lines of the new code above it.