2010-04-26 14 views
6

Tengo una tabla MySQL que tiene una fila llamada cur_odds que es un número porcentual con el porcentaje de probabilidad de que esa fila sea seleccionada. ¿Cómo realizo una consulta que realmente seleccionará las filas en aproximadamente esa frecuencia cuando ejecute 100 consultas, por ejemplo?Seleccionar una fila aleatoria de MySQL (con probabilidad)

Intenté lo siguiente, pero una fila que tiene una probabilidad de 0.35 termina siendo seleccionada alrededor del 60-70% del tiempo.

SELECT * FROM table ORDER BY RAND()*cur_odds DESC 

Todos los valores de cur_odds en la tabla suman exactamente 1.

+0

ORDER BY RAND() puede ser muy lento con grandes conjuntos de datos, ya que es O (n log (n)). ¿Cuántas filas tendrá tu mesa? –

Respuesta

4

Si cur_odds se cambia rara vez se podría implementar el algoritmo siguiente:

1) Crear otra columna prob_sum, para lo cual

prob_sum [0]: = cur_odds [0]

de 1 < = i < = row_count - 1:

prob_sum [i]: = prob_sum [i - 1] + cur_odds [i]

2) generar un número aleatorio de 0 a 1:

rnd: = rand (0,1)

3) Encuentra la primera fila para la que prob_sum > rnd (si crear un índice BTREE en el prob_sum, la consulta debe trabajar mucho más rápido):

CREATE prob_sum_ind íNDICE dE lA < mesa> (prob_sum);

SET @rnd: = RAND();

SELECCIONAR MIN (prob_sum) FROM < tabla> WHERE prob_sum> @rnd;

+0

Una mejor respuesta está aquí: http://stackoverflow.com/a/12301949/901739 –

3

Teniendo en cuenta la instrucción SQL anterior, cualquier número que tiene en cur_odds son no las probabilidades de que se selecciona cada fila, sino que es sólo una ponderación arbitraria (en relación a los "pesos" de todas las otras filas) que podrían en su lugar, se interpretará mejor como una tendencia relativa a flotar hacia la parte superior de la tabla ordenada. El valor real en cada fila no tiene sentido (por ejemplo, podría tener 4 filas con valores de 0.35, 0.5, 0.75 y 0.99, o podría tener valores de 35, 50, 75 y 99, y los resultados serían los mismos).

Actualización: Esto es lo que está sucediendo con su consulta. Tiene una fila con un valor cur_odds de 0,35. Por el bien de la ilustración, voy a suponer que las otras 9 filas tienen el mismo valor (0.072). También para ilustrar, supongamos que RAND() devuelve un valor de 0.0 a 1.0 (en realidad puede).

Cada vez que ejecuta esta instrucción SELECT, a cada fila se le asigna un valor de clasificación multiplicando su valor cur_odds por un valor RAND() de 0.0 a 1.0. Esto significa que la fila con un 0.35 tendrá un valor de clasificación entre 0.0 y 0.35.

Cada dos filas (con un valor de 0.072) tendrá valores de clasificación que oscilan entre 0.0 y 0.072. Esto significa que hay aproximadamente un 80% de posibilidades de que su fila tenga un valor de clasificación mayor que 0.072, lo que significa que hay sin posibilidad de de que cualquier otra fila se pueda clasificar más arriba. Esta es la razón por la cual su fila con el valor cur_odds de 0.35 está subiendo primero más de lo esperado.

Describí incorrectamente el valor cur_odds como una ponderación de cambio relativa. En realidad, funciona como una ponderación relativa máxima, que luego implicaría algunas matemáticas complejas para determinar las probabilidades relativas reales involucradas.

No estoy seguro de qué se puede hacer con T-SQL directo. Implementé un selector de probabilidad ponderado muchas veces (incluso irónicamente, iba a hacer una pregunta sobre los mejores métodos para esto esta mañana) pero siempre en código.

+0

En realidad, tengo 10 filas, y los 10 valores en cur_odds equivalen a 1 exactamente. –

+1

Intenta multiplicar todos los valores por 10 (para que sumen a 10.0 exactamente) y verás que obtienes los mismos resultados de ordenamiento. O puede dividirlos por 3 o multiplicar por 100, etc. – MusiGenesis

Cuestiones relacionadas