Parquet介绍
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等),并且它是语言和平台无关的。Parquet最初是由Twitter和Cloudera(由于Impala的缘故)合作开发完成并开源,
2015
年
5
月从Apache的孵化器里毕业成为Apache顶级项目
。
另外,随着嵌套格式的数据的需求日益增加,目前Hadoop生态圈中主流的查询引擎都支持更丰富的数据类型,例如Hive、SparkSQL、Impala等都原生的支持诸如struct、map、array这样的复杂数据类型,这样也就使得诸如Parquet这种原生支持嵌套数据类型的存储格式也变得至关重要,性能也会更好。
列式存储列式存储,顾名思义就是按照列进行存储数据,把某一列的数据连续的存储,每一行中的不同列的值离散分布。列式存储技术并不新鲜,在关系数据库中都已经在使用,尤其是在针对OLAP场景下的数据存储,由于OLAP场景下的数据大部分情况下都是批量导入,基本上不需要支持单条记录的增删改操作,而查询的时候大多数都是只使用部分列进行过滤、聚合,对少数列进行计算(基本不需要select * from xx之类的查询)。列式存储可以大大提升这类查询的性能,较之于行是存储,列式存储能够带来这些优化:
由于每一列中的数据类型相同,所以可以针对不同类型的列使用不同的编码和压缩方式,这样可以大大降低数据存储空间。
读取数据的时候可以把映射(Project)下推,只需要读取需要的列,这样可以大大减少每次查询的I/O数据量,更甚至可以支持谓词下推,跳过不满足条件的列。
由于每一列的数据类型相同,可以使用更加适合CPU pipeline的编码方式,减小CPU的缓存失效。
Parquet仅仅是一种存储格式,它是语言、平台无关的,并且不需要和任何一种数据处理框架绑定,目前能够和Parquet适配的组件包括下面这些,可以看出基本上通常使用的查询引擎和计算框架都已适配,并且可以很方便的将其它序列化工具生成的数据转换成Parquet格式。
代码如下:
parquet文件在 spark 安装目录下有测试文件 /opt/module/spark/examples/src/main/resources
object SparkParquetDemo {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("SparkParquetDemo").master("local[*]").getOrCreate()
//val userDF = spark.read.load("C:\\Users\\LUFFY\\Desktop\\testData\\users.parquet") 也 ok ,因为默认读取 parquet 文件
//val userDF = spark.read.option("path", "C:\\Users\\LUFFY\\Desktop\\testData\\users.parquet").load() 也 ok
val userDF = spark.read.format("parquet").load("C:\\Users\\LUFFY\\Desktop\\testData\\users.parquet")
userDF.printSchema()
userDF.show()
userDF.select("name","favorite_color").show()
userDF.select("name","favorite_numbers").write.format("json")
.save("C:\\Users\\LUFFY\\Desktop\\testData\\users")
spark.stop()
}
}
运行结果如下
也可以通过 spark-sql 操作 parquet 文件
#创建表
CREATE TEMPORARY VIEW parquetTable
USING org.apache.spark.sql.parquet
OPTIONS (
path "/users.parquet"
)
#执行查询
SELECT * FROM parquetTable