Skip to main content
pg_pinecone can rank a Postgres table’s rows by meaning with semantic search, using a Pinecone index it keeps in sync with the table. Pinecone can embed one of the table’s text columns with a hosted model, or you can store your own vectors in a vector column.

Before you begin

  • pg_pinecone installed.
  • A Pinecone API key stored in the database. Store it with SELECT pinecone.set_api_key('YOUR_API_KEY');.
  • pg_pinecone in shared_preload_libraries, followed by a Postgres restart. See Preload the extension.
  • A table with a single-column primary key, which becomes each document’s ID. You must own the table.
  • A Pinecone plan that includes the hosted model you use. For example, gemini-embedding-2 requires a Builder, Standard, or Enterprise plan.

Search by meaning

1

Create a sample table

This guide uses a table of notes:
SQL
2

Embed a text column

Call pinecone.track_docs() and give one text column an embed option. Pinecone then embeds that column’s text with a hosted model on every write and every query, using integrated embedding:
SQL
This creates a Pinecone index and copies the table’s existing rows to it, then keeps it in sync. To check when the initial copy is done, see the full-text search guide.
3

Search the table

Search with mode => 'embed'. Pinecone embeds the query with the same model and ranks rows by similarity:
SQL
The two notes about search rank first, though neither contains the words “finding information”:
Output
Keep these points in mind:
  • Model settings: pg_pinecone passes the embed object to Pinecone. model is required, and you can also set dimension, metric, processing_location, write_parameters, and read_parameters. Pinecone fills in defaults for anything you leave out.
  • Keyword and semantic search on one column: The column keeps its full-text index, so mode => 'text' still ranks it with BM25. Semantic and BM25 scores use different scales. To rank by both, run two searches and merge the results by rank.
  • Filters: mode => 'embed' works with filter and must, so you can rank by meaning within rows that match a metadata value or required text. For examples, see the full-text search guide.
  • One embedded column: Only one text column can set embed, and you can’t combine it with vector_column.
  • Empty text: A row whose embed column is NULL or blank isn’t indexed. If Pinecone already has a copy of that row, pg_pinecone deletes it.
If your table already stores embeddings, declare the column with vector_column instead of using embed. Then pass a query vector with vector, and name the column the text query must match with field. The text query narrows the results to rows that match it in that column, and the vector ranks what’s left. This example uses the articles table from Search a table with full-text search, which declares vector_column => 'embedding':
SQL
Output

Embed a field on an index directly

To embed a field on an index that isn’t tied to a table, add the same embed object to the field in pinecone.create_doc_index(), then search it with an embed clause in pinecone.search_doc_index():
SQL
To add documents with pinecone.upsert_docs() and delete the index with pinecone.drop_doc_index(), see the full-text search guide.