我从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,而不是文件行级别吗?有更好的想法吗?
谢谢!
答案 0 :(得分:1)
您可以尝试使用wholeTextFiles()方法(here),它会读取整个目录并返回一对RDD(文件名,内容)对。
然后,文件名将成为传感器,内容可以与以前类似的方式处理。
答案 1 :(得分:0)
数据存储在hdfs
中,这意味着它分布在您的集群上,并且spark可以实现数据并行,但您编写的代码就像是一个目录一样,您需要担心分区。如果可能的话,还要将数据转换成实木复合地板。
我强烈建议您使用datasets
,spark
将能够优化计算。
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")
中的通配符