Spark Cassandra Connector:SQLContext.read + SQLContext.write与手动解析和插入(JSON - > Cassandra)

时间:2016-07-01 06:52:43

标签: apache-spark cassandra apache-spark-sql spark-dataframe spark-cassandra-connector

早上好,

我刚刚开始调查Apache Spark和Apache Cassandra。第一步是一个真正简单的用例:获取包含例如文件的文件。客户+得分。

Cassandra表的客户为PrimaryKey。 Cassandra只是在本地运行(所以根本没有集群!)。

所以SparkJob(Standalone local [2])正在解析JSON文件,然后将整个内容写入Cassandra。

第一个解决方案是

val conf = new SparkConf().setAppName("Application").setMaster("local[2]")
val sc = new SparkContext(conf)
val cass = CassandraConnector(conf)

val customerScores = sc.textFile(file).cache()

val customerScoreRDD = customerScores.mapPartitions(lines => {
  val mapper = new ObjectMapper with ScalaObjectMapper
  mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
  mapper.registerModule(DefaultScalaModule)
  lines
    .map(line => {
      mapper.readValue(line, classOf[CustomerScore])
    })
    //Filter corrupt ones: empty values
    .filter(customerScore => customerScore.customer != null && customerScore.score != null)
})


customerScoreRDD.foreachPartition(rows => cass.withSessionDo(session => {
  val statement: PreparedStatement = session.prepare("INSERT INTO playground.customer_score (customer,score) VALUES (:customer,:score)")
  rows.foreach(row => {
    session.executeAsync(statement.bind(row.customer.asInstanceOf[Object], row.score))
  })
}))

sc.stop()

表示手动完成所有操作,解析行然后插入Cassandra。

对于10000000条记录,总共需要 714020 ms (包括创建SparkContext等等)。

然后我读到了spark-cassandra-connector并做了以下事情:

val conf = new SparkConf().setAppName("Application").setMaster("local[2]")
val sc = new SparkContext(conf)
var sql = new SQLContext(sc)

val customerScores = sql.read.json(file)

val customerScoresCorrected = customerScores
  //Filter corrupt ones: empty values
  .filter("customer is not null and score is not null")
  //Filter corrupt ones: invalid properties
  .select("customer", "score")

customerScoresCorrected.write
  .format("org.apache.spark.sql.cassandra")
  .mode(SaveMode.Append)
  .options(Map("keyspace" -> "playground", "table" -> "customer_score"))
  .save()

sc.stop()

在所需代码和使用给定API的意义上更简单。

对于10000000条记录,此解决方案大致需要 1232871 ms (同样全部,所以相同的测量点)。

(还有第三个解决方案,手动解析加saveToCassandra 1530877 ms

现在我的问题:

哪种方式是"正确"实现这个用例的方法,哪一个是最佳实践" (现在,在一个真实场景中,聚集的cassandra和spark,表现最好的一个)如今? 由于我的结果,我会使用"手册"而不是SQLContext.read + SQLContext.write

感谢您的意见和提示。

1 个答案:

答案 0 :(得分:0)

实际上在玩了很长时间之后,必须考虑以下事项。

  • 当然数据量
  • 您的数据类型:特别是各种分区键(每个分区键与许多重复项不同)
  • 环境:Spark Executors,Cassandra Nodes,Replication ...

我的UseCase玩

def initSparkContext: SparkContext = {
    val conf = new SparkConf().setAppName("Application").setMaster("local[2]")
        // since we have nearly totally different PartitionKeys, default: 1000
        .set("spark.cassandra.output.batch.grouping.buffer.size", "1")
        // write as much concurrently, default: 5
       .set("spark.cassandra.output.concurrent.writes", "1024")
       // batch same replica, default: partition
       .set("spark.cassandra.output.batch.grouping.key", "replica_set") 
    val sc = new SparkContext(conf)
    sc
}

在我的本地跑步中确实提高了速度。

所以非常需要尝试各种参数来获得最佳方式。至少这是我得到的结论。