我正在尝试使用pyspark读取avro文件,并根据某些键对列之一进行排序。我的avro文件中的一列包含MapType
数据,我需要根据键对它们进行排序。测试avro仅包含一行,其中实体列包含MapType
数据。我的意图是将输出写回到avro文件中,但要按键顺序进行。不幸的是,我无法实现这一目标,不确定在avro中是否完全可以实现?它以输入出现的相同方式回写。
这是我的代码(我创建了一个笔记本进行测试):
from pyspark.conf import SparkConf
from pyspark.sql import SparkSession
from pyspark.sql.functions import udf, lit, to_json, create_map, from_json
from pyspark.sql import Row
from pyspark import StorageLevel
import json
from pyspark.sql.types import StringType
import shutil
from pyspark.sql.types import MapType, ArrayType, StringType, StructType, StructField
spark = SparkSession .builder .appName("AvroTest") .config("spark.jars.packages", "org.apache.spark:spark-avro_2.11:2.4.0") .getOrCreate()
df = spark.read.format("avro").load("part-r-00000.avro")
schema = df.select('entities').schema
sch = schema.fields[0].dataType
print(df.schema)
@udf
def udf_func(line):
for entkey,subdict in line.items():
subdictnew = subdict.asDict(True)
sorteddict = dict(sorted(subdictnew['entities'].items(), key=lambda a: int(a[0])))
subdictnew['entities'] = sorteddict
line[entkey] = subdictnew
return str(line)
dfnew = df.withColumn('entities', from_json(udf_func(df['entities']), sch)).persist(StorageLevel.MEMORY_ONLY_SER)
#dfnew.show()
d = dfnew.dtypes
newschema = dfnew.schema
try:
shutil.rmtree('testavro/sortedData')
except:
print('folder already removed')
dfnew.write.format('avro').save('ctipavro/sortedData')
dfnew.show(1, False)
上面的代码以无排序的方式写回avro。最后一行以排序方式打印“实体”的数据框列记录。
|37321431529|37321431529|1561020714|[trade -> [trade, [59489777 -> [TRADE_ASSOC_TO_DB_DT -> 2011-09-30, FCBA_IN -> N, ACCT_BALANCE_AM -> 0, CII_BKRPT_CD -> , CREDIT_AM_EXCP_CD -> 6, FRAUD_IN -> N, ACCT_REPORTED_DT -> 2019-04-01, DATA_USAGE_EXCL_IN -> N, CII_REAFF_CD -> , DEDUP_RANK_CD -> 0, NY_DISPLAY_RULE_IN -> N, ACCT_HIGH_BALANCE_AM_EXCP_CD -> 6, ACCT_PAYMENT_AM -> 13, EXCLUSION_CD -> 0, KOB_CD -> BB, PAYMENT_GRID_2 -> 0000000-0-0000-00-00000..............
请注意,这里我正在打印已排序的数据帧输出。但是,当我尝试将已保存的avro文件读回到新的数据帧并执行show()
时,键再次未排序。请注意,trade -> [trade
的第一个键应该是59489777
,而其他则是51237292611
。顺便说一句,当我第一次读取输入的avro时,这个键就出现了,不知道为什么在排序和写回之后为什么先打印相同的键:
dffresh = spark.read.format("avro").load("testavro/sortedData")
schema = dffresh.schema
print(schema)
dffresh.show(1, False)
输出:
|37321431529|37321431529|1561020714|[trade -> [trade, [51237292611 -> [TRADE_ASSOC_TO_DB_DT -> 2014-09-20, FCBA_IN -> N, ACCT_BALANCE_AM -> 0, CII_BKRPT_CD -> , CREDIT_AM_EXCP_CD -> 6, FRAUD_IN -> N, ACCT_REPORTED_DT -> 2019-05-01, DATA_USAGE_EXCL_IN -> N, CII_REAFF_CD -> , DEDUP_RANK_CD -> 0, NY_DISPLAY_RULE_IN -> N, ACCT_HIGH_BALANCE_AM_EXCP_CD -> 6, ACCT_PAYMENT_AM -> 0, EXCLUSION_CD -> 0, KOB_CD -> BC, PAYMENT_GRID_2 -> 000000C0000000..................................
我会要求任何人帮助我。我尝试了许多方法,并搜索了多个SO问题,但找不到有关实现方法的线索。
答案 0 :(得分:0)
如果您的源数据是avro格式,通常也最好以Parquet文件格式写入处理后的输出。您将获得谓词下推的优势,并且始终可以处理选择性的列数。
但是,如果再次写入avro格式是您处理的一部分,则由于使用的数据结构为 Map
,因此无法始终保证列的顺序。您可以通过使用select
函数并按选择的顺序读取列来缓解这种情况。