Recorrer un archivo json es algo sencillo, ¿cierto? Pues parece que cuando el tamaño del archivo es grande las cosas ya no son tan simples…
Lo que se haría típicamente sería algo similar a:
<?php $json = json_decode( file_get_contents( $argv[1] ), true ); print_r( $json );
El problema aquí es que se requiere primero leer todo el archivo para, recién entonces empezar a procesar…
Tomemos un ejemplo como el árbol de categorías de MercadoLibre Brasil. Este archivo pesa 229 MB (Una vez descomprimido).
229 MB de puro json… es bastante, sí, pero… ¿es mucho?
La respuesta en definitiva depende la configuración que tengas en tu php.ini.
A efectos de este análisis hice un cambio al mío de modo que quede así:
; Maximum amount of memory a script may consume (128MB) ; http://php.net/memory-limit memory_limit = 128
128 MB no es algo inusual para una instalación de PHP (Al día de hoy, es el valor por defecto), con lo cual, estaremos en un problema al tratar de leer un archivo de más de 200…
Aumentar la memoria disponible
Una solución posible es darle más holgura a nuestro intérprete (En este caso, dejarle ocupar más memoria).
Podemos hacerlo cambiando la configuración a algo como:
; Maximum amount of memory a script may consume (128MB) ; http://php.net/memory-limit memory_limit = 256
Pero eso es, como decimos en mi país, «Pan para hoy, hambre para mañana».
Si elegimos esta ruta (y queremos asegurarnos de estar bien cubiertos), lo ideal sería hacer esto:
; Maximum amount of memory a script may consume (128MB) ; http://php.net/memory-limit memory_limit = -1
Y ahí el limitante que tendremos será la memoria física de la computadora… algo drástico para mi gusto y, más aún, poco practicable.
El problema es que no siempre tenemos acceso a la configuración de php (como por ejemplo, en un hosting compartido).
Aún si lo tuviéramos, tengo dudas sobre la posibilidad de alterar un setting tan sensible como este, ya que al aprovecharnos de los recursos de una forma tan poco medida estaríamos muy probablemente afectando a nuestros vecinos.
Mejorar el modo de procesar JSON
Otra forma de resolver el problema es cambiar la librería que usamos para procesar JSON.
Existen varias alternativas pero en este artículo quiero mostrarte JsonReader (Una extensión de PHP).
Una vez instalada, es bastante fácil de usar. Veamos un ejemplo de cómo obtener todos los nombres de los artículos del archivo que te mostraba antes:
<?php require 'vendor/autoload.php'; use pcrov\JsonReader\JsonReader; $reader = new JsonReader(); $reader->open( $argv[1] ); while ($reader->read("name")) { echo $reader->value(), "\n"; } $reader->close();
Al usar el comando
php process.php categoriesMLB
Obtenemos una salida como:
Acessórios de Carros Acessórios para Veículos Acessórios de Carros Exterior Interior Comércio Agro, Indústria e Comércio Comércio Contêineres Marítimos Insumos Máquinas Móveis Outros Acessórios para Veículos Acessórios para Veículos Acessórios de Carros Acessórios de Motos Acessórios Náutica Ferramentas GPS Limpeza Automotiva
Que continúa por unas 1218885 líneas
Reducir el problema
Por último, no podemos dejar de lado la solución de «pensamiento lateral» (Que suele ser la mejor :)): re-definir el problema en términos más simples.
Se trata de hacernos la pregunta: ¿Realmente necesitamos ese archivo? ¿No podríamos trabajar con uno más pequeño?
Claramente, la respuesta dependerá del contexto más que de cuestiones de tecnología, pero no estaría completo el artículo si no lo mencionara.
(Si preferís resolver el problema intentando reducir el tamaño del archivo, este artículo puede ser de tu interés).
Algunas notas finales
Es importante distinguir entre la necesidad de procesar un archivo tan grande en forma online (Es decir, mientras estamos generando una respuesta para un visitante al sitio) y offline (En un cronjob en la mitad de la noche por ejemplo).
Claramente, esta herramienta va bien para el segundo caso (Para el primero te diría que si estás con esa necesidad tendrías que re-pensar algo…).
Por último, no puedo dejar de agradecer a mis amigos y colegas Alejandro Chapiro y Eric Danan por la inspiración para escribir este texto (Y la discusión sobre soluciones que te mostré acá).
- Cómo usar PHPUnit - 03/12/2024
- ¿Cómo instalar extensiones PHP en Docker? - 26/11/2024
- Cómo agregar una página de error 500 en un proyecto PHP - 31/10/2024