Перейти к содержимому
Последнее обновление

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))

Введение в 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​

  1. Хранение в формате 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) |
+-------------------------------------+
  1. Хранение в формате 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) |
+------------------------------------+
  1. Хранение координат в виде чисел с плавающей точкой (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​

  1. Хранение в формате 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) |
+-------------------------------------------------+
  1. Хранение в формате 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​

  1. Хранение в формате 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)) |
+------------------------------------------+
  1. Хранение в формате 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​

  1. Хранение в формате 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 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Альтернативный текст