使用二级索引更新 Cassandra 2.1 中的行
Using secondary indexes to update rows in 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
包含大约 1 亿行,而其中只有 500 万行具有大约 50,000 张不同的票证。所以一张票 - 平均 - 有 100 个事件。
无需提供分区键即可查询二级索引,这在我们的情况下很方便。由于 bucket
列有时很难事先确定(即您应该知道事件的日期,bucket
是当前日期)。
cqlsh> select * from events where ticket_id = 123;
client_id | bucket | timestamp | ... | ticket_id
-----------+--------+-----------+-----+-----------
(0 rows)
一张工单的所有事件都应该移动到另一张工单的问题如何解决? IE。以下查询将不起作用:
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
查询?
我应该使用什么模型来支持这些变化?
您可以使用二级索引查询旧票的事件,然后使用检索到的事件中的主键来更新事件。
我不确定您为什么需要手动执行此操作,似乎 Cassandra 应该能够在后台执行此操作。
首先,UPDATE
和 INSERT
操作在 Cassandra 中被视为相同。他们通俗地称为 "UPSERTs."
Does this imply secondary indexes cannot be used in UPDATE queries?
正确。如果不指定完整的 PRIMARY KEY,则无法在 Cassandra 中执行 UPSERT。即使是带有部分 PRIMARY KEY 的 UPSERT 也不起作用。并且(正如您所发现的)通过索引值进行 UPSERTing 也不起作用。
How do I solve the problem when all events of a ticket should be moved to another ticket?
不幸的是,完成此操作的唯一方法是查询 events
中每一行的键(具有特定的 ticket_id
)并通过这些键进行 UPSERT ticket_id
。好处是,您不必首先 DELETE
它们,因为 ticket_id
不是 PRIMARY KEY 的一部分。
How do I solve the problem when all events of a ticket should be moved to another ticket?
我认为您最好的计划是完全放弃二级索引,并创建一个查询 table 与您的 events
table:
一起工作
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
。这将为您提供所需的信息在你的 events
table.
上更新新的 ticket_id
您还可以通过 ticket_id
(在 eventsbyticketid
table 上)执行 DELETE
。只要您拥有完整的分区键 (ticket_id
),Cassandra 就允许使用部分主键进行 DELETE
操作。因此,从查询 table 中删除旧的 ticket_id
会很容易。为了确保写入原子性,您可以将 UPSERT 批处理在一起:
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
实际上是 Cassandra 中的一种(保留字)数据类型。这使得它成为 timeuuid
列的一个非常糟糕的名称。
我正在使用 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
包含大约 1 亿行,而其中只有 500 万行具有大约 50,000 张不同的票证。所以一张票 - 平均 - 有 100 个事件。
无需提供分区键即可查询二级索引,这在我们的情况下很方便。由于 bucket
列有时很难事先确定(即您应该知道事件的日期,bucket
是当前日期)。
cqlsh> select * from events where ticket_id = 123;
client_id | bucket | timestamp | ... | ticket_id
-----------+--------+-----------+-----+-----------
(0 rows)
一张工单的所有事件都应该移动到另一张工单的问题如何解决? IE。以下查询将不起作用:
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
查询?
我应该使用什么模型来支持这些变化?
您可以使用二级索引查询旧票的事件,然后使用检索到的事件中的主键来更新事件。
我不确定您为什么需要手动执行此操作,似乎 Cassandra 应该能够在后台执行此操作。
首先,UPDATE
和 INSERT
操作在 Cassandra 中被视为相同。他们通俗地称为 "UPSERTs."
Does this imply secondary indexes cannot be used in UPDATE queries?
正确。如果不指定完整的 PRIMARY KEY,则无法在 Cassandra 中执行 UPSERT。即使是带有部分 PRIMARY KEY 的 UPSERT 也不起作用。并且(正如您所发现的)通过索引值进行 UPSERTing 也不起作用。
How do I solve the problem when all events of a ticket should be moved to another ticket?
不幸的是,完成此操作的唯一方法是查询 events
中每一行的键(具有特定的 ticket_id
)并通过这些键进行 UPSERT ticket_id
。好处是,您不必首先 DELETE
它们,因为 ticket_id
不是 PRIMARY KEY 的一部分。
How do I solve the problem when all events of a ticket should be moved to another ticket?
我认为您最好的计划是完全放弃二级索引,并创建一个查询 table 与您的 events
table:
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
。这将为您提供所需的信息在你的 events
table.
ticket_id
您还可以通过 ticket_id
(在 eventsbyticketid
table 上)执行 DELETE
。只要您拥有完整的分区键 (ticket_id
),Cassandra 就允许使用部分主键进行 DELETE
操作。因此,从查询 table 中删除旧的 ticket_id
会很容易。为了确保写入原子性,您可以将 UPSERT 批处理在一起:
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
实际上是 Cassandra 中的一种(保留字)数据类型。这使得它成为 timeuuid
列的一个非常糟糕的名称。