(一) 加载数据
加载Parquet数据源,并将加载后的people使用createOrReplaceTempView方法注册到临时表中,然后使用SQL语句对该临时表进行操作,最后将操作结果打印出来。
scala> valpeople =spark.read.parquet("/resources/people.parquet")
18/02/18 08:51:40WARN metastore.ObjectStore: Failed to get database global_temp, returningNoSuchObjectException
people:org.apache.spark.sql.DataFrame = [age: bigint, name: string]
scala>people.createOrReplaceTempView("parquetFile")
scala> valteenagers = spark.sql("SELECT name FROM parquetFile WHERE age >= 13 ANDage <= 19")
teenagers:org.apache.spark.sql.DataFrame = [name: string]
scala>teenagers.show
+------+
| name|
+------+
|Justin|
+------+
(二) 分区发现
在类似于Hive的系统上,表分区是一种常见的优化方法。在一个分区表中,数据通常存储在不同的目录中,将分区列值编码到每个分区目录的路径上。Parquet数据源可以自动地发现和推导分区信息。
例如,我们可以带上额外的列gender,作为我们的分区列,用以下目录结构,将员工信息数据存储到分区表中:
path
└── to
└── table
├── gender=male
│ └── data.parquet
└── gender=female
│ └── data.parquet
│ └── ...
通过将分区表的路径传递到spark.read.parquet或spark.read.load,Spark SQL会自动地从路径中提取分区信息。返回的DataFrame/DataSet将构建Schema。
root
|-- name: string(nullable = true)
|-- age: long(nullable = true)
|-- gender: string(nullable = true)
|-- salary: string(nullable = true)
注意,用于分区的列的数据类型是自动推导的,自动推导支持数字数据类型和字符串类型。
分区发现案例参考以下“合并Schema”的案例。
(三) 合并Schema。
和ProtocolBuffer, Avro 和 Thrift 一样,Parquet也支持Schema演变,用户可以先使用一个简单的Schema,然后根据需要逐步添加更多的列到Schema中。通过这种方式,最终可以让多个不同的Parquet在Schema上互相兼容。Parquet数据源目前可以自动检测到这种情况,并合并所有这些文件。
以下案例说明合并Schema的详细步骤:
1) 构建一个元素值为(i,i * i)的RDD,并转化为列名为("value","square")的DataFrame,获取从1到5的每个元素的平方值。
scala> val squaresDF = spark.sparkContext.makeRDD(1to 5).map(i => (i, i * i)).toDF("value",
"square")
squaresDF:org.apache.spark.sql.DataFrame = [value: int, square: int]
2) 将构建的squaresDF存储到test_table的key=1子目录下。
scala> squaresDF.write.parquet("/data/test_table/key=1")
3) 构建一个元素值为(i,i * i* i)的RDD,并转化为列名为("value", "cube")的DataFrame,获取从6到10的每个元素的立方值。
scala> val cubesDF = spark.sparkContext.makeRDD(6to 10).map(i => (i, i * i * i)).toDF("value",
"cube")
cubesDF:org.apache.spark.sql.DataFrame = [value: int, cube: int]
4) 将构建的cubesDF存储到test_table的key=2子目录下。
scala> cubesDF.write.parquet("/data/test_table/key=2")
5) 通过数据源选项option("mergeSchema","true")启用模式合并,读取包含两个子目录的test_table目录,自动推导出对应的Parquet数据源的Schema信息。
scala> valmergedDF = spark.read.option("mergeSchema","true").parquet("/data/test_table")
mergedDF:org.apache.spark.sql.DataFrame = [value: int, square: int ... 2 more fields]
6) 打印mergedDF的Schema信息。
scala>mergedDF.printSchema()
root
|-- value: integer (nullable = true)
|-- square: integer (nullable = true)
|-- cube: integer (nullable = true)
|-- key: integer (nullable = true)
7) 查询squaresDF的数据。
scala>squaresDF.show
+-----+------+
|value|square|
+-----+------+
| 1| 1|
| 2| 4|
| 3| 9|
| 4| 16|
| 5| 25|
+-----+------+
8) 查询cubesDF的数据。
scala>cubesDF.show
+-----+----+
|value|cube|
+-----+----+
| 6| 216|
| 7| 343|
| 8| 512|
| 9| 729|
| 10|1000|
+-----+----+
9) 查询mergedDF的数据。
scala>mergedDF.show
+-----+------+----+---+
|value|square|cube|key|
+-----+------+----+---+
| 1| 1|null| 1|
| 2| 4|null| 1|
| 3| 9|null| 1|
| 4| 16|null| 1|
| 5| 25|null| 1|
| 6| null| 216| 2|
| 7| null| 343| 2|
| 8| null| 512| 2|
| 9| null| 729| 2|
| 10| null|1000| 2|
+-----+------+----+---+
Parquet数据分区保存后的Web Interface界面(http://192.168.189.1:50070/explorer.html#/data/test_table),如图3-5所示。
图 3 - 5 Parquet数据分区保存
合并Schema案例,首先通过spark.sparkContext.makeRDD方法构建一个RDD实例,然后调用RDD实例的toDF方法指定Schema,生成DataFrame实例,对应的Schema信息为:[value:int, square: int]。然后将该DataFrame实例squaresDF,保存到分区路径"/data/test_table/key=1"下。
用相同的方法构建DataFrame实例cubesDF,对应的Schema为[value: int, cube: int],cubesDF的Schema信息比squaresDF添加列”cube”列,同时删除了” square”列,然后保存到分区路径"/data/test_table/key=2"下。
最后读取分区表到Parquet,其路径为包含"/data/test_table/key=1"和"/data/test_table/key=2"两个路径的"/data/test_table"路径,加载构建DataFrame实例mergedDF之后,会自动推导出mergedDF的Schema信息,最终推导出的Schema信息为[value: int, square:int ... 2 more fields],包含列squaresDF和cubesDF的 ”value”,”square”和” cube”列信息,以及出现在分区路径上的 ”key”分区列信息。
注意:如果没有指定具体路径,在使用HDFS作为存储系统时,默认会放在HDFS文件系统中当前用户/user/root的目录下,例如” /user/root/data/test_table/”目录;如果指定具体路径,在指定的路径目录下“/data/test_table”,可以看到文件已经保存成功。
如果目录以/开头,则对应的是HDFS的根目录(对应core-site.xml中的fs.defaultFS配置属性),而非当前用户所在目录下。例如/data,对应为hdfs://namenode:port/data。其中namenode为启动NameNode进程的节点,当前环境下的节点地址为http://192.168.189.1。
2018年新春报喜!热烈祝贺王家林大咖大数据经典传奇著作《SPARK大数据商业实战三部曲》畅销书籍 清华大学出版社发行上市!
本书基于Spark 2.2.0最新版本(2017年7月11日发布),以Spark商业案例实战和Spark在生产环境下几乎所有类型的性能调优为核心,以Spark内核解密为基石,分为上篇、中篇、下篇,对企业生产环境下的Spark商业案例与性能调优抽丝剥茧地进行剖析。上篇基于Spark源码,从一个动手实战案例入手,循序渐进地全面解析了Spark 2.2新特性及Spark内核源码;中篇选取Spark开发中最具有代表的经典学习案例,深入浅出地介绍,在案例中综合应用Spark的大数据技术;下篇性能调优内容基本完全覆盖了Spark在生产环境下的所有调优技术。
本书适合所有Spark学习者和从业人员使用。对于有分布式计算框架应用经验的人员,本书也可以作为Spark高手修炼的参考书籍。同时,本书也特别适合作为高等院校的大数据教材使用。
当当网、京东、淘宝、亚马逊等网店已可购买!欢迎大家购买学习!