Cassandra-使用ORDER BY和UPDATE对密钥进行聚类的另一种方法

Cassandra-使用ORDER BY和UPDATE对密钥进行聚类的另一种方法,cassandra,cassandra-2.0,clustered-index,nosql,Cassandra,Cassandra 2.0,Clustered Index,Nosql,我的模式是: CREATE TABLE friends ( userId timeuuid, friendId timeuuid, status varchar, ts timeuuid, PRIMARY KEY (userId,friendId) ); CREATE TABLE friends_by_status ( userId timeuuid, friendId timeuuid, status varc

我的模式是:

CREATE TABLE friends (
     userId timeuuid,
     friendId timeuuid,
     status varchar, 
     ts timeuuid,   
     PRIMARY KEY (userId,friendId)
);

CREATE TABLE friends_by_status (
    userId timeuuid,
    friendId timeuuid,
    status varchar, 
    ts timeuuid,   
    PRIMARY KEY ((userId,status), ts)
)with clustering order by (ts desc);
在这里,每当发出好友请求时,我都会在两个表中插入记录。 当我想检查用户的一对一状态时,我将使用以下查询:

SELECT status FROM friends WHERE userId=xxx AND friendId=xxx;
当我需要查询所有处于挂起状态的记录时,我将使用:

SELECT * FROM friends_by_status WHERE userId=xxx AND status='pending';
但是,当状态发生更改时,我可以更新'friends'表中的'status'和'ts',但不能更新'friends\u by\u status'表中的'status'和'ts',因为它们都是主键的一部分

您可以看到,即使我将其非规范化,我也肯定需要更新“friends\u by\u status”表中的“status”和“ts”以保持一致性

保持一致性的唯一方法是删除记录并再次插入。
但在cassandra模型中也不建议频繁删除

我发现这是卡桑德拉最大的限制

有没有其他办法来解决这个问题


任何解决方案都值得赞赏

为什么第二个表的主键中需要status?如果这是您的模式:

CREATE TABLE friends_by_status (
userId timeuuid,
friendId timeuuid,
status varchar, 
ts timeuuid,   
PRIMARY KEY ((userId), status, ts) 
with clustering order by (ts desc));

您可以根据需要更新状态,但仍可以根据状态进行筛选。您将在一个分区下存储更多数据,但似乎您为用户的每个朋友存储了一行数据。这将与第一个表中的相同,因此我不认为分区大小是一个问题

我不知道您需要多久部署它,但在Cassandra 3.0中,您可以使用物化视图处理此问题。您的friends表将是基表,friends\u by\u状态将是基表的视图。当您更改基表时,Cassandra会注意更新视图

例如:

CREATE TABLE friends ( userid int, friendid int, status varchar, ts timeuuid, PRIMARY KEY (userId,friendId) );
CREATE MATERIALIZED VIEW friends_by_status AS
    SELECT userId from friends WHERE userID IS NOT NULL AND friendId IS NOT NULL AND status IS NOT NULL AND ts IS NOT NULL
    PRIMARY KEY ((userId,status), friendID);

INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 500, 'pending', now());
INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 501, 'accepted', now());
INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 502, 'pending', now());
SELECT * FROM friends;                

 userid | friendid | status   | ts
--------+----------+----------+--------------------------------------
      1 |      500 |  pending | a02f7fe0-49f9-11e5-9e3c-ab179e6a6326
      1 |      501 | accepted | a6c80980-49f9-11e5-9e3c-ab179e6a6326
      1 |      502 |  pending | add10830-49f9-11e5-9e3c-ab179e6a6326
因此,现在在视图中,您可以按状态选择行:

SELECT * FROM friends_by_status WHERE userid=1 AND status='pending';

 userid | status  | friendid
--------+---------+----------
      1 | pending |      500
      1 | pending |      502

(2 rows)
然后,当您更新基表中的状态时,它会在视图中自动更新:

UPDATE friends SET status='pending' WHERE userid=1 AND friendid=501;
SELECT * FROM friends_by_status WHERE userid=1 AND status='pending';

 userid | status  | friendid
--------+---------+----------
      1 | pending |      500
      1 | pending |      501
      1 | pending |      502

(3 rows)
但是请注意,在视图中不能将ts作为键的一部分,因为您只能从基表中添加一个非键字段作为视图中键的一部分,在您的情况下,这将是向键添加“状态”


如果你想试用的话,我想3.0的第一个beta版明天就要发布了。

update friends\u by\u status set status='accepted'where userId=now();由于状态是主键的一部分,因此此查询无法工作。请重新思考您正在尝试执行的操作。在当前模型中,如何指定要更新的个人友谊关系?在userId=now()处,通过更新好友,即使您被允许更新,也会更新该用户的所有行。您可以考虑的一个选项是为“挂起的朋友请求”使用集合(集合或列表),您可以动态更改这些请求。我确实考虑过使用集合。在每个用户上设置诸如“待处理的请求”、“已接受的请求”、“已拒绝的请求”之类的列是一个好主意吗。?它会提供良好的性能,因为每一列可能有多个值。e、 g:挂起的_请求集合中可能有200-1000项。这是一个很好的实践吗?谢谢你提到3.0…它真的很棒。但我不确定稳定版本何时发布。不管怎样,在每个用户上设置集合列(如“待定的请求”、“已接受的请求”、“已拒绝的请求”)是一个好主意吗。?它会提供良好的性能,因为每个列可能都有很多值。e、 g:挂起的_请求集合中可能有200-1000项。这是一个好的实践吗?到目前为止,3.0对我来说相当稳定。开发人员在这方面做了大量的工作。实际上,我打算为您的用例向您推荐集合。我相信集合是作为一个数据块读取的,因此如果您经常读取大型集合,那么这可能会影响性能,但最好尝试一下,看看。@JimMeyer当我们有多个非键时,是否有解决方案?