たのしいRuby 第23章 郵便番号検索
膨大なデータから素早く検索処理をしたい!!そうなると、データベースの力を借りるのがいい。しかし、サーバー型のデータベースを使うほどでも無い。
そんな中途半端な問題を解決してくれるのが、ハッシュ型のデータベース。今回はgdbmを使った郵便番号の検索です。
まずは、実行結果から
% ./jzipcode.rb 907-1800 沖縄県八重山郡与那国町 search time : 8.533465 % ./jzipcode.rb 907-1800 沖縄県八重山郡与那国町 search time : 0.002622
DB作成時には9秒近くかかっていた処理が、DB作成後には、0.002秒で検索出来てしまう!!
凄いね。
改造ポイント
実際のコード
今回は長いよ・・・。
jzipcode.rb
#!/usr/bin/ruby =begin 郵便番号検索 Usage : jzipcode.rb [郵便番号] =end module Make # makeが必要かどうか判断する # true 必要 def make?(target, *prereq) return true unless File.exist?(target) # targetが存在しない return true if prereq.length.zero? # 依存ファイルが無い target_ctime = File.stat(target).ctime prereq.each do |req| return true if target_ctime < File.stat(req).ctime end return false end # target : prereq1 prereq2 .... # { ruby code } def make(target, *prereq) if make?(target, *prereq) yield end end end module ZipCode ZIP_FILE = "ken_all.csv" DB_FILE = "ken_all.db" COLUMN_ZIP = 2 include Make require "gdbm" require "csv" def make_database() make(DB_FILE, $0, ZIP_FILE) do open(ZIP_FILE) do |io| GDBM.open(DB_FILE, 0644, GDBM::NEWDB) do |db| io.each do |line| colums = line.split(",") zipcode = colums[COLUMN_ZIP].delete('"') if tmp = db[zipcode] line = tmp + line end db[zipcode] = line end end end end end def find(code) make_database() GDBM.open(DB_FILE, nil, GDBM::READER|GDBM::NOLOCK) do |db| if line = db[code] return CSV.parse(line) end end return nil end end # main t = Time.now include ZipCode require "nkf" begin str = ARGV[0] || "100-0000" if rows = find(str.delete("-")) rows.each do |row| address = row[6] + row[7] puts NKF.nkf("-w", address) end else puts "can't find #{str}" end rescue => ex abort ex.message end puts "search time : #{Time.now - t}"