Ruby 在处理大文件时搜索和合并 CSV 文件

Ruby to Search and Combine CSV files when dealing with large files

总结

看看其他有点符合这个的问题也没有帮助,因为我还在逐行打开文件所以我不会 运行 内存不足文件。事实上,我的内存使用率非常低,但创建较小的文件需要很长时间才能搜索并将其他 CSV 文件连接到文件中。

问题

已经5天了,我不确定我还剩下多少,但它还没有退出主文件的foreach行,csv文件中有1780万条记录。在 ruby 中是否有更快的方法来处理此处理?我可以对 MacOSX 做些什么来优化它吗?任何建议都会很棒。

# # -------------------------------------------------------------------------------------
# # USED TO GET ID NUMBERS OF THE SPECIFIC ITEMS THAT ARE NEEDED
# # -------------------------------------------------------------------------------------
etas_title_file = './HathiTrust ETAS Titles.csv'
oclc_id_array = []
angies_csv = []
CSV.foreach(etas_title_file ,'r', {:headers => true, :header_converters => :symbol}) do |row| 
  oclc_id_array << row[:oclc]
  angies_csv << row.to_h
end 
oclc_id_array.uniq!


# -------------------------------------------------------------------------------------
# RUN ONCE IF DATABASE IS NOT POPULATED
# -------------------------------------------------------------------------------------

headers = %i[htid   access  rights  ht_bib_key  description source  source_bib_num  oclc_num    isbn    issn    lccn    title   imprint rights_reason_code  rights_timestamp    us_gov_doc_flag rights_date_used    pub_place   lang    bib_fmt collection_code content_provider_code   responsible_entity_code digitization_agent_code access_profile_code author]

remove_keys = %i[access rights description  source  source_bib_num isbn issn    lccn    title   imprint rights_reason_code  rights_timestamp    us_gov_doc_flag rights_date_used    pub_place   lang    bib_fmt collection_code content_provider_code   responsible_entity_code digitization_agent_code access_profile_code author]

new_hathi_csv = []
processed_keys = []
CSV.foreach('./hathi_full_20200401.txt' ,'r', {:headers => headers, :col_sep => "\t", quote_char: "[=11=]" }) do |row| 
  next unless oclc_id_array.include? row[:oclc_num]
  next if processed_keys.include? row[:oclc_num]
  puts "#{row[:oclc_num]} included? #{oclc_id_array.include? row[:oclc_num]}"
  new_hathi_csv << row.to_h.except(*remove_keys)
  processed_keys << row[:oclc_num]
end 

据我所知,OCLC ID 是字母数字。这意味着我们要使用哈希来存储这些 ID。哈希的一般查找复杂度为 O(1),而未排序的数组的查找复杂度为 O(n)。

如果使用数组,最坏情况下查找是 1800 万次比较(要查找单个元素,Ruby 必须遍历所有 1800 万个 ID),而使用哈希将是一次比较.简单地说:使用哈希将比您当前的实现快数百万倍。

下面的伪代码会让您了解如何进行。我们将使用一个 Set,它类似于一个 Hash,但是当您需要做的只是检查是否包含时,它很方便:

oclc_ids = Set.new

CSV.foreach(...) {
  oclc_ids.add(row[:oclc])  # Add ID to Set
  ...
}

# No need to call unique on a Set. 
# The elements in a Set are always unique.

processed_keys = Set.new

CSV.foreach(...) {
   next unless oclc_ids.include?(row[:oclc_num])   # Extremely fast lookup
   next if processed_keys.include?(row[:oclc_num]) # Extremely fast lookup
   ...
   processed_keys.add(row[:oclc_num])
}