Réduction de la taille des données JSON

1. Introduction

Les applications Java utilisent souvent JSON comme format courant pour envoyer et recevoir des données. De plus, il est utilisé comme protocole de sérialisation pour stocker des données. Avec des tailles de données JSON plus petites, nos applications deviennent moins chères et plus rapides.

Dans ce didacticiel, nous examinerons différentes manières de réduire la taille de JSON dans nos applications Java.

2. Modèle de domaine et données de test

Créons un modèle de domaine pour un client avec des données de contact:

public class Customer { private long id; private String firstName; private String lastName; private String street; private String postalCode; private String city; private String state; private String phoneNumber; private String email;

Notez que tous les champs seront obligatoires, à l'exception de phoneNumber et email .

Pour tester correctement les différences de taille de données JSON, nous avons besoin d'au moins quelques centaines d' instances Customer . Ils doivent avoir des données différentes pour rendre nos tests plus réalistes. Le site Web de génération de données mockaroo nous aide ici. Nous pouvons y créer 1000 enregistrements de données JSON gratuitement, dans notre propre format et avec des données de test authentiques.

Configurons mockaroo pour notre modèle de domaine:

Voici quelques éléments à garder à l'esprit:

  • C'est là que nous avons spécifié les noms de champs
  • Ici nous avons sélectionné les types de données de nos champs
  • 50% des numéros de téléphone sont vides dans les données factices
  • 30% des adresses e-mail sont également vides

Tous les exemples de code ci-dessous utilisent les mêmes données de 1000 clients de mockaroo . Nous utilisons la méthode d'usine Customer.fromMockFile () pour lire ce fichier et le transformer en objets Customer .

Nous utiliserons Jackson comme bibliothèque de traitement JSON.

3. Taille des données JSON avec les options par défaut de Jackson

Écrivons un objet Java en JSON avec les options Jackson par défaut:

Customer[] customers = Customer.fromMockFile(); ObjectMapper mapper = new ObjectMapper(); byte[] feedback = mapper.writeValueAsBytes(customers); 

Voyons les données simulées pour le premier client :

{ "id" : 1, "firstName" : "Horatius", "lastName" : "Strognell", "street" : "4848 New Castle Point", "postalCode" : "33432", "city" : "Boca Raton", "state" : "FL", "phoneNumber" : "561-824-9105", "email" : "[email protected]" }

Lorsque vous utilisez les options Jackon par défaut, le tableau d'octets de données JSON avec les 1 000 clients a une taille de 181,0 Ko .

4. Compression avec gzip

En tant que données texte, les données JSON se compressent bien. C'est pourquoi gzip est notre première option pour réduire la taille des données JSON. De plus, il peut être automatiquement appliqué dans HTTP, le protocole commun pour l'envoi et la réception de JSON.

Prenons le JSON produit avec les options Jackson par défaut et compressons-le avec gzip . Cela donne 45,9 Ko, soit 25,3% de la taille d'origine . Donc, si nous pouvons activer la compression gzip via la configuration, nous allons réduire la taille des données JSON de 75% sans aucune modification de notre code Java!

Si notre application Spring Boot fournit les données JSON à d'autres services ou frontaux, nous activerons la compression gzip dans la configuration Spring Boot. Voyons une configuration de compression typique dans la syntaxe YAML:

server: compression: enabled: true mime-types: text/html,text/plain,text/css,application/javascript,application/json min-response-size: 1024 

Tout d'abord, nous avons activé la compression en général en définissant enabled sur true. Ensuite, nous avons spécifiquement activé la compression de données JSON en ajoutant application / json à la liste des types mime . Enfin, notez que nous définissons min-response-size à 1 024 octets de long. En effet, si nous compressons de courtes quantités de données, nous pouvons produire des données plus importantes que l'original.

Souvent, des proxys tels que NGINX ou des serveurs Web tels que Apache HTTP Server fournissent les données JSON à d'autres services ou frontaux. La configuration de la compression de données JSON dans ces outils dépasse le cadre de ce didacticiel.

Un tutoriel précédent sur gzip nous dit que gzip a différents niveaux de compression. Nos exemples de code utilisent gzip avec le niveau de compression Java par défaut. Spring Boot, les proxys ou les serveurs Web peuvent obtenir des résultats de compression différents pour les mêmes données JSON.

Si nous utilisons JSON comme protocole de sérialisation pour stocker les données, nous devrons compresser et décompresser les données nous-mêmes.

5. Noms de champ plus courts dans JSON

Il est recommandé d'utiliser des noms de champ qui ne sont ni trop courts ni trop longs. Omettons ceci pour des raisons de démonstration: nous utiliserons des noms de champs à un seul caractère dans JSON, mais nous ne changerons pas les noms de champs Java. Cela réduit la taille des données JSON mais diminue la lisibilité JSON. Comme cela nécessiterait également des mises à jour de tous les services et frontaux, nous n'utiliserons probablement ces noms de champs courts que lors du stockage des données:

{ "i" : 1, "f" : "Horatius", "l" : "Strognell", "s" : "4848 New Castle Point", "p" : "33432", "c" : "Boca Raton", "a" : "FL", "o" : "561-824-9105", "e" : "[email protected]" }

Il est facile de changer les noms de champs JSON avec Jackson tout en laissant les noms de champs Java intacts. Nous utiliserons l' annotation @JsonProperty :

@JsonProperty("p") private String postalCode; 

L'utilisation de noms de champ à un seul caractère conduit à des données qui représentent 72,5% de la taille d'origine. De plus, l'utilisation de gzip compressera cela à 23,8%. Ce n'est pas beaucoup plus petit que les 25,3% que nous avons obtenus en compressant simplement les données d'origine avec gzip . Nous devons toujours rechercher une relation coût-bénéfice appropriée. Perdre la lisibilité pour un petit gain de taille ne sera pas recommandé pour la plupart des scénarios.

6. Sérialisation vers une baie

Voyons comment nous pouvons réduire davantage la taille des données JSON en omettant complètement les noms de champ. Nous pouvons y parvenir en stockant un tableau de clients dans notre JSON. Notez que nous allons également réduire la lisibilité. Et nous devrons également mettre à jour tous les services et frontaux qui utilisent nos données JSON:

[ 1, "Horatius", "Strognell", "4848 New Castle Point", "33432", "Boca Raton", "FL", "561-824-9105", "[email protected]" ] 

Le stockage du client sous forme de tableau conduit à une sortie correspondant à 53,1% de la taille d'origine et à 22,0% avec la compression gzip . C'est notre meilleur résultat à ce jour. Pourtant, 22% n'est pas beaucoup plus petit que les 25,3% que nous avons obtenus en compressant simplement les données d'origine avec gzip .

Afin de sérialiser un client en tant que tableau, nous devons prendre le contrôle total de la sérialisation JSON. Reportez-vous à nouveau à notre tutoriel Jackson pour plus d'exemples.

7. Exclusion des valeurs nulles

Jackson and other JSON processing libraries may not handle JSON null values correctly when reading or writing JSON. For example, Jackson writes a JSON null value by default when it encounters a Java null value. That's why it's a good practice to remove empty fields in JSON data. This leaves the initialization of empty values to each JSON processing library and reduces the JSON data size.

In our mock data, we set 50% of the phone numbers, and 30% of the email addresses, as empty. Leaving out these null values reduces our JSON data size to 166.8kB or 92.1% of the original data size. Then, gzip compression will drop it to 24.9%.

Now, if we combine ignoring null values with the shorter field names from the previous section, then we'll get more significant savings: 68.3% of the original size and 23.4% with gzip.

We can configure the omission of null value fields in Jackson per class or globally for all classes.

8. New Domain Class

We achieved the smallest JSON data size so far by serializing it to an array. One way of reducing that even further is a new domain model with fewer fields. But why would we do that?

Let's imagine a front-end for our JSON data that shows all customers as a table with two columns: name and street address. Let's write JSON data specifically for this front-end:

{ "id" : 1, "name" : "Horatius Strognell", "address" : "4848 New Castle Point, Boca Raton FL 33432" }

Notice how we concatenated the name fields into name and the address fields into address. Also, we left out email and phoneNumber.

This should produce much smaller JSON data. It also saves the front-end from concatenating the Customer fields. But on the downside, this couples our back-end tightly to the front-end.

Let's create a new domain class CustomerSlim for this front-end:

public class CustomerSlim { private long id; private String name; private String address;

If we convert our test data to this new CustomerSlim domain class, we‘ll reduce it to 46.1% of the original size. That will be using the default Jackson settings. If we use gzip it goes down to 15.1%. This last result is already a significant gain over the previous best result of 22.0%.

Next, if we also use one-character field names, this gets us down to 40.7% of the original size, with gzip further reducing this to 14.7%. This result is only a small gain of over 15.1% we reached with the Jackson default settings.

No fields in CustomerSlim are optional, so leaving out empty values has no effect on the JSON data size.

Notre dernière optimisation est la sérialisation d'un tableau. En sérialisant CustomerSlim dans un tableau, nous obtenons notre meilleur résultat: 34,2% de la taille d'origine et 14,2% avec gzip . Ainsi, même sans compression, nous supprimons près des deux tiers des données d'origine. Et la compression réduit nos données JSON à seulement un septième de la taille d'origine!

9. Conclusion

Dans cet article, nous avons d'abord vu pourquoi nous devons réduire la taille des données JSON. Ensuite, nous avons appris différentes manières de réduire cette taille de données JSON. Enfin, nous avons appris comment réduire davantage la taille des données JSON avec un modèle de domaine personnalisé pour un front-end.

Le code complet est disponible, comme toujours, sur GitHub.