Apache spark Spark-将字符串ID转换为唯一的整数ID
我有一个类似这样的数据集,其中每个用户和产品ID都是一个字符串:Apache spark Spark-将字符串ID转换为唯一的整数ID,apache-spark,Apache Spark,我有一个类似这样的数据集,其中每个用户和产品ID都是一个字符串: userA, productX userA, productX userB, productY 拥有约280万产品和3亿用户;大约21亿用户产品协会 我的最终目标是在这个数据集上运行Spark collaborative filtering(ALS)。因为它为用户和产品使用int键,所以我的第一步是为每个用户和产品分配一个唯一的int,并转换上面的数据集,以便用户和产品由int表示 以下是我迄今为止所尝试的: val rawIn
userA, productX
userA, productX
userB, productY
拥有约280万产品和3亿用户;大约21亿用户产品协会
我的最终目标是在这个数据集上运行Spark collaborative filtering(ALS)。因为它为用户和产品使用int键,所以我的第一步是为每个用户和产品分配一个唯一的int,并转换上面的数据集,以便用户和产品由int表示
以下是我迄今为止所尝试的:
val rawInputData = sc.textFile(params.inputPath)
.filter { line => !(line contains "\\N") }
.map { line =>
val parts = line.split("\t")
(parts(0), parts(1)) // user, product
}
// find all unique users and assign them IDs
val idx1map = rawInputData.map(_._1).distinct().zipWithUniqueId().cache()
// find all unique products and assign IDs
val idx2map = rawInputData.map(_._2).distinct().zipWithUniqueId().cache()
idx1map.map{ case (id, idx) => id + "\t" + idx.toString
}.saveAsTextFile(params.idx1Out)
idx2map.map{ case (id, idx) => id + "\t" + idx.toString
}.saveAsTextFile(params.idx2Out)
// join with user ID map:
// convert from (userStr, productStr) to (productStr, userIntId)
val rev = rawInputData.cogroup(idx1map).flatMap{
case (id1, (id2s, idx1s)) =>
val idx1 = idx1s.head
id2s.map { (_, idx1)
}
}
// join with product ID map:
// convert from (productStr, userIntId) to (userIntId, productIntId)
val converted = rev.cogroup(idx2map).flatMap{
case (id2, (idx1s, idx2s)) =>
val idx2 = idx2s.head
idx1s.map{ (_, idx2)
}
}
// save output
val convertedInts = converted.map{
case (a,b) => a.toInt.toString + "\t" + b.toInt.toString
}
convertedInts.saveAsTextFile(params.outputPath)
当我尝试在集群(40个执行器,每个执行器有5 GB RAM)上运行此操作时,它能够很好地生成idx1map和idx2map文件,但是它失败了,没有内存不足错误,并且在cogroup之后的第一个平面图上获取失败。我以前在Spark方面做得不多,所以我想知道是否有更好的方法来实现这一点;我不知道这项工作的哪些步骤会很昂贵。当然,cogroup需要在整个网络上洗牌整个数据集;但是像这样的事情意味着什么呢
FetchFailed(BlockManagerId(25, ip-***.ec2.internal, 48690), shuffleId=2, mapId=87, reduceId=25)
我之所以不使用散列函数,是因为我最终希望在更大的数据集上运行它(大约10亿个产品、10亿个用户、350亿个关联),Int键冲突的数量将变得相当大。在如此规模的数据集上运行ALS是否更接近可行?我看你基本上是在收集所有用户列表,只是为了再次将它们拆分。试着使用join而不是cogroup,在我看来,这更像是你想要的。例如:
import org.apache.spark.SparkContext._
// Create some fake data
val data = sc.parallelize(Seq(("userA", "productA"),("userA", "productB"),("userB", "productB")))
val userId = sc.parallelize(Seq(("userA",1),("userB",2)))
val productId = sc.parallelize(Seq(("productA",1),("productB",2)))
// Replace userName with ID's
val userReplaced = data.join(userId).map{case (_,(prod,user)) => (prod,user)}
// Replace product names with ID's
val bothReplaced = userReplaced.join(productId).map{case (_,(user,prod)) => (user,prod)}
// Check results:
bothReplaced.collect()) // Array((1,1), (1,2), (2,2))
请对它的表现发表评论
(我不知道FetchFailed(…)是什么意思)我的平台版本:CDH:5.7,Spark:1.6.0/StandAlone 我的测试数据大小:31815167所有数据;31562704个不同的用户字符串,4140276个不同的产品字符串
- 驱动程序:2G,2个cpu李>
- 执行器:(8G,4个cpu)*7李>
- 1) 查找唯一的用户字符串和ZipWithindex李>
- 2) 加入原始数据李>
- 3) 保存编码后的数据李>