Обсуждаем новые структуры данных API, избавляемся от строка=строка

Объяснение почему не нужно парсить ключи чтобы спросить все amenity=
Объяснение почему в рамках API 0.6 приходится парсить sport:billiards: у части key=
Объяснение почему нужно столько ключей, какие преимущества при маппинге для обычного пользователя
Предложение избавится от ключей вообще, писать текст и размечать его по желанию

В чем проблема старых key=value? Мапперы злопооутребляли частью “value”, когда этого делать не стоило. Постоянные вопросы “как обозначать X” это симптомы проблемы. Беда в онтологии и классификации тегов.

amenity=* - ничего не значит этот ключ.
man_made - всё подряд лепят в man_made, “потому что их много” и он не рендерится пока ещё
leisure/amenity - кто вообще додумался до такой классификации. Ну да ладно. Теперь это будут просто исторические префиксы.

Попытаюсь сейчас целую науку объяснить на пальцах.

Если у нас было


здание=да (building=yes)

То когда мы хотим указать свойство объекта мира (здание), мы не пытаемся его прилепить в значение старого свойства.


здание=да; 3 этажа

Мы вводим новый тег, с новым смыслом


здание=да  (building=yes)
здание:колвоэтажей=3  (building:levels=3)

Если у здания есть крыша, то в терминах OSM нужен новое свойство-подтег:


здание=да
здание:колвоэтажей=3
здание:крыша=есть

Если у крыши есть цвет то его нужно указывать как свойство у крыши (которое свойство здания)


здание=да
здание:колвоэтажей=3
здание:крыша=есть
здание:крыша:цвет=есть

Если у крыши есть **определённый цвет **то его нужно указывать как свойство у цвета, которое свойство крыши, которое свойство здания:


здание=да
здание:колвоэтажей=3
здание:крыша=есть
здание:крыша:цвет=есть
здание:крыша:цвет:определённый=красный

OSM API 0.6 убог и считает что двух цветов у крыши не может быть:


здание:крыша:цвет:определённый=красный
здание:крыша:цвет:определённый=жёлтый

API нужно менять чтобы можно было указывать несколько значений:
здание:крыша:цвет:определённый=[красный, жёлтый] - массив

Пример с цветами крыш на самом деле плохой

Для рендера мы используем hex-значения цветов: http://taginfo.openstreetmap.org/keys/building%3Aroof%3Acolour#values

Тем не менее возникают ситуации когда нужно отмечать несколько значений. Хороший пример был с разновидностями бильярдов.

В новом (никем не разработанном API) это можно представить так:
sport:billiards=yes
sport:billiards:type=[“pool”, “snooker”, “pyramid**:10ft**”, “pyramid**:12ft**”]

Как вы могли заметить, значениями value здесь опять злоупотребляют, поэтому приходится вводить отдельное свойство для размера стола:

sport:billiards:table_size = [pool:(7ft, 8ft), snooker:(9ft, 12ft)]

Сложность онтологий растёт колоссально быстро. Тем сумашедшим котортые пытаются обработать её самым формальным языком на земле (регулярными выражениями, автоматами) я предлагаю остудить пыл и признать фиаско до того как потратят всю свою жизнь на составление онтологии мира (мега-регулярки, которая “теперь точно и безошибочно обработает этот ключ”, ещё одного геокодера, ещё одного рендера).

Отказ от слишком жёстких и на деле не работающих тегов совсем

Более адекватный подход был предложен с использованием свободного для написания **простого текста **и свободного для разметки смысловыми конструкциями:

фигурные скобки - ограничитель смысла (в программировании это неймспейс)
хеш-тег - это старые теги магазинов которые мы импортируем из старой базы. shop=tea станет #shop:tea, shop=yes станет shop
элементы разметки для разметки свойств хеш-тегов - пока неясно какой стандарт или подход выбрать лучше в рамках OSM

