6

¿Hay alguna manera inteligente de evitar hacer una consulta costosa con una cláusula IN en casos como el siguiente?Minimizar subconsultas con consultas IN en App Engine (python)

Estoy usando Google App Engine para construir una aplicación de Facebook y en algún momento (obviamente) necesito consultar el almacén de datos para obtener todas las entidades que pertenecen a cualquiera de los amigos de Facebook del usuario dado.

Supongamos que tengo un par de entidades modelada como tal:

class Thing(db.Model): 
    owner = db.ReferenceProperty(reference_class=User, required=True) 
    owner_id = db.StringProperty(required=True) 
    ... 

y

class User(db.Model): 
    id = db.StringProperty(required=True) 
    ... 

En algún momento me consulto Facebook para obtener la lista de amigos de un usuario determinado y necesito realice la siguiente consulta

# get all Thing instances that belong to friends 
query = Thing.all() 
query.filter('owner_id IN', friend_ids) 

Si lo hiciera, AppEngine realizaría una subconsulta para cada i d en friend_ids, probablemente excediendo el número máximo de subconsultas que cualquier consulta puede engendrar (30).

¿Hay alguna forma mejor de hacerlo (es decir, minimizar el número de consultas)? Entiendo que no hay relaciones y uniones utilizando el almacén de datos pero, en particular, consideraría agregar nuevos campos a la clase User o Thing si ayuda a facilitar las cosas.

Respuesta

5

No creo que haya una solución elegante, pero se puede intentar esto:

En el modelo de usuario, utilice el ID de Facebook como el nombre de la clave, y almacenar la lista de las cosas de cada usuario en un ListProperty.

class Thing(db.Model): 
    ... 

class User(db.Model): 
    things = db.ListProperty(db.Key) 
    ... 

creación Entidad iría así:

user = User.get_or_insert(my_facebook_id) 

thing = Thing() 
thing.put() 

user.things.append(thing.key()) 
user.put() 

recuperación tarda 2 consultas:

friends = User.get_by_key_name(friend_ids) 
thing_keys = [] 

for friend in friends: 
    thing_keys.extend(friend.things) 

things = db.get(thing_keys) 
+0

+1 Otra opción es hacer que Things children to User permita que las consultas de ancestros devuelvan un tipo específico de cosa. El uso de key_names es fundamental para que esto realmente funcione. – kevpie

+0

Eso es genial, incluso hice cosas para los niños según lo sugerido por kevpie. Sin embargo, tuve que lidiar con un par de problemas más: a) No guardo una entidad de usuario para cada friend_id, así que necesito filtrar los valores None que obtengo al consultar utilizando get_by_key_name; b) También tengo que filtrar las cosas por otros campos, pero lo hago en las entidades que obtengo después de obtenerlas de DataStore. ¿Hay alguna forma mejor de hacer eso? – abahgat

+0

Asegúrate de ver las conversaciones que Nick publicó en su respuesta. Es posible que desee utilizar una entidad de índice combinada con una propiedad de lista. Esto se muestra en la primera charla publicada por Nick. – kevpie

3

This Google I/O talk por Brett Slatkin aborda la situación exacta que está tratando. Vea también his follow up talk este año.

+0

Me temo que publicó dos veces el mismo enlace a la última charla. ¿Te estabas refiriendo a este? http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html – abahgat

+0

Sí, lo era. Lo siento, solucionado –