我正在尝试研究如何在Cassandra中创建模型,以便以一种有效的方式(可能是单个查询)获取信息,无论当前登录的用户是否喜欢发布以及发布数据。在RDMBS中它很容易,但我无法理解如何在Cassandra中完成它。
以下是我在Cassandra上尝试在RDBMS上实现的示例:
SELECT
x.post_id,
x.content,
x.created_at,
(
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM post_likes AS p1
WHERE (p1.user_id = @currentUserId) AND (x.post_id = p1.post_id))
THEN TRUE::bool ELSE FALSE::bool
END
) AS "has_current_user_liked_post"
实现此目的的最简单方法是创建表likes_by_post:
CREATE TABLE likes_by_post (
post_id text,
user_id text,
PRIMARY KEY (post_id, user_id)
);
此表将允许您获得喜欢某些帖子的所有用户:
SELECT * FROM likes_by_post WHERE post_id='post_1';
检查用户喜欢的帖子:
SELECT * FROM likes_by_post WHERE post_id='post_1' AND user_id='user_1';
但这个approch有一个缺点 - 如果你期望很多用户喜欢每个帖子(数百万或数十亿),这个表将有太大的分区,它将导致糟糕的性能和残疾存储这么多喜欢每个帖子。 Cassandra每个分区键限制为2亿行。
在这种情况下,您可以使用复合主键将此单个帖子的相关信息传播到多个分区(此方法通常称为Consistent Hashing):
CREATE TABLE likes_buckets_by_post (
post_id text,
bucket_id int,
user_id text,
PRIMARY KEY (( post_id, bucket_id ), user_id)
);
其中bucket_id
是一个合成字段,负责为同一帖子为不同用户生成不同的分区键。
bucked_id
应该是基于user_id
字段的某种哈希。一致散列提供了根据指定的用户ID在指定范围内生成某个数字的功能。 (例如,Guava java库提供consistent hashing function)
在将数据插入likes_buckets_by_post
表之前,您需要使用一致的散列函数和指定的存储桶数来计算bucket_id
:
var bucket = consistentHash(user_id, N)
其中N是桶的总数,这个数字将取决于您的条件:您拥有多少Cassandra节点,您期望每个帖子有多少喜欢,这个数字越大,用于存储的分区将被扩展。
请注意,如果您需要为帖子请求所有喜欢,您必须执行N个请求,但对于您的情况,它只需要一个请求来检查单个用户,如单个帖子。
INSERT INTO likes_buckets_by_post (post_id, bucket_id, user_id) VALUES ('post_1', bucket, 'user_1' );
在选择数据之前,您需要使用与insert相同的参数计算哈希值:
var bucket = consistentHash(user_id, N)
然后你可以检查用户喜欢的帖子:
SELECT * FROM likes_buckets_by_post WHERE post_id='post_1' AND bucket_id=bucket AND user_id='user_1';