Join 加入数据帧,在Spark 1.5.2的物理计划中创建CartesianProduct
当使用spark avro库连接从avro文件创建的数据帧时,我遇到了性能问题 数据帧由120K avro文件创建,总大小约为1.5 TB。 这两个数据帧非常巨大,包含数十亿条记录 这两个数据帧的连接将永远运行。 该流程在一个具有300个执行器、4个执行器芯和8GB内存的纱线簇上运行 任何关于这次加入的见解都会有所帮助。我已经在下面发布了解释计划。 我注意到实物平面图中有一个Cartesian产品。我想知道这是否是导致性能问题的原因 下面是逻辑计划和物理计划。(由于保密性质,我无法在此发布任何列名或文件名) 代码如下所示 val customerDateFormat=新的SimpleDateFormat(“yyyy/MM/dd”)Join 加入数据帧,在Spark 1.5.2的物理计划中创建CartesianProduct,join,apache-spark,dataframe,apache-spark-sql,cartesian,Join,Apache Spark,Dataframe,Apache Spark Sql,Cartesian,当使用spark avro库连接从avro文件创建的数据帧时,我遇到了性能问题 数据帧由120K avro文件创建,总大小约为1.5 TB。 这两个数据帧非常巨大,包含数十亿条记录 这两个数据帧的连接将永远运行。 该流程在一个具有300个执行器、4个执行器芯和8GB内存的纱线簇上运行 任何关于这次加入的见解都会有所帮助。我已经在下面发布了解释计划。 我注意到实物平面图中有一个Cartesian产品。我想知道这是否是导致性能问题的原因 下面是逻辑计划和物理计划。(由于保密性质,我无法在此发布任何列
val dates=新零售日期()
val dataStructures=新数据结构()
//读取CSV格式的输入文件--零售日期
//这个DF有75条记录
val retailDatesWithSchema=sqlContext.read
.format(“com.databricks.spark.csv”)
.选项(“分隔符“,”,”)
.schema(dates.retailDatesSchema)
.load(日期文件)
.合并(1)
.cache()
//创建自定义项以将字符串转换为日期
val dateUDF:(String=>java.sql.Date)=(dateString:String)=>new java.sql.Date(customerDateFormat.parse(dateString.getTime())
val stringToDateUDF=udf(日期udf)
//读取Avro格式的输入文件
//这个DF有5亿条记录
val userInputDf=sqlContext.read.avro(“customerLocation”)
val userDf=userInputDf.withColumn(“CAL_DT”),stringToDateUDF(col(“CAL_DT”))。选择(
“CAL_DT”、“用户ID”、“用户证书ID”
)
val userDimDf=sqlContext.read.avro(userDimFiles)。选择(“USER\u ID”、“USER\u CNTRY\u ID”、“PRIMARY\u USER\u ID”)//此DF有8亿条记录
val retailDatesWithSchemaBroadcast=sc.broadcast(retailDatesWithSchema)
val userDimDfBroadcast=sc.broadcast(userDimDf)
val userandetaildates=userDnaSdDf
.join((retailDatesWithSchemaBroadcast.value).as(“retailDates”),
在($“retailDates.WEEK\u BEGIN\u DATE”、$“retailDates.WEEK\u END\u DATE”)之间的userDf(“CAL\u DT”)
“内部”)
val userAndRetailDates和userdim=userAndRetailDates
.join((userDimDfBroadcast.value)
.WithColumnRename(“用户ID”、“用户ID\u用户ID”)
.WithColumnRename(“用户ID”、“用户ID\U国家ID”)
.as(“userdim”)
,userAndRetailDates(“USER\u ID”)$“userdim.USER\u DIM\u USER\u ID”
&&UserAndDetailDates(“用户\u CNTRY\u ID”)$“userdim.USER\u DIM\u COUNTRY\u ID”
“内部”)
userandretaildates和userdim.show()
谢谢,
Prasad。这里没有太多的内容(即使您的数据或列/表名称是机密的,查看一些代码可能会有用,这些代码可以显示您正在尝试实现的目标),但是
CartesianProduct
肯定是个问题。O(N^2)在大型数据集上,这是您真正想要避免的,在这种特殊情况下,它会触及Spark中的所有弱点
一般来说,如果联接扩展为显式笛卡尔积或等效运算,则表示联接表达式不是基于相等的,因此无法使用基于洗牌(或广播+哈希)的联接(SortMergeJoin
,HashJoin
)进行优化
编辑:
在您的情况下,以下情况最有可能是问题:
userDf("CAL_DT") between(
$"retailDates.WEEK_BEGIN_DATE", $"retailDates.WEEK_END_DATE")
例如,最好在userDf
上计算WEEK\u BEGIN\u DATE
,然后直接加入
$"userDf.WEEK_BEGIN_DATE" === $"retailDates.WEEK_BEGIN_DATE"
另一个小的改进是在不使用UDF的情况下解析日期,例如使用unix\u timestamp
函数
编辑:
这里的另一个问题,由指出的是,
在Spark中没有太多的内容(即使您的数据或列/表名是机密的,查看一些代码可能会有用,这些代码可以显示您试图实现的目标),但是CartesianProduct
肯定是一个问题。O(N^2)在大型数据集上,这是您真正想要避免的,在这种特殊情况下,它会触及Spark中的所有弱点
一般来说,如果联接扩展为显式笛卡尔积或等效运算,则表示联接表达式不是基于相等的,因此无法使用基于洗牌(或广播+哈希)的联接(SortMergeJoin
,HashJoin
)进行优化
编辑:
在您的情况下,以下情况最有可能是问题:
userDf("CAL_DT") between(
$"retailDates.WEEK_BEGIN_DATE", $"retailDates.WEEK_END_DATE")
例如,最好在userDf
上计算WEEK\u BEGIN\u DATE
,然后直接加入
$"userDf.WEEK_BEGIN_DATE" === $"retailDates.WEEK_BEGIN_DATE"
另一个小的改进是在不使用UDF的情况下解析日期,例如使用unix\u timestamp
函数
编辑:
这里的另一个问题是Spark中的