- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我们正在使用 Cassandra 解决的用例是这样的:我们需要检索在过去 90 天内在特定时间范围内更新的实体 UUID 列表。想象一下,我们正在构建一个文档跟踪系统,因此我们的相关实体是一个文档,其键是一个 UUID。
我们需要在此用例中支持的查询是:查找在 StartDateTime 和 EndDateTime 之间更改的所有文档 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 驱动程序 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 个?好吧,当我在我的 SELECT 中包含 token(event_uuid)
时,答案就很明显了:
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 按散列 token 值顺序存储分区键(event_uuid
)。你可以在使用 token
函数时看到这一点。 Cassandra 使用名为 consistent hashing 的进程生成分区 token 保证集群分布均匀。换句话说,除非实际(散列) token 值对您的应用程序有意义,否则按 token 范围查询没有意义。
回到您的第一个问题,这意味着您将必须找到不同的列进行分区。我的建议是使用一种称为“日期桶”的时间序列机制。选择日期桶可能会很棘手,因为它取决于您的要求和查询模式……所以这真的取决于您选择一个有用的桶。
出于本示例的目的,我将选择“月份”。因此,我将在 month
重新创建您的表分区并按 event_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
可能不适用于您的应用程序。因此,想一想想出一个合适的列进行分区,然后您应该能够解决这个问题。
关于java - Cassandra:使用 DataStax Java 驱动程序选择一系列 TimeUUID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30388311/
我们有 2 个 cassandra 集群,第一个有旧数据,第二个有新数据。 现在我们想要将旧数据从第一个集群移动或复制到第二个集群。什么是最好的方法来做到这一点以及如何做到这一点? 我们正在使用 DS
我正在考虑安装 OpsCenter 来监控我们在 RackSpace VM 上运行的 24 节点 Cassandra 集群。过去我听说 OpsCenter 减慢了集群速度。我有点担心 OpsCente
假设我有一个复制因子(RF)= 2 的 2 节点集群。 我使用一致性 2 触发插入。当客户端等待响应时,Cassandra 开始写入这 2 个节点。中间一个节点失败,无法完成写入,而另一节点上的写入成
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足 Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以
我在 Cassandra 中有一个表,其中我用 1000 多个条目填充了一些行(每行有 10000 多列)。行中的条目更新非常频繁,基本上只是一个字段(它是一个整数)被更新为不同的值。列的所有其他值保
当Cassandra端有“掉落的突变”时,它是否向调用客户端返回相应的失败?或者即使在服务器端丢弃相应的突变并导致数据丢失,它总是成功响应调用事务的调用客户端? 在一个特定实例中,当我们的 TPS 约
我有一个 Multi-Tenancy 应用程序,其中 tenantId 将成为每个查询的一部分,因此我将其放入所有表的分区键中。 例子: CREATE TABLE users { tenantId t
根据 Datastax 文档,在 Cassandra 中先读后写是一种反模式。 每当我们在 CQLSH 中使用 UPDATE 或使用 Datastax 驱动程序来设置几列(带有 IF 和集合更新)时,
是否有命令或任何方式可以知道 Cassandra 的哪些节点上存储了哪些数据? 我对 Cassandra 很陌生,在谷歌上搜索这个问题并没有多少运气。 谢谢! 最佳答案 您可以使用 nodetool
我们有一个包含 1500 万条记录的表,而我们的表是一个 10 节点的 cassandra 集群。我们有一列有接近 20 个可重复值。是否建议在此列上建立二级索引? 最佳答案 假设在该列上完全均匀分布
Cassandra 发布了它的 technical limitations但没有提到允许的最大列数。是否有最大列数?我需要存储 400 多个字段。这在 Cassandra 中可能吗? 最佳答案 每行的
我想知道当表中有多个非 PK 列时会发生什么。我读过这个例子: http://johnsanda.blogspot.co.uk/2012/10/why-i-am-ready-to-move-to-cq
我有两个关于 Cassandra 查询结果的问题。 当我在 Cassandra 中对表进行“完全”选择(即 select * from table )时,是否保证结果将按分区标记的递增顺序返回? 例如
我无法为 Cassandra 设置 Hector。我已经浏览了 documentation和 Cassandra wiki .这些文档的问题在于,那里的很多信息都已经过时或过时(或者我缺乏知识)。无论
我正在使用 DataStax Enterprise 中 cassandra 中提供的压力测试。如果有人知道的话,我也想要一些关于它和 cassandra 的信息。 - 首先,压力测试使用哪些节点?我的
当我在 CQL 中创建表时,列的顺序是否必须精确 不是 在主键和 中不是 聚类列: CREATE TABLE user ( a ascii, b ascii, c ascii,
我有一张如下表: CREATE TABLE tab( categoryid text, id text, name text, author text, des
我正在尝试学习 Cassandra,但对术语感到困惑。 很多情况下它表示该行存储键/值对。 但是,当我定义一个表时,它更像是声明一个 SQL 表,即;您创建一个表并指定列名和数据类型。 谁能澄清一下?
如何对 cassandra 数据实现审计? 我正在寻找一个开源选项。 cassandra 是否有任何有助于审计的功能? 我可以使用触发器将记录记录到表中吗?我关注了 Triggers示例并且能够将记录
我遇到了一个问题“me.prettyprint.hector.api.exceptions.HUnavailableException:: 可能没有足够的副本来处理一致性级别。”当我有 RF=1 时,
我是一名优秀的程序员,十分优秀!