Рубрики
Без рубрики

Уменьшение Размера Данных JSON

В этом уроке мы рассмотрим различные способы уменьшения размера JSON в наших Java-приложениях.

Автор оригинала: Karsten Silz.

1. введение

Java-приложения часто используют JSON в качестве общего формата для отправки и получения данных. Кроме того, он используется в качестве протокола сериализации для хранения данных. С меньшими размерами данных JSON наши приложения становятся дешевле и быстрее.

В этом уроке мы рассмотрим различные способы уменьшения размера JSON в наших Java-приложениях.

2. Модель предметной области и тестовые данные

Давайте создадим модель домена для Клиента с некоторыми контактными данными:

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;

Обратите внимание, что все поля будут обязательными, за исключением номера телефона и электронной почты .

Чтобы правильно проверить различия в размерах данных JSON, нам нужно, по крайней мере, несколько сотен экземпляров Customer . У них должны быть разные данные, чтобы сделать наши тесты более реалистичными. Веб-сайт генерации данных mockaroo помогает нам здесь. Мы можем создать там 1000 записей данных JSON бесплатно, в нашем собственном формате и с аутентичными тестовыми данными.

Давайте настроим mockaroo для нашей модели домена:

Вот некоторые пункты, которые следует иметь в виду:

  • Здесь мы указали имена полей
  • Здесь мы выбрали типы данных наших полей
  • 50% телефонных номеров пусты в фиктивных данных
  • 30% адресов электронной почты тоже пусты

Во всех приведенных ниже примерах кода используются одни и те же данные 1000 клиентов из mockaroo . Мы используем фабричный метод Customer.fromMockFile () , чтобы прочитать этот файл и превратить его в объекты Customer .

Мы будем использовать Джексона в качестве нашей библиотеки обработки JSON.

3. Размер данных JSON с параметрами Джексона по умолчанию

Давайте напишем объект Java в JSON с параметрами Джексона по умолчанию:

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

Давайте посмотрим макет данных для первого Клиента :

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

При использовании параметров Джексона по умолчанию размер массива байтов данных JSON со всеми 1000 клиентами составляет 181,0 КБ .

4. Сжатие с помощью gzip

В виде текстовых данных данные JSON хорошо сжимаются. Вот почему gzip – это наш первый вариант для уменьшения размера данных JSON. Кроме того, он может быть автоматически применен в HTTP, общем протоколе для отправки и получения JSON.

Давайте возьмем JSON, созданный с параметрами Джексона по умолчанию, и сожмем его с помощью gzip . Это приводит к 45,9 КБ, что составляет всего 25,3% от исходного размера . Поэтому, если мы сможем включить сжатие gzip через конфигурацию, мы сократим размер данных JSON на 75% без каких-либо изменений в нашем Java-коде!

Если наше приложение Spring Boot доставляет данные JSON в другие службы или интерфейсы, мы включим сжатие gzip в конфигурации Spring Boot. Давайте рассмотрим типичную конфигурацию сжатия в синтаксисе YAML:

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

Во-первых, мы включили сжатие в целом, установив enabled как true. Затем мы специально включили сжатие данных JSON, добавив application/json в список mime-типов . Наконец, обратите внимание, что мы установили min-response-size длиной 1024 байта. Это связано с тем, что если мы сжимаем короткие объемы данных, мы можем получить больше данных, чем исходные.

Часто прокси-серверы, такие как NGINX или веб-серверы, такие как HTTP-сервер Apache , доставляют данные JSON другим службам или интерфейсам. Настройка сжатия данных JSON в этих инструментах выходит за рамки данного руководства.

Предыдущий учебник по gzip говорит нам, что gzip имеет различные уровни сжатия. В наших примерах кода используется gzip с уровнем сжатия Java по умолчанию. Spring Boot, прокси-серверы или веб-серверы могут получать разные результаты сжатия для одних и тех же данных JSON.

Если мы используем JSON в качестве протокола сериализации для хранения данных, нам нужно будет сжимать и распаковывать данные самостоятельно.

5. Более короткие имена полей в JSON

Рекомендуется использовать имена полей, которые не являются ни слишком короткими, ни слишком длинными. Давайте опустим это ради демонстрации: мы будем использовать односимвольные имена полей в JSON, но мы не будем изменять имена полей Java. Это уменьшает размер данных JSON, но снижает читаемость JSON. Поскольку это также потребует обновления всех служб и интерфейсов, мы, вероятно, будем использовать эти короткие имена полей только при хранении данных:

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

Легко изменить имена полей JSON с помощью Jackson, оставив имена полей Java нетронутыми. Мы будем использовать аннотацию @JsonProperty :

