Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Spark-将字符串ID转换为唯一的整数ID_Apache Spark - Fatal编程技术网

Apache spark Spark-将字符串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

我有一个类似这样的数据集,其中每个用户和产品ID都是一个字符串:

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个不同的产品字符串

  • 第一个想法:
  • 我的第一个想法是使用collectAsMap操作,然后使用map想法将用户/产品字符串更改为int。由于驱动程序内存高达12G,我得到了OOM或GC开销异常(该异常受驱动程序内存的限制)

    但是这个想法只能在较小的数据量上使用,如果数据量较大,则需要更大的驱动程序内存

  • 第二个想法: 第二个想法是使用Tobber提出的连接方法。以下是一些测试结果: 作业设置:

    • 驱动程序:2G,2个cpu
    • 执行器:(8G,4个cpu)*7
  • 我遵循以下步骤:

    • 1) 查找唯一的用户字符串和ZipWithindex
    • 2) 加入原始数据
    • 3) 保存编码后的数据
    完成这项工作大约需要10分钟