antonio leandro

busca e recuperação

The Faiss library

paper · Douze, Matthijs, Guzhva, Alexandr, Deng, Chengqi, Johnson, Jeff, Szilvasy, Gergely, Mazaré, Pierre-Emmanuel, Lomeli, Maria, Hosseini, Lucas · · ~78 min de leitura do original

a tese

busca vetorial não tem método vencedor: tem um eixo de compressão e um eixo de poda, e o índice certo é a combinação que cabe no orçamento de memória, latência e recall que você aceitou

o que fica

  1. O tempo de busca de um índice IVF cresce com N elevado a algo entre 0,29 e 0,45, e o expoente sobe junto com o recall alvo: exigir 0,99 em vez de 0,5 piora a escala, não só a constante.
  2. O k-means puro deixa de servir como compressor por volta de 3 bytes por código, porque os 16 milhões de centroides correspondentes ficam inviáveis de treinar e guardar.
  3. Achar o código ótimo de um quantizador aditivo é NP-difícil, então RQ e LSQ usam heurísticas (beam search, simulated annealing) que trocam tempo de codificação por erro de reconstrução.
  4. Índices em grafo só compensam quando memória não é restrição; acima de uns 10 milhões de vetores o tempo de construção vira o gargalo e sobra o IVF com vetores comprimidos.
  5. HNSW aceita inserção de vetores em produção mas não remoção nem alteração, e NSG congela o grafo depois do primeiro lote — mutabilidade é decisão de arquitetura, não de configuração.
  6. Faiss não é banco de dados: não tem escrita concorrente, sharding, transação nem metadata, só um id inteiro de 63 bits por vetor.

o problema

Embedding virou o formato padrão para representar texto, imagem, áudio, usuário e item de catálogo. A aposta é simples: se a rede foi treinada para que a distância entre vetores acompanhe a semelhança entre as mídias, achar itens parecidos vira achar vizinhos próximos num espaço de algumas centenas de dimensões. O jeito honesto de fazer isso é comparar a query com cada um dos N vetores da base, o que custa da ordem de N vezes d operações por consulta. N passou de bilhão faz tempo.

A saída clássica dos bancos não funciona aqui. kd-tree, hashing por projeção aleatória e parentes têm complexidade favorável no papel, mas param de dar ganho acima de umas dez dimensões, e em dimensão alta os métodos exatos de branch-and-bound não batem a força bruta. Restou aceitar erro: devolver quase sempre os vizinhos certos, muito mais rápido. A última década produziu um fluxo constante de papers fazendo exatamente isso, cada um com sua implementação e cada um vencendo numa faixa diferente de base, memória e latência. Quem precisa escolher fica sem chão — e o paper argumenta que a pergunta “qual algoritmo é melhor” está mal formulada desde o começo.

a ideia

Faiss não aposta num método. Ele decompõe o problema em dois eixos que se combinam livremente: compressão, que decide quantos bytes cada vetor ocupa e quanta distorção isso injeta na distância; e poda, que decide quantos vetores sequer chegam a ser comparados. Um índice é a escolha de um ponto em cada eixo, e os nomes das classes dizem isso na cara: IndexIVFPQ é poda por inverted file mais compressão por product quantizer, IndexHNSWFlat é poda por grafo sem compressão nenhuma.

Junto vem uma separação de responsabilidade que os autores chamam de contrato do embedding. A rede se compromete a produzir vetores cuja distância reflete a tarefa; o índice se compromete a aproximar bem a busca exata sob aquela métrica. Faiss cuida só da segunda metade: não extrai feature, não é serviço, não é banco.

como funciona

Os codecs formam uma hierarquia estrita — binarização, quantizador escalar, product quantizer, product-additive, additive — em que cada nível representa tudo que o de baixo representa, com mais precisão e mais custo de treino e de codificação. Na prática o PQ costuma ser o ponto de equilíbrio, e os quantizadores aditivos ganham nos códigos curtos.

A busca acontece no domínio comprimido: a query chega, o índice pré-computa tabelas de lookup por sub-quantizador e a distância até cada código vira uma soma de consultas em tabela, sem descomprimir nada. Isso é a asymmetric distance computation, em que só a base perde precisão, não a query.

Na poda, o IVF agrupa a base com um coarse quantizer em nlist clusters e visita só os nprobe mais próximos da query. O ótimo teórico coloca o número de listas proporcional à raiz de N; medido, a razão fica entre 15 e 20 vezes a raiz de N. Comprimir o resíduo em relação ao centroide, e não o vetor original, é o padrão e ajuda principalmente em códigos curtos. Os grafos (HNSW e NSG) trocam memória por velocidade e não usam compressão; aumentar arestas por nó melhora até 64 e depois piora.

Como cada índice tem vários hiperparâmetros monótonos, o ajuste é feito por poda de fronteira de Pareto: num exemplo do paper, 5.808 combinações caem para 398 experimentos, dos quais 87 são ótimos. Tudo isso é montável por string:

PCA160,IVF20000_HNSW,PQ20x10,RFlat

PCA para 160 dimensões, IVF com 20.000 listas e coarse quantizer HNSW, PQ de 20 sub-quantizadores de 10 bits, reranking exato no fim.

o que isso custou

O escopo é deliberadamente estreito, e isso aparece na hora de operar. Não há metadata: filtrar por atributo exige um callback chamado no loop mais interno, com cache miss garantido. O truque dos autores na competição BigANN foi roubar os bits não usados do id de 63 bits para guardar assinaturas de 39 bits e pré-filtrar com duas instruções — solução boa, mas que denuncia a falta de suporte de primeira classe. Índices em grafo não suportam remoção; o mapa direto de id para posição vive desligado por custo de memória.

Não há garantia teórica de nada: a qualidade é medida empiricamente em benchmark, e os autores dizem por que — as métricas de distorção são só proxy do problema real de k vizinhos. Os experimentos assumem treino, base e query da mesma distribuição; dados out-of-distribution ficam de fora do trabalho. E a otimização SIMD cobre apenas alguns tamanhos de código; fora deles, você cai no caminho genérico.

onde isso aparece hoje

O paper é o registro de projeto de uma biblioteca que virou infraestrutura: aberta em 2017, com mais de 30.000 stars no GitHub e 3 milhões de downloads na contagem dos autores. O Milvus usa Faiss como um dos engines da sua camada Knowhere; a Pinecone começou nele e depois reescreveu o motor em Rust. É a matéria-prima da geração de sistemas descritos em Vector Database Management Techniques and Systems e Manu.

Os dois algoritmos centrais têm verbete próprio: Product Quantization for Nearest Neighbor Search, de autoria em parte do mesmo grupo, e HNSW. Do outro lado, a recuperação de texto para tarefas intensivas em conhecimento — a família de RAG — aparece na própria seção de aplicações. O caso extremo relatado indexa 1,5 trilhão de vetores em 144 dimensões comprimidos a 54 bytes, com um memory map de 83 TiB e cerca de 1 segundo por consulta.

lido na íntegra por pipeline de llm, revisado por antonio leandro antes de publicar ·