Кассандра и операторы <=, => для дат без РАЗРЕШЕНИЯ ФИЛЬТРАЦИИ - PullRequest
1 голос
/ 31 октября 2019

Я новичок с Кассандрой, и я не понимаю, почему я не могу фильтровать по датам (хочу вернуть результат между датами), например:

CREATE TABLE test.service_bar(
    service_bar_id UUID,
    start_date_time timestamp,
    end_date_time timestamp,
    title varchar,
    message text,
    is_active boolean,
    PRIMARY KEY((start_date_time, end_date_time))
);

тогда эта работа:

  SELECT start_date_time, end_date_time, is_active, message, service_bar_id, title
  FROM test.service_bar
  WHERE start_date_time = '2019-10-30 14:10:29'  AND end_date_time = '2019-10-30 14:10:29'
  LIMIT 500;

но это не так

  SELECT start_date_time, end_date_time, is_active, message, service_bar_id, title
  FROM test.service_bar
  WHERE start_date_time >= '2019-10-30 14:10:29'  AND end_date_time <= '2019-10-30 14:10:29'
  LIMIT 500;

Я не могу использовать ALLOW FILTERING

как я могу делать такие запросы в Кассандре?

1 Ответ

1 голос
/ 31 октября 2019

Я не понимаю, почему я не могу фильтровать по датам (хочу вернуть результат между датами)

Поведение, которое вы видите, из-за этого:

PRIMARY KEY((start_date_time, end_date_time))

Вы определили start_date_time и end_date_time как ключ составного раздела. Поскольку Cassandra использует распределенный хеш для обеспечения правильного распределения данных, разделы не сохраняются в порядке их значений. Они хранятся в хешированном значении ключа ключа раздела. Это можно увидеть с помощью функции token на ключе раздела:

aaron@cqlsh:stackoverflow> SELECT token(start_date_time,end_date_time),start_date_time,end_date_time,service_bar_id FROM service_bar ;

 system.token(
     start_date_time,
     end_date_time)   | start_date_time                 | end_date_time                   | service_bar_id
----------------------+---------------------------------+---------------------------------+--------------------------------------
    26346508703811310 | 2019-10-30 19:10:29.000000+0000 | 2019-10-30 19:10:29.000000+0000 | 49a70440-8689-4248-b389-13b8d0373e58
  1488616260313758762 | 2019-11-01 19:10:29.000000+0000 | 2019-11-01 19:10:29.000000+0000 | b0bab610-a285-41e7-ba5c-d56f8fb12f52
  2185622653117187064 | 2019-10-30 21:10:29.000000+0000 | 2019-10-30 21:10:29.000000+0000 | 3686c6a6-fd8d-4247-b501-964363a48f63
  7727638696734890177 | 2019-10-30 20:10:29.000000+0000 | 2019-10-30 20:10:29.000000+0000 | 97fc799e-fb54-4b7f-956e-f06bcb9e9d9d

(4 rows)

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

как я могу выполнять такие запросы в Cassandra?

Это также должно сказать вам, что вы должны строить свои таблицы и запросы, чтобы гарантировать, что они могут быть выполнены запросом к одному узлу. Учитывая это, ваш вариант использования действительно будет работать только в том случае, если вы измените свой ключ раздела.

Один из способов, которым команды разработчиков реализуют подобные решения, - это использование метода моделирования, называемого «ведением во времени», а иногда и просто «ведением». "В этом случае, допустим, вы никогда не будете писать более нескольких тысяч записей в месяц. Может быть, это не так, но я буду использовать его для этого примера. Затем я могу разделить по месяцам, а затем использовать столбцы _time в качестве ключей кластеризации.

CREATE TABLE stackoverflow.service_bar_by_month (
    month_bucket int,
    start_date_time timestamp,
    end_date_time timestamp,
    is_active boolean,
    message text,
    service_bar_id uuid,
    title text,
    PRIMARY KEY (month_bucket, start_date_time, end_date_time)
) WITH CLUSTERING ORDER BY (start_date_time DESC, end_date_time DESC);

Это сохранит все строки вместе по значению month_bucket, и в каждом разделе строки будутсортировать по start_date_time и end_date_time в порядке убывания. Теперь это работает:

aaron@cqlsh:stackoverflow> SELECT start_date_time, end_date_time, is_active, message, service_bar_id, title
                 ... FROM service_bar_by_month
                 ... WHERE month_bucket = 201910 AND start_date_time >= '2019-10-30 14:10:29'  AND start_date_time <= '2019-10-31 23:59:59';

 start_date_time                 | end_date_time                   | is_active | message           | service_bar_id                       | title
---------------------------------+---------------------------------+-----------+-------------------+--------------------------------------+--------
 2019-10-30 21:10:29.000000+0000 | 2019-10-30 21:10:29.000000+0000 |      True | This is an alert3 | eae5d3be-b2b2-40a1-aa28-0412fe9c18e6 | alert3
 2019-10-30 20:10:29.000000+0000 | 2019-10-30 20:10:29.000000+0000 |      True | This is an alert2 | af4ec72f-7758-42ef-b731-8d08f8a00006 | alert2
 2019-10-30 19:10:29.000000+0000 | 2019-10-30 19:10:29.000000+0000 |      True | This is an alert1 | 8b13db5c-9e39-4ee5-90a9-64758c5ab5be | alert1

(3 rows)

Обратите внимание, что вы можете применять запрос диапазона только к одному ключу кластеризации, как start_date_time выше. Это не может работать:

AND start_date_time >= '2019-10-30 14:10:29'  AND end_date_time <= '2019-10-31 23:59:59';

И это не может работать, потому что Cassandra предназначена для последовательного чтения и записи данных с / на диск. Разрешение запросов диапазона для нескольких столбцов в одном запросе потребует от Кассандры случайного чтения, что просто не очень хорошо. Вы можете сделать это сделать с помощью директивы ALLOW FILTERING, но это не рекомендуется. Хотя использование ALLOW FILTERING в небольших разделах, вероятно, будет работать нормально.

...