【问题标题】:How do I parse xml documents in Palantir Foundry?如何在 Palantir Foundry 中解析 xml 文档?
【发布时间】:2022-01-10 04:35:35
【问题描述】:

我有一组要解析的 .xml 文档。

我之前曾尝试使用获取文件内容并将它们转储到单个单元格中的方法来解析它们,但是我注意到这在实践中不起作用,因为我看到运行时间越来越慢,通常是一项需要数十小时才能运行的任务:

我的第一个转换将.xml 内容放入单个单元格,第二个转换将这个字符串并使用Python 的xml 库将字符串解析为一个文档。然后我可以从这个文档中提取属性并返回一个 DataFrame。

我正在使用UDF 来执行将字符串内容映射到我想要的字段的过程。

我怎样才能更快/更好地处理大型 .xml 文件?

【问题讨论】:

    标签: pyspark palantir-foundry foundry-code-repositories foundry-python-transform


    【解决方案1】:

    对于这个问题,我们将结合几种不同的技术来使这段代码既可测试又具有高度可扩展性。

    理论

    在解析原始文件时,您可以考虑以下几个选项:

    1. ❌您可以编写自己的解析器来从文件中读取字节并将它们转换为 Spark 可以理解的数据。
      • 由于工程时间和不可扩展的体系结构,尽可能不建议这样做。当您这样做时,它不会利用分布式计算,因为您必须将整个原始文件带到您的解析方法中,然后才能使用它。这不是对您资源的有效利用。
    2. ⚠ 可以使用自己的非Spark解析器库,比如问题中提到的XML Python库
      • 虽然这比编写自己的解析器要容易完成,但它仍然没有利用 Spark 中的分布式计算。运行起来更容易,但最终会遇到性能限制,因为它没有利用仅在编写 Spark 库时才公开的低级 Spark 功能。
    3. ✅ 你可以使用 Spark 原生的原始文件解析器
      • 这是所有情况下的首选选项,因为它利用了低级 Spark 功能,并且不需要您编写自己的代码。如果存在低级 Spark 解析器,则应使用它。

    在我们的例子中,我们可以使用 Databricks 解析器来获得很好的效果。

    一般来说,您还应该避免使用.udf 方法,因为它很可能被用来代替 Spark API 中已经提供的良好功能。 UDF 的性能不如本机方法,只有在没有其他选项可用时才应使用。

    UDF 掩盖隐藏问题的一个很好的例子是列内容的字符串操作;虽然您在技术上可以使用 UDF 来执行诸如拆分和修剪字符串之类的事情,但这些事情已经存在于 Spark API 中,并且将比您自己的代码快几个数量级。

    设计

    我们的设计将使用以下内容:

    1. 通过Databricks XML Parser 完成的低级 Spark 优化文件解析
    2. 测试驱动的原始文件解析,如 here 所述

    连接解析器

    首先,我们需要将.jar 添加到Transforms 中可用的spark_session。由于最近的改进,此参数在配置后将允许您在预览/测试和完整构建时使用.jar。以前,这需要一个完整的构建,但现在不需要了。

    我们需要转到我们的transforms-python/build.gradle 文件并添加 2 个配置块:

    1. 启用pytest插件
    2. 启用condaJars 参数并声明.jar 依赖项

    我的/transforms-python/build.gradle 现在如下所示:

    buildscript {
        repositories {
           // some other things
        }
    
        dependencies {
            classpath "com.palantir.transforms.python:lang-python-gradle-plugin:${transformsLangPythonPluginVersion}"
        }
    }
    
    apply plugin: 'com.palantir.transforms.lang.python'
    apply plugin: 'com.palantir.transforms.lang.python-defaults'
    
    dependencies {
        condaJars "com.databricks:spark-xml_2.13:0.14.0"
    }
    
    // Apply the testing plugin
    apply plugin: 'com.palantir.transforms.lang.pytest-defaults'
    
    // ... some other awesome features you should enable
    

    应用此配置后,您需要通过单击底部功能区并点击 Refresh 来重新启动 Code Assist 会话

    刷新 Code Assist 后,我​​们现在可以使用低级功能来解析我们的 .xml 文件,现在我们需要对其进行测试!

    测试解析器

    如果我们采用与here相同的测试驱动开发方式,我们最终会得到/transforms-python/src/myproject/datasets/xml_parse_transform.py,其内容如下:

    from transforms.api import transform, Output, Input
    from transforms.verbs.dataframes import union_many
    
    
    def read_files(spark_session, paths):
        parsed_dfs = []
        for file_name in paths:
            parsed_df = spark_session.read.format('xml').options(rowTag="tag").load(file_name)
            parsed_dfs += [parsed_df]
        output_df = union_many(*parsed_dfs, how="wide")
        return output_df
    
    
    @transform(
        the_output=Output("my.awesome.output"),
        the_input=Input("my.awesome.input"),
    )
    def my_compute_function(the_input, the_output, ctx):
        session = ctx.spark_session
        input_filesystem = the_input.filesystem()
        hadoop_path = input_filesystem.hadoop_path
        files = [hadoop_path + "/" + file_name.path for file_name in input_filesystem.ls()]
        output_df = read_files(session, files)
        the_output.write_dataframe(output_df)
    

    ...一个示例文件/transforms-python/test/myproject/datasets/sample.xml,内容如下:

    <tag>
    <field1>
    my_value
    </field1>
    </tag>
    

    还有一个测试文件/transforms-python/test/myproject/datasets/test_xml_parse_transform.py

    from myproject.datasets import xml_parse_transform
    from pkg_resources import resource_filename
    
    
    def test_parse_xml(spark_session):
        file_path = resource_filename(__name__, "sample.xml")
        parsed_df = xml_parse_transform.read_files(spark_session, [file_path])
        assert parsed_df.count() == 1
        assert set(parsed_df.columns) == {"field1"}
    

    我们现在有:

    1. 一种分布式计算、低级 .xml 解析器,具有高度可扩展性
    2. 一种测试驱动的设置,我们可以对其进行快速迭代以获得正确的功能

    干杯

    【讨论】:

      猜你喜欢
      • 2022-08-03
      • 1970-01-01
      • 1970-01-01
      • 2022-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多