Parquet是一种列式存储格式,很多种处理引擎都支持这种存储格式,也是sparksql的默认存储格式。Spark SQL支持灵活的读和写Parquet文件,并且对parquet文件的schema可以自动解析。当Spark SQL需要写成Parquet文件时,处于兼容的原因所有的列都被自动转化为了nullable。
分区发现
分区表时很多系统支持的,比如hive,对于一个分区表,往往是采用表中的某一或多个列去作为分区的依据,分区是以文件目录的形式体现。所有内置的文件源(Text/CSV/JSON/ORC/Parquet)都支持自动的发现和推测分区信息。例如,我们想取两个分区列,gender和country,先按照性别分区,再按照国家分区。
从spark 1.6开始,分区发现默认情况只会发现给定路径下的分区。比如,上面的分区表,假如你讲路径path/to/table/gender=male传递给SparkSession.read.parquet 或者 SparkSession.read.load 那么gender不会被认为是分区列。如果想检测到该分区,传给spark的路径应该是其父路径也即是path/to/table/,这样gender就会被认为是分区列。
Schema合并
跟protocol buffer,avro,thrift一样,parquet也支持schema演变升级。用户可以在刚开始的时候创建简单的schema,然后根据需要随时扩展新的列。
spark sql 用Parquet 数据源支持自动检测新增列并且会合并schema。
由于合并schema是一个相当耗费性能的操作,而且很多情况下都是不必要的,所以从spark 1.5开始就默认关闭掉该功能。有两种配置开启方式:
-
通过数据源option设置mergeSchema为true。
-
在全局sql配置中设置spark.sql.parquet.mergeSchema 为true.
Hive Metastore Parquet表转换
当读写hive metastore parquet格式表的时候,Spark SQL为了较好的性能会使用自己默认的parquet格式而不是采用hive SerDe。该行为是通过参数spark.sql.hive.convertMetastoreParquet空值,默认是true。
Hive和parquet兼容性
从表schema处理角度讲hive和parquet有两个主要的区别
-
hive是大小写敏感的,但是parquet不是。
-
hive会讲所有列视为nullable,但是nullability在parquet里有独特的意义。
由于上面的原因,在将hive metastore parquet转化为spark parquet表的时候,需要处理兼容一下hive的schema和parquet的schema。
兼容处理的原则是:
-
有相同名字的字段必须要有相同的数据类型,忽略nullability。兼容处理的字段应该保持parquet侧的数据类型,这样就可以处理到nullability类型了。
-
兼容处理的schema应直接包含在hive元数据里的schema信息:
a. 任何仅仅出现在parquet schema的字段将会被删除
b. 任何仅仅出现在hive 元数据里的字段将会被视为nullable。
元数据刷新
Spark SQL为了更好的性能会缓存parquet的元数据。当spark 读取hive表的时候,schema一旦从hive转化为spark sql的,就会被spark sql缓存,如果此时表的schema被hive或者其他外部工具更新,必须要手动的去刷新元数据,才能保证元数据的一致性。
spark.catalog.refreshTable("my_table")
网友评论