spark快速大数据分析之数据读取与保存

1 动机

  探索spark对不同地方或不同的数据的读取和保存方法,通过本节学习可以掌握将数据读取到spark,并将计算结果以你希望的方式存储起来。


spark生态常见三种数据源: 文件格式与文件系统,spark SQL中的结构化数据源, 数据库与键值存储

2文件格式

      a.0....逗号分隔值CSV与制表符分隔值

     a.文本文件 ------非结构化

     b.JSON  -----半结构化,下面几个是结构化

    

     c.SequenceFile------是由没有相对关系结构的键值对文件组成的常用的Hadoop格式。

     d.对象文件----------它允许存储只包含值得RDD,是使用java序列化写出的

      e. hadoop输入输出格式

      f.文件压缩----------gzip,lzo,bzip2,zlib,Snappy


3 文件系统

      a.本地文件系统

      b.Amazon S3

      c.HDFS

4spark SQL中结构化数据

     a.Apache Hive

     b.JSON

5 数据库

   a.java数据库连接

   b.Cassandra

   c.HBase

   d.Elasticsearch



 

spark所支持的文件格式

 

1.文本文件

在 Spark 中读写文本文件很容易。

当我们将一个文本文件读取为 RDD 时,输入的每一行 都会成为 RDD 的 一个元素

也可以将多个完整的文本文件一次性读取为一个 pair RDD, 其中键是文件名,值是文件内容

 在 Scala 中读取一个文本文件

1
2
val  inputFile  =  "file:///home/common/coding/coding/Scala/word-count/test.segmented"
val  textFile  =  sc.textFile(inputFile)

 在 Scala 中读取给定目录中的所有文件

1
val  input  =  sc.wholeTextFiles( "file:///home/common/coding/coding/Scala/word-count" )

 保存文本文件,Spark 将传入的路径作为目录对待,会在那个目录下输出多个文件

1
2
textFile.saveAsTextFile( "file:///home/common/coding/coding/Scala/word-count/writeback" )
//textFile.repartition(1).saveAsTextFile 就能保存成一个文件

对于dataFrame文件,先使用.toJavaRDD 转换成RDD,然后再使用  coalesce(1).saveAsTextFile

 

2.JSON

JSON 是一种使用较广的半结构化数据格式。

读取JSON,书中代码有问题所以找了另外的一段读取JSON的代码

 build.sbt

1
"org.json4s"  %%  "json4s-jackson"  %  "3.2.11"

 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
import  org.json 4 s. _
import  org.json 4 s.jackson.JsonMethods. _
import  org.json 4 s.jackson.Serialization
import  org.json 4 s.jackson.Serialization.{read, write}
 
/**
   * Created by common on 17-4-3.
   */
 
case  class  Person(firstName :  String, lastName :  String, address :  List[Address]) {
   override  def  toString  =  s "Person(firstName=$firstName, lastName=$lastName, address=$address)"
}
 
case  class  Address(line 1 :  String, city :  String, state :  String, zip :  String) {
   override  def  toString  =  s "Address(line1=$line1, city=$city, state=$state, zip=$zip)"
}
 
object  WordCount {
   def  main(args :  Array[String]) {
     val  inputJsonFile  =  "file:///home/common/coding/coding/Scala/word-count/test.json"
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
     val  input 5  =  sc.textFile(inputJsonFile)
     val  dataObjsRDD  =  input 5 .map { myrecord  = >
       implicit  val  formats  =  DefaultFormats
       // Workaround as      DefaultFormats is not serializable
       val  jsonObj  =  parse(myrecord)
       //val addresses = jsonObj \ "address"
       //println((addresses(0) \ "city").extract[String])
       jsonObj.extract[Person]
     }
     dataObjsRDD.saveAsTextFile( "file:///home/common/coding/coding/Scala/word-count/test1.json" )
 
   }
 
 
}

 读取的JSON文件

1
2
{ "firstName" : "John" , "lastName" : "Smith" , "address" : [{ "line1" : "1 main street" , "city" : "San Francisco" , "state" : "CA" , "zip" : "94101" },{ "line1" : "1 main street" , "city" : "sunnyvale" , "state" : "CA" , "zip" : "94000" }]}
{ "firstName" : "Tim" , "lastName" : "Williams" , "address" : [{ "line1" : "1 main street" , "city" : "Mountain View" , "state" : "CA" , "zip" : "94300" },{ "line1" : "1 main street" , "city" : "San Jose" , "state" : "CA" , "zip" : "92000" }]}

 输出的文件