@JsonProperty("p")
private String postalCode;

Использование односимвольных имен полей приводит к тому, что размер данных составляет 72,5% от исходного размера. Более того, использование gzip приведет к сжатию до 23,8%. Это не намного меньше, чем 25,3%, которые мы получили от простого сжатия исходных данных с помощью gzip . Нам всегда нужно искать подходящее соотношение затрат и выгод. Потеря удобочитаемости при небольшом увеличении размера не рекомендуется для большинства сценариев.

6. Сериализация в массив

Давайте посмотрим, как мы можем еще больше уменьшить размер данных JSON, полностью исключив имена полей. Мы можем достичь этого, сохранив массив customers в нашем JSON. Обратите внимание, что мы также уменьшим читабельность. И нам также нужно будет обновить все службы и интерфейсы, которые используют наши данные JSON:

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

Хранение Customer в виде массива приводит к выходу, который составляет 53,1% от исходного размера и 22,0% с gzip сжатием. Это наш лучший результат на данный момент. Тем не менее, 22% не намного меньше, чем 25,3%, которые мы получили, просто сжав исходные данные с помощью gzip .

Чтобы сериализовать клиента в виде массива, нам нужно полностью контролировать сериализацию JSON. Обратитесь еще раз к нашему учебнику по Джексону для получения дополнительных примеров.

7. Исключение нулевых Значений

Джексон и другие библиотеки обработки JSON могут неправильно обрабатывать значения JSON null при чтении или записи JSON. Например, Джексон записывает значение JSON null по умолчанию, когда он встречает значение Java null . Вот почему рекомендуется удалять пустые поля в данных JSON . Это оставляет инициализацию пустых значений для каждой библиотеки обработки JSON и уменьшает размер данных JSON.

В наших фиктивных данных мы установили 50% телефонных номеров и 30% адресов электронной почты как пустые. Исключение этих значений null уменьшает размер данных JSON до 166,8 Кб, или 92,1% от исходного размера данных. Затем сжатие gzip снизит его до 24,9%.

Теперь, если мы объединим игнорирование значений null с более короткими именами полей из предыдущего раздела, мы получим более значительную экономию: 68,3% от исходного размера и 23,4% с gzip .

Мы можем настроить пропуск полей null value в Джексоне для каждого класса или глобально для всех классов .

8. Новый Класс Домена

До сих пор мы достигли наименьшего размера данных JSON, сериализовав их в массив. Один из способов уменьшить это еще больше-это новая модель домена с меньшим количеством полей. Но зачем нам это делать?

Давайте представим себе интерфейс для наших данных JSON, который показывает всех клиентов в виде таблицы с двумя столбцами: имя и адрес. Давайте напишем данные JSON специально для этого интерфейса:

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

Обратите внимание, как мы объединили поля имени в имя и поля адреса в адрес . Кроме того, мы не указали адрес электронной почты и номер телефона .

Это должно привести к гораздо меньшему объему данных JSON. Это также избавляет интерфейс от объединения полей Customer . Но с другой стороны, это плотно связывает наш задний конец с передним .

Давайте создадим новый доменный класс Customer Slim для этого интерфейса:

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

Если мы преобразуем наши тестовые данные в этот новый класс Customer Slim domain, мы уменьшим его до 46,1% от исходного размера. Это будет с использованием настроек Джексона по умолчанию. Если мы используем gzip , он снизится до 15,1%. Этот последний результат уже является значительным приростом по сравнению с предыдущим лучшим результатом в 22,0%.

Далее, если мы также используем односимвольные имена полей, это уменьшит наш размер до 40,7% от исходного размера, а gzip дополнительно уменьшит его до 14,7%. Этот результат-лишь небольшой прирост более чем на 15,1%, которого мы достигли с настройками Джексона по умолчанию.

Никакие поля в Customer Slim не являются необязательными, поэтому исключение пустых значений не влияет на размер данных JSON.

Наша последняя оптимизация-это сериализация массива. Сериализуя Customer Slim в массив, мы достигаем наилучшего результата: 34,2% от исходного размера и 14,2% с помощью gzip . Таким образом, даже без сжатия мы удаляем почти две трети исходных данных. А сжатие сокращает наши данные JSON всего до одной седьмой от исходного размера!

9. Заключение

В этой статье мы впервые увидели, почему нам нужно уменьшить размеры данных JSON. Затем мы изучили различные способы уменьшения размера данных JSON. Наконец, мы узнали, как еще больше уменьшить размер данных JSON с помощью модели домена, настроенной на один интерфейс.

Полный код доступен, как всегда, на GitHub .