AI Engineering Academy · Lektion

Hybridsuche in Pinecone und pgvector

Konfigurieren Sie die Hybridsuche in Pinecone mit dem Modus für Sparse-Dense-Indizes und in pgvector mit parallelen Abfragen und RRF-Zusammenführung. Bewerten Sie anschließend die Abrufqualität anhand Ihres Datensatzes.

Lektion 4 von 413 Schritte

Hybridsuche in Pinecone und pgvector ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Native hybride Suche in Vektordatenbanken

Sie können die hybride Suche zwar selbst mit zwei getrennten Indizes und RRF-Fusion implementieren, doch bieten Vektordatenbanken für den Produktiveinsatz zunehmend eine integrierte hybride Suche, die Sparse- und Dense-Retrieval in einer einzigen Abfrage verarbeitet. Pinecone und pgvector unterstützen beide hybride Modi, verwenden dabei jedoch unterschiedliche Architekturentscheidungen und weisen unterschiedliche Vor- und Nachteile auf. Wenn Sie beide Optionen verstehen, können Sie das passende Tool für Ihre Infrastruktur auswählen.

Pinecone-Modus für Sparse-Dense-Indizes

Pinecone unterstützt einen Sparse-Dense-Index, in dem jeder Vektordatensatz sowohl ein dichtes Embedding (als Float-Array) als auch einen Sparse-Vektor (als Dictionary aus Token-ID und Gewicht) speichert. Abfragen können sowohl einen dichten als auch einen Sparse-Abfragevektor enthalten, und Pinecone führt die Ergebnisse mithilfe einer gewichteten linearen Kombination zusammen. Das unterscheidet sich von RRF: Pinecone verwendet eine Fusion der Roh-Scores mit konfigurierbaren Gewichten namens 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')

Sparse-Vektoren mit SPLADE erzeugen

Um den Sparse-Dense-Modus von Pinecone zu verwenden, müssen Sie für jedes Dokument Sparse-Vektoren erzeugen. Der effektivste Ansatz ist SPLADE (Sparse Lexical and Expansion), ein neuronales Modell, das trainierte Sparse-Repräsentationen mit Expansion erzeugt: Es fügt dem Sparse-Vektor semantisch verwandte Begriffe hinzu, die im Text nicht wörtlich vorkommen müssen. Alternativ können Sie einfache BM25-Begriffgewichte als Sparse-Vektoren verwenden.

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}

Hybride Vektoren in Pinecone einfügen

Jeder Pinecone-Datensatz in einem hybriden Index speichert eine id, ein dichtes values-Array, ein sparse_values-Dictionary mit indices und values sowie optionale metadata. Fügen Sie Datensätze in Batches von 100 ein, um den Durchsatz zu maximieren und gleichzeitig die Größenbeschränkungen für Pinecone-Anfragen einzuhalten.

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}')

Den hybriden Pinecone-Index abfragen

Eine hybride Abfrage übergibt sowohl einen dichten vector als auch einen sparse_vector an die Pinecone-Query-API. Der alpha-Parameter (0 bis 1) steuert das Verhältnis: alpha=1.0 steht für reines Dense-Retrieval, alpha=0.0 für reines Sparse-Retrieval und alpha=0.5 gewichtet beide gleich. Stimmen Sie alpha anhand eines Validierungsdatensatzes ab – typische optimale Werte liegen zwischen 0.3 und 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: Vektorsuche in PostgreSQL

Die Erweiterung pgvector fügt PostgreSQL einen Spaltentyp vector und Distanzoperatoren hinzu. Für die hybride Suche führen Sie zwei Abfragen parallel aus – eine Approximate-Nearest-Neighbor-Abfrage auf der Vektorspalte und eine Volltextsuche mit den integrierten PostgreSQL-Typen tsvector und tsquery – und führen die Ergebnisse anschließend mit RRF in Ihrem Anwendungscode zusammen.

-- 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);

Dichte und Sparse-Abfragen in pgvector ausführen

Mit pgvector führen Sie die dichte Abfrage mithilfe des Kosinus-Distanzoperators <=> aus, um die nächsten Nachbarn des Abfrage-Embeddings zu finden. Die Sparse-Abfrage verwendet ts_rank_cd für die Spalte tsvector, um Übereinstimmungen mit Schlüsselwörtern zu bewerten. Rufen Sie beide Ergebnismengen unabhängig voneinander ab und führen Sie sie anschließend mit RRF in Python zusammen.

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)

