Modèle de données Cassandra pour l'application de messagerie simple

j'essaie D'apprendre Cassandra et toujours trouver le meilleur moyen est de commencer par créer une application très simple et petite. Par conséquent, je crée une application de messagerie de base qui utilisera Cassandra comme back-end. Je voudrais faire la chose suivante:

  • L'utilisateur va créer un compte avec un nom d'utilisateur, email, et mot de passe. Le le courriel et le mot de passe peuvent être modifiés à tout moment.
  • L'utilisateur peut ajouter un autre utilisateur que leur contact. L'utilisateur ajouterait un contacter en cherchant leur nom d'utilisateur ou e-mail. Les contacts n'ont pas besoin pour être sens commun si j'ajoute un utilisateur ils sont mon contact, Je ne besoin d'attendre qu'ils acceptent/approuvent quelque chose comme dans Facebook.
  • un message est envoyé d'un utilisateur à un autre. L'expéditeur doit être capable de voir les messages qu'ils ont envoyés (ordonnés par le temps) et le les messages qui leur ont été envoyés (ordonnés par le temps). Lorsqu'un utilisateur ouvre l'application que je dois vérifier la base de données pour tous les nouveaux messages pour cela utilisateur. J'ai aussi besoin de pour marquer si le message a été lu.

comme je viens du monde des bases de données relationnelles, ma base de données relationnelles ressemblerait à quelque chose comme ceci:

UsersTable
    username (text)
    email (text)
    password (text)
    time_created (timestamp)
    last_loggedIn (timestamp)
------------------------------------------------ 
ContactsTable
    user_i_added (text)
    user_added_me (text)
------------------------------------------------     
MessagesTable
    from_user (text)
    to_user (text)
    msg_body (text)
    metadata (text)
    has_been_read (boolean)
    message_sent_time (timestamp)

en lisant quelques manuels de Cassandra, j'ai une idée de comment modéliser la base de données. Ma principale préoccupation est de modéliser la base de données de manière très efficace. Donc j'essaie d'éviter les choses comme les index secondaires etc. C'est mon modèle jusqu'à présent:

CREATE TABLE users_by_username (
    username text PRIMARY KEY,
    email text,
    password text
    timeCreated timestamp
    last_loggedin timestamp
)

CREATE TABLE users_by_email (
    email text PRIMARY KEY,
    username text,
    password text
    timeCreated timestamp
    last_loggedin timestamp
)

pour étaler les données de façon uniforme et pour lire un nombre minimal de partitions (avec un peu de chance juste une) je peux rechercher un utilisateur basé sur leur nom d'utilisateur ou email rapidement. L'inconvénient est évidemment que je double mes données, mais le coût de stockage est assez bon marché, donc je trouve que c'est un bon compromis au lieu d'utiliser des indices secondaires. La Dernière connexion devra également être écrite deux fois mais Cassandra est efficace à écrit donc je crois que c'est un bon compromis aussi bien.

pour les contacts Je ne peux pas penser à une autre façon de modéliser ceci donc je l'ai modélisé très similaire à ce que je ferais dans une base de données relationnelle. C'est tout à fait un design dénormalisé que je crois qui devrait être bon pour la performance selon les livres que j'ai lus?

CREATE TABLE "user_follows" (
  follower_username text,
  followed_username text,
  timeCreated timestamp, 
  PRIMARY KEY ("follower_username", "followed_username")
);

CREATE TABLE "user_followedBy" (

  followed_username text,
  follower_username text,
  timeCreated timestamp,
  PRIMARY KEY ("followed_username", "follower_username")
);

je suis bloqué sur la façon de créer cette partie suivante. Pour la messagerie, je pensais à cette table car elle a créé de grandes lignes qui permet l'ordre des messages. J'ai besoin d'un message pour répondre à deux questions. Il doit d'abord être en mesure de montrer à l'utilisateur tous les messages qu'ils ont et être également en mesure de montrer l'utilisateur les messages qui sont nouvelles et non lus. Il s'agit d'un modèle de base, mais ne savez-vous pas comment le rendre plus efficace?

