from pyspark.sql.functions import *
def flatten_df(nested_df):
exist = True
while exist:
flat_cols = [c[0] for c in nested_df.dtypes if c[1][:6] != 'struct']
nested_cols = [c[0] for c in nested_df.dtypes if c[1][:6] == 'struct']
if len(nested_cols) > 0:
print(nested_cols)
flat_df = nested_df.select(flat_cols +
[col("`"+nc+'`.`'+c+"`").alias((nc+'_'+c).replace(".","_"))
for nc in nested_cols
for c in nested_df.select("`"+nc+'`.*').columns])
nested_df=flat_df
#break
else:
exist = False
return flat_df
df = sqlContext.read.format("com.databricks.spark.xml").option("rowTag", "GetDocument").load("/FileStore/tables/test.xml")
df1=flatten_df(df)
Вот код, который я использую для выравнивания XML-документа. По сути, я хочу взять xml с вложенным xml и выровнять все это в одну строку без структурированных типов данных, поэтому каждое значение является столбцом. Приведенный выше код работает для тестовых случаев, которые я сделал, но я попробовал очень большой XML, и после пары циклов сглаживания (в цикле while) он завершается со следующей ошибкой:
'Ambiguous reference to fields StructField(_Id,StringType,true), StructField(_id,StringType,true);'
Я предполагаю, потому что он пытается создать 2 отдельных столбца с одинаковым именем. Как я могу избежать этого, но сохранить свой код универсальным для любого XML?
Следует отметить, что в качестве типа данных для столбца можно использовать массивы. Я буду разбирать эти массивы для разделения строк на следующем шаге.
Пример обновления
Оригинал DF -
|-- Order: long (nullable = true)
|-- attval: string (nullable = true)
|-- children: struct (nullable = true)
| |-- id: string(nullable = true)
| |-- att: array (nullable = true)
| | |-- element: struct (containsNull = true)
| | | |-- Order: long (nullable = true)
| | | |-- attval: string (nullable = true)
DF после функции -
|-- Order: long (nullable = true)
|-- attval: string (nullable = true)
|-- children_id: string(nullable = true)
|-- children_att: array (nullable = true)
| |-- children_att_element_Order: long (nullable = true)
| |-- children_att_element_attval: string (nullable = true)