- Para reducir las limitaciones de
sqlite-vss,sqlite-vecse está desarrollando como una extensión embebida de búsqueda vectorial basada en C puro, orientada a prácticamente cualquier entorno donde se ejecute SQLite - El flujo de uso en SQL se simplifica en torno a
CREATE VIRTUAL TABLE,INSERT INTOySELECT, y admite búsquedas estilo KNN junto con entrada de vectores en JSON y en formato binario compacto - Al eliminar la dependencia de Faiss, apunta no solo a Linux y macOS, sino también a Windows, WebAssembly, móviles y Raspberry Pi, con un tamaño binario esperado de cientos de KB, menor que los 3 MB a 5 MB anteriores
- Almacena los vectores por chunks en una shadow table para reducir la necesidad de cargar todo en RAM, y permite acelerar la búsqueda en memoria con
PRAGMA mmap_size - La versión inicial solo ofrecerá full-scan exhaustivo y no incluirá ANN; el lanzamiento de
v0.1.0está previsto una vez que se completen los 246 TODO desqlite-vec.c
Cómo sqlite-vec busca cambiar la búsqueda vectorial en SQLite
sqlite-veces una nueva extensión de SQLite escrita en C puro, y es un proyecto que busca reemplazar asqlite-vss, publicado en febrero de 2023- El alcance previsto incluye funciones SQL definidas por el usuario para búsqueda vectorial rápida, tablas virtuales y herramientas y utilidades para operaciones con vectores
- cuantización
- conversión JSON/BLOB/numpy
- aritmética de vectores
- Los usuarios pueden crear un almacén vectorial y hacer búsquedas usando solo SQL puro
- crear una tabla virtual para vectores con
CREATE VIRTUAL TABLE - insertar vectores con
INSERT INTO - hacer búsquedas estilo KNN con la forma
SELECT ... WHERE sample_embedding MATCH ... ORDER BY distance LIMIT ...
- crear una tabla virtual para vectores con
- La entrada de vectores puede usar cadenas JSON o formato binario compacto
Entornos de ejecución que habilitan C puro y cero dependencias
sqlite-vecapunta a ser una extensión de C puro sin dependencias, y esa decisión es la condición clave para ampliar las plataformas compatibles- El anterior
sqlite-vss, debido a su dependencia de C++, solo funcionaba de forma estable en Linux y macOS, y su tamaño binario estaba en el rango de 3 MB a 5 MB - La nueva extensión apunta a ejecutarse en los siguientes entornos
- Linux
- macOS
- Windows
- WebAssembly en el navegador
- dispositivos móviles
- dispositivos pequeños como Raspberry Pi
- El tamaño binario estimado está en el rango de cientos de KB
Control de uso de memoria y velocidad de búsqueda
sqlite-veccontrola el uso de memoria almacenando los vectores divididos en chunks dentro de una shadow table- durante una búsqueda KNN, lee por chunks en lugar de cargar todos los vectores a la vez en RAM
- no hace falta mantener todos los vectores residentes en memoria
- Si se necesita velocidad basada en memoria, se puede usar
PRAGMA mmap_sizede SQLite para acelerar aún más la búsqueda KNN
Nuevas capacidades vectoriales y limitaciones iniciales
sqlite-vecbusca dar mejor soporte a las siguientes funciones, reflejando las herramientas y líneas de investigación recientes en búsqueda vectorial- embeddings de longitud adaptativa, es decir, Matryoshka embeddings
- vectores
int8ybit - binary and scalar quantization
- Estas capacidades sientan la base para ajustar con más precisión la velocidad, la exactitud y el uso de disco de los vectores
- La versión inicial de
sqlite-vecsolo soportará búsqueda vectorial exhaustive full-scan- al principio no habrá opción de “approximate nearest neighbors”
- IVF y HNSW son funciones que esperan añadir más adelante
Estructura del demo en navegador
- El demo usa
sqlite-vecejecutándose en el navegador - La configuración visible en las herramientas de desarrollo es la siguiente
sqlite3.wasmde 5.9 MB sin optimizar- el build oficial de SQLite WASM compilado con
sqlite-vec - una base de datos SQLite
movies.bit.dbde 2.6 MB
movies.bit.dbcontiene 4,800 sinopsis de películas en la tablaarticles, basadas en TMDB movie metadata- Una tabla virtual separada,
vec_movies, es el índice vectorial de los embeddings de esas sinopsis- los embeddings usan el modelo Nomic 1.5 embeddings
- los vectores están cuantizados como binary vector
Datos del demo y flujo de búsqueda KNN
- La tabla
articlestiene columnas comotitle,release_dateyoverview - La columna
overviewcontiene una breve descripción de la trama de cada película y es lo que se embebe en el demo - La tabla virtual
vec_moviesalmacena los embeddings dearticles.overviewen la columnaoverview_embeddings- los vectores son un binary vector de 768 dimensiones
- el tamaño de almacenamiento es
768 / 8 = 96, es decir, 96 bytes
- Cuando el usuario selecciona una película con un botón de opción, el ID de la película elegida se coloca en el parámetro
:selected_moviede la consulta SQL KNN - Los resultados de búsqueda son las 10 películas más cercanas a la película seleccionada
- como es un binary vector, para calcular la distancia se usa hamming distance
- el resultado más cercano siempre es la misma película, con distancia 0
- Los resultados de embeber tramas cortas de una sola frase y un dataset pequeño de películas no son de máxima calidad, y la cuantización binaria sacrifica aún más calidad, pero el enfoque está en mostrar una búsqueda vectorial rápida y “lo suficientemente buena” dentro del navegador
- Para ver el funcionamiento interno, se puede anteponer
EXPLAIN QUERY PLANaSELECT, y así ver el “index”0:knnque usavec_movies
Limitaciones de sqlite-vss y dependencia de Faiss
- El desarrollo y la adopción de
sqlite-vsstuvieron varios obstáculos- solo funciona en Linux y macOS, y no soporta Windows, WASM ni dispositivos móviles
- guarda todos los vectores en memoria
- tiene bugs y problemas relacionados con transacciones
- compilarlo es muy difícil y toma mucho tiempo
- carece de operaciones vectoriales comunes como scalar/binary quantization
- Casi todos estos problemas provienen de la dependencia de
Faiss - Algunos podrían resolverse con mucho tiempo y esfuerzo, pero una parte importante puede quedar bloqueada por Faiss
- A partir de la idea de que una solución de bajo nivel sin dependencias era una opción atractiva, y de que la búsqueda vectorial en sí no es tan compleja, nació
sqlite-vec
Estado del lanzamiento y pedido de patrocinio
- Las funciones principales de
sqlite-vecya funcionan, pero aún faltan mucho manejo de errores y pruebas - En el archivo
sqlite-vec.cquedan 246 TODO- 191
todo_assert() - 41 comentarios
// TODO - 14
todo panic - el progreso total aparece como 0/246, 0%, para
sqlite-vec v0
- 191
- Cuando se completen los 246 TODO, está previsto el primer lanzamiento
v0.1.0- documentación
- demo
- bindings
- y otros componentes se ofrecerán junto con él
- El objetivo es dentro de aproximadamente un mes, pero no hay una fecha confirmada
- Se buscan patrocinadores entre empresas interesadas en el éxito de
sqlite-vec, y se puede consultar por correo electrónico
1 comentarios
Opiniones de Hacker News
Soy el autor; si tienen preguntas, las respondo. Esto es más bien del tipo “estoy trabajando en un proyecto nuevo” que un lanzamiento oficial, y la extensión en sí todavía está en progreso. El enlace del proyecto es https://github.com/asg017/sqlite-vec
Tengo una idea bastante concreta de cómo se verá la v0.1.0 de esta extensión, pero probablemente falten unas semanas para llegar ahí. El objetivo de este post era sobre todo avisar a los usuarios de sqlite-vss, la extensión de búsqueda vectorial para SQLite que hice antes, qué viene después; cuando esté lista habrá un lanzamiento más grande.
En general, me entusiasma mucho tener una alternativa de búsqueda vectorial fácil de embeber. Es especialmente bueno que funcione en todos los sistemas operativos, WASM, dispositivos móviles, Raspberry Pi, etc.; personalmente estoy intentando correr una pequeña app de búsqueda semántica en una Beepy, así que está divertido.
[0] https://beepy.sqfmi.com/
También me gustaría conocer el rendimiento comparado con sqlite-vss. Me interesan métricas de profiling tanto de velocidad de consulta como de uso de memoria.
En general se ve realmente excelente y me gusta esta dirección.
Me parece 1000% correcto el enfoque de que al principio sqlite-vec solo soporte búsqueda vectorial por escaneo completo exhaustivo y no tenga opciones de vecinos más cercanos aproximados (ANN), pero que más adelante quiera agregar IVF y HNSW. Me gusta que no lo vuelvan excesivamente complejo desde el inicio.
Ya lancé búsqueda vectorial on-device, y con vectores binarios de 128 bits más distancia de Hamming era lo bastante rápida como para ejecutar una búsqueda de distancia completamente por fuerza bruta en cada frame de cámara, incluso con una base de datos de más de 200 mil elementos. En teléfonos de gama baja daba más de 10 fps, y en teléfonos buenos iba muy fluido. Hay una cantidad sorprendente de casos en los que la fuerza bruta es suficiente.
Dicho eso, al implementar algoritmos ANN como HNSW, sería genial si pudiera manejarse con el paradigma de índices de tabla. Así, cambiar de búsqueda por fuerza bruta a ANN sería tan simple como crear un índice en la tabla, y experimentar con varios algoritmos ANN y parámetros sería posible ajustando los parámetros de creación del índice. Tal vez ya vaya por ese lado, pero lo menciono por si acaso.
También me pregunto si lo están compilando junto con sqlite-httpvfs. Parece que encajaría bien con este proyecto: https://github.com/phiresky/sql.js-httpvfs
Me pregunto si consideraste hacerlo compatible en sintaxis con pgvector para tener un DSL vectorial SQL común. Sospecho que las desventajas no son mucho menores que las ventajas, pero me da curiosidad si es posible.
https://observablehq.com/@asg017/introducing-sqlite-loadable...
sqlite-vss ya se usa bien en varios proyectos.
Me confunde la parte de “es un vector binario de 768 dimensiones, por lo que ocupa 96 bytes (768 / 8 = 96)”. Creo que ahí está justamente la maldición de la dimensionalidad, un problema que sufren la mayoría de los almacenes vectoriales, y es un problema previo a la indexación.
Pensé que quizá se refería a 768 dimensiones * 8 bytes (f64), es decir 6144 bytes. Normalmente se reduce a f32, f16 o una representación aún más pequeña, aceptando una pequeña pérdida.
Si hay una forma de meter 768 dimensiones en 96 bytes mediante compresión, algún tipo de amortización similar a tries, etc., me gustaría leer otro post al respecto. Si se trata de manejar cada dimensión como 1 bit, lo entiendo, pero entonces sigo teniendo dudas sobre la calidad de búsqueda.
Algunos modelos de embeddings, como nomic v1.5[0] o el nuevo modelo de mixedbread[1], se entrenan específicamente para mantener la calidad incluso después de la cuantización binaria. No todos los modelos son así, así que los resultados pueden variar. En general, con vectores muy grandes, como el gran modelo de embeddings de OpenAI de 3072 dimensiones, parece funcionar hasta cierto punto aunque no hayan sido entrenados específicamente para eso.
[0] https://twitter.com/nomic_ai/status/1769837800793243687
[1] https://www.mixedbread.ai/blog/binary-mrl
Si usas un índice FAISS sobre los datos y aplicas cuantización de producto (Product Quantization), para características binarias puedes probar vectores binarios con algo como PQ768x1, y también comparar enfoques como cuantizar cada par de vectores a uno de cuatro valores: https://github.com/facebookresearch/faiss/wiki/The-index-fac...
Normalmente, en las bases de datos vectoriales, los datos se comprimen o proyectan a un espacio de menor dimensión antes de almacenarlos, así que eso más bien mejora esta situación.
Gracias a sqlite-vss pude aprender cómo funciona RAG e implementarlo en un proyecto de juguete. La depuración fue un poco difícil, pero cuando lo ajustabas bien funcionaba sin problemas en Ubuntu, y todavía lo uso.
Me alegra que estén creando una nueva versión mejor, sin dependencias limitantes.
Me pregunto si planean usar solo la API de SQLite pública, o si imaginan algo acoplado a la amalgamación de SQLite.
Sin duda me interesa una funcionalidad así, pero tendría que pensar cómo distribuirla por separado de SQLite en bindings de Go basados en Wasm. Hasta ahora he empaquetado todo el código C porque es mucho más simple que el “enlace dinámico” en Wasm.
También mencionaste la E/S incremental de BLOB; seguramente ya lo sabes, pero hay que tener en cuenta que, como los BLOB grandes se almacenan como listas enlazadas de páginas, la E/S de BLOB nunca es de acceso aleatorio.
Me gustan mucho los bindings de SQLite de wazero. De hecho planeo ofrecer 1) bindings CGO para sqlite-vec y 2) una compilación WASI personalizada de sqlite-vec que pueda usarse directamente en go-sqlite3. Originalmente pensaba usar los scripts de compilación de ese repositorio para generar el archivo sqlite3.wasm. Si quisieran darle soporte directo en el proyecto, creo que bastaría con poner los archivos sqlite-vec.c/h dentro de go-sqlite3/sqlite3.
Aprendí por las malas lo de la E/S incremental de BLOB. Definitivamente es un factor limitante en la velocidad de consulta de sqlite-vec. Mantener el tamaño de los chunks relativamente pequeño, en el rango bajo de MB, y aumentar page_size daba un equilibrio razonable, pero tiene efectos secundarios, sobre todo page_size. PRAGMA mmap_size también ayuda mucho, porque parece mantener las páginas en memoria y acelera las búsquedas en overflow, pero obviamente aumenta mucho el uso de memoria. Es un equilibrio difícil.
DuckDB anunció hoy la extensión “Vector Similarity Search in DuckDB”.
https://duckdb.org/2024/05/03/vector-similarity-search-vss.h...
Con DuckDB VSS parece que podrías generar embeddings, guardarlos en formato DuckDB y luego ejecutar SQL dentro del CDN.
Me gustan los proyectos de este estilo. Me gusta que sean proyectos open source enfocados en un problema muy específico.
En el ecosistema de TypeScript/Next.js/React sigo pensando si podría crear algo muy útil para algún nicho técnico, pero todavía no se me ocurre la inspiración.
En https://github.com/rnadigital/agentcloud, una app de AI RAG, usamos Qdrant vector DB para automatización end-to-end, así que me entusiasma que estén haciendo un sucesor. Me pregunto cuándo estará listo para usarse y si habrá una guía de inicio rápido.
También podría ayudar con la redacción del blog.
Hay un paquete pip de
sqlite-vecsin documentar, así que si quieres llamarlo directamente desde el “Agent Backend” en Python, creo que ya podrías probarlo.Esto se parece bastante a lo que imaginaba que sería el “desarrollo guiado por README”. Me pregunto si el autor empezó por la documentación.
Pero está en el estado de “hice el 80% con el 20% del esfuerzo”, así que el 20% restante —manejo de errores, fuzz testing y pruebas de corrección— probablemente se llevará el 80% del tiempo. Aun así, la gente ya estaba preguntando por el estado actual de
sqlite-vss, así que pensé que este post de blog de “trabajo en curso” podría responder algunas preguntas.También me gusta la idea de empezar por la documentación. Especialmente en extensiones de SQLite, es muy importante cómo se ve la API SQL, es decir, funciones escalares, tablas virtuales, etc. Antes de escribir la mayor parte del código, bosquejé bastante cómo debería verse la parte SQL de sqlite-vec.
[0] https://github.com/asg017/sqlite-vec/blob/main/sqlite-vec.c
Parece casi una respuesta a un issue de GitHub que abrí hace unos meses en SQLite-vss. Técnicamente no es una respuesta a ese issue, pero aun así.
https://github.com/asg017/sqlite-vss/issues/124
De hecho, cuando leí ese ticket por primera vez, caí en la madriguera de “cómo podría mejorar sqlite-vss”, y eso terminó llevándome a “debería crear sqlite-vec”. Gracias por ayudarme a tomar este camino.
Con la cuantización binaria integrada de sqlite-vec, podrías hacer algo más o menos así:
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*/)))Me pregunto si, al ejecutarse dentro del navegador, sqlite-vec puede persistir datos en el IndexedDB nativo del navegador. O si esto es algo que el usuario debe manejar directamente
Aunque la respuesta sea que todavía no lo has pensado, agradecería que compartieras tus ideas en esa dirección
No estoy seguro de si IndexedDB está soportado específicamente, pero se pueden usar localStorage/OPFS VFS
[0] https://sqlite.org/wasm/doc/trunk/persistence.md#kvvfs