Geobuf формат

Geobuf представляет собой бинарный формат сериализации геоданных, построенный поверх Protocol Buffers, предназначенный для компактного хранения и передачи структур GeoJSON. Его ключевая задача — уменьшить размер геоданных при сохранении логической структуры GeoJSON, которая широко используется в веб-картографии и, в частности, в связке с Mapbox GL JS.

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


Принцип работы и структура кодирования

Geobuf преобразует объекты GeoJSON в бинарное представление с использованием схемы Protocol Buffers. В основе лежит идея сжатия повторяющихся структур и числовой оптимизации геометрии.

Основные принципы кодирования:

  • координаты переводятся в целочисленное представление с масштабированием (quantization);
  • повторяющиеся ключи GeoJSON (например, "type", "properties", "coordinates") заменяются на бинарные поля protobuf;
  • геометрии (Point, LineString, Polygon) кодируются как последовательности чисел;
  • свойства объектов сериализуются в типизированные структуры protobuf map/fields.

Ключевая особенность — упор на геометрические данные, которые составляют основную массу GeoJSON-документов.


Архитектурная схема обработки

Типичный цикл работы с Geobuf в веб-картографических приложениях выглядит следующим образом:

  1. Сервер формирует GeoJSON из источников данных (PostGIS, Shapefile, OSM).
  2. GeoJSON преобразуется в Geobuf на серверной стороне.
  3. Клиент получает бинарный поток.
  4. Декодирование выполняется в браузере.
  5. Результат передается в Mapbox GL JS как обычный GeoJSON источник.

Mapbox GL JS не поддерживает Geobuf нативно, поэтому слой декодирования является обязательным.


Преимущества использования Geobuf

Снижение объёма данных

Geobuf обеспечивает значительное уменьшение размера по сравнению с GeoJSON:

  • сокращение за счёт protobuf-структуры;
  • уменьшение числа повторяющихся строк;
  • компактное хранение координат.

В реальных сценариях снижение может достигать 30–80% в зависимости от структуры данных.

Быстрая передача по сети

Меньший размер напрямую влияет на:

  • сокращение времени загрузки;
  • уменьшение нагрузки на сеть;
  • повышение отзывчивости картографических приложений.

Эффективная десериализация

Protocol Buffers обеспечивают:

  • линейную сложность парсинга;
  • минимальные накладные расходы на разбор структуры;
  • отсутствие необходимости в полноценном JSON-парсинге.

Ограничения и особенности

Несмотря на эффективность, Geobuf имеет ряд ограничений:

Отсутствие нативной поддержки в Mapbox GL JS

Mapbox GL JS работает с GeoJSON, vector tiles и raster sources. Geobuf требует промежуточного слоя декодирования.

Дополнительная нагрузка на CPU клиента

Хотя уменьшается сеть, появляется нагрузка на браузер:

  • декодирование protobuf;
  • восстановление координат;
  • преобразование в GeoJSON-структуры.

Потеря читаемости и дебага

Geobuf невозможно инспектировать без декодирования, что усложняет:

  • отладку;
  • визуальный контроль данных;
  • логирование на промежуточных этапах.

Библиотеки для работы с Geobuf в JavaScript

Основные инструменты:

  • geobuf — основная библиотека для кодирования/декодирования;
  • pbf — низкоуровневый protobuf парсер.

Типичная связка выглядит следующим образом:

  • geobuf.decode(buffer, new Pbf(buffer))
  • geobuf.encode(geojson, new Pbf())

Интеграция Geobuf с Mapbox GL JS

Базовый сценарий загрузки

Так как Mapbox GL JS принимает GeoJSON, требуется декодирование перед передачей в источник.

Пример загрузки Geobuf:

import mapboxgl from "mapbox-gl";
import geobuf from "geobuf";
import Pbf from "pbf";

async function loadGeobufSource(url, map) {
  const response = await fetch(url);
  const arrayBuffer = await response.arrayBuffer();

  const geojson = geobuf.decode(new Pbf(new Uint8Array(arrayBuffer)));

  map.addSource("geobuf-source", {
    type: "geojson",
    data: geojson
  });
}

После декодирования данные становятся полностью совместимыми с системой слоёв Mapbox GL JS:

