ferret を使いたい (その3)
先週末に 書籍 "Ferret" を入手した。
書籍のサンプルを試して、使い方は分かった気がする。
そこでferret で 郵便番号データ(全国版) を index を作り、検索をさせてみた。
index をつくるのが遅いけど、検索は十分な速さがある。
この程度なら、xfy/xvcd から ruby を呼び出して使う際も、十分な速度が得られると思われる。
// index を作るソースが、我ながらいダサイ。もっとよい書き方に変更できると思うが、まずは動作させることから...
使用マシンは MacBook, MacOSX 10.5。
$ gem list ferret
*** LOCAL GEMS ***
ferret (0.11.6)
$ ruby -version
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9]
インデックスを作る。
$ time ruby ZiptoFerret.rb
..........................................................................................................................
indexed 122535 zips.
real 2m7.108s
user 1m26.578s
sys 0m36.770s
ferret のワイルドカード検索を使う。
$ time ruby search-zipcode.rb '*有楽町*'
1.0: 0383135 青森県 つがる市 木造有楽町
1.0: 3260801 栃木県 足利市 有楽町
1.0: 3591114 埼玉県 所沢市 北有楽町
1.0: 3591117 埼玉県 所沢市 有楽町
1.0: 1000006 東京都 千代田区 有楽町
1.0: 9188008 福井県 福井市 有楽町
1.0: 5020033 岐阜県 岐阜市 長良有楽町
1.0: 5060013 岐阜県 高山市 有楽町
1.0: 4418035 愛知県 豊橋市 有楽町
1.0: 4750837 愛知県 半田市 有楽町
1.0: 5110079 三重県 桑名市 有楽町
1.0: 7450035 山口県 周南市 有楽町
12 hits.
real 0m0.313s
user 0m0.243s
sys 0m0.065s
AND 指定で絞り込むこともできる。
$ time ruby search-zipcode.rb '*東京* AND *有楽町*'
1.0: 1000006 東京都 千代田区 有楽町
1 hits.
real 0m0.424s
user 0m0.333s
sys 0m0.085s
以下にコードを示す。
$ cat LineAnalyzer.rb
require 'pp'
require 'MeCab'
class LineAnalyzer
def initialize()
end
def token_stream(field, str)
return LineTokenizer.new(str)
end
end
class LineTokenizer
def initialize(str)
self.text = str
end
def text=(str)
@n = str
end
attr_reader :text
def next
return nil if @n == nil
token = Analysis::Token.new(@n, 0, @n.length)
@n = nil
return token
end
end
$ cat ZiptoFerret.rb
# See http://webos-goodies.jp/archives/51369852.html
require 'rubygems'
require 'nkf'
require 'csv'
require 'ferret'
require 'LineAnalyzer'
include Ferret
include Ferret::Index
include Ferret::Analysis
$KCODE='UTF8'
Ferret.locale = 'ja_JP.UTF-8'
index_dir = 'zip_index'
csv_fname = 'KEN_ALL.CSV'
data = NKF.nkf('-Sw80m0', IO.read(csv_fname))
# index = Index.new(:path=> index_dir, :create => true, :analyzer => RegExpAnalyzer.new(/.*/, false))
index = Index.new(:path=> index_dir, :create => true, :analyzer => LineAnalyzer.new)
line_count = 0
# 01101,"060 ","0600000","ホッカイドウ","サッポロシチュウオウク","イカニケイサイガナイバアイ","北海道","札幌市中央区","以下に掲載がない場合",0,0,0,0,0,0
CSV::Reader.parse(data) do |row|
line_count += 1
index << {
:id => line_count,
:zip => row[2],
:prefecture => (row[6]||''),
:city => (row[7]||''),
:street => (row[8]||'')
}
if line_count % 1000 == 0
printf "."
$stdout.flush
end
end
index.optimize
index.close
puts "\nindexed #{line_count} zips."
$ cat search-zipcode.rb
require 'rubygems'
require 'ferret'
require 'fileutils'
require 'MecabAnalyzer'
require 'pp'
include Ferret
include Ferret::Index
$KCODE='utf8'
def usage(message = nil)
puts message if message
puts "ruby #{File.basename(__FILE__)} <search_pattern>"
puts " examples for search_patter:"
puts " '*10000*' "
puts " '*千代田区*' "
puts " ':zip:*1000*'"
puts " ':city:*千代田区*'"
puts " ':street:*有楽町*'"
puts " '*千代田区* AND *有楽町*'"
puts " 注意: 文字コードは UTF-8. "
exit(1)
end
index_dir ="zip_index"
limit = 100
offset = 0
usage() if ARGV.size != 1
search_phrase = ARGV[0]
index = Index.new(:path => index_dir)
results = []
total_hits = index.search_each(search_phrase,
:limit => limit, :offset => offset) do |id, score|
results << " #{score}: #{index[id][:zip]} #{index[id][:prefecture]} #{index[id][:city]} #{index[id][:street]}"
end
index.close
puts results.join("\n")
puts "#{total_hits} hits."
« タイマー付きダイアログボックス | トップページ | ピックアップ:大規模にしないためにはどうするか」を考えよう, 部下のやる気を育てる為にリーダーが知っておくべき名言, etc... »
この記事へのコメントは終了しました。
« タイマー付きダイアログボックス | トップページ | ピックアップ:大規模にしないためにはどうするか」を考えよう, 部下のやる気を育てる為にリーダーが知っておくべき名言, etc... »
コメント