search-index
v0.1.0Hybrid vector and full-text search primitives over module-owned SQLite (vec0, fts5) and PostgreSQL (pgvector, tsvector) tables.
Run
wippy run kickside/search-indexKickSide Search Index
kickside.search_index:index runs hybrid retrieval over tables that the
calling module owns. The library owns no schema and no connection: the caller
passes an open connection and a table spec.
Table spec
vectors: Vector table: avec0virtual table on SQLite, a table with avector(512)column on PostgreSQL.vector_key: Column invectorsthat references the row id.vector_column: Vector column, defaultembedding.rows: Row table that holds the searchable content.row_key: Row id column.partition: Column present on both tables that scopes every search (avec0partition key on SQLite).columns: Row columns returned with each hit.fts/fts_key: SQLitefts5table and its row-id column.tsvector: PostgreSQLtsvectorcolumn onrows.json_columns: Row columns decoded from JSON text.
Functions
search(db, spec, vector, {partition, limit, filters, query_text}): dense search without query text; with query text, reciprocal-rank fusion of lexical and dense candidates.dense_search,lexical_search,lexical_query,fuse: the parts ofsearch.filtersis a list of{column, values, table = "rows" | "vectors"}equality orINconstraints.vector_literal,placeholders,insert_rows_tx,VECTOR_DIMENSIONS.
db is a pooled connection, not a transaction: on PostgreSQL a dense search
runs in its own read transaction with hnsw.iterative_scan = strict_order, so
an HNSW index keeps scanning until the partition and filters admit limit
rows on pgvector 0.8 or later. Earlier versions retain their existing index
scan behavior without receiving an unsupported setting. The setting is local
to the read transaction and does not change the caller's session defaults.
Each hit carries id and similarity; fused hits also carry
vector_similarity, vector_rank, lexical_rank and hybrid_score.