2010-11-25 25 views
5

J'ai beaucoup de messages (par exemple), marqués d'un ou de plusieurs tags. La publication peut être créée ou supprimée, et l'utilisateur peut également faire une requête de recherche pour une ou plusieurs étiquettes (combinées avec AND logique). idée d'abord qui est venu à mon esprit était un modèle simpleTags très évolutifs sur Google App Engine (Python)

class Post(db.Model): 
    #blahblah 
    tags = db.StringListProperty() 

Mise en oeuvre de créer et supprimer des opérations est évidente. La recherche est plus complexe. Pour rechercher N tags, il fera N requêtes NQL comme "SELECT * FROM Post WHERE tags =: 1" et fusionner les résultats en utilisant les curseurs, et il a des performances terribles.

idée deuxième consiste à séparer les tags dans les différentes entités

class Post(db.Model): 
    #blahblah 
    tags = db.ListProperty(db.Key) # For fast access 

class Tag(db.Model): 
    name = db.StringProperty(name="key") 
    posts = db.ListProperty(db.Key) # List of posts that marked with tag 

Il faut Balises de db par clé (beaucoup plus rapide que de prendre par GQL) et fusionner en mémoire, je pense que cette mise en œuvre a une meilleure performance que le premier, mais très souvent, les balises utilisables peuvent dépasser la taille maximale autorisée pour un seul objet de banque de données. Et il y a un autre problème: le magasin de données peut modifier un seul objet seulement ~ 1/sec, donc pour les balises fréquemment utilisables, nous avons également un goulot d'étranglement avec la latence de modification.

Des suggestions?

Répondre

0

Probablement une solution possible est de prendre votre deuxième exemple, et le modifier d'une manière qui permettrait des requêtes efficaces sur les plus grands ensembles. Une façon qui vient à l'esprit est d'utiliser plusieurs entités de base de données pour une seule étiquette, et les regrouper de telle sorte que vous auriez rarement besoin de plus de quelques groupes. Si l'ordre de tri par défaut (bien, nous l'appelons le seul autorisé) est par post-date, alors remplissez les entités du groupe de balises dans cet ordre.

class Tag(db.Model): 
    name = db.StringProperty(name="key") 
    posts = db.ListProperty(db.Key) # List of posts that marked with tag 
    firstpost = db.DateTimeProperty() 

Lors de l'ajout ou la suppression des balises à un groupe, vérifiez combien de postes sont dans ce groupe, si le poste que vous ajoutez ferait le poste ont plus que, disons 100 postes, il divisé en deux tag groupes. Si vous supprimez un post pour que le groupe contienne moins de 50 messages, dérobez des messages d'un groupe précédent ou suivant. Si l'un des groupes adjacents a également 50 messages, il suffit de les fusionner ensemble. Lors de la liste des publications par étiquette (dans l'ordre après la date), vous n'avez besoin que d'une poignée de groupes.

Cela ne résout pas vraiment le problème des étiquettes à forte demande. En pensant à cela, il pourrait être acceptable que les insertions soient un peu plus spéculatives. Obtenez les dernières entrées de groupe de balises, fusionnez-les et placez un nouveau groupe de balises. Le retard dans les transactions pourrait effectivement ne pas être un vrai problème.

+1

Lag dans les transactions peut être résolu en mettant en place un journal pour ajouter des postes. Lorsque poste est mis en file d'attente pour ajouter - il crée un objet spécial avec des informations telles que "Regardez, ce message appartient à cette balise" pour chaque balise (et modifie également la copie memcache des balises), si la copie de memcache est expirée, applier recueille toutes les entrées de journal et l'applique à l'entité de balise dans le magasin de données (et le copie également dans memcache). –