Пригодность MongoDB для запросов иерархического типа - PullRequest
10 голосов
/ 08 апреля 2011

У меня есть определенное требование к обработке данных, которое я разработал, как это сделать в SQL Server и PostgreSQL. Тем не менее, я не слишком доволен скоростью, поэтому я изучаю MongoDB.

Лучший способ описать запрос заключается в следующем. Представьте себе иерархические данные США: Страна, Штат, Округ, Город. Допустим, конкретный поставщик может обслуживать всю Калифорнию. Другой может обслуживать только Лос-Анджелес. Потенциально существуют сотни тысяч поставщиков, и все они могут обслуживать некоторые точки этой иерархии. Я не путаю это с Geo - я использую это, чтобы проиллюстрировать необходимость.

Используя рекурсивные запросы, довольно просто получить список всех поставщиков, которые могли бы обслуживать конкретного пользователя. Если бы он был, скажем, в Пасадене, Лос-Анджелес, Калифорния, мы бы пошли вверх по иерархии, чтобы получить применимые идентификаторы, а затем отправили бы запрос обратно, чтобы найти поставщиков.

Я знаю, что это можно оптимизировать. Опять же, это простой пример запроса.

Я знаю, MongoDB - это хранилище документов. Это удовлетворяет другим потребностям, которые у меня есть очень хорошо. Вопрос в том, насколько он подходит для типа запроса, который я описываю? (Я знаю, что у него нет соединений - они смоделированы).

Я понял, что это вопрос "как долго это кусок строки". Я просто хочу знать, есть ли у кого-нибудь опыт работы с MongoDB. Мне может потребоваться некоторое время, чтобы перейти от 0 к проверенному, и я надеюсь сэкономить время, если MongoDB не подходит для этого.

Пример

Местный кинотеатр "А" может поставить Blu-Rays в Спрингфилде. Сеть магазинов "B" с распределением по всему штату может поставлять Blu-Rays для всех IL. А магазин для загрузки по требованию "C" может поставлять товары в любую точку США.

Если бы мы хотели получить всех подходящих поставщиков фильмов для Спрингфилда, Иллинойс, ответ был бы [A, B, C].

Другими словами, существует множество поставщиков, подключенных к различным уровням в иерархии.

Ответы [ 2 ]

8 голосов
/ 09 марта 2012

Я понимаю, что этот вопрос задавался почти год назад, но с тех пор MongoDB имеет официально поддерживаемое решение для этой проблемы, и я просто использовал их решение. Обратитесь к их документации здесь: http://www.mongodb.org/display/DOCS/Trees+in+MongoDB

Часть, относящаяся ближе всего к вашему вопросу, находится в разделе "частичный путь" на странице.

Хотя может быть немного тяжело встраивать данные предка; Этот подход является наиболее подходящим способом решения вашей проблемы в MongoDB. Единственный подводный камень, о котором я до сих пор сталкивался, это то, что если вы храните все это в одном документе, то при работе с достаточным объемом данных вы можете достичь предельного размера документа в 16 МБ (хотя, Я могу видеть это только в том случае, если вы используете эту структуру для отслеживания рефералов пользователей [которые могут достигать миллионов], а не городов США [что превышает 26 000 по последней переписи США]).


Ссылка:

http://www.mongodb.org/display/DOCS/Schema+Design

http://www.census.gov/geo/www/gazetteer/places2k.html

2 голосов
/ 09 апреля 2011

Обратите внимание, что этот вопрос также задавался в группе Google.См. http://groups.google.com/group/mongodb-user/browse_thread/thread/5cd5edd549813148 для этой дискуссии.

Один из вариантов - использовать ключ массива.Вы можете сохранить иерархию в виде массива значений (например, ['US', 'CA', 'Los Angeles']).Затем вы можете выполнять запросы к записям на основе отдельных элементов в этом ключе массива. Например: сначала сохраните некоторые документы со значением массива, представляющим иерархию

> db.hierarchical.save({ location: ['US','CA','LA'], name: 'foo'} ) 
> db.hierarchical.save({ location: ['US','CA','SF'], name: 'bar'} ) 
> db.hierarchical.save({ location: ['US','MA','BOS'], name: 'baz'} ) 

. Убедитесь, что у нас есть индекс в поле местоположения, поэтому мыможет выполнять быстрые запросы к его значениям

> db.hierarchical.ensureIndex({'location':1}) 

Найти все записи в Калифорнии

> db.hierarchical.find({location: 'CA'}) 
{ "_id" : ObjectId("4d9f69cbf88aea89d1492c55"), "location" : [ "US", "CA", "LA" ], "name" : "foo" } 
{ "_id" : ObjectId("4d9f69dcf88aea89d1492c56"), "location" : [ "US", "CA", "SF" ], "name" : "bar" } 

Найти все записи в Массачусетсе

> db.hierarchical.find({location: 'MA'}) 
{ "_id" : ObjectId("4d9f6a21f88aea89d1492c5a"), "location" : [ "US", "MA", "BOS" ], "name" : "baz" } 

Найти все записи в США

> db.hierarchical.find({location: 'US'}) 
{ "_id" : ObjectId("4d9f69cbf88aea89d1492c55"), "location" : [ "US", "CA", "LA" ], "name" : "foo" } 
{ "_id" : ObjectId("4d9f69dcf88aea89d1492c56"), "location" : [ "US", "CA", "SF" ], "name" : "bar" } 
{ "_id" : ObjectId("4d9f6a21f88aea89d1492c5a"), "location" : [ "US", "MA", "BOS" ], "name" : "baz" } 

Обратите внимание, что в этой модели ваши значения в массиве должны быть уникальными.Так, например, если бы у вас было «спрингфилд» в разных штатах, то вам нужно было бы проделать некоторую дополнительную работу для дифференциации.

> db.hierarchical.save({location:['US','MA','Springfield'], name: 'one' }) 
> db.hierarchical.save({location:['US','IL','Springfield'], name: 'two' }) 
> db.hierarchical.find({location: 'Springfield'}) 
{ "_id" : ObjectId("4d9f6b7cf88aea89d1492c5b"), "location" : [ "US", "MA", "Springfield"], "name" : "one" } 
{ "_id" : ObjectId("4d9f6b86f88aea89d1492c5c"), "location" : [ "US", "IL", "Springfield"], "name" : "two" } 

Вы можете преодолеть это, используя оператор $ all и указав больше уровней иерархии.Например:

> db.hierarchical.find({location: { $all : ['US','MA','Springfield']} }) 
{ "_id" : ObjectId("4d9f6b7cf88aea89d1492c5b"), "location" : [ "US", "MA", "Springfield"], "name" : "one" } 
> db.hierarchical.find({location: { $all : ['US','IL','Springfield']} }) 
{ "_id" : ObjectId("4d9f6b86f88aea89d1492c5c"), "location" : [ "US", "IL", "Springfield"], "name" : "two" } 
...