GAE - ¿Cómo vivir sin unir?
-
22-07-2019 - |
Pregunta
Problema de ejemplo:
Entidades:
- El usuario contiene el nombre y una lista de amigos (referencias de usuario)
- La publicación del blog contiene título, contenido, fecha y escritor (usuario)
Requisito:
Quiero una página que muestre el título y un enlace al blog de las últimas 10 publicaciones del amigo de un usuario. También me gustaría la posibilidad de seguir buscando en las entradas más antiguas.
Solución SQL:
Entonces, en tierra sql sería algo así como:
select * from blog_post where user_id in (select friend_id from user_friend where user_id = :userId) order by date
Las soluciones GAE que se me ocurren son:
- Cargar usuario, recorrer la lista de amigos y cargar sus últimas publicaciones de blog. Finalmente, combine todas las publicaciones de blog para encontrar las últimas 10 entradas de blog
- En una publicación de blog, tenga una lista de todos los usuarios que tienen al escritor como amigo. Esto significaría una lectura simple pero daría lugar a una sobrecarga de cuotas al agregar un amigo que tiene muchas publicaciones en el blog.
No creo que ninguna de estas soluciones vaya a escalar.
Estoy seguro de que otros han tenido este problema, pero he buscado, visto videos de google io, leí el código de otros ... ¿Qué me estoy perdiendo?
Solución 2
Este tema se trata en una charla io de Google: http://code.google.com/events/io/sessions/BuildingScalableComplexApps. html
Básicamente, el equipo de Google sugiere utilizar las propiedades de la lista y lo que llaman entidades de índice relacional, aquí se puede encontrar una aplicación de ejemplo: http://pubsub-test.appspot.com/
Otros consejos
Si observa cómo se ejecutará la solución SQL que proporcionó, básicamente será así:
- Obtener una lista de amigos para el usuario actual
- Para cada usuario en la lista, inicie un análisis de índice de publicaciones recientes
- Combinar y unir todos los escaneos del paso 2, deteniéndose cuando haya recuperado suficientes entradas
Puede realizar exactamente el mismo procedimiento en App Engine, utilizando las instancias de consulta como iteradores y uniendo una combinación sobre ellas.
Tiene razón en que esto no escalará bien a un gran número de amigos, pero sufre exactamente los mismos problemas que tiene la implementación de SQL, simplemente no los disfraza también: Recuperando los últimos 20 (por ejemplo) las entradas cuestan aproximadamente O (n log n) trabajo, donde n es el número de amigos.
" Cargar usuario, recorrer la lista de amigos y cargar sus últimas publicaciones en el blog. "
Eso es todo lo que una unión es: bucles anidados. Algunos tipos de combinaciones son bucles con búsquedas. La mayoría de las búsquedas son solo bucles; algunos son hashes.
" Finalmente, combine todas las publicaciones del blog para encontrar las últimas 10 entradas de blog "
Eso es un ORDENADO CON un LÍMITE Eso es lo que la base de datos está haciendo por usted.
No estoy seguro de qué no es escalable sobre esto; es lo que hace una base de datos de todos modos.
Aquí hay un ejemplo en python obtenido de http://pubsub-test.appspot.com/:
¿Alguien tiene uno para Java? Gracias.
from google.appengine.ext import webapp
from google.appengine.ext import db
class Message(db.Model):
body = db.TextProperty(required=True)
sender = db.StringProperty(required=True)
receiver_id = db.ListProperty(int)
class SlimMessage(db.Model):
body = db.TextProperty(required=True)
sender = db.StringProperty(required=True)
class MessageIndex(db.Model):
receiver_id = db.ListProperty(int)
class MainHandler(webapp.RequestHandler):
def get(self):
receiver_id = int(self.request.get('receiver_id', '1'))
key_only = self.request.get('key_only').lower() == 'on'
if receiver_id:
if key_only:
keys = db.GqlQuery(
'SELECT __key__ FROM MessageIndex WHERE receiver_id = :1',
receiver_id).fetch(10)
messages.extend(db.get([k.parent() for k in keys]))
else:
messages.extend(Message.gql('WHERE receiver_id = :1',
receiver_id).fetch(10))