Источник
System Design Interview
Классический Proximity Service как отдельный паттерн геопоиска в продуктовых системах.
Proximity Service - это сервис, который отвечает на вопрос: "что находится рядом" для заданной точки, радиуса и фильтров. В продукте уровня Google Maps архитектура строится вокруг двух разных контуров: offline ingestion/indexing и online low-latency serving.
Требования
Функциональные
- Пользователь двигает карту и получает ближайшие POI в текущем viewport.
- Поиск nearby по радиусу, категории и текстовому запросу.
- Поддержка пагинации и стабильного порядка результатов при скролле карты.
- Отдельный API для подсказок (autocomplete) и API для деталей точки.
- Онлайн-обновление данных о загруженности/статусе точки (опционально).
Нефункциональные
Latency: p95 < 200ms
UI карты не должен «лагать» при pan/zoom.
Availability: 99.99%
Поиск должен работать даже при деградации части индексов.
Freshness: минуты, не часы
Новые/закрытые точки должны попадать в выдачу быстро.
Scale: миллионы QPS
Геораспределённый трафик с ярко выраженными hot zones.
High-Level Architecture
Client Apps
Map UI, pan/zoom, nearby search
Geo API Gateway
Auth, throttling, routing by region
Proximity Serving
Geo index lookup + ranking + filters
Hot Cache
Redis/Memcached, геоячейки популярных зон
Geo Index Store
S2/H3/Geohash + posting lists по категориям
POI Metadata DB
Название, часы работы, рейтинг, теги
Запрос обрабатывается в две фазы: candidate retrieval по соседним ячейкам, затем ranking с учётом дистанции, релевантности и бизнес-сигналов.
Интерактивная обработка nearby-запроса
Меняй категорию и радиус, затем проходи pipeline по шагам.
Шаг 1 из 5
Geo API Gateway: валидация и нормализация запроса
Сервис валидирует входные параметры и направляет запрос в ближайший регион.
- Проверка API ключа, лимитов и обязательных параметров.
- Нормализация lat/lng, радиуса и локали клиента.
- Route-by-region в ближайший proximity serving cluster.
{
"lat": 37.7793,
"lng": -122.4192,
"radius_m": 1500,
"category": "cafe",
"region": "us-west-1",
"auth": "ok",
"quota": "ok"
}Выбор spatial index
| Подход | Где особенно полезен | Компромиссы |
|---|---|---|
| Geohash | Простой старт и key-value storage | Неравномерность ячеек и edge effects возле границ. |
| S2 | Глобальные карты и аккуратная геометрия сферы | Сложнее implementation и debugging. |
| H3 | Аналитика, плотности, heatmaps | Переход между резолюциями требует аккуратной настройки. |
| R-tree/QuadTree | Тяжёлые spatial queries в БД | Дороже обновления при high write нагрузке. |
API и data model (упрощённо)
Основной 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: события для incremental re-index
Надёжность и anti-patterns
Что помогает в production
- Региональное шардирование по cell ranges + репликация по зонам.
- Двухуровневый кэш: edge cache для популярных зон + service cache.
- Graceful degradation: fallback на более грубую резолюцию индекса.
- Incremental reindex вместо полного пересчёта индекса.
Типичные ошибки
- Искать только в одной ячейке и забывать про соседние клетки на границе радиуса.
- Сортировать только по расстоянию без quality score (rating, relevance, открыто/закрыто).
- Не отделять online serving index от batch-пайплайна подготовки данных.
- Делать глобальный кэш без регионального шардирования и без защиты от stampede.
- Забыть про дедупликацию POI из разных провайдеров данных.
Связанные главы
Reference
S2 Geometry
Практический инструмент для cell-based spatial indexing на сфере.
