spark将计算结果写入到hdfs的两种方法

spark将计算结果写入到hdfs的两种方法
第一种方法:

rdd.saveAsTextFile(path, classOf[com.hadoop.compression.lzo.LzopCodec])

这种方法有这么几个问题

1、生成的lzo文件不会创建index文件,需要手动进行创建。

2、每个文件的名称不能自定义。


第二种方法是直接调用LzopOutputstream的接口和hdfs的api,直接操作hdfs文件。可以规避以上几个问题。

 def main(args: Array[String]) {
    //保存的路径
    val basePath = "/tmp/kuan2"
    //设置日志级别
    //    Example.setStreamingLogLevels()
    //创建sparkConf
    val sparkConf = new SparkConf().setAppName("runJob")
    //设置master,此处设置本地执行
    //    sparkConf.setMaster("local[*]")
    //创建SparkContext
    val sc = new SparkContext(sparkConf)
    /**
    val hadoopRDD = sc.newAPIHadoopFile[LongWritable, Text, LzoTextInputFormat]("/tmp/mls.nginx201601281705",
      classOf[LzoTextInputFormat],
      classOf[LongWritable],
      classOf[Text])
    val rdd:RDD[String] = hadoopRDD.map(x=>x._2.toString)
      * */
    val rdd = sc.makeRDD(List("1", "2", "会议", "1", "2", "会议", "1", "2", "会议", "1", "2", "会议"), 2)

    //在每个executor上执行的函数
    //此处定义的是,针对每个分区,我们把计算好的结果写入到本地目录中
    val func = (tc: TaskContext, it: Iterator[String]) => {
      //输出文件路径
      val outFilePath: String =
        s"""$basePath/${tc.partitionId()}.lzo"""
      val outIndexFilePath = s"""${basePath}/${tc.partitionId()}.index"""

      //****************开始往文件中写数据********************//
      //得到文件系统
      val fs: FileSystem = FileSystem.get(new Configuration)
      //目标路径
      val dstPath = new Path(outFilePath)
      val dstIndexPath = new Path(outIndexFilePath)

      //打开一个输出流
      val lzopCodec = new LzopCodec()
      lzopCodec.setConf(new Configuration())
      val lzoIndexOuputStream = lzopCodec.createIndexedOutputStream(fs.create(dstPath),fs.create(dstIndexPath))
      val pw:PrintWriter = new PrintWriter(new OutputStreamWriter(lzoIndexOuputStream,Charset.forName("UTF-8")));

      try {
        var count = 0
        while (it.hasNext) {
          //写数据
          pw.println(it.next())

          //增加计数
          count = count + 1
          //判断是否需要将数据写到硬盘中
          if (count >= 1000) {

            //强制写入到存储中
            pw.flush()
            //数量重新计算
            count = 0
          }

        }
      } finally {
        //关闭数据流
        pw.close()
        fs.close()
      }

      //此处单机测试,所有的输出本机文件,如果分布式运行,那么输出文件还是放到hdfs吧
      s"I Am Partition ${tc.partitionId()}"
    }

    //开始执行函数
    val res = sc.runJob(rdd, func)
    //输出各个partition的执行结果.如果返回结果比较小,直接返回到driver
    res.foreach(println)
    sc.stop()
  }

每个task输出的文件的文件名可以自定义,同时可以生成索引文件

输出的目录如果不存在,可以在执行job之前进行创建。如果存在也不影响运行,生成的文件会进行覆盖。

posted on 2016-03-08 02:00  luckuan1985  阅读(24652)  评论(0编辑  收藏  举报