Для объектно-реляционной СУБД PostgreSQL (Postgres) существует множество расширений. Их также называют экстеншенами (от англ. extension - расширение). Некоторые из них помогают в оптимизации работы баз данных, другие нужны для эффективной работы с определенными типами данных. Именно об одном из последних мы поговорим в этой статье.
PostGIS — это расширение с открытым исходным кодом для PostgreSQL. Он привносит в PostgreSQL три вещи, которые имеют решающее значение для работы с пространственными данными:
Пространственные базы данных (spatial databases) хранят пространственные объекты и управляют ими так же, как и любыми другими объектами в базе данных. Таким образом, в обычной базе данных вы храните данные разных типов (числовые, текстовые, временные метки) и при необходимости вы можете запрашивать (извлекать) их, чтобы отвечать на вопросы с помощью ваших данных. Вопросы могут быть о том, «сколько людей зашло на ваш сайт» или «сколько транзакций было совершено в интернет-магазине». Вместо этого пространственные функции могут отвечать на такие вопросы, как «насколько близко находится ближайший магазин», «находится ли эта точка внутри этой области» или «каков размер этой страны».
Заводим сервер на Timeweb Cloud и устанавливаем PostgreSQL.
Для начала обновим программные пакеты. В системах Linux это можно сделать, воспользовавшись командой:
sudo apt update
Затем установим Postgres, а именно пакет postgresql-contrib
, содержащий дополнительные модули и функции дистрибутива PostgreSQL:
sudo apt install postgresql postgresql-contrib
Когда установка заверена, следует проверить статус сервера базы данных:
service postgresql status
Если статус down, сервис нужно запустить командой:
sudo service postgresql start
Или:
sudo systemctl status postgresql.service
sudo systemctl start postgresql.service
Выбор команды зависит от используемой системы инициализации: sysvinit или systemd. Проверить это можно при помощи команды:
ps -p 1 -o comm=
В случае использования Ubuntu внутри Windows это будет первый вариант.
Когда вы устанавливаете PostgreSQL, по умолчанию создается пользователь-администратор postgres
. От его имени мы в первый раз заходим на сервер PostgreSQL.
Зададим пароль пользователю postgres:
sudo passwd postgres
Вы можете взаимодействовать с ядром базы данных несколькими способами. К примеру, инструмент pgAdmin
предоставляет графический клиент для управления базами данных. Но мы будем использовать psql
— клиентский инструмент командной строки. Вызовем его от имени пользователя postgres
, чтобы начать интерактивный сеанс.
sudo -u postgres psql
Или:
su postgres -c psql
Во втором случае необходимо будет ввести пароль, заданный шагом ранее.
Наряду с пользователем-администратором postgres
, PostgreSQL также создает базу данных по умолчанию с именем «postgres» и автоматически подключает вас к ней при первом запуске psql
.
Проверьте детали вашего соединения после первого запуска psql
, набрав \conninfo
в интерпретаторе.
postgres=# \conninfo
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5433".
Вы также можете посмотреть список всех баз данных, доступных на сервере, используя команду \l
.
А чтобы увидеть список всех пользователей с их привилегиями, — используйте команду \du
.
Теперь, когда мы подключены к серверу базы данных через инструмент командной строки psql
с полными правами доступа, пришло время создать новую базу данных.
CREATE DATABASE test;
И подключиться к ней:
\c test
dbaas
Вероятно, вы захотите подключиться к базе данных через удаленный сервер.
Сразу после установки сервер PostgreSQL доступен только локально, через петлевой IP-адрес вашего компьютера. Но вы можете разрешить удалённый доступ, изменив соответсвующий параметр в файле конфигурации PostgreSQL.
Получить доступ к файлу конфигурации postgresql.conf
PostgreSQL версии 13 (ваша версия указывается при запуске psql
) можно с помощью текстового редактора nano
:
sudo nano /etc/postgresql/13/main/postgresql.conf
Раскомментируйте и отредактируйте атрибут listen_addresses
, чтобы начать прослушивание всех доступных IP-адресов.
listen_addresses = '*'
Теперь внесём изменения в файл конфигурации политики доступа PostgreSQL:
sudo nano /etc/postgresql/13/main/pg_hba.conf
Добавьте новую политику подключения (шаблон [CONNECTION_TYPE][DATABASE][USER] [ADDRESS][METHOD]
) внизу файла.
host all all 0.0.0.0/0 md5
Мы разрешаем подключения по протоколу TCP/IP (host
) ко всем базам данных (all
) для всех пользователей (all
) с любым адресом IPv4 (0.0.0.0/0
) с использованием зашифрованного пароля MD5 для аутентификации (md5
).
После изменения настроек перезапускаем службу postgresql
:
sudo service postgresql restart
В Ubuntu 20.04 расширение присутствует в репозиториях и может быть установлено с помощью команды:
sudo apt install postgis
Функции PostGIS для каждой базы мы будем настраивать отдельно. Начнём с только что созданной базы test
, а именно создадим расширения:
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
И убедимся, что оно создано:
SELECT PostGIS_version();
В командной строке увидим примерно следующее:
postgis_version
---------------------------------------
3.0 USE_GEOS=1 USE_PROJ=1 USE_STATS=1
Давайте загрузим некоторые данные PostGIS в нашу базу данных. Будем использовать набор данных из PostGIS tutorial.
mkdir nyc
cd nyc
wget http://s3.cleverelephant.ca/postgis-workshop-2020.zip
unzip postgis-workshop-2020.zip
Чтобы загрузить пространственные данные в базу, воспользуемся утилитой shp2pgsql
. Она конвертирует шейп-файлы в SQL.
Что представляют собой шейп-файлы? Обозначение шейп-файл, как правило, имеет отношение к группе файлов, имеющих расширения .shp, .shx, .dbf и др., объединенных общим названием (например, nyc_subway_stations). Фактически же шейп-файлом является именно файл с расширением .shp. Тем не менее файл данного типа не является самодостаточным и не может распространяться без необходимых вспомогательных файлов.
Обязательные файлы:
Необязательные файлы включают в себя:
Для загрузки используем следующую команду:
shp2pgsql -I -s 26918 nyc/postgis-workshop/data/nyc_subway_stations.shp nyc_subway_stations | sudo -u postgres psql dbname=test
Где:
I
указывает программе создать пространственный индекс для таблицы после завершения загрузки.26918
.nyc/postgis-workshop/data/nyc_subway_stations.shp
указывает расположение шейп-файла для чтенияnyc_subway_stations
— имя для целевой таблицы| sudo -u postgres psql dbname=test
Оператор |
принимает сгенерированный утилитой поток sql и использует его в качестве входных данных для терминала psql
. Подключаемся через psql
к целевой базе данных.
Таким же образом создадим в базе остальные таблицы nyc_census_blocks, nyc_homicides, nyc_neighborhoods, nyc_streets.
Посмотреть столбцы и их типы в созданных таблицах можно следующим образом:
\d <имя_таблицы>
К примеру мы можем видеть, что станции метро имеют тип geometry(Point,26918)
, то есть являются точками, а районы — geometry(MultiPolygon,26918)
, и являются полигонами.
Если выполнить SELECT * FROM
для любой из наших таблиц, то в результате мы увидим, что столбец geom
представляет собой непрозрачное кодирование геометрических данных. Вы, возможно, ожидали увидеть точки данных долготы/широты. Именно здесь начинают действовать функции PostGIS. К примеру, функция ST_AsText(geom)
превращает данные столбца в точки геометрии.
Получим с помощью данной функции координаты долготы и широты станций метро:
SELECT name, ST_AsText(geom)
FROM nyc_subway_stations;
В результате увидим:
name | st_astext
--------------------------+------------------------------------------
Allerton Ave | POINT(595454.531087843 4524436.50062031)
Baychester Ave | POINT(597856.15605485 4525936.78154763)
Bedford Park Blvd | POINT(593712.996886201 4525155.29643926)
Bedford Park Blvd | POINT(593550.086762622 4525318.36272269)
Bronx Park East | POINT(595390.744161286 4522610.04524754)
Brook Ave | POINT(591158.462734484 4517957.5457551)
Buhre Ave | POINT(598436.457893145 4522431.7978544)
Burke Ave | POINT(595458.276100251 4525102.84081136)
Burnside Ave | POINT(592095.242680619 4523101.90192447)
Castle Hill Ave | POINT(596821.240860527 4520985.43791063)
Cypress Ave | POINT(591563.743613455 4517738.30592931)
Dyre Ave | POINT(598514.310720232 4527104.05810844)
E 143rd St | POINT(592119.080134076 4518038.84260289)
Другая полезная функция — ST_Length(geom)
вычисляет длину:
Получим с помощью нее самые короткие улицы города:
SELECT name, ST_Length(geom) as street_length
FROM nyc_streets
ORDER BY street_length ASC
LIMIT 5;
name | street_length
-------------+--------------------
W 66 St | 0.9209664156687739
Linden Blvd | 1.1366550633216888
Village Ct | 3.0275240748000387
Bay 38 St | 3.30965835413287
Wilder Ave | 3.62538546315785
Или, например, найдем 10 самых больших районов Нью-Йорка, используя функцию ST_Area(geom)
, вычисляющую площадь:
SELECT boroname, name, ST_Area(geom) as neighborhood_area
FROM nyc_neighborhoods
ORDER BY neighborhood_area DESC
LIMIT 10;
boroname | name | neighborhood_area
---------------+---------------------------+--------------------
Queens | The Rockaways | 27956418.73731064
Brooklyn | Gravesend-Sheepshead Bay | 19920099.58695366
Brooklyn | Canarsie | 17702913.620151885
Queens | Douglastown-Little Neck | 17532480.147214886
Staten Island | Bloomfield-Chelsea-Travis | 14118408.808009561
Queens | Jamaica | 13848478.727482272
Staten Island | Richmondtown | 12904057.943439055
Brooklyn | Mapleton-Flatlands | 12197264.514111498
Brooklyn | East Brooklyn | 11090294.27801337
The Bronx | Eastchester | 10786177.928620113
Больше функций можно найти в документации или упомянутом выше туториале PostGIS.
Разверните PostgreSQL в облаке за пару кликов
Обсудим еще одну важную деталь — геометрия и география. В PostgreSQL и PostGIS есть важное различие между геометрией и географией: геометрия является декартовой, а география добавляет дополнительные вычисления кривизны земли. В общем, если вы имеете дело с небольшими областями, такими как город или здание, вам не нужно добавлять дополнительные вычислительные ресурсы для географии, но если вы пытаетесь рассчитать что-то более крупное, например маршруты авиакомпаний, — это необходимо.
Вот как вы могли бы создать таблицу географии (т.е. преобразовать данные функцией ST_Transform
) из одной из наших существующих таблиц:
CREATE TABLE nyc_subway_stations_geog AS
SELECT
ST_Transform(geom,4326)::geography AS geog,
name,
routes
FROM nyc_subway_stations;
Таким образом, мы создали базу управления данными в PostgreSQL PostGIS, загрузили разнообразные пространственные данные, описывающие Нью-Йорк, и попробовали узнать некоторые факты о городе, используя функции для работы с геометрией.
Надеемся, эта статья была вам полезна!