将DataFrame操作应用于mapWithState中的单行

时间:2017-04-26 06:44:40

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

我使用Scala 2.11使用spark 2.1.0。我需要为每个键以Map [String,Any]格式存储状态。解决我问题的正确候选人似乎是mapWithState()PairDStreamFunctions中定义了mapWithState()。我正在应用{DARream} DStream[Row]的类型为mapWithState()。在应用dstream.map(row=> (row.get(0), row)) 之前,我这样做:

Tuple2[Any, Row]

现在我的DStream属于def stateUpdateFunction(): (Any, Option[Row], State[Map[String, Any]]) => Option[Row] = { (key, newData, stateData) => { if (stateData.exists()) { var oldState = stateData.get() stateData.update(Map("count" -> newData.get.get(1), "sum" -> newData.get.get(2))) Some(Row.fromSeq(newData.get.toSeq.++(Seq(oldState.get("count").get, oldState.get("sum").get)))) } else { stateData.update(Map("count" -> newData.get.get(1), "sum" -> newData.get.get(2))) Some(Row.fromSeq(newData.get.toSeq.++(Seq[Any](null, null)))) } } } 类型。在这个DStream上,我应用mapWithState,这是我的updatefunction的外观:

var transformedRow = originalRow.select(concat(upper($"C0"), lit("dummy")), lower($"C1") ...)

现在,更新功能仅在Map中存储2个值(每个键),并将针对“count”和“sum”存储的旧值附加到输入Row并返回。状态映射由输入行中新传递的值更新。我的要求是能够像在DataFrame上那样在输入行上执行复杂的操作,然后将它们存储在状态Map中。换句话说,我希望能够做到这样的事情:

android:windowSoftInputMode="adjustPan"

在update-function中,我无权访问SparkContext或SparkSession。所以,我无法创建单行DataFrame。如果我能做到这一点,应用DataFrame操作并不困难。我为转换的行定义了所有列表达式。

这是我的操作顺序: readState->在输入行上使用此状态执行复杂的DataFrame操作 - >执行更复杂的DataFrame操作以定义状态的新值。

是否可以获取与DataFrame查询/操作相对应的SparkPlan / logicalPlan并将其应用于单个spark-sql Row?我非常感谢这里的任何线索。如果问题不明确或需要更多细节,请告诉我。

1 个答案:

答案 0 :(得分:0)

我发现了一个针对给定问题的效率不高的解决方案。通过我们已知的DataFrame操作,我们可以使用已知的模式创建一个空的DataFrame。这个DataFrame可以通过

给我们SparkPlan
DataFrame.queryExecution.sparkPlan

此对象是可序列化的,可以传递给stateUpdateFunction。在stateUpdateFunction中,我们可以迭代传递的SparkPlan中包含的表达式,转换它以用相应的文字替换未解析的属性:

sparkPlan.expressions.map(expr=>{
            expr.transform{
              case attr: AttributeReference =>
                println(s"Resolving ${attr.name} to ${map.getOrElse(attr.name, null)}, type: ${map.getOrElse(attr.name, null).getClass().toString()}")
                Literal(map.getOrElse(attr.name, null))
              case a => a
            }
          })

此处的地图指的是Row的列值对。在这些转换的表达式上,我们将eval称为空的InternalRow。这给了我们与每个表达式相对应的结果。因为这种方法涉及解释性评估并且不使用代码生成,所以在现实世界的用例中使用它是低效的。但我会进一步深入研究如何在这里利用代码生成。