在 Spark UDF 中处理 XML 字符串并返回 Struct Field

Posted

技术标签:

【中文标题】在 Spark UDF 中处理 XML 字符串并返回 Struct Field【英文标题】:Processing XML string inside Spark UDF and return Struct Field 【发布时间】:2017-09-20 04:13:56 【问题描述】:

我有一个名为 Body(String) 的数据框列。正文列数据是这样的

<p>I want to use a track-bar to change a form's opacity.</p>

<p>This is my code:</p>

 <pre><code>decimal trans = trackBar1.Value / 5000;
this.Opacity = trans;
</code></pre>

<p>When I build the application, it gives the following error:</p>

<blockquote>
  <p>Cannot implicitly convert type 'decimal' to 'double'.</p>
</blockquote>

<p>I tried using <code>trans</code> and <code>double</code> but then the 
control doesn't work. This code worked fine in a past VB.NET project. </p>
,While applying opacity to a form should we use a decimal or double value?

使用正文我想准备两个单独的列代码和文本。代码位于名为代码的元素之间,而文本则是其他一切。

我创建了一个如下所示的 UDF

 case class bodyresults(text:String,code:String)
 val Body:String=>bodyresults=(body:String)=> val xmlbody=scala.xml.XML.loadString(body)
val code = (xmlbody \\ "code").toString;
val text = "I want every thing else as text. what should I do"
(text,code)

val bodyudf=udf(Body)
val posts5=posts4.withColumn("codetext",bodyudf(col("Body")))

这不起作用。我的问题是 1.如您所见,数据中没有根节点。我还能使用 scala XML 解析吗? 2. 如何将除代码之外的所有内容解析为文本。

如果我的代码有问题请告诉我

预期输出:

 (code,text)
 code = decimal trans = trackBar1.Value / 5000;this.Opacity = trans;trans double  
 text = everything else  

【问题讨论】:

有什么错误,如果有的话?您的预期输出是什么? 在 spark-shell 中没有显示任何错误消息。 UDF 正文中有问题。 spark-shell 没有创建函数。 好的。代码标签位于多个位置。你想要全部还是只想要里面的pre,即decimal trans = ... 所有这些都在一起。我添加了预期的输出 在这种情况下,是否会从最后一段中删除 trans 和 double ? 【参考方案1】:

除了替换之外,您还可以使用RewriteRule 并覆盖XML 类的transform 方法以清空xml 中的&lt;pre&gt; 标记。

case class bodyresults(text:String,code:String)

val bodyudf = udf (body: String)  =>

    // Appending body tag explicitly to the xml before parsing  
    val xmlElems = XML.loadString(s""" <body> $body </body> """)
    // extract the code inside the req
    val code = (xmlElems \\ "body" \\ "pre" \\ "code").text

    val text = (xmlElems \\ "body").text.replaceAll(s"$code" ,"" )

    bodyresults(text, code)

此 UDF 将返回 StructType 类似:

org.apache.spark.sql.UserDefinedFunction = UserDefinedFunction(<function1>,StructType(StructField(text,StringType,true), StructField(code,StringType,true)),List(StringType))

您现在可以像 posts5 数据框一样调用它:

val posts5 = df.withColumn("codetext", bodyudf($"xml") )
posts5: org.apache.spark.sql.DataFrame = [xml: string, codetext: struct<text:string,code:string>]

提取特定列:

posts5.select($"codetext.code" ).show
+--------------------+
|                code|
+--------------------+
|decimal trans = t...|
+--------------------+

【讨论】:

非常感谢。我现在明白了。我没有足够的声望来支持你的回答。 当我尝试实现这一点时,我收到一个错误 SAXParseException:实体“nbsp”被引用,但未声明。我已将 附加到字符串,但它不起作用。你碰巧知道这件事吗? 尝试在&lt;?xml version..&gt;之后添加&lt;!ENTITY nbsp "&amp;#160;"&gt;,看看是否有效。 不,它会导致另一个错误“根元素之前的文档中的标记必须格式正确。”

以上是关于在 Spark UDF 中处理 XML 字符串并返回 Struct Field的主要内容,如果未能解决你的问题,请参考以下文章

无法序列化 PySpark UDF

pyspark 数据框 UDF 异常处理

Apache Spark - 将 UDF 的结果分配给多个数据框列

为 Spark UDF 执行提供上下文

使用 scala 在 spark sql 中编写 UDF

尝试从 UDF 执行 spark sql 查询