jsongrep: búsqueda de JSON con autómatas, no con filtros

Share

Si usas jq para parsear JSON en tus scripts, ya sabes la historia: funciona bien para la mayoría de los casos, pero en archivos de cientos de megabytes empieza a doler. jsongrep propone un enfoque distinto: en lugar de interpretar un filtro sobre el JSON, compila la consulta en un autómata determinístico finito (DFA) antes de mirar los datos. El resultado es una búsqueda en un único pase, sin backtracking, con complejidad O(n).

Es un proyecto open-source en Rust, MIT, nacido como investigación de pregrado. Lleva poco tiempo en el radar público —publicó sus benchmarks hace días en Reddit— pero la comparativa es difícil de ignorar.

¿Qué hace jsongrep exactamente?

jsongrep (binario: jg) toma una consulta de caminos regulares y un JSON, y devuelve todos los valores cuyo path coincida. El lenguaje de consulta es deliberadamente simple: secuencias, wildcards, alternación, descenso recursivo. Se parece a regex aplicada a rutas de árbol, no a un lenguaje de transformación.

Aprende IA con nosotros

Únete gratis a mi comunidad en Skool, donde compartimos noticias, tutoriales y recursos para seguir aprendiendo juntos.

👥 Únete gratis 🚀

Algunos ejemplos rápidos:

# Buscar "name" a cualquier profundidad
cat data.json | jg -F name

# Todos los emails de un array
cat data.json | jg 'users[*].email'

# Alternación: cualquier campo bajo "error" o "warn"
cat data.json | jg '(error|warn).*'

La diferencia clave respecto a jq: jsongrep es una herramienta de búsqueda, no de transformación. No tiene filtros, aritmética ni interpolación de strings. Si necesitas remodelar datos, jq sigue siendo la opción. Si necesitas encontrar valores por path —especialmente en archivos grandes—, jsongrep es otra conversación.

¿Por qué es más rápido? La arquitectura del motor

El punto central del proyecto es su motor de búsqueda basado en DFA. El pipeline tiene cinco pasos:

  1. Parsear el JSON en árbol usando serde_json_borrow (zero-copy: trabaja con referencias al buffer original, sin alocar nuevas strings)
  2. Parsear la consulta del usuario en un AST
  3. Construir un NFA desde la consulta usando el algoritmo de Glushkov (produce un NFA libre de transiciones epsilon)
  4. Determinizar el NFA en un DFA mediante construcción de subconjuntos
  5. Recorrer el árbol JSON con el DFA, tomando transiciones O(1) en cada arista

El resultado práctico: el DFA permite podar ramas enteras del árbol JSON en O(1). Si la consulta es roommates[*].name y el cursor está en la raíz del documento, el DFA descarta inmediatamente las claves "name" y "favorite_drinks" sin entrar en sus subárboles. Eso, en un archivo de 190 MB, marca la diferencia.

El tradeoff es real y el autor lo documenta explícitamente: la compilación de la consulta a DFA tiene un costo upfront. En archivos pequeños ese overhead importa. En archivos grandes, el costo se amortiza con creces.

Los benchmarks

Los benchmarks usan Criterion.rs (framework estadístico) y están diseñados para aislar cada costo por separado: parseo del documento, compilación de la consulta, búsqueda pura, y pipeline end-to-end. El dataset más exigente es un GeoJSON de San Francisco de ~190 MB.

Las herramientas comparadas: jsonpath-rust, jmespath, jaq (clon de jq), y jql. En end-to-end sobre el dataset grande, jsongrep no es marginalmente más rápido —la diferencia es de un orden de magnitud contra varias de esas herramientas.

El análisis completo está en el sitio de Criterion con todos los gráficos interactivos. La metodología incluye consideraciones de fairness: el costo de zero-copy está aislado, el compilador de DFA se mide por separado, y las herramientas que no soportan cierta feature simplemente se omiten de ese benchmark en lugar de penalizarse.

Por qué importa

La mayoría de los devs no toca archivos JSON de 190 MB en la línea de comandos todos los días. Pero hay contextos donde esto sí pesa: pipelines de datos, análisis de logs, procesamiento de respuestas de APIs masivas, flujos CI/CD que manipulan resultados de herramientas como Kubernetes o OpenAPI specs. En esos contextos, pasar de segundos a milisegundos no es cosmético.

Hay también un ángulo más de fondo: este es el mismo enfoque que tomó ripgrep con grep (el proyecto que inspiró explícitamente a jsongrep). Compilar patrones en DFAs antes de buscar no es una idea nueva en teoría de autómatas, pero sigue siendo sorprendentemente poco frecuente en herramientas de línea de comandos cotidianas. El hecho de que jq domine tan ampliamente significa que hay espacio para herramientas especializadas en el subproblema de búsqueda. Para eso existe la presión de reemplazar partes del stack de procesamiento de datos cuando hay suficiente ganancia técnica para justificarlo.

Que venga de un proyecto de investigación universitaria —y no de una empresa— es relevante. El código está bien documentado, los benchmarks son reproducibles, y la arquitectura interna tiene un artículo técnico completo. Eso es más de lo que se puede decir de muchas herramientas que llegan con mucho más ruido.

Para quienes trabajan en Rust: jsongrep también expone su motor DFA como crate de librería, así que se puede integrar búsqueda rápida de JSON directamente en proyectos propios.

Instalación: cargo install jsongrep. El binario se llama jg.


Fuentes

Leer más

Otras noticias