Mengurangkan Saiz Data JSON

1. Pengenalan

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

Dalam tutorial ini, kita akan melihat pelbagai cara untuk mengurangkan ukuran JSON dalam aplikasi Java kita.

2. Model Domain dan Data Ujian

Mari buat model domain untuk Pelanggan dengan beberapa data hubungan:

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 bahawa semua bidang akan menjadi wajib, kecuali nombor telefon dan e - mel .

Untuk menguji perbezaan ukuran data JSON dengan betul, kami memerlukan sekurang-kurangnya beberapa ratus contoh Pelanggan . Mereka mesti mempunyai data yang berbeza untuk menjadikan ujian kami lebih hidup. Mockaroo laman web penjanaan data membantu kami di sini. Kami boleh membuat 1,000 rekod data JSON di sana secara percuma, dalam format kami sendiri, dan dengan data ujian sahih.

Mari konfigurasikan mockaroo untuk model domain kami:

Di sini, beberapa perkara yang perlu diingat:

  • Di sinilah kami menentukan nama medan
  • Di sini kami memilih jenis data bidang kami
  • 50% nombor telefon kosong dalam data tiruan
  • 30% alamat e-mel juga kosong

Semua contoh kod di bawah menggunakan data yang sama dari 1,000 pelanggan dari mockaroo . Kami menggunakan kaedah kilang Customer.fromMockFile () untuk membaca fail itu dan mengubahnya menjadi objek Pelanggan .

Kami akan menggunakan Jackson sebagai perpustakaan pemprosesan JSON kami.

3. Saiz Data JSON dengan Pilihan Lalai Jackson

Mari tulis objek Java ke JSON dengan pilihan Jackson lalai:

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

Mari lihat data palsu 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]" }

Apabila menggunakan pilihan Jackon lalai, susunan bait data JSON dengan semua 1,000 pelanggan berukuran 181.0 KB .

4. Memampatkan dengan gzip

Sebagai data teks, data JSON memampatkan dengan baik. Itulah sebabnya gzip adalah pilihan pertama kami untuk mengurangkan saiz data JSON. Lebih-lebih lagi, ia dapat diterapkan secara otomatis dalam HTTP, protokol umum untuk mengirim dan menerima JSON.

Mari ambil JSON yang dihasilkan dengan pilihan Jackson lalai dan kompresnya dengan gzip . Ini menghasilkan 45.9 KB, hanya 25.3% dari ukuran asal . Oleh itu, jika kita dapat mengaktifkan pemampatan gzip melalui konfigurasi, kita akan mengurangkan ukuran data JSON sebanyak 75% tanpa perubahan pada kod Java kita!

Sekiranya aplikasi Spring Boot kami memberikan data JSON ke perkhidmatan lain atau front-end, maka kami akan mengaktifkan pemampatan gzip dalam konfigurasi Spring Boot. Mari lihat konfigurasi pemampatan khas 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 pemampatan secara umum dengan menetapkan diaktifkan sebagai benar. Kemudian, kami secara khusus mengaktifkan pemampatan data JSON dengan menambahkan aplikasi / json ke senarai jenis mime . Akhirnya, perhatikan bahawa kami menetapkan ukuran tindak balas min kepada 1.024 bait panjang. Ini kerana jika kita memampatkan jumlah data yang pendek, kita mungkin menghasilkan data yang lebih besar daripada yang asal.

Selalunya, proksi seperti NGINX atau pelayan web seperti Apache HTTP Server menyampaikan data JSON ke perkhidmatan lain atau front-end. Mengkonfigurasi pemampatan data JSON dalam alat ini berada di luar skop tutorial ini.

Tutorial sebelumnya mengenai gzip memberitahu bahawa gzip mempunyai pelbagai tahap pemampatan. Contoh kod kami menggunakan gzip dengan tahap pemampatan Java lalai. Spring Boot, proksi, atau pelayan web mungkin mendapat hasil pemampatan yang berbeza untuk data JSON yang sama.

Sekiranya kita menggunakan JSON sebagai protokol serialisasi untuk menyimpan data, kita perlu memampatkan dan menyahkompres data sendiri.

5. Nama Medan yang lebih pendek di JSON

Merupakan amalan terbaik untuk menggunakan nama bidang yang tidak terlalu pendek atau terlalu panjang. Mari kita hilangkan ini demi demonstrasi: Kami akan menggunakan nama bidang watak tunggal di JSON, tetapi kami tidak akan menukar nama bidang Java. Ini mengurangkan saiz data JSON tetapi menurunkan kebolehbacaan JSON. Oleh kerana ia juga memerlukan kemas kini untuk semua perkhidmatan dan front-end, kami mungkin akan menggunakan nama bidang pendek ini hanya ketika menyimpan 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]" }

Sangat mudah untuk menukar nama medan JSON dengan Jackson sambil meninggalkan nama medan Java utuh. Kami akan menggunakan anotasi @JsonProperty :

@JsonProperty("p") private String postalCode; 

Menggunakan nama bidang aksara tunggal membawa kepada data yang 72.5% dari ukuran asal. Lebih-lebih lagi, menggunakan gzip akan memampatkannya menjadi 23.8%. Itu tidak jauh lebih kecil daripada 25.3% yang kita dapat dengan hanya memampatkan data asal dengan gzip . Kita selalu perlu mencari hubungan kos-manfaat yang sesuai. Kehilangan keterbacaan untuk keuntungan kecil tidak akan disarankan untuk kebanyakan senario.

6. Bersiri ke Array

Mari kita lihat bagaimana kita dapat mengurangkan lagi ukuran data JSON dengan meninggalkan nama bidang sama sekali. Kami dapat mencapainya dengan menyimpan pelbagai pelanggan di JSON kami. Perhatikan bahawa kita juga akan mengurangkan kebolehbacaan. Kami juga perlu mengemas kini semua perkhidmatan dan front-end yang menggunakan data JSON kami:

[ 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.

Pengoptimuman terakhir kami adalah serialisasi array. Dengan menyenaraikan CustomerSlim ke array, kami mencapai hasil terbaik kami: 34.2% dari ukuran asal dan 14.2% dengan gzip . Oleh itu, walaupun tanpa pemampatan, kami membuang hampir dua pertiga daripada data asal. Dan pemampatan mengecilkan data JSON kami kepada hanya sepertiga dari ukuran asal!

9. Kesimpulannya

Dalam artikel ini, pertama kali kita melihat mengapa kita perlu mengurangkan ukuran data JSON. Seterusnya, kami mempelajari pelbagai cara untuk mengurangkan ukuran data JSON ini. Akhirnya, kami belajar bagaimana untuk mengurangkan lagi ukuran data JSON dengan model domain yang disesuaikan untuk satu bahagian depan.

Kod lengkap tersedia, seperti biasa, di GitHub.