GEO
Описанный в этом документе тип GEO не является отдельным типом данных в Doris. Речь идёт об особом формате данных, хранящихся в значениях типа String/Varchar, и об использовании связанных функций.
Геопространственные типы представляют собой специальные типы данных в базах данных, предназначенные для хранения и обработки геопространственных данных. Они позволяют представлять геометрические объекты, такие как точки, линии и многоугольники. Основные задачи:
- Хранение сведений о географическом положении (например, долготы и широты).
- Поддержка пространственных запросов (например, вычисление расстояний, проверка принадлежности области и пересечения).
- Выполнение геопространственного анализа (например, анализ буферных зон, планирование маршрутов). Геоинформационные системы широко применяются в картографических сервисах, планировании логистики, социальных сетях с привязкой к местоположению, метеорологическом мониторинге и других областях. Основное требование заключается в эффективном хранении огромных объёмов пространственных данных и выполнении пространственных вычислений с низкой задержкой.
Основные технологии кодирования
S2 Geometry Library
S2 Geometry представляет собой систему кодирования сферической геометрии, разработанную Google. Её основная идея состоит в эффективном индексировании геопространственных данных всей планеты путём проецирования сферы на плоскость.
Основные принципы
- Сферическая проекция: сфера Земли проецируется на 6 граней правильного шестигранника, что позволяет преобразовать сферические данные 3D в плоские данные 2D.
- Иерархическое разбиение на ячейки: каждая грань рекурсивно делится на четырёхугольные ячейки, а каждая ячейка может быть дополнительно разделена на 4 меньшие ячейки. Так формируется иерархическая структура с 30 уровнями точности (чем выше уровень, тем меньше площадь ячейки и выше точность).
- 64-битное кодирование: каждой ячейке присваивается уникальный 64-битный ID, с помощью которого можно быстро определять пространственное положение и проверять пространственные отношения.
- Упорядочивание по кривой Гильберта: для кодирования ячеек используются кривые Гильберта, заполняющие пространство. Благодаря этому соседние в пространстве ячейки получают последовательные ID, что повышает производительность диапазонных запросов.
Преимущества
- Высокая точность и плавный переход: 30 уровней иерархии обеспечивают точность от глобального масштаба (уровень 0) до сантиметрового (уровень 30), позволяя плавно переходить между уровнями в зависимости от потребностей различных сценариев.
- Эффективность запросов в глобальном масштабе: подходит для масштабных пространственных запросов (например, анализа регионов на разных континентах или в разных странах) без существенного снижения производительности.
- Эффективное вычисление пространственных отношений: включение, пересечение и другие отношения можно быстро проверять по ID ячеек, избегая сложных геометрических операций.
Кодирование GeoHash
GeoHash представляет собой метод геокодирования на основе равнопромежуточной проекции, который обеспечивает пространственное индексирование путём преобразования долготы и широты в строки.
Основные принципы
- Проекция на плоскость: сфера Земли приближённо представляется плоскостью, а область рекурсивно разбивается путём двоичного деления долготы и широты.
- Разбиение на прямоугольные ячейки: поверхность Земли делится на прямоугольные ячейки с различной точностью. Длина строки определяет точность (до 12 символов), причём каждый дополнительный символ повышает точность примерно в 10 раз.
- Кодирование по кривой Z-порядка: кривая Z-порядка формируется путём попеременного отбора двоичных разрядов долготы и широты, преобразуя координаты 2D в строки 1D.
Особенности
- Удобство индексирования: соседние области можно быстро находить с помощью сопоставления префиксов строк (например, коды GeoHash с одинаковым префиксом соответствуют соседним в пространстве областям).
- Ограничения:
- Ограниченное число уровней точности: до 12 уровней с резкими переходами между ними, что затрудняет плавное разбиение с высокой точностью.
- Разрывы кривых Z-порядка: соседние в пространстве области могут иметь непоследовательные коды из-за скачков кривой, что влияет на точность диапазонных запросов.
- Низкая эффективность масштабных запросов: при запросах в глобальном масштабе приходится сканировать большое количество разрозненных ячеек, что снижает производительность.
Комплексное сравнение и выбор
Сравнив характеристики S2 Geometry Library и GeoHash, мы выбрали S2 Geometry Library в качестве сторонней зависимости для обработки геопространственных данных. Основные причины:
- Пригодность для запросов в глобальном масштабе: иерархическая структура ячеек S2 лучше подходит для масштабного пространственного анализа, тогда как GeoHash сталкивается с ограничениями производительности при запросах, охватывающих разные регионы.
- Точность и плавность переходов: иерархия S2 из 30 уровней обеспечивает плавный переход от глобального масштаба до сантиметрового, удовлетворяя требованиям к точности в разных сценариях и превосходя разбиение GeoHash на 12 уровней.
- Пространственная непрерывность: кривые Гильберта обладают лучшей пространственной непрерывностью, чем кривые Z-порядка, что позволяет сократить избыточные вычисления в диапазонных запросах.
Введение в WKT
WKT (Well-Known Text) представляет собой стандартный текстовый формат для представления геопространственных данных.
Определение
- Текстовый формат: структура и координаты геометрических объектов описываются текстовыми строками.
- Особенности: удобен для чтения человеком, легко редактируется, подходит для ручного ввода и простого обмена данными.
Структура синтаксиса
- Основной формат: GeometryType(CoordinateValues)
- Распространённые геометрические типы:
- Point: POINT(longitude, latitude)
Пример: POINT(112.46, 45.23) представляет долготу и широту точки. - LineString: LINESTRING(point1, point2)
Пример: LINESTRING(0 0, 1 1) представляет отрезок, соединяющий две точки. - Polygon: POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))
- Point: POINT(longitude, latitude)
Введение в WKB
WKB (Well-Known Binary) представляет собой стандартный бинарный формат данных для представления геопространственных данных.
Определение
- Бинарный формат: геометрические объекты представляются в бинарной кодировке, которая компактнее и эффективнее WKT.
- Особенности: оптимизирован для внутреннего хранения и передачи данных компьютерами, экономит место и обеспечивает быстрый разбор.
Структура кодирования
WKB состоит из следующих частей:
- Порядок байтов (1 байт):
- 0x00: Big Endian (сетевой порядок байтов)
- 0x01: Little Endian (распространён в архитектурах Intel/AMD)
- Тип геометрии (4-байтовое целое число):
- 1: Point
- 2: LineString
- 3: Polygon
- ... (другие типы)
- Значения координат:
- Point: x, y (или x, y, z)
- LineString: координаты point1, координаты point2
- Polygon: координаты point1, координаты point2...
Пример
01 01 00 00 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 40
└─┘ └─┘ └───────────────┘ └───────────────┘
│ │ │ │
Little Endian Point type x=1.0 y=2.0
Тип GeoPoint
- Хранение в формате WKT с использованием String или Varchar
CREATE TABLE simple_point ( id INT, wkt STRING) ;
INSERT INTO simple_point VALUES(1,'POINT(121.4737 31.2304)');
create table simple_point(id int, wkt VARCHAR(255));
INSERT INTO simple_point VALUES(1,'POINT(121.4737 31.2304)');
Запрос данных в формате WKT
select st_astext(st_geometryfromtext(wkt)) from simple_point;
+-------------------------------------+
| st_astext(st_geometryfromtext(wkt)) |
+-------------------------------------+
| POINT (121.4737 31.2304) |
+-------------------------------------+
- Хранение в формате WKB
CREATE TABLE simple_point ( id INT, wkb STRING) ;
INSERT INTO simple_point VALUES(1,'\x01010000005f07ce19515e5e4097ff907efb3a3f40');
create table simple_point(id int, wkb VARCHAR(255));
INSERT INTO simple_point VALUES(1,'\x01010000005f07ce19515e5e4097ff907efb3a3f40');
Запрос данных в формате WKB
select st_astext(st_geometryfromwkb(wkb)) from simple_point;
+------------------------------------+
| st_astext(st_geometryfromwkb(wkb)) |
+------------------------------------+
| POINT (121.4737 31.2304) |
+------------------------------------+
- Хранение координат в виде чисел с плавающей точкой (x для широты, y для долготы)
CREATE TABLE simple_point_double (id INT,x DOUBLE,y DOUBLE)
INSERT INTO simple_point_double VALUES(0,1,2);
Запрос данных в формате чисел с плавающей точкой
select st_astext(st_point(x,y)) from simple_point_double;
+--------------------------+
| st_astext(st_point(x,y)) |
+--------------------------+
| POINT (1 2) |
+--------------------------+
Тип GeoLine
- Хранение в формате WKT с использованием String или Varchar
CREATE TABLE simple_line ( id INT, wkt STRING)
INSERT INTO simple_line VALUES(1,'LINESTRING(116.4074 39.9042, 121.4737 31.2304)');
CREATE TABLE simple_line ( id INT, wkt VARCHAR(255))
INSERT INTO simple_line VALUES(1,'LINESTRING(116.4074 39.9042, 121.4737 31.2304)');
Запрос данных в формате WKT
select st_astext(st_linefromtext(wkt)) from simple_line;
+-------------------------------------------------+
| st_astext(st_linefromtext(wkt)) |
+-------------------------------------------------+
| LINESTRING (116.4074 39.9042, 121.4737 31.2304) |
+-------------------------------------------------+
- Хранение в формате WKB
CREATE TABLE simple_line ( id INT, wkb STRING)
INSERT INTO simple_line VALUES(1,'\x010200000002000000fc1873d7121a5d4088855ad3bcf343405f07ce19515e5e4097ff907efb3a3f40');
CREATE TABLE simple_line ( id INT, wkb VARCHAR(255))
INSERT INTO simple_line VALUES(1,'\x010200000002000000fc1873d7121a5d4088855ad3bcf343405f07ce19515e5e4097ff907efb3a3f40');
Запрос данных в формате WKB
select st_astext(st_geometryfromwkb(wkb)) from simple_line;
+-------------------------------------------------+
| st_astext(st_geometryfromwkb(wkb)) |
+-------------------------------------------------+
| LINESTRING (116.4074 39.9042, 121.4737 31.2304) |
+-------------------------------------------------+
Тип GeoPolygon
- Хранение в формате WKT с использованием String или Varchar
CREATE TABLE simple_polygon ( id INT, wkt STRING)
INSERT INTO simple_polygon VALUES(1,'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
CREATE TABLE simple_polygon ( id INT, wkt VARCHAR(255))
INSERT INTO simple_polygon VALUES(1,'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
Запрос данных в формате WKT
select st_astext(st_polygon(wkt)) from simple_polygon;
+------------------------------------------+
| st_astext(st_polygon(wkt)) |
+------------------------------------------+
| POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0)) |
+------------------------------------------+
- Хранение в формате WKB
CREATE TABLE simple_polygon_wkb ( id INT, wkb STRING)
INSERT INTO simple_polygon_wkb VALUES(1,'\x010300000001000000050000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000024400000000000000000');
CREATE TABLE simple_polygon_wkb ( id INT, wkb VARCHAR(255))
INSERT INTO simple_polygon_wkb VALUES(1,'\x010300000001000000050000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000024400000000000000000');
Запрос данных в формате WKB
select st_astext(st_geometryfromwkb(wkb)) from simple_polygon_wkb;
+------------------------------------------+
| st_astext(st_geometryfromwkb(wkb)) |
+------------------------------------------+
| POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0)) |
+------------------------------------------+
Тип GeoMultiPolygon
- Хранение в формате WKT с использованием String или Varchar
CREATE TABLE simple_multipolygon ( id INT, wkt STRING)
INSERT INTO simple_multipolygon VALUES(1,'MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)),((20 20, 20 30, 30 30, 30 20, 20 20)))');
CREATE TABLE simple_multipolygon ( id INT, wkt VARCHAR(255))
INSERT INTO simple_multipolygon VALUES(1,'MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), -- 第一个多边形((20 20, 20 30, 30 30, 30 20, 20 20)) -- 第二个多边形)');
Запрос данных в формате WKT
select st_astext(st_geometryfromtext(wkt)) from simple_multipolygon;
+----------------------------------------------------------------------------------------+
| st_astext(st_geometryfromtext(wkt)) |
+----------------------------------------------------------------------------------------+
| MULTIPOLYGON (((10 0, 10 10, 0 10, 0 0, 10 0)), ((30 20, 30 30, 20 30, 20 20, 30 20))) |
+----------------------------------------------------------------------------------------+
Примечание: преобразование формата WKB для GeoMultiPolygon пока не поддерживается
Тип GeoCircle
Способ хранения (хранение координат центра и радиуса в виде чисел с плавающей точкой) Поскольку круги не соответствуют форматам WKB и WKT, для хранения координат центра (x, y) и радиуса (R) требуются три числа с плавающей точкой:
create table simple_circle(id int, X double,Y double, R double)
INSERT INTO simple_circle VALUES(1,1.0,1.0,2);
Запрос круга
select st_astext(st_circle(X,Y,R)) from simple_circle;
+-----------------------------+
| st_astext(st_circle(X,Y,R)) |
+-----------------------------+
| CIRCLE ((1 1), 2) |
+-----------------------------+
Ограничения
Индексы
Поскольку Doris не реализует тип Geo напрямую, а хранит и преобразует такие данные с помощью WKT и WKB, ускорение запросов к типу GEO с помощью индексов невозможно.
При преобразовании WKT в выходное представление GEO гарантируется точность только до 13 цифр:
mysql> SELECT ST_AsText(ST_GeometryFromText("POINT (1 3.1415926535897223)"));
+----------------------------------------------------------------+
| ST_AsText(ST_GeometryFromText("POINT (1 3.1415926535897223)")) |
+----------------------------------------------------------------+
| POINT (1 3.14159265358972) |
+----------------------------------------------------------------+
При преобразовании бинарных данных в выходное представление GEO гарантируется точность только до 13 цифр:
mysql> select ST_AsText(ST_GeomFromWKB(ST_AsBinary(ST_Point(24.7,3.141592653589793))));
+--------------------------------------------------------------------------+
| ST_AsText(ST_GeomFromWKB(ST_AsBinary(ST_Point(24.7,3.141592653589793)))) |
+--------------------------------------------------------------------------+
| POINT (24.7 3.1415926535898) |
+--------------------------------------------------------------------------+
Типичные сценарии использования и способы работы с типами Geo в Doris
Вычисление расстояния между двумя точками на Земле
Расстояние от Пекина до Шанхая Координаты Пекина (116.4074, 39.9042) и Шанхая (121.4737, 31.2304):
select ST_DISTANCE_SPHERE(116.4074, 39.9042, 121.4737, 31.2304);
+----------------------------------------------------------+
| ST_DISTANCE_SPHERE(116.4074, 39.9042, 121.4737, 31.2304) |
+----------------------------------------------------------+
| 1067311.8461903075 |
+----------------------------------------------------------+

