我知道使用from input
select time:timestampInMilliseconds(time:dateAdd("2016-11-14 19:40:00", 5, 'minute',"yyyy-MM-dd HH:mm:ss"),'yyyy-MM-dd HH:mm:ss') as tm
insert into tmp;
from tmp#window.externalTime(tm,10 min)
select .....
和.withColumn()
向Spark DataSet添加新列的方法,它返回一个DataFrame。我也知道,我们可以将生成的DataFrame转换为DataSet。
我的问题是:
例如:
UDF
我使用 scala> case class Temp(a : Int, b : String) //creating case class
scala> val df = Seq((1,"1str"),(2,"2str),(3,"3str")).toDS // creating DS
scala> val appendUDF = udf( (b : String) => b + "ing") // sample UDF
scala> df.withColumn("c",df("b")) // adding a new column
res5: org.apache.spark.sql.DataFrame = [a: int, b: string ... 1 more field]
scala> res5.as[Temp] // converting to DS
res6: org.apache.spark.sql.Dataset[Temp] = [a: int, b: string ... 1 more field]
scala> res6.map( x =>x.
// list of autosuggestion :
a canEqual equals productArity productIterator toString
b copy hashCode productElement productPrefix
添加的新列c
无法访问,因为列.withColumn()
不在案例类c
中(它只包含{{} 1}}& Temp
)在使用a
转换为DS的瞬间。
如何访问列b
?
答案 0 :(得分:6)
在Dataset
s的类型安全的世界中,您将结构映射到另一个结构。
也就是说,对于每次转换,我们都需要数据的模式表示(因为它是RDD所需的)。访问' c'上面,我们需要创建一个新模式来提供对它的访问。
case class A(a:String)
case class BC(b:String, c:String)
val f:A => BC = a=> BC(a.a,"c") // Transforms an A into a BC
val data = (1 to 10).map(i => A(i.toString))
val dsa = spark.createDataset(data)
// dsa: org.apache.spark.sql.Dataset[A] = [a: string]
val dsb = dsa.map(f)
//dsb: org.apache.spark.sql.Dataset[BC] = [b: string, c: string]
答案 1 :(得分:3)
只是为了添加@ maasg的优秀答案......
如果我们仍然遵循传统的DF方法(即将列名称作为UDF输入的字符串传递),DataSet的类型安全如何在这里发挥作用
让我用另一个问题回答这个问题"我们是谁?我们仍在关注......'"?如果您认为我,我不同意并仅使用DataFrames,因为我懒得创建一个案例类来描述要使用的数据集。
我对UDF的回答是远离UDF,除非它们非常简单并且Spark Optimizer无法优化。是的,我确实相信UDF太容易定义和使用,我自己被带走太多次以来(过度)使用它们。 Spark SQL 2.0中有大约239个函数,你可以认为很难想到没有UDF但是标准函数的解决方案。
scala> spark.version
res0: String = 2.1.0-SNAPSHOT
scala> spark.catalog.listFunctions.count
res1: Long = 240
(上面240是因为我注册了一个UDF)。
您应始终使用标准功能,因为它们可以进行优化。 Spark可以控制您正在做的事情,从而优化您的查询。
您还应该使用数据集(不是Dataset[Row]
,即DataFrame
),因为它们可以让您访问对字段的类型安全访问。
(然而,由于数据集编程完全与Scala自定义代码无关,因此无法对基于DataFrame的代码进行优化,因此无法对某些数据集"好东西"进行优化
是否有"面向对象的方式"访问列(不将列名称作为字符串传递),就像我们以前用RDD一样,用于追加新列。
是。当然。用例类定义数据集的模式并使用字段。两者都可以访问和添加(@maasg很好地响应了所以我不会在这里重复他的话。)
如何在正常操作中访问新列,例如map,filter等?
易......一次。使用描述数据集(模式)的案例类。你如何添加一个新的"东西"到现有的对象?除非以某种方式接受了新列,否则你不能这样做吗?
In""面向对象的方式"访问列或附加新列。"如果您的列是案例类的属性,则不能说"这是一个描述数据的类,同时说这是一个可能具有新属性的类"。它在OOP / FP中是不可能的,是吗?
这就是为什么添加新列可以归结为使用其他案例类或使用withColumn
。那有什么不对?我认为......简直......没有错。