Ricerca ibrida in Pinecone e pgvector
Configuri la ricerca ibrida in Pinecone usando la modalità di indice sparse-dense e in pgvector usando query parallele con fusione RRF, valutando tramite benchmark la qualità del retrieval sul Suo dataset.
Ricerca ibrida in Pinecone e pgvector è una lezione AI Engineering Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Engineering Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Engineering Academy include 4 lezioni in totale.
Ricerca ibrida nativa nei database vettoriali
Sebbene sia possibile implementare autonomamente la ricerca ibrida usando due indici separati e la fusione RRF, i database vettoriali destinati alla produzione offrono sempre più spesso la ricerca ibrida integrata, che gestisce il recupero sparso e denso in un'unica query. Sia Pinecone sia pgvector supportano modalità ibride, ma con scelte architetturali e compromessi diversi. Comprendere entrambe le opzioni consente di scegliere lo strumento più adatto alla propria infrastruttura.
Modalità di indice sparso-denso di Pinecone
Pinecone supporta un indice sparso-denso in cui ogni record vettoriale memorizza sia un embedding denso (come array di float) sia un vettore sparso (come dizionario da ID del token a peso). Le query possono specificare sia un vettore di query denso sia un vettore di query sparso, e Pinecone unisce i risultati usando una combinazione lineare pesata. Questo è diverso da RRF: Pinecone usa la fusione dei punteggi grezzi con pesi configurabili chiamati alpha.
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key='YOUR_API_KEY')
# Create a sparse-dense index
pc.create_index(
name='hybrid-index',
dimension=1536, # dense vector dimension
metric='dotproduct', # must use dotproduct for hybrid
spec=ServerlessSpec(cloud='aws', region='us-east-1'),
)
index = pc.Index('hybrid-index')Generare vettori sparsi con SPLADE
Per usare la modalità sparso-denso di Pinecone, è necessario generare vettori sparsi per ogni documento. L'approccio più efficace è SPLADE (Sparse Lexical and Expansion), un modello neurale che produce rappresentazioni sparse apprese con espansione: aggiunge al vettore sparso termini semanticamente correlati, oltre a quelli che compaiono letteralmente nel testo. In alternativa, è possibile usare semplici pesi dei termini BM25 come vettori sparsi.
from transformers import AutoTokenizer, AutoModelForMaskedLM
import torch
# Load SPLADE model
tokenizer = AutoTokenizer.from_pretrained('naver/splade-cocondenser-ensembledistil')
model = AutoModelForMaskedLM.from_pretrained('naver/splade-cocondenser-ensembledistil')
def generate_sparse_vector(text: str) -> dict:
tokens = tokenizer(text, return_tensors='pt', truncation=True, max_length=512)
with torch.no_grad():
output = model(**tokens)
logits = output.logits
# Max-pool over sequence length and apply log1p activation
sparse = torch.max(torch.log1p(torch.relu(logits)), dim=1).values.squeeze()
# Return non-zero indices and values as a sparse dict
nz_indices = sparse.nonzero().squeeze().tolist()
nz_values = sparse[nz_indices].tolist()
return {'indices': nz_indices, 'values': nz_values}Inserire vettori ibridi in Pinecone
Ogni record Pinecone in un indice ibrido memorizza un id, un array denso values, un dizionario sparse_values con indices e values, oltre a metadata opzionali. Inserisca i record in batch da 100 per massimizzare la velocità, rimanendo entro i limiti di dimensione delle richieste di Pinecone.
def upsert_hybrid_docs(index, documents: list[dict], batch_size: int = 100):
records = []
for doc in documents:
dense_vec = embed(doc['text']) # OpenAI embedding
sparse_vec = generate_sparse_vector(doc['text']) # SPLADE
records.append({
'id': doc['id'],
'values': dense_vec,
'sparse_values': sparse_vec,
'metadata': {'text': doc['text'], 'source': doc['source']},
})
for i in range(0, len(records), batch_size):
batch = records[i:i + batch_size]
index.upsert(vectors=batch)
print(f'Upserted batch {i//batch_size + 1}')Interrogare l'indice ibrido di Pinecone
Una query ibrida invia sia un vector denso sia uno sparse_vector all'API di query di Pinecone. Il parametro alpha (da 0 a 1) controlla l'equilibrio: alpha=1.0 indica una ricerca esclusivamente densa, alpha=0.0 una ricerca esclusivamente sparsa e alpha=0.5 assegna lo stesso peso a entrambe. Ottimizzi alpha su un set di validazione: i valori ottimali tipici sono compresi tra 0.3 e 0.7.
def hybrid_query_pinecone(index, query: str, alpha: float = 0.5, top_k: int = 5):
dense_vec = embed(query)
sparse_vec = generate_sparse_vector(query)
# Scale vectors by alpha for weighted fusion
scaled_dense = [v * alpha for v in dense_vec]
scaled_sparse = {
'indices': sparse_vec['indices'],
'values': [v * (1 - alpha) for v in sparse_vec['values']],
}
results = index.query(
vector=scaled_dense,
sparse_vector=scaled_sparse,
top_k=top_k,
include_metadata=True,
)
return results.matchespgvector: ricerca vettoriale in PostgreSQL
L'estensione pgvector aggiunge a PostgreSQL un tipo di colonna vector e operatori di distanza. Per la ricerca ibrida, esegua due query in parallelo: una query approximate nearest neighbor sulla colonna vettoriale e una query di ricerca full-text usando i tipi integrati di PostgreSQL tsvector e tsquery; quindi unisca i risultati con RRF nel codice dell'applicazione.
-- Setup: enable extensions
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- Create hybrid-capable table
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding vector(1536),
content_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED
);
-- Indexes for both search modes
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON documents USING GIN (content_tsv);Eseguire query dense e sparse in pgvector
Con pgvector, esegua la query densa usando l'operatore di distanza coseno <=> per trovare i vicini più prossimi all'embedding della query, e la query sparsa usando ts_rank_cd sulla colonna tsvector per assegnare un punteggio alle corrispondenze delle parole chiave. Recuperi i due insiemi di risultati in modo indipendente, quindi li unisca usando RRF in Python.
import psycopg2
import json
def pgvector_hybrid_search(conn, query: str, top_k: int = 5):
dense_vec = embed(query)
tsquery = ' & '.join(query.split()) # simple AND query
# Dense query
dense_sql = '''
SELECT id, content, 1 - (embedding <=> %s::vector) AS score
FROM documents
ORDER BY embedding <=> %s::vector
LIMIT 20
'''
# Sparse query
sparse_sql = '''
SELECT id, content, ts_rank_cd(content_tsv, to_tsquery('english', %s)) AS score
FROM documents
WHERE content_tsv @@ to_tsquery('english', %s)
ORDER BY score DESC
LIMIT 20
'''
with conn.cursor() as cur:
cur.execute(dense_sql, [json.dumps(dense_vec), json.dumps(dense_vec)])
dense_rows = cur.fetchall()
cur.execute(sparse_sql, [tsquery, tsquery])
sparse_rows = cur.fetchall()
return fuse_with_rrf(dense_rows, sparse_rows, top_k)Applicare RRF ai risultati di pgvector
Dopo aver raccolto le righe ordinate dalle due query PostgreSQL, applichi RRF estraendo gli ID dei documenti in ordine di posizione da ciascun insieme di risultati ed eseguendo l'algoritmo di fusione. L'elenco finale unificato contiene i documenti top-K più rilevanti sia per il significato semantico sia per la sovrapposizione delle parole chiave.
def fuse_with_rrf(dense_rows, sparse_rows, top_k: int = 5, k: int = 60):
from collections import defaultdict
doc_texts = {}
scores = defaultdict(float)
for rank, row in enumerate(dense_rows, start=1):
doc_id, text, _ = row
scores[doc_id] += 1.0 / (k + rank)
doc_texts[doc_id] = text
for rank, row in enumerate(sparse_rows, start=1):
doc_id, text, _ = row
scores[doc_id] += 1.0 / (k + rank)
doc_texts[doc_id] = text
ranked = sorted(scores.items(), key=lambda x: x[1], reverse=True)
return [{'id': doc_id, 'text': doc_texts[doc_id], 'rrf_score': s}
for doc_id, s in ranked[:top_k]]Valutare con benchmark la qualità del recupero
Dopo aver implementato la ricerca ibrida, la valuti rigorosamente con benchmark rispetto al recupero di base basato solo su vettori densi. Utilizzi un set di test di riferimento con almeno 100 query e documenti rilevanti noti. Misuri NDCG@5, MRR e hit rate@3. I miglioramenti tipici della ricerca ibrida vanno dal 5 al 20 percento su NDCG@5, con i guadagni maggiori per le query che contengono termini tecnici esatti che i modelli densi non riescono a cogliere.
def evaluate_retrieval(search_fn, test_queries, golden_relevant, k=5):
ndcg_scores = []
hit_count = 0
for query, relevant_ids in zip(test_queries, golden_relevant):
results = search_fn(query, top_k=k)
retrieved_ids = [r['id'] for r in results]
# Hit rate
if any(rid in relevant_ids for rid in retrieved_ids):
hit_count += 1
# Simplified NDCG (binary relevance)
dcg = sum(
1.0 / (i + 1)
for i, rid in enumerate(retrieved_ids)
if rid in relevant_ids
)
idcg = sum(1.0 / (i + 1) for i in range(min(len(relevant_ids), k)))
ndcg_scores.append(dcg / idcg if idcg > 0 else 0)
return {
'hit_rate': hit_count / len(test_queries),
'ndcg': sum(ndcg_scores) / len(ndcg_scores),
}Ottimizzare Alpha nella modalità ibrida di Pinecone
Il parametro alpha nelle query ibride di Pinecone richiede un'ottimizzazione sistematica. La stratificazione per tipo di query è un approccio utile: classifichi le query di test come prevalentemente semantiche (parafrasi, concetti) o prevalentemente lessicali (termini esatti, codici) e misuri separatamente l'alpha ottimale per ciascun gruppo. Alcuni sistemi di produzione implementano la selezione dinamica di alpha, classificando la query durante l'esecuzione e scegliendo automaticamente il valore di alpha appropriato.
def find_optimal_alpha(index, test_queries, golden_relevant, alphas=None):
if alphas is None:
alphas = [0.0, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0]
best_alpha, best_score = 0.5, 0
for alpha in alphas:
hits = 0
for query, relevant in zip(test_queries, golden_relevant):
results = hybrid_query_pinecone(index, query, alpha=alpha, top_k=5)
if any(r['id'] in relevant for r in results):
hits += 1
hit_rate = hits / len(test_queries)
print(f'alpha={alpha}: hit_rate={hit_rate:.3f}')
if hit_rate > best_score:
best_score, best_alpha = hit_rate, alpha
return best_alphaScegliere tra Pinecone e pgvector per la ricerca ibrida
Scelga la ricerca ibrida di Pinecone quando ha bisogno di un'infrastruttura gestita, di scalabilità automatica e desidera affidare a un'unica API la complessità della generazione dei vettori sparsi. Scelga la ricerca ibrida di pgvector quando dispone già di un'infrastruttura PostgreSQL, ha bisogno di coerenza transazionale tra i documenti e i relativi metadati, desidera la piena flessibilità SQL per i filtri o deve evitare il vincolo verso un singolo fornitore. Entrambi gli approcci producono un'eccellente qualità di recupero ibrido se ottimizzati correttamente.
Verifica rapida
Verifichi la Sua comprensione dell'implementazione della ricerca ibrida presentata in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che: la modalità sparso-denso di Pinecone memorizza vettori densi e sparsi per ogni record e li fonde con un parametro alpha configurabile, la ricerca ibrida di pgvector combina la ricerca full-text SQL con query vettoriali fuse tramite RRF nel codice dell'applicazione e l'ottimizzazione di alpha su un set di validazione è essenziale per trovare l'equilibrio ottimale per la distribuzione delle query. Nella prossima lezione esploreremo il recupero in due fasi con riordinamento.
Domande Frequenti
La lezione «Ricerca ibrida in Pinecone e pgvector» è gratuita?
Sì — il testo completo di «Ricerca ibrida in Pinecone e pgvector» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Engineering Academy, passa a CoddyKit PRO. Il corso AI Engineering Academy include 4 lezioni in totale.
Cosa imparerò in «Ricerca ibrida in Pinecone e pgvector»?
Configuri la ricerca ibrida in Pinecone usando la modalità di indice sparse-dense e in pgvector usando query parallele con fusione RRF, valutando tramite benchmark la qualità del retrieval sul Suo da… Eserciti AI Engineering Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Engineering Academy?
Non è richiesta alcuna esperienza precedente. AI Engineering Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Ricerca ibrida in Pinecone e pgvector»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Engineering Academy?
Sì. Ogni lezione AI Engineering Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Retrieval dense e sparse: compromessi
- Implementare la ricerca per parole chiave con BM25
- Reciprocal Rank Fusion per unire i punteggi
- Ricerca ibrida in Pinecone e pgvector