Продолжаем изучать географию столицы и как она влияет на комфорт жилья. В этой публикации подключим маршрутизацию и расчитаем пешеходные расстояния от входа в метрополитен до жилых зданий. В прошлый раз я анализировал жилье в городе на удаленность от негативных факторов и поделился инструкцией "Где в Москве жить «неплохо»". Теперь же перейдем на позитивные факторы выбора места квартиры и найдем в Москве жилые дома в шаговой доступности от метро.

Сделаем это c помощью Graphhopper, OpenStreetMap H3 и PostGIS. Если вы далеки от PostgreSQL/Java, то сразу пролистывайте в конец статьи.

Подготовка данных

Загружал геоданные Москвы в Ubuntu, где установлены git, wget, docker.io:

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

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 .

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
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'

После успешного подключения к базе данных командой:

psql -h 127.0.0.1 -p 5432 -U postgres -d osmworld

В первую очередь нужно найти входы в метро и МЦК по тегу railway=subway_entrance:

create temporary table subway_entrance as 
  select id, centre, tags 
    from geometry_global_view e  
    where tags@>'railway=>subway_entrance';
Красные точки - выходы network=МЦК. Видно, что не все выходы из МЦК размечены с network
Красные точки - выходы network=МЦК. Видно, что не все выходы из МЦК размечены с network

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

CREATE TYPE building_info AS (id bigint, type table_reference, x float8, y float8);

create table living_building_near as
select m.id subway_entrance_id,st_x(m.centre) subway_entrance_x,st_y(m.centre) subway_entrance_y,
       array_agg((b.id,b.type,st_x(b.centre),st_y(b.centre))::building_info) buildings
  from subway_entrance m inner join geometry_global_view b on
    b.tags?'building' and
    not(b.tags?'amenity') and
    not(b.tags?'shop') 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','ice_rink','entrance','construction','transformer') and 
    ST_DWithin(b.geom::geography,m.centre::geography,1250) 
  group by 1,2,3; --select m.id subway_entrance_id,st_x(m.centre) subway_entrance_x,st_y(m.centre) subway_entrance_y,array_agg((b.id,b.type,st_x(b.centre),st_y(b.centre))::building_info) buildings from subway_entrance m inner join geometry_global_view b on b.tags?'_lb' and ST_DWithin(b.geom::geography,m.centre::geography,1250) group by group by 1,2,3;

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

osmworld=# \d living_building_near 
                  Table "public.living_building_near"
       Column       |       Type       | Collation | Nullable | Default 
--------------------+------------------+-----------+----------+---------
 subway_entrance_id | bigint           |           |          | 
 subway_entrance_x  | double precision |           |          | 
 subway_entrance_y  | double precision |           |          | 
 buildings          | building_info[]  |           |          | 

Создадим таблицу, куда сохраним рассчитанные программой расстояний:

create table subway_distance(
                entrance_id bigint,
                building_id bigint,
                building_type table_reference,
                distance smallint,
                primary key(entrance_id,building_id,building_type)
);

Расчет пешеходных расстояний

Выбрали дома в окрестностях, но расстояние по прямой обычно короче чем реальный путь. А чтобы его расчитать нужен либо сервис расчета маршрутов за деньги и с ограничением количества запросов, либо локльно запущенный роутер энджин. Для OpenStreetMap есть несколько Open Source движков маршрутизации. Но мне привычнее и удобнее использовать Graphhopper на Java. В чем основное преимущество перед API любого поставщика для прокладки маршрутов - отсутствие лимитов, сетевых задержек и платы за сервис. Например, для этой публикации программа расчитала 450032 расстояний "без регистраций и СМС". Также при желании Graphhopper позволяет настраивать веса и можно делать роутинг по правилам предпочитая например близость деревьев к дорожке и избегая мест где нет асфальта.

Основная проблема с расчетом расстояний - это время вычислений, в случае если сервис взаимодействует с программой как REST через TCP, поэтому я буду использовать Graphhopper 8.0 как библиотеку с in-process взаимодействием без вызовов по HTTP. Для этого добавлю в скрипт сборки программы зависимости graphhopper-core и postgresql jdbc драйвер:

Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.github.igor-suhorukov</groupId>
    <artifactId>routing-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
      </properties>

    <dependencies>
        <dependency>
            <groupId>com.graphhopper</groupId>
            <artifactId>graphhopper-core</artifactId>
            <version>8.0</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.6.0</version>
        </dependency>
    </dependencies>
</project>

Моя Java программа извлекает из таблицы living_building_near идентификаторы входа в метро и здания в окрестностях а также их координаты, расчитывает пешеходную дистанцию и сохраняет ее в таблицу subway_distance. В процессе работы пропуская строения, пешеходное расстояния до которых больше чем 1250м.

package com.github.isuhorukov.routing;

import com.graphhopper.GHRequest;
import com.graphhopper.GHResponse;
import com.graphhopper.GraphHopper;
import com.graphhopper.ResponsePath;
import com.graphhopper.config.CHProfile;
import com.graphhopper.config.Profile;
import org.postgresql.jdbc.PgArray;
import org.postgresql.util.PGobject;

