Ruby для поиска и объединения файлов CSV при работе с большими файлами - PullRequest
0 голосов
/ 28 апреля 2020

Резюме

Просмотр других вопросов, которые в некоторой степени соответствуют этому, не помогает, потому что я все еще открываю файл построчно, поэтому у меня не хватает памяти на большой файл На самом деле мое использование памяти довольно низкое, но создание файла меньшего размера занимает очень много времени, чтобы я мог искать и объединять другие файлы CSV в файл.

Вопрос

Прошло 5 дней, и я не уверен, как далеко я ушел до go, но он не вышел из строки foreach основного файла, есть 17,8 миллионов записей в CSV-файле. Есть ли более быстрый способ обработать эту обработку в 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: "\0" }) 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 

1 Ответ

2 голосов
/ 28 апреля 2020

Насколько мне удалось определить, идентификаторы OCL C - это alphanumeri c. Это означает, что мы хотим использовать Ha sh для хранения этих идентификаторов. Ха sh имеет общую сложность поиска O (1), в то время как ваш несортированный массив имеет сложность поиска O (n).

Если вы используете массив, поиск в худшем случае составляет 18 миллионов сравнений. (чтобы найти один элемент, Ruby должен go через все 18 миллионов ID), в то время как с Ha sh это будет одно сравнение. Проще говоря: использование Ha sh будет в миллионы раз быстрее, чем ваша текущая реализация.

Приведенный ниже псевдокод даст вам представление о том, как действовать дальше. Мы будем использовать Набор, который похож на Ха sh, но удобен, когда все, что вам нужно сделать, это проверить на включение:

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])
}
...