Cassandra Schema的聊天应用程序

Exc*_*ion 9 cql cassandra

我已经删除了这篇文章,这里是我从中获得的模式.这有助于我的应用程序维护用户的状态,但是如何扩展它以维护一对一的聊天存档和用户之间的关系,关系意味着人们属于我的特定组.我是新手,需要一种方法.

要求 :

  • 我想在表中的用户 - 用户之间存储消息.
  • 每当用户想要由用户加载消息时.我想将它们检索回来并发送给用户.
  • 我想在用户请求时检索来自不同用户的所有消息.
  • 而且还想存储一类用户.我的意思是例如user1和user2属于"family"user3,user4,user1属于朋友等...这个组可以是用户给出的自定义名称.

这是我到目前为止所尝试的:

CREATE TABLE chatarchive (
   chat_id uuid PRIMARY KEY,
   username text,
   body text
)

CREATE TABLE chatseries (
username text,
    time timeuuid,
    chat_id uuid,
    PRIMARY KEY (username, time)
) WITH CLUSTERING ORDER BY (time ASC)

CREATE TABLE chattimeline (
    to text,
username text,
    time timeuuid,
    chat_id uuid,
    PRIMARY KEY (username, time)
) WITH CLUSTERING ORDER BY (time ASC)
Run Code Online (Sandbox Code Playgroud)

以下是我目前拥有的架构:

CREATE TABLE users (
   username text PRIMARY KEY,
   password text
)    

CREATE TABLE friends (
    username text,
    friend text,
    since timestamp,
    PRIMARY KEY (username, friend)
)

CREATE TABLE followers (
    username text,
    follower text,
    since timestamp,
    PRIMARY KEY (username, follower)
)

CREATE TABLE tweets (
    tweet_id uuid PRIMARY KEY,
    username text,
    body text
)
CREATE TABLE userline (
    username text,
    time timeuuid,
    tweet_id uuid,
    PRIMARY KEY (username, time)
) WITH CLUSTERING ORDER BY (time DESC)

CREATE TABLE timeline (
    username text,
    time timeuuid,
    tweet_id uuid,
    PRIMARY KEY (username, time)
) WITH CLUSTERING ORDER BY (time DESC)
Run Code Online (Sandbox Code Playgroud)

sub*_*ing 11

使用C*,您需要以您使用它的方式存储数据.那么让我们看看这种情况会是怎样的:

  • 我想在表中的用户 - 用户之间存储消息.
  • 每当用户想要由用户加载消息时.我想将它们检索回来并发送给用户.

    CREATE TABLE chat_messages ( message_id uuid, from_user text, to_user text, body text, class text, time timeuuid, PRIMARY KEY ((from_user, to_user), time) ) WITH CLUSTERING ORDER BY (time ASC);

这将允许您检索两个用户之间的消息时间轴.请注意,使用复合主键,以便为每对用户创建宽行.

SELECT * FROM chat_messages WHERE from_user = 'mike' AND to_user = 'john' ORDER BY time DESC ;

  • 我想在用户请求时检索来自不同用户的所有消息.

CREATE INDEX chat_messages_to_user ON chat_messages (to_user);

这允许你这样做:

SELECT * FROM chat_messages WHERE to_user = 'john';
Run Code Online (Sandbox Code Playgroud)
  • 而且还想存储一类用户.我的意思是例如user1和user2属于"family"user3,user4,user1属于朋友等...这个组可以是用户给出的自定义名称.

CREATE INDEX chat_messages_class ON chat_messages (class);

这将允许您:

SELECT * FROM chat_messages WHERE class = 'family';
Run Code Online (Sandbox Code Playgroud)

请注意,在这种数据库中,异常数据是一种很好的做法.这意味着一次又一次地使用类的名称并不是一个坏习惯.

