Самый эффективный способ запрашивать cassandra небольшими порциями по времени.

Моему приложению на основе Cassandra необходимо прочитать строки, измененные с момента последнего чтения. Для этой цели мы планируем иметь таблицу changed_rows, которая будет содержать два столбца —

  1. ID - ID измененной строки и
  2. Updated_Time — метка времени, когда оно было изменено.

Как лучше всего читать такую ​​таблицу, чтобы она читала небольшую группу строк, упорядоченных по времени. Пример: если таблица:

ID   Updated_Time
foo    1000
bar    1200
abc    2000
pqr    2500
zyx    2900
 ...
xyz   901000
 ...

Я показал идентификаторы как простые трехбуквенные ключи, на самом деле это UUID. Кроме того, время, показанное выше, для простоты показано как целое число, но это фактическая временная метка Cassandra (или дата Java). Столбец Updated_Time является монотонно возрастающим.

Если я запрашиваю эти данные с помощью:

SELECT * FROM changed_rows WHERE Updated_Time < toTimestamp(now())

Я получаю следующую ошибку:

Cannot execute this query as it might involve data filtering and 
thus may have unpredictable performance... Use Allow Filtering

Но я думаю, что Allow Filtering в этом случае убьет производительность. Страница индекса Cassandra предупреждает, что следует избегать индексов для столбцов с высокой кардинальностью, а Updated_Time выше наверняка выглядит как высокая кардинальность.

Я заранее не знаю столбец идентификаторов, потому что цель запроса — узнать идентификаторы, обновленные между заданными интервалами времени.

Каков наилучший способ запроса Cassandra в этом случае?
Могу ли я каким-то образом изменить свою таблицу, чтобы более эффективно выполнять запрос временного фрагмента?

Примечание. Это должно звучать примерно так же, как функция Cassandra-CDC, но мы нельзя использовать одно и то же, потому что наше решение должно работать для всех версий Cassandra.


person user2250246    schedule 27.02.2017    source источник


Ответы (1)


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

CREATE TABLE modified_records (
    timeslot timestamp,
    updatedtime timestamp,
    recordid timeuuid,
    PRIMARY KEY (timeslot, updatedtime)
);

Теперь вы можете разделить свой «журнал обновленных записей» на временные интервалы, например, 1 час, и заполнить таблицу следующим образом:

INSERT INTO modified_records (timeslot, updatedtime, recordid) VALUES ( '2017-02-27 09:00:00', '2017-02-27 09:36:00', 123);
INSERT INTO modified_records (timeslot, updatedtime, recordid) VALUES ( '2017-02-27 09:00:00', '2017-02-27 09:56:00', 456);
INSERT INTO modified_records (timeslot, updatedtime, recordid) VALUES ( '2017-02-27 10:00:00', '2017-02-27 10:00:13', 789);

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

SELECT * FROM modified_records WHERE timeslot = '2017-02-27 09:00:00';
SELECT * FROM modified_records WHERE timeslot = '2017-02-27 10:00:00';

В зависимости от того, как часто ваши записи обновляются, вы можете использовать меньшие или большие временные интервалы, например, каждые 6 часов, 1 день или каждые 15 минут. Эта структура очень гибкая. Вам нужно только знать временной интервал, который вы хотите запросить. Если вам нужно охватить несколько временных интервалов, вам потребуется выполнить несколько запросов.

person xmas79    schedule 27.02.2017
comment
Почему не PRIMARY KEY (временной интервал)? Насколько я понимаю, если временной интервал и время обновления являются частями ключа разделения, ваш SELECT не будет работать. - person starikoff; 27.02.2017
comment
@starikoff: они оба являются частью первичного ключа, но на самом деле только timeslot является ключом раздела, updatedtime является ключом кластеризации. - person xmas79; 27.02.2017
comment
Моя беда, я давно не видел спецификацию ключа без явных скобок, окружающих ключ разделения, поэтому я подумал (ошибочно), что без них все части образуют составной ключ разделения. - person starikoff; 27.02.2017
comment
Есть ли у Cassandra функция для возврата dayOfYear из now() каким-то образом? Чтобы я мог использовать его для автоматического заполнения моего столбца? Пример: INSERT INTO modified_records (timeslot, updatedtime, recordid) VALUES (dayOfYear(now()), toTimestamp(now()), 789) - person user2250246; 28.02.2017
comment
@ user2250246 Я так не думаю. Также мне не очень нравятся функции внутри запросов (например, now()), потому что они, как правило, устраняют идемпотентность запросов. Конечно, это зависит от конкретного случая... Кстати, вы можете легко решить это в своем клиентском коде, и, вероятно, вам действительно нужно, если у вас есть часовые/минутные временные интервалы... - person xmas79; 28.02.2017