import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Routing {

    public static void main(String[] args) throws Exception {
        GraphHopper hopper = getGraphHopper();
        try (Connection connection = DriverManager.getConnection(
                System.getenv("jdbc_url"), System.getenv("user"), System.getenv("password"))) {
            connection.setAutoCommit(false);
            try {
                var distances = calculateDistances(connection, hopper);
                saveDistance(connection, distances);
            } catch (SQLException e) {
                connection.rollback();
                throw e;
            }
        }
    }

    private static GraphHopper getGraphHopper() {
        var hopper = new GraphHopper();
        hopper.setOSMFile(System.getenv("osm_file"));
        hopper.setGraphHopperLocation("route");
        hopper.getCHPreparationHandler().setCHProfiles(new CHProfile("foot"));
        hopper.setProfiles(new Profile("foot").setVehicle("foot"));
        hopper.importOrLoad();
        return hopper;
    }

    private static List<Distance> calculateDistances(Connection connection, GraphHopper hopper) throws SQLException {
        List<Distance> distances = new ArrayList<>();
        try (Statement subwayQuery = connection.createStatement()){
            int step=0;
            try (ResultSet livingBuilding = subwayQuery.executeQuery("select * from living_building_near")){
                while (livingBuilding.next()){
                    long subwayEntranceId = livingBuilding.getLong("subway_entrance_id");
                    double subwayEntranceX = livingBuilding.getDouble("subway_entrance_x");
                    double subwayEntranceY = livingBuilding.getDouble("subway_entrance_y");
                    PgArray buildingsArray = (PgArray) livingBuilding.getArray("buildings");
                    List<Building> buildings = mapBuildings(buildingsArray);
                    System.out.println(step++);
                    distances.addAll(buildings.stream().map(building -> {
                        short distance = calculateDistances(hopper, building, subwayEntranceY, subwayEntranceX);
                        return new Distance(subwayEntranceId,building.buildingId, building.buildingType, distance);
                    }).collect(Collectors.toList()));
                }
            }
        }
        return distances;
    }

    private static void saveDistance(Connection connection, List<Distance> distances) throws SQLException {
        try (PreparedStatement insert = connection.prepareStatement(
                "insert into subway_distance(entrance_id,building_id,building_type,distance) " +
                        "values (?,?,?::table_reference,?)")){
            distances.forEach(distance -> {
                if(distance.distance>1250) return;
                try {
                    insert.setLong(1, distance.subwayEntranceId);
                    insert.setLong(2, distance.buildingId);
                    insert.setString(3, distance.buildingType);
                    insert.setShort(4, distance.distance);
                    insert.addBatch();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            });
            insert.executeBatch();
            connection.commit();
        }
    }


    private static List<Building> mapBuildings(PgArray buildingsArray) throws SQLException {
        return getPgObjects(buildingsArray).stream().map(pGobject -> {
            String value = pGobject.getValue();
            if(value==null || value.length()<=2){
                throw new IllegalArgumentException();
            }
            String[] parts = value.substring(1, value.length() - 1).split(",");
            long buildingId = Long.parseLong(parts[0]);
            String buildingType = parts[1];
            double buildingX = Double.parseDouble(parts[2]);
            double buildingY = Double.parseDouble(parts[3]);
            return new Building(buildingId, buildingType, buildingX, buildingY);
        }).collect(Collectors.toList());
    }

    private static List<PGobject> getPgObjects(PgArray buildingsArray) throws SQLException {
        Object[] array = (Object[]) buildingsArray.getArray();
        buildingsArray.free();
        return Arrays.stream(array).map(object -> (PGobject) object).collect(Collectors.toList());
    }

    private static short calculateDistances(GraphHopper hopper,
                                      Building building, double subwayEntranceY, double subwayEntranceX) {
        GHRequest request = new GHRequest(subwayEntranceY, subwayEntranceX, building.buildingY, building.buildingX);
        request.setProfile("foot");
        GHResponse route = hopper.route(request);
        ResponsePath bestRoute = route.getBest();
        return (short) Math.round(bestRoute.getDistance());
    }

    private static class Building{
        long buildingId;
        String buildingType;
        double buildingX;
        double buildingY;
        public Building(long buildingId, String buildingType, double buildingX, double buildingY) {
            this.buildingId = buildingId;
            this.buildingType = buildingType;
            this.buildingX = buildingX;
            this.buildingY = buildingY;
        }
    }

    private static class Distance{
        long subwayEntranceId;
        long buildingId;
        String buildingType;
        short distance;
        public Distance(long subwayEntranceId, long buildingId, String buildingType, short distance) {
            this.subwayEntranceId = subwayEntranceId;
            this.buildingId = buildingId;
            this.buildingType = buildingType;
            this.distance = distance;
        }
    }
}

Параметры программе передаются через переменные окружения jdbc_url, osm_file, password, user.

Центры зданий выгрузил в GeoJSON файл:

\copy (select json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', st_AsGeoJSON(centre)::json))) from (select distinct centre from subway_distance s inner join geometry_global_view b on b.id=s.building_id and b.type=s.building_type) buildings ) to '~/moscow_metro_footpath.json';

Когда хочется найти панельный дом в OpenStreetMap

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

Современные 3D технологии оживляют атмосферу домов, построенных по типовому проекту
Современные 3D технологии оживляют атмосферу домов, построенных по типовому проекту
--все жилые дома
select count(tags->'design:ref')*100.0/count(*) cnt, count(*) from geometry_global_view where tags?'_lb';
         cnt         | count  
---------------------+--------
 18.7563917273088398 | 118317


--в 15минутах от метро
select count(tags->'design:ref')*100.0/count(*) cnt, count(*) from (select distinct building_id, building_type, b.tags from subway_distance s inner join geometry_global_view b on b.id=s.building_id and b.type=s.building_type) b;
         cnt         | count 
---------------------+-------
 38.1045937491921516 | 38683
Значения серий домов, указанные для Москвы в OpenStreetMap
select regexp_split_to_table(tags->'design:ref',';') design_ref, count(*) 
  from geometry_global_view 
  where tags?'_lb' 
    group by 1 
    order by 2 desc;

design_ref            | count 
---------------------------------+-------
 II-18-01/12                     |  1100
 П44-1/17 тип 1                  |   636
 II-18-01/МИ вариант «Б»         |   635
 1-511-4/М                       |   627
 П44Т-1/17 тип 1                 |   534
 П3-2/16                         |   514
 И-209А                          |   496
 1-511-3/М                       |   464
 1-515-4/М                       |   371
 II-68-01/16Ю-2/78               |   361
 II-49-04/Ю вариант «Д»          |   331
 II-14                           |   309
 КОПЭ-85                         |   295
 1-410                           |   267
 1-510-4/М23                     |   265
 СМ-6                            |   252
 1-515-04/9ЮЛ                    |   246
 1-515-4/М37                     |   243
 П44-1/16 тип 1                  |   242
 П43/16                          |   233
 II-14-33                        |   231
 II-68-01/16Ю                    |   231
 Башня Вулыха                    |   227
 КТЖС-2                          |   223
 П47/12                          |   222
 1-410-9                         |   219
 1-515-3/Ю37                     |   218
 II-49-06/Ю вариант «Д»          |   216
 КТЖС-1                          |   206
 КТЖС-5                          |   191
 И-209                           |   184
 1-515-5/М                       |   181
 II-01                           |   180
 П46-2/12В                       |   180
 1-510-3/М23                     |   171
 1-515-3/Ю                       |   163
 П44Т-4/17 тип 2                 |   162
 1-515-5/М37                     |   157
 1-515-04/9М                     |   155
 II-18-11/МИ вариант «Б»         |   151
 1605АМ/12                       |   151
 П44-4/17 тип 2                  |   147
 II-49-08/Ю вариант «Д»          |   145
 1-511-4/М37                     |   144
 1-511-3/Ю                       |   141
 II-14-31                        |   140
 II-29-41/37                     |   135
 II-18-21/12                     |   134
 П30-4/12                        |   133
 1-515-06/9ЮЛ                    |   131
 1-510-4/М                       |   130
 1605АМ-04/12Ю                   |   129
 П55-4/12                        |   124
 II-68-03/12Ю                    |   122
 П-44                            |   118
 1-511-3/М37                     |   117
 1-511-4/Ю                       |   114
 II-57-03/12ЮА                   |   112
 1-511-2/Ю                       |   108
 1-511                           |   106
 1-510-4/Ю23                     |   104
 1-510-3/М                       |   103
 П3-1/16                         |    98
 П30-3/12                        |    97
 II-29/37                        |    94
 П46М-2/14                       |    94
 II-18-31/12                     |    94
 1-515-06/9М                     |    92
 Мг-1                            |    90
 КТЖС-9                          |    89
 II-18-01/МИ вариант «К»         |    89
 П44Т-4/17 тип 3                 |    89
 II-49-06/Ю вариант «П»          |    89
 II-49-04/Ю вариант «П»          |    88
 П44-4/17 тип 3                  |    88
 II-28-3                         |    88
 П46М                            |    87
 П46-3/12                        |    86
 1-410-10                        |    86
 1-447С-5                        |    85
 II-49-02/Ю вариант «Д»          |    84
 II-18-31/12А                    |    83
 II-14-32                        |    81
 II-49-06/М вариант «Д»          |    81
 П44Т-4/17 тип 5                 |    81
 1-447С-7                        |    79
 П30-1/12                        |    79
 П44-4/17 тип 4                  |    79
 II-28-4                         |    78
 П44Т-4/17 тип 4                 |    75
 II-29-03/Ю37                    |    74
 КОПЭ-2000                       |    73
 1-511-2/М                       |    72
 П46/12                          |    71
 II-18-02/12                     |    70
 II-49-04/М вариант «Д»          |    67
 1-410 (общежития)               |    67
 Унифицированный каркас          |    65
 П44-4/16 тип 2                  |    65
 II-29-03/М37                    |    63
 ГМС-2001                        |    61
 II-29-04/М37                    |    61
 П30-2/12                        |    61
 1-511-3/Ю37                     |    60
 1-510-4/М37                     |    59
 4572А                           |    59
 П44-4/17 тип 5                  |    57
 П46М-4/14                       |    57
 II-49/Ю вариант «Д»             |    57
 II-29-04/Ю37                    |    57
 II-68-02/16М                    |    55
 1-510-3/Ю23                     |    55
 П44Т                            |    54
 II-68-02/12К                    |    54
 1-410-12                        |    54
 П3М-1/17                        |    54
 II-29                           |    53
 II-05-02А                       |    52
 ИП46С                           |    52
 П55-26/12                       |    51
 П3М                             |    51
 И-522А                          |    50
 П46М-4/9                        |    48
 II-18-01 вариант «Б»            |    48
 1-511-4/Ю37                     |    47
 И-155Б                          |    47
 П55-25/12                       |    46
 КОПЭ-80                         |    46
 II-29-05/Ю37                    |    45
 П44                             |    45
 П3М-1/16                        |    45
 1-447С-8                        |    42
 П55-21/12                       |    42
 II-67 Смирновская               |    42
 П44К-1/17                       |    42
 II-29-14/Ю37                    |    41
 П30-6/12                        |    41
 II-57                           |    40
 П30/12                          |    40
 111М                            |    40
 II-29-03/М                      |    40
 1-511-14/М37                    |    40
 1-447С-3                        |    40
 II-04                           |    39
 II-49-08/Ю вариант «П»          |    39
 КОПЭ-М «Парус»                  |    39
 1-515-178/9М                    |    39
 И-III-3                         |    38
 СМ-3                            |    38
 II-29-04/М                      |    38
 1605АМ/9                        |    38
 II-49/М вариант «Д»             |    37
 П55-23/12                       |    37
 БС 05-17М                       |    37
 1-410-13                        |    36
 1-410-11                        |    36
 1Мг-601/Д                       |    36
 II-49-08/М вариант «Д»          |    35
 1-510-4/Ю37                     |    35
 II-68                           |    35
 П3М-3/17                        |    35
 II-68-01/22-83                  |    34
 II-29-05/М                      |    33
 П3/16                           |    33
 1Мг-601                         |    32
 П46М-22пр/14                    |    32
 4570                            |    32
 II-57-05/Ю                      |    31
 1-515/9                         |    31
 II-29-15/М37                    |    31
 1-447С-1                        |    31
 1605АМ-04/9Ю                    |    30
 1-510-3/Ю                       |    30
 П30-5/12                        |    30
 П3М-4/17                        |    29
 1-510-3/М37                     |    29
 1-515-3/М                       |    29
 Тип I                           |    29
 П3М-2/16                        |    29
 1-511-2/Ю37                     |    29
 П46М-2/9                        |    29
 КТЖС 1п-25                      |    29
 II-05-01                        |    28
 1Мг-601/Ж                       |    28
 II-29-14/М37                    |    28
 Тип IV                          |    28
 II-29-05/М37                    |    28
 II-67 Москворецкая              |    28
 II-28-2                         |    27
 II-49-04/М вариант «П»          |    27
 П44-4/16 тип 5                  |    27
 П42/16                          |    26
 1-300-3                         |    26
 П3М-2/17                        |    26
 II-57-05/12ЮА                   |    26
 1-410-5                         |    26
 1-335-1                         |    26
 П46М-22пр/9                     |    26
 II-57-07/Ю                      |    25
 1-447С-2                        |    25
 П3МК                            |    25
 П44-4/16 тип 3                  |    24
 П-111М                          |    24
 II-29-04/Ю                      |    24
 II-49/12 вариант «П»            |    24
 П31/12                          |    24
 II-49/Ю вариант «П»             |    24
 1-511-130/37                    |    23
 II-57-03/12МА                   |    23
 ПИК-1                           |    22
 1-515-24/9М                     |    22
 I-511(I-511/25БИ)               |    22
 1-510/23                        |    22
 И-155НБ                         |    22
 СМ-3-3                          |    22
 1-447С-6                        |    21
 П44-4/16 тип 4                  |    21
 I-515(I-515/37)                 |    21
 II-29-03/Ю                      |    21
 II-18-01 вариант «К»            |    21
 II-20                           |    21
 II-29-15/Ю37                    |    21
 КТЖС-1ук                        |    20
 1-335-2                         |    20
 П30                             |    20
 1605АМ-06/12Ю                   |    20
 И-155Мк                         |    19
 1-247С-1                        |    19
 П55-24/12                       |    19
 П3М-3/16                        |    18
 1605АМ/5                        |    18
 КТЖС 2п-25                      |    18
 1-447С-38                       |    18
 И-491А                          |    17
 И-155-16К1                      |    17
 П46М-21/9                       |    17
 1-410-8                         |    17
 1-447С-40                       |    17
 П46М-21/14                      |    17
 II-07-19                        |    17
 II-49-02/М вариант «Д»          |    17
 И-1782/1                        |    17
 1605АМ-06/9Ю                    |    17
 II-57-03/ЮА                     |    16
 П3М-4/16                        |    16
 II-68-01/12-83                  |    16
 1605АМ-08/9М                    |    16
 II-57-05/ЮА                     |    16
 1-511/37                        |    16
 Пд4-1/12Н1                      |    15
 II-67-386                       |    15
 1-801                           |    15
 П3М-7/23                        |    15
 1-513                           |    15
 П46М-22л/9                      |    15
 П55М-4/14                       |    15
 1-515-26/9М                     |    15
 1-515-3/М37                     |    15
 222-15/17                       |    14
 П44Т-1/14М тип 1                |    14
 II-67 Тишинская                 |    14
 II-29-160                       |    14
 1-510-3/Ю37                     |    14
 И-700                           |    14
 СМ-3-5                          |    14
 ПИК-2                           |    14
 ЛСР                             |    14
 1-515/37                        |    13
 I-511(I-511/37)                 |    13
 1-464А-15                       |    13
 II-49-06/М вариант «П»          |    13
 КОПЭ                            |    13
 II-14-34                        |    13
 II-14-35                        |    13
 1-244-1                         |    13
 БС 05-16М                       |    13
 II-57-07/ЮА                     |    13
 II-57-05/12МА                   |    12
 1МГ-601-Ж                       |    12
 КОПЭ-87                         |    12
 П-3/17                          |    12
 П55/12                          |    12
 П3М-6/17                        |    12
 И-155Мм                         |    12
 II-34                           |    12
 II-68-03/12Ю-2/76               |    12
 1-467Д                          |    12
 I-515(I-515/5)                  |    12
 ШКД                             |    12
 Мм1-3                           |    12
 II-18/12                        |    12
 1-467А-17                       |    12
 1-447С-4                        |    11
 1-233-2                         |    11
 И-1491-17                       |    11
 I-515-3/Ю37                     |    11
 П44К                            |    11
 I-410                           |    11
 1-510-2/23                      |    11
 II-18-11/МИ вариант «К»         |    11
 1-510-4/Ю                       |    11
 1-464А-17                       |    11
 1-204-113                       |    11
 222-02/17                       |    11
 1-447С-37                       |    11
 II-29-05/Ю                      |    11
 Мг-2                            |    11
 1Р-447С-25                      |    11
 1Р-447С-26                      |    11
 П46М-22л/9И                     |    11
 II-68-01/16-83                  |    10
 П22/25                          |    10
 П46                             |    10
 1Мг-600-1                       |    10
 1-515-4/Ю                       |    10
 II-68-01/14-83                  |    10
 1-510/37                        |    10
 П44Т-1/25                       |    10
 1-204-5                         |    10
 4570-63                         |    10
 1-515/9М                        |    10
 Пд4-1/16Н1                      |    10
 БС 08-17К                       |    10
 П55М-2/14                       |    10
 И-155-16К2                      |    10
 I-410 (САКБ)                    |     9
 П-46М                           |     9
 П44М-1/17                       |     9
 Мм1-4                           |     9
 КТЖС-14                         |     9
 П55-22/12                       |     9
 П30(П30/12)                     |     9
 Пд4-5/12Н1                      |     9
 И-700Н                          |     9
 II-57-05/М                      |     9
 I-515-4/М37                     |     9
 П30М                            |     9
 1-225-109                       |     9
 И-155Б2                         |     9
 ЭК-1                            |     8
 КОПЭ-Башня(КОПЭ-Башня М-2)      |     8
 Пд4-5/16Н1                      |     8
 2-4-1                           |     8
 Пд4                             |     8
 Бекерон                         |     8
 И-782                           |     8
 II-68-04/12М1                   |     8
 111                             |     8
 Пд4-1/10Н1                      |     8
 И-155-16М4                      |     8
 И-155                           |     8
 1-447С-39                       |     8
 1-511-2/М37                     |     8
 БС 07-17М                       |     8
 И-1820                          |     8
 1Мг-601-441                     |     8
 И-155-22М3                      |     8
 II-66                           |     8
 И-155С                          |     7
 II-49                           |     7
 1-801-1                         |     7
 И-155-9М2                       |     7
 П4/22                           |     7
 И-155-16К3                      |     7
 И-155-9М3                       |     7
 1605АМ-06/9М                    |     7
 Пп83(83-305/28-503)             |     7
 II-08                           |     7
 индивидуальный проект           |     7
 И-1158                          |     7
 Пд4-1/12                        |     7
 П46М-21/9И                      |     7
 II-29-208                       |     7
 Град-2М                         |     7
 П55-2/12А                       |     7
 И-155-16К8                      |     7
 СЭМ-2                           |     7
 II-07-04                        |     7
 1605АМ-04/9М                    |     7
 1-467А-15                       |     7
 1-467А-12                       |     7
 ПД-4                            |     7
 П22К                            |     7
 1605АМ/Э                        |     7
 II-49-08/М вариант «П»          |     7
 1-515-142/9М                    |     7
 I-410(I-410 (САКБ))             |     7
 1605АМ-08/9Ю                    |     7
 II-18/12(II-18-01/12)           |     7
 I-510/23БИ                      |     6
 И-286                           |     6
 Пд4-5/10Н1                      |     6
 1-211-2                         |     6
 I-511                           |     6
 П3М-3/9                         |     6
 БАШНЯ М-1                       |     6
 Тип II                          |     6
 П-44Т                           |     6
 И-155-22М4                      |     6
 И-273                           |     6
 П55-2/12                        |     6
 И-155-9М4                       |     6
 СМ-3-4                          |     6
 БС 09-17К                       |     6
 П3М-6                           |     6
 БОД-1                           |     6
 1605-АМ(1605АМ/12Ю)             |     6
 1-211-3                         |     6
 II-57-07/МА                     |     6
 БС 08-17М                       |     6
 222-12/25                       |     6
 П-44м                           |     6
 П3-3/16                         |     6
 Пд4-2/16Н1                      |     6
 1Мг-600                         |     5
 220-М17-1122-РТ                 |     5
 И-155-22М2                      |     5
 Пд4-1/8                         |     5
 I-515/9М                        |     5
 СЭМ2                            |     5
 1-253А-7                        |     5
 1-235-1                         |     5
 1МГ-601(1МГ-601-Ж)              |     5
 ПБ-02                           |     5
 И-155Н                          |     5
 1-515-5/Ю                       |     5
 И-155-16М2                      |     5
 И-1751                          |     5
 1-515                           |     5
 П46М-10л/17                     |     5
 220-М25-1222-РТ                 |     5
 ТМ-25                           |     5
 II-28                           |     5
 Призма (И-1630)                 |     5
 1-234-1КБ                       |     5
 I-447С-26                       |     5
 И-760А                          |     5
 1МГ-601                         |     5
 I-515/9ЮЛ                       |     5
 Пд3-02/22                       |     5
 КПД-4570-73/75                  |     5
 1-510                           |     5
 КОПЭ(КОПЭ-85)                   |     5
 П3-4/16                         |     5
 1-801-3                         |     5
 II-18-32/12А                    |     5
 П46М-2/14И                      |     5
 I-511/25БИ                      |     5
 СМ-3-2                          |     5
 П44Т-4/14М тип 4                |     5
 Пд3-03/22                       |     5
 I-510(I-510/23БИ)               |     5
 МПСМ                            |     5
 И-155-16М5                      |     5
 ПБ-01                           |     4
 П44ТМ                           |     4
 1-253А-2                        |     4
 II-57-07/12ЮА                   |     4
 II-18/12(II-18-21/12А)          |     4
 П44ТМ/25                        |     4
 222-11/17                       |     4
 II-49(II-49/Ю вариант Д)        |     4
 XI-36-01                        |     4
 1Мг-601/Е                       |     4
 К7/16                           |     4
 БС 08-16К                       |     4
 С-222-01/17                     |     4
 1605АМ/л                        |     4
 1-446С-3                        |     4
 1-447С                          |     4
 И-155-22М1                      |     4
 И-521А                          |     4
 И-155-Б                         |     4
 1-428-3                         |     4
 Мм1-2                           |     4
 I-515/37                        |     4
 И-1630(Призма)                  |     4
 1605АМ-03/12Ю                   |     4
 1-510-2/37                      |     4
 БС 12-17М                       |     4
 БС 06-17М                       |     4
 1-447С-34                       |     4
 П3М-1/9                         |     4
 И-1723 (ШКД)                    |     4
 МЭС-84                          |     4
 Пд4-4/16Н1                      |     4
 Колос                           |     4
 1-440С-1                        |     4
 Д-25                            |     4
 П22-1/16                        |     4
 1-447                           |     4
 1-260-3А                        |     4
 220-М25-1223-УТ                 |     4
 М-10                            |     4
 1-515-4/Ю37                     |     4
 И-155-9М5                       |     3
 П23/16                          |     3
 1-515-5/Ю37                     |     3
 П3                              |     3
 114-86                          |     3
 II-57-07/М                      |     3
 Пд4-1/16                        |     3
 система КУБ                     |     3
 ЕвроПа                          |     3
 БС 09-17М                       |     3
 1-440С-3                        |     3
 222-01/17                       |     3
 II-18-01/08                     |     3
 МЮ                              |     3
 II-57-А/12                      |     3
 П44Т-4/14М тип 3                |     3
 1-260-1                         |     3
 VII-40                          |     3
 КТЖС-13                         |     3
 И-1168                          |     3
 И-1194                          |     3
 1-253-3                         |     3
 БС 09-16К                       |     3
 К4/16                           |     3
 П46ММ, И-1824                   |     3
 II-18-01/09 МИБ                 |     3
 Пд4-2/16                        |     3
 КТЖС-16                         |     3
 И-155-16М1                      |     3
 И-1822/1                        |     3
 КОПЭ-М-Парус                    |     3
 1-439А-5                        |     3
 П55М-30                         |     3
 1-228                           |     3
 1-467А-18                       |     3
 П30(85-07)                      |     3
 И-155-9К1                       |     3
 222-08/17                       |     3
 И-155-22М7                      |     3
 I-447С                          |     3
 VI-12А                          |     3
 I-515-178/9М                    |     3
 222-09/17                       |     3
 II-68-04/12М2                   |     3
 И-155-16М6                      |     3
 П44Т-4/14М тип 5                |     3
 И-1414                          |     3
 II-49/М вариант Д               |     3
 Пд4-5/8                         |     3
 И-155-16М3                      |     3
 VII-42                          |     3
 И-1824                          |     3
 И-701                           |     3
 II-18-22/МИ вариант «Б»         |     3
 И-155-16К4                      |     3
 И-155-9К5                       |     3
 1-515-5                         |     3
 II-49(II-49/М вариант П)        |     3
 П46М-22пр/9И                    |     3
 П46М(ИП46М)                     |     3
 П-46                            |     3
 1-428-1                         |     2
 164-80-3                        |     2
 1-228-9                         |     2
 I-511-4/М                       |     2
 II-18-01/09 МИ вариант К        |     2
 П-3М                            |     2
 1-447С-47                       |     2
 П46М-22л/14ПР                   |     2
 П46М-322/14                     |     2
 П46М-23пр/14                    |     2
 П46ММ                           |     2
 220-М17-1234-РТ                 |     2
 1-801-13                        |     2
 П-30                            |     2
 КТЖС 3п-25                      |     2
 1-447С-10                       |     2
 П55М                            |     2
 VI-44                           |     2
 1-228-7                         |     2
 И-155-9К3                       |     2
 II-49(II-49/М вариант Д)        |     2
 1-447С-17                       |     2
 П3(П3/16)                       |     2
 I-511-2/Ю                       |     2
 I-515-06/9ЮЛ                    |     2
 КТЖС-3                          |     2
 1-801-4                         |     2
 И-155-16К5                      |     2
 И-155-16К7                      |     2
 II-18                           |     2
 1-460-7                         |     2
 1-466К-4                        |     2
 И-155-22М6                      |     2
 1-260-2                         |     2
 1-277-1                         |     2
 П44К(П44Т,П44К)                 |     2
 I-515-06/9М                     |     2
 1-510-2                         |     2
 1МГ-601/Д                       |     2
 II-05                           |     2
 1-467А-20                       |     2
 1-234-1                         |     2
 1-225-110                       |     2
 Пд4-2/12                        |     2
 П46М-23л/14                     |     2
 С-222-15/17                     |     2
 И-155-16М7                      |     2
 1-222-126                       |     2
 1-447С-46                       |     2
 1-300                           |     2
 ИП46М                           |     2
 И-155-9М1                       |     2
 1-446С-1                        |     2
 1-467Д-20                       |     2
 1-447С-35                       |     2
 Пд3-01/22                       |     2
 П46М-302/14                     |     2
 II-68-04/12М                    |     2
 1-447С-53                       |     2
 I-511/37                        |     2
 К-8-49Б                         |     2
 II-57-02/12ЮА                   |     2
 1-428-2                         |     2
 Пп70-07/17                      |     2
 1Р-447С-25М                     |     2
 И-1782                          |     2
 XI-36-02                        |     2
 1-206-104                       |     2
 П44Т-4/14М тип 2                |     2
 II-57-07/12МА                   |     2
 И-155-9К2                       |     2
 1-204-112                       |     2
 II-57/17                        |     2
 II-18-01/09                     |     2
 II-18(II-18-01/09 МИБ)          |     2
 И-209A                          |     2
 1-253А-6                        |     2
 I-511-3/М                       |     2
 И-155-22К1                      |     2
 I-515-24/9М                     |     2
 II-29-Б                         |     2
 СУ-155                          |     2
 1-301-1                         |     2
 1-464А-1                        |     2
 1-102-12                        |     2
 I-510-4/М23                     |     2
 1-225-111                       |     2
 VI-52 вариант 1                 |     1
 1Р-303-2                        |     1
 II-49/М вариант «П»             |     1
 П-3/16                          |     1
 1-439А-7                        |     1
 П3М-2/9                         |     1
 Пд4-5/12                        |     1
 БАШНЯ М-2                       |     1
 1-447С-13                       |     1
 II-18/12(II-18-31/12А)          |     1
 VII-70                          |     1
 1С-01-1                         |     1
 Пд4-2/12Н1                      |     1
 П30(П31/12)                     |     1
 1-464Д-105                      |     1
 1-410-4                         |     1
 II-07                           |     1
 1-255-5                         |     1
 1-515-5М                        |     1
 Лебедь (унифицированный каркас) |     1
 II-32-04                        |     1
 II-66/БС-36                     |     1
 КПД-4570(КПД-4570-I)            |     1
 1-460-10                        |     1
 I-515-5/М37                     |     1
 П46М-22пр/14ПР                  |     1
 I-447С-1                        |     1
 К-7-3-5                         |     1
 C-222-01/17                     |     1
 II-32-05                        |     1
 П44Т(П44Т, П44К)                |     1
 II-57-А/09                      |     1
 ЦИТП № 51                       |     1
 1Р-303-17                       |     1
 1-439А-4                        |     1
 1-300-2                         |     1
 1-251-7                         |     1
 1-203-15                        |     1
 1-447С-12                       |     1
 1-301-2                         |     1
 И-155-22М5                      |     1
 I-335-5                         |     1
 П46М, И-1824                    |     1
 brown                           |     1
 1-275-4                         |     1
 П46М-321/14                     |     1
 С-222-02/17                     |     1
 БС 10-17М                       |     1
 II-57-05/МА                     |     1
 II-49/Ю вариант Д               |     1
 Пд4-4/12Н1                      |     1
 II-38-03/1A                     |     1
 К-7 (К7-3)                      |     1
 I-447                           |     1
 II-49(II-49П/12 (И-294А))       |     1
 1-418                           |     1
 II-66/БС-34                     |     1
 161-101-21                      |     1
 1-251А-17                       |     1
 1-460-9                         |     1
 I-467А-15                       |     1
 П30(П30/12*)                    |     1
 I-447С-25                       |     1
 И-1849                          |     1
 БС 01-17К                       |     1
 1-251-15                        |     1
 1-801-16                        |     1
 II-32-130                       |     1
 БС 07-16М                       |     1
 1-447С-12А                      |     1
 124-124-4                       |     1
 Пд4-5/14Н1                      |     1
 1-335-4                         |     1
 1-253-5                         |     1
 КОПЭ(монолит-кирпич)            |     1
 II-29-3(II-29-3(9))             |     1
 II-49/Ю                         |     1
 V-79                            |     1
 12 (Союзтранспроект)            |     1
 1-204-6                         |     1
 1-204-114                       |     1
 Т-3                             |     1
 II-57-02/12МА                   |     1
 1-251                           |     1
 КПД-4572А                       |     1
 1-242-103                       |     1
 I-335-4                         |     1
 Призма(И-1630)                  |     1
 I-447С-38                       |     1
 Пд4-1/14Н1                      |     1
 П3М-4/9                         |     1
 I-515(сталинский)               |     1
 VI-13А                          |     1
 КОПЭ(КОПЭ-2000))                |     1
 И-1747                          |     1
 1-275-1                         |     1
 1-466А-2                        |     1
 222-10/17                       |     1
 БС 10-16М                       |     1
 БС 06-16М                       |     1
 I-510(I-510/37)                 |     1
 II-51                           |     1
 П46М-302/14И                    |     1
 П47(П47/12*)                    |     1
 K-7(индивидуальный проект)      |     1
 И-1746                          |     1
 65-426/I                        |     1
 VI-23                           |     1
 П-49 Д                          |     1
 I-515/9                         |     1
 I-515-04/9ЮЛ                    |     1
 П47(П47/12)                     |     1
 1-253А-4                        |     1
 1-251-11                        |     1
 1-294-3                         |     1
 1-447С-54                       |     1
 VI-52/2                         |     1
 1-467Д-19                       |     1
 I-467А-4                        |     1
 2-5-6                           |     1
 1МГ-601-441                     |     1
 1-277-2                         |     1
 1-251-2                         |     1
 КПД-4570-I                      |     1
 1-447С-44                       |     1
 П46М-23пр/9                     |     1
 I-511-130/37                    |     1
 II-18-21/12А                    |     1
 С222                            |     1
 П-111М(П-111)                   |     1
 1-464Д-102                      |     1
 1-447С-36                       |     1
 II-66/БС-35                     |     1
 ИП-46С                          |     1
 С-222(222)                      |     1
 white                           |     1
 II-65                           |     1
 1-201-12                        |     1
 ПЗ                              |     1
 П30/12*                         |     1
 1-252-8                         |     1
 ДОМРИК тип 1                    |     1
 1-439А-3                        |     1
 1-447С-11А                      |     1
 17 (Союзтранспроект)            |     1
 П46М-23л/9                      |     1
 И-155-22К5                      |     1
 1-447С-33                       |     1
 П-3м                            |     1
 1-255-4                         |     1
 П46М-322/14И                    |     1
 I-410 (тип I, IV)               |     1
 1-251-13                        |     1
 1-447С-9                        |     1
 I-447С-8                        |     1
 1-262                           |     1
 1-280                           |     1
 1-241-115                       |     1
 КОПЭ(КОПЭ-80)                   |     1
 II-68-01                        |     1
 II-18-03/МИ вариант «Б»         |     1
 1-255-6                         |     1
 II-49(II-49/12 вариант П)       |     1
 П46М-23пр/14И                   |     1
 П46М-22л/14                     |     1
 II-29-3(9)                      |     1
 K-7                             |     1
 1-253-6                         |     1
 И-1483                          |     1
 П3М-2/19                        |     1
(813 rows)

Всего-то вручную надо проверить 100 000 жилых зданий в Москве и указать design:ref где не указан... Бродить по джунглям бетонных коробок с OSMTracker, наслаждаясь атмосферой мелонхолии и флешбеками детства и студенчества. В этом есть что-то родное и одновременно грустное!

Для домов у метро процент design:ref = 35%, значит осталось проверить 23983 не размеченных этим тегом домов! Эх, если бы каждый Хабровчанин окинул взором свои окрестности и указал design:ref и год постройки для пары домов. Но пока я решил не включать этот параметр в аналитику.

Результаты

По данным OpenStreetMap 32% зданий в Москве расположены в 15 минутах пешком от метро. Рассмотреть расположение этих домов у метро можно по ссылке GitHub Gist, где карту можно масштабировать (там еще случайно оказалась пасхалочка в центре с домом).

Расчеты основаны на открытых геоданных используя только Open Source компоненты. Если вы нашли ошибку, в первую очередь проверьте на OpenStreetMap обозначена ли там пешеходная дорога от вашего дома к метро. Во вторую очередь попробуйте вручную построить маршрут на сайте и смотрите как прокладывается маршрут и какое расстояние. И если вдруг у вашего дома с моей карты "пропало метро", то пишите в коментариях - будем разбираться!

В следующих публикациях рассчитаем пешеходное расстояние от домов до школ, детсадов, поликлиник. Удачного вам поиска комфортного жилья!

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


  1. Mitya78
    26.10.2023 18:26

    А из кадастровой карты что-то можно извлечь? Уже и не помню.


    1. sshikov
      26.10.2023 18:26
      +1

      Вроде можно. Но когда я пытался это сделать, кадастровая карта Росреестра работала ужасно медленно. И потом, очень желателен доступ к API (там вроде был ArcGIS), но его не факт что дадут.


  1. aborouhin
    26.10.2023 18:26
    +2

    Вот если бы спарсить гугл/яндекс-панорамы, "прогулять" по ним нейросеть, обучив на тех данных, которые уже размечены на OSM, и на основании полученной модели разметить всё остальное... Дата-сайентисты, ау! :)


    1. sshikov
      26.10.2023 18:26
      +1

      А не проще пойти от года строительства, фактически большинство домов района построены одновременно, и относятся к примерно одной серии.


      1. igor_suhorukov Автор
        26.10.2023 18:26

        Кстати, да! Плюс можно попробовать автоматическую кластеризацию по форме линий, как подсказку для человека что дома скорее всего относятся к одному проекту.


        1. sshikov
          26.10.2023 18:26

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

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


    1. DevsStorm
      26.10.2023 18:26

      Есть Яндекс Народная карта)

      В ней Яндекс как раз таким и занимается.

      Только за нейронками люди потом проверяют.


      1. igor_suhorukov Автор
        26.10.2023 18:26
        +2

        Все что люди размечают в "Яндекс Народная карта" пренадлежит Яндексу, а не тем кто создавал эти данные. Так что толку что там эти данные есть, если эти данные закрытые.


    1. igor_suhorukov Автор
      26.10.2023 18:26

      Отличная идея! И для Yandex/Google/Bing и Mapillary это уже реальность для распознавания с панорам. Для OpenStreetMap все компьютерное зрение пока относится к распознаванию дорог и домов по спутниковым снимкам в rapideditor.org

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


  1. sshikov
    26.10.2023 18:26
    +1

    Для Москвы тут не хватает МЦК, которая по сути тоже метро. Ну т.е. по сути, какие-то еще виды транспорта не учтены (скорее всего МЦК и ее станции на карте OSM есть).


    1. igor_suhorukov Автор
      26.10.2023 18:26

      @sshikovзамечание в точку! Они уже автомагически включены:

      osmworld=# select tags->'network',count(*) from subway_entrance group by 1;
              ?column?         | count 
      -------------------------+-------
                               |   273
       МЦК                     |    56
       МЦК(14)                 |     1
       Московский метрополитен |   853
      (4 rows)
      

      Если какие станции пропустил, надо загребаться в разметку


      1. sshikov
        26.10.2023 18:26

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


        1. igor_suhorukov Автор
          26.10.2023 18:26

          Красные точки - входы в МЦК Зорге, синие - центры зданий считающимися жилыми, расположенные на расстоянии до 1250м от входов


          1. sshikov
            26.10.2023 18:26
            +1

            ну так вроде все логично.


            1. igor_suhorukov Автор
              26.10.2023 18:26

              Вроде не облажался здесь с SQL. Спасибо за проверку!


    1. igor_suhorukov Автор
      26.10.2023 18:26


  1. PastorGL
    26.10.2023 18:26

    Неплохое упражнение в аналитике small data :)

    Для больших данных ST_DWithin (и вообще георасширения любой СУБД) не подошло бы, да и вообще, слишком уж это медленно и неэффективно — сравнивать в лоб все сочетания пар POI из двух наборов. Но для ~300 станций и ~100к домов (≅ 30М сочетаний) потянет.


    1. igor_suhorukov Автор
      26.10.2023 18:26

      @PastorGLперечитал все твои статьи на Хабре и OneRing/datacooker-etl в моих закладках. Смотрю как ты героически допиливаешь spark инструментарий чтобы решать проблемы которые в олдскульных решениях для работы с данными из коробки. Твой проект с SQL ETL для геоданных вызывает мое уважение, как технаря! С другой стороны глядя на как архитектор и менеджер хочется в моих проектах взять готовые вещи и не разрабатывать что-то новое и потом не поддерживать это.

      Неплохое упражнение в аналитике small data :)

      Мерси! Считаю если что-то можно решить без hadoop/spark это и нужно решать подходящими простыми инструментами, не пытаясь сразу заложиться на петабайты данных. Моя задача пока не тянет на бигдату и divide and conquer позволяет решать задачи с помощью UberH3. Когда от геофункции ST_DWithin перехожу к работе с геохешами h3_grid_disk.

      Проблема PostgreSQL в этих задачах - отсутствие SIMD для геофункций и заточеность его query executor и планировщика на row based структурах, так как эта база из 90х годов и до сих пор основной сценарий её использования OLTP. Поэтому не спасает

      Для больших данных ST_DWithin (и вообще георасширения любой СУБД) не
      подошло бы, да и вообще, слишком уж это медленно и неэффективно —
      сравнивать в лоб все сочетания пар POI из двух наборов. Но для ~300
      станций и ~100к домов (≅ 30М сочетаний) потянет.

      В прошлых статьях я создавал GIST геоиндексы, поэтому

      план запроса использует GIST индекс для ST_DWithin
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
      --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
       GroupAggregate  (cost=4181841.45..4184368.59 rows=1183 width=56)
         Group Key: m.id, (st_x(m.centre)), (st_y(m.centre))
         ->  Sort  (cost=4181841.45..4182199.51 rows=143225 width=68)
               Sort Key: m.id, (st_x(m.centre)), (st_y(m.centre))
               ->  Nested Loop  (cost=0.54..4166133.76 rows=143225 width=68)
                     ->  Seq Scan on subway_entrance m  (cost=0.00..52.83 rows=1183 width=40)
                     ->  Append  (cost=0.54..3520.85 rows=17 width=191)
                           ->  Index Scan using nodes_000_geom_idx1 on nodes_000 nodes  (cost=0.54..25.78 rows=1 width=76)
                                 Index Cond: ((geom)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                 Filter: ((tags ? 'building'::text) AND (NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((geom)::geography, (m.centre)::geography, '1250'::double precision, true))
                           ->  Bitmap Heap Scan on nodes_001 nodes_1  (cost=183.03..757.78 rows=1 width=76)
                                 Recheck Cond: (tags ? 'building'::text)
                                 Filter: ((NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((geom)::geography, (m.centre)::geography, '1250'::double precision, true))
                                 ->  Bitmap Index Scan on nodes_001_tags_idx  (cost=0.00..182.76 rows=22 width=0)
                                       Index Cond: (tags ? 'building'::text)
                           ->  Index Scan using ways_000_linestring_idx1 on ways_000 ways  (cost=0.67..155.15 rows=1 width=197)
                                 Index Cond: ((linestring)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                 Filter: ((tags ? 'building'::text) AND (NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((linestring)::geography, (m.centre)::geography, '1250'::double precision, true))
                           ->  Index Scan using ways_001_linestring_idx1 on ways_001 ways_1  (cost=0.68..2385.05 rows=10 width=177)
                                 Index Cond: ((linestring)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                 Filter: ((tags ? 'building'::text) AND (NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((linestring)::geography, (m.centre)::geography, '1250'::double precision, true))
                           ->  Index Scan using ways_32767_linestring_idx1 on ways_32767 ways_2  (cost=0.53..25.65 rows=1 width=843)
                                 Index Cond: ((linestring)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                 Filter: ((tags ? 'building'::text) AND (NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((linestring)::geography, (m.centre)::geography, '1250'::double precision, true))
                           ->  Index Scan using multipolygon_000_polygon_idx2 on multipolygon_000 multipolygon  (cost=0.53..25.67 rows=1 width=807)
                                 Index Cond: ((polygon)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                 Filter: ((tags ? 'building'::text) AND (NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((polygon)::geography, (m.centre)::geography, '1250'::double precision, true))
                           ->  Bitmap Heap Scan on multipolygon_001 multipolygon_1  (cost=90.96..117.09 rows=1 width=471)
                                 Recheck Cond: (tags ? 'building'::text)
                                 Filter: ((NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((polygon)::geography, (m.centre)::geography, '1250'::double precision, true))
                                 ->  BitmapAnd  (cost=90.70..90.70 rows=1 width=0)
                                       ->  Bitmap Index Scan on multipolygon_001_polygon_idx2  (cost=0.00..1.00 rows=5 width=0)
                                             Index Cond: ((polygon)::geography && _st_expand((m.centre)::geography, '1250'::double precision))
                                       ->  Bitmap Index Scan on multipolygon_001_tags_idx  (cost=0.00..88.32 rows=10749 width=0)
                                             Index Cond: (tags ? 'building'::text)
                           ->  Bitmap Heap Scan on multipolygon_32767 multipolygon_2  (cost=2.46..28.59 rows=1 width=5966)
                                 Recheck Cond: (tags ? 'building'::text)
                                 Filter: ((NOT (tags ? 'amenity'::text)) AND (NOT (tags ? 'shop'::text)) 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,ice_rink,entrance,construction,transformer}'::text[])) AND st_dwithin((polygon)::geography, (m.centre)::geography, '1250'::double precision, true))
                                 ->  Bitmap Index Scan on multipolygon_32767_tags_idx  (cost=0.00..2.20 rows=1 width=0)
                                       Index Cond: (tags ? 'building'::text)
       JIT:
         Functions: 55
         Options: Inlining true, Optimization true, Expressions true, Deforming true
      (43 rows)
      


      1. PastorGL
        26.10.2023 18:26

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

        BTW, мы тоже ведь начинали 6 лет назад именно с PostGIS, и для считанных сотен тыщ точек использовать тамошние ST_ функции было ещё нормально. Проблемы начались, когда точек стали миллионы, и постгря перестала справляться с такими запросами. Вот тогда и мигрировали на Spark, поначалу с разбиениями по полигонам и/или по Вороному. А к решениям, позволяющим работать с миллиардами точек, и требующим нормальное геометрическое индексирование типа того же H3, мы пришли за несколько лет.


        1. igor_suhorukov Автор
          26.10.2023 18:26

          Ну, GIST эт такое себе индексирование, для геометрий его натянули примерно как сову понятно на что.

          Неэффективно по сравнению с чем? Расскажи пожалуйста какие самые частые операции в ваших запросах, какие геофункции используете, какие индексы, библиотеки для Spark?

          да и вообще, слишком уж это медленно и неэффективно — сравнивать в лоб
          все сочетания пар POI из двух наборов. Но для ~300 станций и ~100к домов
          (≅ 30М сочетаний) потянет.

          Вот я показываю выше план запроса, в котором видно что используется Index Scan, Index Cond: ((geom)::geography && _st_expand((m.centre)::geography, '1250'::double precision))а не перебор "в лоб".

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

          Сам по себе Spark удобный фреймворк для распределенных вычислений над данными, но в плане эффективности использования аппаратного обеспечения ему еще далеко до многих колоночных/MPP баз, многое пытаются вынести из jvm байткода в нативный чтобы повысить его производительность/уменьшить накладные расходы связанные с GC. Мне интересно какие у вас расчеты в запросах, почему не проще было взять тот же omniscidb(heavydb) на GPGPU?


  1. Vsevo10d
    26.10.2023 18:26

    Угу, выбираешь так квартиру недалеко от входа на станцию МЦД, потом от этого "входа" кандехаешь 250 метров по крытым надземным кишкам и павильонам с шаурмячными до самих поездов.


    1. igor_suhorukov Автор
      26.10.2023 18:26

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


      1. Vsevo10d
        26.10.2023 18:26
        -1

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

        Я бы вообще жил подальше (в разумных пределах) от входов в метро, это тот еще рассадник всякого быдла.


        1. igor_suhorukov Автор
          26.10.2023 18:26

          Я говорю о том, что выбранная автором метрика сомнительна

          Я и есть автор) Жизненный опыт показывает что когда в моем присутствии говорят обо мне в третьем лице, то мотивация человека не добрая и не направлена на конструктивную критику.

          Расскажите как вы предлагаете изменить учет расстояния? Погрешность указанных вами 250м на максимальном расстоянии 1250м - это 20%. Есть документированнный алгоритм как расчитывают метрику расстояния до метро другие сервисы?

          Я бы вообще жил подальше

          На каком расстоянии?

          от входов в метро, это тот еще рассадник всякого быдла

          Вы ставите себя выше других людей, пользующихся метрополитеном?


          1. Vsevo10d
            26.10.2023 18:26
            -2

            Я и есть автор) Жизненный опыт показывает что когда в моем присутствии говорят обо мне в третьем лице, то мотивация человека не добрая и не направлена на конструктивную критику.

            Я не всегда смотрю на цвет плашек в ответах (иногда сам Хабр их не подсвечивает зеленым).

            Расскажите как вы предлагаете изменить учет расстояния? Погрешность указанных вами 250м на максимальном расстоянии 1250м - это 20%. Есть документированнный алгоритм как расчитывают метрику расстояния до метро другие сервисы?

            Я не могу точно ответить на это и тем более дать алгоритм, могу только указать юзеркейс. Я бы вообще не рассматривал МЦД, они говно как транспорт и связан чисто условными "переходами" с метро, на которые нужно потратить 10-15 минут по улице. Входы в метро – более честное понятие, даже если идти от лестницы в подземный переход и по эскалаторам на платформу, то это не будет дольше 5 минут ни на одной станции.

            Вы ставите себя выше других людей, пользующихся метрополитеном?

            Это вы, похоже, ставите, раз приравниваете к быдлу всех пассажиров метро.

            https://ru.wiktionary.org/wiki/быдло#быдло_II

            1. перен.разг.презр. тупой, грубый, неотёсанный, бескультурный человек 

            На каком расстоянии?

            Повторюсь: на достаточно близком, чтобы ходить до дома пешком (<700 м); на достаточно далеком, чтобы быдло (всякие обитающие у входов рыгающие панки и стреляющие мелочь бомжи) были не у меня под окнами (>50-100 м).


            1. igor_suhorukov Автор
              26.10.2023 18:26

              Я бы вообще не рассматривал МЦД, они говно как транспорт и связан чисто
              условными "переходами" с метро, на которые нужно потратить 10-15 минут
              по улице.

              А где в статье указано что я его рассматриваю? Все что я учитываю в этой аналитики - railway=>subway_entrance

              Это вы, похоже, ставите, раз приравниваете к быдлу всех пассажиров метро.

              Вы только что сами придумали и приписали мне неуважительное высказывание по отношению к пассажирам Московского метрополитена. Чистой воды демагогия! Еще и выбрали из викисловаря определение удобное вам

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

              У меня в целом положительные впечатления от пользования метрополитеном. Не знаю где вы находите маргинальные элементы.


            1. igor_suhorukov Автор
              26.10.2023 18:26

              были не у меня под окнами (>50-100 м

              Достаточно ли этой дистанции? В прошлых статьях некоторые коментаторы возмущались что 150м от негативных факторов им мало.


  1. fekrado
    26.10.2023 18:26

    Ну тут напрашивается привязка к циану и тд. И аналитика на подбор кв в доступности от метро и по ₽


    1. igor_suhorukov Автор
      26.10.2023 18:26

      Только если подпольно?


  1. CBET_TbMbI
    26.10.2023 18:26

    Только на практике 5 км/ч это максимальная скорость. Так ходят единицы и то не всегда. Средная скорость пешеходов, скорее, 3 км/ч.


    1. igor_suhorukov Автор
      26.10.2023 18:26
      +1

      Да ладно) В Москве почти все бегают!


      1. sshikov
        26.10.2023 18:26
        +1

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

        Ну т.е. когда я ездил на работу самокатом, мне было удобно доехать 20 минут до МЦК, 20 минут на нем, и 20 минут до офиса. При этом метро от меня в 5 минутах, а МЦК где-то 3.5-4 км. Но - тут уже вступают в игру погодные условия. Сегодня вот снег выпал - какие нафиг самокаты (хотя прокатчики их еще не убирали)?


        1. igor_suhorukov Автор
          26.10.2023 18:26

          Похоже на новую фичу для Graphhopper. Он до сих пор не поддерживает "из коробки" комбинированные маршруты (велосипед+пешком+транспорт итп) При этом поддержка для общественного транспорта по протоколу gtfs в коде есть, но кто же в РФ будет публиковать такие данные для общественного транспорта, хотя эти данные есть у Яндекса и Мосгортранса? Так что я бы пока так не усложнял задачу на старте.


          1. sshikov
            26.10.2023 18:26
            +1

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


            1. igor_suhorukov Автор
              26.10.2023 18:26

              Ко-фаундер Graphhopper мне честно отвечал почему они удалили нужный код для сложной навигации:

              Считается, что я на самокате не могу войти в лифт, или закатить его по лестнице с пандусом?

              Надо разработчиков маршрутизации в Яндексе спрашивать. Отправь к ним на митап или конференцию своих коллег этим с вопросом)


              1. sshikov
                26.10.2023 18:26

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