Работа с геоданными в mongodb
TRANSCRIPT
Работа с геоданными в MongoDb
Марк Заславский, [email protected]
О чем будет доклад
● Обзор:– Короткое знакомство с Mongo
– Коротко про GeoJson
– Какие данные можно хранить в Mongo
– Как хранить геоданные в Mongo
– Как индексировать геоданные
– Как выполнять запросы к данным (поиск объектов рядом/внутри/на пересечении с областями)
● Примеры использования геовозможностей MongoDb в Geo2Tag
Примеры к докладу
● Ссылка для скачивания: http://bit.ly/1OHMY0N
● В архиве текстовые файлы со списками комманд для каждого примера
● Решетки (#) это не комментарий в Mongo, их нужно удалить
● Примеры проверялись на MongoDb 2.4.9
(Вопросы в зал)
Введение и мотивация
● Геоданные:– часто (но не всегда) = bigdata,
– имеют сложные алгоритмы анализа/обработки,
– могут иметь сложную структуру (границы областей, маршруты).
● Mongo– из коробки умеет работать с геоданными,
– хорошо масштабируется,
– представление геоданных стандартизовано (GeoJSON).
Короткое введние в Mongo
● MongoDb – документо-ориентированная СУБД
● Данные хранятся в BSON (почти JSON)
● Документы объединяются в коллекции
● У коллекций нет обязательной схемы
● MapReduce● Полнотекстовый поиск
Коллекции и документы
● Примерное соответствие с SQL СУБД:– Коллекция = таблица
– Документ = запись в таблице
– Идентификатор _id (обязательное поле документа) = первичный ключ
● Коллекции и базы данных создаются “ленивым образом”
Пример CRUD 1mongo_crud.txt
$ mongo test_db
> db.test_collection.insert({key1:'val1', key2:'val2'})
> db.test_collection.insert({key3:'val3'})
> db.test_collection.find({key3:'val3'})
> db.test_collection.find()
> db.test_collection.remove({key3:'val3'})
> db.test_collection.find()
> db.test_collection.update({ "key1" : "val1", "key2" : "val2" }, {$set: {"key1" : "val2"}})
Формат GeoJSON
● Надмножество JSON для хранения точек, ломаных и многоугольников (а также их совокупностей (гладких кривых нет:)).
● Не накладывает ограничение на тип координат (плоские, сферические, параболические ...).
● Координаты точки задаются в виде массива
[x , y]
Или
[долгота, широта]
Наглядные примеры
● https://ru.wikipedia.org/wiki/GeoJSON#.D0.9E.D0.B1.D1.8A.D0.B5.D0.BA.D1.82.D1.8B
Наглядные примеры
● https://ru.wikipedia.org/wiki/GeoJSON#.D0.9E.D0.B1.D1.8A.D0.B5.D0.BA.D1.82.D1.8B
GeoJSON - инструменты
● Генерация GeoJSON по карте - http://geojson.io/
● Валидатор - http://geojsonlint.com/● Бьютификатор -
https://jsonformatter.curiousconcept.com/
● Описание стандарта – http://geojson.org/
Как сохранить геоданные в БД● Форматы:
– legacy coordinate pairs (только точки) [x,y]
– GeoJson (точки, линии, полигоны ...)
● Нет контроля типов у полей координат
● Одно поле = один формат представления
● Можно сохранять как в отдельное поле, так и во вложенное
Сохранение геоданных в БД – пример 2location_writing.txt
$ mongo test_db> db.test_collection1.insert({ name: '1', location : { "type" : "Point", "coordinates" : [ 1.0, 1.0 ] }})> db.test_collection2.insert({ name: '2', location : [ 1.0, 1.0 ]})
Пространственные индексы - преамбула
● Индексы – ускорение запросов.● Разные геометрии:
– Плоская (евклидово расстояние)– Сферическая WGS84,
http://spatialreference.org/ref/epsg/4326/)
http://www.colorado.edu/geography/gcraft/notes/datum/gif/geoid2.gif
Пространственные индексы
● 2dsphere– Сферическая геометрия, GeoJSON или legacy
coordinate pairs
– Можно делать связанный индекс с несколькими полями
● 2d– Плоская геометрия, legacy coordinate pairs
– Связанный индекс только с одним полем
● geoHaystack– 2d + одно не геополе, быстрее на малых площадях
чем 2d
Пример - Создаем индекс 3indexes_creation.txt
> db.test_collection1.createIndex({
location: '2dsphere'})
> db.test_collection2.createIndex({
location: '2d'})
# Проверяем индексы
> db.system.indexes.find()
$geoWithin и $geoIntersects
● Что это:– Критерии для поиска (могут быть частью сложного
запроса)
– Поиск либо объектов внутри (geoWithin), либо на пересечении с областью (geoIntersects)
– Работает для всех геометрий и типов задания координат
● Особенности– Индекс не нужен
– Есть проблема с ооочень большими областями фильтрации
$geoWithin и $geoIntersects
● Что приходит в ответ - список документов без сортировки
● Как можно искать: – Сферическая геометрия: $geometry,
$centerSphere
– Плоская геометрия: $box, $polygon, $center
Пример про $geoWithin 4geowithin.txt
db.test_collection1.find( { location : { $geoWithin : { $geometry : { type : "Polygon" , coordinates : [ [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] # Замыкаем фигуру ] ] } } } } )
Пример про $geoWithin 4geowithin.txt
db.test_collection1.find( { location :
{ $geoWithin :
{ $centerSphere:
[ [1, 1], # Центр
2] # Радиус в радианах
}}})
Пример про $geoIntersects 4geointersects.txt
db.test_collection1.find( { location :
{ $geoIntersects :
{$geometry:
{"type": "LineString",
"coordinates": [ [0, 1], [1, 1] ]
}
}
}
})
$near и $nearSphere
● Что это: операторы поиска объектов, близких к точке.
● Особенности– Near – использует евклидово расстояние,
nearSphere – сферическое.
– Требует наличия любого геоиндекса.
– Нельзя комбинировать со сложными запросами, требующими специальный индекс
– Можно задать пределы расстояний.
$near и $nearSphere
● Что приходит в ответ: отсортированные по расстоянию документы
● Единицы измерения расстояний зависят от того, как задана точка отсчета:– GeoJSON – метры
– Legacy pair - радианы
Пример - поиск точек по расстоянию 5nearsphere.txt
db.test_collection1.find( { location :
{ $nearSphere:
{ $geometry :
{ type : "Point",
coordinates : [ 0, 0 ]}, # Точка отсчета
$maxDistance : 190000} # В метрах
}
})
Операции аггрегирования
● примерный аналог группировки в SQL базах данных
● выбираем данные по критерию и работаем с ними:– группируем дальше ( можно делать
многоступенчатую аггрегацию)
– меняем формат
– создаем новые поля на основании вычислений в текущих (минимум, среднее, максимум и тд)
$geoNear
● Аналог near/nearSphere – но на этапе аггрегации
● Требует наличия одного геоиндекса● Не нужно указывать поле с координатами ● Может быть только первым этапом
аггрегирования● Нельзя использовать одновременно с near*,
но можно geoWithin/Intersect
$geoNear пример – 6geonear.txt
db.test_collection1.aggregate([ { $geoNear: { near: { type: "Point", coordinates: [ 1 , 1.0000001 ] }, distanceField: "dist.calculated", # Название нового поля для записи расстояния maxDistance: 2, # Максимальное расстояние до точки query: {name:"1"} , # ЗАпрос с дополнительной фильтрацией includeLocs: "dist.location", # Новое поле, где будут дополнительно выведены координаты spherical: true } } ])
GeoHaystack Index + geoSearch
● GeoHaystack ориентирован на:– Запросы сначала по непространственному полю,
а затем по пространственному
– Данные из ограниченной области
● команда geoSearch - аналог geoNear для коллекций с geoHaystack индексом
Пример использования GeoSearch 7geosearch.txt
> db.test_collection3.insert({ _id : 100, pos: { lng : 126.9, lat : 35.2 } , type : "restaurant"})
> db.test_collection3.insert({ _id : 200, pos: { lng : 127.5, lat : 36.1 } , type : "restaurant"})
> db.test_collection3.insert({ _id : 300, pos: { lng : 128.0, lat : 36.7 } , type : "national park"})
Пример использования GeoSearch 7geosearch.txt
db.test_collection3.createIndex( { pos : "geoHaystack", type : 1 } ,{ bucketSize : 1 } )
db.runCommand( { geoSearch : "test_collection3" ,
search : { type: "restaurant" } ,
near : [-74, 40.74] ,
maxDistance : 1000 } )
Реальное использование в Geo2Tag
● Geo2Tag – платформа для создания геоконтекстных сервисов
● Геоданные – отдельные точки (широта, долгота, высота) с привязанным описанием/ссылкой
● REST интерфейс для поиска точек по вхождению в пространственную область
● Индексирование через 2dSphere ● Запрос GeoWithin + запросы поиска по
высоте и параметрам описания
Что почитать
● Хороший туториал от создателей БД по геовозможностям https://docs.mongodb.org/manual/tutorial/geospatial-tutorial/
● Индексы, типы геометрий https://docs.mongodb.org/manual/applications/geospatial-indexes/
● Введение в Mongo http://jsman.ru/mongo-book/
● Формат GeoJSON http://geojson.org/