2010-03-15 82 views
1

我是這個問題相關領域的開始程序員,所以如果可能的話,避免假設我已經知道很多東西是有幫助的。將大型數據集導入數據庫

我想將OpenLibrary數據集導入本地Postgres數據庫。在導入之後,我打算將它用作Ruby on Rails應用程序的開始種子,該應用程序將包含有關書籍的信息。

的OpenLibrary數據集可在這裏,在修改的JSON格式: http://openlibrary.org/dev/docs/jsondump

我只需要我的應用程序非常基本的信息,比什麼是在垃圾場提供的要少得多。我只是試圖擺脫書名,作者姓名以及書籍和作者之間的關係。

下面是他們的數據集中的兩個典型條目,第一個是作者,第二個是書(他們似乎每本書的每個版本都有一個條目)。在包含實際的JSON數據庫轉儲之前,條目似乎以主鍵和類型爲先導。

/一個/ OL2A /類型/作者{ 「名稱」: 「U. Venkatakrishna饒」, 「PERSONAL_NAME」: 「U. Venkatakrishna饒」, 「LAST_MODIFIED」:{ 「類型」:「/類型/ datetime「,」value「:」2008-09-10 08:44:01.978456「},」key「:」/ a/OL2A「,」birth_date「:」1904「,」type「:{」key「:」/type/author「},」id「:99,」revision「:3}

/b/OL345M/type/edition {」publishers「:[」社會科學研究項目,地理系,大學Dacca「],」pagination「:」ii,54 p。「,」title「:」Fayadabad地區的土地使用「,」lccn「:[」sa 65000491「],」subject_place「達卡地區。「],」number_of_pages「:54,」languages「:[{」comment「:」initial import「,」code「:」eng「,」name「:」English「,」key「:」/ l/eng「}],」lc_classifications「:[」S471.P162 E23「] ,「publisher_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 and F. Karim汗「,」oclc_numbers「:[」4671066「],」文稿「:[」汗,Fazle Karim,合着者。「],」主題「:[」土地使用 - 東巴基斯坦 - 達卡地區。「] }

未壓縮轉儲的大小非常大,作者列表大約2GB,書籍版本列表大小爲18GB。 OpenLibrary本身並沒有提供任何工具,它們提供了一個簡單的未優化的Python腳本來讀取示例數據(與實際的轉儲不同,它採用純JSON格式),但他們估計如果修改了它們以用於其實際數據,它會花2個月(!)完成加載數據。

我該如何讀取數據庫?我想我需要編寫一個程序來做到這一點。我應該怎樣做才能在合理的時間內完成什麼語言和指導?我有任何經驗的唯一腳本語言是Ruby。

回答

1

這將需要兩個月的時間從他們的網站下載轉儲。但它應該只需要幾個小時來導入。

最快的方式將是你使用Postgres的複製命令。您可以將其用於作者的文件。但是這些版本文件需要插入到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' 
+0

當你說我可以只爲作者的文件Postgres複製命令,你是什麼意思?我是否也需要將其處理成Postgres期望使用此類腳本的格式? – user294140 2010-03-16 01:35:16

+0

當然可以。我爲你做了兩個文件中較難的部分,並假定你可以自己做更簡單的文件。 – 2010-03-16 05:16:22

+0

再次感謝,得到了解決,你的幫助是無價的。 – user294140 2010-03-17 05:58:47

0

繼斯科特貝利的建議,我寫了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