Spark Python从结构中选择并从特定深度返回

2024-09-30 20:16:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Spark和Python还不熟悉——在Jupyter笔记本上工作

假设我有以下XML:

<metadata>
    <person>
        <personalName>
            <surname>The Batmaner</surname>
        </personalName>
        <personalName>
            <surname>Batman</surname>
        </personalName>
    </person>
</metadata>

我已使用以下方法将其加载到日期框中:

df = spark.read.format("com.databricks.spark.xml").options(rowTag='metadata').load(path)

现在我可以看到df中的数据了,如果surname==Batman,我想从<person>中拉出整个部分

基本上,我对2位感到困惑:

  • 在有struct或重复块的情况下搜索,在我的例子中是多个personalName
  • 如何从<person>级别返回所有内容

任何帮助都将不胜感激

谢谢


Tags: the方法dfread笔记本jupyterxmlsurname
1条回答
网友
1楼 · 发布于 2024-09-30 20:16:58

在我看到的之后,你的可处理实体应该是metadata > person > personalName,因为超人和蝙蝠侠不是同一个英雄,对吧?如果是这样,当您将metadata指定为rowTag时,Spark将metadata下的所有内容转换为具有以下架构的行:

root
 |  person: struct (nullable = true)
 |    |  personalName: array (nullable = true)
 |    |    |  element: struct (containsNull = true)
 |    |    |    |  surname: string (nullable = true)

当您将rowTag更改为personalName时,您将得到以下模式:

root
 |  surname: string (nullable = true)

如果仍然是这样,则预期的模式应该位于metadata,您应该使用Apache Spark SQL array functions对行进行操作,例如:

<metadata>
    <person>
        <personalName>
            <surname>Superman</surname>
        </personalName>
        <personalName>
            <surname>Batman</surname>
        </personalName>
    </person>
</metadata>
<metadata>
<person>
    <personalName>
        <surname>XX</surname>
    </personalName>
</person>
</metadata>
<metadata>
<person>
    <personalName>
        <surname>EEEE</surname>
    </personalName>
    <personalName>
        <surname>Batman</surname>
    </personalName>
    <personalName>
        <surname>XXXXX</surname>
    </personalName>
</person>
</metadata>
val df = sparkSession.read.format("com.databricks.spark.xml")
  .option("rowTag", "metadata")
  .load("./test_xml.xml")

df.filter(functions.array_contains($"person.personalName.surname", "Batman")).show(true)

应返回:

+              -+
|person                       |
+              -+
|[[[Superman], [Batman]]]     |
|[[[EEEE], [Batman], [XXXXX]]]|
+              -+

您可以在这里找到一个非常好的sparksql数组函数列表:Querying Spark SQL DataFrame with complex types


更新

Searching when there is that struct or repeating block so in my case multiple personalNames

为此,可以使用apachespark的高阶函数和数组函数。如果你搜索spark higher order function,你会发现很多关于他们的博客文章和文档。上面我给了你一个关于过滤数组的例子

How to return everything from the level

这取决于你的模式。使用rowTag=metadata,Spark返回一个由单个字段组成的行,该字段是一个名为person的结构,仅由一个数组personalName组成。如果在其中添加了更多字段,则仍然可以查询:

<metadata>
    <person>
        <id>1</id>
        <age>30</age>
        <personalName>
            <surname>Superman</surname>
        </personalName>
        <personalName>
            <surname>Batman</surname>
        </personalName>
    </person>
</metadata>
<metadata>
    <person>
        <id>2</id>
        <age>40</age>
        <personalName>
            <surname>XX</surname>
        </personalName>
        <personalName>
            <surname>EEEEE</surname>
        </personalName>
    </person>
</metadata>
<metadata>
    <person>
        <id>3</id>
        <age>50</age>
        <personalName>
            <surname>EEEE</surname>
        </personalName>
        <personalName>
            <surname>Batman</surname>
        </personalName>
        <personalName>
            <surname>XXXXX</surname>
        </personalName>
    </person>
</metadata>

使用:

df.filter("person.id > 0")
  .filter(functions.array_contains($"person.personalName.surname", "Batman"))
  .show(false)

结果将是:

+                  +
|person                              |
+                  +
|[30, 1, [[Superman], [Batman]]]     |
|[50, 3, [[EEEE], [Batman], [XXXXX]]]|
+                  +

否则,如果将指针移到person,您的模式将丢失一个级别,因此编写查询将更容易:

df.printSchema()
df.filter("id > 0")
  .filter(functions.array_contains($"personalName.surname", "Batman"))
  .show(false)

对于这样的架构和数据:

root
 |  age: long (nullable = true)
 |  id: long (nullable = true)
 |  personalName: array (nullable = true)
 |    |  element: struct (containsNull = true)
 |    |    |  surname: string (nullable = true)

+ -+ -+             -+
|age|id |personalName               |
+ -+ -+             -+
|30 |1  |[[Superman], [Batman]]     |
|50 |3  |[[EEEE], [Batman], [XXXXX]]|
+ -+ -+             -+

相关问题 更多 >