Где лучше жить можно выбирать как по привлекательности места, так и избегать заведомо некомфортного для вас окружения. И если привлекательность района обычно преукрашивается риэлторами, то недостатки скорее всего окажутся сюрпризом, когда начнете жить в новом месте. На сайте аренды жилья мне часто попадались квартиры "почти у метро в хорошем районе" симпатичные на фотографиях, при просмотре которых в голове крутился мотив песни "Мусорный ветер, дым из трубы" иногда и с транспортной доступностью в реальности проблемы были не меньше.

Визуальные фантазии нейросети для следующего абзаца...
Визуальные фантазии нейросети для следующего абзаца...

Если из окна видна труба завода из которой валит дым "кислотного" цвета, под другим окном оживленная автотрасса/железная дорога и летом не открыть окно из-за гари и громких сигналов транспорта, рядом с этим прелестным пейзажем видны дымок от крематория и кладбище. Когда решите выйти на балкон летом, то комары напомнят что совсем рядом есть заболоченный участок. Поздравляю, вы оказались в том самом месте!!!

Что общего во всех этих факторах, кроме того что я сгустил краски StableDiffusion? В описаном примере для многих людей есть не только экологическая, но психологически дискомфортная составляющая. В студенчестве в части диплома, связанной с экологией, были расчеты уровня шума в жилых помещениях от трассы/индустриальных объектов. Главный параметр был - расстояние по прямой от жилья.

К сожалению, объективная и структурированная информации про экологию и безопасность нового для нас места обычно не доступна. Скорее всего эти данные есть у префектуры, полиции и бизнеса которые с вами ей не поделятся. Все это уменьшит шанс на осознанный выбор нового места жительства.

Но даже без статистики по правонарушениям и без информации о реальном загрязнении воздуха мы все равно сможем избегать заведомо дискомфортных мест. К счастью, доступны геоданные OpenStreetMap.

Давайте напишем прототип запроса, по которому сможете понять где вероятнее всего вы бы не захотели жить. Хоть он основан на факторах, выбранных по моему личному мнению и они могут не совпадать с вашими предпочтениями. Можете изменять SQL запрос так, чтобы геоаналитика была больше похожа на ваш кошмар! И конечно же применим его к доступным для столицы геоданным и визуализируем их на карте.

Перед тем как начнем

Если не планируете воспроизводить процесс подготовки данных самостоятельно, то смело пропускайте следующий текст и пролистывайте до заголовка "Анализ данных для Москвы".

Подготавливаем данные для анализа

Этот раздел предполагает что вы знаете как работать с PostgreSQL и Linux. Я выполнял следующие шаги на Ubuntu, где установлены git, wget, docker.io

Скачиваем OSM геоданные сайта geofabric и извлекаем данные Москвы по полигону Russia_Moscow.poly.

mkdir moscow && cd moscow 
wget https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf
wget https://raw.githubusercontent.com/mapsme/omim/master/data/borders/Russia_Moscow.poly
docker run -rm -it -w /wkd -v $(pwd):/wkd mschilde/osmium-tool osmium extract --polygon Russia_Moscow.poly central-fed-district-latest.osm.pbf -o moscow.osm.pbf
Готовых выгрузок, к сожалению, не нашел

Данные с сайта https://download.openstreetmap.fr/extracts/russia/central_federal_district/ для столицы оказались не полные, что приводило к ошибке location for one or more nodes not found in node location index.

Загружаем утилиту openstreetmap_h3 подготовки данных OpenStreetMap для аналитики в PostGIS. Про нее я рассказывал в серии публикаций на Хабре.

Все как и раньше, с небольшими дополнениями

Во время подготовки этой статьи, я разобрался как запускать Docker in Docker для случая с openstreetmap_h3 и теперь не надо устанавливать JDK, maven. Все зависимости и сборка упакованы в докер образ. Не самое красивое решение конечно, но поскольку osmium используется сейчас как утилита командной строки в виде Docker образа, а не библиотека, то оставлю как есть.

git clone https://github.com/igor-suhorukov/openstreetmap_h3.git
cd openstreetmap_h3 && docker build -t openstreetmap_h3 .
cd postgis_docker-master && docker build -t postgres15_postgis .

Заходим в директорию, где подготовили moscow.osm.pbf и запускаем:

cd moscow
docker run -it --rm -w $(pwd) -v $(pwd):/$(pwd) -v /var/run/docker.sock:/var/run/docker.sock openstreetmap_h3:latest -source_pbf $(pwd)/moscow.osm.pbf -result_in_tsv true
Данные из moscow.osm.pbf будут готовы для загрузки в PostGIS в директории "moscow_loc_ways"
docker run -it --rm -w $(pwd) -v $(pwd):/$(pwd) -v /var/run/docker.sock:/var/run/docker.sock openstreetmap_h3:latest -source_pbf $(pwd)/moscow.osm.pbf -result_in_tsv true

[ 0:00] Started osmium add-locations-to-ways
[ 0:00]   osmium version 1.14.0
[ 0:00]   libosmium version 2.18.0
[ 0:00] Command line options and default settings:
[ 0:00]   input options:
[ 0:00]     file names: 
[ 0:00]       moscow.osm.pbf
[ 0:00]     file format: 
[ 0:00]   output options:
[ 0:00]     file name: moscow_loc_ways.pbf
[ 0:00]     file format: pbf,pbf_compression=none
[ 0:00]     generator: osmium/1.14.0
[ 0:00]     overwrite: no
[ 0:00]     fsync: no
[ 0:00]   other options:
[ 0:00]     index type (for positive ids): sparse_mem_array
[ 0:00]     index type (for negative ids): flex_mem
[ 0:00]     keep untagged nodes: no
[ 0:00]     keep nodes that are relation members: yes
[ 0:00] 
[ 0:00] Getting all nodes referenced from relations...
[ 0:00] Found 40919 nodes referenced from relations.
[ 0:00] Copying input file 'moscow.osm.pbf'...
[ 0:02] About 78 MBytes used for node location index (in main memory or on disk).
[ 0:02] Peak memory used: 809 MBytes
[ 0:02] Done.

0
188  time 14295
diff between total and processing 12765
total thread time 57059
total processing time 44294
total save time 4074
total waiting for save time 4120
thread max time 1024
processing max time 767
nodes 419908
ways 991744
relations 85883
relation members 875942
multipolygon count 54309
0	[-32768,4520)	10044611	37288
1	[4520,32695)	151011380	28175
2 10 80.5279955

