Spark存储与读取文件方法小结

本文介绍了Spark中处理RDD存储的方法,包括检查输出目录是否存在并删除、使用saveAsObjectFile存储对象、利用SequenceFile进行序列化存储及读取、以及创建mapFile以实现快速索引。

http://blog.csdn.net/buring_/article/details/42424477   mark

一:Spark中常常面临这RDD的存储问题,记录一下常常面临的几种情况。saveAsObjectFile, SequenceFile, mapFile, textFile我就不说了。

首先:在写文件的时候,经常输出的目录以及存在,需要一个删掉目录以及存在的情况。大致功能如下

[java]  view plain  copy
  1. def checkDirExist(sc:SparkContext,outpath:String) = {  
  2.   logInfo("check output dir is exists")  
  3.   val hdfs = FileSystem.get(new URI("hdfs://hdfs_host:port"),sc.hadoopConfiguration)  
  4.   try{  
  5.     hdfs.delete(new Path(outpath),true//这里已经new 目录了,删除再说,总之是删了  
  6.     logInfo("输出目录存在,删除掉:%s".format(outpath))  
  7.   } catch {  
  8.     case _:Throwable => logWarning("输出目录不存在,不用删除"//永远不会来吧  
  9.   }  
  10. }  

1)存取对象,saveAsObjectFile ,十分方便,类似于python的cPickle.主要用法如下:
比如有一个

[java]  view plain  copy
  1. val rdd:RDD[(Long,Array[Double])]  
  2. rdd.saveAsObjectFile(outpath)  
  3.   
  4. 读取对象文件,需要指定类型  
  5. val input:RDD[(Long,Array[Double])] = sc.objectFile[(Long,Array[Double])](outpath)  

2)有时候需要节约空间,这样就需要存储序列化文件。如

[java]  view plain  copy
  1. val rdd: RDD[(Long, Array[Byte])]  
  2. new SequenceFileRDDFunctions(rdd).saveAsSequenceFile(outpath)  
  3. 这里需要注意序列化时候,Long,Array都需要一个隐式转换函数,如下:  
  4. implicit def arrayBytetoBytesArray(bytes:Array[Byte]):BytesWritable = new BytesWritable(bytes)  
  5. implicit  def long2LongWritable(ll:Long):LongWritable = new LongWritable(ll)  
  6.   
  7. 读取序列化文件:  
  8. val rdd = sc.sequenceFile(dir+"/svd",classOf[LongWritable],classOf[BytesWritable]).map{case(uid,sessions)=>  
  9.   sessions.setCapacity(sessions.getLength)  
  10.   (uid.get(),sessions.getBytes.clone())  
  11. }  
这里需要注意的是,读取序列化文件,默认复用了同样的Writable object for each record, 也就导致了返回的RDD将会创建许多引用到同一个对象,我被这个坑了好久。因此这里需要将Array[Byte] 拷贝出来,不然所以的数据都是一样的,Long不是引用对象不需要。

3)有时候需要存储mapFile,用来根据key 快速索引。实践发现,索引的确很快,而且节约存储空间。
存储mapFile文件,需要注意是现要排序以后才能输出,为了快速索引,排序也是可以理解的嘛。

[java]  view plain  copy
  1. val temp: RDD[(Long, Array[Byte])]  
  2. val mapfile = temp.toArray().sortBy(e => e._1)  
  3. var writer: MapFile.Writer = null  
  4. val conf = sc.hadoopConfiguration  
  5. val fs = FileSystem.get(URI.create(dir+"/merge"),conf)  
  6. val key = new LongWritable()  
  7. val value = new BytesWritable()  
  8. try{  
  9.   writer = new Writer(conf,fs,dir+"/merge",classOf[LongWritable],classOf[BytesWritable])  
  10.   //这里不知道设置多少比较合适,感觉都ok  
  11.   writer.setIndexInterval(1024)  
  12.   for(ele <-mapfile){  
  13.     key.set(ele._1)  
  14.     value.set(ele._2)  
  15.     writer.append(key,value)  
  16.   }  
  17. }finally {  
  18.   IOUtils.closeStream(writer)  
  19. }  
  20.   
  21. 快捷根据key 来检索value  
  22. val reader = new Reader(FileSystem.get(sc.hadoopConfiguration),  
  23.   dir,sc.hadoopConfiguration)  
  24.   
  25. val key = new LongWritable(args(1).toLong)  
  26. val value = new BytesWritable()  
  27.   
  28. reader.get(key,value)  
  29. value.setCapacity(value.getLength)  
  30. val bytes = value.getBytes  