1
2
Person(firstName = John, lastName = Smith, address = List(Address(line 1 = 1  main street, city = San Francisco, state = CA, zip = 94101 ), Address(line 1 = 1  main street, city = sunnyvale, state = CA, zip = 94000 )))
Person(firstName = Tim, lastName = Williams, address = List(Address(line 1 = 1  main street, city = Mountain View, state = CA, zip = 94300 ), Address(line 1 = 1  main street, city = San Jose, state = CA, zip = 92000 )))

 

3.逗号分割值与制表符分隔值

逗号分隔值(CSV)文件每行都有固定数目的字段,字段间用逗号隔开(在制表符分隔值文件,即 TSV 文 件中用制表符隔开)。

如果恰好CSV 的所有数据字段均没有包含换行符,你也可以使用 textFile() 读取并解析数据,

build.sbt

1
"au.com.bytecode"  %  "opencsv"  %  "2.4"

3.1 读取CSV文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import  java.io.StringReader
 
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
import  org.json 4 s. _
import  org.json 4 s.jackson.JsonMethods. _
import  org.json 4 s.jackson.Serialization
import  org.json 4 s.jackson.Serialization.{read, write}
import  au.com.bytecode.opencsv.CSVReader
 
/**
   * Created by common on 17-4-3.
   */
 
object  WordCount {
   def  main(args :  Array[String]) {
 
     val  input  =  sc.textFile( "/home/common/coding/coding/Scala/word-count/sample_map.csv" )
     val  result 6  =  input.map{ line  = >
       val  reader  =  new  CSVReader( new  StringReader(line));
       reader.readNext();
     }
     for (result <- result 6 ){
       for (re <- result){
         println(re)
       }
     }
 
   }
 
}

 CSV文件内容

输出

1
2
3
4
5
6
0
Front Left
/usr/share/alsa/samples/Front _ Left.wav
1
Front Right
/usr/share/alsa/samples/Front _ Right.wav

 

如果在字段中嵌有换行符,就需要完整读入每个文件,然后解析各段。如果每个文件都很大,读取和解析的过程可能会很不幸地成为性能瓶颈。

 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import  java.io.StringReader
 
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
import  org.json 4 s. _
import  org.json 4 s.jackson.JsonMethods. _
import  org.json 4 s.jackson.Serialization
import  org.json 4 s.jackson.Serialization.{read, write}
import  scala.collection.JavaConversions. _
import  au.com.bytecode.opencsv.CSVReader
 
/**
   * Created by common on 17-4-3.
   */
 
case  class  Data(index :  String, title :  String, content :  String)
 
object  WordCount {
   def  main(args :  Array[String]) {
 
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
     val  input  =  sc.wholeTextFiles( "/home/common/coding/coding/Scala/word-count/sample_map.csv" )
     val  result  =  input.flatMap {  case  ( _ , txt)  = >
       val  reader  =  new  CSVReader( new  StringReader(txt));
       reader.readAll().map(x  = > Data(x( 0 ), x( 1 ), x( 2 )))
     }
     for (res <- result){
       println(res)
     }
   }
 
}

 输出

1
2
Data( 0 ,Front Left,/usr/share/alsa/samples/Front _ Left.wav)
Data( 1 ,Front Right,/usr/share/alsa/samples/Front _ Right.wav)

 或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import  java.io.StringReader
 
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
import  org.json 4 s. _
import  org.json 4 s.jackson.JsonMethods. _
import  org.json 4 s.jackson.Serialization
import  org.json 4 s.jackson.Serialization.{read, write}
import  scala.collection.JavaConversions. _
import  au.com.bytecode.opencsv.CSVReader
 
/**
   * Created by common on 17-4-3.
   */
 
case  class  Data(index :  String, title :  String, content :  String)
 
