Pregunta

Estoy intentando escribir una consulta que devuelve registros GQL N al azar de un tipo específico. Mi implementación actual funciona, pero requiere N llama al almacén de datos. Me gustaría que sea 1 llamada al almacén de datos si es posible.

Actualmente asigno un número aleatorio a cada clase que he puesto en el almacén de datos. Cuando consulta para un registro aleatorio genero otro número aleatorio y consulta de registros> rand ORDER BY ASC LIMIT 1.

Esto funciona, sin embargo, que sólo devuelve 1 registro por lo que tengo que hacer N consultas. Cualquier ideas sobre cómo hacer esto una consulta? Gracias.

¿Fue útil?

Solución

"Bajo el capó" una sola llamada de consulta de búsqueda sólo puede devolver un conjunto de filas consecutivas de algún índice. Por ello, algunas consultas GQL, incluyendo cualquier uso de! =, Expanda a varias llamadas del almacén de datos.

N uniformes independiente selecciones aleatorias no son (en general) consecutiva en cualquier índice.

QED.

Probablemente se podría utilizar Memcache para almacenar las entidades, y reducir el costo de agarrar N de ellos. O si no te importa las selecciones "al azar" estar muy juntos en el índice, seleccionar un bloque elegido al azar de (digamos) 100 en una consulta, a continuación, elegir N al azar de esos. Puesto que usted tiene un campo que ya se asignaron al azar, no será inmediatamente obvio para una persona ajena que los artículos N están relacionados. Al menos, no hasta que se ven en una gran cantidad de muestras y observe que los puntos A y Z nunca aparecen en el mismo grupo, porque son más de 100, aparte del índice aleatorio. Y si lo permite el rendimiento, puede volver a asignar al azar a sus entidades de vez en cuando.

Otros consejos

¿Qué tipo de compensaciones está buscando? Si usted está dispuesto a poner con un pequeño impacto en el rendimiento sobre la inserción de estas entidades, se puede crear una solución para obtener N de ellos muy rápidamente.

Esto es lo que tiene que hacer:

Al insertar sus entidades, especifique la clave. Se quiere dar a sus entidades claves en orden, empezando por 1 y subiendo desde allí. (Esto requiere un poco de esfuerzo, como motor de aplicación no tiene incremento automático () por lo que tendrá que hacer un seguimiento de la última ID que utilizó en alguna otra entidad, vamos a llamarlo un IdGenerator)

Ahora cuando se necesita entidades aleatorias N, N generar números aleatorios entre 1 y cualquiera que sea el último ID que ha generado era (su IdGenerator sabrá esto). A continuación, puede hacer llegar un lote de clave utilizando las teclas N, que sólo requieren un viaje al almacén de datos, y será más rápido que una consulta así, ya que el pulsador hace son generalmente más rápido que las consultas, que yo sepa.

Este método requiere tratar con algunos detalles molestos:

  1. Su IdGenerator podría convertirse en un cuello de botella cuando se inserta un montón de estos elementos sobre la marcha (más de uno por segundo), lo que requeriría algún tipo de aplicación IdGenerator fragmentada. Si está precargado todos estos datos, o no es alto volumen, lo tienes fácil.
  2. Usted puede encontrar que alguna identificación no tiene realmente una entidad asociada a ella más, porque lo eliminó o porque un put () falló en alguna parte. Si esto ocurriera tendría que agarrar otra entidad azar. (Si desea conseguir la suposición y reducir las probabilidades de que esto se podría poner a disposición este ID para el IdGenerator reutilizar para "rellenar los huecos")

Así que la pregunta se reduce a la rapidez con que necesita estos artículos N vs frecuencia con la que va a agregar y eliminar ellos, y si un poco de complejidad extra vale la pena que aumenta el rendimiento.

Parece que el único método es mediante el almacenamiento del valor entero aleatorio en propiedad especial de cada entidad y consultar al respecto. Esto se puede hacer muy automáticamente si acaba de añadir una propiedad inicializado automáticamente.

Por desgracia, esto requerirá el procesamiento de todas las entidades una vez si su almacén de datos ya está lleno de.

Es raro, lo sé.

Estoy de acuerdo con la respuesta de Steve, no hay tal manera de recuperar N filas al azar en una consulta.

Sin embargo, incluso el método de recuperación de una sola entidad no suele funcionar de tal manera que la prbability de los resultados devueltos se distribuye uniformemente. La probabilidad de volver una entidad dada depende de la brecha de su número y el siguiente número aleatorio más alto asignado al azar. P.ej. si los números aleatorios 1,2, y 10 han sido asignados (y ninguno de los números 3-9), el algoritmo volverán "2" 8 veces más a menudo que "1".

he fijado esto de una manera un poco más caros comparados. Si alguien está interesado, estoy feliz de compartir

Sólo tenía el mismo problema. Me decidido no asignar identificadores a mis entradas ya existentes en el almacén de datos e hizo esto, como ya tenía el totalCount de un contador fragmentada.

Esto selecciona entradas "recuento" de entradas "totalCount", ordenados por clave .

    # select $count from the complete set
    numberlist = random.sample(range(0,totalcount),count)
    numberlist.sort()

    pagesize=1000

    #initbuckets
    buckets = [ [] for i in xrange(int(max(numberlist)/pagesize)+1) ]
    for k in numberlist:
        thisb = int(k/pagesize)
        buckets[thisb].append(k-(thisb*pagesize))
    logging.debug("Numbers: %s. Buckets %s",numberlist,buckets)

    #page through results.

    result = []
    baseq =  db.Query(MyEntries,keys_only=True).order("__key__")
    for b,l in enumerate(buckets):
        if len(l) > 0: 
            result += [ wq.fetch(limit=1,offset=e)[0] for e in l ]

        if b < len(buckets)-1: # not the last bucket
            lastkey  = wq.fetch(1,pagesize-1)[0]
            wq = baseq.filter("__key__ >",lastkey)

Tenga en cuenta que esto para mí es algo complejo, y todavía no estoy conviced que no tiene errores off-by-one o off-by-x.

Y ten en cuenta que si el recuento está cerca de totalCount esto puede ser muy costoso. Y ten en cuenta que en millones de filas puede que no sea posible hacerlo dentro de los límites de tiempo de App Engine.

Si he entendido bien, es necesario recuperar N instancia aleatoria.

Es fácil. Eso sí, consultar solo con llave. Y hacer random.choice N veces en la lista de resultados de llaves. A continuación, obtener resultados por ir a buscar en las teclas.

keys = MyModel.all(keys_only=True)

n = 5 # 5 random instance

all_keys = list(keys)
result_keys = []

for _ in range(0,n) 
    key = random.choice(all_keys)
    all_keys.remove(key)
    result_keys.append(key)

# result_keys now contain 5 random keys.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top