Scala UDF连接隐藏在行对象中的未定义Case类的数组

Scala UDF连接隐藏在行对象中的未定义Case类的数组,scala,apache-spark,apache-spark-sql,spark-dataframe,Scala,Apache Spark,Apache Spark Sql,Spark Dataframe,我有一个名为sessions的数据框架,其中的列可能会随着时间的推移而变化。(编辑以澄清:我没有列的case类-只有一个反映的架构。)我将在外部范围中始终有一个uuid和clientId,以及一些其他可能构成跟踪事件的内部和外部范围列,因此。。。比如: root |-- runtimestamp: long (nullable = true) |-- clientId: long (nullable = true) |-- uuid: string (nullable = true) |

我有一个名为sessions的数据框架,其中的列可能会随着时间的推移而变化。(编辑以澄清:我没有列的case类-只有一个反映的架构。)我将在外部范围中始终有一个uuid和clientId,以及一些其他可能构成跟踪事件的内部和外部范围列,因此。。。比如:

root
 |-- runtimestamp: long (nullable = true)
 |-- clientId: long (nullable = true)
 |-- uuid: string (nullable = true)
 |-- oldTrackingEvents: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- timestamp: long (nullable = true)
 |    |    |-- actionid: integer (nullable = true)
 |    |    |-- actiontype: string (nullable = true)
 |    |    |-- <tbd ... maps, arrays and other stuff matches sibling> section
 ...
 |-- newTrackingEvents: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- timestamp: long (nullable = true)
 |    |    |-- actionid: integer (nullable = true)
 |    |    |-- actiontype: string (nullable = true)
 |    |    |-- <tbd ... maps, arrays and other stuff matches sibling>      
 ...
在每一行。。。以内存/速度高效的方式获取单个“trackingEvents”结构数组

补充:

看着向我展示的一个问题。。。有一个可能的暗示,如果相关性存在<代码>要创建传递给udf的结构函数,必须返回产品类型(元组*或案例类),而不是行。 也许。。。这另一个职位是相关的/有用的

我想这一切都可以解释,所以我重申一下。使用
udf
时:

  • StructType
    的输入表示是弱类型的
    对象
  • StructType
    的输出类型必须是Scala
    Product
    。不能返回
    对象
如果这是一个很大的负担,您应该使用强类型的
Dataset

val f: T => U 
sessions.as[T].map(f): Dataset[U]

其中,
T
是表示
Session
模式的代数数据类型,
U
是表示结果的代数数据类型。

或者。。。如果您的目标是通过一些操作来合并一些随机行结构/模式的序列,那么这是一种替代的、通常说明的方法,可以避免分区讨论:

从主数据帧中,为每个trackingEvents部分创建数据帧,
new
old
。使用每个选项,选择分解的“trackingEvents”部分的列。将这些
val
数据帧声明保存为
newTE
oldTE

创建另一个数据帧,其中拾取的列对于
oldTrackingEvents
newTrackingEvents
数组中的每个跟踪事件都是唯一的,例如每个跟踪事件的
uuid
clientId
和事件
时间戳
。您的伪模式将是:

(uuid:String,clientId:Long,newTE:Seq[Long],oldTE:Seq[Long])

使用UDF连接结构的两个简单序列,都是
Seq[Long]
,这是一个“类似于未测试的”示例:

val limitEventsUDF = udf { (newTE: Seq[Long], oldTE: Seq[Long], limit: Int, tooOld: Long) => {
    (newTE ++ oldTE).filter(_ > tooOld).sortWith(_ > _).distinct.take(limit) 
}}
UDF将返回一个已清除跟踪事件的数据帧&您现在有了一个非常纤细的数据帧,其中包含已删除的事件,可以在合并后自动连接回分解的
newTE
oldTE

根据需要使用收集列表进行分组


还是。。。这似乎是一个很大的工作-这是否应该作为
“答案”
投票-我不确定

我开始明白你的意思了。我认为问题在于我没有代数数据类型。。。我只有一个由
sessions.select('oldTrackingEvents.schema
(因为这是灵活的类型)推断出的模式,我认为这个模式需要转换为scala.product。顺便说一句,我还被迫使用Spark 1.6。也许有一种方法可以将Seq[Elem]的两列连接到新列中Seq[Elem]的一列,只使用select语句?是的。“trackingEvents”(trackingEvent数组)列中有列表、地图和结构。。。这些可以更改,因此我也不能硬编码case类。
val f: T => U 
sessions.as[T].map(f): Dataset[U]
val limitEventsUDF = udf { (newTE: Seq[Long], oldTE: Seq[Long], limit: Int, tooOld: Long) => {
    (newTE ++ oldTE).filter(_ > tooOld).sortWith(_ > _).distinct.take(limit) 
}}