Конец года дается Деду Морозу и его эльфам непросто. Они очень заняты приготовлением и доставкой подарков миллионам детей. Я уверен, что им действительно понадобится дополнительная помощь! Используя возможности геопространственной базы данных, мы можем анализировать статистические данные и даже планировать идеальный путь для саней Санты.
Обычным способом работать с пространственными данными непросто. Вам постоянно приходится иметь дело с числами точности с плавающей запятой, картографическими проекциями и сложными функциями обработки. К счастью, Центр данных Северного полюса использует базу данных PostgreSQL, поэтому мы можем воспользоваться библиотекой расширений PostGIS. Это дает вам возможность работать с пространственными данными прямо в вашей базе данных, используя стандартные SQL-запросы. Разве это не круто?
Функции
Типы данных
Главной особенностью PostGIS является то, что он дает вам возможность создавать пространственные типы данных и манипулировать ими. Эти объекты представлены в базе данных с использованием специального языка описания векторной геометрии: WKT (общеизвестный текст), который является удобочитаемым языком разметки и представляет собой двоичную версию для внутреннего использования БД WKB (хорошо известный двоичный файл). Он поддерживает несколько типов геометрических объектов, включая:
- Геометрия (общий суперкласс для всех других типов)
- Точка
POINT(20.1 23.5)
(например, текущее положение оленя) - LineString (многоугольная цепочка)
LINESTRING(0 0, 2.3 1.3, 14 6)
(например, путь для саней Санты) - Многоугольник
POLYGON ((30 10, 40 40, 20 40, 30 10))
(например, контур фабрики Санты)
Каждая геометрия включает также параметр SRID
, который является ссылкой на систему координат, которая изменяет работу всех функций и вычислений. Например, для географической системы координат мы будем использовать SRID 4326
(насколько я знаю, Санта доставляет подарки только на Земле). Полный список см. в docs PostGIS.
Функции
PostGIS имеет широкий набор функций для создания, сравнения, обработки и вычислений пространственных данных. Некоторые из них:
Конструкторы
ST_GeomFromText(text,[<srid>])
(создает объект из любого WKT)ST_MakePoint(<x>, <y>)
ST_MakeLine(point, point, point...)
ST_MakePolygon(linestring)
ST_Union(geometries set)
(объединяет все геометрические формы)
Расчеты
ST_Distance(geometry, geometry, use_spheroid)
(расстояние между двумя геометрическими фигурами)ST_Length(geometry, use_spheroid)
(длина геометрии, например, кривая)ST_Area(geometry, use_spheroid)
(область геометрии, например, многоугольник)
use_spheroid
логический флаг указывает, должны ли вычисления выполняться на сфероиде, например. поверхность земли.
Предикаты
ST_Intersects(geometry, geometry)
(верно, если две геометрии пересекаются)ST_Crosses(geometry, geometry)
(верно, если пересекаются две геометрические фигуры)ST_Within(geometry A, geometry B)
(верно, если A полностью в B)
Другое
ST_AsText(geometry)
(преобразует WKB в WKT)ST_SRID(geometry)
(изменяет SRID геометрии)
Полный список (+1000) можно найти здесь.
Настраивать
Начнем с простой настройки. Я сосредоточусь на OSX и Ubuntu, но вы можете найти подробные инструкции почти для каждой ОС на сайте PostGIS.
OSX
Самый простой способ получить Postgres и PostGIS на OSX - это загрузить и установить Postgres.app, который поставляется со встроенной поддержкой PostGIS.
Другой вариант - использовать менеджер пакетов Homebrew и запустить:
$ brew install postgis
Ubuntu
Начните с установки PostgreSQL с помощью Aptitude:
$ sudo apt-get update
$ sudo apt-get install postgresql postgresql-contrib
К сожалению, пакет Ubuntu не включает PostGIS, но мы можем получить его через репозиторий UbuntuGIS, который включает множество пакетов ГИС с открытым исходным кодом. Сначала добавьте новый репозиторий в свои источники:
$ sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
Нажмите [Enter]
для подтверждения, а затем установите желаемый пакет со всеми его необходимыми зависимостями:
$ sudo apt-get update
$ sudo apt-get install postgis
Включить суперсилы PostGIS
PostGIS - это необязательная библиотека, поэтому вы должны включить ее, чтобы иметь возможность использовать пространственные функции в вашей базе данных и помочь в доставке на Рождество как можно скорее.
Создайте пустую базу данных и подключитесь к ней с помощью psql
. Затем включите расширение PostGIS в этой недавно созданной базе данных:
$ createdb santa_project $ psql santa_project santa_project=# CREATE EXTENSION postgis;
Теперь вы готовы присоединиться к команде Санты!
База данных
Наконец-то пришло время по-настоящему поработать с нашими пространственными данными. Чтобы иметь возможность работать с функциями PostGIS, вы можете загрузить образцы данных для своей базы данных, предоставленные эльфами, работающими в Центре данных Северного полюса Санты. Для его загрузки используйте:
$ psql santa_project < santa_db.sql
Страны
Первая таблица в базе данных Санты - это countries
, в которой хранится информация о странах, включая их географические очертания.
CREATE TABLE countries ( id integer NOT NULL PRIMARY KEY, name character varying(256), geom geometry(MultiPolygon, 4326) );
Вы можете увидеть тип PostGIS geometry
с необязательными параметрами MultiPolygon
(набор полигонов) и RSID 4326.
(Существует соглашение о присвоении географическому названию столбец geom
)
Столицы
Для упрощения анализа мы будем рассматривать только столицу каждой страны.
create table capitals ( id integer NOT NULL PRIMARY KEY, name character varying(256), geom geometry(Point, 4326) );
Дети
Конечно, Санте также нужен список детей с их текущим местонахождением, чтобы доставить подарки. (это всего лишь образец данных из ~ 3500 случайных точек, потому что база данных настоящего Санты, конечно же, СОВЕРШЕННО СЕКРЕТНА)
CREATE TABLE children ( id integer NOT NULL PRIMARY KEY, name character varying(256), geom geometry(Point, 4326) );
Напишите немного SQL
После этого долгого вступления, наконец, пришло время написать несколько простых запросов.
Для годового отчета Санте нужны статистические данные:
Проблема 1
Список стран, упорядоченный по их региону.
Для этой задачи мы должны использовать функцию ST_Area
и передать ей геометрию данной страны. Не забудьте установить флаг use_spheroid
как true
.
Окончательный запрос будет выглядеть следующим образом:
SELECT name, ST_Area(geom, true) AS area
FROM countries
ORDER BY area
DESC;
name | area [m2]
------------------------+------------------
Russia | 16899340799018.3
Antarctica | 12307608053238.4
Canada | 9690145858384.64
United States | 9552731304330.88
China | 9360697736226.59
...
Проблема 2
Список из 5 стран с наибольшим количеством детей.
На этот раз мы обязательно должны присоединить дочернюю таблицу к странам в зависимости от их местоположения. Но как это сделать? Ответ - ST_Within
функция.
SELECT countries.name,COUNT(children.id) AS children_count
FROM countries LEFT JOIN children ONST_Within(children.geom, countries.geom) GROUP BY countries.id, countries.name ORDER BY children_count DESC LIMIT 5;
name | children_count --------------+---------------- Russia | 672 Canada | 389 United States | 288 China | 210 Australia | 169
Проблема 3
Список 5 столиц с наибольшим количеством детей в радиусе 200 км.
Эта задача очень похожа на предыдущую, но теперь нам нужно подключиться по другому условию. Чтобы выбрать все объекты в заданном радиусе от точки, мы проверим, меньше или равно ли их расстояние до точки радиусу, используя функцию PostGIS ST_Distance
.
SELECT capitals.name, COUNT(children.id)AS children_count FROM capitals LEFT JOIN
children ONST_Distance(children.geom, capitals.geom, true) <= 200000 GROUP BY capitals.id, capitals.name ORDER BY children_count DESC LIMIT 5;
name | children_count --------+---------------- Ottawa | 8 Berlin | 7 Lusaka | 7 Astana | 7 Vilnius | 6
Проблема 4
Один из секретных центров распространения Санты находится в этих координатах: lat -15.953918, lon -64.504169.
Давайте узнаем, в какой это стране.
Как и в Задаче 2, мы должны назначить страну данной точке с помощью функции ST_Within
, но на этот раз точка задается координатами, поэтому мы должны создать новую точку с помощью конструктора точки с правильным RSID.
(поскольку в нашем наборе данных координаты хранятся в формате (lon, lat)
, мы должны записывать данные точки в обратном порядке)
SELECT name
FROM countries
WHERE ST_Within(
ST_SetSRID(ST_MakePoint(-15.953918, -64.504169
), 4326),
geom
);
name
---------
Bolivia
Проблема 5
Теперь мы знаем, где находится распределительный центр, и можем проверить, какие страны граничат с Боливией, чтобы доставить оттуда подарки.
Чтобы выяснить это, мы можем использовать функцию ST_Intersects
, потому что граница является линией пересечения.
(поскольку Боливия, конечно, пересекается сама с собой, мы должны исключить ее из окончательного результата, используя простое условие)
SELECT name FROM countries WHERE ST_Intersects( (SELECT geom FROM countries WHERE name='Bolivia'), geom ) AND name != 'Bolivia'; name ----------- Argentina Brazil Chile Paraguay Peru
Это все на сегодня!
С вашей помощью Санта готов начать производство и доставку для всех детей по всему миру. Может быть, вам интересно, как это возможно с таким большим объемом данных, учитывая, что даже эти простые запросы к небольшому набору данных выполнялись за несколько секунд? В следующей части этого руководства я объясню, как ускорить запросы PostGIS с помощью пространственных индексов и как спланировать кратчайший путь для саней Санты с помощью другого замечательного расширения Postgresql.
Оставайтесь с нами и с Рождеством Христовым! 🎅 🎄🎁
Если вам понравился этот пост, не забудьте нажать ❤! Вы также можете подписаться на нас в Facebook, LinkedIn и Twitter.