### 回答1: Spark可以通过以下方式读取本地和HDFS文件: 1. 读取本地文件: ```scala val localFile = spark.read.textFile("file:///path/to/local/file") ``` 2. 读取HDFS文件: ```scala val hdfsFile = spark.read.textFile("hdfs://namenode:port/path/to/hdfs/file") ``` 其中,`namenode`是HDFS的名称节点,`port`是HDFS的端口号,`path/to/hdfs/file`是HDFS文件的路径。 需要注意的是,如果要读取HDFS文件,需要确保Spark集群可以访问HDFS,并且需要在Spark配置文件中设置HDFS的相关参数。 ### 回答2: Spark是一个开源的分布式计算框架,支持从本地和远程存储读取数据进行处理。本地文件可以通过指定文件路径直接读取,而Hadoop分布式文件系统(HDFS)上的文件需要使用Spark的Hadoop文件系统API进行读取。 首先,要读取本地文件,可以使用Spark的textFile API,该API可以从本地文件系统中读取文本文件。以下是读取本地文件的示例代码: ```scala import org.apache.spark.SparkConf import org.apache.spark.SparkContext object LocalFileReader { def main(args: Array[String]) { val conf = new SparkConf().setAppName("LocalFileReader").setMaster("local[*]") val sc = new SparkContext(conf) val textFile = sc.textFile("file:///path/to/localfile.txt") // 对textFile进行处理 ... sc.stop() } } ``` 其中,`file:///`表示本地文件路径,`path/to/localfile.txt`为本地文件的路径。SparkConf中的`setMaster("local[*]")`表示应用程序运行在本地模式下,使用所有可用的CPU核。如果本地文件是二进制格式或非文本格式,应使用相应的API读取。 其次,要读取HDFS文件,可以使用Spark的Hadoop文件系统API,通过设置`fs.defaultFS`属性指定HDFS的访问地址。以下是读取HDFS文件的示例代码: ```scala import org.apache.spark.SparkConf import org.apache.spark.SparkContext import org.apache.hadoop.fs.{FileSystem, Path} object HDFSFileReader { def main(args: Array[String]) { val conf = new SparkConf().setAppName("HDFSFileReader") val sc = new SparkContext(conf) val hdfs = FileSystem.get(sc.hadoopConfiguration) val path = new Path("hdfs://namenode:port/path/to/hdfsfile.txt") val textFile = sc.textFile(path.toString) // 对textFile进行处理 ... sc.stop() } } ``` 其中,`namenode`和`port`为HDFS的名称节点和端口号,`path/to/hdfsfile.txt`为HDFS文件路径。SparkConf不需要设置`setMaster`属性,因为Spark将根据Hadoop配置自动进行集群管理。 无论是从本地还是HDFS读取文件,均可以使用Spark的强大的分布式计算功能进行并行处理和分析。 ### 回答3: Spark 是一个基于内存的分布式计算框架,常用于大数据计算和处理。Spark 可以读取本地文件和 HDFS 文件,下面我们就分别介绍一下。 首先是读取本地文件Spark 可以直接读取本地文件系统中的文件方法如下: ```scala val sc = new SparkContext("local", "app") val textFile = sc.textFile("file:///path/to/local/file.txt") ``` 其中,`file:///path/to/local/file.txt` 中的 `file:///` 表示文件协议,`/path/to/local/file.txt` 是文件的路径。可以在 `textFile` 的参数中指定所读取文件类型,例如: ```scala val textFile = sc.textFile("file:///path/to/local/file.txt", 4) ``` 其中 `4` 表示分片数量,Spark文件拆分为 4 个部分进行读取和处理。 然后是读取 HDFS 文件Spark 同样可以读取 HDFS 文件方法如下: ```scala val sc = new SparkContext("local", "app") val textFile = sc.textFile("hdfs://namenode:8020/path/to/hdfs/file.txt") ``` 其中 `hdfs://namenode:8020` 中的 `hdfs://` 表示 HDFS 协议,`namenode:8020` 表示 HDFS 在集群中的地址,`/path/to/hdfs/file.txt` 是要读取文件在 HDFS 中的路径。同样可以在 `textFile` 的参数中指定分片数量: ```scala val textFile = sc.textFile("hdfs://namenode:8020/path/to/hdfs/file.txt", 4) ``` 以上就是 Spark 读取本地和 HDFS 文件方法。需要注意的是,Spark 针对文件读取和处理会自动进行分片,减少计算的时间和资源消耗。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值