Learning objectives
After reading this article you will be able to:
- Understand embeddings and distance between vectors
- See how approximate search (HNSW and IVFFlat) gains speed
- Choose between a dedicated vector database and a vector extension on a regular database
A traditional database is good at exact questions: "the user with id 42", "orders with a value above 100". It struggles with "show me the texts about something similar to this", because similar meaning is not the same as matching words. "Put my code on a server" and "deploy" share no terms, yet they say the same thing.
A vector database solves that problem. It powers semantic search, recommendations and much of RAG, which gives an LLM context before it answers.
What is an embedding?#
An embedding is a list of numbers (a vector) that a model produces to represent the meaning of some content. The same model turns "how to host a bot" and "get my bot online" into nearby vectors, and "cake recipe" into a distant one.
Each position in the vector is a dimension. Real models use hundreds or thousands. You do not read the numbers one by one: what matters is the distance between two vectors.
How does the database measure "similar"?#
By the distance between vectors. The three most common measures:
- Cosine distance: compares the direction of the vectors and ignores their length. The most used for text.
- Inner product: measures alignment and magnitude together. Equivalent to cosine when vectors are normalized.
- Euclidean distance (L2): the straight-line distance between the two points.
The example below does the whole search in memory, with three made-up 3-dimensional "documents" (the query vector stands for "put my code on a server"):
import numpy as np
docs = {
"How to host a bot": [0.9, 0.1, 0.0],
"Cake recipe": [0.0, 0.1, 0.9],
"Deploying a Python API": [0.8, 0.3, 0.1],
}
query = np.array([0.85, 0.2, 0.05])
def cosine(a, b):
a, b = np.array(a), np.array(b)
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
ranking = sorted(docs, key=lambda t: cosine(docs[t], query), reverse=True)
for t in ranking:
print(f"{cosine(docs[t], query):.3f} {t}")The output is 0.991 How to host a bot, 0.990 Deploying a Python API and 0.082 Cake recipe. In practice, the vectors come from an embedding model, not from hand-written numbers. Calling that model through an API costs money too, and the math works like LLM API cost.
Why not compare against every vector?#
Comparing the query with every row (exact search, or brute force) gives the perfect result, but the cost grows with the size of the data. With a few thousand vectors, that is fine. With millions, it gets slow.
That is why vector databases use approximate nearest neighbor (ANN) indexes. They trade a little accuracy (recall) for a lot of speed. Two indexes appear in almost every tool:
- HNSW: builds a multilayer graph. It offers the better speed-recall tradeoff, but takes longer to build and uses more memory. It can be created on an empty table.
- IVFFlat: splits vectors into lists (groups) and searches only some of them. It builds faster and uses less memory, but queries perform worse. Create it after the table already has data.
In both cases the result is approximate: the index may, rarely, miss a neighbor that exact search would return.
Dedicated vector database or an extension on a regular one?#
There are two paths:
- An extension on a database you run yourself. Some relational databases, such as PostgreSQL, accept extensions that add a vector type and distance operators. Your vectors sit in the same table and transaction as the rest of your data, and you filter with plain SQL.
- A dedicated vector database. Services and servers built only for vectors, with their own scaling and filtering features. They make sense when volume or latency outgrow what an extension delivers.
For most small and medium projects, starting with the extension avoids running one more system. Migrating later is possible, because the data is just a list of numbers plus an id.
What does a vector search look like in practice?#
The flow is similar in almost every tool:
- Generate the embedding of each document and store the vector with an id and its metadata.
- Create the ANN index with the same distance measure your queries will use. An index built for cosine does not speed up an L2 search.
- At query time, embed the question with the same model and ask for the k nearest neighbors, for example the top 5.
- Tune the recall-speed tradeoff with the index's search parameter: in HNSW, how many candidates the graph examines; in IVFFlat, how many lists are visited.
Always use the same model for documents and queries. Vectors from different models are not comparable, even when they have the same number of dimensions.
When should you not use a vector database?#
- You search by exact word, code or id. A regular index or full-text search does it better.
- The dataset is small. A few thousand vectors fit in memory and brute force is enough.
- You always need the exact result. ANN indexes are approximate.
Search quality, by the way, depends on the embedding model, not the database. A model that is poor for your language or domain returns poor neighbors, however fast the index is.
How to do this on Square Cloud#
Square Cloud does not offer a vector database, and the hosted PostgreSQL is native PostgreSQL with no extensions: no pgvector. Your vectors live in an external vector service or, for a small dataset, in the application's own memory, with the brute-force search from the example above. What you host is the application that runs the flow: an API that receives the question, generates the embedding, queries the vectors and calls the LLM. It runs in an isolated, always-on container and, as a web application, uses at least 512 MB of the plan's RAM pool. See how to publish it in API hosting.
Each piece has its place:
- Embeddings: an external provider. The Python runtime ships prebuilt torch and transformers wheels, but a local embedding model does not fit in the 1 GB Hobby plan.
- Documents and metadata: database hosting starts on Standard, from R$44.99 a month. Hobby, from R$12.49, includes no database.
- The LLM's answer: from Standard, the AI Gateway writes the final text through an OpenAI-compatible API with the
cubicmodel. It does not generate embeddings or store vectors: it only covers the last step, with the retrieved passages in the prompt. It is in beta with early access at no extra cost, and the limits may change when the beta ends.
AI
Host AI apps in always-on containers
FAQs
What is the difference between a vector database and a SQL database?
A SQL database compares exact values (equal, greater than, contains). A vector database orders rows by the distance between vectors, which answers 'what is most similar to this'. Some SQL databases do both through a vector extension.
Do I need a vector database for RAG?
Not necessarily. With a few thousand chunks, an in-memory brute-force search is enough. A dedicated vector database pays off when volume and latency call for an index.
What is an embedding?
It is a list of numbers a model produces to represent the meaning of text, an image or audio. Similar content produces nearby vectors.
More in AI
See all 13 articles- How much does an AI chatbot cost to build and run?Running an AI chatbot costs model tokens, hosting, a database and, with RAG, extra context per message. See how to estimate the cost per conversation.
- How much does a RAG system cost? Embeddings, database and LLMA RAG system has three costs: embeddings, a vector database and the LLM. See the math for 1,000 questions a day, with hypothetical prices, and where the bill grows.
- How to build a Discord AI botBuild a Discord AI bot with discord.js: an /ask command, the API key in an environment variable, per-channel memory, Discord limits and how to host it.
- How to host an AI chatbotAn AI chatbot is an API that takes messages, calls a language model and streams the reply back. Here is the code and how to put it online.