Cassandra SELECT по второму индексу всегда сортируется по ключу раздела?

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

CREATE TABLE ItemUpdates (
    time         timestamp,
    item_name    text,
    item_context text,
    item_descr   text,
    tags         map<text, int>,
    PRIMARY KEY ((time, item_name, item_context))
);

CREATE INDEX ItemUpdateByName
    ON ItemUpdates(item_name);

CREATE INDEX ItemUpdateByContext
    ON ItemUpdates(item_context);

CREATE INDEX ItemUpdateByTag
    ON ItemUpdates(KEYS(tags));

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

Естественный запрос в моем приложении: «показать мне все обновления элемента X с определенным тегом». Это означает:

SELECT * FROM ItemUpdates
    WHERE item_name='x'
        AND item_context='a'
        AND tags CONTAINS KEY 't';

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

(1) Всегда ли Cassandra возвращает строки, отсортированные по ключу секции, при выборе в (n) (наборе) индексированных столбцов?

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

  • получить все обновления элемента X, начиная с даты D
  • получить 300 последних обновлений элемента X

Что меня удивляет, так это то, что добавление предложения ORDER BY time DESC к моему оператору выбора в ItemUpdates приводит к сообщению об ошибке «ORDER BY с 2-мя индексами не поддерживается».

(2) (Как) я могу выполнить запрос диапазона для ключа секции, когда я сужаю запрос, выбирая индексированный столбец?


person Rinke    schedule 04.11.2014    source источник


Ответы (1)


Единственная естественная "автоматическая" сортировка, которую вы должны получить на cassandra, - это столбцы в широком ряду. разделы при использовании murmur3 не «сортируются», так как это испортило бы случайное распределение (на самом деле). Индексы хранятся на каждом узле в «скрытой» таблице в виде широких строк. При фильтрации индекса он попадает в этот «раздел» «на узле», а значения представляют собой строки в этом разделе (которые соответствуют совпадающим строкам на этом узле). Попробуйте выполнить запрос, используя разные наборы данных и разные столбцы. Возможно, данные, которые у вас есть, вызывают сортировку результатов.

(2) В настоящее время вы можете выполнять запросы диапазона только для ключей кластеризации, а не для ключа раздела. В общем, для эффективного запроса вы должны попытаться попасть в один (или несколько) разделов и отфильтровать по индексам/фильтровать по ключам кластеризации/запросу диапазона по ключу кластеризации. Если вы попытаетесь не попасть в раздел, это станет операцией в масштабе всего кластера, что обычно не очень хорошо. Если вы хотите выполнить анализ всего кластера (в стиле уменьшения карты), взгляните на Apache Spark. Интеграция Spark cassandra довольно хороша и становится все лучше.

person ashic    schedule 04.11.2014
comment
Спасибо. Так что ответ на (1) - нет. Проверил ваше предложение и действительно: результаты не отсортированы. Мне кажется, я до сих пор не до конца понимаю внутренности вторичных индексов. Я думал, что индекс представляет собой CF широких строк с индексированным значением в качестве ключа раздела широкой строки и ключами раздела «целевых» строк в виде имен столбцов (без значения). Результатом будет то, что результаты поиска по индексу будут отсортированным (!) списком ключей разделов (поскольку столбцы упорядочены по имени). - person Rinke; 04.11.2014
comment
Первая версия ItemUpdates имела ((item_name, item_context), time) в качестве ПК. Маркированные запросы из моего вопроса, конечно, будут простыми. Но, проведя некоторые расчеты, я понял, что через какое-то время строки станут слишком широкими, поэтому мне нужно было разбить их по-другому. Какие-либо предложения? - person Rinke; 04.11.2014
comment
Вы могли бы ввести ведро. Например, ((название, контекст, год), время). Это дает вам один широкий ряд в год. Если это слишком много, вы можете сделать это по месяцам+годам: ((название, контекст, месяц_год), время). Может означать больше запросов со стороны клиента, но обычно запросы n*2 мс дешевле, чем уменьшение большой карты. - person ashic; 04.11.2014
comment
Хорошее понимание. Итак, вы говорите, что шаблон для эффективного запроса таков: сначала выберите ключ секции, а затем отфильтруйте дальше, используя ключ кластеризации или вторичные индексы, верно? - person Rinke; 04.11.2014
comment
Наиболее эффективно указать раздел + ключ кластеризации. Следующим по эффективности является ключ раздела + (кластеризация и/или индекс). Затем наиболее эффективным является несколько ключей раздела (с оператором IN). Это немного зависит от размера широкой строки. Отсутствие указания ключа секции является операцией в масштабе всего кластера, и обычно для таких вещей (типа анализа) лучше использовать Spark. - person ashic; 04.11.2014
comment
Под кластеризацией вы имеете в виду диапазонные запросы на CK? - person Rinke; 04.11.2014
comment
Ключи кластеризации — это ключи в первичном ключе, которые не являются ключом секции. Итак, ((a, b), c, d) pk будет иметь c и d в качестве ключей кластеризации. Ключи кластеризации разрешают запросы диапазона, если указаны все предыдущие ключи. Это имеет смысл, если вы думаете об этом, поскольку данные располагаются внутри раздела, упорядоченного каждым последовательным ключом кластеризации. Итак, в предыдущем примере для каждой секции данные будут отсортированы по c, а внутри c данные будут отсортированы по d. - person ashic; 04.11.2014