首先:在写文件的时候,经常输出的目录以及存在,需要一个删掉目录以及存在的情况。大致功能如下
def checkDirExist(sc:SparkContext,outpath:String) = {
logInfo("check output dir is exists")
val hdfs = FileSystem.get(new URI("hdfs://hdfs_host:port"),sc.hadoopConfiguration)
try{
hdfs.delete(new Path(outpath),true) //这里已经new 目录了,删除再说,总之是删了
logInfo("输出目录存在,删除掉:%s".format(outpath))
} catch {
case _:Throwable => logWarning("输出目录不存在,不用删除") //永远不会来吧
}
}
val rdd:RDD[(Long,Array[Double])]
rdd.saveAsObjectFile(outpath)
读取对象文件,需要指定类型
val input:RDD[(Long,Array[Double])] = sc.objectFile[(Long,Array[Double])](outpath)
val rdd: RDD[(Long, Array[Byte])]
new SequenceFileRDDFunctions(rdd).saveAsSequenceFile(outpath)
这里需要注意序列化时候,Long,Array都需要一个隐式转换函数,如下:
implicit def arrayBytetoBytesArray(bytes:Array[Byte]):BytesWritable = new BytesWritable(bytes)
implicit def long2LongWritable(ll:Long):LongWritable = new LongWritable(ll)
读取序列化文件:
val rdd = sc.sequenceFile(dir+"/svd",classOf[LongWritable],classOf[BytesWritable]).map{case(uid,sessions)=>
sessions.setCapacity(sessions.getLength)
(uid.get(),sessions.getBytes.clone())
}
这里需要注意的是,读取序列化文件,默认复用了同样的Writable object for each record, 也就导致了返回的RDD将会创建许多引用到同一个对象,我被这个坑了好久。因此这里需要将Array[Byte] 拷贝出来,不然所以的数据都是一样的,Long不是引用对象不需要。
3)有时候需要存储mapFile,用来根据key 快速索引。实践发现,索引的确很快,而且节约存储空间。
存储mapFile文件,需要注意是现要排序以后才能输出,为了快速索引,排序也是可以理解的嘛。
val temp: RDD[(Long, Array[Byte])]
val mapfile = temp.toArray().sortBy(e => e._1)
var writer: MapFile.Writer = null
val conf = sc.hadoopConfiguration
val fs = FileSystem.get(URI.create(dir+"/merge"),conf)
val key = new LongWritable()
val value = new BytesWritable()
try{
writer = new Writer(conf,fs,dir+"/merge",classOf[LongWritable],classOf[BytesWritable])
//这里不知道设置多少比较合适,感觉都ok
writer.setIndexInterval(1024)
for(ele <-mapfile){
key.set(ele._1)
value.set(ele._2)
writer.append(key,value)
}
}finally {
IOUtils.closeStream(writer)
}
快捷根据key 来检索value
val reader = new Reader(FileSystem.get(sc.hadoopConfiguration),
dir,sc.hadoopConfiguration)
val key = new LongWritable(args(1).toLong)
val value = new BytesWritable()
reader.get(key,value)
value.setCapacity(value.getLength)
val bytes = value.getBytes