从n个可能元素中获取3个值的所有可能组合

时间:2016-11-03 12:36:11

标签: scala apache-spark

我试图从30个项目的列表中获取3个元素的所有可能组合的列表。我尝试使用以下代码,但它无法抛出OutOfMemoryError。有没有比这更有效的替代方法?

val items = sqlContext.table(SOURCE_DB + "." + SOURCE_TABLE).
  select("item_id").distinct.cache

val items.take(1) // Compute cache before join

val itemCombinations = items.select($"item_id".alias("id_A")).
  join(
    items.select($"item_id".alias("id_B")), $"id_A".lt($"id_B")).
    join(
      items.select($"item_id".alias("id_C")), $"id_B".lt($"id_C"))

1 个答案:

答案 0 :(得分:3)

这种方法似乎没问题,但可能会在查询执行级别产生一些开销。假设n是一个相当小的数字,我们可以直接使用Scala实现:

val localItems = items.collect
val combinations = localItems.combinations(3)

结果是iterator,当时可以使用一个元素,而不会产生大量的内存开销。

Spark版本(编辑)

鉴于希望制作Spark版本,可以通过降低到RDD级别来避免查询规划器(假设存在问题)。这基本上与问题中的连接表达式相同:

val items = sqlContext.table(SOURCE_DB + "." + SOURCE_TABLE).select("item_id").rdd

val combinations = items.cartesian(items).filter{case(x,y) => x<y}.cartesian(items).filter{case ((x,y),z) => y<z}

在我的本地计算机上运行等效代码:

val data = List.fill(1000)(scala.util.Random.nextInt(999))
val rdd = sparkContext.parallelize(data)
val combinations = rdd.cartesian(rdd).filter{case(x,y) => x<y}.cartesian(rdd).filter{case ((x,y),z) => y<z}

combinations.count
// res5: Long = 165623528