Contents
Changelog
All notable changes to pg_fts are documented here.
0.2.0
Breaking: the index access method was renamed bm25 → fts
(CREATE INDEX ... USING fts (to_ftsdoc('english', body))). This lets pg_fts
coexist in the same database as Timescale pg_textsearch (whose AM is named
bm25), so a pg_textsearch workload can be migrated one index at a time rather
than in a single hard cutover. Existing USING bm25 indexes must be recreated
as USING fts. The BM25 scoring functions (fts_bm25, fts_bm25f,
fts_bm25_opts) are unchanged — BM25 is the ranking algorithm, fts is the
access method.
- On-disk format version check: opening an index whose stored format version
does not match the loaded shared library now raises a clear error
(
... has pg_fts on-disk format version N, but this build expects M) with aREINDEXhint, instead of silently misreading the index. - New
doc/MIGRATING_FROM_PG_TEXTSEARCH.md: query/DDL rewrite table, the multi-column → concatenated-to_ftsdocpattern, and index build sizing (CREATE INDEXbounds build memory tomaintenance_work_mem).
0.1.0 — initial public release
First public release. The extension was developed as an internal, qualified
feature series (each stage clean under --enable-cassert, regression-green)
that reached internal version 1.20 before being squashed to a single 0.1.0
install script for release. Versioning starts at 0.1.0 to signal that the
on-disk format and ranked-query performance will iterate before 1.0.
Included in 0.1.0:
ftsdoc/ftsquerytypes, the@@@match operator, and the<=>relevance-ordering operator (ORDER BY d <=> q LIMIT kplans as an index scan, no Sort).- The
bm25inverted-index access method: WAL-logged via GenericXLog (crash-safe, physical-replication safe), MVCC-correct (per-segment tombstones), segmented (Lucene/Tantivy-style) on-disk format with a size-tiered background merge, block-max WAND / MaxScore top-k with lazy per-column decode. - Okapi BM25 scoring with the lucene / robertson / atire / bm25+ / bm25l variants; BM25F multi-field weighting; index-maintained corpus statistics (N, avgdl, per-term df) so ranking needs no heap recheck.
- A rich query language over one operator: boolean, phrase
"a b c", NEAR, prefixterm*, fuzzyterm~k(Levenshtein DFA), and regex/re/, with a trigram pre-filter for fuzzy/regex. fts_highlight()/fts_snippet();tsquery_to_ftsquery()migration helper and cast.- Incremental maintenance (INSERT appends to a pending list, no REINDEX);
fts_merge()andfts_vacuum()(compact + truncate) for on-demand maintenance. fts_count()and a transparentcount(*) ... WHERE @@@CustomScan pushdown for MVCC-correct bulk counts from the index — a capability the specialist BM25 extensions do not expose.- Parallel index build/merge; standalone PGXS build plus Nix flake and a Windows/MSVC meson recipe; supported on PostgreSQL 17, 18, and 19/devel.
Known performance position (see bench/RESULTS_VS_VCHORD_PGTEXTSEARCH.md and
HANDOFF.md): pg_fts is far faster than the built-in tsvector/GIN + ts_rank
stack on ranked retrieval (up to ~40×), but trails the specialist BM25
extensions (VectorChord-bm25, Timescale pg_textsearch) on raw ranked latency and
index size, because it stores positional postings for phrase/NEAR. Closing that
gap is a posting-codec rewrite tracked in ROADMAP.md; 0.1.0 ships on its
distinguishing strengths — query-language breadth, index-native COUNT, and
MVCC/crash correctness — and will iterate on ranked performance.