Cassandra:使用DataStax Java驱动程序选择一系列TimeUUID

彼得

我们正在与Cassandra一起解决的用例是:我们需要检索在过去90天内的特定时间范围内已更新的实体UUID的列表。假设我们正在构建一个文档跟踪系统,那么我们的相关实体是一个文档,其密钥是一个UUID。

在此用例中,我们需要支持的查询是:查找在StartDateTime和EndDateTime之间更改的所有Document UUID。

问题1:什么是支持此查询的最佳Cassandra表设计?

我认为答案如下:

CREATE TABLE document_change_events (
    event_uuid TIMEUUID,
    document_uuid uuid,
    PRIMARY KEY ((event_uuid), document_uuid)
) WITH default_time_to_live='7776000';

考虑到我们无法对分区键进行范围查询,我们需要使用该token()方法。这样,查询将是:

SELECT document_uuid 
 WHERE token(event_uuid) > token(minTimeuuid(?)) 
   AND token(event_uuid) < token(maxTimeuuid(?))

例如:

SELECT document_uuid 
 WHERE token(event_uuid) > token(minTimeuuid('2015-05-10 00:00+0000')) 
   AND token(event_uuid) < token(maxTimeuuid('2015-05-20 00:00+0000'))

问题2:我似乎无法使用DataStax的驱动程序获得以下Java代码来可靠地返回正确的结果。

如果我将以下代码运行10次,每次间隔30秒,则此表中将有10行:

private void addEvent() {

    String cql = "INSERT INTO document_change_events (event_uuid, document_uuid) VALUES(?,?)";

    PreparedStatement preparedStatement = cassandraSession.prepare(cql);
    BoundStatement boundStatement = new BoundStatement(preparedStatement);
    boundStatement.setConsistencyLevel(ConsistencyLevel.ANY);

    boundStatement.setUUID("event_uuid", UUIDs.timeBased());
    boundStatement.setUUID("document_uuid", UUIDs.random());

    cassandraSession.execute(boundStatement);

}

结果如下:

cqlsh:> select event_uuid, dateOf(event_uuid), document_uuid from document_change_events;

 event_uuid                           | dateOf(event_uuid)       | document_uuid
--------------------------------------+--------------------------+--------------------------------------
 414decc0-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:51:09-0500 | 92b6fb6a-9ded-47b0-a91c-68c63f45d338
 9abb4be0-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:53:39-0500 | 548b320a-10f6-409f-a921-d4a1170a576e
 6512b960-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:52:09-0500 | 970e5e77-1e07-40ea-870a-84637c9fc280
 53307a20-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:51:39-0500 | 11b4a49c-b73d-4c8d-9f88-078a6f303167
 ac9e0050-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:54:10-0500 | b29e7915-7c17-4900-b784-8ac24e9e72e2
 88d7fb30-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:53:09-0500 | c8188b73-1b97-4b32-a897-7facdeecea35
 0ba5cf70-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:49:39-0500 | a079b30f-be80-4a99-ae0e-a784d82f0432
 76f56dd0-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:52:39-0500 | 3b593ca6-220c-4a8b-8c16-27dc1fb5adde
 1d88f910-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:50:09-0500 | ec155e0b-39a5-4d2f-98f0-0cd7a5a07ec8
 2f6b3850-0014-11e5-93a9-51f9a7931084 | 2015-05-21 18:50:39-0500 | db42271b-04f2-45d1-9ae7-0c8f9371a4db

(10 rows)

但是如果我随后运行此代码:

private static void retrieveEvents(Instant startInstant, Instant endInstant) {

    String cql = "SELECT document_uuid FROM document_change_events " + 
                 "WHERE token(event_uuid) > token(?) AND token(event_uuid) < token(?)";

    PreparedStatement preparedStatement = cassandraSession.prepare(cql);
    BoundStatement boundStatement = new BoundStatement(preparedStatement);
    boundStatement.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);

    boundStatement.bind(UUIDs.startOf(Date.from(startInstant).getTime()),
                        UUIDs.endOf(Date.from(endInstant).getTime()));

    ResultSet resultSet = cassandraSession.execute(boundStatement);

    if (resultSet == null) {
      System.out.println("None found.");
      return;
    }

    while (!resultSet.isExhausted()) {
      System.out.println(resultSet.one().getUUID("document_uuid"));
    }

}

它仅检索三个结果:

3b593ca6-220c-4a8b-8c16-27dc1fb5adde
ec155e0b-39a5-4d2f-98f0-0cd7a5a07ec8
db42271b-04f2-45d1-9ae7-0c8f9371a4db

为什么没有检索全部10个结果?为了支持此用例,我需要进行哪些更改才能获得正确的结果?

作为参考,我已经针对dsc-2.1.1,dse-4.6和使用DataStax Java Driver v2.1.6对此进行了测试。

亚伦

首先,请一次只问一个问题。您在这里的两个问题都可以很容易地独立解决。我知道这些是相关的,但这只会使读者对tl; dr感到失望

我将首先回答您的第二个问题,因为答案与对数据模型正确设置至关重要的基本理解有关。当我插入您的行并运行以下查询时,这就是我得到的:

aploetz@cqlsh:stackoverflow2> SELECT document_uuid FROM document_change_events 
WHERE token(event_uuid) > token(minTimeuuid('2015-05-10 00:00-0500')) 
  AND token(event_uuid) < token(maxTimeuuid('2015-05-22 00:00-0500'));

 document_uuid
