2015-05-11 2 views
3

Я использую Cassandra 2.1 и есть модель, которая примерно выглядит следующим образом:Использование вторичных индексов для обновления строк в Cassandra 2.1

CREATE TABLE events (
    client_id bigint, 
    bucket int, 
    timestamp timeuuid, 
    ... 
    ticket_id bigint, 
    PRIMARY KEY ((client_id, bucket), timestamp) 
); 
CREATE INDEX events_ticket ON events(ticket_id); 

Как вы можете видеть, я создал вторичный индекс по ticket_id. Этот индекс работает нормально. events содержит около 100 миллионов строк, в то время как только 5 миллионов из этих строк имеют около 50 000 отдельных билетов. Таким образом, билет - в среднем - имеет 100 событий.

Выполнение запроса вторичного индекса работает без предоставления ключа раздела, что удобно в нашей ситуации. Поскольку столбец bucket иногда трудно определить заранее (т. Е. Вы должны знать дату событий, bucket в настоящее время является датой).

cqlsh> select * from events where ticket_id = 123; 

client_id | bucket | timestamp | ... | ticket_id 
-----------+--------+-----------+-----+----------- 

(0 rows) 

Как решить проблему, когда все события билета должны быть перенесены в другой билет? То есть Следующий запрос не будет работать:

cqlsh> UPDATE events SET ticket_id = 321 WHERE ticket_id = 123; 
InvalidRequest: code=2200 [Invalid query] message="Non PRIMARY KEY ticket_id found in where clause" 

Означает ли это вторичные индексы не могут быть использованы в UPDATE запросов?

Какую модель следует использовать для поддержки этих изменений?

ответ

3

Прежде всего, UPDATE и INSERT операции обрабатываются одинаково в Кассандре. Их разговорно называют «UPSERT».

Означает ли это, что вторичные индексы не могут использоваться в запросах UPDATE?

Исправить. Вы не можете выполнить UPSERT в Кассандре, не указав полный PRIMARY KEY. Даже UPSERT с частичным PRIMARY KEY не будут работать. И (как вы обнаружили) UPSERTing по индексированному значению тоже не работает.

Как решить проблему, когда все события билета должны быть перенесены в другой билет?

К сожалению, единственный способ для достижения этой цели, является запрос ключи каждой строки в events (с конкретной ticket_id) и UPSERT ticket_id этими ключами. Самое приятное, что вам не нужно сначала DELETE их, потому что ticket_id не является частью ПЕРВИЧНОГО КЛЮЧА.

Как решить проблему, когда все события билета должны быть перенесены в другой билет?

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

CREATE TABLE eventsbyticketid (
    client_id bigint, 
    bucket int, 
    timestamp timeuuid, 
    ... 
    ticket_id bigint, 
    PRIMARY KEY ((ticket_id), timestamp) 
) WITH CLUSTERING ORDER BY (timestamp DESC); 

Это позволит запрос по ticket_id быстро (чтобы получить ваш client_id, bucket и timestamp. Это даст вам информацию, которую вы должны UPSERT новый ticket_id на вашем events столе.

вы могли затем выполните DELETE на ticket_id (на столе eventsbyticketid). Cassandra разрешает операцию DELETE с частичным PRIMARY KEY, если у вас есть полный ключ раздела (ticket_id). Поэтому удаление старого ticket_id s из таблицы запросов было бы простым. А чтобы обеспечить запись атомарность, вы могли партия в UPSERTs вместе:

BEGIN BATCH 
    UPDATE events SET ticket_id = 321 WHERE client_id=2112 AND bucket='2015-04-22 14:53' AND timestamp=4a7e2730-e929-11e4-88c8-21b264d4c94d; 
    UPDATE eventsbyticketid SET client_id=2112, bucket='2015-04-22 14:53' WHERE ticket_id=321 AND timestamp=4a7e2730-e929-11e4-88c8-21b264d4c94d 
APPLY BATCH; 

Что на самом деле так же, как исполнительства:

BEGIN BATCH 
    INSERT INTO events (client_id,bucket,timestamp,ticketid) VALUES(2112,'2015-04-22 14:53',4a7e2730-e929-11e4-88c8-21b264d4c94d,321); 
    INSERT INTO eventsbyticketid (client_id,bucket,timestamp,ticketid) VALUES(2112,'2015-04-22 14:53',4a7e2730-e929-11e4-88c8-21b264d4c94d,321); 
APPLY BATCH; 

Примечание стороны: timestamp фактически (зарезервированное слово) тип данных в Кассандре , Это делает его довольно паршивым именем для столбца timeuuid.

1

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

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

Смежные вопросы