Модель данных Cassandra для запроса упорядоченного диапазона

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

Мне нужно хранить данные только для одного типа объекта, представляющего финансовую транзакцию. Основные поля (применимы для запросов, сортировки):

  1. uuid: уникальный идентификатор транзакции
  2. timestamp: время транзакции
  3. source_id: строка (низкая мощность, обычно <10 уникальных значений в наборе данных)
  4. destination_id: строка (низкая мощность, обычно <10 уникальных значений в наборе данных)
  5. merchant_id: string (высокая мощность, ~ 100 тыс. уникальных значений)

Есть дополнительные поля (всего около 20), но они не требуются для запроса или заказа.

Мне нужно запрашивать транзакции двумя способами:

  1. Автор: UUID
  2. По диапазону дат, для точных значений source_id / destination_id, упорядоченных по merchant_id

Запрос UUID должен быть быстрым и, хотя запрос диапазона дат должен быть максимально эффективным, он запускается ежедневно как автономный процесс, поэтому может занять больше времени. Было бы хорошо понять, как масштабируется время запроса с помощью no. записи.

Cassandra будет настроен как кластер из 4 узлов в 2 центрах обработки данных, если это повлияет на конфигурацию ключа раздела. Я использую Cassandra 2.0.

Будучи новичком в Cassandra, я читал о составных ключах, timeuuid, запросах срезов и т. Д., Но немного запутался. Если кто-нибудь сможет предложить правильный подход или указать мне правильное направление, я был бы очень признателен.

Спасибо.


person siwatson    schedule 26.04.2014    source источник


Ответы (1)


Запрос 1 довольно прост, в CQL3 это выглядит так:

create table tx_by_uuid (
tx_id uuid PRIMARY KEY,
tx_time timestamp,
source_id text,
dest_id text,
merchant_id text
) 

Запрос 2 немного сложнее: (обратите внимание, здесь я предполагаю, что source_id / destination_id относится к требованию, чтобы оба были указаны, а не и либо / или ситуация)

Поскольку мы хотим запрашивать точные значения source_id / destination_id, в идеале нам нужен первичный ключ, который использует комбинацию этих столбцов в качестве ключа раздела. Поскольку это столбцы с низкой мощностью, мы можем столкнуться с проблемой неуклюжего разбиения, но поскольку вы предоставили нам дополнительную информацию о количестве узлов, мы можем убедить себя, что source_id + destination_id является приемлемым ключом разделения для этой таблицы, наблюдая что если каждый из этих столбцов имеет около 10 различных значений, при объединении будет около 100 различных значений. В более крупном кластере это не было бы идеальным распределением данных, и мы могли бы добавить временное ведро к ключу разделения, но для кластера с четырьмя узлами здесь все может быть хорошо.

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

create table tx_by_merchant(
tx_id uuid,
tx_time timestamp,
source_id text,
dest_id text,
merchant_id text,
primary key((source_id, dest_id), tx_time, merchant_id, tx_id)
)

Обратите внимание, что эти разделы могут быть очень широкими, поэтому было бы неплохо добавить дополнительный столбец год + месяц к ключу раздела, чтобы немного их разбить. Кроме того, если вам нужно отменить порядок, обратите внимание на предложение WITH CLUSTERING ORDER.

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

person stinkymatt    schedule 26.04.2014
comment
Большое спасибо за ваш ответ. Мне было полезно увидеть предложенный вами первичный ключ для поддержки запроса диапазона. Раньше я пробовал использовать метку времени в ключе раздела, и это вызывало ошибку. Как я теперь понимаю, я должен ограничить ключ раздела, чтобы запросить диапазон, то есть запросить только один узел? Кроме того, если я правильно понял, ваш пример требует, чтобы записи дублировались в двух таблицах? Есть ли способ также иметь эффективный доступ к записям по UUID с одной таблицей? Я предполагаю, что вторичный индекс для UUID - не лучшая идея из-за высокой мощности? - person siwatson; 28.04.2014
comment
В Cassandra дублирование данных в разные структуры для эффективного выполнения запросов - это как раз то, как мы работаем;) И вы совершенно правы насчет высокой мощности. - person stinkymatt; 28.04.2014
comment
Спасибо за разъяснения. Еще один вопрос о моем требовании запрашивать записи в диапазоне дат, но упорядочивать результаты по идентификатору продавца - первичному ключу вы предлагаете только заказы по merchant_id для записей с идентичными значениями tx_time. Другими словами, если я запрашиваю у tx_by_merchant диапазон дат, я действительно получаю записи, упорядоченные по tx_time. Лучше ли я здесь запрашивать по дате и помещать результаты во временную таблицу, которую я могу проиндексировать по merchant_id (с фиксированным ключом раздела)? - person siwatson; 28.04.2014
comment
Ой, попался. Тогда возникает вопрос: сколько строк, по вашему мнению, вы сможете сопоставить в целом с помощью этого запроса? Если это тонна, вы действительно хотите вернуть все это одним запросом? Я подозреваю, что лучший вариант - создать 10-минутные (или 1-минутные, или 1-часовые) блоки транзакций. Затем корзина становится частью ключа раздела, и вы можете получить заказ продавца, который вам нужен. Компромисс будет заключаться в том, что для запроса по временному диапазону в нескольких сегментах вам придется выполнить несколько запросов. Сообщите мне, какой вариант звучит привлекательно, и я отредактирую ответ, чтобы показать, как это сделать. - person stinkymatt; 02.05.2014
comment
Спасибо за ответ. Решение, которое я реализовал, - использовать дополнительную таблицу для заказа по merchant_id (всего 3 таблицы). Я вставляю результаты запроса диапазона дат в эту таблицу (используя новый ключ раздела UUID для всех результатов) и запрашиваю их для сортировки по merchant_id. - person siwatson; 07.05.2014