日期分区大小10GB有效读取

时间:2019-07-11 12:52:43

标签: apache-spark-sql datastax cassandra-3.0

我们正在使用Cassandra DataStax 6.0和启用了Spark。我们每天都会有10GB的数据。所有查询均基于日期。我们有一张巨大的桌子,有40列。我们计划使用Spark生成报告。设置此数据的最佳方法是什么。由于我们每天都在获取数据,并将数据保存在一张表中大约一年。

我们尝试使用不同的分区,但是我们的大多数键都是基于日期的。

没有代码只需要建议

我们的查询应该足够快。我们有9个节点的256GB Ram。 44核CPU。

1 个答案:

答案 0 :(得分:1)

将数据组织在日常分区中并不是一个很好的设计-在这种情况下,只有RF节点在白天写入数据时才处于活动状态,然后在生成报表时就处于活动状态。

由于您将仅从Spark访问数据,因此可以使用以下方法-将一些存储桶字段用作分区键,例如,使用统一生成的随机数,并将时间戳作为聚类列,也许还有{ 1}}列,以确保记录的唯一性,例如:

uuid

应该选择create table test.sdtest ( b int, ts timestamp, uid uuid, v1 int, primary key(b, ts, uid)); 的生成最大值,以使分区没有太大和很小,以便我们可以有效地读取它们。

然后我们可以像这样运行Spark代码:

b

这里的窍门是我们使用随机分区键在节点之间分配数据,因此所有节点将在写入数据和生成报告期间处理负载。

如果我们研究一下该Spark代码的物理计划(为便于阅读而格式化):

import org.apache.spark.sql.cassandra._
val data = spark.read.cassandraFormat("sdtest", "test").load()
val filtered = data.filter("ts >= cast('2019-03-10T00:00:00+0000' as timestamp) AND ts < cast('2019-03-11T00:00:00+0000' as timestamp)")

我们可以看到,这两个条件都将被推到CQL级别的DSE上-这意味着Spark不会将所有数据加载到内存中并对其进行过滤,而是所有过滤都将在Cassandra中进行,而只有必要的数据会返回。而且由于我们在多个节点之间分散请求,因此读取(比对测试)可能比读取一个巨型分区更快(需要测试)。这种设计的另一个好处是,使用Spark可以很容易地执行删除旧数据的操作,如下所示:

== Physical Plan ==
*Scan org.apache.spark.sql.cassandra.CassandraSourceRelation [b#23,ts#24,v1#25] 
PushedFilters: [*GreaterThanOrEqual(ts,2019-03-10 00:00:00.0),
  *LessThan(ts,2019-03-11 00:00:00.0)], ReadSchema: struct<b:int,ts:timestamp,v1:int>

在这种情况下,Spark将执行非常有效的范围/行删除,这将产生更少的逻辑删除。

P.S。建议使用DSE的Spark连接器版本,因为它可能会有更多优化。

P.P.S。从理论上讲,我们可以将val toDel = sc.cassandraTable("test", "sdtest").where("ts < '2019-08-10T00:00:00+0000'") toDel.deleteFromCassandra("test", "sdtest", keyColumns = SomeColumns("b", "ts")) ts合并到一个uid列中,但是我不确定它是否可以与Dataframes一起使用。