Как упорядочить поля объектов Row в Spark (Python)

Я создаю объекты Row в Spark. Я не хочу, чтобы мои поля заказывались по алфавиту. Однако, если я делаю следующее, они упорядочены по алфавиту.

row = Row(foo=1, bar=2)

Затем он создает объект, подобный следующему:

Row(bar=2, foo=1)

Когда я затем создаю DataFrame для этого объекта, порядок столбцов будет сначала первым, а второй - вторым, когда я предпочел бы иметь его наоборот.

Я знаю, что могу использовать "_1" и "_2" (соответственно для "foo" и "bar" ), а затем назначить схему (с соответствующими именами "foo" и "bar" ). Но есть ли способ предотвратить объект Row от их заказа?

Ответ 1

Но есть ли способ помешать объекту Row упорядочить их?

Нет Если вы предоставите kwargs аргументы будут отсортированы по имени. Сортировка необходима для детерминированного поведения, поскольку Python до 3.6 не сохраняет порядок аргументов ключевого слова.

Просто используйте простые кортежи:

rdd = sc.parallelize([(1, 2)])

и передайте схему в качестве аргумента в RDD.toDF (не путать с DataFrame.toDF):

rdd.toDF(["foo", "bar"])

или createDataFrame:

from pyspark.sql.types import *

spark.createDataFrame(rdd, ["foo", "bar"])

# With full schema
schema = StructType([
    StructField("foo", IntegerType(), False),
    StructField("bar", IntegerType(), False)])

spark.createDataFrame(rdd, schema)

Вы также можете использовать namedtuples:

from collections import namedtuple

FooBar = namedtuple("FooBar", ["foo", "bar"])
spark.createDataFrame([FooBar(foo=1, bar=2)])

Наконец, вы можете отсортировать столбцы, select:

sc.parallelize([Row(foo=1, bar=2)]).toDF().select("foo", "bar")

Ответ 2

Из документация:

Строка также может использоваться для создания другого класса Row, а затем его можно использовать для создания объектов Row

В этом случае сохраняется порядок столбцов:

>>> FooRow = Row('foo', 'bar')
>>> row = FooRow(1, 2)
>>> spark.createDataFrame([row]).dtypes
[('foo', 'bigint'), ('bar', 'bigint')]

Ответ 3

Как отсортировать исходную схему в соответствии с алфавитным порядком RDD:

schema_sorted = StructType()
structfield_list_sorted = sorted(df.schema, key=lambda x: x.name)
for item in structfield_list_sorted:
    schema_sorted.add(item)