【问题标题】:How to convert csv into a dictionary in apache beam dataflow如何将 csv 转换为 apache Beam 数据流中的字典
【发布时间】:2019-05-29 01:56:49
【问题描述】:

我想读取一个 csv 文件并使用 apache Beam 数据流将其写入 BigQuery。为此,我需要以字典的形式将数据呈现给 BigQuery。为了做到这一点,如何使用 apache Beam 转换数据?

我的输入 csv 文件有两列,我想在 BigQuery 中创建一个后续的两列表。我知道如何在 BigQuery 中创建数据,这很简单,我不知道如何将 csv 转换为字典。下面的代码不正确,但应该让我知道我正在尝试做什么。

# Standard imports
import apache_beam as beam
# Create a pipeline executing on a direct runner (local, non-cloud).
p = beam.Pipeline('DirectPipelineRunner')
# Create a PCollection with names and write it to a file.
(p
| 'read solar data' >> beam.Read(beam.io.TextFileSource('./sensor1_121116.csv'))
# How do you do this??
| 'convert to dictionary' >> beam.Map(lambda (k, v): {'luminosity': k, 'datetime': v})
| 'save' >> beam.Write(
   beam.io.BigQuerySink(
   output_table,
   schema='month:INTEGER, tornado_count:INTEGER',
   create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED,
   write_disposition=beam.io.BigQueryDisposition.WRITE_TRUNCATE)))
p.run()

【问题讨论】:

    标签: python csv google-bigquery google-cloud-dataflow apache-beam


    【解决方案1】:

    编辑:从 2.12.0 版开始,Beam 带有新的fileio 转换,允许您从 CSV 读取而无需重新实现源。你可以这样做:

    def get_csv_reader(readable_file):
      # You can return whichever kind of reader you want here
      # a DictReader, or a normal csv.reader.
      if sys.version_info >= (3, 0):
        return csv.reader(io.TextIOWrapper(readable_file.open()))
      else:
        return csv.reader(readable_file.open())
    
    with Pipeline(...) as p:
      content_pc = (p
                    | beam.io.fileio.MatchFiles("/my/file/name")
                    | beam.io.fileio.ReadMatches()
                    | beam.Reshuffle()  # Useful if you expect many matches
                    | beam.FlatMap(get_csv_reader))
    

    我最近为此为 Apache Beam 编写了一个测试。你可以看看the Github repository


    旧答案依赖于重新实现源。这不再是这样做的主要推荐方式:)

    这个想法是有一个返回解析的 CSV 行的源。您可以通过继承 FileBasedSource 类来包含 CSV 解析来做到这一点。特别是,read_records 函数看起来像这样:

    class MyCsvFileSource(apache_beam.io.filebasedsource.FileBasedSource):
      def read_records(self, file_name, range_tracker):
        self._file = self.open_file(file_name)
    
        reader = csv.reader(self._file)
    
        for rec in reader:
          yield rec
    

    【讨论】:

    • 非常感谢 Pablo,这真的很好用!这是一个代码 sn-p,以防人们正在寻找完整性 (p | 'read solar data' >> beam.Read(CsvFileSource('./sensor1_121116.csv')) | 'save' >> beam.Write(beam .io.TextFileSink('./greetings_solar')))
    • 我正在尝试将结果写入 BigQuery,但运气不佳,表已创建但没有数据。你能告诉我发生了什么吗?这是一个 sn-p (p | 'read solar data' >> beam.Read(CsvFileSource('./sensor1_121116.csv')) | 'save' >> beam.Write( beam.io.BigQuerySink( output_table, schema ='lumosity:INTEGER, time:INTEGER', create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED, write_disposition=beam.io.BigQueryDisposition.WRITE_TRUNCATE))))
    • @user1753640:我遇到了同样的问题,在将数据存储到 GBQ 之前,我必须使用与架构匹配的字典。
    • 我正在尝试from beam_utils.sources import CsvFileSource,但它抱怨无法from apache_beam.io import fileio。我已经完成了pip install beam_utilspip install apache_beam - 还有什么我需要安装的吗?如果是这样,为什么beam_utils 没有在其依赖项中指定?
    • 可能有点晚了,但是玩了一段时间后,我发现完整性代码应该是这个(p | 'read solar data' >> beam.io.Read(CsvFileSource('./sensor1_121116.csv')) | 'save' >> beam.io.Write(beam.io.TextFileSink('./greetings_solar')))注意io 在应用调用中的 beam 引用之后插入
    【解决方案2】:

    作为对 Pablo 帖子的补充,我想分享一下我自己对他的示例所做的一些更改。 (+1 给你!)

    更改: reader = csv.reader(self._file)reader = csv.DictReader(self._file)

    csv.DictReader 使用 CSV 文件的第一行作为字典键。其他行用于使用其值填充每行的字典。它会根据列顺序自动将正确的值放入正确的键中。

    一个小细节是 Dict 中的每个值都存储为字符串。如果您使用例如,这可能会与您的 BigQuery 架构发生冲突。某些字段的整数。所以你需要在之后注意正确的铸造。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 2015-06-24
    • 2020-03-29
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多