Skip to main content
Traditional search matches exact keywords. Vector search matches by meaning — so a query for “javascript tips” also returns results about “js performance” or “node.js tricks” even if those exact words aren’t in the query. The way it works:
  1. You send text to an embedding model (an AI model that converts text to numbers)
  2. The model returns a list of numbers called an embedding — e.g. [0.02, -0.14, 0.87, ...]
  3. You store that embedding alongside each record in the database
  4. When searching, you convert the search query to an embedding the same way, then find records whose embeddings are mathematically closest
Do you need an AI model? Yes — an embedding model is required to convert text into vectors. You can use a hosted API like OpenAI Embeddings, Cohere, or Voyage AI, or run a model locally with Ollama. IlanaORM doesn’t include an embedding model — you bring your own and plug it in as a function.
pgvector is PostgreSQL only. It does not work with MySQL or SQLite.

Setup

1. Enable the pgvector extension

In a migration:

2. Add an embedding column

The number of dimensions must match your embedding model’s output. OpenAI’s text-embedding-ada-002 outputs 1536 dimensions.

3. Configure the model

Tell IlanaORM which column holds embeddings and provide a function that converts text to a vector:

Storing embeddings

When creating or updating a record, generate and store the embedding:
Or use a model event to do it automatically:

Searching

Model.search(text, options?)

Converts the search text to a vector using the embedding provider, then finds the nearest records:

Model.nearestTo(vector, options?)

Search by a raw vector — useful when you already have a pre-computed embedding:

Results

Each result has a distance attribute — lower means more similar (for cosine and l2):

Distance metrics

For most text search use cases, cosine is the right choice.

Performance

Add an index so similarity queries don’t scan the entire table:
Without an index, PostgreSQL does an exact scan of every row — fine for small tables, slow for large ones.