我的spark数据框的输出有问题。文件范围从几GB到50 + GB
SparkDF = spark.read.format("csv").options(header="true", delimiter="|", maxColumns="100000").load(my_file.csv)
这给了我想要的正确DF。但是根据要求,我需要将列名和与该键相关的集合中的所有值作为键。
例如:
df = {'col1': ['1', '2', '3', '4'], 'col2': ['Jean', 'Cecil', 'Annie', 'Maurice'], 'col3': ['test', 'aaa', 'bbb', 'ccc','ddd']}
df = pd.DataFrame(data=d)
应该在最后给我
{'col1': {'1', '2', '3', '4'},'col2': {'Jean', 'Cecil', 'Annie', 'Maurice'},'col3': {'test', 'aaa', 'bbb', 'ccc','ddd'}
我实现了以下内容:
def columnDict(dataFrame):
colDict = dict(zip(dataFrame.schema.names, zip(*dataFrame.collect())))
return colDict if colDict else dict.fromkeys(dataFrame.schema.names, ())
但是,它返回了一个带有元组作为值的字典,而不是我所需要的集合。
我想将字典中的元组转换为集合,或者只是直接将字典作为集合作为我函数的输出。
编辑:
有关全部要求:
除了上面提到的字典外,还有另一本包含类似数据以供检查。
意味着我加载到spark DF并转换为字典的文件包含必须对照其他字典进行检查的数据。
目标是对照检查字典检查字典(已加载文件)中的每个键,首先查看它们是否存在,然后检查是否存在,以检查键的值是否是检查值的子集
如果我将检查数据加载到数据帧中,它将看起来像这样:(请注意,我可能无法更改它是dict的事实,我会看看是否可以将dict修改为spark df)>
df = {'KeyName': ['col1', 'col2', 'col3'], 'ValueName': ['1, 2, 3, 4', 'Jean, Cecil, Annie, Maurice, Annie, Maurice', 'test, aaa, bbb, ccc,ddd,eee']}
df = pd.DataFrame(data=df)
print(df)
KeyName ValueName
0 col1 1, 2, 3, 4
1 col2 Jean, Cecil, Annie, Maurice, Annie, Maurice
2 col3 test, aaa, bbb, ccc,ddd,eee
因此,最后,我文件中的数据应该是与我的字典具有相同KeyName的行的子集。
我对遗留代码有些犹豫,我在为将其迁移到数据砖而苦苦挣扎。
编辑2: 希望这会起作用。我上传了2个文件,其中包含修改后的数据: https://filebin.net/1rnnvqn2b0ww7qc8
FakeData.csv包含我上面用上述代码加载的数据,并且必须是第二个数据的子集。 FakeDataChecker.csv包含实际可用的完整数据集
编辑3: 忘了补充说,应该不考虑FakeData中的所有空字符串以及FakeDataChecker中的空字符串
答案 0 :(得分:0)
所以我不确定我是否完全理解您的用例。但是,让我们尝试一下初稿。
据我了解,您拥有包含所有数据的第一个文件。还有一个文件检查器,它在dataforeach列中需要具有键。并且应该过滤掉数据中存在的其他键。
这可以通过初始数据和数据检查器之间的内部联接来完成。如果数据检查器中的键太多,Spark应该自动广播数据检查器数据帧以优化连接。
这是代码的初稿,尚不能完全自动地等待您的第一个问题和评论。
from pyspark.sql.functions import col
from pyspark.sql import Window
spark.sql("set spark.sql.caseSensitive=true")
data = (
spark
.read
.format("csv")
.options(header=True, delimiter="|", maxColumns="100000")
.load("FakeData.csv")
.na.drop()
)
data_checker = (
spark
.read
.format("csv")
.options(header=True, delimiter="|", maxColumns="100000")
.load("FakeDataChecker.csv")
.na.drop(subset=["ValueName"])
)
我们根据需要删除空值,您可以使用subset
关键字指定所需的列
data_checker_date = data_checker.filter(col("KeyName") == "DATE").select(col("ValueName").alias("date"))
data_checker_location = data_checker.filter(col("KeyName") == "LOCATION").select(col("ValueName").alias("location"))
data_checker_location_id = data_checker.filter(col("KeyName") == "LOCATIONID").select(col("ValueName").alias("locationid"))
data_checker_type = data_checker.filter(col("KeyName") == "TYPE").select(col("ValueName").alias("type"))
在连接过程中,我们需要为列添加别名,以避免重复的列名。并且我们在删除列时指定了区分大小写的选项,这样我们就不会在CAPS中删除初始的列。
(
data
.join(data_checker_date, data.DATE == data_checker_date.date)
.join(data_checker_location, data.LOCATION == data_checker_location.location)
.join(data_checker_location_id, data.LOCATIONID == data_checker_location_id.locationid)
.join(data_checker_type, data.TYPE == data_checker_type.type)
.drop("date", "location", "locationid", "type")
.show()
)
在接下来的步骤中,我们可以通过检索列的不同keyName来自动执行此操作(例如:“ DATE”,“ LOCATION”等)。因此,我们不必复制粘贴代码4次或将来X次。
以下行中的内容
from pyspark.sql.functions import collect_set
distinct_keynames = data_checker.select(collect_set('KeyName').alias('KeyName')).first()['KeyName']
for keyname in distinct_keynames:
etc... implement the logic of chaining joins