2015-09-08 41 views
15

我想学习Cassandra并始终找到最好的方法是从创建一个非常简单和小型的应用程序开始。因此,我正在创建一个将使用Cassandra作为后端的基本消息应用程序。我想要做以下事情:Cassandra简单消息传递应用程序的数据模型

  • 用户将使用用户名,电子邮件和密码创建一个帐户。 电子邮件和密码可随时更改。
  • 用户可以添加另一个用户作为他们的联系人。用户将通过搜索他们的用户名或电子邮件添加一个 联系人。如果我添加一个用户他们是我的联系人,我不需要 是相互含义,我不需要 等待他们接受/批准任何类似于Facebook中的内容。
  • 消息从一个用户发送到另一个用户。发送者需要 能够看到他们发送的消息(按时间排序)和发送给他们的消息(按时间顺序排列)。当用户打开 我需要检查数据库中是否有该用户的任何新消息。我还需要标记消息是否已被读取。

由于我来自关系数据库的世界我的关系型数据库将是这个样子:

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) 

通过一对夫妇卡桑德拉教科书我对如何数据库建模思想的解读。我主要关心的是以非常有效的方式对数据库进行建模。因此,我试图避免的东西,如二级指标等,这是我的模型至今:

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 
) 

要均匀地分布数据和读取分区的最小量(希望只有一个)我可以查找基于用户快速输入用户名或电子邮件这样做的缺点显然是我的数据翻倍,但是存储成本相当便宜,所以我觉得这是一个很好的折衷,而不是使用二级索引。上次登录也需要两次写入,但Cassandra在写入时非常有效,所以我相信这是一个很好的折衷方案。

对于联系人,我想不出任何其他方式来模拟这个模型,所以我将它与我在关系数据库中的模型非常类似。这是相当不规范的设计,我相信,根据我读过的书籍,这应该对性能有好处?

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

我被困在如何创建下一部分。对于消息传递,我正在考虑这张表,因为它创建了宽行,从而可以对消息进行排序。 我需要消息来回答两个问题。它首先需要能够向用户显示他们拥有的所有消息,并且能够向用户显示新消息并且未读的消息 。这是一个基本模型,但我不确定如何使它更有效率?

​​

我也考虑使用的东西,比如静态列“粘”在一起,用户和消息,以及设置为存储联系人的关系,但是从我的狭隘理解到目前为止,我所呈现的方式是更高效。我问是否有任何想法可以改善这种模式的效率,如果有更好的做法做我正在尝试做的事情,或者如果我可以用这种设计来解决任何隐藏的问题?

总之,我试图对查询进行建模。如果我使用关系数据库,这些将基本上是我期待的查询回答:

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

干杯

回答

12

是它总是以适应卡桑德拉从关系型数据库背景的人当限制的斗争。由于我们还没有在Cassandra中进行加入的奢侈,所以您通常希望尽可能多地将其填入单个表格中。在你的情况下,这将是users_by_username表。

卡桑德拉有几个特点可以让你做到这一点。

由于您是Cassandra的新手,您可能可以使用目前处于测试版的Cassandra 3.0。在3.0中有一个很好的功能称为物化视图。这将允许您将users_by_username作为基表,并将用户_by_email创建为物化视图。然后Cassandra会在您更新基表时自动更新视图。

另一个可以帮助你的功能是用户定义的类型(在C * 2.1及更高版本中)。您不必为追随者和消息创建单独的表,您可以创建UDT的结构,然后在用户表中保留这些类型的列表。 (我没有展示一些像时间戳这样的字段来保持这个简单,但这些很容易添加)。

首先创建UDT的:

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

CREATE TYPE msg (
    from_user text, 
    body text 
); 

接下来,我们创建基表:

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

现在我们创建通过电子邮件分区的物化视图:

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

现在,让我们它的旋转,看看它能做什么。让我们创建一个用户:

INSERT INTO users_by_username (username , email , password) 
    VALUES ('someuser', '[email protected]', 'somepassword'); 

让用户跟随其他用户:

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

让我们向用户发送消息:

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

现在让我们来看看有什么在表:

SELECT * FROM users_by_username ; 

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

现在我们来检查一下我们的物化视图的工作:

SELECT new_messages, old_messages FROM users_by_email WHERE email='[email protected]'; 

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

现在,让我们阅读的电子邮件,并把它放在旧邮件:

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='[email protected]'; 

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

所以希望给你一些想法,你可以使用。查看关于集合(即列表,地图和集合)的文档,因为这些文档可以帮助您将更多信息保存在一张表中,并且有点像表格中的表格。

3

对于卡桑德拉或NoSQL数据建模初学者,有参与数据建模应用程序中的过程,就像

1-了解您的数据,设计的概念图
2-列表详细
所有奎雷斯3-使用定义的规则和模式映射您的查询,最适合cassandra
4-创建一个逻辑设计,包含来自查询的字段的表格
5-现在创建一个模式并测试其接受度。

如果我们对它进行良好的建模,那么很容易处理诸如新的复杂查询,数据过载,数据一致性setc等问题。

采取这个免费的在线数据建模培训后,您将获得更清晰

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

祝您好运!

相关问题