Traitement de gros fichiers JSON en PHP

j'essaie de traiter de gros fichiers JSON (JUSQU'à 200M). La structure du fichier est essentiellement un tableau d'objets.

Si quelque chose le long des lignes de:

[
  {"property":"value", "property2":"value2"},
  {"prop":"val"},
  ...
  {"foo":"bar"}
]

chaque objet a des propriétés arbitraires et ne les partage pas nécessairement avec d'autres objets dans le tableau (comme dans, ayant le même).

je veux appliquer un traitement sur chaque objet du tableau et que le fichier est potentiellement énorme, Je ne peux pas slurp le contenu du fichier entier en mémoire, décodant le JSON et itérant sur le tableau PHP.

Donc, idéalement, je voudrais lire le fichier, extraire suffisamment d'informations pour chaque objet et chaque processus. Une approche de type SAX serait acceptable s'il y avait une bibliothèque similaire disponible pour JSON.

une suggestion sur la meilleure façon de traiter ce problème?

19
demandé sur The Mighty Rubber Duck 2010-10-29 10:10:35

5 réponses

j'ai décidé de travailler sur un analyseur d'événements. Ce n'est pas encore tout à fait fait et je vais éditer la question avec un lien vers mon travail lorsque je lance une version satisfaisante.

EDIT:

j'ai finalement élaboré une version de l'analyseur qui me satisfait. Il est disponible sur GitHub:

https://github.com/kuma-giyomu/JSONParser

il y a probablement une marge d'amélioration et reçois des commentaires.

14
répondu The Mighty Rubber Duck 2012-04-07 03:13:15

j'ai écrit un streaming JSON pull parser pcrov/JsonReader pour PHP 7 avec une api basée sur XMLReader .

il diffère significativement des analyseurs basés sur des événements en ce qu'au lieu de configurer des callbacks et de laisser l'analyseur faire son truc, vous appelez des méthodes sur l'analyseur pour vous déplacer ou récupérer des données comme désiré. Vous avez trouvé vos morceaux désirés et vous voulez arrêter de parser? Alors arrêtez de Parser (et appelez close() parce que c'est la bonne chose à faire.)

(pour un aperçu un peu plus long de la fonction pull vs event-based parsers, voir XML reader models: SAX versus XML pull parser .)


exemple 1:

lisez chaque objet en entier de votre JSON.

use pcrov\JsonReader\JsonReader;

$reader = new JsonReader();
$reader->open("data.json");

$reader->read(); // Outer array.
$depth = $reader->depth(); // Check in a moment to break when the array is done.
$reader->read(); // Step to the first object.
do {
    print_r($reader->value()); // Do your thing.
} while ($reader->next() && $reader->depth() > $depth); // Read each sibling.

$reader->close();

sortie:

Array
(
    [property] => value
    [property2] => value2
)
Array
(
    [prop] => val
)
Array
(
    [foo] => bar
)

les objets sont retournés comme les matrices stringly-keyed dues (en partie) à edge les cas où JSON valide produirait des noms de propriétés qui ne sont pas autorisés dans les objets PHP. Travailler autour de ces conflits n'en vaut pas la peine car un objet stdClass anémique n'apporte aucune valeur sur un simple tableau de toute façon.


exemple 2:

lire chaque élément nommé individuellement.

$reader = new pcrov\JsonReader\JsonReader();
$reader->open("data.json");

while ($reader->read()) {
    $name = $reader->name();
    if ($name !== null) {
        echo "$name: {$reader->value()}\n";
    }
}

$reader->close();

sortie:

property: value
property2: value2
prop: val
foo: bar

exemple 3:

lire chaque propriété d'un prénom. Bonus: lire à partir d'une chaîne de caractères au lieu d'un URI, plus obtenir des données à partir de propriétés avec des noms dupliqués dans le même objet (ce qui est autorisé dans JSON, comme c'est amusant.)

$json = <<<'JSON'
[
    {"property":"value", "property2":"value2"},
    {"foo":"foo", "foo":"bar"},
    {"prop":"val"},
    {"foo":"baz"},
    {"foo":"quux"}
]
JSON;

$reader = new pcrov\JsonReader\JsonReader();
$reader->json($json);

while ($reader->read("foo")) {
    echo "{$reader->name()}: {$reader->value()}\n";
}

$reader->close();

sortie:

foo: foo
foo: bar
foo: baz
foo: quux

la meilleure façon de lire votre JSON dépend de sa structure et de ce que vous voulez en faire. Ces exemples devraient vous donner endroit pour commencer.

14
répondu Paul Crovella 2016-09-28 18:11:02

Il existe quelque chose comme cela, mais seulement pour C++ et Java . Sauf si vous pouvez accéder à L'une de ces bibliothèques à partir de PHP, il n'y a pas d'implémentation pour cela dans PHP mais json_read() autant que je sache. Cependant, si le json est structuré aussi simple, il est facile de simplement lire le fichier jusqu'à la prochaine } et puis traiter le JSON reçu via json_read() . Mais vous devriez faire mieux que tamponné, comme la lecture 10kb, divisé par}, si pas trouvé, lire un autre 10k, et traiter les valeurs trouvées. Puis lire le bloc suivant et ainsi de suite..

2
répondu joni 2010-10-29 06:20:41

il s'agit d'un analyseur simple en continu pour le traitement de gros documents JSON. Utilisez-le pour analyser de très grands documents JSON pour éviter de charger toute la chose dans la mémoire, ce qui est à peu près tous les autres JSON parser pour PHP fonctionne.

https://github.com/salsify/jsonstreamingparser

2
répondu Aaron Averill 2015-03-14 03:15:47

il y a http://github.com/sfalvo/php-yajl / Je ne l'ai pas utilisé moi-même.

0
répondu Alex Jasmin 2010-10-29 06:15:13