[ 0:00] Started osmium export
[ 0:00]   osmium version 1.14.0
[ 0:00]   libosmium version 2.18.0
[ 0:00] Command line options and default settings:
[ 0:00]   input options:
[ 0:00]     file name: moscow.osm.pbf
[ 0:00]     file format: 
[ 0:00]   output options:
[ 0:00]     file name: moscow_loc_ways/multipolygon/source.tsv
[ 0:00]     file format: pg
[ 0:00]     overwrite: no
[ 0:00]     fsync: yes
[ 0:00]   attributes:
[ 0:00]     type:      @type
[ 0:00]     id:        @id
[ 0:00]     version:   (omitted)
[ 0:00]     changeset: (omitted)
[ 0:00]     timestamp: (omitted)
[ 0:00]     uid:       (omitted)
[ 0:00]     user:      (omitted)
[ 0:00]     way_nodes: (omitted)
[ 0:00]   output format options:
[ 0:00]     tags_type = hstore
[ 0:00]   linear tags: none
[ 0:00]   area tags:   one of the following:
[ 0:00]     @type=relation
[ 0:00]   other options:
[ 0:00]     index type: sparse_mem_array
[ 0:00]     add unique IDs: no
[ 0:00]     keep untagged features: no
[ 0:00] 
[ 0:00] Create table with something like this:
[ 0:00] CREATE EXTENSION IF NOT EXISTS hstore;
[ 0:00] CREATE TABLE osmdata (
[ 0:00]     geom      GEOMETRY, -- or GEOGRAPHY
[ 0:00]     osm_type  TEXT,
[ 0:00]     osm_id    BIGINT,
[ 0:00]     tags      hstore
[ 0:00] );
[ 0:00] Then load data with something like this:
[ 0:00] \copy osmdata FROM 'moscow_loc_ways/multipolygon/source.tsv'
[ 0:00] 
[ 0:00] First pass (of two) through input file (reading relations)...
[ 0:00] First pass done.
[ 0:00] Second pass (of two) through input file...
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
Geometry error: Could not build area geometry
[ 0:03] About 78 MBytes used for node location index (in main memory or on disk).
[ 0:03] Second pass done.
[ 0:03] Wrote 55341 features.
[ 0:03] Encountered 39 errors.
[ 0:03] Peak memory used: 828 MBytes
[ 0:03] Done.

cat /home/user/dev/map/moscow/moscow_loc_ways/multipolygon/source.tsv | grep $'\trelation\t' | split -l 13578 - /home/user/dev/map/moscow/moscow_loc_ways/multipolygon/multipolygon_

Осталось загрузить эти данные в PostGIS. Я это cделаю в той же директории с помощью Docker, а параметры контейнера будут зависеть от конфигурации вашей системы:

docker run --name postgis15-moscow --memory=12g --memory-swap=12g --memory-swappiness 0 --shm-size=1g -v $(pwd)/database:/var/lib/postgresql/data -v $(pwd)/moscow_loc_ways:/input -e POSTGRES_PASSWORD=osmworld -d -p 5432:5432 postgres15_postgis:latest -c checkpoint_timeout='15 min' -c checkpoint_completion_target=0.9 -c shared_buffers='4096 MB' -c wal_buffers=-1 -c bgwriter_delay=200ms -c bgwriter_lru_maxpages=100 -c bgwriter_lru_multiplier=2.0 -c bgwriter_flush_after=0 -c max_wal_size='32768 MB' -c min_wal_size='16384 MB'
Теперь можно подключаться любым клиентом, пароль у вас указан в POSTGRES_PASSWORD команды создания. Посмотреть статистику по таблицам, например:
PSQL_PAGER="pspg" psql -h 127.0.0.1 -p 5432 -U postgres -d osmworld
Password for user postgres: 
???? ???? postgres_dba 6.0 installed. Use ":dba" to see menu
Timing is on.
psql (14.8 (Ubuntu 14.8-1.pgdg20.04+1), server 15.2 (Debian 15.2-1.pgdg110+1))
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
Type "help" for help.

osmworld=# :dba
Time: 1,892 ms
Time: 0,458 ms
Time: 0,413 ms
Time: 0,538 ms
Menu:
   0 – Node & current DB information: master/replica, lag, DB size, tmp files, etc.
   1 – Databases: size, stats
   2 – Tables: table/index/TOAST size, number of rows
   3 – Load profile
  a1 – Current activity: count of current connections grouped by database, user name, state
  b1 – Table bloat (estimated)
  b2 – B-tree index bloat (estimated)
  b3 – Table bloat (requires pgstattuple; expensive)
  b4 – B-tree indexes bloat (requires pgstattuple; expensive)
  b5 – Tables and columns without stats (so bloat cannot be estimated)
  e1 – Extensions installed in current DB
  i1 – Unused and rarely used indexes
  i2 – Redundant indexes
  i3 – FKs with Missing/Bad Indexes
  i4 – Invalid indexes
  i5 – Cleanup unused and redundant indexes – DO & UNDO migration DDL
  l1 – Lock trees (leightweight)
  l2 – Lock trees, detailed (based on pg_blocking_pids())
  p1 – [EXP] Alignment padding: how many bytes can be saved if columns are reordered?
  s1 – Slowest queries, by total time (requires pg_stat_statements)
  s2 – Slowest queries report (requires pg_stat_statements)
  t1 – Postgres parameters tuning
  v1 – Vacuum: current activity
  v2 – Vacuum: VACUUM progress and autovacuum queue
   q – Quit

Type your choice and press <Enter>:
2
Time: 0,990 ms
         Table          | Rows  |     Total Size     |     Table Size     |  Index(es) Size  |     TOAST Size     
------------------------+-------+--------------------+--------------------+------------------+--------------------
 *** TOTAL ***          | ~2M   | 722 MB (100.00%)   | 682 MB (100.00%)   | 35 MB (100.00%)  | 4712 kB (100.00%)
                        |       |                    |                    |                  | 
 ways_001               | ~932k | 461 MB (63.93%)    | 460 MB (67.44%)    | 0 bytes (0.00%)  | 1280 kB (27.35%)
 relation_members       | ~876k | 74 MB (10.30%)     | 48 MB (7.03%)      | 26 MB (75.64%)   | 8192 bytes (0.17%)
 nodes_001              | ~412k | 72 MB (9.92%)      | 72 MB (10.49%)     | 0 bytes (0.00%)  | 32 kB (0.68%)
 multipolygon_001       | ~53k  | 43 MB (6.01%)      | 36 MB (5.29%)      | 4992 kB (13.98%) | 2448 kB (52.31%)
 ways_000               | ~59k  | 30 MB (4.20%)      | 30 MB (4.41%)      | 0 bytes (0.00%)  | 248 kB (5.30%)
 h3_3_bounds_complex    | ~41k  | 15 MB (2.13%)      | 12 MB (1.77%)      | 3344 kB (9.37%)  | 8192 bytes (0.17%)
 relations              | ~86k  | 15 MB (2.07%)      | 15 MB (2.18%)      | 0 bytes (0.00%)  | 80 kB (1.71%)
 spatial_ref_sys        | ~9k   | 7144 kB (0.97%)    | 6928 kB (0.99%)    | 208 kB (0.58%)   | 8192 bytes (0.17%)
 nodes_000              | ~8k   | 1152 kB (0.16%)    | 1144 kB (0.16%)    | 0 bytes (0.00%)  | 8192 bytes (0.17%)
 multipolygon_000       | ~745  | 960 kB (0.13%)     | 752 kB (0.11%)     | 112 kB (0.31%)   | 96 kB (2.05%)
 ways_32767             | ~518  | 816 kB (0.11%)     | 616 kB (0.09%)     | 0 bytes (0.00%)  | 200 kB (4.27%)
 multipolygon_32767     | ~50   | 440 kB (0.06%)     | 152 kB (0.02%)     | 40 kB (0.11%)    | 248 kB (5.30%)
 osm_file_block_content | ~598  | 80 kB (0.01%)      | 80 kB (0.01%)      | 0 bytes (0.00%)  | 
 osm_file_block         | ~188  | 48 kB (0.01%)      | 48 kB (0.01%)      | 0 bytes (0.00%)  | 
 osm_stat_nodes_3_3     | ~6    | 16 kB (0.00%)      | 8192 bytes (0.00%) | 0 bytes (0.00%)  | 8192 bytes (0.17%)
 osm_stat_ways_3_3      | ~4    | 16 kB (0.00%)      | 8192 bytes (0.00%) | 0 bytes (0.00%)  | 8192 bytes (0.17%)
 osm_file_statistics    | ~1    | 8192 bytes (0.00%) | 8192 bytes (0.00%) | 0 bytes (0.00%)  | 
