通过文件独立分配Spark处理

时间:2017-05-03 15:32:04

标签: scala apache-spark distributed-computing

我从10 000个传感器测量了10年。 这可用作存储在HDFS中的ASCII文件(需要改进,而不是此请求的主题):

  • 每个传感器一个文件
  • 每个样本一行
  • 两列(时间,价值)
  • 一行标题

作为概念验证,我使用Spark计算传感器的平均值,并使用以下SCALA代码 Spark v1.6.1

// Read file as text
val lines = sc.textFile("/data/sensor_1.dat")
// Drop header
val header = lines.first
val lines_clean = lines.filter(line => line != header)
// Compute mean
val values = lines_clean.map(_.split("\t").last.toDouble)
val mean = values.sum / values.count

现在,我想将它应用于10 000多个文件,为每个传感器获得一个平均值。我该怎么办?我应该实现循环吗?我可以在文件级别处理RDD,而不是文件行级别吗?有更好的想法吗?

谢谢!

4 个答案:

答案 0 :(得分:1)

您可以尝试使用wholeTextFiles()方法(here),它会读取整个目录并返回一对RDD(文件名,内容)对。

然后,文件名将成为传感器,内容可以与以前类似的方式处理。

答案 1 :(得分:0)

数据存储在hdfs中,这意味着它分布在您的集群上,并且spark可以实现数据并行,但您编写的代码就像是一个目录一样,您需要担心分区。如果可能的话,还要将数据转换成实木复合地板。

我强烈建议您使用datasetsspark将能够优化计算。

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

case class Sensor(time: java.sql.Timestamp, value: Double)

val ds = spark.read
  .option("header", "true")
  .option("delimiter", "\t")
  .csv(s"hdfs://${master}:9000/data.tsv")
.as[Sensor] 
 // tune by partition number   .partition(100)

val mean = ds.select(avg(col("value")).as("mean"))

答案 2 :(得分:0)

您可以像这样阅读整个文件夹:

import org.apache.spark.sql.functions.input_file_name

val inputPath: String = "/data/"

val lines = sqlContext.read.text(inputPath)
  .select(input_file_name.alias("filename"), $"value")
  .rdd

然后您可以像处理问题一样处理String文件名和值:

val linesClean = lines.filter(l => l.getString(1) != header).map(l => (l.getString(0), l.getString(1)))
val meanForEachFile = linesClean.groupByKey().map{
    case (name, linesInFile) => 
    val values = linesInFile.map(v => v.split("\t").last.toDouble)
    val mean = values.sum / values.count
    mean
}

答案 3 :(得分:0)

由于每个文件中的数据似乎不包含传感器ID,您可能希望使用将加载的wholeTextFiles选项  将每个文件放入一个pairRDD,其中键是文件名。这将意味着更多的解析,因为您需要解析获取传感器名称并从值中拆分整个文件以获取样本 - 但至少您可以区分哪些数据属于哪个传感器。

您应该注意,传递给wholeTextFiles(或textFile)的路径可以是路径列表,包括sc.wholeTextFiles("/dir/to/first/sensor,/dir/to/second/sensor,/sensor[0-10]*,/etc")中的通配符