当从仅某些Cassandra分区检索数据时,是否有替代Spark(Scala)中的DataFrames的joinWithCassandraTable?

时间:2017-04-21 21:48:48

标签: scala apache-spark cassandra spark-cassandra-connector

使用RDD从大型C *表中提取少量分区时,我们可以使用:

val rdd = …  // rdd including partition data
val data = rdd.repartitionByCassandraReplica(keyspace, tableName)
    .joinWithCassandraTable(keyspace, tableName)

我们是否有使用DataFrames同样有效的方法?

更新(2017年4月26日):

更具体一点,我准备了一个例子。

我在Cassandra有两张桌子:

CREATE TABLE ids (
   id text,
   registered timestamp,
   PRIMARY KEY (id)
)

CREATE TABLE cpu_utils (
   id text,
   date text,
   time timestamp,
   cpu_util int,
   PRIMARY KEY (( id, date ), time)
)

第一个包含有效ID列表和第二个cpu利用率数据。我希望有效地获得表 ids 中每个 id 一天的平均cpu利用率,比如说“2017-04-25”。

我所知道的RDD最有效的方法如下:

val sc: SparkContext = ...
val date = "2017-04-25"
val partitions = sc.cassandraTable(keyspace, "ids")
  .select("id").map(r => (r.getString("id"), date))

val data = partitions.repartitionByCassandraReplica(keyspace, "cpu_utils")
  .joinWithCassandraTable(keyspace, "cpu_utils")
  .select("id", "cpu_util").values
  .map(r => (r.getString("id"), (r.getDouble("cpu_util"), 1)))

// aggrData in form: (id, (avg(cpu_util), count))
// example row: ("718be4d5-11ad-4849-8aab-aa563c9c290e",(6,723))
val aggrData = data.reduceByKey((a, b) => (
  1d * (a._1 * a._2 + b._1 * b._2) / (a._2 + b._2), 
  a._2 + b._2))

aggrData.foreach(println)

此方法需要大约5秒钟才能完成(在我的本地计算机上安装Spark,在某些远程服务器上安装Cassandra)。使用它,我在表cpu_utils中的不到1%的分区上执行操作。

使用Dataframes这是我目前使用的方法:

val sqlContext = new SQLContext(sc)
import sqlContext.implicits._
val date = "2017-04-25"

val partitions = sqlContext.read.format("org.apache.spark.sql.cassandra")
  .options(Map("table" -> "ids", "keyspace" -> keyspace)).load()
  .select($"id").withColumn("date", lit(date))

val data: DataFrame = sqlContext.read.format("org.apache.spark.sql.cassandra")
  .options(Map("table" -> "cpu_utils", "keyspace" -> keyspace)).load()
  .select($"id", $"cpu_util", $"date")

val dataFinal = partitions.join(data, partitions.col("id").equalTo(data.col("id")) and partitions.col("date").equalTo(data.col("date")))
  .select(data.col("id"), data.col("cpu_util"))
  .groupBy("id")
  .agg(avg("cpu_util"), count("cpu_util"))

dataFinal.show()

然而,这种方法似乎将整个表cpu_utils加载到内存中,因为这里的执行时间相当长(差不多1分钟)。

我在问是否有更好的方法使用Dataframes,如果表现不如上面提到的RDD方法那么至少可以达到?

P.s。:我正在使用Spark 1.6.1。

0 个答案:

没有答案