(19 rows)

Time: 12,725 ms
Press <Enter> to continue…

Создадим индексы для колонок типа географии, которые ускорят наши запросы:

CREATE INDEX idx_nodes_geography ON nodes USING gist (cast (geom as geography));
CREATE INDEX idx_ways_geography ON ways USING gist (cast (linestring as geography));
CREATE INDEX idx_multipolygon_geography ON multipolygon USING gist (cast (polygon as geography));

Тип geography, вместо geometry в запросе приходится использовать, так как измерять расстояния будем в метрах, а не долях градусов.

Проверим план нашего запроса расчета растояний от зданий до факторов дискомфорта:
osmworld=# explain create table distance as
                    select h3_lat_lng_to_cell(b.centre,10) h3_10, h3_lat_lng_to_cell(b.centre,8) h3_8,
                    round(ST_Distance(b.geom::geography,g.geom::geography))::integer distance,
                    b.type from_type, g.type to_type, b.id from_id, g.id to_id
                        from geometry_global_view b inner join geometry_global_view g
                            on ST_DWithin(b.geom::geography,g.geom::geography,200) and
    b.tags->'building' is not null and
    b.tags->'building' not in --в перечисленных ниже зданиях обычные люди не живут на постоянной основе
        ('service','garages','industrial','retail','office','roof','commercial','garage','kiosk','warehouse','church',
        'parking','public','shed','hangar','train_station','guardhouse','transportation','terrace','greenhouse','bridge',
        'government','chapel','gazebo','civic','ruins','supermarket','sports_centre','semidetached_house','toilets',
        'sports_hall','clinic','farm_auxiliary','stable','grandstand','bunker','gatehouse','store','temple','ventilation_kiosk',
        'carport','cowshed','barracks','shop','cabin','barn','cathedral','wall','townhouse','manufacture','shelter',
        'fire_station','stadium','stands','sport_hall','theatre','storage_tank','checkpoint','houseboat','abandoned','dovecote',
        'mosque','museum','military','container','observatory','lift','tent','factory','sport','mall','riding_hall','depot',
        'prison','gate','triumphal_arch','water_works','public_building','pavilion','bank','institute','works','collapsed',
        'car_repair','crossing_box','fuel','tree_house','presbytery','yesq','farm','outbuilding','police','porch','sauna',
        'monastery','cinema','tower','boathouse','library','transformer_tower','heat_exchange_station')
    and
