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