protector (11 Декабрь 2020 - 00:55) писал:
Как сделать через геокодер, я знаю. Но это слишком сложно для такой простой вещи. Хочется просто
Полные ссылки - это какие? У меня из данных есть только адрес: город, улица, дом. Хочу по клику по ссылке, сразу открывалась яндекс.карта с данным адресом и маленьким масштабом, чтобы сразу было видно: внутри МКАД или за МКАД.
P.S. Знаю можно спрограммировать, чтобы автоматом мне в системе заказов писалась подсказка: внутри кольца или нет... Но пока влом программировать.
Я разобрался, геокодер за вечер можно накидать, достаточный для для этой задачи.
Качаем последние данные с OSM для Центрального округа,
wget http://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf
Обрезаем примерно по границам Старой и новой Москвы
osmium extract -b 36.80,55.14,37.97,56.02 central-fed-district-latest.osm.pbf -s simple -o moscow.pbf
Закидываем всё в postgresql с подключенным postgis и hstore.
imposm3 import -config imposm3_config.json -read moscow.pbf -dbschema-import public -write -overwritecache
imposm3_config.json
{
"cachedir": "/tmp/imposm3_cache",
"mapping": "mapping.yml",
"connection": "postgis://user:pass@127.0.0.1/geocoder"
}
mapping.yml
tables:
buildings:
type: "polygon" # тип геометрии используемый для таблицы, по сути, говорим что будем брать данные из таблички multipolygons
mapping: # фильтрация по наличия поля, и значению в этом поле
building: [__any__] # любое не NULL значение, какие значения бывают https://wiki.openstreetmap.org/wiki/RU:Key:building
columns: # перечисляем поля таблицы
- {name: osm_id, type: id} # идентификатор OpenStreetMap
- {name: geometry, type: geometry} # геометрия
- {key: name, name: name, type: string} # поле с именем объекта
- {key: "addr:street", name: street, type: string} # улица
- {key: "addr:postcode", name: postcode, type: string} # почтовый индекс
- {key: "addr:city", name: city, type: string} # город
- {key: "addr:housenumber", name: housenumber, type: string} # номер дома
- {key: "addr:quarter", name: quarter, type: string} # квартал
cities:
type: "polygon" # тип геометрии используемый для таблицы
mapping:
place: # кто есть кто можно посмотреть тут https://wiki.openstreetmap.org/wiki/RU:Key:place
- city # крупные города
- town # средний или малый город
- village # посёлок городского типа
- hamlet # Любой сельский населённый пункт размером от двух-трёх домашних хозяйств, не подходящий под критерии village
- allotments # всякие СНТ, ДНТ и т.п.
- isolated_dwelling # хутор
- neighbourhood # микрорайоны, кварталы и т.п.
- suburb # пригороды
- locality # заброшенные деревни, урочище
columns:
- {name: osm_id, type: id}
- {name: geometry, type: geometry}
- {name: type, type: mapping_value}
- {key: name, name: name, type: string}
- {key: "addr:country", name: country, type: string}
- {key: "addr:district", name: district, type: string}
- {key: "addr:region", name: region, type: string}
- {key: "addr:postcode", name: postcode, type: string}
- {key: population, name: population, type: string}
- {key: "population:date", name: population_date, type: string}
- {key: official_status, name: official_status, type: string}
заполним незаполненые значения поля city в таблице osm_buildings:
UPDATE osm_buildings b
SET city = c.name
FROM osm_cities c
WHERE st_contains(c.geometry, b.geometry) AND coalesce(b.city, '') = '';
Дальше можно подключить словари сокращений, но у меня что-то никак не завелось, упущу эту часть (это чтобы запрос содержащий ул и улица давали одинаковый результат).
Добавим функцию, чтобы потом индекс построить:
CREATE OR REPLACE FUNCTION make_tsvector(city text, street text, housenumber text)
RETURNS tsvector
IMMUTABLE
LANGUAGE plpgsql
AS $$
BEGIN
RETURN (to_tsvector(city) || to_tsvector(street) || to_tsvector(housenumber));
END
$$;
Добавим индекс:
CREATE INDEX IF NOT EXISTS osm_buildings_address_gin_index ON osm_buildings
USING gin(make_tsvector(city, street, housenumber));
Ну и далее простым запросом получаем координаты:
SET DEFAULT_TEXT_SEARCH_CONFIG=russian;
SELECT osm_id, city, housenumber, street
FROM osm_buildings
WHERE make_tsvector(city, street, housenumber)
@@ plainto_tsquery('Москва Проспект мира');
Выдаст все соответсвия, можно брать только первый, можно все и находить centroid.
Позже гляну как спарсить из OSM координаты МКАДа и функцией проверять внтури него или вне находится эта точка.