Apresentação
🗄️ Vector Databases — Similarity Search em Escala
Armazena embeddings de documentos e permite retrieval por similaridade semântica. Fundamental para RAG e sistemas de AI.
🎯 Frase que impressiona
Penso em vector databases como a espinha dorsal de retrieval do RAG — a escolha depende da escala, latência e se precisas de hybrid search ou filtragem por metadados. HNSW para recall, filtros de metadados para multi-tenancy, e consistência de embeddings é não negociável.
1️⃣ Fluxo: Query → Retrieval
Query text → Embedding model → Vector (d dims)
↓
Vector DB similarity search
↓
Top-k nearest neighbors
↓
Chunks + metadata
↓
Reranker (opcional) → LLM
2️⃣ Similarity Metrics — Quando cada um
| Métrica | Fórmula | Quando usar |
|---|---|---|
| Cosine | cos(θ) = A·B / (‖A‖‖B‖) | Embeddings normalizados. [-1, 1]. Padrão em RAG. |
| Dot product | A·B | Se vetores normalizados ≈ cosine. Mais rápido (sem divisão). |
| Euclidean (L2) | ‖A - B‖ | Distância. Menor = mais similar. Requer normalização para comparar. |
Embeddings (OpenAI, Cohere): normalizados → cosine = dot product. Cosine ignora magnitude — textos de tamanhos diferentes comparáveis.
3️⃣ ANN — Approximate Nearest Neighbor
Exact search: compara query com todos os vetores. O(n). Só para <100k docs.
ANN: sublinear. Tradeoff recall vs velocidade. Escala a milhões.
HNSW (Hierarchical Navigable Small World)
- Grafo em camadas: topo esparso (poucos nós), base denso
- Busca: greedy do topo para baixo. Em cada nível: vai para vizinho mais próximo
- Parâmetros:
M(vizinhos por nó),ef_construction(qualidade na construção),ef_search(qualidade na query) - Complexidade: ~O(log n). Usado em Pinecone, Weaviate, Qdrant, Milvus
IVF (Inverted File Index)
- Agrupa vetores em clusters (k-means). Query → encontra clusters mais próximos → search só nesses
- nlist, nprobe: nlist = nº clusters, nprobe = clusters a pesquisar na query
- Bom para datasets muito grandes. Milvus, FAISS
LSH (Locality Sensitive Hashing)
- Hash similar → mesmo bucket. Aproximação por hashing
- Menos preciso que HNSW. Mais barato em memória
4️⃣ Ferramentas — Comparação
| Ferramenta | Escala | Managed | Filtros | Hybrid | Uso |
|---|---|---|---|---|---|
| Pinecone | Muito alto | ✅ Cloud | ✅ | ✅ | Produção, serverless, escala |
| Qdrant | Alto | Cloud ou self | ✅ | ✅ | Open source, boa perf |
| Weaviate | Alto | Cloud ou self | ✅ | ✅ | GraphQL, módulos |
| Chroma | Baixo-médio | Self | ✅ | ❌ | Dev, POC, simples |
| pgvector | Médio (<10M) | Self (Postgres) | ✅ SQL | ❌ | Já tens Postgres, ACID |
| Milvus | Muito alto | Self ou Zilliz | ✅ | ✅ | Enterprise, distributo |
| FAISS | Alto | In-memory | ❌ | ❌ | Pesquisa, não DB |
5️⃣ pgvector (PostgreSQL)
Extensão: CREATE EXTENSION vector. Tipo vector(1536) para OpenAI embeddings.
Operadores:
<=>— cosine distance (menor = mais similar)<->— L2 distance<#>— negative dot product
Índices:
- IVFFlat:
CREATE INDEX ON t USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);— mais rápido construção - HNSW:
CREATE INDEX ON t USING hnsw (embedding vector_cosine_ops);— melhor recall, mais lento build
Quando usar: já tens Postgres, <10M vetores, querer ACID, queries mistas (SQL + vector). Ex: filtrar por tenant_id + similarity.
6️⃣ Metadata Filtering
Pre-filter: filtra por metadata ANTES do vector search. Ex: WHERE tenant_id = X → depois similarity nos resultados filtrados. Pode reduzir recall se filtro muito restritivo.
Post-filter: vector search primeiro, depois filtra. Pode perder resultados se top-k não tem diversidade de metadata.
Híbrido: alguns DBs (Pinecone, Qdrant) fazem filtering durante o search — melhores dos dois mundos.
Multi-tenancy: SEMPRE filtrar por tenant_id ou namespace. tenant_id do auth (JWT), nunca do user input.
7️⃣ Hybrid Search no Vector DB
Alguns DBs combinam vector + keyword (BM25) numa única query:
- Weaviate: módulo
bm25+vector - Pinecone: pode fazer em aplicação (2 queries, fusão RRF)
- Qdrant: full-text + vector
- Elasticsearch: knn + keyword
RRF (Reciprocal Rank Fusion): fundir rankings. score = Σ 1/(k + rank_i). k=60 comum.
8️⃣ Indexing e Performance
Embedding consistency: MESMO modelo para index e query. Trocar modelo = reindexar tudo.
Batch upsert: mais eficiente que um a um. 100-1000 vectors por batch.
Reindexing: ao mudar índice (ex: IVFFlat → HNSW), ou modelo de embedding. Planejar downtime ou blue-green.
Tuning HNSW: ef_search alto = melhor recall, mais lento. ef_construction alto = índice melhor, build mais lento.
9️⃣ Escolher Vector DB — Critérios
| Critério | Perguntas |
|---|---|
| Escala | Quantos vetores? Milhões? Sharding? |
| Latência | p50, p99? <100ms? |
| Filtros | Metadata filtering? Multi-tenant? |
| Hybrid | Precisa BM25 + vector? |
| Managed | Ops próprio ou cloud? |
| Custo | Por pod, por query, storage? |
| Consistência | ACID? Eventual? |
🔟 Namespaces e Multi-Tenancy
Namespace/Collection por tenant: tenant_123, tenant_456. Cada query filtra: WHERE namespace = :tenant_id.
tenant_id: SEMPRE de auth (JWT, API key). NUNCA do user input (prompt injection).
Isolamento: garantia de que retrieval nunca devolve docs de outro tenant.
🔧 Hands-on — Building RAG pipelines com Vector DBs
Experiência prática com Pinecone, Weaviate, Qdrant, pgvector. Cada um tem API diferente; o fluxo é o mesmo: embed → upsert → query.
Fluxo comum (todos)
1. Documentos → Chunking → Embedding model → Vetores
2. Upsert: vetores + metadata → Vector DB
3. Query: embed(query) → similarity_search → top-k chunks
4. Chunks + query → LLM → resposta
Pinecone
Managed, serverless. Escala automática. Bom para produção.
import pinecone
from openai import OpenAI
pinecone.init(api_key="...", environment="us-east-1")
index = pinecone.Index("rag-index")
# Upsert
vectors = [(id, embedding, {"text": chunk, "source": doc_id}) for id, embedding, chunk, doc_id in ...]
index.upsert(vectors=vectors)
# Query
res = index.query(vector=query_embedding, top_k=5, include_metadata=True)
chunks = [r["metadata"]["text"] for r in res["matches"]]
Quando: Produção, escala alta, não queres gerir infra.
Weaviate
Self-host ou Cloud. GraphQL API. Módulos para embeddings, BM25, etc.
import weaviate
client = weaviate.Client("http://localhost:8080")
# Schema com vectorizer
client.schema.create_class({"class": "Document", "vectorizer": "text2vec-openai", "properties": [{"name": "content", "dataType": ["text"]}]})
# Upsert
client.data_object.create({"content": chunk}, "Document", vector=embedding)
# Query (GraphQL)
res = client.query.get("Document", ["content"]).with_near_vector({"vector": query_embedding}).with_limit(5).do()
Quando: Queres hybrid search (vector + BM25), GraphQL, módulos.
Qdrant
Open source, boa performance. REST ou Python client.
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, VectorParams, Distance
client = QdrantClient("localhost", port=6333)
client.create_collection("docs", vectors_config=VectorParams(size=1536, distance=Distance.COSINE))
# Upsert
client.upsert(collection_name="docs", points=[PointStruct(id=i, vector=emb, payload={"text": chunk}) for i, emb, chunk in ...])
# Query
hits = client.search(collection_name="docs", query_vector=query_embedding, limit=5)
chunks = [h.payload["text"] for h in hits]
Quando: Self-host, controlo total, hybrid search.
pgvector (PostgreSQL)
Extensão do Postgres. Já tens Postgres? Adiciona vector.
# SQL
# CREATE EXTENSION vector;
# CREATE TABLE docs (id SERIAL, embedding vector(1536), content TEXT, metadata JSONB);
# CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops);
import psycopg2
from pgvector.psycopg2 import register_vector
conn = psycopg2.connect("postgresql://...")
register_vector(conn)
# Upsert
cur.execute("INSERT INTO docs (embedding, content) VALUES (%s, %s)", (embedding, chunk))
# Query (cosine distance)
cur.execute("SELECT content FROM docs ORDER BY embedding <=> %s LIMIT 5", (query_embedding,))
chunks = [r[0] for r in cur.fetchall()]
Quando: Já tens Postgres, <10M vetores, queries mistas (SQL + vector), ACID.
Comparação prática
| DB | Setup | Latência | Hybrid | Multi-tenant |
|---|---|---|---|---|
| Pinecone | API key, index name | Muito baixa | Sim | Namespaces |
| Weaviate | Docker ou Cloud | Baixa | Nativo (BM25) | Filtros |
| Qdrant | Docker, config | Baixa | Sim | Filtros |
| pgvector | CREATE EXTENSION | Média | Não (fazer em app) | WHERE tenant_id |
Para entrevista: Já construí pipelines RAG com [Pinecone/pgvector/...]. O fluxo é chunking → embed → upsert. Na query, embed da pergunta, similarity search, top-k no prompt. O que varia é a API do vector DB e se uso managed ou self-host.
Ferramentas Resumidas
| Categoria | Ferramentas |
|---|---|
| Managed | Pinecone, Weaviate Cloud, Qdrant Cloud |
| Self-host | Qdrant, Weaviate, Milvus, Chroma |
| Database ext | pgvector (Postgres) |
| Library | FAISS (in-memory, pesquisa) |
Zona de prática
Sem perguntas. Clica em Editar para adicionar.