另请注意,我没有使用'chat_id'或'聊天'表.我们可以很容易地添加这个,但我觉得你的用例并不需要它,因为它已被提出.通常,您不能在C*中进行连接.因此,使用聊天ID会暗示两个查询.

编辑:二级索引效率低下.物化视图将是C*3.0的更好实现

  • 不会索引: CREATE INDEX chat_messages_to_user ON chat_messages (to_user); 随着唯一的用户-用户聊天数量 N 的增加,效率会越来越低。在像 Cassandra 这样的分布式系统上,数据将按 (from_user, to_user) 进行分区,这意味着索引可以引用不同集群中的多个分区。Cassandra 必须从多个分区查询并组合您的请求。如果 N 很小,这不是问题,但是如果 N 很大并且非常分散,它可能会变得效率低下。您可能想要创建一个全新的表并进行非规范化。 (2认同)

Tam*_*Tas 6

Alan Chandler创建了一个聊天应用程序,github它具有您请求的功能:

它使用两阶段身份验证.首先,在论坛中验证用户,然后在聊天数据库上验证用户.

这是架构的第一个验证部分(架构位于inc/user.sql):

BEGIN;

CREATE TABLE users (
  uid integer primary key autoincrement NOT NULL,
  time bigint DEFAULT (strftime('%s','now')) NOT NULL,
  name character varying NOT NULL,
  role text NOT NULL DEFAULT 'R',      -- A (CEO), L (DIRECTOR), G (DEPT HEAD), H (SPONSOR) R(REGULAR)
  cap integer DEFAULT 0 NOT NULL,      -- 1 = blind, 2 = committee secretary, 4 = admin, 8 = mod, 16 = speaker 32 = can't whisper( OR of capabilities).
  password character varying NOT NULL, -- raw password
  rooms character varying,             -- a ":" separated list of rooms nos which define which rooms the user can go in
  isguest boolean DEFAULT 0 NOT NULL
);
CREATE INDEX userindex ON users(name);
-- Below here you can add the specific users for your set up in the form of INSERT Statements

-- This list is test users to cover the complete range of functions. Note names are converted to lowercase, so only put lowercase names in here
INSERT INTO users(uid,name,role,cap,password,rooms,isguest) VALUES
(1,'alice','A',4,'password','7',0),     -- CEO class user alice
(2,'bob','L',3,'password','8',0),       -- DIRECTOR class user bob 
(3,'carol','G',2,'password','7:8:9',0), -- DEPT HEAD class user carol
Run Code Online (Sandbox Code Playgroud)



这是模式的第二个验证部分(模式位于data/chat.sql):

CREATE TABLE users (
  uid integer primary key NOT NULL,
  time bigint DEFAULT (strftime('%s','now')) NOT NULL,
  name character varying NOT NULL,
  role char(1) NOT NULL default 'R',
  rid integer NOT NULL default 0,
  mod char(1) NOT NULL default 'N',
  question character varying,
  private integer NOT NULL default 0,
  cap integer NOT NULL default 0,
  rooms character_varying 
);
Run Code Online (Sandbox Code Playgroud)



以下是聊天的架构,您可以看到用户及其示例:

CREATE TABLE rooms (
  rid integer primary key NOT NULL,
  name varchar(30) NOT NULL,
  type integer NOT NULL -- 0 = Open, 1 = meeting, 2 = guests can't speak, 3 moderated, 4 members(adult) only, 5 guests(child) only, 6 creaky door
) ;