Чего будет не хватать при таком подходе?
Можно ли написать препроцессор который будет все запросы старых API (0.6, overpass) транслировать в поиск хеш-тегов и обработку разметки? С чем можно столкнуться?

В целом, если делать новую структуру данных (мы же тут об этом говорим, а не о новой схеме тегирования в текущей базе?), то у тегов нужно просто отбросить потерявший смысл value. Точнее потерялся смысл деления на ключ и значение: эта граница стала очень размыта. Ключ тега и так может содержать все необходимое. Т.к. уже широко используются сложные неймспейсы типа lanes:psv:forward=1, то почему бы этот “1” не сделать частью самого тега (ключа): lanes:psv:forward:1. К тому же сейчас существует куча тегов у которых значение просто yes - это бессмысленно.

Можно просто иметь теги “shop”, “shop:cloth”, “oneway”, “building:levels:3”, “maxspeed:backward:60”, “highway:service:driveway”, “opening_hours:Mo-Fr:10:00-20:00”. При этом остается в силе правило одним тегом не помечать дважды (да и в этом просто не будет смысла)

Кроме того можно продолжать использовать множественные значения через “;” (в рамках одного неймспейса). Просто как сокращение записи: shop:cloth + shop:shoes = shop:cloth;shoes

По примеру с бильярдом:

sport:billiards:pool;snooker
sport:billiards:table_size:pool:7ft;8ft
sport:billiards:table_size:snooker:9ft;12ft
working_hours:pool:Mo-Fr:10\:00-20\:00
working_hours:snooker:Mo-Fr:20\:00-23\:00
working_hours:snooker:Sa:10\:00-19\:00;20\:00-23\:00

ИМХО много повторений, но раз уж мы фантазируем на тему тегов, то неплохо бы подошла бы схема вроде JSON. Вот например для спортивного центра:


object:
{
	"name":"Спортивный центр по прыжкам в воду и фигурному катанию имени Саутина и Сихарулидзе",
	"building":
	{
		"type":"public",
		"levels":"2",
		"height":"15m",
		"material":"brick",
		"roof":
		{
			"shape":"flat",
			"material":"rubber"
		}
	}
	"sport_object":
	{
		"type":"center",
		"facilities":["ice_rink","swimming_pool","gym"],
		"sports":["swimming","skating","jumping"]
	}
}

Теги совершенно от балды, чисто проиллюстрировать принцип. И не нужно повторять трёхэтажные ключи.

API, грубо говоря, менять-то и не надо. В XML можно передавать и два одноименных тега. А вот хранение и обработку тогда надо менять.

	<node id="265663798" lat="44.5685688" lon="33.4544987" version="5">
		<tag k="amenity" v="restaurant"/>
		<tag k="amenity" v="pub"/>
	</node>

Вы просто не поняли одной простой вещи, что “building=yes” это вовсе не “здание=да”, а “здание=на знаю точно какого типа (iшкола/многоквартирный дом и т.п.) и при случае надо бы поставить правильный тип”.
В highway ровно для этих целей используют highway=road

Поэтому логично, что для указания другого свойства у этого здания используют другой тег, а не тег типа здания.

Ну и далее

здание:крыша=есть

здание:крыша=лениво уточнять тип, покатая или еще какая, сделайте это за меня, кто в курсе

Исходя их этого

здание:крыша:цвет=есть

безумие. Ибо на самом деле получаем
здание:крыша:цвет=не знаю какой

highway=road подтверждает что есть дорога
building=yes подтверждает что есть здание (здание=да)

highway=road не указывает **конкретный тип **дороги (highway=primary, highway=service, …)
building=yes не указывает **конкретный тип ** здание (жилое. производственное)

Что я не понял и как это противоречит с моим высказыванием?

Это не нормально, это заляпа , такой фиксми. То есть тут принципиально не булева переменная. Не наличие, но тип!
И верное значение ее нельзя вывести из одного только наличия building:level

