Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spark UDF:如何在每行上编写一个UDF来提取嵌套结构中的特定值?_Java_Xml_Apache Spark_Apache Spark Sql_User Defined Functions - Fatal编程技术网

Java Spark UDF:如何在每行上编写一个UDF来提取嵌套结构中的特定值?

Java Spark UDF:如何在每行上编写一个UDF来提取嵌套结构中的特定值?,java,xml,apache-spark,apache-spark-sql,user-defined-functions,Java,Xml,Apache Spark,Apache Spark Sql,User Defined Functions,我正在使用Java中的Spark来处理XML文件。来自DataRicks的spark xml包用于将xml文件读入dataframe 示例xml文件包括: <RowTag> <id>1</id> <name>john</name> <expenses> <travel> <details> <date

我正在使用Java中的Spark来处理XML文件。来自DataRicks的spark xml包用于将xml文件读入dataframe

示例xml文件包括:

<RowTag>
    <id>1</id>
    <name>john</name>
    <expenses>
        <travel>
            <details>
                <date>20191203</date>
                <amount>400</amount>
            </details>
        </travel>
    </expenses>
</RowTag>
df.printSchema()显示如下:

root
|-- id: int(nullable = true)
|-- name: string(nullable = true)
|-- expenses: struct (nullable = true)
|    |-- travel: struct (nullable = true)
|    |    |-- details: struct (nullable = true)
|    |    |    |-- date: string (nullable = true)
|    |    |    |-- amount: int (nullable = true)
|    |-- food: struct (nullable = true)
|    |    |-- details: struct (nullable = true)
|    |    |    |-- date: string (nullable = true)
|    |    |    |-- amount: int (nullable = true)
所需的输出数据帧如下所示:

+--+------+-------------+
|id| name |expenses_date|
+---------+-------------+
|1 | john |20191203     |
|2 | joe  |20191204     |
+--+------+-------------+
基本上,我想要一个通用的解决方案,用以下结构从xml中获取日期,其中只有标记
不同。

<RowTag>
    <id>1</id>
    <name>john</name>
    <expenses>
        **<X>**
            <details>
                <date>20191203</date>
                <amount>400</amount>
            </details>
        **</X>**
    </expenses>
</RowTag>

1.
厕所
****
20191203
400
****
我尝试过的:

spark.udf().register("getDate",(UDF1 <Row, String>) (Row row) -> {
            return row.getStruct(0).getStruct(0).getAs("date").toString();
        }, DataTypes.StringType);

df.select(callUDF("getDate",df.col("expenses")).as("expenses_date")).show();
spark.udf(){
返回row.getStruct(0).getStruct(0).getAs(“日期”).toString();
},DataTypes.StringType);
df.select(callUDF(“getDate”,df.col(“expenses”).as(“expenses_date”)).show();
但是它不起作用,因为row.getStruct(0)路由到
,但是对于row joe,在
下没有
标记,所以它返回了
java.lang.NullPointerException
。我想要的是一个通用解决方案,它可以为每一行自动获取下一个标记名,例如,
row.getStruct(0)
为row john路由到
,为row joe路由到

所以我的问题是:我应该如何重新制定我的UDF来实现这一目标

提前谢谢!!:)

该包允许您直接访问select表达式中的嵌套字段。你为什么要找UDF

df.selectExpr("id", "name", "COALESCE(`expenses`.`food`.`details`.`date`, `expenses`.`travel`.`details`.`date`) AS expenses_date" ).show()
输出:

+---+----+-------------+
| id|name|expenses_date|
+---+----+-------------+
|  1|john|     20191203|
|  2| joe|     20191204|
+---+----+-------------+
编辑

如果唯一正在更改的标记是
expenses
struct之后的标记,则可以搜索
expenses
下的所有字段,然后
coalesce
列:
expenses.X.details.date
。在Spark中类似这样的内容:

val expenses_fields = df.select(col("expenses.*")).columns
val date_cols = expenses_fields.map(f => col(s"`expenses`.`$f`.`details`.`date`"))

df.select(col("id"), col("name"), coalesce(date_cols: _*).alias("expenses_date")).show()

不过,您不需要使用UDF

如果你提到到目前为止你所做的一切都会有所帮助。这样您的代码/尝试可以得到改进或类似的东西。@VarunJain谢谢!我现在就做。嘿,谢谢你的回答。对不起,我没说清楚。因为我必须处理这样一种情况,即我不知道标签下会出现什么,它可能是或任何其他标签名称,在这种情况下,我需要一个UDF函数(或任何其他可能的方法)来概括这部分的解决方案。谢谢!这可以翻译成Java吗?我已经尝试过这个解决方案,.columns函数返回一个字符串[],我不能使用这个字符串来使用map函数……在Java8中,您也可以使用map。我没有这样做过:
Arrays.stream(expenses\u fields).map(f->col(s)
expenses
$f
详细信息
日期
)).collect(Collectors.toList())
我也尝试过这个,但是collect函数将返回Java中的列表,而不是spark列……这实际上将返回
List
。你所说的“用Java列表代替spark列”是什么意思?
+---+----+-------------+
| id|name|expenses_date|
+---+----+-------------+
|  1|john|     20191203|
|  2| joe|     20191204|
+---+----+-------------+
val expenses_fields = df.select(col("expenses.*")).columns
val date_cols = expenses_fields.map(f => col(s"`expenses`.`$f`.`details`.`date`"))

df.select(col("id"), col("name"), coalesce(date_cols: _*).alias("expenses_date")).show()