(
    g.tags->'amenity'='waste_transfer_station' or --_качество воздуха_
    g.tags->'landuse'='landfill' or --_качество воздуха_
    g.tags->'man_made'='spoil_heap' or --_качество воздуха_
    g.tags->'man_made'='wastewater_plant' or --_качество воздуха_
    g.tags->'amenity'='crematorium' or --_качество воздуха_
    (g.tags->'natural'='wetland' and g.tags->'wetland' is distinct from 'mangrove') or --_комары_
    g.tags->'power'='substation' or --_промышленность_
    g.tags->'power'='generator' or --_промышленность_
    g.tags->'power'='plant' or --_промышленность_
    g.tags->'building'='industrial' or --_промышленность_
    g.tags->'landuse'='industrial' or --_промышленность_
    g.tags->'landuse'='quarry' or --промышленность_
    g.tags->'aeroway'='runway' or --_шумное место_
    g.tags->'railway'='rail' or --_шумное место_
    g.tags->'highway'='primary' or --_шумное место_
    g.tags->'highway'='trunk' or --_шумное место_
    g.tags->'leisure'='stadium' or --_шумное место_
    g.tags->'landuse'='construction' --_шумное место_
);
Time: 41,440 ms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.53..698216225.15 rows=91264670 width=44)
   Workers Planned: 4
   ->  Nested Loop  (cost=0.53..689088758.15 rows=22816168 width=44)
         ->  Parallel Append  (cost=0.00..124924.54 rows=31608 width=162)
               ->  Parallel Seq Scan on ways_001 ways_4  (cost=0.00..83311.46 rows=20092 width=178)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on nodes_001 nodes_3  (cost=0.00..27175.52 rows=14806 width=76)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on multipolygon_001 multipolygon_4  (cost=0.00..6941.94 rows=1913 width=467)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on ways_000 ways_3  (cost=0.00..6444.37 rows=2136 width=198)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on nodes_000 nodes_2  (cost=0.00..628.11 rows=402 width=76)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on multipolygon_000 multipolygon_3  (cost=0.00..137.01 rows=38 width=807)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on ways_32767 ways_5  (cost=0.00..108.99 rows=26 width=843)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
               ->  Parallel Seq Scan on multipolygon_32767 multipolygon_5  (cost=0.00..19.09 rows=9 width=5966)
                     Filter: (((tags -> 'amenity'::text) = 'waste_transfer_station'::text) OR ((tags -> 'landuse'::text) = 'landfill'::text) OR ((tags -> 'man_made'::text) = 'spoil_heap'::text) OR ((tags -> 'man_made'::text) = 'wastewater_plant'::text) OR ((tags -> 'amenity'::text) = 'crematorium'::text) OR (((tags -> 'natural'::text) = 'wetland'::text) AND ((tags -> 'wetland'::text) IS DISTINCT FROM 'mangrove'::text)) OR ((tags -> 'power'::text) = 'substation'::text) OR ((tags -> 'power'::text) = 'generator'::text) OR ((tags -> 'power'::text) = 'plant'::text) OR ((tags -> 'building'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'industrial'::text) OR ((tags -> 'landuse'::text) = 'quarry'::text) OR ((tags -> 'aeroway'::text) = 'runway'::text) OR ((tags -> 'railway'::text) = 'rail'::text) OR ((tags -> 'highway'::text) = 'primary'::text) OR ((tags -> 'highway'::text) = 'trunk'::text) OR ((tags -> 'leisure'::text) = 'stadium'::text) OR ((tags -> 'landuse'::text) = 'construction'::text))
         ->  Append  (cost=0.53..3735.74 rows=76 width=129)
               ->  Index Scan using nodes_000_geom_idx on nodes_000 nodes  (cost=0.53..25.56 rows=1 width=44)
                     Index Cond: ((geom)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((geom)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using nodes_001_geom_idx on nodes_001 nodes_1  (cost=0.66..1027.11 rows=20 width=44)
                     Index Cond: ((geom)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((geom)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using ways_000_linestring_idx on ways_000 ways  (cost=0.66..150.89 rows=3 width=166)
                     Index Cond: ((linestring)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((linestring)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using ways_001_linestring_idx on ways_001 ways_1  (cost=0.67..2329.28 rows=46 width=146)
                     Index Cond: ((linestring)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((linestring)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using ways_32767_linestring_idx on ways_32767 ways_2  (cost=0.52..25.56 rows=1 width=811)
                     Index Cond: ((linestring)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((linestring)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using multipolygon_000_polygon_idx1 on multipolygon_000 multipolygon  (cost=0.52..25.56 rows=1 width=775)
                     Index Cond: ((polygon)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((polygon)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using multipolygon_001_polygon_idx1 on multipolygon_001 multipolygon_1  (cost=0.66..125.86 rows=3 width=435)
                     Index Cond: ((polygon)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((polygon)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
               ->  Index Scan using multipolygon_32767_polygon_idx1 on multipolygon_32767 multipolygon_2  (cost=0.52..25.55 rows=1 width=5934)
                     Index Cond: ((polygon)::geography && _st_expand((ways_4.linestring)::geography, '200'::double precision))
                     Filter: (((tags -> 'building'::text) IS NOT NULL) AND ((tags -> 'building'::text) <> ALL ('{service,garages,industrial,retail,office,roof,commercial,garage,kiosk,warehouse,church,parking,public,shed,hangar,train_station,guardhouse,transportation,terrace,greenhouse,bridge,government,chapel,gazebo,civic,ruins,supermarket,sports_centre,semidetached_house,toilets,sports_hall,clinic,farm_auxiliary,stable,grandstand,bunker,gatehouse,store,temple,ventilation_kiosk,carport,cowshed,barracks,shop,cabin,barn,cathedral,wall,townhouse,manufacture,shelter,fire_station,stadium,stands,sport_hall,theatre,storage_tank,checkpoint,houseboat,abandoned,dovecote,mosque,museum,military,container,observatory,lift,tent,factory,sport,mall,riding_hall,depot,prison,gate,triumphal_arch,water_works,public_building,pavilion,bank,institute,works,collapsed,car_repair,crossing_box,fuel,tree_house,presbytery,yesq,farm,outbuilding,police,porch,sauna,monastery,cinema,tower,boathouse,library,transformer_tower,heat_exchange_station}'::text[])) AND st_dwithin((polygon)::geography, (ways_4.linestring)::geography, '200'::double precision, true))
 JIT:
   Functions: 81
   Options: Inlining true, Optimization true, Expressions true, Deforming true
(48 rows)

Теперь расчитаем расстояния от жилых зданий, при этом считаем что если здание ближе 200м, то на него будет влиять негативный фактор:

osmworld=# create table distance as
                    select h3_lat_lng_to_cell(b.centre,10) h3_10, h3_lat_lng_to_cell(b.centre,8) h3_8,
                    round(ST_Distance(b.geom::geography,g.geom::geography))::integer distance,
                    b.type from_type, g.type to_type, b.id from_id, g.id to_id,
                    CASE
                        WHEN g.tags->'amenity'='waste_transfer_station' or
                             g.tags->'landuse'='landfill' or
                             g.tags->'man_made'='spoil_heap' or
                             g.tags->'man_made'='wastewater_plant' or
                             g.tags->'amenity'='crematorium' THEN 'air_quality'
                        WHEN g.tags->'power'='substation' or
                             g.tags->'power'='generator' or
                             g.tags->'power'='plant' or
                             g.tags->'building'='industrial' or
                             g.tags->'landuse'='industrial' or
                             g.tags->'landuse'='quarry' THEN 'industrial'
                        WHEN g.tags->'natural'='wetland' and g.tags->'wetland' is distinct from 'mangrove' THEN 'mosquitoes'
                        WHEN g.tags->'aeroway'='runway' or
                             g.tags->'railway'='rail' or
                             g.tags->'highway'='primary' or
                             g.tags->'highway'='trunk' or
                             g.tags->'leisure'='stadium' or
                             g.tags->'landuse'='construction' THEN 'noisy_place'
                    END reason
                        from geometry_global_view b inner join geometry_global_view g
                            on ST_DWithin(b.geom::geography,g.geom::geography,200) and
    b.tags->'building' is not null and
    b.tags->'building' not in --в перечисленных ниже зданиях не живут на постоянной основе
        ('service','garages','industrial','retail','office','roof','commercial','garage','kiosk','warehouse','church',
        'parking','public','shed','hangar','train_station','guardhouse','transportation','terrace','greenhouse','bridge',
        'government','chapel','gazebo','civic','ruins','supermarket','sports_centre','semidetached_house','toilets',
        'sports_hall','clinic','farm_auxiliary','stable','grandstand','bunker','gatehouse','store','temple','ventilation_kiosk',
        'carport','cowshed','barracks','shop','cabin','barn','cathedral','wall','townhouse','manufacture','shelter',
        'fire_station','stadium','stands','sport_hall','theatre','storage_tank','checkpoint','houseboat','abandoned','dovecote',
        'mosque','museum','military','container','observatory','lift','tent','factory','sport','mall','riding_hall','depot',
        'prison','gate','triumphal_arch','water_works','public_building','pavilion','bank','institute','works','collapsed',
        'car_repair','crossing_box','fuel','tree_house','presbytery','yesq','farm','outbuilding','police','porch','sauna',
        'monastery','cinema','tower','boathouse','library','transformer_tower','heat_exchange_station')
    and
(
    g.tags->'amenity'='waste_transfer_station' or --_качество воздуха_
    g.tags->'landuse'='landfill' or --_качество воздуха_
    g.tags->'man_made'='spoil_heap' or --_качество воздуха_
    g.tags->'man_made'='wastewater_plant' or --_качество воздуха_
    g.tags->'amenity'='crematorium' or --_качество воздуха_
    (g.tags->'natural'='wetland' and g.tags->'wetland' is distinct from 'mangrove') or --_комары_
    g.tags->'power'='substation' or --_промышленность_
    g.tags->'power'='generator' or --_промышленность_
    g.tags->'power'='plant' or --_промышленность_
    g.tags->'building'='industrial' or --_промышленность_
    g.tags->'landuse'='industrial' or --_промышленность_
    g.tags->'landuse'='quarry' or --промышленность_
    g.tags->'aeroway'='runway' or --_шумное место_
    g.tags->'railway'='rail' or --_шумное место_
    g.tags->'highway'='primary' or --_шумное место_
    g.tags->'highway'='trunk' or --_шумное место_
    g.tags->'leisure'='stadium' or --_шумное место_
    g.tags->'landuse'='construction' --_шумное место_
);
SELECT 808496
Time: 50868,122 ms (00:50,868)

osmworld=# ALTER TABLE distance ADD primary key(from_id,from_type,to_id,to_type);
ALTER TABLE
Time: 678,886 ms

osmworld=# \d distance
                   Table "public.distance"
  Column   |      Type       | Collation | Nullable | Default 
-----------+-----------------+-----------+----------+---------
 h3_10     | h3index         |           |          | 
 h3_8      | h3index         |           |          | 
 distance  | integer         |           |          | 
 from_type | table_reference |           | not null | 
 to_type   | table_reference |           | not null | 
 from_id   | bigint          |           | not null | 
 to_id     | bigint          |           | not null | 
 reason    | text            |           |          | 
Indexes:
    "distance_pkey" PRIMARY KEY, btree (from_id, from_type, to_id, to_type)

geometry_global_view - это представление, которое объединяет таблицы nodes, ways, multipolygon из OSM PgSnapshot схемы базы и сильно упрощает написание запросов, когда вам надо найти геометрию по заданным тегам, но ее тип заранее не знаете.

Для агрегации данных нам понадобится расширение H3:

CREATE EXTENSION h3_postgis CASCADE;

Сохраним предагрегированные данные в таблицы h3_10_stat для агрегации с H3 ячейкой 10 масштаба и h3_8_stat соответственно:

create table h3_8_stat as select h3_cell_to_boundary_geography(h3) cell ,count, reason from (select h3_8 h3, count(distinct (to_id,to_type)),array_agg(distinct reason) reason from distance group by 1 order by 1) geo;
SELECT 2047
Time: 1257,269 ms (00:01,257)

osmworld=# create table h3_10_stat as select h3_cell_to_boundary_geography(h3) cell ,count, reason from (select h3_10 h3, count(distinct (to_id,to_type)),array_agg(distinct reason) reason from distance group by 1 order by 1) geo;
SELECT 15660
Time: 1107,552 ms (00:01,108)

Предрасчет сделал, чтобы QGIS не "подвисала" во время отображения из PostGIS. Для таблицы выгружу данные в TSV файл, вы можете посмотреть что же это за места "портят" комфорт жизни в районах Москвы. Районы определяются разбивкой гексагональной сеткой с ребром около 75м для уровня=10:

osmworld=# \copy (select distinct h3_10, reason, CASE WHEN to_type='nodes' THEN 'https://www.openstreetmap.org/node/'||to_id WHEN to_type='ways' THEN 'https://www.openstreetmap.org/way/'||to_id WHEN to_type='multipolygon' THEN 'https://www.openstreetmap.org/relation/'||to_id END OSM_URL from distance order by 1) to 'uncomfortable_h3-10_region.tsv'
COPY 27354
Time: 289,032 ms

Анализ данных для Москвы

Почему я решил начать с Москвы - во первых цена ошибки здесь слишком большая, что с арендой, что с покупкой недвижимости. К тому же я достаточно долго прожил в Москве и могу сказать что для меня этот город достаточно комфортный. В плане удобства метрополитена и развитости/цены на общественный транспорт в Москве достаточно хорошо. Есть парки, места где погулять пешком поближе к природе. И все неплохо, пока живешь в хорошем районе, не дальше 10минут ходьбы от метро. Да все отлично пока живешь и работаешь в приличном месте, где не нужно быть на работе к времени попадая в час пик!

Итак, я считаю что рядом с квартирой, ближе чем в 200м не хотел бы видеть, нюхать и слышать то что ухудшает:

Конечно модель - это всего лишь грубое приближение реальности, тем более что данные о материалах дома и реальное качество строительства не учитываются. Как и года постройки здания, название типового проекта. Не учитывается слышимость из соседних квартир и с улицы. Так же как не расчитывается затухание шума на деревьях/ на шумозащитном экране у трассы( детальная информация о высоте деревьев и плотности из размещения на OpenStreetMap отсутствует), какие соседи из каких квартир уходят в запой и поколачивают свою семью, где есть агрессивные к другим людям индивиды во дворах и парках, качество водоснабжения и можно ли безопасно пить воду из-под крана. Живут ли тараканы, у соседки-пенсионерки с 20 котами. Как часто ломает лифт "упоротый" сосед осознанно перегружая его до потолка стройматериалами. Есть ли хулиганы жгущие пластиковые кнопки в лифте, изрисовывают ли стены дома. И многое другое важное для комфорта остается вне модели.

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

Напишите в коментариях какие еще места могут вас отпугнуть от места где собираетесь жить и почему?

Загружаем данные в QGIS
Загружаем данные в QGIS
Настраиваем цвет ячейки в зависимости от числа факторов в ней
Настраиваем цвет ячейки в зависимости от числа факторов в ней
Скрываем те ячейки где фактор "дискомфорта" минимален и любуемся на места где бы я не хотел жить
Скрываем те ячейки где фактор "дискомфорта" минимален и любуемся на места где бы я не хотел жить

Из QGIS я экспортировал данные слоя в GeoJSON и поделюсь им с вами. Вы можете загрузить его либо удобную вам для просмотра программу или воспользоваться онлайн инструментом https://geojson.io

Не самое удачное место для жилья, если верить статистике OSM - 220 проблемных мест на 7км2
Не самое удачное место для жилья, если верить статистике OSM - 220 проблемных мест на 7км2

А для примера, можем выгрузить GeoJSON для H3 ячеек уровня 10 с помощью SQL:

osmworld=# \copy (select json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', st_AsGeoJSON(cell)::json, 'properties', json_build_object('count', count, 'reason', reason)))) FROM h3_10_stat) to 'uncomfortable_h3-10_region.json.geojson';
COPY 1
Time: 87,625 ms

Результаты доступны здесь.

Просмотр uncomfortable_h3-10_region.json.geojson в gist.github.com
Просмотр uncomfortable_h3-10_region.json.geojson в gist.github.com
Просмотр uncomfortable_h3-10_region.json.geojson в geojson.io
Просмотр uncomfortable_h3-10_region.json.geojson в geojson.io

Забыл упомянуть что расстояния считал только до жилых зданий. А это все что не:

building = ...

'service','garages','industrial','retail','office','roof','commercial','garage','kiosk','warehouse','church','parking','public','shed','hangar','train_station','guardhouse','transportation','terrace','greenhouse','bridge','government','chapel','gazebo','civic','ruins','supermarket','sports_centre','semidetached_house','toilets','sports_hall','clinic','farm_auxiliary','stable','grandstand','bunker','gatehouse','store','temple','ventilation_kiosk','carport','cowshed','barracks','shop','cabin','barn','cathedral','wall','townhouse','manufacture','shelter','fire_station','stadium','stands','sport_hall','theatre','storage_tank','checkpoint','houseboat','abandoned','dovecote','mosque','museum','military','container','observatory','lift','tent','factory','sport','mall','riding_hall','depot','prison','gate','triumphal_arch','water_works','public_building','pavilion','bank','institute','works','collapsed','car_repair','crossing_box','fuel','tree_house','presbytery','yesq','farm','outbuilding','police','porch','sauna','monastery','cinema','tower','boathouse','library','transformer_tower','heat_exchange_station'

Считая, что остальные здания являются жилыми. Исходные данные с OpenStreetMap не могут быть идеальными и всегда правильно размеченными, как и запросы к данным могут содержать ошибки. Но лично я лучше перестрахуюсь, и обойду здание - "жемчужину" индустриального района стороной.

Смотря на данные по Москве, я заметил что идеальная транспортная доступность играет в минус жилью, когда трасса ближе 200м к зданию - из-за шума автотранспорта и загазованности воздуха.

StableDiffusion: Best place in the city to live
StableDiffusion: Best place in the city to live

Ищите ваш дом и исследуйте окрестности, пишите что бы вы добавили к запросу, какие объекты! Загружайте данные - выгрузки по ссылкам в статье или исходные OSM файлы.

Результат

Модель вышла слишком общей для разных людей. В реальности же предпочтения могут различаться, и некоторые люди могут жить в таких "некомфортных" местах из-за других факторов, таких как доступность жилья, близость к работе или просто нравится готичность и индустриальность места. Открытые данные OSM и инструмент для работы с ними доступны и я выше как их импортировать, в чем визуализировать.

Если вы вдруг обнаружили что район вашего дома незаслуженно оказался помечен как неуютный, то ищите причину в разметке данных на OpenStreetMap и исправляйте ошибки, следуя инструкциям с wiki. Но помните, что сообщество борется с вандализмом данных - когда кто-либо начинает искажать действительность или портить существующие данные.

Свет провели в прошлом году! Три локтя по карте от центра мегаполиса... Попросил еще белку на лужайке)
Свет провели в прошлом году! Три локтя по карте от центра мегаполиса... Попросил еще белку на лужайке)

Если тема вас заинтересует, то могу провести анализ для других городов: как мегаполисов, так и более индустриальных Красноярска, Омска или курортных городов на побережье. Можем проверить запросы на фавелах в других странах, островах, континентах. Жду ваши идеи и предложения в коментариях.

Комментарии (64)


  1. sshikov
    13.09.2023 19:14
    +1

    когда трасса ближе 200м к зданию

    Наверное смотря какая трасса, но вот у меня в 100 м трасса 10 полос в одном направлении, так я честно скажу — это задница. По многим параметрам. При этом насколько я вижу, мой дом не попадает в те шестиугольники, где совсем уж плохо — они дальше от трассы, как ни странно.


    1. igor_suhorukov Автор
      13.09.2023 19:14

      О, интересно! Пока метрика простая - count объектов без учета что громче и дискомфортнее. У тебя есть идеи что можно улучшить в запросе, чтобы в ваших окрестностях картина была ближе к реальности? Можешь скинуть ближайший сегмент трассы из OSM? Я посмотрю по тегам, может не учитываю ее. Может ты баг нашел, а может - фичу.


      1. novoselov
        13.09.2023 19:14

        Кроме плохих районов было бы интересно увидеть и хорошие.

        Можно тоже с цветовой градацией:
        - желтый если в 200 метрах заканчивается красная зона
        - зеленый если в 200 метрах заканчивается желтая зона
        и т.д.


        1. igor_suhorukov Автор
          13.09.2023 19:14
          +1

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

          Это для жилых домов в центре, без вышеперечисленных негативных факторов. H3 scale10
          Это для жилых домов в центре, без вышеперечисленных негативных факторов. H3 scale10

          Тут особо раскрашивать не выйдет. после фильтрации зданий внутри зоопарка и сторожек в парках.


    1. igor_suhorukov Автор
      13.09.2023 19:14

      (g.tags->'lanes' is not null and g.tags->'lanes'~'^\d+$' and (g.tags->'lanes')::integer>2) --_шумное место_


  1. selivanov_pavel
    13.09.2023 19:14
    +9

    тюрьмы/изоляторы, психиатрические, наркологические и инфекционные( они редко правильно протегированны) больницы, морги, кладбища

    Близость ни к чему из вышеперечисленных не означает концентрацию маргинальных личностей - они в эти места попадают вынужденно и снаружи не тусят.


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +2

      Почти как говорит знакомый реаниматолог: "ко мне пациенты сами не приходят".

      Тема спорная и при возможности выбора, я бы не выбрал окрестности. Но тут у каждого разные предпочтения!


      1. selivanov_pavel
        13.09.2023 19:14
        +14

        А зря, во все перечисленные места люди идут по делу, обычно не самому весёлому, напиваться или бузить им не нужно. Одна алко-разливайка по генерации неадекватов на единицу площади переплюнет всё выше перечисленное вместе взятое.

        Кладбища вообще отличная штука - много зелени, практически парк в городской черте, чистый воздух.


        1. igor_suhorukov Автор
          13.09.2023 19:14
          +1

          Кладбища вообще отличная штука - много зелени, практически парк в городской черте, чистый воздух.

          Если историческое, то согласен. В командировках в Лондон, в центре в Сити, на обеденном перерыве многие и разбредались по древним кладбищам к лавочкам и прогуляться.

          алко-разливайка, интересная идея! Знаете каким тегом официально помечают, это же не бар/паб где охрана и не алкомаркет дорогой где в себя содержимое тоже не заливают


        1. neee3k
          13.09.2023 19:14
          +5

          Кладбища вообще отличная штука - много зелени, практически парк в городской черте, чистый воздух.

          А ещё тишина, покой и конфетки с печеньем на халяву.


    1. 1755
      13.09.2023 19:14
      +1

      Я думаю, встретить концентрацию маргиналов сильно проще возле вокзалов, нежели этих заведений)


  1. avacha
    13.09.2023 19:14
    +6

    @igor_suhorukov,спасибо за статью. По поводу вашего предложения

    Если тема вас заинтересует, то могу провести анализ для других городов: как мегаполисов, так и более индустриальных Красноярска, Омска или курортных городов на побережье.

    "Если выпало в империи родиться - лучше жить в глухой провинции, у моря."

    А давайте попробуем, в первом приближении, прикинуть. Что у нас из курортных городов на побережье имеется? "Если есть на свете рай - то это Краснодарский край". Открываем карту...

    Азовское море. По большому счету городов нет. Пара курортных мест - станица Голубицкая и город Ейск. Не в курсе, есть ли в Ейске какой-либо завод, который влияет на экологию, но скорее всего - ничего большого.

    Дальше по побережью... Анапа. С Анапой все понятно - армянская столица края, адская застройка, постоянные пробки. В остальном - ничего примечательного. Город-курорт, производств особо нет.

    Новороссийск. Первый интересный объект для анализа, как мне кажется. Третий по населению город края (фактически - второй, т.к Сочи считается как агломерация более 100км в длину). Крупный порт, цементные заводы, жд, транснефть (крупнейший терминал в РФ) и Каспийский трубопроводный консорциум (опять нефть), металлургический завод, легкая промышленность. При этом население стремительно растет, хотя и немного меньше чем в Краснодаре. Туризм в зачаточном состоянии. Есть море, которое как магнитом тянет переехать поближе к нему граждан из средней полосы и северных регионов. В наличии военно-морская база. Да, есть в составе порта перевалка всяких разных химических веществ - от асбеста до уксусной кислоты. С нефтяных терминалов тоже попахивает (не конкретно в Новороссийске, а вообще), надо иметь в виду. Реальное население пожалуй в районе 400-500.000. Думаю с учетом близлежащих поселков и бурного строительства - скорее ближе к 500.000. Было бы интересно взглянуть на результаты анализа.

    Далее. Геленджик понятно, город-курорт, парки, две главных улицы крестом...

    Далее. Туапсе. Туапсе - весьма небольшой город, я бы оценил в 100.000 населения, имеется порт и какая-никакая промышленность. Некий Новороссийск в миниатюре. В целом - ничего сверхъестественного. Тоже можно было бы посмотреть.

    Дальше идет курортная зона сплошняком до Сочи. Небуг, Ольгинка, тысячи их, этих поселочков, где сдают дома/комнаты "дикарям"-туристам. С ними все понятно, в зимний сезон жизнь в них замирает, и на улицах пусто, как в Сайлент-Хилле. Производств нет.

    Сочи. Сочи на самом деле - это агломерация, состоящая из Лоо, сосбтвенно самого Сочи, Сириуса и прочих, прочих прочих. Летняя веранда клуба "Москва", на которую можно выйти с тусы и облокотившись на перила, выпить коктейль, лениво посматривая на припаркованные автомобили люкс-класса. С соответствующими ценниками. Производств нет практически, однако очень специфичный рельеф и транспортная доступность в городе - оставляют желать лучшего. Тем не менее - второй город по концентрации мажоров населению после олимпиады Краснодара. Безусловно, интересен для анализа.

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

    Подведя итоги - Новороссийск, Туапсе, Сочи. Краснодар.


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +2

      @avacha спасибо за ценные мысли! Попробуем текущий запрос, если он не будет отражать действительность, то посмотрим что в нем "подкрутить". В ближайшее время тогда напишу про Краснодар, Новороссийск, Туапсе, Сочи


    1. 0Bannon
      13.09.2023 19:14

      А Владивосток? Тут самый офигенный океанариум в стране. А еще в море купаться можно и снега нет. А у вас всё краснодар да сочи.


      1. igor_suhorukov Автор
        13.09.2023 19:14

        Владивосток чуть ниже в коментариях


      1. yoz
        13.09.2023 19:14
        +1

        Климат Владивостока и Сочи сложно поставить на одну полку.


    1. Komrus
      13.09.2023 19:14

      Как-то Туапсе совсем не впечатлил...

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


      1. igor_suhorukov Автор
        13.09.2023 19:14

        Восточнее от Туапсе главный минус - ходить на пляж через железную дорогу. А так Черное море оно везде похоже в воде...


      1. igor_suhorukov Автор
        13.09.2023 19:14

        Ну и конечно же славится

        своим богатым подводным миром)


      1. Ariki
        13.09.2023 19:14

        В Туапсе в последнее время ещё и пробки дикие, причём не только летом. При выборе места для жизни рельеф важен, а также оползневые зоны и зоны, регулярно страдающие от наводнений.

        Помимо нефтезавода и нефтяного порта, там ещё перевалка минеральных удобрений. В остальном город хороший, очень его люблю. А за городом ещё лучше.


    1. Dolios
      13.09.2023 19:14

      "Если выпало в империи родиться - лучше жить в глухой провинции, у моря."
      Подведя итоги - Новороссийск, Туапсе, Сочи. Краснодар.

      Климат паршивый. Адская жара летом и нет нормальной зимы. Владивосток и Архангельск привлекательнее гораздо, как по мне. Петрозаводск вообще отлично должно быть. Климат, природа в "море" нормальная человеческая пресная вода, а не солёная непонятная дрянь для кальмаров...


  1. Yukr
    13.09.2023 19:14
    +1

    Есть ещё Калининград. Мне лично ещё и Кронштадт нравится. Не все любят погорячее))

    Ах да! Владивосток! Летом в окрестностях красиво


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +1

      Ок - Владивосток, Калининград


  1. SnakeSolid
    13.09.2023 19:14
    +6

    Я бы в список ухудшающих объектов добавил тюрьмы и СИЗО, мне бы не хотелось видеть их ежедневно. И мне лично не хотелось бы жить рядом с церквями и мечетями, из-за постоянного звона колоколов.


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Мечети, храмы и церкви, как мне кажется наоборот добавляют уют району.

      Но сложно только различить где Муэдзиин через громкоговоритель читает Азан после полуночи и около 5 утра( это в мусульманских странах зависит от времени по солнцу, а не времени по часам), а где дают поспать кому не надо идти по зову


  1. kasiopei
    13.09.2023 19:14
    +2

    Еще нельзя жить у жд дорог, аэродромов, местах затопления или схода селей, складов пиротехники и удобрений.


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +1

      Спасибо! Уже есть

      g.tags->'aeroway'='runway' g.tags->'railway'='rail'

      А вот как понять по OSM где склад удобрений и пиротехники... Поищу!

      Но удобрения не все опасны и имеют резкий запах, опять же.


      1. artemisia_borealis
        13.09.2023 19:14

        Но удобрения не все опасны и имеют резкий запах, опять же.

        Зато те, что опасны, могут даже не иметь запаха, зато при пожаре могут довольно сильно деформирововать окуржающее пространство, почти как в чёрной дыре...


        1. igor_suhorukov Автор
          13.09.2023 19:14

          Ну не настолько! Сравнили химические реакции азотистых удобрений с гравитационной сингулярностью...


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +1

      Про потопы и сели отличная идея!!! Поищу есть ли эти данные. Не уверен что они будут в OSM, так как это временные и непредсказуемые явления. Возможно учитывать высоту зданий над уровнем воды воды, но разрешающая способность карты высот 30x30м и во о местах из-за плохого разрешения просто не узнаешь(


      1. mentin
        13.09.2023 19:14

        Про потопы это отдельная тема, постоянно на конференциях идут обсуждения и уточнения моделей расчета областей затопления. У ArcGIS есть встроенные алгоритмы, по-моему учитывают высоту, направление склонов - что куда течет, и долю заасфальтированной поверхности. Но это итеративные модели, просто высоты не достаточно, и на SQL описать что-то разумное сложно. Лучше искать готовые результаты расчетов. В штатах можно найти flood map - от FEMA или города.


        1. igor_suhorukov Автор
          13.09.2023 19:14

          Звучит как тема для отдельного проекта!

          Похоже как на гитхабе проекте обсуждали возможность визуализации коралловых рифов. Вместо простого решения основанного на данных OSM( если их нет то просто нужно добавлять), автор понеслась в "космос":

          Maybe we could use DEM (elevation data) here to get nice gradients based
          on water depth, but I don't know if this kind of detailed water depth
          data is available anywhere.


    1. PsihXMak
      13.09.2023 19:14

      Еще нельзя жить у жд дорог

      У меня жд дорога под окном. И в целом это намного лучше, чем жить напротив автомобильной дороги. Электричка проносится днём примерно раз в час почти бесшумно. Товарняки ходят раз в пару дней, что тоже не критично. Зато в остальное время полная тишина.


      1. igor_suhorukov Автор
        13.09.2023 19:14

        Я года 4 жил над линией московского метрополитена в типовой многоэтажке из железобетона "башне Вулых". И если не успевал засыпать, то слышал около 2х ночи как поезда идут в депо по линии в депо, которая отходила от основной ветки.

        Так что кому как повезло!


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Есть даже специальная разметка в OSM для областей подверженный затоплению Key:flood_prone а так же hazard=washout(hazard_type=flood)


  1. tommyangelo27
    13.09.2023 19:14
    +1

    Самое шумное место из тех, где доводилось жить - по соседству со студенческой общагой. Постоянные песни под гитару до 2 ночи, какие-то разборки, неудержимое веселье со смехом и криками. А учитывая, что жил на 1 этаже...


    1. igor_suhorukov Автор
      13.09.2023 19:14

      +общежития резонно. Я внутри недолго пожил впечатлений за 2 месяца как за 2 года!

      Если бы на 1курсе заехал, то наверное было бы привычно сразу, а так это был 4 курс. Уже знал сколько денег на жизнь в месяц тратится и что я ожидаю от жилья...


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Даже в рабочих общежитии хватает приключений и шума. Не так конечно, как в студенческом, но менее предсказуемо.


    1. YNK
      13.09.2023 19:14
      +1

      Общежитие музучилища или консерватории доставляет отдельно.


  1. JediPhilosopher
    13.09.2023 19:14
    +1

    Капну каплю пессимизма.

    OpenStreetMap это хорошо, но часто недостаточно. И в небольших городах там все размечено так себе. В итоге такие алгоритмы часто не работают, или выдают ерунду, и относиться к ним нужно с осторожностью.

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

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

    https://habr.com/ru/articles/584598/


    1. igor_suhorukov Автор
      13.09.2023 19:14
      +1

      Егор! Вот уже собирался вас упомянуть, я читал ваши статьи здесь раньше. А вы написали быстрее.

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


    1. igor_suhorukov Автор
      13.09.2023 19:14

      И в небольших городах там все размечено так себе.

      Согласен. Можно просто сказать что все бесполезно и забросить. Я же предпочитаю взять треки и iD реже JOSM, закатать рукава и добавить данные. Итого, почти за 10 лет около 400 дней работы с картами. Данные что мне нужны самому так и появляются и актуализируются.

      Если нет подходящего мне инструмента в opensource, то создаю. Так и появился openstreetmap_h3


      1. JediPhilosopher
        13.09.2023 19:14

        Все, очевидно, не бесполезно. Вот данные дополнять - это полезно ) Сам обычно из поездок привожу хотя бы несколько треков и где-то что-то в OSM дорисовываю.

        Комментарий я написал скорее для тех, кто на подобное натыкается в первый раз. У нас в ИДУ студенты, впервые столкнувшиеся с алгоритмами и тем же OSM, часто в эту ловушку попадаются - начинают думать, что можно алгоритмом по карте померять все что угодно. И тратят на это кучу времени там, где очевидно что ничего работать не будет, как бы хорошо не была сделана техническая часть.

        Но увы, наша урбанистика все-таки завязана на реальный мир, а в этом реальном мире не все можно добыть и сделать техническими средствами.


        1. igor_suhorukov Автор
          13.09.2023 19:14

          Вот данные дополнять - это полезно )

          Да, пока еще "человеки" это делают. Но думаю, что скоро эта механическая работа перейдет нейросеткам. Но будут ли актуализировать открытые данные или каждый производитель автопилотов будет у себя складывать петабайты векторных данных(скорее всего) распознанных и "причесанных" с сенсоров авто, роботов доставщиков и тп. Так как уже открытый rapid упрощает векторизацию спутниковых снимков.

          Сам обычно из поездок привожу хотя бы несколько треков и где-то что-то в OSM дорисовываю.

          Данные разные нужны, данные разные важны!

          Комментарий я написал скорее для тех, кто на подобное натыкается в
          первый раз. У нас в ИДУ студенты, впервые столкнувшиеся с алгоритмами и
          тем же OSM, часто в эту ловушку попадаются - начинают думать, что можно
          алгоритмом по карте померять все что угодно.

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


  1. Dolios
    13.09.2023 19:14
    +3

    Что не так с кладбищем? Тихое место, спокойные соседи (с)


  1. kreo_OL
    13.09.2023 19:14

    Отлично перекликается с этой статьей) https://habr.com/ru/articles/574068/


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Был хороших проект, жаль что он у @Serinec ее коллегами "не взлетел". Они пытались идти от инфраструктуры, а не негативных факторов(моя публикация только про то что избегать) и гексагональная разбивка в статье по ссылке была не Uber H3, а похоже на ST_HexagonGrid


  1. YNK
    13.09.2023 19:14

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


    1. JediPhilosopher
      13.09.2023 19:14
      +1

      Начхать обычно всем на это с высокой башни. Учитываются радиусы и санитарно-защитные зоны, это да. Но не более того. И рядом со свалками строят еще как, хз как там люди живут.


  1. RomanistHere
    13.09.2023 19:14

    https://habr.com/ru/articles/665656/ пробовал подойти к этой же проблеме с немного другого ракурса, предлагаю колаб)


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Посмотрел публикацию. Суть как я понял - вы пытаетесь повторить сообщество OSM. А в чем будет преимущество?


      1. RomanistHere
        13.09.2023 19:14

        собирать данные это только поверхностная часть сервиса, большая часть будет отвечать за предложение "идеального" места в определённом городе, например.

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

        edit: просто подбор будет реализован на основании пользовательских рейтингов, как отзовик на дома/районы/города


        1. igor_suhorukov Автор
          13.09.2023 19:14

          Нужна большая база реальных отзывов. Как же без этого?

          Мультик South Park серия You're Not Yelping рассказывает про рейтинги...


        1. igor_suhorukov Автор
          13.09.2023 19:14

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


          1. RomanistHere
            13.09.2023 19:14

            понятно, что правдивость рейтингов может стать проблемой, я проектировал сервис на эффекте мудрости толпы, когда с увеличением рейтингов он становится всё более и более правдоподобный

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

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

            edit: именно поэтому и предлагаю коллаб, потому что лишние факты и немного другое видение будут очень полезны для всех)


            1. igor_suhorukov Автор
              13.09.2023 19:14

              Удачи вам в этом благородном деле!

              IMHO доверие пользователей можно завоевать в децентрализованной платформе. В централизованных рейтинги легко подгоняются.


            1. igor_suhorukov Автор
              13.09.2023 19:14

              мудрости толпы

              Чтобы была эмерджентность минимум надо отфильтровать ботов и мухлюющих подлецов( любые KPI подгоняются при желании)


        1. JediPhilosopher
          13.09.2023 19:14
          +1

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

          В итоге очень сильно снижается польза от рейтингов "по соседству". Нельзя толком оценивать этот дом, если именно для него нет отзывов. Плохо будет работать попытка агрегировать отзывы с соседних домов.

          Простой пример: дом с одной стороны улицы, некое крутое место (парк, школа, ресторан, метро) - с другой. По прямой - 100 метров. Но улица - шестиполосная магистраль со сплошным потоком машин, а чтобы ее перейти - нужно делать крюк до ближайшего перехода в километр. Совсем другие радиусы доступности. Я делал такое исследование для Питера. Вот только для городов меньше Питера и Москвы вы даже не найдете зачастую карты пешеходных переходов, и такую метрику не построите.

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

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

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

          В общем много, много подводных камней, которые ломают все попытки создать подобные рекомендательные сервисы. Можно рекомендовать конкретный дом по отзывам тех, кто в нем жил, но вот рекомендации на уровне кварталов и районов по каким-то усредненным рейтингам - выходит уже совсем анекдотичная "средняя температура по больнице", практически бесполезная.


  1. Nikita_ele
    13.09.2023 19:14

    На чистоту воздуха также довольно значительно влияет высота поверхности рельефа - чем выше, тем чище воздух. В Москве очень хорошо прослеживается корреляция. Вот видео хорошее по теме: https://youtu.be/_YMACvdYkaI?si=lIkFPS1Mv3U_2yRq
    Недавно девушка писала статью про контроль качества воздуха в Ереване. Тоже внизу менее чистый: https://habr.com/ru/articles/755586/

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


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Статью почитал, интересно! Как экономить деньги на готовой станции, если очень хочется.

      заводы, очистные сооружения, свалки

      Я был рядом, ближе 150м. Не хочу не учитывать)

      С высотой над уровнем моря есть сложности с разрешением и точностью данных. Розу ветров учитывать не буду. Первое приближение с дистанцией работает!


  1. CAJAX
    13.09.2023 19:14

    Можно для каждого нехорошего фактора предрассчитать heatmap с градиентами, чтобы не было дискретности 199 - шумно, 200 - не шумно. А потом комбинировать по желанию с положительными/негативными весами. Вон, вам церкви и мечети нравятся, а кому-то шумят.


    1. CAJAX
      13.09.2023 19:14
      +1

      Типа такого


      1. igor_suhorukov Автор
        13.09.2023 19:14

        чтобы не было дискретности 199 - шумно, 200 - не шумно

        По ссылке сетка разбивки тепловой карты дискретная...


    1. igor_suhorukov Автор
      13.09.2023 19:14

      Отличная идея! Спасибо!!!

      Градиенты - это про комплексный вектор в каждой точки дискретной решетки? Как считать воздействие нескольких одинаковых факторов в одной точке?