Quando NON usare vector DB: alternative ranking
Vector database come Pinecone e Weaviate sono la moda del 2026. Ma in 7 su 10 caso d'uso reali, alternative come BM25, Elasticsearch e Redis outperformano i VDB su costi e relevance. Guida pragmatica alle scelte di ranking quando i vector DB sono overkill.
Answer-First: quando i VDB NON servono
Vector database brillano per similarità semantica su miliardi di record. Ma se il tuo use case rientra in uno di questi scenari, scegli altro:
- Keyword-focused search (90%+ query match esatto): BM25 batte VDB su speed, cost e relevance. Un utente cerca "budget tracker app"? BM25 trova titoli esatti in <5ms. VDB genera embedding, aggiunge latenza, e spesso rankizza male i match keyword.
- Dataset <1M record con accesso <100 QPS: Postgres full-text search, Elasticsearch open-source o Redis + Lua script costano 10x meno e predicono meglio di Pinecone per query semplici.
- Ranking multi-fattore (prezzo, rating, freshness): I VDB non hanno capacità di leggere fattori strutturali e re-rankizzare base su regole aziendali. Elasticsearch BM25 + scripting lo fa nativamente.
- Retrieval on sparse/structured data (relazioni graph-like): Se il ranking dipende da link tra entità ("show me articles authored by reviewers che hanno dato 5-star"), graph database o SQL vince. Vector similarity non capisce grafi.
- Latency-critical (<10ms SLA) con embedding batch: Se devi calcolare embedding a query-time, il costo computazionale è proibitivo. Metti BM25 pre-computed.
Risultato: Il 70% dei siti che oggi "dovrebbero" usare VDB funzionerebbero meglio (e risparmierebbe) con una stack BM25 + Elasticsearch + Redis per ranking custom. VDB è la soluzione ottimale per il rimanente 30%: similarity multi-lingua, dense retrieval su unstructured docs a scale, recommendation engine su user behavior embedding.
1. Cos'è un Vector DB e quando REALMENTE brillano
Un vector database memorizza embedding (vettori N-dimensionali) e trova k-nearest-neighbors via indexing approssimativo (HNSW, IVF). Designed per: "dammi i 10 articoli semanticamente più simili a questa query", dove semantico significa "contenuto concettualmente affine indipendentemente dalle parole usate".
Caso d'uso ideale: Utente scrive in francese "comment gagner de l'argent en ligne", il tuo backend ha 10M articoli IT/EN/FR. VDB genera embedding della query, cerca i 100 vicini, re-rankizza con LLM. Output: articoli rilevanti anche se non matchano keyword esatte.
Caso d'uso pessimo: Utente cerca "iPhone 15 Pro Max 256GB silver". Match esatto al titolo del prodotto. VDB introduce latenza (embedding + kNN search), e il ranking spesso scorpora questo match a favore di articoli "concettualmente simili" (altri smartphone) che l'utente non vuole. BM25 avrebbe risolto in 2ms.
2. Il costo nascosto dello storage vettoriale
Un vector database non riduce solo il tempo di query: aumenta i costi operativi in modi non ovvii.
- Embedding computation: Con embedding-on-write, ogni nuovo documento genera un embedding tramite LLM (API cloud proprietaria o Ollama on-prem). Su 100K documenti al mese, API cloud costa €0.02 per 1K token embedding (€2K/mese). Con Ollama on-prem risparmi in API cost, ma aggiungi costo di GPU locale.
- Storage moltiplicato: Un articolo è 5KB di testo; l'embedding è 3KB (384-dim float32). Totale è 8KB. Multiply 10M articoli = 80GB on-disk + 80GB in-memory HNSW index = 160GB RAM. Singola istanza Pinecone per questo volumenè €500-1000/mese. Redis con persistenza costa €50-150 ma hai overhead di maintenance.
- Latency non sempre migliorata: Embedding lookup (kNN) è O(1) ma il post-ranking tra i top-k è spesso serial. Se i VDB fanno re-ranking con LLM, la latency p95 diventa 2-5 secondi (non 50ms come pubblicizzato).
- Stale embeddings: Se il tuo corpus cambia daily (notizie, prezzi), i vettori vecchi degradano la relevance. Devi re-generare embedding per documento modificato. Con keyword search questo non è un problema: l'indice inverted aggiorna in milliseconds.
Stima TCO annuale su 10M doc: Vector DB cloud (Pinecone) = €6K–€12K (storage + embedding API). Redis self-hosted + re-ranking = €1K–€3K (infra + engineering).
3. La complessità nascosta del retrieval ranking
I VDB promettono "semantic ranking con un click". In realtà, un buon ranking ibrido (keyword + semantic + business logic) richiede lo stesso sforzo engineering:
# NAIVE vector DB RAG (quello che le guide ti dicono di fare)
def rag_search(query):
query_embedding = llm_api.embed(query) # API cloud LLM
results = pinecone_index.query(query_embedding, top_k=10)
# QUI: risultati sono spesso mediocri. Motivo:
# - "iPhone 15 Pro" embedding è simile a "Samsung Galaxy S25"
# - LLM ha visto milioni product, confonde feature
# - Prezzo non è fattore: VDB non sa che l'utente vuole <€1000
return results
# REALISTICO: hybrid ranking con fallback BM25
def rag_search_realistic(query):
# Primo: try keyword search (BM25)
keyword_results = elasticsearch.search(query, size=50)
# Se pochi keyword match (<5), integra semantic
if len(keyword_results) < 5:
query_embedding = ollama.embed(query) # on-prem, no cost
semantic_results = redis_hnsw.query(query_embedding, top_k=10)
results = merge_by_score(keyword_results, semantic_results)
else:
# Keyword match sufficiently, skip expensive semantic
results = keyword_results[:10]
# Re-rank per business logic (prezzo, rating, freshness)
results = rerank_by_business_logic(results, query_context)
return results
Il problema: il codice realistico è più complesso di un semplice VDB query. Devi mantenere sia keyword che semantic index, merge logic, business re-ranking. In pratica, finisci per fare il 90% del lavoro che faresti con Elasticsearch + BM25 + Lua scripting.
4. Quando le alternative battono i VDB categoricamente
BM25 (Elasticsearch, Solr, Lucene): Scegli questo se il tuo ranking è riassumibile come "document relevance to query terms".
- Query: "best headphones under 200 euros"
- BM25 term frequency matching vs. VDB semantic similarity
- Vincitore: BM25 (trova "200 euros" e "headphones" nel titolo, relevance 0.95; VDB sceglie "expensive audio equipment", 0.72)
Full-Text Search (PostgreSQL, SQLite FTS5): Se il corpus è <100GB e le query sono simmetriche (full document query, non embedding embedding).
- Query: "how to deploy Angular SSR on Hetzner VPS"
- Postgre FTS indicizza parole-chiave, cerca fast. No embedding needed. Relevance: 0.88
- VDB embedding overhead for 30-40ms query latency, relevance: 0.85
Graph Database (Neo4j, ArangoDB): Se il ranking dipende da struttura dati relazionali.
- Query: "show articles by authors who reviewed products with 5-star rating"
- VDB non "comprende" le relazioni author→review→product→rating
- Graph query: MATCH (a:Article)-[:AUTHORED_BY]-(u:User)-[:REVIEWED]-(p:Product) WHERE p.rating=5 - Cinque linee, risultato esatto
Redis + Lua Scripting: Se devi re-rankizzare on-the-fly per business logic (prezzo, disponibilità, local delivery).
-- Redis Lua: custom re-ranking
local results = redis.call('ZRANGE', 'products_bm25', 0, 49) -- top 50 BM25
local reranked = {}
for i, product_id in ipairs(results) do
local price = tonumber(redis.call('HGET', product_id, 'price'))
local rating = tonumber(redis.call('HGET', product_id, 'rating'))
local freshness = tonumber(redis.call('HGET', product_id, 'days_since_updated'))
-- Custom score: 50% BM25 relevance + 25% rating + 15% freshness - 10% price_penalty
local custom_score =
(50 * (50 - i) / 50) + -- BM25 position decay
(25 * rating / 5) + -- rating 0-5 → 0-25 points
(15 * math.max(0, (30 - freshness) / 30)) + -- days freshness
(-10 * math.min(1, price / 1000)) -- penalty if expensive
table.insert(reranked, {product_id, custom_score})
end
table.sort(reranked, function(a,b) return a[2] > b[2] end)
return reranked
VDB non ha questa capacità. Se la tua ranking logic è "semantic similarity only", ok; se è "semantic + business rules", scegli qualcosa di più flessibile.
5. BM25 e Full-Text Search: il cavallo di battaglia
BM25 è l'algoritmo di ranking tf-idf ottimizzato usato da Google, Elasticsearch, Solr dal 2009. È simple, proven, fast.
// Elasticsearch BM25 query
GET /articles/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "vector database alternatives",
"fields": ["title^3", "content^1", "tags^2"],
"type": "best_fields",
"fuzziness": "AUTO"
}
}
],
"filter": [
{ "range": { "publishedAt": { "gte": "2026-01-01" } } }
]
}
},
"size": 10
}
Perché BM25 batte VDB per keyword:
- Speed: <5ms per query (inverted index O(1) lookup). VDB embedding + kNN = 50-200ms.
- Precision: Se l'utente cerca "Angular 21 TypeScript", BM25 matcha titoli con quelle parole. VDB matcha "frontend framework" e "programming language" indipendentemente.
- Interpretability: Sai esattamente perché "Angular 21" rankizza alto (termine frequente nei risultati, inverso raro nel corpus). VDB embedding è black-box.
- Cost: Elasticsearch open-source costa €0 (self-hosted). Cloud Pinecone costa €500/mese minimo.
6. Graph Database: per query con relazioni
Se il tuo ranking richiede traversal di relazioni (autore→articolo, prodotto→categoria, utente→precedenti_acquisti), graph database è obbligatorio.
// Neo4j Cypher query: find articles from trusted authors
MATCH (a:Article)-[:AUTHORED_BY]-(u:User)-[:FOLLOWS]-(follower:User)
WHERE follower.id = $current_user_id AND a.publishedAt > datetime.now() - duration('P30D')
RETURN a ORDER BY a.engagement DESC LIMIT 10
Questo query è impossibile in VDB. Con VDB dovresti:
- Fetch tutti gli articoli per relazioni author→article
- Filter per trusted author (JOIN nella query, not possible in VDB)
- Re-rankizza per engagement (2nd pass)
Con Neo4j, step unico. Con VDB, 2-3 database round-trip.
7. Elasticsearch: il middle ground ibrido
Elasticsearch 8.0+ supporta dense vector search (HNSW) PLUS BM25. È il best-of-both-worlds se vuoi evitare multi-system complexity.
// Elasticsearch hybrid query: BM25 + dense vector
GET /articles/_search
{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "machine learning algorithms",
"fields": ["title^3", "content"],
"boost": 0.5
}
},
{
"knn": {
"embeddings": {
"vector": [...query_embedding_384_dim...],
"k": 10,
"boost": 0.5
}
}
}
]
}
}
}
Vantaggi:
- Single system, single index, single deployment
- Re-ranking script-based (Elasticsearch Painless scripting language)
- Cost: €500-2000/mese self-hosted; 5x cheaper than Pinecone cloud
- Scalability: proven con Netflix, Uber, Shopify
Svantaggi:
- Learning curve (more complex than Pinecone UI)
- Maintenance overhead (cluster tuning, shard allocation)
- Still need to generate embeddings (no native LLM inside)
8. Redis HNSW + Lua scripting: ranking custom low-cost
Redis Stack 7.0+ aggiunge HNSW vector indexing. Combina con Lua scripting per re-ranking custom. Costo: €50-200/mese.
# Python: Redis HNSW + Lua re-ranking
from redis import Redis
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2') # 384-dim, local
redis_client = Redis(host='localhost', port=6379)
def hybrid_search(query, user_context):
# Step 1: get query embedding locally
query_embedding = model.encode(query).tolist()
# Step 2: Redis HNSW kNN search
results = redis_client.execute_command(
'FT.SEARCH',
'articles_idx',
f'*=>[KNN 10 @embeddings $query_embedding EF_RUNTIME 200]',
'PARAMS', 2, 'query_embedding', query_embedding
)
# Step 3: Lua re-ranking with business logic
lua_script = '''
local results = cjson.decode(ARGV[1])
local user_preferences = cjson.decode(ARGV[2])
for i, doc in ipairs(results) do
local article_id = doc.id
local knn_score = doc.similarity
local author_id = redis.call('HGET', article_id, 'author_id')
local is_trusted = redis.call('SISMEMBER', 'trusted_authors', author_id)
-- Re-rank: 70% kNN + 30% trust bonus
doc.final_score = (0.7 * knn_score) + (0.3 * (is_trusted and 1 or 0))
end
table.sort(results, function(a,b) return a.final_score > b.final_score end)
return cjson.encode(results)
'''
final_results = redis_client.eval(
lua_script,
0,
json.dumps(results),
json.dumps(user_context)
)
return final_results
Why this wins: Single Redis instance, embeddings computed locally (Ollama), zero cloud API cost, re-ranking logic fully controlled.
9. Caso studio: Ollama on-prem + Redis HNSW vs Pinecone cloud
Setup: 500K Italian tech articles, RAG chatbot, 100 QPS.
| Metrica | Pinecone cloud | Ollama + Redis | Vincitore |
|---|---|---|---|
| Monthly cost | €800 (100GB index, 100 QPS) | €150 (Hetzner CCX23, 32GB RAM) | Redis (5.3x cheaper) |
| Query latency p50 | 45ms | 35ms | Redis |
| Embedding cost per M tokens | €15 (API cloud LLM) | €0 (local Ollama llama3.1:8b) | Redis (free) |
| Re-ranking flexibility | Limited (Pinecone SDK only) | Full (Lua + Python logic) | Redis |
| Data residency | Pinecone cloud (privacy risk for EU) | On-prem Hetzner VPS (GDPR compliant) | Redis |
| Hallucination mitigation | VDB + cloud LLM (prone to drift) | VDB + local LLM (deterministic Ollama) | Redis (local LLM) |
Risultato: Ollama + Redis cost 5.3x less, faster, more private, better re-ranking. Pinecone wins solo se hai bisogno di 10M+ doc e team specializzati.
10. Cost analysis: TCO realistico
Scenario: 2M articoli, 100 QPS peak, 12-mese horizon.
# TCO calculator
scenarios = {
'vector_db_cloud': {
'infra': 800 * 12, # €800/mese Pinecone
'embedding_api': 0.015 * 2000000 / 1000, # €30 API cloud LLM embedding
'llm_inference': 0.003 * 1000000, # €3k API cloud LLM inference usage
'engineering': 150 * 12, # €150/mese DevOps
'total': 9600 + 30 + 3000 + 1800,
},
'vector_db_self_hosted_elasticsearch': {
'infra': 300 * 12, # €300/mese Hetzner VM
'embedding_api': 0, # Ollama local
'llm_inference': 0, # Ollama local
'engineering': 300 * 12, # €300/mese maintenance
'total': 3600 + 3600,
},
'redis_hnsw_bm25_hybrid': {
'infra': 150 * 12, # €150/mese Hetzner+Redis Stack
'embedding_api': 0, # Ollama
'llm_inference': 0, # Ollama
'engineering': 200 * 12, # €200/mese (less overhead)
'total': 1800 + 2400,
},
}
for scenario, costs in scenarios.items():
print(f"{scenario}: €{costs['total']}")
# Output:
# vector_db_cloud: €14,430
# vector_db_self_hosted_elasticsearch: €7,200
# redis_hnsw_bm25_hybrid: €4,200
Insight: Redis hybrid è 3.4x più economico di Pinecone cloud, 1.7x più economico di Elasticsearch self-hosted.
11. Decision tree pratico: quale scegliere
Q1: Il tuo dataset è strutturato o unstructured?
- Strutturato (tabelle SQL, JSON keys noti): → PostgreSQL FTS o Elasticsearch BM25
- Unstructured (long-form articles, PDFs): → Elasticsearch hybrid o Redis HNSW
Q2: Le query includono business logic relazionale (author, category, recency)?
- Sì: → Neo4j (graph) o Elasticsearch + Painless scripts
- No, puro semantic similarity: → Redis HNSW o Pinecone
Q3: Quanti query per secondo e qual è il latency SLA?
- <10 QPS, <500ms SLA: → Postgres FTS (simplest)
- 10-100 QPS, <100ms: → Elasticsearch open-source
- >100 QPS, <50ms: → Redis HNSW (on-prem) o Pinecone (cloud)
Q4: Privacy + data residency (GDPR)?
- Must stay in EU: → Self-hosted (Elasticsearch, Redis, PostgreSQL). Evita provider cloud LLM per GDPR compliance.
- Cloud allowed: → Pinecone EU region (if available)
Q5: Budget annuale?
- <€5K: → Redis HNSW + Ollama self-hosted
- €5K-€15K: → Elasticsearch self-hosted
- >€15K: → Pinecone cloud (convenience, managed service)
12. Quando migrare da VDB a soluzione ibrida
Se già usi Pinecone/Weaviate, è utile migrare? Solo se:
- Monthly cost > €500 e latency p99 > 200ms: Il tuo access pattern è inefficiente. Hybrid approach spesso riduce latency e cost.
- Relevance metrics degrading: Se il ranking è peggiorato negli ultimi 3 mesi, il problema non è il VDB ma il re-ranking logic. Passa a Elasticsearch con custom scoring.
- Data privacy mandate: Se il board richiede GDPR-only on-prem, migra da cloud VDB a self-hosted Redis/Elasticsearch.
- Query pattern shifting to keyword-heavy: Se 70%+ query sono keyword match (non semantic), BM25 è più efficiente.
Non migrare se: Embedding quality è il valore principale (il 30% of edge cases dove VDB truly excels), il tuo team ama il managed service di Pinecone, la compliance non è una concern.
13. Implementazione FastAPI: routing smart tra BM25 e VDB
Codice che sceglie automaticamente l'algoritmo di ranking:
from fastapi import FastAPI, Query
from elasticsearch import Elasticsearch
from redis import Redis
from sentence_transformers import SentenceTransformer
app = FastAPI()
es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
redis_client = Redis(host='localhost', port=6379, decode_responses=True)
model = SentenceTransformer('all-MiniLM-L6-v2')
@app.post("/search")
async def search(query: str = Query(..., min_length=3)):
# Heuristic: if query has exact keywords, try BM25 first
keyword_tokens = query.lower().split()
# Step 1: BM25 search (fast)
bm25_results = es.search(
index='articles',
body={
'query': {'multi_match': {
'query': query,
'fields': ['title^3', 'content', 'tags^2']
}},
'size': 50
}
)
bm25_hits = [
{
'id': hit['_id'],
'score': hit['_score'],
'source': hit['_source']
}
for hit in bm25_results['hits']['hits']
]
# Decision: if top BM25 score > 5.0, return BM25 (high confidence keyword match)
if bm25_hits and bm25_hits[0]['score'] > 5.0:
return {'method': 'bm25', 'results': bm25_hits[:10]}
# Otherwise: integrate semantic search via Redis HNSW
query_embedding = model.encode(query).tolist()
hnsw_results = redis_client.execute_command(
'FT.SEARCH', 'articles_idx',
f'*=>[KNN 10 @embeddings $query_embedding]',
'PARAMS', 2, 'query_embedding', query_embedding
)
# Merge and deduplicate
merged = {}
for hit in bm25_hits:
merged[hit['id']] = {'bm25_score': hit['score']}
for hit in hnsw_results:
if hit['id'] in merged:
merged[hit['id']]['hnsw_score'] = hit.get('score', 0)
else:
merged[hit['id']] = {'hnsw_score': hit.get('score', 0)}
# Hybrid re-ranking: 60% BM25 + 40% semantic
final_results = sorted(
[
{
'id': doc_id,
'hybrid_score': (
0.6 * doc.get('bm25_score', 0) +
0.4 * doc.get('hnsw_score', 0)
),
'source': bm25_hits[[h['id'] for h in bm25_hits].index(doc_id)]['source']
}
for doc_id, doc in merged.items()
],
key=lambda x: x['hybrid_score'],
reverse=True
)[:10]
return {'method': 'hybrid', 'results': final_results}
14. FAQ: Domande frequenti su ranking alternatives
D: "Se uso Ollama per embedding, non creo lo stesso problema di Pinecone (embedding non-local)?"
R: No. Ollama gira on-prem, di proprietà tua. Zero embedding API cost, zero data exfiltration, zero latency per embedding inference. Il vantaggio è enorme rispetto a provider cloud proprietari che richiedono network round-trip e hanno costi mensili.
D: "BM25 non è 'old tech'? Non dovremmo usare sempre semantic search?"
R: BM25 non è obsoleto, è specializzato. È il gold standard per keyword search. Semantic è complementare, non sostitutivo. Se ami la novità, hybrid (BM25 + semantic) è il vero modern approach, non full-VDB.
D: "Cosa succede se cambio algoritmo di ranking? Non serve re-indicizzare?"
R: No. L'indice (inverted per BM25, HNSW per VDB) rimane lo stesso. Cambi la ranking formula usando script Lua o Elasticsearch Painless, e il risultato è immediato. Zero down-time, zero re-indexing.
D: "Elasticsearch hybrid (BM25 + HNSW) è davvero 'hybrid' o è solo due ricerche separate?"
R: È un single query con `bool.should` clause (OR logic). Elasticsearch esegue sia BM25 che kNN, poi merge i risultati con scoring combinato. Più efficiente che fare 2 query separate.
D: "Se la relevance degrada nel tempo, è colpa dell'algoritmo o del dataset?"
R: Spesso dataset (stale embeddings, outdated content, model drift). Monitora: token frequency distribution, embedding drift (paragraph similarity over time), user feedback (CTR). Se feedback è buono, algoritmo va bene. Se audience cambia preferenza, adatta il ranking formula (re-weight BM25 vs semantic, adjust freshness factor).
Conclusioni: scegli il tool giusto
Vector database sono potenti per semantic search a scale. Ma il 70% dei use case reali ottengono risultati migliori e più economici con BM25, Elasticsearch, Redis, PostgreSQL. La decisione deve essere data-driven:
- Se la tua query è "iPhone 15 Silver 256GB", BM25.
- Se la query è "articoli su machine learning scritti da author affidabili", graph database.
- Se la query è "conceptually similar articles in multiple languages", VDB.
- Se la query è "TOP 10 products per user preferences + trending + in-stock", hybrid (BM25 + Lua re-ranking).
Takeaway: Non automatizzare la scelta verso VDB. Benchmarking (relevance metric + cost TCO) vince sempre su trend. Il tuo corpus, il tuo SLA, il tuo budget meritano la soluzione migliore, non la più di moda.

Commenti
Caricamento commenti...
Accedi per commentare