0Pricing
AI Engineering Academy · Lezione

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.matches

pgvector: 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_alpha

Scegliere 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

  1. Retrieval dense e sparse: compromessi
  2. Implementare la ricerca per parole chiave con BM25
  3. Reciprocal Rank Fusion per unire i punteggi
  4. Ricerca ibrida in Pinecone e pgvector
← Torna a AI Engineering Academy