使用kiba ETL检查CSV文件标题的最佳位置

时间:2019-02-12 09:32:51

标签: kiba-etl

我需要检查:

  • 标题行存在
  • 标题包含一组特定的标题

这样做的最佳地点。我有一些可能的解决方案,但不知道更惯用的解决方案

  • 在运行完整的ETL之前检查%s块之前的示例
  • 检入ETL中的Kiba.parse
  • 签入ETL源。我倾向于使用它,因为它会更可重用(需要将强制字段作为参数传递)

请注意,即使我可以在pre_process块中签入transform上的可用字段,该解决方案似乎也不是很有效,因为它将针对每一行运行。

任何提示表示赞赏

1 个答案:

答案 0 :(得分:1)

有很多种惯用的方法可以实现这一目标:

在源级别(传递标头数组)

您可以在不使用CSV的情况下使用headers: true,这提供了精细检查标题的机会:

class CSVSource
  def initialize(filename:, csv_options:, expected_headers:)
  # SNIP

  def each
    CSV.foreach(filename, csv_options).with_index do |row, file_row_index|
      if file_row_index == 0
        check_headers!(actual: row.to_a, expected: expected_headers)
        next # do not propagate the headers row
      else
        yield(Hash[expected_headers.zip(row.to_a)])
      end
    end
  end

  def check_headers!(actual:, expected:)
  # SNIP - verify uniqueness, presence, raise a clear message if needed
end     

在源代码级别(让调用者使用lambda定义行为)

class CSVSource
  def initialize(after_headers_read_callback:, ...)
    @after_headers_read_callback = ...

  def each
    CSV.foreach(filename, csv_options).with_index do |row, file_row_index|
      if file_row_index == 0
        @after_headers_read_callback.call(row.to_a)
        next
      end
      # ...
    end
  end

lambda可以让调用者定义自己的检查,必要时进行加注等,以便于重用。

在转换级别

如果您想进一步分离组件(例如,将标头处理与行来自CSV源的事实分开),则可以使用转换。

我通常使用这种设计,这样可以实现更好的重用(此处使用CSV源,它将产生一些元数据):

def transform_array_rows_to_hash_rows(after_headers_read_callback:)
  transform do |row|
    if row.fetch(:file_row_index) == 0
      @headers = row.fetch(:row)
      after_headers_read_callback.call(@headers)
      nil
    else
      Hash[@headers.zip(row.fetch(:row))].merge(
        filename: row.fetch(:filename),
        file_row_index: row.fetch(:file_row_index)
      )
    end
  end
end

不推荐的地方

在所有情况下,请避免在Kiba.parse本身中进行任何处理。这是一个更好的设计,可以确保仅在您调用Kiba.run时才发生IO(因为它将更具前瞻性,并且将在更高版本的Kiba中支持自省功能)。

此外,不建议使用pre_process(虽然它可以工作),因为它会导致重复,等等。

希望这会有所帮助,如果不清楚,请通知我!