You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala篮子Map的重叠关联计算及Spark实现技术咨询

使用Spark计算购物篮的关联购物篮集合

当然可以用Spark实现这个需求!下面我会一步步拆解思路,给出可运行的Scala代码示例,完全匹配你想要的输出结果。

核心思路

要找到每个购物篮的关联篮(有至少一个共同商品的其他购物篮),核心是先建立「商品→购物篮」的反向映射,这样就能快速定位所有共享同一商品的购物篮,再通过聚合去重得到最终结果:

  1. 将原购物篮数据展开为「购物篮ID→商品ID」的扁平结构
  2. 反转映射为「商品ID→关联购物篮集合」
  3. 对每个商品的购物篮集合生成所有有效两两组合(排除自身)
  4. 聚合每个购物篮的所有关联篮并去重
  5. 补全无关联篮的购物篮(比如示例中的b4)

完整代码实现

1. 初始化SparkSession

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._

// 本地模式初始化,生产环境可去掉master配置
val spark = SparkSession.builder()
  .appName("BasketIntersectionCalculator")
  .master("local[*]")
  .getOrCreate()

import spark.implicits._

2. 加载输入数据

// 你的示例输入数据
val basketData = Map(
  "b1" -> Set("i1", "i2", "i3"),
  "b2" -> Set("i2", "i4"),
  "b3" -> Set("i3", "i5"),
  "b4" -> Set("i6")
)

// 转换为Spark DataFrame:(basket_id, item_id)
val basketDF = basketData.toList.flatMap { case (basketId, items) =>
  items.map(item => (basketId, item))
}.toDF("basket_id", "item_id")

3. 核心计算逻辑

// 步骤1:按商品分组,得到每个商品对应的所有购物篮
val itemToBasketsDF = basketDF.groupBy("item_id")
  .agg(collect_set("basket_id").alias("basket_ids"))

// 步骤2:生成每个商品关联购物篮的有效两两组合(排除自身)
val basketPairsDF = itemToBasketsDF.flatMap { row =>
  val baskets = row.getAs[Seq[String]]("basket_ids")
  baskets.flatMap(sourceBasket => 
    baskets.filter(_ != sourceBasket).map(relatedBasket => (sourceBasket, relatedBasket))
  )
}.toDF("source_basket", "related_basket")

// 步骤3:聚合得到每个购物篮的去重关联篮集合
val relatedBasketsDF = basketPairsDF.groupBy("source_basket")
  .agg(collect_set("related_basket").alias("intersect_baskets"))

// 步骤4:补全无关联篮的购物篮(确保所有原始购物篮都出现在结果中)
val allBasketsDF = basketData.keys.toList.toDF("basket_id")
val finalResultDF = allBasketsDF.join(
  relatedBasketsDF,
  allBasketsDF("basket_id") === relatedBasketsDF("source_basket"),
  "left_outer"
).select(
  allBasketsDF("basket_id"),
  coalesce(col("intersect_baskets"), array().cast("array<string>")).alias("intersect_baskets")
)

4. 转换为目标Map格式

// 将DataFrame结果转换为你需要的Map[String, Set[String]]
val intersects = finalResultDF.collect().map { row =>
  val basketId = row.getAs[String]("basket_id")
  val relatedBaskets = row.getAs[Seq[String]]("intersect_baskets").toSet
  (basketId -> relatedBaskets)
}.toMap

// 打印验证结果
println(intersects)
// 输出:Map(b1 -> Set(b2, b3), b2 -> Set(b1), b3 -> Set(b1), b4 -> Set())

额外说明

  • 这个方案是分布式计算,适合处理大规模的购物篮数据(远超出单机内存的量级),如果你的数据已经存储在HDFS、S3等分布式存储上,直接读取即可,无需先转换成本地Map
  • 如果购物篮数量极大,生成两两组合时可能会有性能瓶颈,可以考虑用广播变量优化商品到购物篮的映射,或者调整分区数提升并行度

内容的提问来源于stack exchange,提问作者tyjchen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 22:57:33