Я работал над созданием и перестройкой геопространственной таблицы для работы. Там было много проблем в этом проекте для меня это первый раз, когда я должен был архитектором дб конструкции включения MongoDB с MySql.
Моно-геопространственный репозиторий заменит несколько таблиц в устаревшей системе mySQL — как вы, возможно, знаете, mongodb поставляется с полной геопространственной поддержкой, поэтому выполнение запросов к коллекции (таблице), созданной таким образом, шокирует с точки зрения скорости его отклика, особенно когда Вы сравниваете эти скорости с традиционными алгоритмами mySQL для извлечения географических точек на основе диапазонов расстояний для координат широта / долгота. Tl; dr для этого абзаца: больше никаких отвратительных тригонометрических запросов MySQL!
В этом упражнении я узнал, что ключ к созданию коллекции монго требует от вас переосмысления способа хранения данных. Монго хранит данные в виде коллекции документов . Ключом к успешному мышлению, по крайней мере, с точки зрения хранения на монго, является денормализация ваших объектов данных.
Давайте использовать стандартный объект клиента в качестве примера. У каждого клиента есть хотя бы один номер телефона . Большинство, если не все, клиенты имеют более одного номера телефона . Мы могли бы определить несколько столбцов в таблице клиентов для телефонных номеров: рабочий телефон, домашний телефон, мобильный телефон, другой телефон и таким образом хранить данные. Проблема заключается в том, что в конечном итоге мы столкнемся со стеной, где у нас будет необходимость хранить номера, для которых у нас нет предопределенных столбцов: факс, скайфон, tddphone, vrsphone и т. Д.
Конструкция СУБД требует нормализации этого дизайна данных 1: M, требуя, чтобы во второй таблице хранились только телефонные номера для каждого клиента . Таблица телефона будет иметь первичный ключ (id), идентификатор клиента, номер телефона клиента и, возможно, короткое описательное поле, объясняющее назначение этого номера. Чтобы получить телефонные данные о клиенте , вы просто запросите (или присоединитесь) телефонную таблицу на основе идентификатора клиента, чтобы получить все телефонные кортежи для этого клиента.
Монго, с другой стороны, рассматривает каждого клиента как документ . Думайте о каждом клиенте в вашей коллекции как о листке бумаги. Вы хотите перейти в свою коллекцию и получить на листе бумаги, на котором есть все данные клиента . Так, например, вы извлекаете документ для «Джона Смита», и в этом документе он перечисляет несколько пар ключ-значение под массивом с именем phone:
phone : { home : (408) 123-4567, work : (415) 123-4567, cell : (312) 765-4321 }
…и так далее…
Mongo сохраняет документ для этого или любого пользователя, отменяя нормализацию отношений данных в объекте customer . Эти отношения могут поддерживаться как подмассивы в документе. Поскольку mongo не содержит схем, каждый объект- клиент не обязан иметь все возможные комбинации телефонных номеров. Таким образом, если вы проведете поиск, в котором вы отзовете всех клиентов с номерами факсов, наш мистер Смит не появится в этом списке, поскольку в его списке телефонов нет номера факса.
Увидеть?
Таким образом, этот первый шаг к ясности в архитектуре Монго заключается в том, чтобы продумать все данные при проектировании объекта класса и включить эти данные в один документ . Данные, которые хранились в традиционных таблицах, основанных на отношениях СУБД, включаются в документ как подмассивы документа.
Но вы спрашиваете, что, если вы хотите позже добавить номер факса в коллекцию телефонов Джона Смита? Вы можете сделать это?
Конечно!
Опять же, это неотъемлемая сила mongodb — это без схемы! Добавление другого номера к существующей коллекции телефонных номеров или добавление нового «столбца» к самому документу требует только обновления этого документа. Это оно!
Итак, возвращаясь к геопространственной сборке, я использовал mySQL, извлекаю устаревшие данные и собираю обновленные таблицы каталога в единую базу данных. Затем я построил новые таблицы, в которых (а) были удалены столбцы, которые мне больше не нужны, и (б) была нормализована информация, чтобы каждый кортеж в каждой таблице отражал все данные.
Затем я объединил пять таблиц в одну таблицу под новым значением первичного ключа, а затем импортировал эти данные непосредственно в коллекцию Монго. Это заняло несколько часов, поскольку моя коллекция насчитывает более 3,6 миллиона строк.
Когда у меня была коллекция в монго, я сделал моно-дамп коллекции, чтобы я мог вернуться к этому моменту на случай, если что-нибудь пойдет на юг. (Что это сделал …)
Я выполнил скрипт PHP, который написал, чтобы отсканировать таблицу mySQL, получить кортеж по вновь созданному первичному ключу, а затем создать подмассив в коллекции mongo для геопространственных данных. Смотрите, чтобы наложить геопространственный индекс, ваши данные широты и долготы должны быть подмассивом в первичной коллекции. Я еще не обнаружил способа импортировать данные из плоского (CSV) файла или напрямую из MySQL, чтобы он автоматически создавал ваш подмассив. Следовательно, PHP-скрипт для домашнего просмотра для анализа записей mySQL и создания (вставки) подмассива во вновь созданную коллекцию mongodb.
(Примечание: я старался поддерживать максимальные значения мантиссы для полей lat / lon путем первоначального импорта в поля mySQL as varchar (255) — это сохранило мои 13-значные мантиссы. Когда я импортировал данные в mongodb, mongo преобразовал эти значения делаются на двойные и сохраняют точность. Однако моя PHP-программа преобразует эти значения либо в (плавающее), либо (двойное) преобразовывает (округляет) матрицу в 7-значную точность. Подходит для задачи? Да. Раздражает потеря этих данных ? Да. Если у вас есть решение, пожалуйста, оставьте мне комментарий в конце этой статьи. Спасибо! )
Следующим шагом было добавление геопространственного индекса в коллекцию:
> db.geodata_geo.ensureIndex( { loc : “2d” } ); point not in interval of [ -180, 180 )
Какая?
Это сообщение об ошибке сообщало мне, что мои данные были вне диапазона допустимых значений широты / долготы!
Я попытался найти виновников данных:
> db.geodata_geo.find( { "loc" : { $exists : true }}).count(); 3685667 > db.geodata_geo.find({"loc.lon" : {$lt : -180}}).count(); 0 > db.geodata_geo.find({"loc.lon" : {$gt : 180}}).count(); 0 > db.geodata_geo.find({"loc.lat" : {$gt : 180}}).count(); 0 > db.geodata_geo.find({"loc.lat" : {$lt : -180}}).count(); 0
Эти запросы говорили мне, что, хотя я проиндексировал более 3,6 миллиона записей, ни одна из них не выходит за пределы -180,180.
> db.geodata_geo.find({"loc.lat" : {$gt : -180}, "loc.lon" : {$lt : 180}}).count(); 3685663 > db.geodata_geo.find( { "loc" : { $exists : true }}).count(); 3685667
Эти запросы говорят мне, что у меня есть дельта из 4 записей, которая существует вне границы -180, 180.
Подождите … ВТ?
Я сосредотачиваюсь на $ gt / $ lt и задаюсь вопросом, есть ли у меня «крайний» случай. Учитывая, что я потерял 6 цифр моей мантиссы, мне интересно, округлила ли монго мои данные до моих краевых случаев 180:
> db.geodata_geo.find({"loc.lon" : 180 });
И я получаю ровно четыре записи, которые имеют значение lon ровно 180:
"loc" : { "lon" : 180, "lat" : -16.1499996 }
Мне кажется, это ошибка в том, как mongodb индексирует геопространственные данные. Если 180 — допустимое значение для широты / долготы, то зачем выдавать ошибку, когда вы гарантируете индекс? Я решил решить эту проблему округления, расширив допустимые пределы моего запроса:
> db.geodata_geo.ensureIndex({ "loc" : "2d" }, { min : -180, max : 181 }); > db.geodata_geo.getIndexes(); [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "dev_honeybadger.geodata_geo", "name" : "_id_" }, { "v" : 1, "key" : { "loc" : "2d" }, "ns" : "dev_honeybadger.geodata_geo", "name" : "loc_", "min" : -180, "max" : 181 } ]
И я вижу, что мой геопространственный индекс создан. Теперь, чтобы проверить:
> db.geodata_geo.find( { loc : {$near : [-50,50] } } ).limit(5);
И он немедленно возвращает пять записей (Elliston, Bonavista, Elliston Station, Catalina and Port Union, Division # 7, в Канаде), которые я запросил.
Мой геопространственный индекс завершен! Теперь все, что мне нужно сделать, это добавить свои обычные индексы для поиска по ключевым словам и экспортировать таблицу из моей среды разработки.