- Para reduzir as limitações do
sqlite-vss, osqlite-vecestá sendo desenvolvido como uma extensão embarcada de busca vetorial em C puro, visando praticamente todos os ambientes onde o SQLite roda - O fluxo de uso em SQL é simplificado em torno de
CREATE VIRTUAL TABLE,INSERT INTOeSELECT, com suporte a busca no estilo KNN e entrada de vetores em JSON e formato binário compacto - Ao remover a dependência de Faiss, o projeto mira não só Linux e macOS, mas também Windows, WebAssembly, dispositivos móveis e Raspberry Pi, com expectativa de um binário de algumas centenas de KB, menor que os 3MB~5MB anteriores
- Os vetores são armazenados em chunks dentro de uma shadow table, reduzindo a necessidade de carregar tudo na RAM, e
PRAGMA mmap_sizepode acelerar buscas baseadas em memória - A versão inicial terá apenas full-scan exaustivo, sem ANN, e o lançamento do
v0.1.0está previsto para depois que os 246 TODOs emsqlite-vec.cforem concluídos
O que o sqlite-vec quer mudar na busca vetorial do SQLite
sqlite-vecé uma nova extensão do SQLite escrita em C puro e um projeto que busca substituir osqlite-vss, lançado em fevereiro de 2023- O escopo inclui funções SQL definidas pelo usuário para busca vetorial rápida, tabelas virtuais (virtual tables), ferramentas e utilitários para operações com vetores
- quantização
- conversão entre JSON/BLOB/numpy
- aritmética vetorial
- O usuário pode criar e consultar um armazenamento vetorial usando apenas SQL
- criar uma tabela virtual para vetores com
CREATE VIRTUAL TABLE - inserir vetores com
INSERT INTO - fazer busca no estilo KNN com
SELECT ... WHERE sample_embedding MATCH ... ORDER BY distance LIMIT ...
- criar uma tabela virtual para vetores com
- A entrada de vetores pode usar strings JSON ou formato binário compacto
Ambientes de execução viabilizados por C puro e ausência de dependências
- O
sqlite-vectem como meta ser uma extensão em C puro sem dependências, e essa escolha é a condição central para ampliar as plataformas suportadas - O
sqlite-vssanterior, por causa da dependência de C++, só funcionava de forma estável em Linux e macOS, com binários na faixa de 3MB~5MB - A nova extensão pretende rodar nos seguintes ambientes
- Linux
- macOS
- Windows
- WebAssembly no navegador
- dispositivos móveis
- dispositivos pequenos como Raspberry Pi
- O tamanho esperado do binário é de algumas centenas de KB
Controle de uso de memória e velocidade de busca
- O
sqlite-veccontrola o uso de memória armazenando os vetores divididos em chunks dentro de uma shadow table- em buscas KNN, os vetores são lidos por chunk, sem carregar todos de uma vez na RAM
- não é necessário manter o conjunto inteiro de vetores residente em memória
- Se for necessário desempenho baseado em memória, é possível usar
PRAGMA mmap_sizedo SQLite para acelerar a busca KNN
Novos recursos vetoriais e limitações iniciais
- O
sqlite-vecbusca oferecer suporte melhor aos recursos abaixo, refletindo ferramentas e pesquisas recentes de busca vetorial- embeddings de comprimento adaptativo, ou Matryoshka embeddings
- vetores
int8ebit - quantização binária e escalar
- Esses recursos formam a base para ajustar com mais precisão a velocidade, a precisão e o uso de disco dos vetores
- O
sqlite-vecinicial suporta apenas busca vetorial por full-scan exaustivo- a opção de “approximate nearest neighbors” não estará presente no começo
- IVF e HNSW são recursos desejados para adição futura
Estrutura da demo no navegador
- A demo usa
sqlite-vecrodando no navegador - A configuração que pode ser vista nas ferramentas de desenvolvedor inclui
sqlite3.wasmnão otimizado de 5.9MB- a build oficial SQLite WASM compilada com
sqlite-vec - um banco de dados SQLite
movies.bit.dbde 2.6MB
- O
movies.bit.dbcontém 4.800 overviews de filmes na tabelaarticles, com base em metadados de filmes da TMDB - A tabela virtual separada
vec_moviesé o índice vetorial dos embeddings desses overviews- os embeddings usam o modelo Nomic 1.5 embeddings
- os vetores são quantizados como binary vector
Dados da demo e fluxo de busca KNN
- A tabela
articlestem colunas comotitle,release_dateeoverview - A coluna
overviewcontém o resumo do enredo dos filmes em frases curtas e é o alvo dos embeddings na demo - A tabela virtual
vec_moviesarmazena os embeddings dearticles.overviewna colunaoverview_embeddings- os vetores são binary vectors de 768 dimensões
- o tamanho armazenado é
768 / 8 = 96, ou seja, 96 bytes
- Quando o usuário seleciona um filme com o botão de opção, o ID do filme escolhido preenche o parâmetro
:selected_movieda consulta SQL KNN - O resultado da busca são os 10 filmes mais próximos do filme selecionado
- como se trata de binary vector, o cálculo de distância usa hamming distance
- o resultado mais próximo é sempre o próprio filme, com distância 0
- Os embeddings de resumos curtos em frase única e de um dataset pequeno de filmes não têm a melhor qualidade possível, e a quantização binária sacrifica ainda mais a qualidade, mas o foco é mostrar uma busca vetorial rápida e “boa o suficiente” dentro do navegador
- Para verificar o funcionamento interno, basta colocar
EXPLAIN QUERY PLANantes deSELECT, e será possível ver o “index”0:knnusado porvec_movies
Limitações do sqlite-vss e dependência de Faiss
- Houve vários obstáculos no desenvolvimento e na adoção do
sqlite-vss- só funcionava em Linux e macOS, sem suporte a Windows, WASM, dispositivos móveis etc.
- armazenava todos os vetores na memória
- havia bugs e problemas relacionados a transações
- era muito difícil e demorado de compilar
- faltavam operações vetoriais comuns, como quantização escalar/binária
- Quase todos esses problemas vinham da dependência de
Faiss - Alguns deles talvez pudessem ser resolvidos com muito tempo e esforço, mas vários continuariam bloqueados por causa do Faiss
- A partir da avaliação de que uma solução de baixo nível sem dependências era uma opção atraente e de que a busca vetorial em si não é tão complexa, surgiu o
sqlite-vec
Estado do lançamento e pedido de patrocínio
- Os recursos centrais do
sqlite-vecjá funcionam, mas o tratamento de erros e os testes ainda são muito insuficientes - Ainda restam 246 TODOs no arquivo
sqlite-vec.c- 191
todo_assert() - 41 comentários
// TODO - 14
todo panic - o progresso total aparece como 0/246, 0%, com base no
sqlite-vec v0
- 191
- Quando os 246 TODOs forem concluídos, sairá o primeiro lançamento
v0.1.0- documentação
- demo
- bindings
- outros componentes devem ser fornecidos junto
- A meta é algo como cerca de um mês, mas sem cronograma confirmado
- O projeto está buscando patrocínio de empresas interessadas no sucesso do
sqlite-vec, com contato por e-mail
1 comentários
Comentários do Hacker News
Sou o autor — respondo perguntas, se houver. Isto tem mais o caráter de “estou trabalhando em um projeto novo” do que de um lançamento oficial, e a extensão em si ainda está em desenvolvimento. Link do projeto: https://github.com/asg017/sqlite-vec
Já tenho uma ideia bem concreta de como será a v0.1.0 desta extensão, mas provavelmente ainda vai levar mais algumas semanas até chegar lá. Este post teve muito o objetivo de avisar aos usuários do sqlite-vss, a extensão anterior de busca vetorial para SQLite que criei, o que vem a seguir, e deve haver um lançamento maior quando estiver pronto
No geral, estou muito animado por ter uma alternativa de busca vetorial fácil de embutir. É especialmente ótimo que rode em todos os sistemas operacionais, WASM, dispositivos móveis, Raspberry Pi etc., e pessoalmente estou me divertindo tentando rodar um pequeno app de busca semântica no Beepy
[0] https://beepy.sqfmi.com/
Também queria saber como fica o desempenho em comparação com o sqlite-vss. Tenho curiosidade sobre números de profiling tanto de velocidade de consulta quanto de uso de memória
No geral, isso parece realmente excelente, e gosto dessa direção
Acho 1000% certa a abordagem de o sqlite-vec inicialmente suportar apenas busca vetorial por varredura completa e não ter opção de vizinho mais próximo aproximado (ANN), mas depois querer adicionar IVF e HNSW. Gosto do fato de não tornar tudo excessivamente complexo logo de início
Já lancei busca vetorial on-device antes, e a combinação de vetores binários de 128 bits com distância de Hamming era rápida o suficiente para rodar uma busca exaustiva completa de distância a cada frame da câmera, mesmo com mais de 200 mil itens no banco de dados. Em celulares baratos passava de 10fps, e em aparelhos bons ficava bem fluido. É surpreendente quantas vezes força bruta é suficiente
Dito isso, ao implementar algoritmos ANN como HNSW, seria legal se desse para tratar isso dentro do paradigma de índice de tabela. Assim, mudar de busca por força bruta para ANN ficaria tão simples quanto criar um índice na tabela, e também daria para experimentar vários algoritmos ANN e parâmetros ajustando os parâmetros de criação do índice. Talvez isso já esteja indo nessa direção, mas achei melhor mencionar
Também queria saber se isso compila junto com sqlite-httpvfs. Parece combinar bem com este projeto: https://github.com/phiresky/sql.js-httpvfs
Também queria saber se você pensou em torná-lo compatível em sintaxe com pgvector para uma SQL vector DSL comum. Imagino que as desvantagens não sejam tão maiores que as vantagens, mas queria saber se isso é possível
https://observablehq.com/@asg017/introducing-sqlite-loadable...
O sqlite-vss já está sendo usado bem em alguns projetos
A parte que diz “um vetor binário de 768 dimensões ocupa 96 bytes (768 / 8 = 96)” me confundiu. Justamente esse tipo de coisa é o problema da maldição da dimensionalidade que a maioria dos vector stores enfrenta, e eu vejo isso como um problema anterior à indexação
Achei que talvez quisesse dizer 768 dimensões * 8 bytes (f64), ou seja, 6144 bytes. Normalmente se reduz isso para f32, f16 ou representações ainda menores aceitando alguma perda
Se existir alguma forma de colocar 768 dimensões em 96 bytes usando compressão ou alguma técnica de colapso parecida com trie, eu gostaria muito de ler um post separado sobre isso. Se cada dimensão estiver sendo tratada como 1 bit, eu entendo, mas mesmo assim continuo com dúvidas sobre a qualidade da busca
Alguns modelos de embedding, como o nomic v1.5[0] e o novo modelo da mixedbread[1], são treinados especificamente para manter a qualidade mesmo após quantização binária. Nem todos os modelos são assim, então os resultados podem variar. Em geral, com vetores muito grandes, como o grande modelo de embeddings de 3072 dimensões da OpenAI, isso parece funcionar até certo ponto mesmo sem treinamento específico para isso
[0] https://twitter.com/nomic_ai/status/1769837800793243687
[1] https://www.mixedbread.ai/blog/binary-mrl
Se você usar um índice FAISS nos dados e aplicar Product Quantization, no caso de características binárias dá para testar vetores binários de um jeito como PQ768x1, e também comparar abordagens que quantizam cada par de vetores em um de quatro valores possíveis: https://github.com/facebookresearch/faiss/wiki/The-index-fac...
Normalmente, em bancos de dados vetoriais, os dados são comprimidos ou projetados para um espaço de dimensão menor antes do armazenamento, então, na verdade, essa situação tende a melhorar
Graças ao sqlite-vss, consegui aprender como o RAG funciona e implementar isso em projetos de brinquedo. Depurar foi um pouco difícil, mas, quando tudo foi ajustado corretamente, funcionou sem problemas no Ubuntu, e ainda uso até hoje
Fico feliz em ver que estão criando uma nova versão melhor, sem dependências limitantes
Tenho curiosidade se o plano é usar apenas a API pública do SQLite ou se vocês imaginam algo acoplado ao amalgamation do SQLite
Com certeza tenho interesse nesse tipo de funcionalidade, mas, no caso de bindings de Go baseados em Wasm, preciso pensar em como distribuir isso separadamente do SQLite. Até agora, tenho empacotado todo o código C junto, porque isso é muito mais simples do que “linkagem dinâmica” em Wasm
Você também mencionou E/S incremental de BLOB, mas, como talvez já saiba, BLOBs grandes são armazenados como uma lista encadeada de páginas, então a E/S de BLOB nunca é realmente de acesso aleatório
Gosto muito do binding de SQLite para wazero. Na verdade, o plano é oferecer 1) bindings CGO para o sqlite-vec e 2) um build WASI customizado do sqlite-vec que possa ser usado diretamente no go-sqlite3. Originalmente, eu pensava em usar os scripts de build daquele repositório para gerar o arquivo sqlite3.wasm. Se você quiser dar suporte direto a isso no projeto, talvez baste colocar os arquivos sqlite-vec.c/h em go-sqlite3/sqlite3
Aprendi da maneira difícil sobre E/S incremental de BLOB. Isso é claramente um fator limitante na velocidade de consulta do sqlite-vec. Manter o tamanho dos chunks relativamente pequeno, na faixa de poucos MB, e aumentar o page_size deu um equilíbrio razoável, mas há efeitos colaterais, especialmente com o page_size. PRAGMA mmap_size também ajuda bastante, aparentemente mantendo páginas na memória e acelerando buscas por overflow, mas, claro, isso aumenta muito o uso de memória. É um equilíbrio difícil
O DuckDB anunciou hoje a extensão “Vector Similarity Search in DuckDB”
https://duckdb.org/2024/05/03/vector-similarity-search-vss.h...
Com o DuckDB VSS, parece que daria para gerar embeddings, armazená-los no formato do DuckDB e depois processar tudo executando SQL dentro da CDN
Gosto desse tipo de projeto. É um projeto open source voltado para um problema bem específico, e isso é ótimo
Continuo pensando se também seria possível criar algo muito útil para um nicho técnico no ecossistema TypeScript/Next.js/React, mas ainda não tive inspiração
Usei o banco vetorial Qdrant para automação de ponta a ponta no app de AI RAG https://github.com/rnadigital/agentcloud, então estou animado em ver uma continuação. Tenho curiosidade sobre quando isso estará pronto para uso e se haverá um guia de início rápido
Talvez eu também possa ajudar a escrever posts no blog
Existe um pacote pip
sqlite-vecnão documentado, então, se você quiser chamá-lo diretamente a partir de um “Agent Backend” em Python, talvez já dê para experimentar agoraIsso é bem parecido com o que eu imaginava que seria “desenvolvimento guiado por README”. Fiquei curioso se o autor começou pela documentação
Só que estou naquele ponto clássico de “80% feito com 20% do esforço”, e os 20% restantes — tratamento de erros, fuzz testing e testes de correção — provavelmente vão consumir 80% do tempo. Ainda assim, como as pessoas já estão fazendo perguntas sobre o estado atual do
sqlite-vss, achei que este post de blog de “trabalho em andamento” poderia responder algumas delasTambém gosto da ideia de começar pela documentação. Especialmente em extensões para SQLite, é muito importante como a API SQL vai se parecer, ou seja, funções escalares, tabelas virtuais etc. Antes de escrever a maior parte do código, rabisquei bastante como a parte SQL do sqlite-vec deveria ser
[0] https://github.com/asg017/sqlite-vec/blob/main/sqlite-vec.c
Isso parece próximo de uma resposta para uma issue que abri no GitHub do SQLite-vss alguns meses atrás. Tecnicamente não é uma resposta direta àquela issue, mas chega perto
https://github.com/asg017/sqlite-vss/issues/124
Na verdade, quando li aquele ticket pela primeira vez, acabei entrando numa verdadeira toca de coelho sobre “como tornar o sqlite-vss melhor”, e isso acabou levando à conclusão de que eu deveria criar o sqlite-vec. Obrigado por me ajudar a seguir por esse caminho
Com a quantização binária embutida do sqlite-vec, dá para fazer algo mais ou menos assim:
CREATE VIRTUAL TABLE vec_files USING vec0 ( contents_embedding bit[1536] );INSERT INTO vec_files(rowid,contents_embedding) VALUES ((1, vec_quantize_binary( /* 1536-dimension float vector here*/)))Tenho curiosidade se, ao rodar no navegador, o sqlite-vec consegue persistir dados no IndexedDB nativo do navegador. Ou se essa parte precisa ser tratada pelo próprio usuário
Mesmo que a resposta seja que isso ainda não foi pensado, eu agradeceria se você pudesse compartilhar como está pensando nessa direção
Não tenho certeza se o IndexedDB é suportado especificamente, mas localStorage/OPFS VFS pode ser usado
[0] https://sqlite.org/wasm/doc/trunk/persistence.md#kvvfs