OpenStreetMap

Как я отмечаю POI – Метаданные

Posted by Anton Khorev on 19 June 2018 in Russian (Русский).

Почему пришлось взяться за POI

Если мы посмотрим на карту в масштабах города, то самыми важными объектами на ней будут, скорее всего, улицы, затем дома с адресами, а затем POI. На счёт этого порядка важности можно поспорить, некоторые утверждают, что без адресов карта бесполезна, хотя мне кажется, что это преувеличение. Лично я ближайшие POI помню не по номеру дома, и на вопросы, где находится дом номер такой-то обычно ответить не могу. Кстати, нередко такие вопросы задают рядом с искомым домом, после чего я проверяю, есть ли табличка с номером, и обычно она есть.

Дальше встречаются разные мнения, какие именно разновидности POI важнее. Например, кто-то скажет, что аптеки. На вопрос, что важнее – магазин или столовая, я пока решил не отвечать, и заняться всеми POI, которые подходят под определение, которое я приведу в одной из следующих записей. POI, которые под него попадают, выделены мной не по степени важности, а по степени находимости на местности и скорости изменений.

Мы знаем, что объекты на местности могут меняться, причём разного рода объекты будут меняться с разной скоростью. Из перечисленного выше, улицы меняются редко: иногда появляются новые, иногда продлеваются старые, иногда у них меняется название, и можно считать, что они практически никогда не исчезают. Правда, они могут закрываться на ремонт, что важно для навигации, но за этим не так сложно уследить, потому что самих улиц мало относительно других перечисленных выше объектов. Здания тоже меняются редко: иногда строятся новые, иногда перестраиваются старые. Во временных масштабах существования осма, отрисовка зданий – почти одноразовое дело.

Другое дело – магазины, кафе и т.п. По весьма примерным подсчётам их «время полураспада» составляет 5 лет. То есть если вы их все отметите и подождёте 5 лет, половина из них уже не будет существовать. И если их много, то найдётся какой-нибудь магазин, который закроется или откроется практически сразу после вашей проверки. А их очень даже может быть много – так много, что они на рендер не поместятся. Значит, просто один раз сходить и отметить подобного рода точки, а затем считать, что дело сделано, не выйдет.

Я хочу, чтобы данные о POI в осме были как можно ближе к действительности. Ясно, что для этого придётся перепроверять уже однажды проверенные места. Решать вопрос, куда и когда идти проверять можно по-разному, но при этом не обойтись без информации о том, когда производилась предыдущая проверка. Есть ли в данных осма такая информация?

Время проверок

Первое, что можно вспомнить, это время создания пакета правок. Однако, это время вовсе не обязательно совпадает со временем, когда редактирующий участник видел точку на месте. Строго говоря, оно всегда не совпадает, потому что правка делается позже проверки. Можно, конечно, пытаться делать правку сразу, но часто бывает некогда. Например, я сначала ставил себе задачу вводить данные на следующий день после проверки, потом срок превратился в две недели, теперь я рад, когда отстаю меньше, чем на два месяца. Иногда правка точки вообще не означает, что участник её видел или проверял каким-либо другим способом, например, сдвиг здания вместе со всем его содержимым или замена url. Короче, время проверки надо брать из какого-то другого места.

Вторая идея – пользоваться тегом check_date. Для POI он редко используется, так что первый недостаток – то, что придётся тегировать под x, где x – организация процесса обновления данных о POI. Может возникнуть вопрос, а уместна ли в принципе простановка на точки, линии и отношения тега check_date и подобных ему метаданных. Если нет, то мы могли бы его ставить на пакет, ведь у пакетов тоже есть теги. Тогда, правда, придётся аккуратно делать пакеты, чтобы они не затрагивали лишнего. Такая же проблема была бы и при использовании даты создания пакета, но проблема эта не единственная.

Другим источником проблем является то, что проверять приходится не сами точки, ну или не только сами точки, а ещё и места, где эти точки могут быть. Изначально в данных осм точек нет, так что и check_date искать не на чем. Допустим, мы ставим дату проверки на пакет, и список пакетов, в которых её надо искать, мы составим вручную, чтобы не просматривать все пакеты, затрагивающие интересующее нас место. Но что нам делать, если мы пройдём по месту, и увидим, что в соответствующих ему данных ничего менять не надо. Например, там как не было POI, так и нет. Тогда и правок делать не надо, пакет создавать не из чего, дату проверки писать некуда и читать неоткуда. И, вообще-то, мы так и не определили, что такое интересующие нас места. В осме таких объектов точно нет.

Места проверок