INSERT INTO rooms (rid, name, type) VALUES 
(1, 'The Forum', 0),
(2, 'Operations Gallery', 2),  -- Guests Can't Speak
(3, 'Dungeon Club', 6),        -- creaky door
(4, 'Auditorium', 3),          -- Moderated Room
(5, 'Blue Room', 4),           -- Members Only (in Melinda's Backups this is Adults)
(6, 'Green Room', 5),          -- Guest Only (in Melinda's Backups this is Juveniles AKA Baby Backups)
(7, 'The Board Room', 1),      -- Various meeting rooms - need to be on users room list
Run Code Online (Sandbox Code Playgroud)



用户有另一个表格来指示对话的参与:

CREATE table wid_sequence ( value integer);
INSERT INTO wid_sequence (value) VALUES (1);

CREATE TABLE participant (
  uid integer NOT NULL REFERENCES users (uid) ON DELETE CASCADE ON UPDATE CASCADE,
  wid integer NOT NULL,
  primary key (uid,wid)
);
Run Code Online (Sandbox Code Playgroud)



档案 记录如下:

CREATE TABLE chat_log (
  lid integer primary key,
  time bigint DEFAULT (strftime('%s','now')) NOT NULL,
  uid integer NOT NULL REFERENCES user (uid) ON DELETE CASCADE ON UPDATE CASCADE,
  name character varying NOT NULL,
  role char(1) NOT NULL,
  rid integer NOT NULL,
  type char(2) NOT NULL,
  text character varying
);
Run Code Online (Sandbox Code Playgroud)

编辑:但是这种类型的数据建模不太适合Cassandra.因为,Cassandra您的数据不适合一台机器,因此无法使用连接.因此,在Cassandra 非规范化数据中是实用的选择.检查下面的chat_log表的非规范化版本:

CREATE TABLE chat_log (
  lid uuid,
  time timestamp,
  sender text NOT NULL,
  receiver text NOT NULL,
  room text NOT NULL,
  sender_role varchar NOT NULL,
  receiver_role varchar NOT NULL,
  rid decimal NOT NULL,
  status varchar NOT NULL,
  message text,
  PRIMARY KEY (sender, receiver, room)
  -- PRIMARY KEY (sender, receiver) if you don't want the messages to be separated by the rooms
) WITH CLUSTERING ORDER BY (time ASC);
Run Code Online (Sandbox Code Playgroud)

现在,为了检索数据,您需要使用以下查询:

每当用户想要由用户加载消息时.我想将它们检索回来并发送给用户.

SELECT * FROM chat_log WHERE sender = 'bob' ORDER BY time ASC
Run Code Online (Sandbox Code Playgroud)

我想在用户请求时检索来自不同用户的所有消息.

SELECT * FROM chat_log WHERE receiver = 'alice' ORDER BY time ASC
Run Code Online (Sandbox Code Playgroud)

我想存储和检索用户类.

SELECT * FROM chat_log WHERE sender_role = 'A' ORDER BY time ASC -- messages sent by CEOs

SELECT * FROM chat_log WHERE receiver_role = 'A' ORDER BY time ASC -- messages received by CEOs
Run Code Online (Sandbox Code Playgroud)


对数据建模后.您需要创建索引以进行快速有效的查询,如下所示:

  • 用于检索来自不同用户的所有消息至所述用户有效地

CREATE INDEX chat_log_uid ON chat_log(sender);
CREATE INDEX chat_log_uid ON chat_log(receiver);

  • 用于有效地从用户检索所有消息

CREATE INDEX chat_log_class ON chat_log(sender_role);
CREATE INDEX chat_log_class ON chat_log(receiver_role);


我相信这些例子会为您提供所需的方法.

如果您想了解有关Cassandra数据建模的更多信息,请查看以下内容:

  • @TamerTas,你的例子不起作用.您已经从不使用Cassandra的应用程序粘贴了SQL(而不是CQL).如果您尝试在cqlsh中输入该代码,则会出错.但是,我尊重OP的观点,即您的示例可以了解通用聊天应用程序的工作原理. (2认同)
  • 关系数据库与 Cassandra 等最终一致的数据库在数据建模方面存在巨大差异。一个不能用作另一个的基础。正如我在回复中所说,对于 Cassandra,您需要以查询的方式组织数据,而在关系数据库中,您的目标是数据标准化。这导致了非常不同的模型。 (2认同)