Modelo de datos de Cassandra para una aplicación de mensajería simple

Estoy tratando de aprender Cassandra y siempre encuentro que la mejor manera es comenzar creando una aplicación muy simple y pequeña. Por lo tanto, estoy creando una aplicación de mensajería básica que utilizará Cassandra como back-end. Me gustaría hacer lo siguiente:

El usuario creará una cuenta con un nombre de usuario, correo electrónico y contraseña. El correo electrónico y la contraseña se pueden cambiar en cualquier momento.El usuario puede agregar otro usuario como su contacto. El usuario agregaría un contacto buscando su nombre de usuario o correo electrónico. No es necesario que los contactos tengan un significado mutuo si agrego un usuario que es mi contacto, no necesito esperar a que acepten / aprueben algo como en Facebook.Se envía un mensaje de un usuario a otro usuario. El remitente debe poder ver los mensajes que envió (ordenados por tiempo) y los mensajes que se les enviaron (ordenados por tiempo). Cuando un usuario abre la aplicación, necesito revisar la base de datos para ver si hay mensajes nuevos para ese usuario. También necesito marcar si el mensaje ha sido leído.

Como vengo del mundo de las bases de datos relacionales, mi base de datos relacional se vería así:

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)

Leyendo un par de libros de texto de Cassandra, pensé en cómo modelar la base de datos. Mi principal preocupación es modelar la base de datos de una manera muy eficiente. Por lo tanto, estoy tratando de evitar cosas como índices secundarios, etc. Este es mi modelo hasta ahora:

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
)

Para difundir los datos de manera uniforme y leer una cantidad mínima de particiones (con suerte solo una), puedo buscar un usuario en función de su nombre de usuario o correo electrónico rápidamente. La desventaja de esto es que obviamente estoy duplicando mis datos, pero el costo de almacenamiento es bastante barato, así que considero que es una buena compensación en lugar de usar índices secundarios. El último inicio de sesión también deberá escribirse dos veces, pero Cassandra es eficiente en las escrituras, por lo que creo que esta también es una buena compensación.

Para los contactos no se me ocurre otra forma de modelar esto, así que lo modelé de manera muy similar a como lo haría en una base de datos relacional. Este es un diseño bastante desnormalizado que creo que debería ser bueno para el rendimiento de acuerdo con los libros que he leído.

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")
);

Estoy atrapado en cómo crear esta próxima parte. Para los mensajes, pensaba en esta tabla, ya que creaba filas anchas que permitían ordenar los mensajes. Necesito mensajes para responder dos preguntas. Primero debe poder mostrarle al usuario todos los mensajes que tiene y también mostrarle al usuario los mensajes nuevos y no leídos. Este es un modelo básico, pero no estoy seguro de cómo hacerlo más eficiente.

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);

También estaba buscando usar cosas como columnas ESTÁTICAS para 'pegar' al usuario y los mensajes, así como SETS para almacenar relaciones de contacto, pero desde mi comprensión hasta ahora, la forma en que presenté es más eficiente. Pregunto si hay alguna idea para mejorar la eficiencia de este modelo, si hay mejores prácticas para hacer las cosas que estoy tratando de hacer, o si hay algún problema oculto que pueda enfrentar con este diseño.

En conclusión, estoy tratando de modelar alrededor de las consultas. Si estuviera usando bases de datos de relaciones, estas serían esencialmente las consultas que estoy buscando responder:

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];

Salud

Respuestas a la pregunta(2)

Su respuesta a la pregunta