2010-10-24 25 views
0

Il s'agit d'une question générale sur la pagination avec des modèles contenant plusieurs index d'entité. C'est plus facile avec un exemple, prenons l'exemple que Brett Slatkin a fourni dans sa vidéo (http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html).Pagination et index d'entités relationnelles multiples avec AppEngine

Vous avez votre modèle de message (j'ai ignoré le modèle MessageIndex) et j'ai également ajouté deux propriétés supplémentaires (pour les délais de publication et d'expiration). Maintenant, je suis intéressé à faire des filtres sur plusieurs champs, disons des messages publiés dans une fenêtre de temps particulière. par exemple

select * from Message where pubished > some_date and expires < some_other_date 

Depuis GAE ne permet pas de filtres d'inégalité sur plusieurs domaines, nous devons décomposer les modèles en indices supplémentaires. Nous avons donc maintenant un index pour les publiés et arrive à échéance des champs, nous donnant les modèles suivants (avec une instance de message étant le parent des instances MessagePublishedIndex et MessageExpiryIndex):

class Message(db.Model): 
    sender = db.StringProperty() 
    body = db.TextProperty() 

class MessagePublishedIndex(db.Model): 
    published = db.DateTimeProperty() 

class MessageExpiryIndex(db.Model): 
    expires = db.DateTimeProperty() 

et les requêtes key_only suivantes:

publish_keys = MessagePublishedIndex.all(key_only = True).filter("published >", some_date) 
expire_keys = MessageExpiryIndex.all(key_only = True).filter("expires <", some_other_date) 

msgs_by_pubdate = db.get([k.parent() for k in publish_keys]) 
msgs_by_expiry = db.get([k.parent() for k in expire_keys]) 

Maintenant, il doit faire une intersection de ces listes pour trouver les communes pour obtenir tous les messages dans une fenêtre de temps particulière.

Cela semble plutôt inutile. Y a-t-il un moyen plus facile de faire cela? Ce problème est également exacerbé si le champ dans l'index est ListProperty car les requêtes key_only ne peuvent pas avoir de filtres "IN". Et pire encore, si je veux une pagination (c.-à-d. Que le "compte" résulte d'un "décalage"), il faut supprimer manuellement les premiers résultats de "décalage" et ensuite faire une intersection. Il doit sûrement y avoir une façon plus facile (et plus intelligente) de le faire. Des idées? Il est assez mauvais que GAE n'autorise pas les filtres d'inégalité sur plusieurs champs (quoique pour des raisons d'efficacité), mais avoir à faire manuellement tous les zig-zags nous semble assez inefficace (sans parler du fonctionnement des cpu et des limites de temps).

+0

Je ne comprends pas complètement la question. Peut-être que les échantillons de code ont été mélangés? – max

+0

Désolé à ce sujet. Mon message a en quelque sorte été "coupé", j'ai donc retapé les morceaux qui ont été perdus. – Sri

Répondre

0

Dans votre scénario, je créerais un seul indice Relational Entité

class MessageIndex(db.Model): 
    keywords = db.StringListProperty(); 

où chaque élément dans la liste des mots-clés serait dans le format < propriété> = valeur <>

par exemple: mots-clés = ["published = 2011-03-24", "expires = 2011-03-25"]

Vous devrez effectuer une sérialisation/désérialisation vous-même pour obtenir la valeur de la propriété. Vous pouvez également stocker des valeurs de propriété dans le modèle Message uniquement pour la redondance. Cependant, l'approche ne fonctionne pas avec la requête de plage. (Je n'ai pas testé mais vous pouvez probablement utiliser la requête avec le préfixe pour fausse plage requête: u "publié = 2010" + u "\ ufffd", here is more details)

Il a toujours été un défi d'optimiser pour GAE. Mais c'est amusant et enrichissant.