Обзор
MVTEncodeGeom— скалярная функция, которая проецирует геометрию в локальное пиксельное пространство тайла slippy-map и обрезает её по границам тайла.MVTEncode— агрегатная функция, которая собирает спроецированные геометрии группы в бинарное представление однослойного тайла.
MVTBoundingBox и MVTBoundingBoxMercator, возвращают ограничивающий прямоугольник тайла, чтобы
отфильтровать по нему строки в условии WHERE с использованием индекса.
Поддерживаются точечные, линейные и полигональные геометрии, включая тип Geometry и конкретные гео-типы (Point,
LineString, MultiLineString, Ring, Polygon, MultiPolygon).
Результирующие байты представляют собой полноценный тайл, который можно напрямую вернуть через HTTP-интерфейс с FORMAT RawBLOB.
Эти функции повторяют workflow PostGIS и также доступны под своими именами PostGIS как псевдонимы: ST_AsMVTGeom
для MVTEncodeGeom и ST_AsMVT для MVTEncode.
MVTEncodeGeom
zoom, tile_x и tile_y, обрезает её по границам тайла, привязывает к целочисленной пиксельной сетке
и возвращает геометрию в координатах тайла.
Используется проекция Web Mercator во всём диапазоне координат UInt32. Возвращаемые координаты имеют начало в
левом верхнем углу тайла, а ось y направлена вниз, что соответствует соглашению о координатах формата Mapbox Vector
Tile, поэтому результат можно напрямую передавать в MVTEncode. Координаты округляются до целых пикселей, поэтому группировка по
MVTEncodeGeom объединяет геометрии, попадающие в одну и ту же ячейку сетки, в один кластер.
Когда clip включён (по умолчанию), геометрия обрезается по тайлу, расширенному на buffer пикселей (диапазон
[-buffer, extent + buffer] по каждой оси); геометрия, полностью выходящая за эти пределы, становится NULL. Это аналог
PostGIS ST_AsMVTGeom.
Тип выходной геометрии зависит от входного: Point возвращает Point; LineString или MultiLineString возвращает
MultiLineString; Ring, Polygon или MultiPolygon возвращает MultiPolygon (при обрезке геометрия может разделиться на
несколько частей).
Синтаксис
geometry— Geometry в градусах долготы и широты. Долгота ограничивается диапазоном[-180, 180], а широта — диапазоном Web Mercator[-85.05112878, 85.05112878].Point/LineString/MultiLineString/Ring/Polygon/MultiPolygon/Geometry.zoom— Уровень масштабирования Slippy-map в диапазоне[0, 32].UInt8.tile_x— Индекс столбца тайла в диапазоне[0, 2^zoom - 1].UInt32.tile_y— Индекс строки тайла в диапазоне[0, 2^zoom - 1].UInt32.extent— Необязательный размер тайла в пикселях на сторону, в диапазоне[1, 2147483647]. По умолчанию4096— стандартное значение Mapbox Vector Tile.UInt32.buffer— Необязательный буфер обрезки в пикселях, в диапазоне[0, 2147483647]. По умолчанию1.UInt32.clip— Необязательный флаг; если значение ненулевое (по умолчанию), геометрия обрезается по границам тайла с учётом буфера.UInt8.
NULL, если она полностью обрезается. Geometry.
Пример
MVTEncode
MVTEncodeGeom. Каждая входная строка становится отдельной возможностью; поддерживаются геометрии Point, line и Polygon.
Аргумент geometry — это Geometry с координатами в пространстве тайла, обычно создаваемая MVTEncodeGeom. Строки, у которых
геометрия имеет значение NULL (например, если она была отсечена функцией MVTEncodeGeom), пропускаются. Необязательный аргумент properties — это
именованный кортеж, имена элементов которого становятся ключами атрибутов возможности, а типы элементов определяют типы значений
векторного тайла.
Результат представляет собой raw bytes одного слоя тайла. Пустая группа создаёт пустой тайл. Это аналог
PostGIS ST_AsMVT.
Синтаксис
layer_name— Имя слоя векторного тайла.String.extent— Размер тайла в пикселях по каждой стороне, в диапазоне[1, 2147483647]. Значение по умолчанию —4096.UInt32.feature_id_name— Необязательное имя элемента типа беззнакового целого в кортежеproperties, который будет записан какidвозможности MVT (типаUInt64), а не как тег. Целые числа со знаком не допускаются. ИдентификаторNULLдля такой возможности опускается. Параметры позиционные, поэтому для использования этого параметра нужно указатьextent.String.stringify_unsupported— Необязательный флаг (0/1, по умолчанию0); при значении1типы свойств, которые не поддерживаются напрямую (например, большие целые числа,UUID,Decimal), кодируются как их текстовое значениеstring_valueвместо выдачи ошибки.UInt8.
geometry— Геометрия в пространстве тайла, например изMVTEncodeGeom.Geometry.properties— Необязательный именованный кортеж атрибутов возможности. Имена элементов становятся ключами атрибутов.Tuple.
String.
Типы свойств
Value Mapbox Vector Tile, соответствующий его типу ClickHouse:
| Тип ClickHouse | Тип значения векторного тайла |
|---|---|
String / FixedString | string_value |
Float32 / BFloat16 | float_value |
Float64 | double_value |
Bool | bool_value |
Int8 / Int16 / Int32 / Int64 / Date32 | sint_value |
UInt8 / UInt16 / UInt32 / UInt64 / Date / DateTime | uint_value |
Nullable и/или LowCardinality. Значение NULL опускает этот атрибут у возможности, так как
формат векторных тайлов не поддерживает null-значения. Любой другой тип свойства вызывает исключение, если только не задан stringify_unsupported, в
этом случае он кодируется как текстовый string_value.
Одинаковые значения свойств интернируются в общий пул значений слоя, поэтому значение, которое встречается у многих возможностей,
сохраняется только один раз.
Именование кортежа properties
properties должен иметь явно заданные имена элементов. Псевдонимы столбцов внутри tuple(...) не становятся именами элементов кортежа, поэтому задавайте имена элементов с помощью приведения типа:
Кластеризация
MVTEncodeGeom округляет до целых пикселей, группировка по
пиксельной геометрии объединяет совпадающие геометрические объекты; выполните агрегацию в подзапросе, а затем передайте в
MVTEncode по одной строке на каждый кластер:
Geometry требует allow_suspicious_types_in_group_by = 1, поскольку группировка по типу Geometry на базе Variant
по умолчанию запрещена. Опустите внутренний GROUP BY (и count()), чтобы выводить по одной возможности на каждую входную строку
вместо кластеризованных возможностей.
MVTBoundingBox
zoom, tile_x и tile_y, в виде кортежа
(min_lon, min_lat, max_lon, max_lat) в градусах.
Используйте эту функцию, чтобы ограничить строки тайлом, фильтруя напрямую по столбцам longitude/latitude, — так можно использовать первичный ключ или
индекс по этим столбцам — вместо того чтобы заново вычислять проекцию Web Mercator для каждой строки. Необязательный параметр margin
расширяет ограничивающий прямоугольник с каждой стороны на указанную долю размера тайла; установите его в buffer / extent, чтобы охватить буфер отсечения
MVTEncodeGeom.
Синтаксис
zoom— Уровень масштабирования Slippy Map, в диапазоне[0, 32].UInt8.tile_x— Индекс столбца тайла, в диапазоне[0, 2^zoom - 1].UInt32.tile_y— Индекс строки тайла, в диапазоне[0, 2^zoom - 1].UInt32.margin— Необязательная доля размера тайла, на которую ограничивающий прямоугольник расширяется с каждой стороны. По умолчанию0.Float64.
(min_lon, min_lat, max_lon, max_lat) в градусах. Tuple(Float64, Float64, Float64, Float64).
Пример
MVTBoundingBoxMercator
MVTBoundingBox для Web Mercator. Возвращает
ограничивающий прямоугольник тайла в полном координатном пространстве Web Mercator с UInt32, которое внутренне использует MVTEncodeGeom, в виде кортежа
(min_x, min_y, max_x, max_y). Ось y направлена вниз (север сверху). Предназначена для таблиц, которые материализуют
столбцы с координатами Mercator и индексируют их вместо longitude/latitude.
Синтаксис
MVTBoundingBox.
Возвращаемое значение
Возвращает ограничивающий прямоугольник тайла в виде кортежа (min_x, min_y, max_x, max_y) в координатах проекции Web Mercator. Tuple(Float64, Float64, Float64, Float64).
Пример
Ограничение строк рамками тайла
WHERE (для производительности) и обрезкой в MVTEncodeGeom (для корректности).
Обрезка отсекает геометрию за пределами тайла, поэтому даже неточный предикат ограничивающего прямоугольника не даст геометрии вне тайла попасть
в результат.
MVTEncodeGeom. Передайте clip => false (седьмой аргумент) в MVTEncodeGeom, чтобы отключить обрезку и полагаться
только на предикат WHERE.
Раздача тайлов по HTTP
/. Удобный
URL /tile/{z}/{x}/{y} добавляется оператором с помощью обработчика предопределённого запроса в
конфигурации сервера. url обработчика использует форму regex: для захвата сегментов пути, связывает их с
параметрами запроса и возвращает байты в формате FORMAT RawBLOB.
В самом простом случае таблица содержит столбец Geometry, а обработчик отдаёт по одной возможности на строку — MVTEncodeGeom
проецирует каждую геометрию в запрошенный тайл и обрезает её, поэтому строки вне тайла автоматически отбрасываются:
shapes — это таблица со столбцом geom Geometry (любое сочетание точек, линий и полигонов). GET /tile/10/550/335
возвращает закодированный тайл.
Для точечных данных это так же хорошо работает и с обычными столбцами longitude/latitude, если формировать точку прямо в запросе с помощью
MVTEncodeGeom((lon, lat)::Point, …). Чтобы кластеризовать совпадающие возможности или добавить для больших таблиц предварительный фильтр по ограничивающему прямоугольнику с использованием индекса,
расширьте внутренний запрос, как показано в разделах Кластеризация и
Ограничение строк пределами тайла.
Ограничения
-
Проекция Web Mercator ограничивает широту значениями
±85.05112878°и не поддерживает входные данные, пересекающие антимеридиан. -
Обрезка полигонов не гарантирует выходные данные, корректные для MVT. Обрезка исправляет ориентацию и замыкание контуров, но не самопересечения. Поэтому самопересекающийся контур («галстук-бабочка») не исправляется: в зависимости от того, как он пересекает тайл, он либо выводится без изменений (и остаётся некорректным), либо заменяется на
NULL. Например, контур в форме галстука-бабочки, полностью лежащий внутри тайла, заменяется наNULL, тогда как те же четыре угла, заданные как простой контур, сохраняются:
- Geometry обрезается перед округлением до целочисленной пиксельной сетки. PostGIS сначала привязывает геометрию к целочисленной пиксельной сетке, а уже потом обрезает её;
MVTEncodeGeom, наоборот, сначала обрезает (по спроецированным координатам с плавающей запятой), а затем округляет. Вблизи края тайла из-за этого может отсечься координата, которая иначе округлилась бы до граничного пикселя. Например, приbuffer = 0точка сразу к востоку от границы тайла отсекается, хотя она округляется до граничного пикселя4096, который при подходе с округлением перед обрезкой был бы сохранён: