0Pricing
AI Engineering Academy · Aula

Busca híbrida no Pinecone e no pgvector

Configure a busca híbrida no Pinecone usando o modo de índice esparso-denso e no pgvector usando consultas paralelas com combinação por RRF, avaliando a qualidade da recuperação no seu conjunto de dados.

Busca híbrida no Pinecone e no pgvector é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

Busca híbrida nativa em bancos de dados vetoriais

Embora seja possível implementar a busca híbrida por conta própria usando dois índices separados e fusão com RRF, os bancos de dados vetoriais usados em produção oferecem cada vez mais busca híbrida integrada, que lida com a recuperação esparsa e densa em uma única consulta. O Pinecone e o pgvector são compatíveis com modos híbridos, mas usam arquiteturas e apresentam compromissos diferentes. Compreender as duas opções ajuda você a escolher a ferramenta certa para sua infraestrutura.

Modo de índice esparso-denso do Pinecone

O Pinecone é compatível com um índice esparso-denso, no qual cada registro vetorial armazena tanto uma incorporação densa (como uma matriz de números de ponto flutuante) quanto um vetor esparso (como um dicionário de ID de token para peso). As consultas podem especificar tanto um vetor de consulta denso quanto um vetor de consulta esparso, e o Pinecone combina os resultados usando uma combinação linear ponderada. Isso é diferente do RRF: o Pinecone usa a fusão de pontuações brutas com pesos configuráveis chamados 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')

Gerando vetores esparsos com SPLADE

Para usar o modo esparso-denso do Pinecone, você precisa gerar vetores esparsos para cada documento. A abordagem mais eficaz é o SPLADE (Sparse Lexical and Expansion), um modelo neural que produz representações esparsas aprendidas com expansão: ele adiciona ao vetor esparso termos semanticamente relacionados que vão além dos que aparecem literalmente no texto. Como alternativa, você pode usar pesos simples de termos BM25 como vetores esparsos.

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}

Inserindo vetores híbridos no Pinecone

Cada registro do Pinecone em um índice híbrido armazena um id, uma matriz densa values, um dicionário sparse_values com indices e values, além de metadata opcional. Insira os registros em lotes de 100 para maximizar a vazão e permanecer dentro dos limites de tamanho de requisição do 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}')

Consultando o índice híbrido do Pinecone

Uma consulta híbrida envia tanto um vector denso quanto um sparse_vector à API de consulta do Pinecone. O parâmetro alpha (de 0 a 1) controla o equilíbrio: alpha=1.0 é totalmente denso, alpha=0.0 é totalmente esparso e alpha=0.5 atribui o mesmo peso a ambos. Ajuste alpha em um conjunto de validação: os valores ideais típicos ficam entre 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: busca vetorial no PostgreSQL

A extensão pgvector adiciona ao PostgreSQL um tipo de coluna vector e operadores de distância. Para a busca híbrida, você executa duas consultas em paralelo: uma consulta aproximada de vizinhos mais próximos na coluna vetorial e uma consulta de busca em texto completo usando tsvector e tsquery, integrados ao PostgreSQL; depois, combina os resultados com RRF no código da aplicação.

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

Executando consultas densas e esparsas no pgvector

Com o pgvector, execute a consulta densa usando o operador de distância cosseno <=> para encontrar os vizinhos mais próximos da incorporação da consulta, e a consulta esparsa usando ts_rank_cd na coluna tsvector para pontuar correspondências de palavras-chave. Recupere os dois conjuntos de resultados de forma independente e combine-os usando RRF em 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)

Aplicando RRF aos resultados do pgvector

Depois de coletar as linhas ordenadas das duas consultas do PostgreSQL, aplique RRF extraindo os IDs dos documentos na ordem do ranking de cada conjunto de resultados e executando o algoritmo de fusão. A lista final combinada fornece os documentos entre os primeiros K mais relevantes tanto pelo significado semântico quanto pela sobreposição de palavras-chave.

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

Avaliando a qualidade da recuperação

Depois de implementar a busca híbrida, avalie-a rigorosamente em comparação com sua recuperação de referência somente densa. Use um conjunto de testes de referência com pelo menos 100 consultas e documentos relevantes conhecidos. Meça NDCG@5, MRR e taxa de acerto@3. As melhorias típicas da busca híbrida variam de 5 a 20 por cento no NDCG@5, com os maiores ganhos em consultas que contêm termos técnicos exatos que os modelos densos não identificam.

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

Ajustando Alpha no modo híbrido do Pinecone

O parâmetro alpha na consulta híbrida do Pinecone exige um ajuste sistemático. A estratificação por tipo de consulta é uma abordagem útil: classifique suas consultas de teste como predominantemente semânticas (paráfrases, conceitos) ou predominantemente lexicais (termos exatos, códigos) e meça o alpha ideal separadamente para cada grupo. Alguns sistemas de produção implementam a seleção dinâmica de alpha, que classifica a consulta durante a execução e escolhe automaticamente o alpha adequado.

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

Escolhendo entre o híbrido do Pinecone e o do pgvector

Use o híbrido do Pinecone quando precisar de infraestrutura gerenciada, escalabilidade automática e quiser transferir a complexidade da geração de vetores esparsos para uma única API. Use o híbrido do pgvector quando já tiver uma infraestrutura PostgreSQL, precisar de consistência transacional entre documentos e seus metadados, quiser flexibilidade total de SQL para filtragem ou precisar evitar a dependência de um fornecedor. Ambas as abordagens produzem excelente qualidade de recuperação híbrida quando ajustadas corretamente.

Verificação rápida

Teste sua compreensão da implementação de busca híbrida apresentada nesta lição.

Resumo da lição

Nesta lição, você aprendeu que: o modo esparso-denso do Pinecone armazena vetores densos e esparsos por registro e os combina com um parâmetro alpha configurável; a busca híbrida com pgvector combina a busca SQL em texto completo com consultas vetoriais, unificadas por RRF no código da aplicação; e o ajuste de alpha em um conjunto de validação é essencial para encontrar o equilíbrio ideal para a distribuição das suas consultas. Em seguida, exploraremos a recuperação em duas etapas com reordenação.

Perguntas Frequentes

A aula “Busca híbrida no Pinecone e no pgvector” é grátis?

Sim — o texto completo de “Busca híbrida no Pinecone e no pgvector” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Busca híbrida no Pinecone e no pgvector”?

Configure a busca híbrida no Pinecone usando o modo de índice esparso-denso e no pgvector usando consultas paralelas com combinação por RRF, avaliando a qualidade da recuperação no seu conjunto de da… Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Busca híbrida no Pinecone e no pgvector”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Recuperação densa versus esparsa: compromissos
  2. Implementando busca por palavras-chave com BM25
  3. Fusão recíproca de posições para combinar pontuações
  4. Busca híbrida no Pinecone e no pgvector
← Voltar para AI Engineering Academy