object  WordCount {
   def  main(args :  Array[String]) {
 
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
     val  input  =  sc.wholeTextFiles( "/home/common/coding/coding/Scala/word-count/sample_map.csv" )   //wholeTextFiles读出来是一个RDD(String,String)
     val  result  =  input.flatMap {  case  ( _ , txt)  = >
       val  reader  =  new  CSVReader( new  StringReader(txt));
       //reader.readAll().map(x => Data(x(0), x(1), x(2)))
       reader.readAll()
     }
     result.collect().foreach(x  = > {
       x.foreach(println); println( "======" )
     })
 
   }
}

 输出

1
2
3
4
5
6
7
8
0
Front Left
/usr/share/alsa/samples/Front _ Left.wav
======
1
Front Right
/usr/share/alsa/samples/Front _ Right.wav
======

 

3.2 保存CSV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import  java.io.{StringReader, StringWriter}
 
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
import  org.json 4 s. _
import  org.json 4 s.jackson.JsonMethods. _
import  org.json 4 s.jackson.Serialization
import  org.json 4 s.jackson.Serialization.{read, write}
 
import  scala.collection.JavaConversions. _
import  au.com.bytecode.opencsv.{CSVReader, CSVWriter}
 
/**
   * Created by common on 17-4-3.
   */
 
case  class  Data(index :  String, title :  String, content :  String)
 
object  WordCount {
   def  main(args :  Array[String]) {
 
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
     val  inputRDD  =  sc.parallelize(List(Data( "index" "title" "content" )))
     inputRDD.map(data  = > List(data.index, data.title, data.content).toArray)
       .mapPartitions { data  = >
         val  stringWriter  =  new  StringWriter();
         val  csvWriter  =  new  CSVWriter(stringWriter);
         csvWriter.writeAll(data.toList)
         Iterator(stringWriter.toString)
       }.saveAsTextFile( "/home/common/coding/coding/Scala/word-count/sample_map_out" )
   }
}

 输出

1
"index" , "title" , "content"

 

4.SequenceFile 是由没有相对关系结构的键值对文件组成的常用 Hadoop 格式。

SequenceFile 文件有同步标记, Spark 可 以用它来定位到文件中的某个点,然后再与记录的边界对齐。这可以让 Spark 使 用多个节点高效地并行读取 SequenceFile 文件。SequenceFile 也是Hadoop MapReduce 作 业中常用的输入输出格式,所以如果你在使用一个已有的 Hadoop 系统,数据很有可能是以 S equenceFile 的格式供你使用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import  org.apache.hadoop.io.{IntWritable, Text}
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkContext. _
import  org.apache.spark.SparkConf
 
/**
   * Created by common on 17-4-6.
   */
object  SparkRDD {
 
   def  main(args :  Array[String]) {
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
 
     //写sequenceFile,
     val  rdd  =  sc.parallelize(List(( "Panda" 3 ), ( "Kay" 6 ), ( "Snail" 2 )))
     rdd.saveAsSequenceFile( "output" )
 
     //读sequenceFile
     val  output  =  sc.sequenceFile( "output" , classOf[Text], classOf[IntWritable]).
       map{ case  (x, y)  = > (x.toString, y.get())}
     output.foreach(println)
 
   }
}

 

 

5.对象文件

对象文件看起来就像是对 SequenceFile 的简单封装,它允许存储只包含值的 RDD。和 SequenceFile 不一样的是,对象文件是使用 Java 序列化写出的。

如果你修改了你的类——比如增减了几个字段——已经生成的对象文件就不再可读了。

读取文件——用 SparkContext 中的 objectFile() 函数接收一个路径,返回对应的 RDD。

写入文件——要 保存对象文件, 只需在 RDD 上调用 saveAsObjectFile

 

6.Hadoop输入输出格式

除了 Spark 封装的格式之外,也可以与任何 Hadoop 支持的格式交互。Spark 支持新旧两套Hadoop 文件 API,提供了很大的灵活性。

旧的API:hadoopFile,使用旧的 API 实现的 Hadoop 输入格式

新的API:newAPIHadoopFile 
接收一个路径以及三个类。第一个类是“格式”类,代表输入格式。第二个类是键的类,最后一个类是值的类。如果需要设定额外的 H adoop 配置属性,也可以传入一个 conf 对象。

KeyValueTextInputFormat 是最简单的 Hadoop 输入格式之一,可以用于从文本文件中读取键值对数据。每一行都会被独立处理,键和值之间用制表符隔开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import  org.apache.hadoop.io.{IntWritable, LongWritable, MapWritable, Text}
import  org.apache.spark.SparkContext
import  org.apache.spark.SparkConf
import  org.apache.spark. _
import  org.apache.hadoop.mapreduce.Job
import  org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat
import  org.apache.hadoop.mapreduce.lib.output.TextOutputFormat
import  org.apache.spark.rdd. _
 
/**
   * Created by common on 17-4-6.
   */
object  SparkRDD {
 
   def  main(args :  Array[String]) {
     val  conf  =  new  SparkConf().setAppName( "WordCount" ).setMaster( "local" )
     val  sc  =  new  SparkContext(conf)
 
     //使用老式 API 读取 KeyValueTextInputFormat(),以JSON文件为例子
     //注意引用的包是org.apache.hadoop.mapred.KeyValueTextInputFormat
//    val input = sc.hadoopFile[Text, Text, KeyValueTextInputFormat]("input/test.json").map {
//      case (x, y) => (x.toString, y.toString)
//    }
//    input.foreach(println)
 
     // 读取文件,使用新的API,注意引用的包是org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat
     val  job  =  new  Job()
     val  data  =  sc.newAPIHadoopFile( "input/test.json"  ,
       classOf[KeyValueTextInputFormat],
       classOf[Text],
       classOf[Text],
       job.getConfiguration)
     data.foreach(println)
 
     //保存文件,注意引用的包是org.apache.hadoop.mapreduce.lib.output.TextOutputFormat
     data.saveAsNewAPIHadoopFile(
       "input/test1.json" ,
       classOf[Text],
       classOf[Text],
       classOf[TextOutputFormat[Text,Text]],
       job.getConfiguration)
 
   }
}

 

 

Hadoop 的非文件系统数据源

除 了 hadoopFile() 和 saveAsHadoopFile() 这 一 大 类 函 数, 还 可 以 使 用 hadoopDataset/saveAsHadoopDataSet 和 newAPIHadoopDataset/ saveAsNewAPIHadoopDataset 来访问 Hadoop 所支持的非文件系统的存储格式。例如,许多像 HBase 和 MongoDB 这样的键值对存储都提供了用来直接读取 Hadoop 输入格式的接口。我们可以在 Spark 中很方便地使用这些格式。

 

7.文件压缩

Spark 原生的输入方式( textFile 和 sequenceFile)可以自动处理一些类型的压缩。在读取压缩后的数据时,一些压缩编解码器可以推测压缩类型。 
这些压缩选项只适用于支持压缩的 Hadoop 格式,也就是那些写出到文件系统的格式。写入数据库的 Hadoop 格式一般没有实现压缩支持。如果数据库中有压缩过的记录,那应该是数据库自己配置的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要使用Spark进行大数据分析,可以按照以下步骤进行: 1. 安装和配置Spark:首先,需要下载和安装Spark,并根据需要进行相应的配置。可以从Spark官网获取Spark的安装包和配置文档。 2. 编写Spark应用程序:使用Scala、Java或Python等编程语言编写Spark应用程序。Spark提供了丰富的API和库,可以进行数据加载、转换、处理和分析等操作。 3. 数据加载:使用Spark的API从不同的数据源加载数据,例如从HDFS、关系型数据库、NoSQL数据库或其他文件系统中加载数据。 4. 数据转换和处理:使用Spark的转换操作,例如map、filter、reduce等,对数据进行转换和处理。可以使用Spark提供的高级API,如DataFrame和Dataset,进行结构化数据的操作和处理。 5. 数据分析:根据需求使用Spark提供的功能进行数据分析,例如聚合、排序、过滤、连接等操作。还可以使用Spark提供的机器学习库(如MLlib)进行机器学习和模型训练。 6. 结果输出:将分析结果保存文件系统、数据库或其他存储介质中,以便后续使用或展示。 7. 集群部署和运行:将编写好的Spark应用程序部署到Spark集群中,并通过Spark的集群管理器(如Spark Standalone、Apache Mesos或Hadoop YARN)来分配和管理资源。可以使用命令行工具或Web界面来监视和管理Spark应用程序的运行。 需要注意的是,Spark是一个分布式计算框架,可以在集群中并行处理大规模的数据。因此,在使用Spark进行大数据分析时,需要有一定的集群资源和配置经验,以确保系统的稳定性和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值