API 0.8 должен в какой-то степени (указывается в параметрах запросов к API) позволять “разворачивать” вложенность структур:

К JSON-у не думаю что стоит прибегать потому что мы и так xml пользуемся (osmosis переписывать не ok) да и типизация в JSON костыльная http://json-schema.org/, а не десятилетиями рабочий xsd.

Тем кому нужен будет xsd - будут его использовать, тем кому не нужен навязывать его не будем, от XML точно отказываться не нужно. Пытаться добавлять JSON как дополнительный формат ответа от API (параллельно XML) - да.

Это потому что некоторые мапперы пытались засунуть два смысла в один тег вместо двух смысловых ключей:
building=yes
building:type=fixme

building:levels=2
building:height=15m
building:material=brick
building:roof:shape=flat
building:roof:material=rubber

Выводим обратно старые значения
Наличие building:roof:* говорит, что надо не то building:roof=yes , не то building:roof=shape,rubber .
получаем

building:levels=2
building:height=15m
building:material=brick
building:roof=yes 

Дальше сводим не то к building=yes, не то к
building=levels,height,material,roof

Наличие building:roof:* по старой схеме ни о чём не говорит, новые смысловые конструкции придётся дополнительно обрабатывать с учётом сюрпризов
highway=road
building=yes который некоторые считают еще “неопределённым типом”

Ну это можно учесть до какой-то разумной степени. Это же режим совместимости с 0.6 в котором все неоднозначности не получится разрешить в принципе изза строка=строка.

Нагромождений вида building=levels,height,material,roof можно избежать написав код-обработку. Для всех данных в OSM - нет, для большинства POI ключей (sport, amenity, shop, leisure) и building-ов - скорее да чем нет.

Ну я продолжу выступать за “свободный” синтаксис, а не JSON/XML, перегруженный, ИМХО, оформлением.


  #building
  #type: public
  #levels: 2
  #height: 15m /замерено на глаз
  #material: brick  /красный кирпич
  {
    #roof
    #shape: flat
    #material: rubber  /уже поизносилась
  }

Спорт-центр


#sport
#type: center
#facility: ice_rink
#facility: swimming_pool
#facility: gym
#sports: swimming
#sports: skating
#sports: jumping

Биллиарды:


#sport
#facility: pool
#facility: snooker
{
  #pool
  #table_size: 7ft
  #table_size: 8ft
  #opening_hours: {Mo-Fr 10:00-20:00}
}
{
  #snooker
  #table_size: 9ft
  #table_size: 12ft
  #opening_hours: {Mo-Fr 20:00-23:00; Sa 10:00-19:00,20:00-23:00}
}

От # тоже можно избавиться, если условиться что первый не-пробел в строке должен быть либо началом “тэга”, либо { / }, либо / для комментария

С текстом пора кончать! HDF5 рулит! :wink:

Вы ещё ASN.1 предложите :slight_smile:
Текст удобнее тем, что для него много средств по сравнению, синхронизации, версионности, слияния и прочего.
Да и живут текстовые форматы дольше, ИМХО, - пока на них есть документация. А бинарные - пока есть рабочий софт по их парсингу. :slight_smile:

