Run your first BM25 ranked full-text search query in PostgreSQL with vchord_bm25.
Important
Current source targets 0.4.0 (unreleased), with native tsvector and a new index format. Examples labeled 0.3.x use the historical bm25vector API. In-place upgrades are blocked; read the 0.4.0 migration guide before changing binaries.
This guide walks through creating a table, tokenizing documents, building a bm25 index, and executing Top-K BM25 queries.
Need domain-specific vocabulary, Chinese (jieba), or Japanese (lindera)? See the Tokenizers (pg_tokenizer) section.
3. Create a Table and Populate Documents
CREATETABLEdocuments(idSERIALPRIMARYKEY,passageTEXTNOTNULL,embeddingbm25vector);INSERTINTOdocuments(passage)VALUES('PostgreSQL is a powerful, open-source object-relational database system. It has over 35 years of active development.'),('Full-text search is a technique for searching a single computer-stored document or a collection in a full-text database.'),('BM25 is a bag-of-words retrieval function that ranks a set of documents based on the query terms appearing in each document.'),('VectorChord-bm25 is a PostgreSQL extension that provides native BM25 ranking index using the Block-WeakAnd algorithm.');
4. Tokenize Documents into bm25vector
tokenize(text, tokenizer_name) returns an INT[] array of token IDs, which implicitly casts to bm25vector (aggregating duplicate token IDs into term frequencies):
UPDATEdocumentsSETembedding=tokenize(passage,'my_tokenizer');-- Inspect the sparse bm25vector representation ({token_id:term_frequency, ...})
SELECTid,embeddingFROMdocumentsLIMIT2;
Why is <&> negative?
PostgreSQL only supports index-driven ORDER BY scans in ascending (ASC) order. Therefore, <&> returns the negative BM25 score (e.g., -2.8415). More negative values represent higher relevance, allowing ORDER BY embedding <&> to_bm25query(...) ASC LIMIT K to use the Block-WeakAnd index scan directly. Negate the expression (-(embedding <&> ...)) in SELECT if you want positive scores displayed.
Workflow B: Native tsvector API (main Branch)
In the next-generation main branch rewrite, vchord_bm25 indexes PostgreSQL’s native tsvector type directly—no external tokenizer extension is required for standard languages.
1. Create Extension and Table
CREATEEXTENSIONIFNOTEXISTSvchord_bm25CASCADE;CREATETABLEdocuments(idSERIALPRIMARYKEY,passageTEXTNOTNULL,vectortsvectorGENERATEDALWAYSAS(to_tsvector('english',passage))STORED);INSERTINTOdocuments(passage)VALUES('PostgreSQL is a powerful, open-source object-relational database system.'),('Full-text search is a technique for searching documents in a full-text database.'),('BM25 is a bag-of-words retrieval function that ranks documents based on query terms.'),('VectorChord-bm25 provides a native BM25 ranking index in PostgreSQL.');