4

我正在使用 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)

当一张票的所有事件都应该移动到另一张票时,我该如何解决这个问题?即以下查询将不起作用:

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查询中使用?

我应该使用什么模型来支持这些更改?

4

2 回答 2

5

首先,UPDATEINSERT操作在 Cassandra 中是一样的。它们通俗地称为“UPSERT”。

这是否意味着二级索引不能在 UPDATE 查询中使用?

正确的。如果不指定完整的 PRIMARY KEY,就无法在 Cassandra 中执行 UPSERT。即使具有部分 PRIMARY KEY 的 UPSERT 也不起作用。并且(正如您所发现的)通过索引值进行 UPSERTing 也不起作用。

当一张票的所有事件都应该移动到另一张票时,我该如何解决这个问题?

events不幸的是,实现这一点的唯一方法是通过这些键查询(使用特定的ticket_id)和 UPSERT中每一行的ticket_id键。好消息是您不必首先使用DELETE它们,因为ticket_id它不是 PRIMARY KEY 的一部分。

当一张票的所有事件都应该移动到另一张票时,我该如何解决这个问题?

我认为您最好的计划是一起放弃二级索引,并创建一个查询表以与您的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_idbucket和。这将为您提供在您的表上timestamp进行 UPSERT 更新所需的信息。ticket_idevents

然后,您还可以执行DELETEby ticket_id(在eventsbyticketid桌子上)。Cassandra 确实允许DELETE使用部分 PRIMARY KEY 进行操作,只要您拥有完整的分区键 ( ticket_id)。所以从查询表中删除 old ticket_ids 会很容易。为了确保写入原子性,您可以将 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列名称。

于 2015-05-11T14:15:34.970 回答
1

您可以使用二级索引查询旧票的事件,然后使用这些检索到的事件中的主键来更新事件。

我不确定您为什么需要手动执行此操作,这似乎是 Cassandra 应该能够在后台执行的操作。

于 2015-05-11T13:58:38.933 回答