map.addLayer({
  id: "points-layer",
  type: "circle",
  source: "geobuf-source",
  paint: {
    "circle-radius": 5,
    "circle-color": "#ff5500"
  }
});

Оптимизация загрузки больших наборов данных

Использование Web Workers

Декодирование Geobuf может быть вынесено в отдельный поток, чтобы избежать блокировки UI:

// worker.js
importScripts("geobuf.js", "pbf.js");

onmess age = function (e) {
  const buffer = e.data;
  const geojson = geobuf.decode(new Pbf(buffer));
  postMessage(geojson);
};

Основной поток:

const worker = new Worker("worker.js");

fetch("/data.geobuf")
  .then(r => r.arrayBuffer())
  .then(buffer => {
    worker.postMessage(buffer, [buffer]);
  });

worker.onmess age = function (e) {
  map.addSource("data", {
    type: "geojson",
    data: e.data
  });
};

Такой подход особенно эффективен при работе с десятками мегабайт геоданных.


Серверная генерация Geobuf

Генерация Geobuf чаще всего выполняется на сервере для снижения нагрузки на клиента.

Пример на Node.js:

import geobuf from "geobuf";
import Pbf from "pbf";
import fs from "fs";

const geojson = JSON.parse(fs.readFileSync("data.json", "utf8"));

const buffer = geobuf.encode(geojson, new Pbf());

fs.writeFileSync("data.geobuf", Buffer.from(buffer));

В связке с PostGIS возможна генерация GeoJSON через SQL-запрос и последующее кодирование в Geobuf на backend-слое.


Сравнение с альтернативными форматами

GeoJSON

  • текстовый формат;
  • легко отлаживать;
  • большой размер;
  • медленный парсинг.

TopoJSON

  • топологическая оптимизация;
  • уменьшение дублирования геометрий;
  • сложнее в обработке.

Vector Tiles (MVT)

  • оптимизирован для Mapbox GL JS;
  • поддерживает масштабирование;
  • требует тайлизации.

Geobuf

  • бинарная упаковка GeoJSON;
  • универсальность;
  • отсутствие тайловой структуры;
  • необходимость декодирования.

Geobuf часто занимает промежуточную позицию между GeoJSON и vector tiles.


Поведение в Mapbox GL JS при обновлении данных

Mapbox GL JS позволяет динамически обновлять источник GeoJSON, что критично для Geobuf-потока.

map.getSource("geobuf-source").setData(decodedGeojson);

При потоковой загрузке данных возможны сценарии:

  • частичное обновление;
  • батчинг геометрий;
  • постепенная отрисовка объектов.

Кэширование и доставка

При использовании Geobuf эффективно работают следующие стратегии:

HTTP caching

  • immutable версии файлов;
  • ETag заголовки;
  • CDN-доставка бинарных данных.

Service Worker

Geobuf хорошо кэшируется как бинарный ресурс без необходимости повторного декодирования при каждом запросе.


Производительность и масштабирование

Ключевые факторы производительности:

  • размер исходного GeoJSON;
  • плотность геометрий;
  • сложность объектов (MultiPolygon vs Point);
  • стратегия декодирования (main thread vs worker).

В сценариях с десятками тысяч объектов Geobuf снижает сетевую нагрузку, но основная стоимость смещается в CPU-декодирование.


Практические паттерны использования

1. Статические наборы данных

Используется предварительно сгенерированный .geobuf файл и однократное декодирование при загрузке карты.

2. Динамические слои

Geobuf поступает частями, декодируется и обновляет источник через setData.

3. Гибрид с vector tiles

Geobuf применяется для вспомогательных слоёв (например, аналитика, heatmap), тогда как основная карта работает на MVT.


Роль Geobuf в экосистеме Mapbox GL JS

Geobuf не является частью нативного пайплайна Mapbox GL JS, однако он эффективно закрывает нишу между серверной генерацией GeoJSON и клиентской визуализацией.

Его использование оправдано в случаях, когда:

  • требуется уменьшить трафик без перехода на vector tiles;
  • данные остаются в формате GeoJSON в бизнес-логике;
  • необходима простая интеграция без переработки тайловой структуры;
  • важна скорость передачи, а не нативная рендер-оптимизация Mapbox.