如何使用Scala通过spark中的spark中的一个或多个字符串参数传递selectExpr中的列名?

时间:2019-10-27 03:24:22

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

我正在火花流中使用CDC Merge脚本。我希望通过一个参数传递selectExpr中的列值,因为每个表的列名都会改变。当我通过字符串变量传递column和struct字段时,由于==>输入''不匹配,我得到了错误,期望

下面是我要参数化的代码段。

var filteredMicroBatchDF=microBatchOutputDF
.selectExpr("col1","col2","struct(offset,KAFKA_TS) as otherCols" )
.groupBy("col1","col2").agg(max("otherCols").as("latest"))
.selectExpr("col1","col2","latest.*")

参考我尝试模仿的脚本:- https://docs.databricks.com/_static/notebooks/merge-in-cdc.html

我已经尝试过以下方法,将列名传递给变量,然后从这些变量中读取selectExpr:-

val keyCols = "col1","col2"
val structCols = "struct(offset,KAFKA_TS) as otherCols" 

var filteredMicroBatchDF=microBatchOutputDF
.selectExpr(keyCols,structCols )
.groupBy(keyCols).agg(max("otherCols").as("latest"))
.selectExpr(keyCols,"latest.*")

当我运行脚本时,它给我以下错误: org.apache.spark.sql.streaming.StreamingQueryException: mismatched input ',' expecting <<EOF>>

编辑

以下是我在路易斯·米格尔(Luis Miguel)评论后尝试过的方法,效果很好:-

import org.apache.spark.sql.{DataFrame, functions => sqlfun}

def foo(microBatchOutputDF: DataFrame)
       (keyCols: Seq[String], structCols: Seq[String]): DataFrame =
  microBatchOutputDF
    .selectExpr((keyCols ++ structCols) : _*)
    .groupBy(keyCols.head, keyCols.tail : _*).agg(sqlfun.max("otherCols").as("latest"))
    .selectExpr((keyCols :+ "latest.*") : _*)

var keyColumns = Seq("COL1","COL2")
var structColumns = "offset,Kafka_TS"

foo(microBatchOutputDF)(keyCols = Seq(keyColumns:_*), structColumns = Seq("struct("+structColumns+") as otherCols"))

注意:以下内容会导致错误

foo(microBatchOutputDF)(keyCols = Seq(keyColumns), structColumns = Seq("struct("+structColumns+") as otherCols"))

与上面的工作代码有关的是,这里的keyColumns是硬编码的。因此,我尝试(首先)从参数文件读取,(第二)从窗口小部件读取,这导致了错误,在这里我正在寻找建议和建议:-

第一种方法

def loadProperties(url: String):Properties = {
    val properties: Properties = new Properties()
    if (url != null) {
      val source = Source.fromURL(url)
      properties.load(source.bufferedReader())
    }
  return properties
}
var tableProp: Properties = new Properties()
tableProp = loadProperties("dbfs:/Configs/Databricks/Properties/table/Table.properties") 
var keyColumns = Seq(tableProp.getProperty("keyCols"))
var structColumns = tableProp.getProperty("structCols")

keyCols和StructCols在参数文件中定义为:-

keyCols = Col1, Col2 (我也尝试将它们分配为“ Col1”,“ Col2”)
StructCols = offset,Kafka_TS

最后,

foo(microBatchOutputDF)(keyCols = Seq(keyColumns:_*), structColumns = Seq("struct("+structColumns+") as otherCols"))

代码抛出指向第一个逗号的错误(就像它以columns字段作为单个参数一样):
mismatched input ',' expecting <EOF>
== SQL ==
"COL1","COL2""
-----^^^

如果仅在keyCols属性中传递一列,则代码工作正常。
例如。 keyCols = Col1

第二种方法
在这里,我尝试再次从小部件读取键列及其相同的错误。

dbutils.widgets.text("prmKeyCols", "","") 
val prmKeyCols = dbutils.widgets.get("prmKeyCols") 
var keyColumns = Seq(prmKeyCols)

该小部件将按以下方式传递
"Col1","Col2"

最后,

foo(microBatchOutputDF)(keyCols = Seq(keyColumns:_*), structColumns = Seq("struct("+structColumns+") as otherCols"))

这也给出了相同的错误。

1 个答案:

答案 0 :(得分:2)

类似的事情应该起作用:

import org.apache.spark.sql.{DataFrame, functions => sqlfun}

def foo(microBatchOutputDF: DataFrame)
       (keyCols: Seq[String], structCols: Seq[String]): DataFrame =
  microBatchOutputDF
    .selectExpr((keyCols ++ structCols) : _*)
    .groupBy(keyCols.head, keyCols.tail : _*).agg(sqlfun.max("otherCols").as("latest"))
    .selectExpr((keyCols :+ "latest.*") : _*)

您可以像这样使用:

foo(microBatchOutputDF)(keyCols = Seq("col1", "col2"), structCols = Seq("struct(offset,KAFKA_TS) as otherCols"))