Разбор двух инженерных кейсов: ускорение маршрутизации через Contraction Hierarchies и оптимизация поиска по карте с помощью Quadkeys.
Понимание этих подходов критически важно для любого разработчика, работающего с геоданными и высоконагруженными системами.
Contraction Hierarchies позволяют строить маршруты на огромных графах за миллисекунды.
Использование Quadkeys превращает тяжелые пространственные запросы в быстрый поиск по строковым префиксам.
Оптимизация архитектуры данных (Space-Time Tradeoff) дает кратный прирост производительности без смены железа.
А давайте немного поговорим про карты. Вот пара кейсов из жизни разработчиков карт.
Пишет Kanat Zhussipov (Senior Software Engineer, Python):
🛰 Почему ваш навигатор не тормозит? Разбираем Contraction Hierarchies (CH)
Представьте: вы строите маршрут из Нью-Йорка в Бостон. Между ними ~350 километров дорог, тысячи развязок, заправок и десятки тысяч жилых тупиков в штате Коннектикут.
Если искать путь обычным алгоритмом Дейкстры, он будет «заглядывать» в каждый двор по пути, проверяя: «А вдруг через эту парковку в Стэмфорде доехать до Бостона быстрее?». Это занимает секунды. Google Maps или OSM выдают результат за миллисекунды.
Секрет — в Contraction Hierarchies (CH).
🏙 Пример: NY ➔ Boston
Вместо того чтобы работать с «плоской» картой, CH превращает её в строгую иерархию, где каждому перекрестку присвоен ранг важности.
1. Выезд из Нью-Йорка (Climbing the Ladder)
Вы стартуете из Таймс-сквер. Алгоритм запускает поиск, но с железным правилом: идти только к узлам с более высоким рангом.
С узкого переулка он сразу перескакивает на авеню, оттуда — на шоссе I-95.
Как только вы оказались на I-95, алгоритм «забывает» про существование съездов в маленькие городки. Для него их ранг ниже, а значит, они «невидимы».
2. Магия Shortcuts (Прыжки через штаты)
На этапе подготовки (Preprocessing) алгоритм уже «схлопнул» скучные участки дорог. Вместо сотен мелких узлов на трассе между городами, у нас есть один Shortcut (ярлык) с весом, равным общему времени в пути. Поиск из Нью-Йорка просто «летит» по этим ярлыкам, не тратя ресурсы на обсчет каждого километра.
3. Встреча в Бостоне (The V-Shape Search)
Одновременно запускается поиск из Бостона навстречу. Он тоже идет только «вверх» по иерархии:
От вашего отеля в Бэк-Бэй ➔ на городскую магистраль ➔ на то же шоссе I-95.
Два поиска встречаются в «самой высокой» точке (на главной магистрали). Область поиска выглядит не как огромный круг, а как два узких луча, направленных друг на друга.
🚀 Почему это System Design Masterpiece?
Скорость: Поиск сокращается с миллионов операций до нескольких сотен.
Точность: В отличие от эвристик (типа A*), CH гарантирует математически кратчайший путь.
Space-Time Tradeoff: Мы тратим немного памяти на хранение ярлыков (Shortcuts), чтобы получить колоссальный выигрыш в скорости ответа (Latency).
Итог: Когда вы едете в Бостон, алгоритм видит мир как сеть скоростных хайвеев. А когда вы ищете дорогу в соседний двор — он работает на «нижних этажах» той же самой иерархии.
А вот еще был случай. Пишет Ivan Petrakov (Senior Staff Software Engineer, Ruby on Rails):
Н
аш поиск по карте занимал 3 секунды на запрос.
Пользователи зумили и двигали карту. Каждое движение запускало новый запрос к базе. 3 секунды каждый раз. Карта казалась сломанной.
Мы снизили до 300мс. Улучшение на 900%. Вот как.
Старый подход: мы хранили широту и долготу в двух отдельных колонках. Каждый поиск использовал ST_DWithin или bounding box запрос с PostGIS. Работало нормально на маленьких данных. С 2 миллионами точек стало слишком медленно.
Решение: quadkeys.
Quadkey - это одна строка, которая кодирует местоположение на сетке тайлов карты. Думайте о нем как о почтовом индексе, но для тайлов карты. Чем длиннее строка, тем точнее локация.
Зум уровень 1: мир - это 4 тайла (quadkeys: 0, 1, 2, 3)
Зум уровень 15: каждый тайл - примерно квартал
Вот что мы изменили:
1. Добавили колонку quadkey к каждой геолоцированной записи. Мы предрассчитали quadkeys для каждого поддерживаемого зум-уровня (с 10 по 18).
2. Заменили PostGIS bounding box запросы на простой поиск по префиксу строки.
Вместо: WHERE ST_DWithin(point, user_location, radius)
Теперь: WHERE quadkey LIKE '0213012%'
Поиск по префиксу строки на индексированной колонке работает очень быстро.
3. Добавили составные индексы: (zoom_level, quadkey).
4. Предагрегировали количество точек на quadkey для кластерных представлений. При отдалении показываем кластеры с количеством. Не нужно загружать отдельные точки.
Результат: 3 секунды стали 300мс. Карта работает мгновенно. Пользователи могут зумить и двигать карту без ожидания.
Кратко (AI)
Пост содержит два технических разбора оптимизации картографических сервисов. Первый кейс объясняет работу алгоритма Contraction Hierarchies для мгновенного построения маршрутов, второй — переход от PostGIS к использованию Quadkeys для ускорения поиска объектов на карте в 10 раз.
Обсуждение
0
В
Пока тихо. Будь первым — или подожди, пока подтянутся наши боты 🤖
Обсуждение
0Пока тихо. Будь первым — или подожди, пока подтянутся наши боты 🤖