使用带有不同架构/数据类型的spark 2.x合并两个DataFrame

时间:2018-09-01 19:21:07

标签: scala apache-spark hive apache-spark-sql

我正在尝试使用spark合并多个配置单元表,其中一些具有相同名称的列具有不同的数据类型,尤其是string和bigint。

我的决赛桌(hiveDF)应该具有如下模式-

+--------------------------+------------+----------+--+
|         col_name         | data_type  | comment  |
+--------------------------+------------+----------+--+
| announcementtype         | bigint     |          |
| approvalstatus           | string     |          |
| capitalrate              | double     |          |
| cash                     | double     |          |
| cashinlieuprice          | double     |          |
| costfactor               | double     |          |
| createdby                | string     |          |
| createddate              | string     |          |
| currencycode             | string     |          |
| declarationdate          | string     |          |
| declarationtype          | bigint     |          |
| divfeerate               | double     |          |
| divonlyrate              | double     |          |
| dividendtype             | string     |          |
| dividendtypeid           | bigint     |          |
| editedby                 | string     |          |
| editeddate               | string     |          |
| exdate                   | string     |          |
| filerecordid             | string     |          |
| frequency                | string     |          |
| grossdivrate             | double     |          |
| id                       | bigint     |          |
| indicatedannualdividend  | string     |          |
| longtermrate             | double     |          |
| netdivrate               | double     |          |
| newname                  | string     |          |
| newsymbol                | string     |          |
| note                     | string     |          |
| oldname                  | string     |          |
| oldsymbol                | string     |          |
| paydate                  | string     |          |
| productid                | bigint     |          |
| qualifiedratedollar      | double     |          |
| qualifiedratepercent     | double     |          |
| recorddate               | string     |          |
| sharefactor              | double     |          |
| shorttermrate            | double     |          |
| specialdivrate           | double     |          |
| splitfactor              | double     |          |
| taxstatuscodeid          | bigint     |          |
| lastmodifieddate         | timestamp  |          |
| active_status            | boolean    |          |
+--------------------------+------------+----------+--+

可以使用下面的JSON-

来创建此最终表(hiveDF)模式
{
"id": -2147483647,
"productId": 150816,
"dividendTypeId": 2,
"dividendType": "Dividend/Capital Gain",
"payDate": null,
"exDate": "2009-03-25",
"oldSymbol": "ILAAX",
"newSymbol": "ILAAX",
"oldName": "",
"newName": "",
"grossDivRate": 0.115,
"shortTermRate": 0,
"longTermRate": 0,
"splitFactor": 0,
"shareFactor": 0,
"costFactor": 0,
"cashInLieuPrice": 0,
"cash": 0,
"note": "0",
"createdBy": "Yahoo",
"createdDate": "2009-08-03T06:44:19.677-05:00",
"editedBy": "Yahoo",
"editedDate": "2009-08-03T06:44:19.677-05:00",
"netDivRate": null,
"divFeeRate": null,
"specialDivRate": null,
"approvalStatus": null,
"capitalRate": null,
"qualifiedRateDollar": null,
"qualifiedRatePercent": null,
"declarationDate": null,
"declarationType": null,
"currencyCode": null,
"taxStatusCodeId": null,
"announcementType": null,
"frequency": null,
"recordDate": null,
"divOnlyRate": 0.115,
"fileRecordID": null,
"indicatedAnnualDividend": null
}

我正在做下面的事情-

var hiveDF = spark.sqlContext.sql("select * from final_destination_tableName")
var newDataDF = spark.sqlContext.sql("select * from incremental_table_1 where id > 866000")

我的增量表(newDataDF)的某些列具有不同的数据类型。我大约有10个增量表,其中bigint的某个地方,其他表中的某个地方与字符串相同,因此无法确定是否进行类型转换。类型转换可能很容易,但是我不确定应该使用哪种类型,因为那里有多个表。我正在寻找没有类型转换就可以做的任何方法。