CREATE TABLE messages (
    message_id uuid,
    from_user text,
    to_user text,
    body text,
    hasRead boolean,
    timeCreated timeuuid,
    PRIMARY KEY ((to_user), timeCreated )
) WITH CLUSTERING ORDER BY (timeCreated ASC);

je cherchais aussi à utiliser des choses comme des colonnes statiques pour "coller" ensemble l'utilisateur et les messages, ainsi que des ensembles pour stocker les relations de contact, mais de ma compréhension étroite jusqu'ici la façon dont je me suis présenté est plus efficace. Je me demande s'il y a des idées pour améliorer l'efficacité de ce modèle, s'il y a de meilleures pratiques des choses que j'essaie de faire, ou s'il y a des problèmes cachés que je peux affronter avec ce design?

en conclusion, j'essaie de modéliser autour des requêtes. Si j'utilisais les bases de données de relation, ce seraient essentiellement les requêtes auxquelles je cherche à répondre:

To Login:
SELECT * FROM USERS WHERE (USERNAME = [MY_USERNAME] OR EMAIL = [MY_EMAIL]) AND PASSWORD = [MY_PASSWORD];
------------------------------------------------------------------------------------------------------------------------
Update user info:
UPDATE USERS (password) SET password = [NEW_PASSWORD] where username = [MY_USERNAME];
UPDATE USERS (email) SET password = [NEW_PASSWORD ] where username = [MY_USERNAME];
------------------------------------------------------------------------------------------------------------------------ 
To Add contact (If by username):
INSERT INTO followings(following,follower)  VALUES([USERNAME_I_WANT_TO_FOLLOW],[MY_USERNAME]);
------------------------------------------------------------------------------------------------------------------------
To Add contact (If by email):
SELECT username FROM users where email = [CONTACTS_EMAIL];
    Then application layer sends over another query with the username:
INSERT INTO followings(following,follower)  VALUES([USERNAME_I_WANT_TO_FOLLOW],[MY_USERNAME]);
------------------------------------------------------------------------------------------------------------------------
To View contacts:
SELECT following FROM USERS WHERE follower = [MY_USERNAME];
------------------------------------------------------------------------------------------------------------------------
To Send Message:,
INSERT INTO MESSAGES (MSG_ID, FROM, TO, MSG, IS_MSG_NEW) VALUES (uuid, [FROM_USERNAME], [TO_USERNAME], 'MY MSG', true);
------------------------------------------------------------------------------------------------------------------------
To View All Messages (Some pagination type of technique where shows me the 10 recent messages, yet shows which ones are unread):
SELECT * FROM MESSAGES WHERE TO = [MY_USERNAME] LIMIT 10;
------------------------------------------------------------------------------------------------------------------------
Once Message is read:
UPDATE MESSAGES SET IS_MSG_NEW = false WHERE TO = [MY_USERNAME] AND MSG_ID = [MSG_ID];

Cheers

15
demandé sur user2924127 2015-09-08 03:47:43

2 réponses

Oui il est toujours difficile de s'adapter aux limites de Cassandra en venant d'un fond de base de données relationnelle. Comme nous n'avons pas encore le luxe de faire des jointures en Cassandra, vous voulez souvent ramper autant que vous le pouvez dans une seule table. Dans votre cas, ce serait la table users_by_username.

Il ya quelques caractéristiques de Cassandra, qui devraient vous permettre de le faire.

Puisque vous êtes nouveau à Cassandra, vous pourriez probablement utiliser Cassandra 3.0, qui est actuellement en version bêta. Dans 3.0 il y a une belle fonctionnalité appelée vues matérialisées. Cela vous permettrait d'avoir users_by_username comme table de base, et de créer users_by_email comme une vue matérialisée. Alors Cassandra mettra à jour la vue automatiquement chaque fois que vous mettez à jour la table de base.

une autre fonctionnalité qui vous aidera est les types définis par l'utilisateur (en C* 2.1 et suivants). Au lieu de créer des tables séparées pour les suiveurs et les messages, Vous pouvez créer la structure de ceux comme UDT, et puis dans la table d'utilisateur conservent des listes de ces types.

donc une vue simplifiée de votre schéma pourrait être comme ceci (Je ne montre pas certains des champs comme timestamps pour garder cela simple, mais ceux-ci sont faciles à ajouter).

