Cómo trabajar con grandes archivos JSON usando PHP

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á).

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a afinar sus habilidades técnicas y avanzar en sus carreras

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.