ObjectManager, или как работать с большим количеством...
description
Transcript of ObjectManager, или как работать с большим количеством...
ObjectManager или как работать с действительно большим количеством объектов на картеМарина Степанова, Яндекс
О чем поговорим• Почему сложно показать много точек на
карте, обзор решений• Как отрисовать большое количество
меток на клиенте• Загрузка меток по требованию• Организация хранения и обработки
данных на сервере
Почему сложно хорошо показать много меток на карте?
Решаем задачу «в лоб»
Сервер
page.html
page.html<!DOCTYPE html><html><head> <script src="//api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script> <script type="text/javascript">
ymaps.ready(function () { var myMap = new ymaps.Map('map', { center: [55.76, 37.64], zoom: 10 });}); </script> </head> <body><div id="map"></div></body></html>
А теперь добавим метки!
X 50 000
page.html
Очевидные недостатки
• page.html весит несколько Мб и страница долго загружается
• Мы передаем на клиент слишком много данных
• Мы рисуем на клиенте данные, которые пользователь может не видеть
Что предлагалось пользователям многие годы?*
*Не только в API Яндекс.Карт
Решение №1 – активные области
Решение №1 – активные области
Решение №1 – активные области
Плюсы Минусы
Очень быстрый рендеринг на клиенте
Оооочень сложная серверная часть
Передаются только данные для видимой
области
Клиентская картинка абсолютно статична
Решение №2 - кластеризатор
Решение №2 – кластеризатор
Плюсы Минусы
Просто использовать Клиент тратит время на кластеризацию
Дизайн определяется и настраивается на
клиенте
Не решена проблема оптимальной загрузки
данных
Решение №2 – кластеризатор
X 50 000
new ymaps.Placemark([45.3, 25.45])new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
50 000
Решение №2 – кластеризатор
X 50 000
new ymaps.Placemark([45.3, 25.45])new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
50 000
Лишние программные инициализации
Что нужно в идеале?
• Никаких лишних инициализаций на клиенте
• Запрашиваем данные пачками асинхронно
• Передаем на клиент только данные, которые видит пользователь
• Рисуем на клиенте только данные, которые видит пользователь
Что мы сделали для клиентской оптимизации
Храним только данные
• Все данные хранятся как их JSON-описания в специальном менеджере
• Программные сущности создаются только при необходимости нарисовать объект
X 50 000
new ymaps.Placemark([45.3, 25.45])new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
new ymaps.Placemark([45.3, 25.45])
50 000
Храним только данные
Как ускорить геообъекты?
BalloonHintEditorOptionsEventsOverlay…
BalloonHintEditorOptionsEventsOverlay…
BalloonHintEditorOptionsEventsOverlay…
BalloonHintEditorOptionsEventsOverlay…
Компонент, отвечающий непосредственно за отрисовку на карте
BalloonHintEditorOptionsEvents…
ObjectCollection
Overlay Overlay Overlay
Получился ObjectManager• Хранит данные и не создает
программные сущности без надобности• Мы вынесли всю инфраструктуру в
общую коллекцию, в метках оставили только самое нужное
https://clck.ru/9LqPp
Время добавления на карту меток с кластеризацией
1000 10000 500000
1000
2000
3000
4000
5000
6000
ObjectManagerPlacemarks
Поговорим про загрузку данных с сервера на клиент
Классическое решение
Классическое решение
Минусы подхода
• На малейший сдвиг нужно генерировать новый запрос
• Многократная загрузка одних и тех же данных
• Запросы всегда разные, непонятно, как кешировать
Грузим данные потайлово
Видимая область карты
Тайлы в видимой области
Загружаем данные потайлово
• Данные загружаются всегда по одним и тем же областям – легче организовать кеширование
• Запоминаем, какие тайлы подгружены, а какие нет
• Небольшой сдвиг карты не вызывает дозагрузку
RemoteObjectManager, LoadingObjectManager• Следят за видимой областью карты• Следят, какие данные загружены, а какие еще
нет• Отправляют потайловые запросы за данными на
сервер
clck.ru/9Lp2Jclck.ru/9Lp2S
LoadingObjectManagerЗагружает метки и кластеризует на клиенте
RemoteObjectManagerОтвечает за загрузку и отображение результатов серверной кластеризации
Режимы запросов за данными
Как организовать серверную часть?
Генерация статических файлов
Генерация статических файлов
• Не требует сервера, отвечающего на запросы клиента
• Файлы могут занять очень много дискового пространства
• Нужен скрипт, генерирующий эти файлы с некоторой периодичностью
• Очень примитивное решение, подойдет для небольших демо-проектов
Пространственные базы данных
• MySQL – SPATIAL• PostgreSQL – PostGIS• Oracle• MongoDB• …
Поговорим про серверную кластеризацию точек
Кластеризация на клиенте
Формирование списка точек
Передача на клиент
Кластеризация Отображение результата
Кластеризация Отображение результата
Кластеризация Отображение результата
Сервер Клиент
Кластеризация на клиенте
Формирование списка точек
Передача на клиент
Кластеризация Отображение результата
Кластеризация Отображение результата
Кластеризация Отображение результата
Сервер Клиент
Кластеризация на сервере
Формирование списка точек Кластеризация Передача на
клиент
Отображение результата
Отображение результата
Отображение результата
Сервер Клиент
Серверная кластеризация. v1
БД Кластеризация Отправка на клиент
Серверная кластеризация. v1
1. Получаем данные для тайла из базы2. Кластеризуем любым алгоритмом3. Отправляем ответ на клиент
SELECT Id, long, lat,FROM bigTable WHERE latLon in bounds
Серверная кластеризация. v1
Плюсы Минусы
Можно выбрать любой алгоритм кластеризации
Чем красивее алгоритм, тем дольше он работает
Нужно хорошо организовать
кеширование ответа
Grid-кластеризация
Серверная кластеризация. v2
БДОтправка на
клиент
Данные, сгруппированные по grid-кластерам
Серверная кластеризация. v2
SELECT MIN(id) AS minId, COUNT(id) AS count, AVG(long) AS long, AVG(lat) AS lat,FLOOR( long/gridFactor) * gridFactor as gridX,FLOOR( lat/gridFactor) * gridFactor AS gridYFROM bigTable WHERE latLon in bounds GROUP BY gridX,gridY
Вместе с выборкой объектов сразу объединяем объекты в grid-кластеры
Серверная кластеризация. v2
Плюсы Минусы
Не надо писать дополнительной логики
по кластеризации
Grid-кластеризация не самая красивая
Быстро работает Ваша база данных вечно считает, вы не
используете индексы
Quadkey для grid-кластеризации
«Quadkey»
clck.ru/4Xg6s
«Quadkey»tileX = 3 = 0112
tileY = 5 = 1012
quadkey = 1001112 = 2134 = “213”
Используем битовые маски для выборки объектов в тайлеzoom = 1, mask = 110000zoom = 2, mask = 111100…
Серверная кластеризация. v3
БДОтправка на
клиент
Данные, сгруппированные по grid-кластерам
+ quadkey для каждой точки
Серверная кластеризация. v3
SELECT MIN(id) AS minId, COUNT(id) AS count, AVG(long) AS long, AVG(lat) AS latFROM wiki WHERE QuadCode between $Q1 and $Q2. GROUP BY (QuadCode & $free)
Где:free - маска «вариативности» хвоста. free = 0xFFFFFFFF ^ (($Q2^$Q1)>>(2*gridFactor));Q1,Q2 - диапазоны поиска QuadKey
Пример:
QuadCode: 320132321(base4), 9 знаков из 16(uint32)Q1 : 320132321|0000000Q2 : 320132321|3333333free:333333333|3330000 (+3 зума, кластер 32х32)
Серверная кластеризация. v3
Плюсы Минусы
Очень быстро Grid-кластеризация не самая красивая
Нужно заранее насчитать Quad-коды
Поговорим про кеширование и версионирование данных
С кешированием все просто
• Поскольку запросы всегда потайловые, кешируем ответ сервера для тайла на определенном зуме
• Пишите данные в файлы, используйте Memcached, Redis и тд
• Если запрос поступает для большой тайловой области, разбиваем его на отдельные тайлы и собираем ответ из кеша потайлово
Опасный момент – обновление данных
Опасный момент – обновление данных
Опасный момент – обновление данных
Загружены данные старой версии
Сюда могут подгрузиться данные уже новой версии
Закладываем версионирование в архитектуру
• Передаем на клиент версию данных• Клиент всегда отправляет запросы с указанием версии
данных• Храним несколько последних версий на сервере• Системы кеширования тоже завязываем на версию• Если нужно, продумываем автообновление версии на
клиенте
Полезные ссылки
• Работа с большим количеством объектов – clck.ru/9Lp2e
• Если есть вопросы, пишите в клуб – clubs.ya.ru/mapsapi/
Спасибо за внимание!Марина Степанова, руководитель группы разработки API Яндекс.Карт