python - usar - Obteniendo una fila aleatoria a través de SQLAlchemy
python funciones random (8)
Hay un par de maneras a través de SQL, dependiendo de qué base de datos se está utilizando.
(Creo que SQLAlchemy puede usar todos estos de todos modos)
mysql:
SELECT colum FROM table
ORDER BY RAND()
LIMIT 1
PostgreSQL:
SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1
MSSQL:
SELECT TOP 1 column FROM table
ORDER BY NEWID()
IBM DB2:
SELECT column, RAND() as IDX
FROM table
ORDER BY IDX FETCH FIRST 1 ROWS ONLY
Oráculo:
SELECT column FROM
(SELECT column FROM table
ORDER BY dbms_random.value)
WHERE rownum = 1
Sin embargo, no sé de ninguna manera estándar
¿Cómo selecciono una (o algunas) filas aleatorias de una tabla usando SQLAlchemy?
Si está utilizando el orm y la tabla no es grande (o tiene la cantidad de filas en caché) y desea que sea independiente de la base de datos, el enfoque realmente simple es.
import random
rand = random.randrange(0, session.query(Table).count())
row = session.query(Table)[rand]
Esto es hacer trampa un poco, pero es por eso que usas un orm.
Una versión mejorada del ejemplo de Lukasz, en el caso de que necesite seleccionar varias filas al azar:
import random
# you must first select all the values of the primary key field for the table.
# in some particular cases you can use xrange(session.query(Table).count()) instead
ids = session.query(Table.primary_key_field).all()
ids_sample = random.sample(ids, 100)
rows = session.query(Table).filter(Table.primary_key_field.in_(ids_sample))
Por lo tanto, esta publicación es solo para señalar que puede usar .in_ para seleccionar varios campos al mismo tiempo.
Esto es en gran medida un problema específico de la base de datos.
Sé que PostgreSQL y MySQL tienen la capacidad de ordenar por una función aleatoria, por lo que puede usar esto en SQLAlchemy:
from sqlalchemy.sql.expression import func, select
select.order_by(func.random()) # for PostgreSQL, SQLite
select.order_by(func.rand()) # for MySQL
select.order_by(''dbms_random.value'') # For Oracle
A continuación, debe limitar la consulta por la cantidad de registros que necesita (por ejemplo, utilizando .limit()
).
Tenga en cuenta que al menos en PostgreSQL, la selección de registros aleatorios tiene graves problemas de rendimiento; aquí hay un buen artículo al respecto.
Hay una forma simple de extraer una fila aleatoria que IS sea independiente de la base de datos. Solo usa .offset (). No es necesario tirar de todas las filas:
import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()
Donde Table es su tabla (o puede poner cualquier consulta allí). Si quiere algunas filas, puede ejecutar esto varias veces y asegurarse de que cada fila no sea idéntica a la anterior.
esta solución seleccionará una sola fila aleatoria
Esta solución requiere que la clave principal se denomine id, debería ser si aún no lo está:
import random
max_model_id = YourModel.query.order_by(YourModel.id.desc())[0].id
random_id = random.randrange(0,max_model_id)
random_row = YourModel.query.get(random_id)
print random_row
Aquí hay cuatro variaciones diferentes, ordenadas de la más lenta a la más rápida. timeit
resultados de tiempo en la parte inferior:
from sqlalchemy.sql import func
from sqlalchemy.orm import load_only
def simple_random():
return random.choice(model_name.query.all())
def load_only_random():
return random.choice(model_name.query.options(load_only(''id'')).all())
def order_by_random():
return model_name.query.order_by(func.random()).first()
def optimized_random():
return model_name.query.options(load_only(''id'')).offset(
func.floor(
func.random() *
db.session.query(func.count(model_name.id))
)
).limit(1).all()
timeit
resulta para 10,000 carreras en mi Macbook contra una tabla de PostgreSQL con 300 filas:
simple_random():
90.09954111799925
load_only_random():
65.94714171699889
order_by_random():
23.17819356000109
optimized_random():
19.87806927999918
Puede ver fácilmente que usar func.random()
es mucho más rápido que devolver todos los resultados a func.random()
de Python.
Además, a medida que aumenta el tamaño de la tabla, el rendimiento de order_by_random()
se degradará significativamente porque un ORDER BY
requiere una exploración de tabla completa frente a COUNT
en optimized_random()
puede usar un índice.
Esta es la solución que uso:
from random import randint
rows_query = session.query(Table) # get all rows
if rows_query.count() > 0: # make sure there''s at least 1 row
rand_index = randint(0,rows_query.count()-1) # get random index to rows
rand_row = rows_query.all()[rand_index] # use random index to get random row