вопрос такой: главный тэг (#sport в данном случае) предполагается только один? или допускаем несколько?

Можно избавиться от знака равно, если он чем-то не угодил, и заменить его на двоеточие.

Но как можно избавиться от именованных атрибутов?

Например, есть дорога, она асфальтирована, она односторонняя, на ней две полосы, ограничение скорости 40 км/ч, и есть название – улица Космонавтов.

Что и как нужно распарсить, чтобы узнать ограничение скорости и название?

Допускаем, конечо.
#sport” это по сути “#sport: yes”

В “моём” синтаксисе - не надо избавляться :slight_smile:


#highway: primary
#name: {улица Космонавтов}
#max,speed: 40  /знак
#surface: asphalt
#oneway
#lanes: 2

Такое не предлагается. Это основа онтологии и вменяемых информационных систем, кто бы и что про неё не думал.

Мы прячем старые говорливые теги в иерархии меток. Метки могут быть иерархичны (метка ##shop:tea зависит от #shop), а могут быть полностью независимы (более адекватный подход, позволяет несколько таксономий, которые если очень хочется можно потом объединить новой более общей меткой или зависимостью от другой метки)

В недоработанной онтологии OSM пользователи путают атрибут (key=value) и понятия (##метка у семантической коробки). Класса объекта в OSM нет. Нет машинно-читаемого архетипа, если вам будет проще.

Проблема в том что главная ##метка меняется:

  • пишете ли вы рендер (для всего мира, только для одной страны)
  • пишете ли вы геокодер (самая сложная задача для всего мира вообще, ответы на вопрос “как назвать этот объект?”)
  • что является для вас “спортом” (бокс - нет, шахматы - да, фигурное плавание - нет, компьютерные игры - нет)
  • интересны ли для вас только группы спортов (только бильярды)

Вопрос сложный, зависит от цели для которой вы хотите распарить объект. На понятийном уровне нужно учитывать семантические коробки (фигурные скобки у синтаксиса OverQuantum:


##highway
{
    #surface: asphalt
    #oneway: true
    #lanes: 2
    #maxspeed: 40
    #name: улица Космонавтов
}

Т.е. чтобы распарсить такую структуру (я специально сделал #highway похожим на данные из OSM) для графа дорог логика будет очень похожа на предыдущую:

  1. Если встречаешь у коробки #highway, то тебе эта группа тегов (коробка) как минимум интересна (валидация)
  2. Если противоречивых тегов нет у коробки #highway ##nothighway, то можно собственно приступать к извлечению данных
    2.1 можно останавливаться если встречаются метки, отличные от вашего белого списка
    2.2 можно продолжать извлекать данные, на свой страх и риск (те метки могут значить “это не дорога”, а могут не значит ничего ##ufo или вам не мешать ##namedobject)
  3. Извлекаем только те атрибуты которые нам интересны (не нужно имя для графа дорог) и умываем руки

тот же самый объект реального мира могут замапить как


##namedobject
{
     #name: улица Космонавтов
     #name:ru: улица Космонавтов
     #name:en: Kosmonavtov street
     #description: угадываю название на Английском
}
##highway
{
    #surface: asphalt
    #oneway: true
    #lanes: 2
    #maxspeed: 40
    #name: улица Космонавтов
}

Геокодер может обрабатывать только коробку с ##namedobject если хочет работать быстро или “смотреть атрибуты только для него”. Тегирование под роутинг, геокодинг и рендеринг (#hex-значения, которых в реальном мире-то нет) это вообще-то, нормально. Просто делать нужно в отдельных для этого местах, чтобы людей не смущать.

“Постойте-ка в реальном мире только одно имя, мы тут сущности плодим”.

В этом вся соль и есть. Онтологии не строятся из абстрактных побуждений ##объектмира, ##боженькасотворил.
Вместо этого абсолютно все пользователи будут использовать самые-самые практичные для них онтологии:

  • #shop // не самая лучшая идея, я бы сразу использовал ##sells:goods и ##sells:services
  • #highway
  • #poi // плохая категория, я бы такую не стал использовать

Что делать если на вашу очень осмысленную коробку покушаются какой-то непонятной меткой? Завелось тут ##ufo понимаешь, что с ними делать теперь. Ну во-первых, спросить у автора метки ##ufo (до этого дооооооолгий и мучительный процесс принятия тегов) что он хочет с ней делать или посмотреть что он написал в её описании на вики, может быть она вам не навредит с её атрибутами.

Если не походит чья-то метка, делайте копию старой вашей коробки. Например: у вас было #highway {}, кто-то пришел и указал #highway #poi {}

Эту схему poi вы считаете непримиримой к данному объекту реального мира, у вас пасинг ломается от её специфических атрибутов схемы #poi. Эту ситуацию мы всегда видим у приверженцев тега type=. **У одних одно, у других он значит **другое.

Поэтому вы копируете старую коробку только с #highway и не мешаете людям экспериментировать с #poi. Может он у них заработает и вы к них присоединитесь. Может нет, у вас будет своя коробка (и ваш любимый хеш-тег на ней).

(собирая мысли в кучу)

итак, имеем контору, которая:

  • продаёт б/у мотоциклы (японские):
  • торгует экипировкой для мото, квадроциклистов и велосипедистов;
  • предоставляет услуги ремонта мотоциклов;
  • предоставляет услуги зимнего хранения мотоциклов, скутеров и шин;
  • предоставляет услуги гос. тех. осмотра мотоциклов;

как я понимаю, можно будет её описать так:



#shop
{
  #motorcycles: japan            / как тэг б/у поставить не придумал
  #equip: motorcycles
  #equip: atv
  #equip: bicycles
}

#motorcycles
{
  #sale: yes                        / value yes можно в принципе опустить
  #type: enduro
  #type: sport
  #type: chopper
  #made: suzuki
  #made: honda
  #equip                            / подразумевается yes
  #winter_store
  #safety_inspection
}

#equip
{
  #motorcycles              / подразумевается yes
  #motorcycles: cross    / особо отметим продажу кроссовой экипировки
  #atv: winter                 / вот тут вопрос, только ли зимнюю экипировку продаёт магазин? нужно ли добавить просто тэг #atv, если не только?
  #bicycles
  #bicycles: contact_shoes
}

#safety_inspection
{
  #motorcycles
}

#winter_store
{
  #motorcycles
  #scooters
  #tires
  #temperature: 17C
}


это на первый взгляд избыточно, но при составлении карты пунктов техосмотра нам достаточно запросить только глав-тэг #safety_inspection и разобрать его нутро, а не копаться в под-тэгах тэгов вида shop=motorcycles, как ныне.
при карте пунктов зимнего хранения - то же самое, достаточно глав-тэга #winter_store
карта магазинов экипировки (вело, мото, квадро, горнолыжной, снегоходной, каякерской) - опять же: #equip и не будем отвлекаться на магазины, продающие мотоциклы и пункты мото тех. осмотров.
карта “магазинов вообще” получит достаточную инфу из тэга #shop

на мой взгляд - очень приятная схема для создания софта, использующего ОСМ получается.

p.s. конечно, подобную контору необязательно описывать столь уж подробно. но, если такая возможность будет - весьма удобно.

В синтаксе OverQuantum предлагаю различать #атрибуты=значния (обычно внутри скобок) и ##понятия (главные теги в старой схеме OSM, poi-теги).

Найдутся конечно люди которые будут настаивать что #motorcycles это подсвойство магазина, но мне тоже нравятся разные понятия.

  1. я бы назвал не одной меткой #motorcycles, а #sells:goods + #sells:goods:motorcycles
  2. #equip #winter_store #safety_inspection я бы убрал из старого #motorcycles
  3. #equip переименовал в #sells:goods + #sells:goods:motorcyclesequip + #sells:goods:equip
  4. вместо #safety_inspection бы добавил ##sells:service:safety_inspection у магазина или другого объекта, я сам не пойму о какой инспекции идёт речь, для чего
  5. #winter_store добавил бы теги #sells:goods:motorcycles + #sells:goods:scooters + #sells:goods:tires

Пример обсуждаем достаточно абстрактный, трудно сказать как лучше описать его сразу. Т.е. я хотел сказать что классы объектов вам гораздо важнее чем свойства внутри него при поиске/фильтрации/обработке.

Классами объектов в идеале нужно пользоваться так, чтобы потом на них использовать логику множеств, причем не обязательно непересекающихся. некоторые запросы будут ломаться, впрочем, как и сейчас в OSM :slight_smile: