spark支持多种输入源
常见3种数据源
- 文件格式与文件系统
spark可以访问很多种不同的文件格式,包括文本文件、JSON、SequenceFile、protocol buffer. - Spark SQL结构化数据源
包括针对JSON、Apache Hive在内的结构化数据 - 数据库与键值存储
spark自带库和一些第三方库,可以用来连接Cassandra、HBase、Elasticsearch以及JDBC源
文件格式
spark支持常见格式
文本文件
可以将一个文本文件读取为RDD,输入的每一行都会成为RDD的一个元素。或者一次读取多个文件为一个pair RDD,键是文件名,值是文件内容。
1.读取文本文件
调用SparkContext 的textFile()函数,如果要控制分区数,可以指定minPartitions
input = sc.textFile("file:///**.txt")
如果读取一个目录下所有文件,有两种方式处理,textFile,会把各部分都读取到RDD中。如果想要知道数据来自哪个文件,且文件较小,可以用SparkContext的wholeTextFiles()方法,返回一个pair RDD.
spark支持读取给定目录的所有文件,以及输入路径中使用通配符
2.保存文本文件
saveAsTextFile()方法接受路径,并将RDD中的内容输入到对应路径中,spark将传入的路径作为目录对待,会在哪个目录下输出多个文件。
不能控制哪一部分输出到哪个文件,不过可以有些输出格式支持
rdd.saveAsTextFile(outputFile)
JSON
1.读取json
最简单的方式是将数据作为文本文件读取,然后使用JSON解析器来对RDD的值进行映射操作
该方法假设每一行都是一条JSON记录,如果有跨行数据,就只能读入整个文件进行解析
import json
data = input.map(lambda x:json.loads(x))
2.保存json
将字符串RDD转为解析好的JSON数据的库,将由结构化数据组成的RDD转为字符串RDD
(data.filter(lambda x:x["xx"]).map(lambda x:json.dumps(x)).saveAsTextFile(outputfile)
逗号分隔值与制表符分隔值
与JSON中的字段不一样的是,这里的每条记录都没有相关联的字段名,只能得到对应的序号。常规做法是使用第一行每列的值作为字段名。
1.读取CSV
与读取JSON数据类似,都需要先把文件当做普通文本文件来读取,再对数据进行处理。
如果CSV的所有数据字段均没有包含换行符,可以使用textFile读取并解析数据
import csv
import StringIO
def loadRecord(line):
input = StringIO.StringIO(line)
reader = csv.DictReader(input,fieldnames=['name'])
return reader.next()
input = sc.textFile(inputFile).map(loadRecord)
如果在字段中嵌有换行符,需要完整读入整个文件,然后解析
import csv
import StringIO
def loadRecordS(fileNameContents):
input = StringIO.StringIO(fileNameContents[1])
reader = csv.DictReader(input,fieldnames=['name'])
return reader
fullFileData = sc.wholeTextFile(inputFile).flatMap(loadRecord)
可能需要对输入数据进行重新分区使得Spark能够高效地并行化执行后续操作
2.保存CSV
由于CSV不会在每条记录中输出字段名,因此为了使输出保持一致,需要创建一种映射关系。
一种简单做法是写一个函数,用于将各字段转为指定顺序的数据。在Python中,如果输出字典,CSV输出器会根据输出器时指定的fieldnames顺序完成这一行为
import StringWriter
import StringIO
def writeRecords(records):
output = StringIO.StringIO()
writer = csv.DictWriter(output,fieldnames=['name'])
for record in records:
writer.writerow(record)
return [output.getvalue()]
rdd.mapPartitions(writeRecords).saveAsTextFile(outputfile)
如果字段名未知,则需要使用其他方法,比如遍历所有的数据,提取不同的键,然后分别输出
SequenceFile
SequenceFile 是由没有相对关系结构的键值对文件组成的常用 Hadoop 格式。SequenceFile文件有同步标记,Spark 可以用它来定位到文件中的某个点,然后再与记录的边界对齐。这可以让 Spark 使用多个节点高效地并行读取 SequenceFile 文件。SequenceFile 也是Hadoop MapReduce 作业中常用的输入输出格式,所以如果你在使用一个已有的 Hadoop 系统,数据很有可能是以 SequenceFile 的格式供你使用的。
由于 Hadoop 使用了一套自定义的序列化框架,因此 SequenceFile 是由实现 Hadoop 的 Writable接口的元素组成。下表 列出了一些常见的数据类型以及它们对应的 Writable 类。标准的经验法则是尝试在类名的后面加上 Writable 这个词,然后检查它是否是 org.apache.hadoop.io.Writable 已知的子类。如果你无法为要写出的数据找到对应的 Writable 类型(比如自定义的 case class),你可以通过重载 org.apache.hadoop.io.Writable 中的 readfields 和 write 来实现自己的 Writable 类。
1.读取SequenceFile
Spark 有专门用来读取 SequenceFile 的接口。在 SparkContext 中,可以调用 sequenceFile(path,keyClass, valueClass, minPartitions) 。SequenceFile 使用 Writable 类,因此 keyClass 和 valueClass 参数都必须使用正确的 Writable 类。
data = sc.sequenceFile(inFile,"org.apach.hadoop.io.Text","org.apache.hadoop.io.InWritable")
2.保存SequenceFile
在 Scala 中将数据写出到 SequenceFile 的做法也很类似。可以直接调用 saveSequenceFile(path) 保存你的 PairRDD ,它会帮你写出数据。
scala代码
val data = sc.parallelize(List(("pandas",3),("Key",1)))
data.saveSequenceFile(outputFile)
对象文件
对象文件是用java序列化写出的,看起来就像SequenceFile的简单封装,它允许只包含值的RDD
要保存对象文件,只需在RDD上调用saveAsObjectFile。读取对象文件:用sparkContext中的objectFile()函数接受一个路径,返回对应RDD
对象文件在python中无法使用,鸡蛋时可以使用saveAsPickleFile()和pickleFile()方法作为替代。pickle库可能很慢,修改了类定义后,已经生产的数据文件可能无法再读出来
注意:
使用java序列化:对同样的对象,对象文件输出和Hadoop输出不一样,对象通常用于spark作业间通信,序列化很慢
hadoop输入输出格式
1.读取其他hadoop输入格式
keyValueTextInputFormat是最简单的Hadoop输入格式之一,可以用于文本文件读取键值对数据,每一行独立处理,键与值之间用制表符隔开。
scala
val input = sc.hadoopFile[Text,Text,scala](inputFile).map{
case (x,y) => (x.toString,y.toString)
}
2.保存hadoop输出格式
3.非文件系统数据源
4.示例:protocol buffer
文件压缩
对数据进行压缩节省网络开销
有些输入格式,如SequenceFile允许只压缩键值对中数据的值
文件系统
本地/常规文件系统
sc.textFile("file:///'***.txt)
Amazon S3
HDFS
只需要把输入输出路径指定为hdfs://master:port/path
Spark SQL中的结构化数据
Spark SQL操作结构化和半结构化的数据的方式
hive
Spark SQL可以读取Hive支持的所有表
from pyspark.sql import HiveContext
hiveCtx = HiveContext(sc)
rows = hiveCtx("select name from uers")
firstRow = rows.first()
print(firstRow.name)
json
注册为一张表,然后取出特定字段
tweets = hiveCtx.jsonFile("tweets.json")
tweets.registerTempTable("tweets")
results = hiveCtx.sql("select name from uers")
数据库
java数据库连接
Cassandra
HBase
Elasticsearch
参考:《Spark快速大数据分析》
所有代码可以参考:https://github.com/databricks/learning-spark