Cassandra datastax驱动程序ResultSet在多个线程中共享以便快速读取

时间:2015-05-06 09:52:35

标签: cassandra cassandra-2.0 datastax-java-driver

我在cassandra有很多桌子,超过20亿行并且还在增加。行有一个日期字段,它遵循日期桶模式,以限制每一行。

即便如此,我在特定日期的参赛作品超过一百万。

我希望尽快阅读并处理每一天的行。我正在做的是获取com.datastax.driver.core.ResultSet的实例并从中获取迭代器并在多个线程之间共享该迭代器。

所以,基本上我想增加读取吞吐量。这是正确的方法吗?如果没有,请建议更好的方法。

1 个答案:

答案 0 :(得分:6)

很遗憾,你不能这样做。原因是ResultSet提供了internal paging state,用于一次检索第1行。

但你确实有选择。由于我认为您正在进行范围查询(跨多个分区的查询),因此您可以使用策略,使用token指令一次跨令牌范围提交多个查询。 Paging through unordered partitioner results中记录了一个很好的例子。

java-driver 2.0.10和2.1.5各自提供了一种从主机和splitting them检索令牌范围的机制。在TokenRangeIntegrationTest.java#should_expose_token_ranges()的java-driver集成测试中有一个如何执行此操作的示例:

    PreparedStatement rangeStmt = session.prepare("SELECT i FROM foo WHERE token(i) > ? and token(i) <= ?");

    TokenRange foundRange = null;
    for (TokenRange range : metadata.getTokenRanges()) {
        List<Row> rows = rangeQuery(rangeStmt, range);
        for (Row row : rows) {
            if (row.getInt("i") == testKey) {
                // We should find our test key exactly once
                assertThat(foundRange)
                    .describedAs("found the same key in two ranges: " + foundRange + " and " + range)
                    .isNull();
                foundRange = range;
                // That range should be managed by the replica
                assertThat(metadata.getReplicas("test", range)).contains(replica);
            }
        }
    }
    assertThat(foundRange).isNotNull();
}
...
private List<Row> rangeQuery(PreparedStatement rangeStmt, TokenRange range) {
    List<Row> rows = Lists.newArrayList();
    for (TokenRange subRange : range.unwrap()) {
        Statement statement = rangeStmt.bind(subRange.getStart(), subRange.getEnd());
        rows.addAll(session.execute(statement).all());
    }
    return rows;
}

您基本上可以生成语句并以异步方式提交它们,上面的示例只是一次迭代语句。

另一种选择是使用spark-cassandra-connector,它基本上是以封面和非常有效的方式做到这一点。我发现它很容易使用,你甚至不需要设置一个火花簇来使用它。有关如何使用Java API的信息,请参阅this document