Gérez d'énormes JSON avec Java Lambda

J'ai écrit un article qui fait d'InputStream une entrée pour Lambda.

J'ai essayé le type d'entrée / sortie de Java Lambda ~ Stream version ~ https://qiita.com/kazfuku/items/6f0f55ffa3a88d76cfaa

L'avantage d'utiliser InputStream est qu'il peut gérer d'énormes JSON. Alors, j'ai essayé de vérifier ce que c'était réellement.

données de test

Tout d'abord, j'ai préparé un énorme JSON. Les données contiennent 6000 objets avec le nom et le texte, soit environ 5,9 Mo, ce qui est proche de la limite de taille d'entrée de Lambda de 6 Mo.

{
  "data":[
    {
      "name":"vrZPwIw3T7","text":"Ku7aQqW3WzUeiRdXnNB26iVElWdOUj8mQhvHksvN1sMmQ2fT3M8navvbTJuspda2q0bY3FWvsDoguE33tTNtoxuiHjdkUIHmylIezYGitmhJ2bbgcHhcHPzGr4eg3Ger9EijFU82Sq4WS9G5UVW62Cw1rDMNdIld2yxn1Zd3DXqE26iOf1IaBQTzEG7Pld03hkXIkAdTdeAjXlAJlGrwnQgjMh1FohW1bUAYeaLi52qLnbgQd7lZAJuOlitfGUyUbP0BjbsPflOLGQwInPjr2Mt3mG4HDokWj2JJgRkXkRYxq34AxQGNWXjlfWKViDxk2InIP6oMsir5YmTL1oO58dzmBGCoYV7e0PTGQHXJbgPJUFUoCmv3mATCEg1xhOa4IUcP7vC7dMvydS3Qt1QHteYajeCvXiW0HjuHkm2oJ61yEg6JocqLVMQ75RaU0Wjb2KvbAwQmggSel5E6mMl0BacZwBXw7OaYHkHO1p1hQup2hhNkaAkN7B8NS8QJ3oSRPQsM6QsETC3x1ErrN0jZZVqupjDvPEr9xj0fDOpqCo7XqTuSPbf3UhHQgjPyikbc2JaqeMdJf1R0RojlqWmf2STGH8HTuGJTQG3vEP04BkrNLaKNVoXE49tPyePO6EqRAKWNxVZoQmw34Xv6yGzMfOLPcSRhML0rYk1FEaBDmgGNpQIPdYjbT3MC08eEY9cHa813iWvm42XmG5LaiIt2z4IcGaWnLwCRytYJJsdqphSEhyvyOpIKM4i02t9rx3Pkt0704EhFo3SD8gVVIE2y1coFUJqy2GxVqptZrKpFv56c4SsWSPqdLqTH9Gh09Y5Cph6eOKg0JXvip1GoONZ80oBUeRudMvsl32m23fYZlG1dNFnGUZSkz2TiGP9baIfLyPWCcPZGEvVaP9FR64FW0yOLvpKyTNYXg21ZsgEkYo3tbcn3AS5R3Ai4eg5hYMaBoVAsMBK1BPZAncDoqOs97nLa2DZFyqgNSz8Asgmh"
    },
    {
      "name":"OXJIXTP9dz","text":"HkWP0PumYHQZxiGNhGWASXOPrygri7cKXs2hrWx0WaumM8OEVc9UKs2EIknzCsBmAMFRER5YNIUs5oz30LjDrjn1PsoKuh60KPOEaHnBNTt8PivYx0hIfmLoLk56ad6LSLNpUVMCP26WiPyont6OjfD1c4sxtKn3qlg6SaNSs2B1tGoReVb3pwOVvPH2BaULL5rzYyDFfAqFqo4D2UevrdoUOeXK3Ks3tav92wHnECM9pbXdsCbWyr1BNulJ5elcZm8HALPgBeX9dg0vaqpgITfz3klyYIWynzPOJC92t0vMao2tL7lr6uxuQvldWgdhlzGjYP123pdWb2h0zItg8NyyK58tCKy2t2YqtdP23fvmVpmOFygiM6kF9LvDRfnu3mz0X2SvcsQh8UqB84dHiOXwicmnI6DX47OuPXOUZc0wICql8zit6WvbEmDchKy9M74u9mPaiIxGXBy8FvLEptqqGytywwC3GGYXEpLYZlbxDycrSTtCq6PUuWoUbfsJmZT4iZSvM0aoyVKBE2l23oXhFZpM4fxyyziIVAHP9YsQbHQlvr8adtD3voumsGKcklt4mnNQclQdSLKPKSIGdUlkvhcCO4MZcEpKcmSrFU6naOYGL1geB1CuTYHYuw0x6tc7JudQAEB6IWE8xwTgPWQUM15xTsqsLrBIwZ70MGpCGW8JCw6sqJExsXi6wpJ1I3L43TUG4hJOnEPIHeXTco06zaDiSrqG3LsLuCiHIkqYui1N0fJBRJhVcn2X8dXMnQKxqhISGrnP7TeBBcAhI8qrmNK0k9EV6mECQtN2g8qaRYVqwOqC4kwzMpvPWkUnNQuUZbknLlWOKuVeh0mrjTzIxQkMShqhdt21o75h9rz0DPxvNHkS6jLw7TBprYieZwcO8iIRy1zYFedSXyVktczdEczIebkfDFmjGtDeZw5RuuFUYKDk4U3J5lpmfmf9K3G6LuPeV5soPxL54l8ZxlJGNpP1kZftZeadtms7"
    },
...

Essayez avec la méthode Map

Tout d'abord, il s'agit d'une implémentation de la méthode Map, et le nombre de données est compté.

Quelle est la méthode Map? -> J'ai essayé le type d'entrée / sortie de Java Lambda ~ Map edition ~

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Collections;
import java.util.List;
import java.util.Map;

public class MapHugeJsonFunction implements RequestHandler<Map<String, Object>, Map<String, Object>> {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public Map<String, Object> handleRequest(Map<String, Object> event, Context context) {
        List<Map<String, Object>> data = (List<Map<String, Object>>) event.get("data");
        int count = data.size();

        return Collections.singletonMap("count", count);
    }
}

Résultat d'exécution (≠ Cold Start)

REPORT RequestId: ac45a98c-be93-49b5-8813-c30ae7d731c9	Duration: 2030.51 ms	Billed Duration: 2100 ms	Memory Size: 128 MB	Max Memory Used: 118 MB

Nous utilisons 118 Mo, ce qui est proche de la mémoire maximale. Il s'agit de l'état dans lequel tout le JSON est en mémoire lorsque la carte à passer au handlerRequest est générée. Si vous ajoutez une logique métier à cela, 128 Mo ne seront pas assez de mémoire.

Essayez avec la méthode Stream

J'ai essayé le même processus avec la méthode Stream. Avec cette implémentation, vous pouvez traiter tout le JSON sans le mettre en mémoire.

L'API Jackson Streaming (https://github.com/FasterXML/jackson-databind#5-minute-tutorial-streaming-parser-generator) est utilisée pour l'analyse JSON. En XML, c'est la même idée que d'utiliser SAX Parser.

Qu'est-ce que la méthode Stream? -> J'ai essayé le type d'entrée / sortie de Java Lambda ~ Stream version ~

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Map;

public class StreamHugeJsonFunction implements RequestStreamHandler {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        JsonParser parser = OBJECT_MAPPER.createParser(inputStream);

        int count = 0;
        boolean inData = false;
        boolean inDataArray = false;
        JsonToken token;
        while((token = parser.nextToken()) != null) {
            if ("FIELD_NAME".equals(token.name()) && "data".equals(parser.getCurrentName())) {
                inData = true;
            }
            if (inData && "START_ARRAY".equals(token.name())) {
                inDataArray = true;
            }
            if (inDataArray && "END_ARRAY".equals(token.name())) {
                inDataArray = false;
            }
            if (inData && "END_OBJECT".equals(token.name())) {
                inData = false;
            }
            if (inDataArray && "START_OBJECT".equals(token.name())) {
                count++;
            }
        }

        Map<String, Integer> response = Collections.singletonMap("count", count);
        OBJECT_MAPPER.writeValue(outputStream, response);
    }
}

Résultat d'exécution (≠ Cold Start)

REPORT RequestId: 41f93e2e-e1db-4775-b296-8b280d2696f9	Duration: 871.01 ms	Billed Duration: 900 ms	Memory Size: 128 MB	Max Memory Used: 80 MB

Mémoire améliorée à 118 Mo-> 80 Mo. Le temps de traitement a également été amélioré à 2030 ms-> 871 ms.

Résumé

Pour les processus qui sont fastidieux à analyser JSON mais ne nécessitent pas toutes les données JSON, la méthode Stream est susceptible d'économiser du temps de traitement et de la mémoire.

Recommended Posts

Gérez d'énormes JSON avec Java Lambda
Lire JSON en Java
POST JSON en Java
Créer JSON en Java
Entraînez-vous à travailler avec des paires de substitution Unicode en Java
Utiliser des couches Lambda avec Java
[Java] Communication JSON avec jackson
Résolution du problème lorsque Azure Functions a cessé de fonctionner en Java
POST Json en Java ~ HttpURLConnection ~
Sérialisation / désérialisation Json dans Java 1.4
Agrégation et analyse de journaux (utilisation d'AWS Athena en Java)
Créer un SlackBot avec AWS lambda et API Gateway en Java
Expression lambda Java apprise avec Comparator
Tweak Markdown avec Java flexmark-java
Implémenter l'autorisation API Gateway Lambda dans Java Lambda
Méthode de concurrence en Java avec exemple de base
Essayez d'utiliser l'API au format JSON en Java
Lire le fichier xlsx en Java avec Selenium
Diviser une chaîne avec ". (Dot)" en Java
J'ai écrit une fonction Lambda en Java et l'ai déployée avec SAM
Je veux ForEach un tableau avec une expression Lambda en Java
Interagir avec l'API de message LINE à l'aide de Lambda (Java)
Lire une chaîne dans un fichier PDF avec Java
Créer un CSR avec des informations étendues en Java
Outil GUI refactorisé réalisé avec Java8 + JavaFX en 2016
Partition en Java
Analyse de code statique par Checkstyle avec Java + Gradle
Code pour échapper aux chaînes JSON en Java
Changements dans Java 11
Comment utiliser le framework Java avec AWS Lambda! ??
La solution pour NetBeans 8.2 ne fonctionne pas dans l'environnement Java 9
JSON avec Java et Jackson Part 2 XSS mesures
Janken à Java
Extraction de texte en Java à partir de PDF avec pdfbox-2.0.8
Comment utiliser l'API Java avec des expressions lambda
Différé avec JSON
Bonjour Java Lambda
[Java] Expression Lambda
[JAVA] [Spring] [MyBatis] Utiliser IN () avec SQL Builder
Taux circonférentiel à Java
Crypter / décrypter avec AES256 en PHP et Java
Expression lambda Java
FizzBuzz en Java
Gérez le cross-domain JSON avec Play Framework
Programmation utilisant le type de somme directe en Java (news)
S'entendre avec les conteneurs Java dans Cloud Run
Code à utiliser lorsque vous souhaitez traiter Json en Java avec uniquement des bibliothèques standard
Convertir JSON et YAML en Java (en utilisant Jackson et SnakeYAML)
Comment déployer Java sur AWS Lambda avec Serverless Framework
Inclure l'image dans le fichier jar avec la méthode statique java
Remarquez un problème multi-thread lorsque vous travaillez avec Java Servlet
Implémentez rapidement singleton avec enum en Java
Sortie true avec if (a == 1 && a == 2 && a == 3) en Java (identifiant invisible)
Premiers pas avec les anciens ingénieurs Java (Stream + Lambda)
Vérifiez la couverture avec Codecov dans la configuration Java + Gradle + Wercker
Installez java avec Homebrew
Implémentation de l'interpréteur par Java
Faites un blackjack avec Java
Application Janken en Java