Контакты
Блог о картографии и геоинформационных системах
Использование SQL-запросов при работе с ORBISmap на примере данных «Парковок Москвы»
При работе над геосервисами и картами часто возникает ситуация, когда имеющихся данных в исходном виде недостаточно.

Например:
  • часть данных содержится в другом слое,
  • необходимые значения должны быть вычислены,
  • нужно произвести агрегирование и фильтрацию данных для подсчета количества элементов, вычисления суммы их значений или среднего,
  • необходимо произвести те или иные операции по модификации геометрии объектов слоя.
Для решения таких задач в геоинформационной системе ORBISmap используются виртуальные слои.

Виртуальный слой основан на Представлении (View) — сущности базы данных, которая сама по себе не содержит никаких данных. Её содержимое выбирается из других таблиц (слоев — в терминологии ORBISmap) с помощью выполнения SQL-запроса. Этот механизм предоставляет широкие возможности по видоизменению исходных данных (например, объединение слоев, фильтрация, группировка, агрегация, сортировка и т.д.) без их фактической модификации. При помощи функций PostGIS в виртуальных слоях можно осуществлять различные операции с геометрией.

Пример использования SQL-запросов и виртуальных слоев в ORBISmap
В качестве примера рассмотрим задачу визуализации на карте количества парковочных мест и средней стоимости часа парковки по районам Москвы.
Готовый пример

Исходные данные с расположением и описанием парковочных зон получены на Портале открытых данных Правительства Москвы в формате GeoJSON при помощи ключа API. В примере использованы данные от 17 октября 2017 года, они могут не соответствовать реальному состоянию парковок на текущий момент. Для удобства работы метаданные объектов были извлечены из поля attributes отдельным скриптом, полученный результат загружен в систему ORBISmap (слой parking) и отображен в режиме просмотра геометрии.

Для отображения районов Москвы сделана выгрузка соответствующих данных из открытого картографического веб-сервиса OpenStreetMap, после чего также загружена в ORBISmap (слой moscow_al8).
Используем этот слой как подложку для визуализаций, отображающую контуры районов города.
В слое parking не содержится информации о районе Москвы, в котором расположена парковочная зона, поэтому создадим два виртуальных слоя, которые подготовят данные для визуализаций:

  1. Средняя стоимость часа парковки (слой moscow_al8_parking_price):
SELECT
moscow_al8.orbis_id,
moscow_al8.geom,
moscow_al8.localname AS name,
AVG(parking.place_price) AS price
FROM moscow_al8
INNER JOIN parking
ON parking.place_price IS NOT NULL
AND parking.place_period = 'Цена за час'
AND ST_Contains(moscow_al8.geom, parking.geom)
GROUP BY
moscow_al8.orbis_id,
moscow_al8.geom,
moscow_al8.localname
2. Количество парковочных мест (слой moscow_al5_parking_count):
SELECT
moscow_al8.orbis_id,
moscow_al8.geom,
moscow_al8.localname AS name,
SUM(parking.countspaces) AS places
FROM moscow_al8
INNER JOIN parking
ON parking.place_price IS NOT NULL
AND parking.place_period = 'Цена за час'
AND ST_Contains(moscow_al8.geom, parking.geom)
GROUP BY
moscow_al8.orbis_id,
moscow_al8.geom,
moscow_al8.localname

SQL-запросы очень похожи и отличаются только последним выражением в блоке SELECT. Оба запроса выбирают (оператор SELECT) из слоя районов Москвы (FROM moscow_al8):

  • уникальный идентификатор объекта (колонка orbis_id),
  • геоданные (колонка geom),
  • название района (колонка localname) с псевдонимом name.
При этом, c выборкой из moscow_al8 объединяются данные из таблицы парковок (INNER JOIN parking) со следующими условиями (ON):

  • parking.place_price IS NOT NULL — должна быть указана стоимость парковки,
  • parking.place_period = 'Цена за час' — нас интересует только стоимость часа парковки,
  • ST_Contains(moscow_al8.geom, parking.geom) — функция PostGIS, проверяющая, что все точки геометрии объекта парковок (parking) находятся внутри региона Москвы (moscow_al8).
На данном этапе результатом работы запроса является объединение двух множеств по нескольким условиям. Объекты, не удовлетворяющие условиям объединения, отбрасываются (INNER JOIN).

По условиям задачи данного примера необходимо получить агрегированные данные по районам Москвы, поэтому выборки группируются (GROUP BY) по тем же колонкам, что были перечислены в блоке SELECT. Таким образом определяются категории объектов, по которым осуществляется группировка данных. Для таких категорий могут быть вычислены выражения, использующие агрегирующие функции — такие как COUNT (количество объектов), SUM (сумма), AVG (среднее) и другие.

Теперь отличающиеся строки запросов должны стать понятнее:

  1. вычисляется средняя цена в каждой категории сгруппированных объектов:

AVG(parking.place_price) AS price
2. Суммируется количество мест на парковочных зонах в каждой категории:
SUM(parking.countspaces) AS places
Для созданных виртуальных слоев задано отображение в режиме тематической карты, а также настроена публикация.
Средняя стоимость часа парковки
Количество парковочных мест
Готовый пример

Ссылки
  • Ознакомиться со всеми возможностями геоинформационной системы ORBISmap можно на сайте продукта.
  • Подробнее о языке SQL и особенностях СУБД PostgreSQL можно узнать в документации.
  • О возможностях расширения PostGIS можно узнать на сайте GIS-Lab.