rent
PostgreSQL extensions

ParadeDB pg_search

What it is

ParadeDB pg_search adds BM25-ranked full-text search and faceted analytics directly to PostgreSQL. The index stays beside the source table, so application writes do not need a separate search synchronization pipeline.

What it provides

  • BM25 relevance ranking across multiple fields
  • Tokenizers, fuzzy matching, phrase queries, highlighting, and facets
  • Search indexes maintained with the PostgreSQL data they cover

Use it for product catalogs, documentation search, support tickets, log exploration, faceted navigation, or hybrid lexical-and-vector retrieval.

Use it with Rent

extension pg_search {
  name = "pg_search"
}

The RSL declaration makes installation and migration intent part of the reviewed application schema. Register the typed pack at runtime to call its APIs:

let search = extensions.register_pack::<PgSearch>()?;
let index = Bm25Index::new(
    &search,
    "posts_search",
    ["id", "title", "body"],
    "id",
)?
.fast_text_field("title")?;

let migration_operation = index.operation("public", "posts")?;

let query = search.search(
    post::body(),
    "rust database toolkit",
);

let posts = client
    .post()
    .where_raw(query.predicate())
    .order_by_expression_desc(query.rank(post::id()))
    .limit(20)
    .all()
    .await?;

let highlighted_body = query.highlight();
let title_facets = query.facet(
    serde_json::json!({"terms": {"field": "title"}}),
);

Text fields used for facets or sorting must be stored as fast fields. fast_text_field validates that the field is included in the index and emits ParadeDB's text_fields configuration for the migration.

Rent's ParadeDB profile verifies the generated index operation against an image that contains pg_search.

Run the application

cargo run -p rent --example extension_07_pg_search

Set DATABASE_URL to a disposable ParadeDB server whose role can create databases. The application creates a BM25 index through Rent's migration API, inserts posts about databases and cooking, and searches for Rust. It checks the matching post, a positive relevance score, the highlighted body, and the title facet. It also checks an empty result and that hostile search text cannot escape into another SQL statement. The isolated database is removed afterward.

Treat highlighted snippets as untrusted content when rendering them in HTML. Search ranking is not a stable pagination key by itself; add a unique tie-breaker when paginating equally ranked results. Its standalone extension declaration is crates/rent/examples/extension_07_pg_search/schema.rsl.

On this page