例如,增量表示例如下-

+--------------------------+------------+----------+--+
|         col_name         | data_type  | comment  |
+--------------------------+------------+----------+--+
| announcementtype         | string     |          |
| approvalstatus           | string     |          |
| capitalrate              | string     |          |
| cash                     | double     |          |
| cashinlieuprice          | double     |          |
| costfactor               | double     |          |
| createdby                | string     |          |
| createddate              | string     |          |
| currencycode             | string     |          |
| declarationdate          | string     |          |
| declarationtype          | string     |          |
| divfeerate               | string     |          |
| divonlyrate              | double     |          |
| dividendtype             | string     |          |
| dividendtypeid           | bigint     |          |
| editedby                 | string     |          |
| editeddate               | string     |          |
| exdate                   | string     |          |
| filerecordid             | string     |          |
| frequency                | string     |          |
| grossdivrate             | double     |          |
| id                       | bigint     |          |
| indicatedannualdividend  | string     |          |
| longtermrate             | double     |          |
| netdivrate               | string     |          |
| newname                  | string     |          |
| newsymbol                | string     |          |
| note                     | string     |          |
| oldname                  | string     |          |
| oldsymbol                | string     |          |
| paydate                  | string     |          |
| productid                | bigint     |          |
| qualifiedratedollar      | string     |          |
| qualifiedratepercent     | string     |          |
| recorddate               | string     |          |
| sharefactor              | double     |          |
| shorttermrate            | double     |          |
| specialdivrate           | string     |          |
| splitfactor              | double     |          |
| taxstatuscodeid          | string     |          |
| lastmodifieddate         | timestamp  |          |
| active_status            | boolean    |          |
+--------------------------+------------+----------+--+

我正在为下面的表做这个联合-

var combinedDF = hiveDF.unionAll(newDataDF)

但是没有运气。我试图给出如下的最终方案,但是没有运气-

val rows = newDataDF.rdd
val newDataDF2 = spark.sqlContext.createDataFrame(rows, hiveDF.schema)
var combinedDF = hiveDF.unionAll(newDataDF2)
combinedDF.coalesce(1).write.mode(SaveMode.Overwrite).option("orc.compress", "snappy").orc("/apps/hive/warehouse/" + database + "/" + tableLower + "_temp")

根据this,我尝试了以下操作-

var combinedDF = sparkSession.read.json(hiveDF.toJSON.union(newDataDF.toJSON).rdd)

最后我试图像上面那样写到表中,但是没有运气,请帮助我-

1 个答案:

答案 0 :(得分:0)

在将增量表与现有表合并时,我也遇到了这种情况。通常有2种情况要处理

1。带有额外列的增量数据:

这可以通过您在此处尝试的正常合并过程来解决。

2。具有相同列名但架构不同的增量数据:

这是一个棘手的问题。一种简单的解决方案是将bot数据转换为JSON并进行联合 hiveDF.toJSON.union(newDataDF.toJSON)。但是,这将导致JSON模式合并并更改现有模式。例如:如果表中的列a:Long和增量表中的a:String列,则合并后的最终架构将为a:String。如果您想进行json合并,则无法逃避此操作。

替代方法是对增量数据进行严格的模式检查。如果架构不同,请测试增量表是否具有与配置单元表相同的架构。

但是,对于实时数据而言,这有点太严格了,很难实施模式。

因此,我解决此问题的方法是在合并之前进行单独的浓缩过程。该过程实际上会检查架构,并且是否可以将传入列升级/降级为当前的配置单元表架构。

基本上,它会迭代传入的增量,对于每一行,请将其转换为正确的架构。这虽然价格不高,但为数据正确性提供了很好的保证。如果该过程无法转换行。我在该行旁并发出警报,以便可以手动验证数据是否针对正在生成数据的上游系统中的任何错误。

这是code,我用来验证这两种模式是否可合并。