Становится понятно, что придётся задать информацию о местах за пределами данных осма, и информацию об их проверках тоже хранить не в осме. И подобное уже реализовано в MapCraft. Но эти нарезки носят одноразовый характер: вот вам участок, где что-то не нарисовано, пойдите нарисуйте, затем отметьте, что задача выполнена и всё. А у нас – не всё, нам надо перепроверить участок через некоторое время, и сами участки должны быть определены с учётом таких перепроверок.

Нарежем всю территорию, которую хотим проверять, на участки по-своему. Участки нам нужны достаточно небольшие, чтобы каждый из них можно было целиком проверить за один заход. Большинство интересующих нас POI видны с улицы, следовательно в качестве участков подойдут части кварталов, выходящие на определённые улицы. Так можно будет проверить весь участок, даже если он не являлся целью похода. Просто идём мимо, вдруг появляется желание помапить, и начать мапить можно, дойдя до следующего перекрёстка.

Естественное желание – сделать участки непересекающимися, чтобы любая точка попадала только в один из них. Но так не выйдет, потому что некоторые заведения находятся на углу квартала, причём даже вход в них находится прямо на углу. Да и физически POI не являются точками, а значит никто не мешает рисовать их полигонами, а полигон запросто может пересечься с несколькими участками. Полигоны для POI, правда, обычно не используют, к причинам этого мы ещё вернёмся. Итого наши участки могут перекрываться, особенно на углах кварталов, и POI может находиться одновременно в нескольких участках.

Помимо POI, выходящих на улицу, есть ещё POI во дворах, подземных переходах, торговых комплексах, бизнес-центрах. С ними иметь дело сложнее, и они для меня являются второстепенной задачей. Первая сложность тут ещё со сбором данных: их не видно с панорам улиц, и gps рядом с ними не работает, значит пройтись на месте с OsmTracker’ом, а вводить уже потом за компом не получится. Поэтому я пока не брался за ТК и не решил, на какие участки их делить. Весь ТК как один участок – это, наверное, слишком много с точки зрения «целиком проверить за один заход». Если делить, то, видимо, на этажи, хотя тогда получатся не просто перекрывающиеся участки, а полностью совпадающие в проекции на плоскость, а это по ряду причин неудобно.

Со внутриквартальными POI есть свои сложности. В центре Петербурга, как правило, зайти во двор можно через арку, а далее пройти можно только в ограниченную часть квартала. Часто из двора определённого дома никуда попасть нельзя, кроме как обратно на улицу. В этом случае можно сделать участком весь этот двор. Но если таким образом доступна большая часть квартала, да и сам квартал большой, то делить на участки придётся как-то по-другому. В новостройках придётся, видимо, делить вдоль внутриквартальных проездов. Мне это предстоит делать уже и в Центральном районе рядом с Московским вокзалом.

Метаданные проверок

Поскольку для начала я решил никаких инструментов не писать, то и сохранять данные пришлось самым примитивным способом. Это был csv-файл с записями (название участка, дата проверки, пакет правок). Название участка служит его идентификатором и обычно выглядит как (название улицы, тип улицы, диапазон номеров домов). Конечно, в будущем это должно стать таблицей в базе данных, и тогда идентификатором участка мог бы быть суррогатный ключ ещё одной таблицы с данными об участках. Но при редактировании вручную суррогатный ключ, то есть число, которое само по себе ничего не значит, использовать неудобно.

Информация о том, когда была произведена проверка, представлена в виде даты. Точнее даты время мне знать не нужно, соответственно я не слежу за тем, во сколько часов сколько минут я начал проверять определённый участок, главное, чтобы это было время регулярной проверки, об этом позже. Другой вопрос – не нужно ли специально хранить менее точные данные, например, из соображений privacy. Когда я начну принимать данные от других участников, мне, возможно, придётся вернуться к этому вопросу. По поводу намеренного предоставления менее точных данных есть две точки зрения. Одна из них – что для недавнего времени надо давать менее точную информацию, а позже её можно уточнить. Другая – что наоборот по прошествии времени данные надо делать менее детальными. Мне больше подходит первый вариант, в том числе потому что он получается сам собой. Собранные данные я ввожу не сразу, так что если вы захотите узнать, где я сейчас нахожусь, глядя на предоставляемые мной данные о проверках участков, то я уже давно оттуда ушёл. Вторая точка зрения связана с тем, что при точных данных о том, где кто когда был, идущих далеко назад по времени, можно сделать вывод, какие места данный человек имеет обыкновение посещать, например, в определённый день недели. Но те места, информацию о которых я ввожу в рамках данных проверок – это не те места, в которые я хожу с какой-либо другой целью. В большинство проверяемых заведений я вообще не захожу.

