2017-03-10 5 views
3

Je suis à la recherche de Cassandra pour un éventuel projet à venir qui, je pense, pourrait convenir. Le seul endroit potentiel où il me bouscule est autour d'une exigence de conservation des données. Fondamentalement, nous avons un schéma comme celui-ci:Fenêtre coulissante TTL à Cassandra

CREATE TABLE Things (
    user_id int 
    thing_id int 
    a text static 
    b text static 
    .... more static fields 
    updated_at timestamp static 


    type text 
    subthing_id int 

    PRIMARY KEY (user_id, thing_id, subthing_id) 
) 

En termes de base de données relationnelle, je dirais qu'une chose appartient à un utilisateur et une chose a beaucoup Subthings. Une chose a diverses sous-choses qui lui sont associées et qui, à un moment ultérieur, feront une nouvelle insertion mettant à jour les champs statiques appropriés. Nous devons stocker chaque chose pendant 30 jours après la dernière fois qu'un subthing a été inséré pour cette chose. Ainsi, par exemple, Thing A et Thing B sont insérés. Une subthing pour Thing B est insérée une semaine plus tard. La chose A est supprimée 30 jours après l'insertion initiale. La chose B (et tous les sous-thèmes associés) sont supprimés 7 jours plus tard. Pour autant que je sache, je ne peux pas simplement insérer avec un TTL puisque j'ai besoin de mettre à jour le TTL des autres lignes partageant le même user_id et thing_id. Je ne suis pas tout à fait sûr de savoir comment exécuter une commande DELETE ici puisque je ne supprime aucune des touches. Je crois que la clé primaire est correcte ici puisque TOUTES les requêtes seront basées sur le user_id (excepté la suppression qui est déterminée par le updated_at).

Mon autre préoccupation est l'idée des pierres tombales. Je n'ai lu qu'à leur sujet, mais le souci ici est que je supprimerais potentiellement des millions de ces choses chaque jour. Cela va-t-il nécessiter un compactage quotidien après les suppressions quotidiennes?

Mise à jour: Une alternative que j'ai pensé depuis l'affichage d'origine avait une deuxième table qui est insérée à chaque fois qu'un subthing est ajouté. Il ressemblerait à ceci:

CREATE TABLE Expirations (
    expiry date 
    user_id int 
    thing_id int 
    PRIMARY KEY (expiry, user_id, thing_id) 
) 

Où est la date d'expiration de la user_id donnée et thing_id à supprimer. Cette table devrait être mise à jour si nécessaire que les choses sont insérées dans la table Things, puis je devrais exécuter quelque chose chaque jour pour rechercher des valeurs où l'expiration est aujourd'hui et itérer sur eux pour supprimer des choses de la table Things. Je ne suis pas sûr si cela est considéré comme le "chemin de Cassandre" mais il semble que cela pourrait fonctionner.

Répondre

1

Ceci est un défi intéressant. J'utiliserais un map data type pour mapper chaque thing_id à tous ses subthing_id s. Je vais quelque chose comme:

CREATE TABLE Things (
    partition_date timestamp, 
    insertion_date timestamp, 
    user_id int, 
    thing_map map<int,int> 
    a text static 
    b text static 
    .... more static fields 
    updated_at timestamp static 


    type text 

    PRIMARY KEY (partition_date, insertion_date, user_id) 
) WITH CLUSTERING ORDER BY (insertion_date DESC) 

Ici, j'inséré un nouveau champ insertion_date qui devrait tenir exactement la date d'insertion, et un nouveau champ partition_date qui devient le nouveau nouveau ne partitionner KEY, qui devrait enregistrer une troncature de la insertion_date champ, juste pour éviter certains hotspots (je suppose que cela peut simplement demander en fonction d'un champ de jour en raison de vos exigences de TTL, si vous avez besoin de requête sur le champ user_id les choses sont un peu différentes). J'ai récemment répondu à des questions similaires sur ce problème de modélisation here et here, alors jetez un oeil à ceux-ci pour obtenir plus d'informations sur la technique utilisée (il est appelé seau). Ensuite, il ya le thing_map qui est le noyau de votre problème. Pousser un nouvel objet dans la carte devrait réinitialiser le TTL pour cette carte entièrement, de sorte que vous pourriez avoir exactement le comportement désiré. Notez que le TTL supprimera le champ seulement, pas la ligne entière, vous aurez simplement besoin de tester si elle est nulle ou non.Enfin, le comportement de la pierre tombale est un problème auquel vous devrez faire face. Si vous pouvez vous permettre une réécriture complète des lignes, au lieu de mettre à jour uniquement le champ map, vous augmentez toutes les lignes à la fois, vous obtiendrez une suppression au niveau de la partition et les "séries temporelles inversées" modélisées avec la clé de clustering devrait prendre soin de cela sans trop de problèmes.

+0

Merci pour la réponse! J'ai quelques questions à ce sujet cependant. Je suis donc sûr que user_id devra être la clé de partition si chaque requête sera basée sur l'identifiant de l'utilisateur. La date peut être incluse dans ces requêtes, mais elle est facultative. La seule heure à laquelle la date serait utilisée et le user_id n'est pas utilisé est dans la requête pour supprimer les choses expirées. Je suppose que ce qui revient à ce qu'il vaut mieux avoir les commandes DELETE ou SELECT requêtes aussi peu de partitions que possible. Je suis en train de mettre à jour la question originale avec une alternative que je pensais pouvoir travailler aussi ... Faites-moi savoir ce que vous en pensez. –

+0

@ShaneAndrade: Vous pouvez toujours mettre le 'date' ensemble avec le' user_id' pour mieux partitionner vos données. Comme déjà dit, vous pouvez trouver comment faire cela dans les liens que j'ai posté. Notez également que si vous utilisez 'TTL', les données disparaîtront automatiquement *, vous n'avez donc pas besoin d'exécuter' SELECT/DELETE'. Avoir deux tables est une autre alternative viable, mais vous avez 'TTL' ... – xmas79