在Spark Collaborative filtering RDD中将用户和项目功能保存到HDFS

时间:2016-08-18 01:44:34

标签: arrays apache-spark hdfs rdd

我想从Spark中使用ALS的协同过滤结果中提取用户和项目功能(潜在因素)。我到目前为止的代码:

import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
import org.apache.spark.mllib.recommendation.Rating

// Load and parse the data
val data = sc.textFile("myhdfs/inputdirectory/als.data")
val ratings = data.map(_.split(',') match { case Array(user, item, rate) =>
  Rating(user.toInt, item.toInt, rate.toDouble)
})

// Build the recommendation model using ALS
val rank = 10
val numIterations = 10
val model = ALS.train(ratings, rank, numIterations, 0.01)

// extract users latent factors
val users = model.userFeatures

// extract items latent factors
val items = model.productFeatures

// save to HDFS
users.saveAsTextFile("myhdfs/outputdirectory/users") // does not work as expected
items.saveAsTextFile("myhdfs/outputdirectory/items") // does not work as expected

但是,写入HDFS的内容并不是我所期望的。我希望每一行都有一个元组(userId,Array_of_doubles)。相反,我看到以下内容:

[myname@host dir]$ hadoop fs -cat myhdfs/outputdirectory/users/*
(1,[D@3c3137b5)
(3,[D@505d9755)
(4,[D@241a409a)
(2,[D@c8c56dd)
.
.

它正在转储数组的哈希值而不是整个数组。我对print所需的值进行了以下操作:

for (user <- users) {
  val (userId, lf) = user
  val str = "user:" + userId + "\t" + lf.mkString(" ")
  println(str)
}

这会打印我想要的内容,但我无法写入HDFS(这会在控制台上打印)。

如何正确地将完整数组写入HDFS?

Spark版本是1.2.1。

1 个答案:

答案 0 :(得分:1)

@JohnTitusJungao是对的,以下行也按预期工作:

users.saveAsTextFile("myhdfs/outputdirectory/users") 
items.saveAsTextFile("myhdfs/outputdirectory/items")

这就是原因,userFeatures会返回RDD[(Int,Array[Double])]。数组值由您在输出中看到的符号表示,例如[D@3c3137b5D表示double,后跟@和十六进制代码,使用Java toString方法为此类对象创建。更多关于here

val users: RDD[(Int, Array[Double])] = model.userFeatures

要解决这个问题,你需要将数组作为字符串:

val users: RDD[(Int, String)] = model.userFeatures.mapValues(_.mkString(","))

项目也一样。