Skip to content

pg_search

Full text search for PostgreSQL using BM25

Overview

PackageVersionCategoryLicenseLanguage
pg_search0.25.2FTSAGPL-3.0Rust
IDExtensionBinLibLoadCreateTrustRelocSchema
2100pg_searchNoYesYesYesNoNoparadedb

Requires shared_preload_libraries=pg_search and pgvector; bm25 access method conflicts with pg_textsearch and vchord_bm25; PIGSTY uses pgrx 0.19.1 for upstream pgrx 0.19.0.

Version

TypeRepoVersionPG VerPackageDeps
EXTPIGSTY0.25.21817161514pg_searchvector
RPMPIGSTY0.25.21817161514pg_search_$vpgvector_$v, openblas
DEBPIGSTY0.25.21817161514postgresql-$v-pg-searchpostgresql-$v-pgvector, libopenblas0
OS / PGPG18PG17PG16PG15PG14
el8.x86_64N/A
el8.aarch64N/A
el9.x86_64N/A
el9.aarch64N/A
el10.x86_64N/A
el10.aarch64N/A
d12.x86_64N/A
d12.aarch64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
d13.x86_64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
d13.aarch64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
u22.x86_64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
u22.aarch64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
u24.x86_64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
u24.aarch64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A
u26.x86_64N/A
u26.aarch64
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
PIGSTY 0.25.2
N/A

Build

You can build the RPM / DEB packages for pg_search using pig build:

pig build pkg pg_search         # build RPM / DEB packages

Install

You can install pg_search directly. First, make sure the PGDG and PIGSTY repositories are added and enabled:

pig repo add pgsql -u          # Add repo and update cache

Install the extension using pig or apt/yum/dnf:

Install
pig install pg_search;          # Install for current active PG version
pig
pig ext install -y pg_search -v 18  # PG 18
pig ext install -y pg_search -v 17  # PG 17
pig ext install -y pg_search -v 16  # PG 16
pig ext install -y pg_search -v 15  # PG 15
dnf
dnf install -y pg_search_18       # PG 18
dnf install -y pg_search_17       # PG 17
dnf install -y pg_search_16       # PG 16
dnf install -y pg_search_15       # PG 15
apt
apt install -y postgresql-18-pg-search   # PG 18
apt install -y postgresql-17-pg-search   # PG 17
apt install -y postgresql-16-pg-search   # PG 16
apt install -y postgresql-15-pg-search   # PG 15

Preload:

shared_preload_libraries = 'pg_search';

Create Extension:

CREATE EXTENSION pg_search CASCADE;  -- requires: vector

Usage

Sources:

pg_search 0.25.2 adds ParadeDB’s full-text, structured, vector, and hybrid search index to PostgreSQL. Version 0.25 uses the paradedb index access method; the older bm25 access-method name remains a compatibility alias. The extension requires vector, supports PostgreSQL 15-18 upstream, and must be loaded through shared_preload_libraries.

Install and Build an Index

shared_preload_libraries = 'pg_search'

Restart PostgreSQL, then create the extension and a table with a stable unique key:

CREATE EXTENSION pg_search CASCADE;

CREATE TABLE documents (
  id          bigint PRIMARY KEY,
  title       text,
  body        text,
  category    text,
  embedding   vector(768)
);

CREATE INDEX documents_search_idx ON documents
USING paradedb (
  id,
  title,
  body,
  category,
  embedding vector_cosine_ops
)
WITH (key_field = 'id');

The key_field must be the first indexed column and uniquely identify every row. A text key must be indexed without tokenization. A table can have only one ParadeDB index, so include every searchable field in that index.

Use ||| to match any token and &&& to require all tokens:

SELECT id, title, pdb.score(id) AS score
FROM documents
WHERE body ||| 'postgresql search'
ORDER BY score DESC, id;

SELECT id, pdb.snippet(body) AS excerpt
FROM documents
WHERE body &&& 'postgresql indexing';

pdb.score(key_field) exposes the relevance score for the current row. pdb.snippet(indexed_text_column) returns a highlighted excerpt. These helpers are meaningful only in a query driven by a ParadeDB search predicate.

Vector indexing is beta in the 0.25 line and uses the vector type from pgvector. Choose the operator class when the index is created; changing the metric requires rebuilding the index.

SELECT id, title, embedding <=> $1::vector AS distance
FROM documents
WHERE id @@@ pdb.all()
ORDER BY embedding <=> $1::vector, id
LIMIT 20;

Supported index operator classes are vector_l2_ops, vector_ip_ops, and vector_cosine_ops. The 0.25 vector index does not index halfvec, sparsevec, or bit columns.

A single ParadeDB index can combine lexical predicates, structured filters, and vector ordering. For more elaborate fusion, use the documented RRF and weighted hybrid-search functions instead of adding scores from unrelated scales directly.

SELECT id, title, pdb.score(id) AS lexical_score
FROM documents
WHERE body ||| 'postgresql extension'
  AND category === 'database'
ORDER BY embedding <=> $1::vector, id
LIMIT 20;

Version 0.25.2 and Caveats

  • Version 0.25 renamed the primary index access method from bm25 to paradedb. Existing USING bm25 definitions remain supported, but new examples should use USING paradedb.
  • Version 0.25.1 supports deterministic vector tie breakers and pushes the vector arm of reciprocal-rank-fusion queries into the index. It also adds paradedb.vector_clustering_threshold, whose default is 500, and caps vector-index build parallelism at four workers.
  • Version 0.25.1 removes paradedb.vector_cluster_probe_epsilon and changes the vector-index bounds gate. After upgrading a database from 0.25.0, REINDEX every ParadeDB index that contains a vector field; installing the new shared library and running ALTER EXTENSION alone is not sufficient for those indexes.
  • Version 0.25.2 is a stability and correctness release. It fixes fieldless more_like_this with vector columns, pdb.fuzzy under generic prepared plans, orphaned dynamic filters, several parallel subplan and MPP plan-shape errors, and tightens access controls for typemod definitions. It adds no further index migration beyond the inherited 0.25.0 vector-index rebuild.
  • CREATE EXTENSION pg_search CASCADE can install the required vector extension, but every server process still needs the preload configuration and restart first. Loading it only with LOAD or session_preload_libraries is insufficient.
  • Query plans, tokenization, and ranking can change when an index is rebuilt with different field options. Test relevance and vector recall with production-shaped data before rollout.

Was this page helpful?