RDMBS to Cassandra - Нравится ли текущему пользователю запрошенный пост? - PullRequest
0 голосов
/ 21 марта 2019

Я пытаюсь научиться создавать модель в Cassandra, чтобы я мог получать информацию некоторым эффективным способом (возможно, одним запросом), понравилась ли текущему вошедшему в систему пользователю сообщение вместе с данными сообщения. В RDMBS это довольно просто, но я просто не могу понять, как это сделать в Кассандре.

Вот пример того, чего я пытаюсь достичь в Кассандре на RDMBS:

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"

1 Ответ

0 голосов
/ 21 марта 2019

Самый простой способ добиться этого - создать таблицу 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'; 

Но у этого подхода есть недостаток - если вы ожидаете большого количества лайков пользователей на пост (миллионы или миллиарды), эта таблица будет иметь слишком большие разделы, это приведет к низкой производительности инеспособность хранить так много лайков за пост.Кассандра имеет ограничение в 2 миллиарда строк на ключ раздела.

В этом случае вы можете распространять информацию о лайках одного сообщения на несколько разделов, используя составной первичный ключ (этот подход обычно называется согласованным хешированием):

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 поле.Согласованное хеширование обеспечивает возможность генерирования некоторого числа в указанном диапазоне на основе указанного идентификатора пользователя.(Например, java-библиотека Guava предоставляет согласованную функцию хеширования )

Перед тем, как вставить данные в таблицу 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' );

Также перед тем, как выбрать данные, вам нужно вычислить хэш с теми же параметрами, что и для вставки:

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';
...