Spark Cassandra Connector:用于理解错误(类型不匹配)

时间:2016-03-30 19:53:18

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

问题

也许这是由于我缺乏Scala知识,但似乎为添加另一个级别来理解应该可以正常工作。如果第一个 for comprehension 行已注释掉,则代码可以正常工作。我最终想要一个Set [Int]而不是'1到2',但它可以显示问题。 for 的前两行不需要类型说明符,但我包含它以表明我已尝试过显而易见的。

工具/罐

  • IntelliJ 2016.1
  • Java 8
  • Scala 2.10.5
  • Cassandra 3.x
  • spark-assembly-1.6.0-hadoop2.6.0.jar(预建)
  • spark-cassandra-connector_2.10-1.6.0-M1-SNAPSHOT.jar(预建)
  • spark-cassandra-connector-assembly-1.6.0-M1-SNAPSHOT.jar(我建)

代码

case class NotifHist(intnotifhistid:Int, eventhistids:Seq[Int], yosemiteid:String, initiatorname:String)
case class NotifHistSingle(intnotifhistid:Int, inteventhistid:Int, dataCenter:String, initiatorname:String)

object SparkCassandraConnectorJoins {
  def joinQueryAfterMakingExpandedRdd(sc:SparkContext, orgNodeId:Int) {

  val notifHist:RDD[NotifHistSingle] = for {
    orgNodeId:Int <- 1 to 2   // comment out this line and it works
    notifHist:NotifHist <- sc.cassandraTable[NotifHist](keyspace, "notifhist").where("intorgnodeid = ?", orgNodeId)
    eventHistId <- notifHist.eventhistids
  } yield NotifHistSingle(notifHist.intnotifhistid, eventHistId, notifHist.yosemiteid, notifHist.initiatorname)
  ...etc...
 }

编译输出

Information:3/29/16 8:52 AM - Compilation completed with 1 error and 0 warnings in 1s 507ms
       /home/jpowell/Projects/SparkCassandraConnector/src/com/mir3/spark/SparkCassandraConnectorJoins.scala
**Error:(88, 21) type mismatch;
 found   : scala.collection.immutable.IndexedSeq[Nothing]
 required: org.apache.spark.rdd.RDD[com.mir3.spark.NotifHistSingle]
      orgNodeId:Int <- 1 to 2
                    ^**

后来

@slouc感谢您的全面解答。我正在使用 for comprehension的语法糖来保持第二个语句中的状态以填充NotifHistSingle ctor中的元素,所以我没有看到如何使等效的map / flatmap工作。因此,我采用了以下解决方案:

def joinQueryAfterMakingExpandedRdd(sc:SparkContext, orgNodeIds:Set[Int]) {

  def notifHistForOrg(orgNodeId:Int): RDD[NotifHistSingle] = {
    for {
      notifHist <- sc.cassandraTable[NotifHist](keyspace, "notifhist").where("intorgnodeid = ?", orgNodeId)
      eventHistId <- notifHist.eventhistids
    } yield NotifHistSingle(notifHist.intnotifhistid, eventHistId, notifHist.yosemiteid, notifHist.initiatorname)
  }
  val emptyTable:RDD[NotifHistSingle] = sc.emptyRDD[NotifHistSingle]
  val notifHistForAllOrgs:RDD[NotifHistSingle] = orgNodeIds.foldLeft(emptyTable)((accum, oid) => accum ++ notifHistForOrg(oid))
}

1 个答案:

答案 0 :(得分:0)

理解实际上是语法糖;下面真正发生的是一系列链式flatMap次调用,最后一个map替换yield。 Scala编译器会像这样翻译所有的理解。如果您在理解中使用if条件,则会将它们转换为过滤器,如果不产生任何内容,则使用foreach。有关详细信息,请参阅here

所以,要解释你的情况 - 这个:

val notifHist:RDD[NotifHistSingle] = for {
  orgNodeId:Int <- 1 to 2   // comment out this line and it works
  notifHist:NotifHist <- sc.cassandraTable[NotifHist](keyspace, "notifhist").where("intorgnodeid = ?", orgNodeId)
  eventHistId <- notifHist.eventhistids
} yield NotifHistSingle(...)

实际上是由编译器翻译成的:

val notifHist:RDD[NotifHistSingle] = (1 to 2)
  .flatMap(x => sc.cassandraTable[NotifHist](keyspace, "notifhist").where("intorgnodeid = ?", x)
  .flatMap(x => x.eventhistids)
  .map(x => NotifHistSingle(...))

如果包含1 to 2行,则会收到错误,因为这会使您的理解对序列进行操作(向量,更准确)。因此,在调用flatMap()时,编译器希望您跟进一个将向量的每个元素转换为GenTraversableOnce的函数。如果你仔细看看你的表达式的类型(大多数IDE只是悬停在它上面显示它),你可以自己看看:

def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That

这就是问题所在。编译器不知道如何使用返回flatMap的函数1 to 10向量CassandraRDD。它需要一个返回GenTraversableOnce的函数。如果您删除1 to 2行,则会删除此限制。

底线 - 如果你想使用for comprehension并从中获得屈服值,你必须遵守类型规则。不可能使由不是序列的元素组成的序列变平并且不能变成序列。

您可以随时map代替flatMap,因为地图限制较少(需要A => B而不是A => GenTraversableOnce[B])。这意味着您将得到一个序列,其中每个元素都是一组结果(每个查询一个组),而不是将所有结果都放在一个巨大的序列中。你也可以玩这些类型,尝试从你的查询结果中获取GenTraversableOnce(例如调用sc.cassandraTable().where().toArray或者其他东西;我真的不和Cassandra合作,所以我不知道。)