2011-02-28 53 views
9

Todavía estoy aprendiendo mis lecciones sobre modelado de datos en bigtable/nosql y agradecería algunos comentarios. ¿Sería justo decir que debo evitar las relaciones entre padres e hijos en mi modelado de datos si con frecuencia necesito tratar con los niños en conjunto entre los padres?relaciones padre-> hijo en appengine python (bigtable)

Como ejemplo, digamos que estoy compilando un blog al que contribuirá un número de autores, y cada uno tiene publicaciones, y cada publicación tiene etiquetas. Así que potencialmente podría configurar algo como esto:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

Según tengo entendido, esto creará un grupo de entidades basado en el autor padre. ¿Esto causa ineficacia si la mayoría de las veces necesito consultar las Publicaciones por etiquetas que espero cortar entre varios Autores?

Entiendo que hacer una consulta en las propiedades de la lista puede ser ineficiente. Digamos que cada publicación tiene aproximadamente 3 etiquetas en promedio, pero podría llegar hasta 7. Y espero que mi colección de posibles etiquetas esté en los cientos más bajos. ¿Hay algún beneficio en alterar ese modelo a algo como esto?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.ListProperty(db.Key) 

class Tag(db.Model): 
    name = db.StringProperty() 

O ¿sería mejor hacer algo como esto?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 

class Tag(db.Model): 
    name = db.StringProperty() 

class PostTag(db.Model): 
    post = db.ReferenceProperty(Post, 
    collection_name='posts') 
    tag = db.ReferenceProperty(Tag, 
    collection_name='tags') 

Y la última pregunta ... ¿y si mi caso de uso más común será la consulta de los mensajes de múltiples etiquetas. Por ejemplo, "buscar todas las publicaciones con etiquetas en {'manzanas', 'naranjas', 'pepinos', 'bicicletas'}" Es uno de estos enfoques más apropiado para una consulta que busca publicaciones que tienen una colección de etiquetas ?

Gracias, sé que fue un bocado. :-)

+0

Ninguno de sus ejemplos crea grupos de entidades. En el primer ejemplo, está utilizando una propiedad de referencia, que crea una referencia a la otra entidad; esto es mutable y no implica propiedad. Las referencias principales se crean especificando el argumento "principal" para el constructor de la entidad; consulta esta página para obtener más información: http://code.google.com/appengine/docs/python/datastore/entities.html#Entity_Groups_and_ Ancestro_de_asuntos –

+0

Ah, gracias Nick Me faltaba esa parte ... pensé que eran las referencias las que creaban la relación principal y faltaba que necesitaras pasar el padre al constructor. Eso tiene sentido ahora. –

Respuesta

5

Algo parecido al primero o al segundo enfoque son adecuados para App Engine.Considere la siguiente configuración:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    author = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

class Tag(db.Model): 
    post_count = db.IntegerProperty() 

Si utiliza la etiqueta de cadena (caso-normalizada) como el nombre_tecla entidad etiqueta, puede consultar de manera eficiente para mensajes con una etiqueta específica, o una lista de las etiquetas de un poste, o ir a buscar estadísticas de la etiqueta:

post = Post(author=some_author, tags=['app-engine', 'google', 'python']) 
post_key = post.put() 
# call some method to increment post counts... 
increment_tag_post_counts(post_key) 

# get posts with a given tag: 
matching_posts = Post.all().filter('tags =', 'google').fetch(100) 
# or, two tags: 
matching_posts = Post.all().filter('tags =', 'google').filter('tags =', 'python').fetch(100) 

# get tag list from a post: 
tag_stats = Tag.get_by_key_name(post.tags) 

El tercer enfoque requiere consultas adicionales o va a buscar para la mayoría de las operaciones básicas, y es más difícil si se desea consultar para varias variables.

+0

impresionante, gracias Robert. así es como lo tengo escrito. pero todavía soy nuevo, así que no estaba seguro de si esta era realmente la mejor manera, ¡así que te agradezco que compartas tu experiencia! –

+1

@Bob Ralian, hay algo de lo que hay que preocuparse son los índices explosivos. El concepto general es bueno; es posible que también encuentre útil el patrón "Índice de relaciones", pero como su lista es muy pequeña _y_ desea las etiquetas, no necesita una entidad separada. (http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html) –

2

Elegiría el último enfoque, porque permite recuperar una lista de publicaciones directamente con una etiqueta.

El primer enfoque básicamente hace que sea imposible mantener un conjunto canónico de etiquetas. En otras palabras, la pregunta "qué etiquetas están actualmente presentes en el sistema" es muy costosa de responder.

El segundo enfoque soluciona ese problema, pero como mencioné anteriormente no lo ayuda a recuperar publicaciones con una etiqueta.

Los grupos de entidades son un poco de una misteriosa bestia, pero basta con decir que el primer enfoque no crear un grupo de entidades, y que sólo son necesaria para las operaciones de bases de datos transaccionales, ya veces útil para optimizar las lecturas de datos, pero probablemente no sean necesarios en una aplicación pequeña.

Cabe mencionar que cualquier enfoque que tome solo funcionará bien junto con una estrategia de almacenamiento en caché inteligente. Las aplicaciones de GAE AMAN el almacenamiento en caché. Intégrese con la API de Memcache y aprenda las operaciones de lectura/escritura en bloque en Memcache y el almacén de datos.

+0

Gracias Tríptico. En realidad, no me preocupa el problema canónico, ya que lo manejaré durante la validación antes de guardar. Re: grupos de entidades, los documentos dicen "Para crear una entidad en un grupo, declaras que otra entidad es el padre de la nueva entidad cuando la creas". De modo que considero que una relación padre-hijo creará un grupo de entidades si se declara en el niño en el momento en que se crea. Entiendo que el objetivo de los grupos de entidades es para las transacciones. ¿Pero causan latencia/ineficiencia para selecciones en todos los grupos de entidades? ¿Son posibles las transacciones entre grupos? –

+0

Las transacciones de grupos cruzados no son posibles, pero si está haciendo muchas selecciones entre grupos de entidades, eso es una indicación suave de que no debería usarlas de todos modos. Además, comprenda que su proceso de validación requerirá leer cada etiqueta en cada modelo de publicación en la tienda de datos, si usa el primer enfoque. – Triptych

+0

Tendré un modelo de Etiqueta por separado independientemente. Y los mantendré en Memcache. El primer enfoque simplemente no estaba vinculado con ellos, sino que los usaría para dictar cadenas aceptables. No es necesariamente apropiado para Publicaciones donde seleccionaría por etiqueta, pero sería más apropiado para algo como las preferencias de Reader, donde solo tengo que sacar la lista de etiquetas. –

Cuestiones relacionadas