Геопоиск ломается не на формуле расстояния, а там, где пользователь двигает карту, а самые плотные районы одновременно создают самые тяжёлые всплески нагрузки.
Глава помогает связать геоячейки, региональный кэш, подготовку индекса, путь запроса и обновление POI в одну рабочую архитектуру, где важны и свежесть данных, и стоимость обновлений.
В интервью и архитектурных разборах этот кейс полезен тем, что заставляет объяснить, как искать по радиусу, как переживать горячие зоны и где проходит граница между точностью выдачи и скоростью ответа.
Геоячейки
Главный выбор здесь в том, как покрыть радиус соседними ячейками и не раздувать объём лишнего поиска по карте.
Горячие зоны
Центры городов, аэропорты и вокзалы создают локальные пики, поэтому кэш и разбиение нужно проектировать под перекос, а не под среднюю нагрузку.
Свежесть POI
Статус точки, часы работы и временные ограничения устаревают быстрее, чем сама геометрия, поэтому обновление метаданных нельзя откладывать на редкие батчи.
Региональный кэш
Кэш рядом с пользователем снижает задержку, но его нужно согласовывать с географическим разбиением и режимами деградации.
Источник
System Design Interview
Классический разбор Proximity Service как базового паттерна геопоиска в продуктовых системах.
Proximity Service отвечает на вопрос: что находится рядом с заданной точкой для выбранного радиуса и набора фильтров. Для такой системы критичны , работа с и всплески в районах, где внезапно появляется .
Даже если сами точки обновляются не каждую секунду, индекс всё равно должен выдерживать из-за инкрементальных апдейтов и пересборки соседних ячеек. Поэтому крупные инсталляции почти всегда опираются на и дополняют его обычным внутри региона.
Требования
На пользовательском уровне это выглядит как простой , но внутри он живёт под жёстким бюджетом . В крупных городах отдельные районы легко выходят на миллионы , поэтому проектировать нужно и под отзывчивость карты, и под сильный перекос нагрузки.
Функциональные
- Пользователь двигает карту и сразу получает ближайшие POI в текущей видимой области.
- Система умеет искать точки в радиусе, по категории и по текстовому запросу.
- Поддерживаются пагинация и стабильный порядок результатов при сдвиге и масштабировании карты.
- API подсказок (autocomplete) отделён от API деталей точки.
- Статус точки, доступность и временные ограничения можно обновлять почти в реальном времени.
Нефункциональные
Задержка: p95 < 200ms
Карта не должна ощутимо тормозить при сдвиге, масштабировании и повторных запросах.
Доступность: 99.99%
Поиск продолжает работать даже при деградации части индекса или кэша.
Свежесть данных: минуты, не часы
Новые, закрытые и временно недоступные точки должны быстро попадать в выдачу.
Масштаб: миллионы запросов в секунду
Геораспределённый трафик идёт с сильным перекосом по районам и времени суток.
Высокоуровневая архитектура
Контур обработки запросов поиска рядом лучше жёстко отделять от подготовки индекса. Пользовательский путь живёт в отдельном контуре выдачи, где важно держать короткий и заранее определить , если кэш не прогрет или радиус неожиданно вырос.
Клиентские приложения
Карта, сдвиг, масштабирование и поиск по соседству
Шлюз геопоиска
Аутентификация, лимиты и маршрутизация по регионам
Контур выдачи
Работа с индексом, фильтрами и ранжированием
Горячий кэш
Redis/Memcached для частых геоячеек и категорий
Хранилище геоиндекса
S2/H3/Geohash и списки идентификаторов по категориям
База метаданных POI
Название, часы работы, рейтинг и бизнес-теги
Запрос идёт в две фазы: сначала система отбирает кандидатов по соседним ячейкам, а затем отдельно ранжирует их по расстоянию, релевантности и бизнес-сигналам.
Интерактивный разбор запроса поиска рядом
Меняйте категорию и радиус, затем проходите путь обработки по шагам.
Шаг 1 из 5
Шлюз геопоиска: проверка и нормализация запроса
Сервис проверяет параметры запроса и отправляет его в ближайший рабочий регион.
- Проверяет API-ключ, лимиты и обязательные параметры.
- Нормализует lat/lng, радиус и локаль клиента.
- Маршрутизирует запрос в ближайший регион геопоиска.
{
"lat": 37.7793,
"lng": -122.4192,
"radius_m": 1500,
"category": "cafe",
"region": "us-west-1",
"auth": "ok",
"quota": "ok"
}Выбор пространственного индекса
Здесь нет одной универсально лучшей структуры. Обычно это инженерный между точностью покрытия, удобством обновлений и ценой сложной геометрии на больших объёмах.
| Подход | Когда особенно полезен | Компромиссы |
|---|---|---|
| Geohash | Быстрый старт и хранение в простом слое «ключ-значение» | Ячейки ведут себя менее ровно, а на границах чаще всплывают артефакты. |
| S2 | Глобальные карты и аккуратная работа с геометрией сферы | Требует более внимательной реализации и сложнее в отладке. |
| H3 | Аналитику плотности, тепловые карты и агрегации по регионам | Переход между уровнями детализации нужно настраивать очень аккуратно. |
| R-tree/QuadTree | Тяжёлые пространственные запросы прямо в базе данных | Обновления дороже, особенно когда поток записей заметно растёт. |
API и модель данных
Основной API
GET /v1/places/nearby?lat=37.78&lng=-122.41&radius=1500&category=cafe&limit=20
Response:
{
"items": [
{ "place_id": "p123", "distance_m": 120, "score": 0.91 },
{ "place_id": "p889", "distance_m": 240, "score": 0.88 }
],
"next_page_token": "..."
}Индекс и метаданные
- geo_cell_index: cell_id -> place_ids
- poi: place_id, name, category, coords, rating, business_hours
- popularity_signals: recent clicks/check-ins/reviews
- change_log: события для инкрементальной переиндексации
Надёжность и типичные ошибки
Самая неприятная часть этого кейса в том, что нужно одновременно удерживать локальность чтения, приемлемую и понятный режим деградации, если часть геоиндекса или кэша временно недоступна.
Что помогает в эксплуатации
- Региональное разбиение по диапазонам ячеек и репликация по зонам.
- Двухуровневый кэш: пограничный слой для горячих зон и сервисный кэш внутри региона.
- Понятная деградация на более грубую детализацию индекса вместо полного отказа.
- Инкрементальная переиндексация вместо полного пересчёта всего набора точек.
Типичные ошибки
- Смотреть только в одну ячейку и забывать про соседние клетки на границе радиуса.
- Сортировать только по расстоянию и игнорировать рейтинг, релевантность и статус точки.
- Смешивать рабочий контур выдачи с пакетной подготовкой индекса и метаданных.
- Делать единый глобальный кэш без регионального разбиения и защиты от лавинообразных промахов.
- Не удалять дубликаты POI, если данные приходят от нескольких поставщиков.
Инструмент
S2 Geometry
Практический инструмент для пространственной индексации по ячейкам на поверхности сферы.
Связанные главы
- Airbnb: геоиндекс и доступность - показывает соседний геосценарий, где к поиску рядом добавляются календарная доступность и региональное масштабирование.
- Uber/Lyft: живая геолокация - дополняет тему постоянным обновлением координат, маршрутизацией и более жёсткими требованиями по задержке.
- Search System: ранжирование и поисковый конвейер - расширяет часть про отбор кандидатов, сигналы релевантности и организацию большого поискового контура.
- CDN: кэширование на границе сети - помогает понять, как пограничный слой снижает задержку API геопоиска и защищает региональные сервисы от всплесков трафика.
