Apache spark Spark知道数据帧的分区键吗?
我想知道Spark是否知道拼花地板文件的分区键,并使用此信息来避免混乱 上下文: 运行Spark 2.0.1运行本地SparkSession。我在磁盘上保存了一个csv数据集作为拼花文件,如下所示:Apache spark Spark知道数据帧的分区键吗?,apache-spark,partitioning,window-functions,Apache Spark,Partitioning,Window Functions,我想知道Spark是否知道拼花地板文件的分区键,并使用此信息来避免混乱 上下文: 运行Spark 2.0.1运行本地SparkSession。我在磁盘上保存了一个csv数据集作为拼花文件,如下所示: val df0 = spark .read .format("csv") .option("header", true) .option("delimiter", ";") .option("inferSchema", false) .load("SomeFile.csv")
val df0 = spark
.read
.format("csv")
.option("header", true)
.option("delimiter", ";")
.option("inferSchema", false)
.load("SomeFile.csv"))
val df = df0.repartition(partitionExprs = col("numerocarte"), numPartitions = 42)
df.write
.mode(SaveMode.Overwrite)
.format("parquet")
.option("inferSchema", false)
.save("SomeFile.parquet")
我正在按列numerocate
创建42个分区。这应该将多个numerocarte
分组到同一分区。我不想在写入时执行partitionBy(“numerocate”),因为我不希望每张卡都有一个分区。这将是数百万人
在另一个脚本中,我阅读了这个SomeFile.parquet
parquet文件并对其进行了一些操作。特别是,我在上面运行了一个窗口函数
,其中分区是在拼花地板文件被重新分区的同一列上完成的
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val df2 = spark.read
.format("parquet")
.option("header", true)
.option("inferSchema", false)
.load("SomeFile.parquet")
val w = Window.partitionBy(col("numerocarte"))
.orderBy(col("SomeColumn"))
df2.withColumn("NewColumnName",
sum(col("dollars").over(w))
在读取后
我可以看到重新分区
按预期工作,DataFramedf2
有42个分区,每个分区中都有不同的卡
问题:
Spark是否知道数据帧df2
由列Numerocate
进行分区
如果它知道,那么窗口函数中就不会有随机播放。是吗
如果它不知道,它将在窗口函数中执行洗牌。是吗
如果它不知道,我如何告诉Spark数据已经被右列分区
如何检查DataFrame
的分区键?有这个命令吗?我知道如何检查分区数,但如何查看分区键李>
当我在每个步骤后打印文件中的分区数时,我在read
之后有42个分区,在withColumn
之后有200个分区,这表明Spark重新分区了我的DataFrame
如果有两个不同的表使用同一列重新分区,那么连接会使用该信息吗
Spark知道数据帧df2是由列Numerocate分区的吗
事实并非如此
如果它不知道,我如何告诉Spark数据已经被右列分区
你没有。仅仅因为您保存了已被洗牌的数据,并不意味着它将加载相同的拆分
如何检查DataFrame的分区键
加载数据后没有分区键,但可以检查分区器的queryExecution
实际上:
- 如果要支持有效的按键,请使用
DataFrameWriter
的partitionBy
方法
- 如果希望对联接优化提供有限的支持,请将
bucketBy
与metastore和持久表结合使用
有关详细示例,请参见。我正在回答自己的问题,以备将来参考
以下是@user8371915的建议,bucketBy works
我正在保存数据帧df
:
df.write
.bucketBy(250, "userid")
.saveAsTable("myNewTable")
然后,当我需要加载此表时:
val df2 = spark.sql("SELECT * FROM myNewTable")
val w = Window.partitionBy("userid")
val df3 = df2.withColumn("newColumnName", sum(col("someColumn")).over(w)
df3.explain
我确认当我在df2
上执行由userid
分区的窗口功能时,不会出现无序移动!谢谢@user8371915
我在调查过程中学到的一些东西
- myNewTable看起来像一个普通的拼花锉刀,但事实并非如此。您可以使用
spark.read.format(“parquet”).load(“path/to/myNewTable”)
正常读取它,但是以这种方式创建的DataFrame
将不会保留原始分区!必须使用spark.sql
选择
,才能正确分区DataFrame
- 您可以使用
spark.sql(“descripe formatted myNewTable”).collect.foreach(println)
查看表内部。这将告诉您使用了哪些列来制作木桶,以及有多少个木桶
- 利用分区的窗口函数和联接通常也需要排序。您可以在写入时使用
.sortBy()
对存储桶中的数据进行排序,排序也将保留在配置单元表中df.write.bucketBy(250,“userid”).sortBy(“somColumnName”).saveAsTable(“myNewTable”)
- 在本地模式下工作时,表
myNewTable
保存到本地Scala SBT项目中的spark warehouse
文件夹中。通过spark submit
以集群模式使用mesos进行保存时,会将其保存到hive warehouse。对我来说,它位于/user/hive/warehouse
- 执行
spark submit
时,您需要向SparkSession
添加两个选项:.config(“hive.metastore.uris”thrift://addres-to-your-master:9083”
和.enableHiveSupport()
。否则,您创建的配置单元表将不可见
- 如果要将表保存到特定的数据库,请在备份前执行
spark.sql(“使用您的数据库”)
2018年2月5日更新
我在spark bucketing和创建蜂巢表时遇到了一些问题。请参阅中的问题、答复和评论,以检查您应该查看底层RDD的分区器数据框架<代码>df.rdd.partitioner
。如果两个dfs具有相同的分区器,则可能不存在洗牌。您可以通过调用df来检查是否会出现混洗。解释。要检查分区数,请调用df.rdd.partitions.length
。要更完整地解释分区,请参阅Spark Warehouse中的保存也将元数据保存在Metastore中,如分区、顺序等:),但这只是一个小问题addition@T.Gawęda但之前的操作没有元数据,是吗?请注意,OP使用重新分区
。我必须检查,但是重新分区
应该明确添加分区信息。然而,这是一个更为“常见”的补充,与问题关系不大;)准确地说。已向上投票:)来自