Я хочу получить случайную запись из огромного (100 миллионов записей) mongodb
.
Какой самый быстрый и эффективный способ сделать это? Данные уже есть, и нет поля, в котором я могу сгенерировать случайное число и получить случайную строку.
Какие-либо предложения?
mongodb
mongodb-query
Будет М
источник
источник
Ответы:
Начиная с версии 3.2 MongoDB, вы можете получить N случайных документов из коллекции, используя
$sample
оператор конвейера агрегации:Если вы хотите выбрать случайный документ (ы) из отфильтрованного подмножества коллекции, добавьте
$match
этап к конвейеру:Как отмечено в комментариях, когда
size
больше 1, в возвращенном образце документа могут быть дубликаты.источник
Выполните подсчет всех записей, сгенерируйте случайное число между 0 и счетчиком, а затем выполните:
источник
Обновление для MongoDB 3.2
3.2 ввел $ sample в конвейер агрегации.
Есть также хорошая запись в блоге о том, как применить это на практике.
Для более старых версий (предыдущий ответ)
На самом деле это был запрос функции: http://jira.mongodb.org/browse/SERVER-533, но он был подан в разделе «Не будет исправлено».
У кулинарной книги очень хороший рецепт выбора случайного документа из коллекции: http://cookbook.mongodb.org/patterns/random-attribute/
Чтобы перефразировать рецепт, вы назначаете случайные числа вашим документам:
Затем выберите случайный документ:
Запрашивая оба
$gte
и$lte
необходимо найти документ со случайным числом ближайшимrand
.И, конечно, вы захотите проиндексировать случайное поле:
Если вы уже запрашиваете индекс, просто удалите его, добавьте
random: 1
к нему и добавьте снова.источник
$gte
первый. Альтернативное решение stackoverflow.com/a/9499484/79201 будет работать лучше в этом случае.Вы также можете использовать функцию геопространственной индексации MongoDB для выбора документов, «ближайших» к случайному числу.
Сначала включите геопространственную индексацию для коллекции:
Чтобы создать пачку документов со случайными точками на оси X:
Затем вы можете получить случайный документ из коллекции следующим образом:
Или вы можете получить несколько документов, ближайших к случайной точке:
Это требует только одного запроса и никаких нулевых проверок, плюс код чистый, простой и гибкий. Вы даже можете использовать ось Y геопункта, чтобы добавить второе измерение случайности в свой запрос.
источник
Следующий рецепт немного медленнее, чем решение поваренной книги Монго (добавьте случайный ключ к каждому документу), но возвращает более равномерно распределенные случайные документы. Он немного менее равномерно распределен, чем
skip( random )
решение, но гораздо быстрее и безопаснее в случае удаления документов.Это также требует, чтобы вы добавили случайное «случайное» поле в ваши документы, поэтому не забудьте добавить это при создании: вам может понадобиться инициализировать вашу коллекцию, как показано Джеффри
Результаты тестов
Этот метод намного быстрее, чем
skip()
метод (ceejayoz), и генерирует более равномерно случайные документы, чем метод «поваренной книги», сообщенный Майклом:Для коллекции с 1 000 000 элементов:
Этот метод занимает менее миллисекунды на моей машине
skip()
метод занимает 180 мс в среднемМетод кулинарной книги приведет к тому, что большое количество документов никогда не будет выбрано, потому что их случайное число не поддерживает их.
Этот метод будет выбирать все элементы равномерно с течением времени.
В моем тесте он был только на 30% медленнее, чем метод поваренной книги.
случайность не на 100% идеальна, но она очень хороша (и может быть улучшена при необходимости)
Этот рецепт не идеален - идеальное решение было бы встроенной функцией, как отметили другие.
Однако это должно быть хорошим компромиссом для многих целей.
источник
Вот способ использования
ObjectId
значений по умолчанию для_id
и немного математики и логики.Это общая логика в представлении оболочки и легко адаптируемая.
Итак, в баллах:
Найдите минимальные и максимальные значения первичного ключа в коллекции
Создайте случайное число, которое попадает между метками времени этих документов.
Добавьте случайное число к минимальному значению и найдите первый документ, который больше или равен этому значению.
При этом используется «padding» из значения метки времени в «hex», чтобы сформировать действительное
ObjectId
значение, поскольку именно это мы и ищем. Использование целых чисел в качестве_id
значения существенно проще, но та же основная идея в точках.источник
В Python используется pymongo:
источник
count()
наestimated_document_count()
ascount()
устарел в Mongdo v4.2.Теперь вы можете использовать агрегат. Пример:
Смотрите док .
источник
трудно, если там нет данных для отключения. что такое поле _id? они идентификаторы объекта mongodb? Если это так, вы можете получить самые высокие и самые низкие значения:
затем, если вы предполагаете, что идентификаторы распределены равномерно (но это не так, но, по крайней мере, это начало):
источник
Используя Python (pymongo), агрегатная функция также работает.
Этот подход намного быстрее, чем выполнение запроса для случайного числа (например, collection.find ([random_int]). Это особенно касается больших коллекций.
источник
Вы можете выбрать случайную временную метку и найти первый объект, который был создан впоследствии. Он будет сканировать только один документ, хотя это не обязательно даст вам равномерное распределение.
источник
Мое решение на php:
источник
Чтобы получить определенное количество случайных документов без дубликатов:
цикл получает случайный индекс и пропускает дубликаты
источник
Я бы предложил использовать карту / уменьшить, где вы используете функцию карты, чтобы излучать только тогда, когда случайное значение выше заданной вероятности.
Вышеприведенная функция reduf работает, потому что из функции карты выдается только одна клавиша ('1').
Значение «вероятности» определяется в «области видимости» при вызове mapRreduce (...)
Подобное использование mapReduce также должно быть применимо к осколкам БД.
Если вы хотите выбрать ровно n из m документов из БД, вы можете сделать это следующим образом:
Где «countTotal» (m) - это количество документов в БД, а «countSubset» (n) - это количество документов, которые необходимо извлечь.
При таком подходе могут возникнуть проблемы с закрытыми базами данных.
источник
Вы можете выбрать случайный _id и вернуть соответствующий объект:
Здесь вам не нужно тратить место на хранение случайных чисел в коллекции.
источник
Я бы предложил добавить случайное поле int для каждого объекта. Тогда вы можете просто сделать
выбрать случайный документ. Просто убедитесь, что вы уверены, что Index ({random_field: 1})
источник
Когда я столкнулся с подобным решением, я вернулся назад и обнаружил, что бизнес-запрос на самом деле был направлен на создание некоторой формы ротации представляемых запасов. В этом случае есть намного лучшие варианты, которые имеют ответы от поисковых систем, таких как Solr, а не хранилищ данных, таких как MongoDB.
Короче говоря, с требованием «разумно вращать» контент, что мы должны сделать вместо случайного числа во всех документах, это включить персональный модификатор q Score. Чтобы реализовать это самостоятельно, принимая во внимание небольшую группу пользователей, вы можете хранить документ для каждого пользователя, который имеет идентификатор продукта, количество показов, количество кликов, дату последнего посещения и любые другие факторы, которые компания считает значимыми для вычисления показателя aq. модификатор. При извлечении набора для отображения, как правило, вы запрашиваете больше документов из хранилища данных, чем запрошено конечным пользователем, затем применяете модификатор q Score, берете количество записей, запрошенных конечным пользователем, а затем рандомизируете страницу результатов, крошечную установить, поэтому просто сортируйте документы на прикладном уровне (в памяти).
Если юниверс пользователей слишком велик, вы можете классифицировать пользователей по группам поведения и индексировать по группам поведения, а не по пользователю.
Если набор продуктов достаточно мал, вы можете создать индекс для каждого пользователя.
Я обнаружил, что эта методика намного более эффективна, но, что более важно, более эффективна при создании соответствующего полезного опыта использования программного решения.
источник
Ни одно из решений не помогло мне. особенно, когда есть много пробелов и набор мал. это работало очень хорошо для меня (в php):
источник
find
+skip
довольно плохо, вы возвращаете все документы, чтобы выбрать один: S.Если вы используете мангуста, то вы можете использовать мангуста-случайного мангуста-случайного
источник
Мой PHP / MongoDB сортировка / упорядочение по случайному решению. Надеюсь, это кому-нибудь поможет.
Примечание: у меня есть числовые идентификаторы в моей коллекции MongoDB, которые ссылаются на запись базы данных MySQL.
Сначала я создаю массив из 10 случайно сгенерированных чисел
В своей агрегации я использую оператор конвейера $ addField в сочетании с $ arrayElemAt и $ mod (modulus). Оператор модуля даст мне число от 0 до 9, которое я затем использую, чтобы выбрать число из массива со случайными числами.
После этого вы можете использовать сортировку Pipeline.
источник
Если у вас есть простой ключ идентификатора, вы можете сохранить все идентификаторы в массиве, а затем выбрать случайный идентификатор. (Рубиновый ответ):
источник
Используя Map / Reduce, вы, безусловно, можете получить случайную запись, но не обязательно очень эффективно, в зависимости от размера результирующей отфильтрованной коллекции, с которой вы в конечном итоге работаете.
Я протестировал этот метод с 50 000 документов (фильтр сокращает его примерно до 30 000), и он выполняется примерно за 400 мс на Intel i3 с 16 ГБ оперативной памяти и жестким диском SATA3 ...
Функция Map просто создает массив идентификаторов всех документов, соответствующих запросу. В моем случае я проверил это примерно с 30 000 из 50 000 возможных документов.
Функция Reduce просто выбирает случайное целое число между 0 и количеством элементов (-1) в массиве, а затем возвращает этот _id из массива.
400 мс звучит как долгое время, и действительно, если у вас пятьдесят миллионов записей вместо пятидесяти тысяч, это может увеличить накладные расходы до такой степени, что они станут непригодными для использования в многопользовательских ситуациях.
Для MongoDB существует открытый вопрос о включении этой функции в ядро ... https://jira.mongodb.org/browse/SERVER-533
Если бы этот «случайный» выбор был встроен в поиск по индексу вместо того, чтобы собирать идентификаторы в массив и затем выбирать один, это невероятно помогло бы. (иди голосуй!)
источник
Это работает хорошо, это быстро, работает с несколькими документами и не требует
rand
заполнения поля, которое в конечном итоге заполнится само:пс. Как найти случайные записи в вопросе mongodb помечен как дубликат этого вопроса. Разница заключается в том, что этот вопрос требует явно об одной записи в другой явно о получении случайных документов сек .
источник
Если вы используете mongoid, оболочку для документа к объекту, вы можете сделать следующее в Ruby. (Предполагая, что ваша модель - Пользователь)
В моем .irbrc у меня есть
так что в рельсах консоли я могу сделать, например,
получить документы случайным образом из любой коллекции.
источник
вы также можете использовать shuffle-array после выполнения вашего запроса
var shuffle = require ('shuffle-array');
Accounts.find (qry, function (err, results_array) {newIndexArr = shuffle (results_array);
источник
Что работает эффективно и надежно, так это:
Добавьте поле с именем «random» к каждому документу и присвойте ему случайное значение, добавьте индекс для случайного поля и выполните следующие действия:
Предположим, у нас есть коллекция веб-ссылок под названием «ссылки», и мы хотим получить случайную ссылку из нее:
Чтобы та же ссылка не появлялась во второй раз, обновите ее случайное поле новым случайным числом:
источник