subtractByKey修改源RDD中的值

时间:2016-11-23 15:07:11

标签: scala apache-spark

我遇到问题subtractByKey使用Spark 2.0.2和Scala 2.11.x(它还使用Spark 1.6.2和Scala 2.10重现):

相关代码:

object Types {
   type ContentId = Int
   type ContentKey = Tuple2[Int, ContentId]
   type InternalContentId = Int
}

val inverseItemIDMap: RDD[(InternalContentId, ContentKey)] = itemIDMap.map(_.swap).cache()
logger.info(s"Built an inverse map of ${inverseItemIDMap.count()} item IDs")
logger.info(inverseItemIDMap.collect().mkString("I->E ", "\nI->E ", ""))

val superfluousItems: RDD[(InternalContentId, Int)] = .. .cache()
logger.info(superfluousItems.collect().mkString("SI ", "\nSI ", ""))

val filteredInverseItemIDMap: RDD[(InternalContentId, ContentKey)] = 
  inverseItemIDMap.subtractByKey(superfluousItems).cache() // <<===!!!
logger.info(s"${filteredInverseItemIDMap.count()} items in the filtered inverse ID mapping")
logger.info(filteredInverseItemIDMap.collect().mkString("F I->E ", "\nF I->E ", ""))

有问题的操作是.subtractByKey。在调用count()之前,所涉及的两个RDD都会通过subtractByKey进行缓存和强制,因此我希望结果不受superfluousItems的构建方式的影响。

我添加了调试输出,并按相关的InternalContentId值(829911,830071)过滤了生成的日志。输出:

Built an inverse map of 827354 item IDs
.
.
I->E (829911,(2,1135081))
I->E (830071,(1,2295102))
.
.
748190 items in the training set had less than 28 ratings
SI (829911,3)
.
.
79164 items in the filtered inverse ID mapping
F I->E (830071,(2,1135081))

在superfluousItems(SI)中没有关键字830071的元素,因此它不会从源RDD中删除。但是,它的价值由于某种原因被钥匙829911取代。这怎么可能?我无法在本地重现它 - 只有在多机群集上运行时才能重现。这是一个错误还是我错过了什么?

1 个答案:

答案 0 :(得分:1)

问题是我认为缓存和强制RDD保证永远不会重新评估它。 inverseItemIDMap是使用非确定性操作构建的,对它的多次使用也会产生不同的结果:

val itemIDMap: RDD[(ContentKey, InternalContentId)] =
  rawEvents
  .map(_.content)
  .distinct
  .zipWithUniqueId()
  .map(u => (u._1, u._2.toInt))
  .cache()
logger.info(s"Built a map of ${itemIDMap.count()} item IDs")
val inverseItemIDMap: RDD[(InternalContentId, ContentKey)] =
  itemIDMap.map(_.swap).cache()

我通过在.sortBy(c => c)之前添加.zipWithUniqueId()来使操作稳定,这解决了问题。