Python Dask分布式:并行读取和分析大量单个文件

Python Dask分布式:并行读取和分析大量单个文件,python,dask,dask-distributed,pyarrow,Python,Dask,Dask Distributed,Pyarrow,问题 如何使用Dask Distributed将文件目录并行读取到单个数据帧中,然后使用自定义函数处理这些数据帧?假设n个文件大约是100000个 背景 我是Dask的新手,不太知道如何问这个问题(使用哪些术语等),所以这里有一张我试图完成的图片: 我在HDFS中存储了许多小的、单独的.txt“分类账”文件(例如,带有时间戳的行分隔文件和时间戳时的属性值) 同时,我想 将每个文件读入一个数据帧(注意:我不想把所有文件合并成一个大df!) 对每个数据帧应用自定义函数(见下文);然后 将每个结果(

问题

如何使用Dask Distributed将文件目录并行读取到单个数据帧中,然后使用自定义函数处理这些数据帧?假设n个文件大约是100000个

背景

我是Dask的新手,不太知道如何问这个问题(使用哪些术语等),所以这里有一张我试图完成的图片:

我在HDFS中存储了许多小的、单独的.txt“分类账”文件(例如,带有时间戳的行分隔文件和时间戳时的属性值)

同时,我想

  • 将每个文件读入一个数据帧(注意:我不想把所有文件合并成一个大df!)

  • 对每个数据帧应用自定义函数(见下文);然后

  • 将每个结果(从自定义函数返回)合并到最终对象中,并将其保存回HDFS

  • 似乎我找到的几乎每个答案(在谷歌搜索相关术语时)都是关于将多个文件加载到单个数据帧中

    我正在处理的,我正在使用的函数

    每个分类账文件/数据框:

    +---------+------+-------------------+-----+
    | location|status|          timestamp|wh_id|
    +---------+------+-------------------+-----+
    |  PUTAWAY|     I|2019-04-01 03:14:00|   20|
    |PICKABLE1|     X|2019-04-01 04:24:00|   20|
    |PICKABLE2|     X|2019-04-01 05:33:00|   20|
    |PICKABLE2|     A|2019-04-01 06:42:00|   20|
    |  HOTPICK|     A|2019-04-10 05:51:00|   20|
    | ICEXCEPT|     A|2019-04-10 07:04:00|   20|
    | ICEXCEPT|     X|2019-04-11 09:28:00|   20|
    +---------+------+-------------------+-----+
    
    分析功能:

    from dateutil.relativedelta import relativedelta
    from datetime import datetime
    from pyspark.sql.functions import to_timestamp
    
    def analyze(df):
    
      columns_with_age = ("location", "status")
      columns_without_age = ("wh_id")
    
      # Get the most-recent values (from the last row of the df)
      row_count = df.count()
      last_row = df.collect()[row_count-1]
    
      # Create an empty "final row" dictionary
      final_row = {}
    
      # For each column for which we want to calculate an age value ...
      for c in columns_with_age:
    
          # Initialize loop values
          target_value = last_row.__getitem__(c)
          final_row[c] = target_value
          timestamp_at_lookback = last_row.__getitem__("timestamp")
          look_back = 1
          different = False
    
          while not different:
              previous_row = df.collect()[row_count - 1 - look_back]
              if previous_row.__getitem__(c) == target_value:
                  timestamp_at_lookback = previous_row.__getitem__("timestamp")
                  look_back += 1
    
              else:
                  different = True
    
          # At this point, a difference has been found, so calculate the age
          final_row["days_in_{}".format(c)] = relativedelta(datetime.now(), timestamp_at_lookback).days
    
    因此,分类账数据/数据框架将减少到(假设计算在2019-04-14运行):


    从多个进程并行写入单个输出文件实际上是不可能的,因为您不知道每个结果将提前多长时间,所以您不知道在文件中放置其他结果的位置。此外,HDFS确实喜欢接收大块连续数据,而不是增量更新(可能是64MB)

    你可以做几件事:

    • 将所有输出写入单独的文件,然后运行单独的作业来连接它们;如果数据帧的处理比读/写时间要长,那么这是一件非常好的事情
    • 使用分布式
      客户端。提交
      API和
      完成后
      将结果从主进程写入输出文件。请注意,如果这很重要,您可以将这方面作为原始订单,但这需要一些额外的工作

    您可以将读取和文件级评估合并到一个函数中,然后使用:处理完所有文件后,您可以将结果合并到最终输出中。您可以阅读有关延迟的
    的信息。看看这个。看起来我可能想混合上面的两个注释——也就是说,将文件读取/评估合并到一个函数中,然后使用Dask Distributed的
    client.map(eval_func,[HDFS文件路径列表])
    { '_id': 'ledger-filename', 'location': 'ICEXCEPT', 'days_in_location': 4, 'status': 'X', 'days_in_status': 3, 'wh_id': 20 }