Что касается третьего элемента в записи – номера пакета правок, то как мы уже знаем, его может и не быть. Соответственно, уже с самого начала его указывать было необязательно. Тут можно поинтересоваться, зачем в принципе записывать пакет, ведь дата проверки берётся не из него. В данный момент это просто средство для меня, чтобы искать пакеты правок, относящиеся к определённому месту. По обычной истории правок это делать неудобно. В идеале хотелось бы иметь способ получить всю информацию по POI, признанную мной правильной на момент проверки, и она содержалась бы в пакете, если бы правки в обязательном порядке затрагивали все точки и, желательно, ничего кроме точек. Но это не так, хотя отчасти я пользуюсь записанными пакетами в качестве временного средства сделать snapshot данных. (примечание на июнь 2018: кое-что поменялось между написанием и публикацией; собственно snapshot уже делается, и полей в соответствующем csv-файле уже не три)

Далее обнаружилось, что не всегда реально сделать правки для всего участка за один заход. Соответственно, пришлось разрешить указывать множество пакетов правок для одной проверки. Связано это с тем, что попадаются участки, на которых может быть хоть пятьдесят POI, например, Лиговский проспект между площадью Восстания и Транспортным переулком (1, 2), и это если исключить из него Московский вокзал и «Галерею». Придумывать особенный способ деления на участки поменьше для «POI-плотных» мест мне не хочется, так как при текущем способе деления границы участков очевидны даже без разглядывания картинок, где они нарисованы, тем более, что изначально они не были нарисованы.

Метаданные участков

Сначала данные об участках содержались в первую очередь в их названиях. Названия эти состоят из названий улиц и диапазонов номеров домов. Названия улиц не уникальны во всём субъекте федерации, но уникальны внутри центральных районов. В районах, включающих разные населённые пункты, типа Пушкинского, подобной уникальности может уже не быть, но ими я пока систематически не занимаюсь. Если к названию улицы добавить номера домов, то так можно задать сторону квартала, выходящую на определённую улицу – тот тип участков, которые я проверяю в первую очередь. Проблема тут в том, что номеров по нужной улице может не существовать. Улицами здесь я называю всё, что в Петербурге официально ими считается, и отображается зелёными линиями в rgis. Это включает и площади, а по ним часто не бывает номеров, тогда в название участка приходится вместо них писать, какая это сторона, например, юго-западная. Даже если номера и есть, то они не всегда очевидны, их может не быть в осме и так далее. Дополнительно к номерам я решил давать текстовое описание, которое позволит в сочетании с именем участка найти его, даже если я ошибусь с номерами. Сначала это привело к появлению ещё одного csv-файла с записями (название участка, описание).

Через некоторое время это стало неудобно, ведь по прежнему не было никаких машиночитаемых данных о расположении участков. Расположение можно задать, нарисовав полигон, покрывающий участок. Несвязные участки, для которых это не сработает, скорее всего, не понадобятся. Так как я ввожу данные из josm, то и участки легче рисовать в нём же. Поскольку участки не являются данными осма, то их можно держать в отдельном слое. В нём можно рисовать полигоны и задавать им теги name и description для того, что было в csv-файле. Данные самих проверок, в принципе, тоже можно было бы сохранять в тегах полигона, но это менее удобно, и пока я этого не делаю. Слой с участками сохраняется в файл, а не закачивается в базу осма.

Недостатки у работы со слоем-файлом такие:

  • А вдруг его случайно закачаешь, тем более, что josm будет предлагать это сделать, если вносить изменения. К счастью, вскоре после того, как я перешёл к использованию слоя, в josm была добавлена возможность запретить закачивать слой, если в его файле есть xml-атрибут upload='never', поставленный на корневой элемент. Достаточно один раз его вручную поставить, и этот недостаток исчезает.

  • А вдруг в него случайно скачаешь данные осма, ведь их в нём быть не должно. Операцию скачивания ещё и нельзя отменить, так что приходится следить, какой слой выбран, и хранить версии файла, например, в git, чтобы в случае скачивания и сохранения лишних данных можно было бы откатиться к «чистой» версии. Впрочем, недавно был добавлен и атрибут download='never'.

  • josm всё-таки предназначен для редактирования данных осма, и у всех объектов должен быть осмовский идентификатор. А какие идентификаторы у объектов, которых в осме нет и не будет, то есть у наших участков? Всему, что не закачано, josm даёт временные идентификаторы – отрицательные числа - но нет гарантий, что они постоянны. А если мы начали пользоваться системой контроля версий, то изменения идентификаторов для нас нежелательны. Можно попробовать переустановить идентификаторы перед записью в git так, чтобы изменений было поменьше, но пока я этим не занимаюсь.

Теперь у нас есть набор метаданных, пригодный, например, для визуализации свежести данных POI. Про сами эти не-мета-данные POI будет написано в одной из следующих записей дневника.


Login to leave a comment