créez D'abord vos UDT:

CREATE TYPE user_follows (
    followed_username text,
    street text,
);

CREATE TYPE msg (
    from_user text,
    body text
);

Ensuite, nous créons votre table de base:

CREATE TABLE users_by_username (
    username text PRIMARY KEY,
    email text,
    password text,
    follows list<frozen<user_follows>>,
    followed_by list<frozen<user_follows>>,
    new_messages list<frozen<msg>>,
    old_messages list<frozen<msg>>
);

maintenant nous créons une vue matérialisée partitionnée par email:

CREATE MATERIALIZED VIEW users_by_email AS
    SELECT username, password, follows, new_messages, old_messages FROM users_by_username
    WHERE email IS NOT NULL AND password IS NOT NULL AND follows IS NOT NULL AND new_messages IS NOT NULL
    PRIMARY KEY (email, username);

Maintenant, prenons-le pour un tour et voyons ce qu'il peut faire. Nous allons créer un utilisateur:

INSERT INTO users_by_username (username , email , password )
    VALUES ( 'someuser', 'someemail@abc.com', 'somepassword');

permettre à l'utilisateur de suivre un autre utilisateur:

UPDATE users_by_username SET follows = [{followed_username: 'followme2', street: 'mystreet2'}] + follows
    WHERE username = 'someuser';

envoyons un message à l'utilisateur:

UPDATE users_by_username SET new_messages = [{from_user: 'auser', body: 'hi someuser!'}] + new_messages
    WHERE username = 'someuser';

voyons maintenant ce qu'il y a dans le tableau:

SELECT * FROM users_by_username ;

 username | email             | followed_by | follows                                                 | new_messages                                 | old_messages | password
----------+-------------------+-------------+---------------------------------------------------------+----------------------------------------------+--------------+--------------
 someuser | someemail@abc.com |        null | [{followed_username: 'followme2', street: 'mystreet2'}] | [{from_user: 'auser', body: 'hi someuser!'}] |         null | somepassword

maintenant vérifions que notre vue matérialisée fonctionne:

SELECT new_messages, old_messages FROM users_by_email WHERE email='someemail@abc.com'; 

 new_messages                                 | old_messages
----------------------------------------------+--------------
 [{from_user: 'auser', body: 'hi someuser!'}] |         null

maintenant, lisons l'email et mettons-le dans les anciens messages:

BEGIN BATCH
    DELETE new_messages[0] FROM users_by_username WHERE username='someuser'
    UPDATE users_by_username SET old_messages = [{from_user: 'auser', body: 'hi someuser!'}] + old_messages where username = 'someuser'
APPLY BATCH;

 SELECT new_messages, old_messages FROM users_by_email WHERE email='someemail@abc.com';

 new_messages | old_messages
--------------+----------------------------------------------
         null | [{from_user: 'auser', body: 'hi someuser!'}]

nous espérons que cela vous donnera quelques idées que vous pouvez utiliser. Jetez un oeil à la documentation sur collections (listes, des cartes et ensembles), puisque ceux-ci peuvent vraiment vous aider à garder plus d'informations dans un tableau et sont un peu comme les tableaux dans un tableau.

12
répondu Jim Meyer 2015-09-10 10:36:45

pour les débutants en modélisation de données de cassandra ou noSQL, il existe un processus de modélisation de données de votre application, comme

1 - Comprendre vos données, concevoir un diagramme de concept

2-listez toutes vos questions en détail

3 - Carte vos requêtes à l'aide des règles bien définies et modèles, le mieux adapté pour cassandra

4-Créer un design logique, une table avec des champs dérivés de requêtes

5-maintenant créer un schéma et tester son acceptation.

si nous le modélisons bien, alors il est facile de traiter des questions telles que les nouvelles requêtes complexes, le chargement de données, la cohérence des données setc.

après avoir pris cette formation gratuite de modélisation de données en ligne, vous obtiendrez plus de clarté

https://academy.datastax.com/courses/ds220-data-modeling

Bonne Chance!

3
répondu Swam Guru 2015-09-13 18:28:28