Mengurangi Ukuran Data JSON

1. Perkenalan

Aplikasi Java sering menggunakan JSON sebagai format umum untuk mengirim dan menerima data. Selain itu, ini digunakan sebagai protokol serialisasi untuk menyimpan data. Dengan ukuran data JSON yang lebih kecil, aplikasi kami menjadi lebih murah dan lebih cepat.

Dalam tutorial ini, kita akan melihat berbagai cara mengurangi ukuran JSON di aplikasi Java kita.

2. Model Domain dan Data Uji

Mari buat model domain untuk Pelanggan dengan beberapa data kontak:

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;

Perhatikan bahwa semua bidang harus diisi, kecuali untuk nomor telepon dan email .

Untuk menguji perbedaan ukuran data JSON dengan benar, kami memerlukan setidaknya beberapa ratus instance Pelanggan . Mereka harus memiliki data yang berbeda untuk membuat pengujian kami lebih nyata. Situs web pembuatan data mockaroo membantu kami di sini. Kami dapat membuat 1.000 catatan data JSON di sana secara gratis, dalam format kami sendiri, dan dengan data pengujian otentik.

Mari konfigurasikan mockaroo untuk model domain kita:

Berikut, beberapa hal yang perlu diperhatikan:

  • Di sinilah kami menentukan nama bidang
  • Di sini kami memilih tipe data bidang kami
  • 50% dari nomor telepon kosong dalam data tiruan
  • 30% dari alamat email juga kosong

Semua contoh kode di bawah ini menggunakan data yang sama dari 1.000 pelanggan dari mockaroo . Kami menggunakan metode pabrik Customer.fromMockFile () untuk membaca file itu dan mengubahnya menjadi objek Pelanggan .

Kami akan menggunakan Jackson sebagai perpustakaan pemrosesan JSON kami.

3. Ukuran Data JSON dengan Jackson Default Options

Mari tulis objek Java ke JSON dengan opsi Jackson default:

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

Mari kita lihat data tiruan untuk Pelanggan pertama :

{ "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]" }

Saat menggunakan opsi Jackon default, array byte data JSON dengan semua 1.000 pelanggan berukuran 181,0 KB .

4. Mengompresi dengan gzip

Sebagai data teks, data JSON terkompresi dengan baik. Itulah mengapa gzip adalah opsi pertama kami untuk mengurangi ukuran data JSON. Selain itu, dapat diterapkan secara otomatis dalam HTTP, protokol umum untuk mengirim dan menerima JSON.

Mari kita ambil JSON yang diproduksi dengan opsi Jackson default dan kompres dengan gzip . Ini menghasilkan 45,9 KB, hanya 25,3% dari ukuran aslinya . Jadi, jika kami dapat mengaktifkan kompresi gzip melalui konfigurasi, kami akan mengurangi ukuran data JSON hingga 75% tanpa mengubah kode Java kami!

Jika aplikasi Spring Boot kami mengirimkan data JSON ke layanan lain atau front-end, maka kami akan mengaktifkan kompresi gzip di konfigurasi Spring Boot. Mari kita lihat konfigurasi kompresi tipikal dalam sintaks YAML:

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

Pertama, kami mengaktifkan kompresi secara umum dengan menyetel diaktifkan sebagai true. Kemudian, kami secara khusus mengaktifkan kompresi data JSON dengan menambahkan application / json ke daftar tipe mime . Terakhir, perhatikan bahwa kami menetapkan ukuran respons-min menjadi 1.024 byte. Ini karena jika kami mengompresi data dalam jumlah singkat, kami dapat menghasilkan data yang lebih besar dari aslinya.

Seringkali, proxy seperti NGINX atau server web seperti Apache HTTP Server mengirimkan data JSON ke layanan lain atau front-end. Mengonfigurasi kompresi data JSON dalam alat ini berada di luar cakupan tutorial ini.

Tutorial sebelumnya tentang gzip memberi tahu kita bahwa gzip memiliki berbagai tingkat kompresi. Contoh kode kami menggunakan gzip dengan tingkat kompresi Java default. Spring Boot, proxy, atau server web mungkin mendapatkan hasil kompresi yang berbeda untuk data JSON yang sama.

Jika kita menggunakan JSON sebagai protokol serialisasi untuk menyimpan data, kita perlu mengompres dan mendekompresi data itu sendiri.

5. Nama Field Lebih Pendek di JSON

It's a best practice to use field names that are neither too short nor too long. Let's omit this for the sake of demonstration: We'll use single-character field names in JSON, but we'll not change the Java field names. This reduces the JSON data size but lowers JSON readability. Since it would also require updates to all services and front-ends, we'll probably use these short field names only when storing data:

{ "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]" }

It's easy to change the JSON field names with Jackson while leaving the Java field names intact. We'll use the @JsonProperty annotation:

@JsonProperty("p") private String postalCode; 

Using single-character field names leads to data that is 72.5% of the original size. Moreover, using gzip will compress that to 23.8%. That's not much smaller than the 25.3% we got from simply compressing the original data with gzip. We always need to look for a suitable cost-benefit relation. Losing readability for a small gain in size won't be recommendable for most scenarios.

6. Serializing to an Array

Let's see how we can further reduce the JSON data size by leaving out the field names altogether. We can achieve this by storing a customers array in our JSON. Notice that we'll be also reducing readability. And we'll also need to update all the services and front-ends that use our JSON data:

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

Storing the Customer as an array leads to output that's 53.1% of the original size, and 22.0% with gzip compression. This is our best result so far. Still, 22% is not significantly smaller than the 25.3% we got from merely compressing the original data with gzip.

In order to serialize a customer as an array, we need to take full control of JSON serialization. Refer again to our Jackson tutorial for more examples.

7. Excluding null Values

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.

Optimasi terakhir kami adalah serialisasi array. Dengan membuat serial CustomerSlim ke sebuah array, kami mencapai hasil terbaik kami: 34,2% dari ukuran asli dan 14,2% dengan gzip . Jadi, meskipun tanpa kompresi, kami menghapus hampir dua pertiga dari data asli. Dan kompresi menyusutkan data JSON kami menjadi hanya sepertujuh dari ukuran aslinya!

9. Kesimpulan

Dalam artikel ini, pertama-tama kita melihat mengapa kita perlu mengurangi ukuran data JSON. Selanjutnya, kami mempelajari berbagai cara untuk mengurangi ukuran data JSON ini. Terakhir, kami mempelajari cara mengurangi ukuran data JSON lebih lanjut dengan model domain yang disesuaikan untuk satu front-end.

Kode lengkap tersedia, seperti biasa, di GitHub.