Эффективный доступ к упорядоченным результатам в Cassandra

Я пытаюсь преобразовать относительно распространенное требование в SQL в эффективную модель данных в Cassandra. Я пытаюсь решить, как лучше смоделировать свои данные, чтобы я мог упорядочивать свои строки в Cassandra в том же порядке, в котором я хочу сообщать о них в приложении. Обычно это был бы хороший случай для столбца кластеризации, за исключением того, что данные, по которым я хочу упорядочить свой результат, являются метрикой, которая будет обновляться несколько раз в день.

Я собираюсь объяснить проблему в SQL, а затем поделиться подходами к моделированию данных, которые пришли мне в голову. Я хотел бы знать, сталкивался ли кто-нибудь с подобным требованием к моему, и если да, то как вы моделировали данные в Cassandra.

Вот проблема, которую я пытаюсь решить.

Предположим, у меня есть таблица raw_data, определенная так:

CREATE TABLE raw_data (
  A varchar,
  B varchar,
  C varchar,
  D varchar,
  ts timestamp,
  val varint
  PRIMARY KEY (ts,A,B,C,D)
);

А еще у меня есть сводная таблица

CREATE TABLE summary_table (
  A varchar,
  B varchar,
  C varchar,
  total_val varint
  PRIMARY KEY (A,B,C)
);

Где данные в моей сводной таблице агрегируются моим приложением таким образом, который соответствует

SELECT A, B, C, SUM(val) FROM raw_data GROUP BY A, B, C

То, что я хочу сделать, это выполнить запрос, подобный следующему:

SELECT B, C, total_val FROM summary_table WHERE A = "Something" ORDER BY total_val DESC LIMIT 1000;

Другими словами, я хочу подмножить свою сводную таблицу для определенного значения A, а затем вернуть 1000 лучших строк, упорядоченных по total_val.

Total_val обновляется моим приложением каждые несколько минут, так как дополнительные данные передаются в мою таблицу raw_data. Поэтому я не могу использовать total_val в качестве столбца кластеризации для своих данных.

Я пытаюсь решить, как лучше смоделировать этот тип проблемы в Cassandra, в которой мне нужно создать подмножество сводной таблицы с помощью WHERE CLAUSE и упорядочить результирующий набор (который постоянно обновляется) в порядке DESC.

Можно ожидать, что некоторые результирующие наборы будут довольно большими — несколько сотен тысяч строк (то есть в моей сводной таблице есть некоторые значения для A, для которых SELECT COUNT(*) FROM summary_table WHERE A = "some value" будет очень, очень большим, исчисляемым сотнями строк). тысяч). Очевидно, что неэффективно сортировать эти данные и отбрасывать их перед отправкой в ​​мое приложение.

Кроме того, это не лучший вариант использования вторичных индексов. На меньших наборах результатов они очень эффективны. Для более крупных они отстают, и я подозреваю, что может быть лучший способ справиться с этой проблемой.

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

Кто-нибудь сталкивался с такой проблемой, когда вам нужно отфильтровать сводные данные с помощью предложения WHERE и упорядочить (часто меняющиеся) результаты в порядке описания? Если да, то нашли ли вы способ сделать это эффективным, когда определенные предложения WHERE будут возвращать много тысяч строк? Если да, то как вы собирались это сделать?


person Evan Volgas    schedule 16.09.2014    source источник


Ответы (1)


Лучший способ, который я могу придумать, это сделать следующее:

CREATE TABLE summary_table (
  time_bucket long,
  A varchar,
  total_val int,
  timestamp long,
  B varchar,
  C varchar,
  PRIMARY KEY ((time_bucket, A), total_val, timestamp, B, C)
) WITH CLUSTERING ORDER BY (total_val DESC);

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

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

person rs_atl    schedule 16.09.2014
comment
вы превратили сводную таблицу в данные временных рядов... Это действительно блестящая идея, Робби. Я должен вам пиво в следующий раз, когда ATL Cassandra Meetup появится. Я думаю о 20 различных способах применения чего-то подобного... это абсолютно фантастическая идея. - person Evan Volgas; 17.09.2014
comment
Рад быть полезным! На самом деле общий принцип моделирования данных с помощью Cassandra заключается в неизменности записи. Помните, что Cassandra — это хранилище с журнальной структурой, поэтому вы просто конвертируете свои данные в то, что составляет данные журнала, то есть временные ряды. - person rs_atl; 17.09.2014