【问题标题】:Importing a large dataset into a database将大型数据集导入数据库
【发布时间】:2011-01-27 19:05:54
【问题描述】:

我是这个问题相关领域的初级程序员,所以如果可能的话,避免假设我已经了解很多会很有帮助。

我正在尝试将 OpenLibrary 数据集导入本地 Postgres 数据库。导入后,我计划将其用作 Ruby on Rails 应用程序的起始种子,该应用程序将包含书籍信息。

OpenLibrary 数据集在此处提供,采用修改后的 JSON 格式: http://openlibrary.org/dev/docs/jsondump

我的应用程序只需要非常基本的信息,比转储中提供的信息要少得多。我只是想找出书名、作者姓名以及书籍与作者之间的关系。

下面是他们数据集中的两个典型条目,第一个是作者的,第二个是一本书的(他们似乎对一本书的每个版本都有一个条目)。在包含实际的 JSON 数据库转储之前,这些条目似乎以主键开头,然后以类型开头。

/a/OL2A /type/author {"name": "U. Venkatakrishna Rao", "personal_name": "U. Venkatakrishna Rao", "last_modified": {"type": "/type/datetime", “值”:“2008-09-10 08:44:01.978456”},“键”:“/a/OL2A”,“出生日期”:“1904”,“类型”:{“键”:“/type/ author"}, "id": 99, "revision": 3}

/b/OL345M /type/edition {"publishers": ["Social Science Research Project, Dept. of Geography, University of Dacca"], "pagination": "ii, 54 p.", "title": "Fayadabad 地区的土地利用", "lccn": ["sa 65000491"], "subject_place": ["东巴基斯坦", "Dacca region."], "number_of_pages": 54, "languages": [{"comment ": "初始导入", "code": "eng", "name": "English", "key": "/l/eng"}], "lc_classifications": ["S471.P162 E23"], " publish_date”:“1963”,“publish_country”:“pk”,“key”:“/b/OL345M”,“authors”:[{“birth_date”:“1911”,“name”:“Nafis Ahmad”,“ key": "/a/OL302A", "personal_name": "Nafis Ahmad"}], "publish_places": ["Dacca, East Pakistan"], "by_statement": "[by] Nafis Ahmad 和 F. Karim Khan。 ", "oclc_numbers": ["4671066"], "contributions": ["Khan, Fazle Karim, 共同作者。"], "subjects": ["土地利用 -- 东巴基斯坦 -- 达卡地区。"]}

未压缩转储的大小非常巨大,作者列表约为 2GB,书籍版本列表约为 18GB。 OpenLibrary 本身并没有为此提供任何工具,它们提供了一个简单的未优化 Python 脚本来读取示例数据(与实际转储不同的是纯 JSON 格式),但他们估计如果对其进行修改以用于其实际数据,它将需要 2 个月 (!) 才能完成数据加载。

如何将其读入数据库?我想我需要编写一个程序来做到这一点。关于我应该如何在合理的时间内完成它的语言和任何指导?我唯一使用过的脚本语言是 Ruby。

【问题讨论】:

    标签: ruby-on-rails json postgresql import dataset


    【解决方案1】:

    不知道 TAPS 是否会在这里为您提供帮助,http://adam.heroku.com/past/2009/2/11/taps_for_easy_database_transfers/

    【讨论】:

    • 不幸的是,据我所知,我认为不会。 Taps 似乎是用于数据库到数据库的传输,而我有一组需要导入数据库的文件。
    【解决方案2】:

    从他们的网站下载转储需要两个月。但是导入它应该只需要几个小时。

    最快的方法是使用 Postgres 的复制命令。您可以将其用于作者的文件。但是需要将 editions 文件插入到 books 和 author_books 表中。

    此脚本在 Python 2.6 中,但如果需要,您应该能够适应 Ruby。

    !#/usr/bin/env python
    import json
    
    fp = open('editions.json')
    ab_out = open('/tmp/author_book.dump', 'w')
    b_out = open('/tmp/book.dump', 'w')
    for line in fp:
      vals = json.loads(s.split('/type/edition ')[1])
      b_out.write("%(key)s\t%(title)s\t(publish_date)s" % vals)
      for author in vals['authors']:
        ab_out.write("%s\t%s" % (vals['key'], author['key'])
    fp.close()
    ab_out.close()
    b_out.close()
    

    然后复制到 Postgres:

    COPY book_table FROM '/tmp/book.dump'
    

    【讨论】:

    • 当你说我只能对作者的文件使用 Postgres 复制命令时,你是什么意思?我是否还需要使用类似这样的脚本将其处理成 Postgres 期望的格式?
    • 当然可以。我为你做了两个文件中较难的一个,并假设你可以自己做一个更简单的文件。
    【解决方案3】:

    按照 Scott Bailey 的建议,我编写了 Ruby 脚本以将 JSON 修改为 Postgres 复制命令可接受的格式。万一其他人遇到同样的问题,这里是我写的脚本:

    require 'rubygems'
    require 'json'
    
    fp = File.open('./edition.txt', 'r')
    ab_out = File.new('./author_book.dump', 'w')
    b_out = File.new('./book.dump', 'w')
    
    i = 0
    while (line = fp.gets) 
      i += 1
      start = line.index /\{/
      if start
        to_parse = line[start, line.length]
        vals = JSON.parse to_parse
    
        if vals["key"].nil? || vals["title"].nil?
          next
        end
        title = vals["title"]
        #Some titles contain backslashes and tabs, which we need to escape and remove, respectively
        title.gsub! /\\/, "\\\\\\\\"
        title.gsub! /\t/, " "
        if ((vals["isbn_10"].nil? || vals["isbn_10"].empty?) && (vals["isbn_13"].nil? || vals["isbn_13"].empty?))
          b_out.puts vals["key"] + "\t" + title + "\t" + '\N' + "\n"
        #Only get the first ISBN number
        elsif (!vals["isbn_10"].nil? && !vals["isbn_10"].empty?) 
          b_out.puts vals["key"] + "\t" + title + "\t" + vals["isbn_10"][0] + "\n"
        elsif (!vals["isbn_13"].nil? && !vals["isbn_13"].empty?)
          b_out.puts vals["key"] + "\t" + title + "\t" + vals["isbn_13"][0] + "\n"    
        end
        if vals["authors"]
          for author in vals["authors"]
            if !author["key"].nil?
              ab_out.puts vals["key"] + "\t" + author["key"]
            end
          end
        end
      else
        puts "Error processing line: " + line.to_s
      end
      if i % 100000 == 0
        puts "Processed line " + i.to_s
      end
    end
    
    fp.close
    ab_out.close
    b_out.close
    

    require 'rubygems'
    require 'json'
    
    fp = File.open('./author.txt', 'r')
    a_out = File.new('./author.dump', 'w')
    
    i = 0
    while (line = fp.gets) 
      i += 1
      start = line.index /\{/
      if start
        to_parse = line[start, line.length]
        vals = JSON.parse to_parse
    
        if vals["key"].nil? || vals["name"].nil?
          next
        end
        name = vals["name"]
        name.gsub! /\\/, "\\\\\\\\"
        name.gsub! /\t/, " "
        a_out.puts vals["key"] + "\t" + name + "\n"
      else
        puts "Error processing line: " + line.to_s
      end
      if i % 100000 == 0
        puts "Processed line " + i.to_s
      end
    end
    
    fp.close
    a_out.close
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 2018-05-21
      • 2016-07-16
      • 2011-10-19
      • 2011-06-26
      • 2017-09-19
      • 1970-01-01
      相关资源
      最近更新 更多