Estoy buscando obtener un registro aleatorio de un enorme (registro de 100 millones) mongodb
.
¿Cuál es la forma más rápida y eficiente de hacerlo? Los datos ya están allí y no hay ningún campo en el que pueda generar un número aleatorio y obtener una fila aleatoria.
¿Alguna sugerencia?
mongodb
mongodb-query
Will M
fuente
fuente
Respuestas:
A partir de la versión 3.2 de MongoDB, puede obtener N documentos aleatorios de una colección utilizando el
$sample
operador de canalización de agregación:Si desea seleccionar los documentos aleatorios de un subconjunto filtrado de la colección, anteponga una
$match
etapa a la tubería:Como se señaló en los comentarios, cuando
size
es mayor que 1, puede haber duplicados en la muestra del documento devuelto.fuente
Haga un recuento de todos los registros, genere un número aleatorio entre 0 y el recuento, y luego haga:
fuente
Actualización para MongoDB 3.2
3.2 introdujo $ sample en la canalización de agregación.
También hay una buena publicación de blog sobre cómo ponerla en práctica.
Para versiones anteriores (respuesta anterior)
En realidad, esta fue una solicitud de función: http://jira.mongodb.org/browse/SERVER-533 pero se archivó en "No se solucionará".
El libro de cocina tiene una muy buena receta para seleccionar un documento aleatorio de una colección: http://cookbook.mongodb.org/patterns/random-attribute/
Parafraseando la receta, asigna números aleatorios a sus documentos:
Luego seleccione un documento aleatorio:
Consulta con ambos
$gte
y$lte
es necesario encontrar el documento con un número aleatorio más cercanorand
.Y, por supuesto, querrá indexar en el campo aleatorio:
Si ya está consultando un índice, simplemente suéltelo
random: 1
, agréguelo y agréguelo nuevamente.fuente
$gte
está primero. La solución alternativa stackoverflow.com/a/9499484/79201 funcionaría mejor en este caso.También puede usar la función de indexación geoespacial de MongoDB para seleccionar los documentos 'más cercanos' a un número aleatorio.
Primero, habilite la indexación geoespacial en una colección:
Para crear un montón de documentos con puntos aleatorios en el eje X:
Entonces puede obtener un documento aleatorio de la colección como este:
O puede recuperar varios documentos más cercanos a un punto aleatorio:
Esto requiere solo una consulta y no verificaciones nulas, además el código es limpio, simple y flexible. Incluso podría usar el eje Y del geopunto para agregar una segunda dimensión de aleatoriedad a su consulta.
fuente
La siguiente receta es un poco más lenta que la solución de libro de cocina mongo (agregue una clave aleatoria en cada documento), pero devuelve documentos aleatorios distribuidos de manera más uniforme. Está un poco menos distribuido que la
skip( random )
solución, pero es mucho más rápido y más seguro en caso de que se eliminen los documentos.También requiere que agregue un campo aleatorio "aleatorio" a sus documentos, así que no olvide agregar esto cuando los cree: es posible que deba inicializar su colección como lo muestra Geoffrey
Resultados de referencia
Este método es mucho más rápido que el
skip()
método (de ceejayoz) y genera documentos aleatorios más uniformes que el método del "libro de cocina" reportado por Michael:Para una colección con 1,000,000 de elementos:
Este método toma menos de un milisegundo en mi máquina
el
skip()
método tarda 180 ms en promedioEl método del libro de cocina hará que nunca se recojan grandes cantidades de documentos porque su número aleatorio no los favorece.
Este método elegirá todos los elementos de manera uniforme con el tiempo.
En mi punto de referencia fue solo un 30% más lento que el método del libro de cocina.
la aleatoriedad no es 100% perfecta pero es muy buena (y se puede mejorar si es necesario)
Esta receta no es perfecta: la solución perfecta sería una característica incorporada como otros han señalado.
Sin embargo, debería ser un buen compromiso para muchos propósitos.
fuente
Aquí hay una manera de usar los
ObjectId
valores predeterminados para_id
y un poco de matemática y lógica.Esa es la lógica general en la representación de shell y fácilmente adaptable.
Entonces en puntos:
Encuentre los valores de clave primaria mínima y máxima en la colección
Genere un número aleatorio que se encuentre entre las marcas de tiempo de esos documentos.
Agregue el número aleatorio al valor mínimo y encuentre el primer documento que sea mayor o igual a ese valor.
Esto usa "relleno" del valor de marca de tiempo en "hexadecimal" para formar un
ObjectId
valor válido ya que eso es lo que estamos buscando. Usar enteros como_id
valor es esencialmente más simple pero la misma idea básica en los puntos.fuente
En Python usando pymongo:
fuente
count()
conestimated_document_count()
quecount()
está en desuso en Mongdo v4.2.Ahora puedes usar el agregado. Ejemplo:
Ver el doc .
fuente
es difícil si no hay datos para desconectar. ¿Cuáles son los campos _id? ¿son identificaciones de objeto mongodb? Si es así, podría obtener los valores más altos y más bajos:
entonces, si asume que los id están distribuidos uniformemente (pero no lo están, pero al menos es un comienzo):
fuente
Usando Python (pymongo), la función de agregado también funciona.
Este enfoque es mucho más rápido que ejecutar una consulta para un número aleatorio (por ejemplo, collection.find ([random_int]). Este es especialmente el caso de grandes colecciones.
fuente
Puede elegir una marca de tiempo aleatoria y buscar el primer objeto que se creó después. Solo escaneará un solo documento, aunque no necesariamente le proporciona una distribución uniforme.
fuente
Mi solución en php:
fuente
Para obtener un número determinado de documentos aleatorios sin duplicados:
bucle que obtiene índice aleatorio y omisión duplicada
fuente
Sugeriría usar map / reduce, donde usa la función de mapa para emitir solo cuando un valor aleatorio está por encima de una probabilidad dada.
La función reducef anterior funciona porque solo se emite una tecla ('1') desde la función de mapa.
El valor de la "probabilidad" se define en el "alcance", cuando se invoca mapRreduce (...)
El uso de mapReduce como este también debería ser utilizable en una base de datos fragmentada.
Si desea seleccionar exactamente n de m documentos de la base de datos, puede hacerlo así:
Donde "countTotal" (m) es el número de documentos en la base de datos, y "countSubset" (n) es el número de documentos a recuperar.
Este enfoque puede dar algunos problemas en las bases de datos fragmentadas.
fuente
Puede elegir _id aleatorio y devolver el objeto correspondiente:
Aquí no necesita gastar espacio para almacenar números aleatorios en la colección.
fuente
Sugeriría agregar un campo int aleatorio a cada objeto. Entonces puedes hacer un
para elegir un documento al azar. Solo asegúrese de asegurar Index ({random_field: 1})
fuente
Cuando me enfrenté a una solución similar, retrocedí y descubrí que la solicitud comercial era en realidad para crear alguna forma de rotación del inventario que se presentaba. En ese caso, hay opciones mucho mejores, que tienen respuestas de motores de búsqueda como Solr, no almacenes de datos como MongoDB.
En resumen, con el requisito de "rotar inteligentemente" el contenido, lo que deberíamos hacer en lugar de un número aleatorio en todos los documentos es incluir un modificador de puntuación q personal. Para implementar esto usted mismo, suponiendo una pequeña población de usuarios, puede almacenar un documento por usuario que tenga el ID del producto, el recuento de impresiones, el recuento de clics, la fecha de la última visita y cualquier otro factor que la empresa considere significativo para calcular un puntaje q modificador Al recuperar el conjunto para mostrar, normalmente solicita más documentos del almacén de datos que los solicitados por el usuario final, luego aplica el modificador de puntuación q, toma el número de registros solicitados por el usuario final, luego aleatoriza la página de resultados, un pequeño establecer, así que simplemente ordene los documentos en la capa de aplicación (en la memoria).
Si el universo de usuarios es demasiado grande, puede clasificar a los usuarios en grupos de comportamiento e indexarlos por grupo de comportamiento en lugar de usuario.
Si el universo de productos es lo suficientemente pequeño, puede crear un índice por usuario.
He descubierto que esta técnica es mucho más eficiente, pero más importante, más efectiva para crear una experiencia relevante y valiosa de usar la solución de software.
fuente
ninguna de las soluciones funcionó bien para mí. especialmente cuando hay muchos huecos y el conjunto es pequeño. esto funcionó muy bien para mí (en php):
fuente
find
+skip
es bastante malo, está devolviendo todos los documentos solo para elegir uno: S.Si está usando mangosta, entonces puede usar mangosta aleatoria mongoosa aleatoria
fuente
Mi ordenación / orden PHP / MongoDB por solución RANDOM. Espero que esto ayude a cualquiera.
Nota: Tengo identificaciones numéricas dentro de mi colección MongoDB que se refieren a un registro de base de datos MySQL.
Primero creo una matriz con 10 números generados aleatoriamente
En mi agregación, uso el operador de canalización $ addField combinado con $ arrayElemAt y $ mod (módulo). El operador de módulo me dará un número de 0 a 9 que luego usaré para elegir un número de la matriz con números generados al azar.
Después de eso, puede usar el tipo Pipeline.
fuente
Si tiene una clave de identificación simple, puede almacenar todas las identificaciones en una matriz y luego elegir una identificación aleatoria. (Respuesta de Ruby):
fuente
Usando Map / Reduce, ciertamente puede obtener un registro aleatorio, pero no necesariamente de manera muy eficiente dependiendo del tamaño de la colección filtrada resultante con la que termina trabajando.
He probado este método con 50,000 documentos (el filtro lo reduce a aproximadamente 30,000), y se ejecuta en aproximadamente 400 ms en un Intel i3 con 16 GB de RAM y un HDD SATA3 ...
La función de mapa simplemente crea una matriz de id de todos los documentos que coinciden con la consulta. En mi caso, probé esto con aproximadamente 30,000 de los 50,000 documentos posibles.
La función Reducir simplemente elige un número entero aleatorio entre 0 y el número de elementos (-1) en la matriz, y luego devuelve ese _id de la matriz.
400 ms parece mucho tiempo, y realmente lo es, si tuviera cincuenta millones de registros en lugar de cincuenta mil, esto puede aumentar la sobrecarga hasta el punto en que se vuelva inutilizable en situaciones de múltiples usuarios.
Hay un problema abierto para que MongoDB incluya esta característica en el núcleo ... https://jira.mongodb.org/browse/SERVER-533
Si esta selección "aleatoria" se integrara en una búsqueda de índice en lugar de recopilar identificadores en una matriz y luego seleccionar uno, esto sería de gran ayuda. (¡Ve a votar!)
fuente
Esto funciona bien, es rápido, funciona con varios documentos y no requiere un
rand
campo de relleno, que eventualmente se completará:PD. Cómo encontrar registros aleatorios en la pregunta mongodb está marcado como duplicado de esta pregunta. La diferencia es que esta pregunta se refiere explícitamente de registro único como el otro de manera explícita acerca de cómo obtener documentos al azar s .
fuente
Si está usando mongoid, el contenedor de documento a objeto, puede hacer lo siguiente en Ruby. (Suponiendo que su modelo es Usuario)
En mi .irbrc, tengo
así que en la consola de rails, puedo hacer, por ejemplo,
para obtener documentos al azar de cualquier colección.
fuente
También puede usar shuffle-array después de ejecutar su consulta
var shuffle = require ('shuffle-array');
Accounts.find (qry, function (err, results_array) {newIndexArr = shuffle (results_array);
fuente
Lo que funciona de manera eficiente y confiable es esto:
Agregue un campo llamado "aleatorio" a cada documento y asígnele un valor aleatorio, agregue un índice para el campo aleatorio y proceda de la siguiente manera:
Supongamos que tenemos una colección de enlaces web llamados "enlaces" y queremos un enlace aleatorio de ella:
Para asegurarse de que el mismo enlace no aparezca por segunda vez, actualice su campo aleatorio con un nuevo número aleatorio:
fuente