Расстояние от Пекина до Нью-Йорка Координаты Пекина (116.4074, 39.9042) и Нью-Йорка (-74.0060, 40.7128):
select ST_DISTANCE_SPHERE(116.4074, 39.9042, -74.0060, 40.7128);
+----------------------------------------------------------+
| ST_DISTANCE_SPHERE(116.4074, 39.9042, -74.0060, 40.7128) |
+----------------------------------------------------------+
| 10989107.361809434 |
+----------------------------------------------------------+

Вычисление площади области на сфере Земли
Оценка площади Нью-Йорка Приблизительно обозначим границы Нью-Йорка многоугольником и вычислим площадь:
SELECT ST_AREA_SQUARE_KM(
ST_GeomFromText('POLYGON((
-74.2591 40.9155,
-73.8726 40.9147,
-73.7004 40.7506,
-73.9442 40.5840,
-74.0817 40.6437,
-74.1502 40.6110,
-74.0984 40.6550,
-74.0431 40.7290,
-74.0136 40.7903,
-73.9352 40.8448,
-74.2591 40.9155
))'));
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ST_AREA_SQUARE_KM( ST_GeomFromText('POLYGON((-74.2591 40.9155, -73.8726 40.9147, -73.7004 40.7506, -73.9442 40.5840, -74.0817 40.6437,-74.1502 40.6110,-74.0984 40.6550,-74.0431 40.7290,-74.0136 40.7903, -73.9352 40.8448, -74.2591 40.9155))' )) |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 744.3806189617659 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