RRF auf pgvector-Ergebnisse anwenden

Nachdem Sie die gerangten Zeilen aus beiden PostgreSQL-Abfragen gesammelt haben, wenden Sie RRF an, indem Sie aus jeder Ergebnismenge die Dokument-IDs in Rangfolge extrahieren und den Fusionsalgorithmus ausführen. Die endgültige zusammengeführte Liste liefert Ihnen die Top-K-Dokumente, die sowohl hinsichtlich ihrer semantischen Bedeutung als auch ihrer Schlüsselwortüberschneidung am relevantesten sind.

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]]

Die Qualität des Retrievals benchmarken

Nachdem Sie die hybride Suche implementiert haben, benchmarken Sie sie gründlich gegen Ihr Dense-only-Baseline-Retrieval. Verwenden Sie einen Golden-Testdatensatz mit mindestens 100 Abfragen und bekannten relevanten Dokumenten. Messen Sie NDCG@5, MRR und die Trefferquote@3. Typische Verbesserungen durch hybride Suche liegen bei NDCG@5 zwischen 5 und 20 Prozent, wobei die größten Zugewinne bei Abfragen mit exakten technischen Begriffen auftreten, die Dense-Modelle übersehen.

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),
    }

Alpha im hybriden Pinecone-Modus abstimmen

Der Alpha-Parameter in hybriden Pinecone-Abfragen erfordert eine systematische Abstimmung. Die Stratifizierung nach Abfragetyp ist ein nützlicher Ansatz: Klassifizieren Sie Ihre Testabfragen als überwiegend semantisch (Paraphrasen, Konzepte) oder überwiegend lexikalisch (exakte Begriffe, Codes) und messen Sie den optimalen Alpha-Wert für jede Gruppe separat. Einige Produktivsysteme implementieren eine dynamische Alpha-Auswahl, die die Abfrage zur Laufzeit klassifiziert und automatisch den passenden Alpha-Wert auswählt.

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

Zwischen Pinecone und pgvector Hybrid wählen

Verwenden Sie Pinecone Hybrid, wenn Sie eine verwaltete Infrastruktur und automatische Skalierung benötigen und die komplexe Erzeugung von Sparse-Vektoren an eine einzige API auslagern möchten. Verwenden Sie pgvector Hybrid, wenn Sie bereits über eine PostgreSQL-Infrastruktur verfügen, transaktionale Konsistenz zwischen Dokumenten und ihren Metadaten benötigen, vollständige SQL-Flexibilität für Filter wünschen oder eine Abhängigkeit von einem Anbieter vermeiden müssen. Beide Ansätze liefern bei korrekter Abstimmung eine hervorragende Qualität beim hybriden Retrieval.

Kurze Überprüfung

Testen Sie Ihr Verständnis der Implementierung hybrider Suche aus dieser Lektion.

Zusammenfassung der Lektion

In dieser Lektion haben Sie gelernt: Der Sparse-Dense-Modus von Pinecone speichert pro Datensatz sowohl dichte als auch Sparse-Vektoren und führt sie mit einem konfigurierbaren Alpha-Parameter zusammen, die hybride Suche mit pgvector kombiniert die SQL-Volltextsuche mit Vektorabfragen, die im Anwendungscode per RRF fusioniert werden, und das Abstimmen von Alpha anhand eines Validierungsdatensatzes ist entscheidend, um das optimale Verhältnis für Ihre Abfrageverteilung zu finden. Als Nächstes untersuchen wir das zweistufige Retrieval mit Re-Ranking.

Kostenlos starten

Lerne Python mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
30
Lektionen
120

Häufig gestellte Fragen

Ist die Lektion „Hybridsuche in Pinecone und pgvector“ kostenlos?

Ja — der vollständige Text von „Hybridsuche in Pinecone und pgvector“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Hybridsuche in Pinecone und pgvector“?

Konfigurieren Sie die Hybridsuche in Pinecone mit dem Modus für Sparse-Dense-Indizes und in pgvector mit parallelen Abfragen und RRF-Zusammenführung. Bewerten Sie anschließend die Abrufqualität anhan… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Engineering Academy zu starten?

Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Hybridsuche in Pinecone und pgvector“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?

Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Dense- vs. Sparse-Retrieval: Abwägungen
  2. BM25-Keyword-Suche implementieren
  3. Reziproke Rangfusion zum Zusammenführen von Bewertungen
  4. Hybridsuche in Pinecone und pgvector
← Zurück zu AI Engineering Academy