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])
}
总结
看看其他有点符合这个的问题也没有帮助,因为我还在逐行打开文件所以我不会 运行 内存不足文件。事实上,我的内存使用率非常低,但创建较小的文件需要很长时间才能搜索并将其他 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])
}