pg_textsearch
Overview
| Package | Version | Category | License | Language |
|---|---|---|---|---|
pg_textsearch | 1.1.0 | FTS | PostgreSQL | C |
| ID | Extension | Bin | Lib | Load | Create | Trust | Reloc | Schema |
|---|---|---|---|---|---|---|---|---|
| 2180 | pg_textsearch | No | Yes | Yes | Yes | No | No | - |
| Related | pg_search pgroonga pg_bigm zhparser pg_trgm rum biscuit fuzzystrmatch |
|---|
bm25 am conflicts with pg_search; must be preloaded via shared_preload_libraries.
Version
| Type | Repo | Version | PG Ver | Package | Deps |
|---|---|---|---|---|---|
| EXT | PIGSTY | 1.1.0 | 1817161514 | pg_textsearch | - |
| RPM | PIGSTY | 1.1.0 | 1817161514 | pg_textsearch_$v | - |
| DEB | PIGSTY | 1.1.0 | 1817161514 | postgresql-$v-textsearch | - |
| OS / PG | PG18 | PG17 | PG16 | PG15 | PG14 |
|---|---|---|---|---|---|
| el8.x86_64 | PIGSTY 1.1.0 el8.x86_64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el8.x86_64.rpm
| PIGSTY 1.1.0 el8.x86_64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el8.x86_64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| el8.aarch64 | PIGSTY 1.1.0 el8.aarch64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el8.aarch64.rpm
| PIGSTY 1.1.0 el8.aarch64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el8.aarch64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| el9.x86_64 | PIGSTY 1.1.0 el9.x86_64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el9.x86_64.rpm
| PIGSTY 1.1.0 el9.x86_64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el9.x86_64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| el9.aarch64 | PIGSTY 1.1.0 el9.aarch64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el9.aarch64.rpm
| PIGSTY 1.1.0 el9.aarch64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el9.aarch64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| el10.x86_64 | PIGSTY 1.1.0 el10.x86_64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el10.x86_64.rpm
| PIGSTY 1.1.0 el10.x86_64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el10.x86_64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| el10.aarch64 | PIGSTY 1.1.0 el10.aarch64.pg18 : pg_textsearch_18 pg_textsearch_18-1.1.0-1PIGSTY.el10.aarch64.rpm
| PIGSTY 1.1.0 el10.aarch64.pg17 : pg_textsearch_17 pg_textsearch_17-1.1.0-1PIGSTY.el10.aarch64.rpm
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| d12.x86_64 | PIGSTY 1.1.0 d12.x86_64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~bookworm_amd64.deb
| PIGSTY 1.1.0 d12.x86_64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~bookworm_amd64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| d12.aarch64 | PIGSTY 1.1.0 d12.aarch64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~bookworm_arm64.deb
| PIGSTY 1.1.0 d12.aarch64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~bookworm_arm64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| d13.x86_64 | PIGSTY 1.1.0 d13.x86_64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~trixie_amd64.deb
| PIGSTY 1.1.0 d13.x86_64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~trixie_amd64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| d13.aarch64 | PIGSTY 1.1.0 d13.aarch64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~trixie_arm64.deb
| PIGSTY 1.1.0 d13.aarch64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~trixie_arm64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u22.x86_64 | PIGSTY 1.1.0 u22.x86_64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~jammy_amd64.deb
| PIGSTY 1.1.0 u22.x86_64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~jammy_amd64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u22.aarch64 | PIGSTY 1.1.0 u22.aarch64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~jammy_arm64.deb
| PIGSTY 1.1.0 u22.aarch64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~jammy_arm64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u24.x86_64 | PIGSTY 1.1.0 u24.x86_64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~noble_amd64.deb
| PIGSTY 1.1.0 u24.x86_64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~noble_amd64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u24.aarch64 | PIGSTY 1.1.0 u24.aarch64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~noble_arm64.deb
| PIGSTY 1.1.0 u24.aarch64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~noble_arm64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u26.x86_64 | PIGSTY 1.1.0 u26.x86_64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~resolute_amd64.deb
| PIGSTY 1.1.0 u26.x86_64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~resolute_amd64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
| u26.aarch64 | PIGSTY 1.1.0 u26.aarch64.pg18 : postgresql-18-textsearch postgresql-18-textsearch_1.1.0-1PIGSTY~resolute_arm64.deb
| PIGSTY 1.1.0 u26.aarch64.pg17 : postgresql-17-textsearch postgresql-17-textsearch_1.1.0-1PIGSTY~resolute_arm64.deb
| PIGSTY MISS | PIGSTY MISS | PIGSTY MISS |
Build
You can build the RPM / DEB packages for pg_textsearch using pig build:
pig build pkg pg_textsearch # build RPM / DEB packages
Install
You can install pg_textsearch 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:
pig install pg_textsearch; # Install for current active PG version
pig ext install -y pg_textsearch -v 18 # PG 18
pig ext install -y pg_textsearch -v 17 # PG 17
dnf install -y pg_textsearch_18 # PG 18
dnf install -y pg_textsearch_17 # PG 17
apt install -y postgresql-18-textsearch # PG 18
apt install -y postgresql-17-textsearch # PG 17
Preload:
shared_preload_libraries = 'pg_textsearch';
Create Extension:
CREATE EXTENSION pg_textsearch;
Usage
Sources: README v1.1.0, v1.1.0 release notes
pg_textsearch provides BM25-ranked full-text search for PostgreSQL with a bm25 access method and the <@> scoring operator. Upstream marks v1.1.0 as production ready.
v1.1.0 supports PostgreSQL 17 and 18. Prebuilt release assets are published for both PostgreSQL versions on Linux and macOS. The extension must be loaded through shared_preload_libraries before CREATE EXTENSION.
Enable the Extension
shared_preload_libraries = 'pg_textsearch' # add to any existing list
CREATE EXTENSION pg_textsearch;
Install the new binary and restart PostgreSQL before running an extension upgrade:
ALTER EXTENSION pg_textsearch UPDATE;
Upstream says upgrading from 1.0.0 to 1.1.0 does not require REINDEX.
Build and Query BM25 Indexes
CREATE TABLE documents (id bigserial PRIMARY KEY, content text);
CREATE INDEX docs_idx
ON documents USING bm25(content)
WITH (text_config = 'english');
SELECT *
FROM documents
ORDER BY content <@> 'database system'
LIMIT 5;
<@> returns the negative BM25 score because PostgreSQL operator index scans are ascending; lower values are better matches. Use ORDER BY ... LIMIT for fast top-k searches.
For an explicit index reference, use to_bm25query():
SELECT *
FROM documents
ORDER BY content <@> to_bm25query('database system', 'docs_idx')
LIMIT 5;
The main documented SQL surface is:
text <@> 'query'to score text with planner-detected index context.text <@> bm25queryto score with an explicitbm25query.to_bm25query(text)for ORDER BY use with planner-selected index context.to_bm25query(text, text)for query text plus index name.bm25query = bm25queryfor equality checks.
Index Options and Data Shapes
CREATE INDEX ON documents USING bm25(content)
WITH (text_config = 'english', k1 = 1.5, b = 0.8);
Index options are text_config (required), k1 (default 1.2), and b (default 0.75). Text search configurations such as english, simple, french, and german use PostgreSQL text search configuration names.
v1.1.0 adds native array input support for text[], varchar[], and bpchar[] columns; array elements are concatenated before tokenization.
CREATE TABLE posts (id serial PRIMARY KEY, tags text[]);
CREATE INDEX posts_tags_idx ON posts USING bm25(tags)
WITH (text_config = 'english');
SELECT *
FROM posts
ORDER BY tags <@> 'database'
LIMIT 10;
Expression indexes support immutable text expressions, including JSONB extraction, text transformations, and multi-column concatenation:
CREATE INDEX events_msg_idx ON events USING bm25 ((data->>'message'))
WITH (text_config = 'english');
SELECT *
FROM events
ORDER BY (data->>'message') <@> to_bm25query('network error', 'events_msg_idx')
LIMIT 10;
Partial indexes scope search to a subset of rows. Query them with an explicit index name:
CREATE INDEX docs_en_idx ON docs USING bm25(content)
WITH (text_config = 'english')
WHERE lang = 'en';
SELECT *
FROM docs
WHERE lang = 'en'
ORDER BY content <@> to_bm25query('databases', 'docs_en_idx')
LIMIT 10;
Operations and GUCs
SELECT bm25_force_merge('docs_idx');
SELECT * FROM bm25_memory_usage();
bm25_force_merge(index_name) consolidates all segments into one and is best used after bulk loads, not during steady write traffic. bm25_memory_usage() reports shared memory usage for memtables.
Documented pg_textsearch GUCs in v1.1.0 include:
pg_textsearch.default_limitpg_textsearch.compress_segmentspg_textsearch.segments_per_levelpg_textsearch.memory_limitpg_textsearch.bulk_load_thresholdpg_textsearch.memtable_spill_threshold(deprecated; usememory_limitfor new deployments)
pg_textsearch.memory_limit defaults to 2GB and caps dynamic shared memory used by memtables. The release notes also call out improved concurrent insert throughput, faster VACUUM via segment alive bitsets, subtransaction cleanup, and parallel build race fixes.
Caveats
pg_textsearchrequiresshared_preload_libraries = 'pg_textsearch'and a PostgreSQL restart beforeCREATE EXTENSION.- Inside PL/pgSQL and stored procedures, the implicit
text <@> 'query'form does not use planner hooks; upstream says to useto_bm25query()with an explicit index name there. - Phrase queries are not native because the index stores term frequencies, not term positions; use BM25 ranking plus a post-filter for phrase-like matching.
- Partial indexes require
to_bm25query()with the index name because the implicit query form skips them. - BM25 indexes on partitioned tables use partition-local statistics, so cross-partition scores may not be directly comparable.
- Words longer than PostgreSQL’s
tsvectorword length limit are ignored during tokenization.
Feedback
Was this page helpful?
Thanks for the feedback! Please let us know how we can improve.
Sorry to hear that. Please let us know how we can improve.