Загрузка больших xml файлов в Snowflake и выравнивание по тегу - PullRequest
4 голосов
/ 25 февраля 2020

У меня есть несколько очень больших XML файлов, которые мне нужно обработать. Раньше я обрабатывал их с помощью Spark, но я перехожу из SQLDW в Snowflake, поэтому больше не могу использовать Spark. В Spark была концепция сглаживания файлов XML путем предоставления «rowTag» для функции spark. Допустим, у нас есть этот persons.xml файл:

<persons>
    <person id="1">
        <firstname>James</firstname>
        <lastname>Smith</lastname>
        <middlename></middlename>
        <dob_year>1980</dob_year>
        <dob_month>1</dob_month>
        <gender>M</gender>
        <salary currency="Euro">10000</salary>
        <addresses>
            <address>
                <street>123 ABC street</street>
                <city>NewJersy</city>
                <state>NJ</state>    
            </address>
            <address>
                <street>456 apple street</street>
                <city>newark</city>
                <state>DE</state>    
            </address>    
        </addresses>    
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname></lastname>
        <middlename>Rose</middlename>
        <dob_year>1990</dob_year>
        <dob_month>6</dob_month>
        <gender>M</gender>
        <salary currency="Dollor">10000</salary>
        <addresses>
            <address>
                <street>4512 main st</street>
                <city>new york</city>
                <state>NY</state>    
            </address>
            <address>
                <street>4367 orange st</street>
                <city>sandiago</city>
                <state>CA</state>    
            </address>    
        </addresses>            
    </person>
</persons>

Если я хочу сгладить этот XML файл, чтобы он выглядел как CSV с заголовками firstname, lastname, middlename, dob_year, dob_month... et c, я бы запустил функцию это выглядит так:

val df = spark.read
      .format("com.databricks.spark.xml")
      .option("rowTag", "person")
      .load("persons.xml");
display(df);

Предоставляя spark rowTag person в функции .option(), мы получаем кадр данных, который выглядит следующим образом:

_id addresses   dob_month   dob_year    firstname   gender  lastname    middlename  salary                          
1   {"address":[{"city":"NewJersy","state":"NJ","street":"123 ABC street"},{"city":"newark","state":"DE","street":"456 apple street"}]} 1   1980    James   M   Smith       {"_VALUE":10000,"_currency":"Euro"}
2   {"address":[{"city":"new york","state":"NY","street":"4512 main st"},{"city":"sandiago","state":"CA","street":"4367 orange st"}]}   6   1990    Michael M       Rose    {"_VALUE":10000,"_currency":"Dollor"}

Это немного трудно читать, так что вот изображение, чтобы помочь ... image

В любом случае, мне было интересно, как я могу сделать это со Снежинкой, если это возможно? Я хотел бы избежать предварительной обработки моего xml файла, если это возможно.

Помните, что эти файлы большие . 1Gb +. Также нет гарантии, что файлы будут иметь rowTag в начале или в начале - это может быть несколько сотен строк вниз по файлу.

1 Ответ

1 голос
/ 25 февраля 2020

Несколько идей для вас:

  1. При загрузке используйте STRIP_OUTER_ELEMENT = TRUE, чтобы убрать тег PERSONS, и каждый объект PERSON приземлится в своем собственном ряду. Это упрощает данные и позволяет загружать файлы большего размера.

  2. Свести XML, чтобы найти все пути. Например, select * from my_table a, lateral flatten(input=>a.data, recursive=>true) b;

  3. Переведите пути из нотации сглаживания в нотацию поля и создайте запрос:

Например (при условии Внешний тег PERSONS удален):

select 
  data:"@id"::number id,
  data:"$"[0]."$"::text first_name,
  data:"$"[1]."$"::text last_name
from my_table; 

Где data - ваш столбец XML.

Надеюсь, это поможет.


ОБНОВЛЕНИЕ - Образец XML для использования с запросом выше:

create or replace table my_table as
select parse_xml($1) as data 
from values ('
    <person id="1">
        <firstname>James</firstname>
        <lastname>Smith</lastname>
        <middlename></middlename>
        <dob_year>1980</dob_year>
        <dob_month>1</dob_month>
        <gender>M</gender>
        <salary currency="Euro">10000</salary>
        <addresses>
            <address>
                <street>123 ABC street</street>
                <city>NewJersy</city>
                <state>NJ</state>    
            </address>
            <address>
                <street>456 apple street</street>
                <city>newark</city>
                <state>DE</state>    
            </address>    
        </addresses>    
    </person>'),('
    <person id="2">
        <firstname>Michael</firstname>
        <lastname></lastname>
        <middlename>Rose</middlename>
        <dob_year>1990</dob_year>
        <dob_month>6</dob_month>
        <gender>M</gender>
        <salary currency="Dollor">10000</salary>
        <addresses>
            <address>
                <street>4512 main st</street>
                <city>new york</city>
                <state>NY</state>    
            </address>
            <address>
                <street>4367 orange st</street>
                <city>sandiago</city>
                <state>CA</state>    
            </address>    
        </addresses>            
    </person>
');
...