--------------------------------------
 a079b30f-be80-4a99-ae0e-a784d82f0432
 3b593ca6-220c-4a8b-8c16-27dc1fb5adde
 ec155e0b-39a5-4d2f-98f0-0cd7a5a07ec8
 db42271b-04f2-45d1-9ae7-0c8f9371a4db

(4 rows)

这与您所看到的相似。那为什么不归还全部10个呢?好吧,当我将token(event_uuid)SELECT包括在内时,答案就显而易见了

aploetz@cqlsh:stackoverflow2> SELECT token(event_uuid),document_uuid FROM document_change_events WHERE token(event_uuid) > token(minTimeuuid('2015-05-10 00:00-0500')) AND token(event_uuid) < token(maxTimeuuid('2015-05-22 00:00-0500'));

 token(event_uuid)    | document_uuid
----------------------+--------------------------------------
 -2112897298583224342 | a079b30f-be80-4a99-ae0e-a784d82f0432
  2990331690803078123 | 3b593ca6-220c-4a8b-8c16-27dc1fb5adde
  5049638908563824288 | ec155e0b-39a5-4d2f-98f0-0cd7a5a07ec8
  5577339174953240576 | db42271b-04f2-45d1-9ae7-0c8f9371a4db

(4 rows)

Cassandra(event_uuid按您的情况)按其哈希标记值顺序存储分区键使用该token功能时,您可以看到此信息Cassandra通过称为一致性哈希的过程生成分区令牌,以确保均匀的群集分布。换句话说,除非实际的(散列的)令牌值对您的应用有意义,否则按令牌范围进行查询是没有意义的。

回到第一个问题,这意味着您将不得不找到另一列进行分区。我的建议是使用一种称为“日期存储桶”的时间序列机制。选择日期存储区可能很棘手,因为它取决于您的要求和查询模式...因此,实际上要由您选择一个有用的日期存储区。

出于本示例的目的,我将选择“月”。因此,我将在monthevent_uuid上重新创建表分区并进行集群:

CREATE TABLE document_change_events2 (
    event_uuid TIMEUUID,
    document_uuid uuid,
    month text,
    PRIMARY KEY ((month),event_uuid, document_uuid)
) WITH default_time_to_live='7776000';

现在,我还可以按日期范围进行查询,同时还可以按month

aploetz@cqlsh:stackoverflow2> SELECT document_uuid FROM document_change_events2 
WHERE month='201505'
  AND event_uuid > minTimeuuid('2015-05-10 00:00-0500')
  AND event_uuid < maxTimeuuid('2015-05-22 00:00-0500');

 document_uuid
--------------------------------------
 a079b30f-be80-4a99-ae0e-a784d82f0432
 ec155e0b-39a5-4d2f-98f0-0cd7a5a07ec8
 db42271b-04f2-45d1-9ae7-0c8f9371a4db
 92b6fb6a-9ded-47b0-a91c-68c63f45d338
 11b4a49c-b73d-4c8d-9f88-078a6f303167
 970e5e77-1e07-40ea-870a-84637c9fc280
 3b593ca6-220c-4a8b-8c16-27dc1fb5adde
 c8188b73-1b97-4b32-a897-7facdeecea35
 548b320a-10f6-409f-a921-d4a1170a576e
 b29e7915-7c17-4900-b784-8ac24e9e72e2

(10 rows)

同样,month可能不适用于您的应用程序。因此,请想出一个合适的列进行分区,然后应该可以解决此问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在使用Datastax Cassandra驱动程序时是否重新使用PreparedStatement?

Cassandra Datastax驱动程序-连接池

cassandra datastax驱动程序抛出的写入超时

使用Datastax驱动程序3.6的Cassandra分页:不支持空分页状态和获取大小

datastax cassandra java驱动程序PlainTextAuthProvider示例

如何在Cassandra中使用Datastax Java驱动程序有效地使用准备好的语句?

Datastax Java Cassandra驱动程序:使用WHERE的多个AND语句?

如何使用Datastax Java驱动程序有效地使用批写入Cassandra?

如何使用DataStax Java驱动程序设置Cassandra客户端到节点的加密?

使用Datastax Java驱动程序无法通过Cassandra的UDT密钥检索

无法使用DataStax C#驱动程序从Cassandra获取值

Datastax Cassandra Java驱动程序的Accessor是否使用分页?

使用Cassandra的datastax Java驱动程序中的别名可链接便捷方法选择特定列以及avg和max

使用datastax驱动程序检索有关Cassandra集群数据中心的信息

如何使用datastax驱动程序创建Cassandra连接池

Datastax Node.js Cassandra驱动程序何时使用映射器与查询

如何使用带有Datastax Java驱动程序的CQL向Cassandra添加任意列?

Datastax C#驱动程序中的Cassandra timeuuid

Cassandra DataStax驱动程序:如何分页浏览

使用DataStax C#驱动程序处理Cassandra中的所有节点

使用DataStax C#驱动程序时故障转移不适用于Cassandra

Datastax-Cassandra PHP驱动程序-执行CQL脚本

带分页的Datastax Cassandra Java驱动程序RetryPolicy

Cassandra模型的CQL(datastax驱动程序:python)

如何使用 C# Datastax 驱动程序删除 Cassandra 上的表?

无法使用 Cassandra Datastax Java 驱动程序连接到 Cassandra 节点之一

Cassandra ODBC Datastax 在 Windows 中与 Cassandra 2.1 但不是 3.0 一起使用

使用 Datastax Cassandra 驱动程序时出现无效类型错误

Nodejs - Apache Cassandra(使用 Datastax 驱动程序)