akaishi です。 きのうメールを出したのですが返ってこないので再送します。 もし2通届いたらすみません。 しかし netlab.co.jp ってやたらと重くないですか? :::::::::: 九大の西さんが作られた goo-0.2.rb というプログラムがあります。それは、 WWW のアクセスログの referer の情報から、自分のページが検索エンジンでど のようなキーワードで検索され、アクセスされたかを調べるものですが、その goo-0.2.rb を元に、ruby と perl の速度の比較をしてみました。 # あまり厳密な比較ではないので目安程度にみてください。 1. goo-0.2.rb が対象とするログは一般的な形式ではなかったため、より一般的と 思われる Apache の combined 形式に対応させたものを自分で作成し、さらに同 一の正規表現を使った perl 版も作って速度の比較をしました。 http://ruby.freak.ne.jp/goo/goo1.rb ruby 版 http://ruby.freak.ne.jp/goo/goo1.pl perl 版 それぞれで、某 WWW サーバから持ってきたアクセスログ 50000行を食わせた時 間を測定しました(環境 Pentium II 333MHz, RAM 96MB)。時間は複数回測定し、 最速のものをのせています。ruby のバージョンは ruby 1.2.3, perl は 5.005_02 です。 ruby 版の結果 35秒68 perl 版の結果 12秒95 残念ながら perl の方が圧倒的に速いという結果が出ました。 2. WWW のアクセスログを良く見ると、この中で検索エンジンからたどられてきた行 の割合は全体から見ると極少ないことがわかります。よって全ての行に対して複 雑な正規表現を適用するよりも、まず検索エンジンからたどられてきたっぽい行 だけを簡単(高速)なテストで抜き出し、それから本番の正規表現を適用した方が 速くなると思われます。 具体的には while access_log = gets if access_log =~ CompiledRegex ... end end となっているのを、 while access_log = gets if access_log.index(??) if access_log =~ CompiledRegex ... end end end としてみました。検索エンジンからたどられてきた行は必ず '?' を含んでいま す。逆に '?' が含まれているからといって必ず検索エンジンからたどられてき ているとは限りませんが、これでかなり絞り込めるはずです。 このように修正して同じテストを実施すると ruby 版の結果 6秒73 perl 版の結果 3秒70 どちらも速くなりましたが、まだ perl のほうがずっと速いです。 なお、固定1文字の検索ならば、access_log =~ /\?/ よりも access_log.index(??) のほうが高速です。 (index の代りに include? でも良い) 3. 今度は RegexStr の http:\/\/.*(' + HostsStr + ')[^\?]*\? という部分を http:\/\/.*\b(' + HostsStr + ')\b[^\?]*\? にしてみます。これで正規表現でのバックトラックの回数が減ると思われます。 ruby 版の結果 4秒74 perl 版の結果 3秒07 4. '?' を含んだ行で絞り込みましたが、'?' を含んでいるからといって検索エンジ ンからたどってきたログとは限りません。それでさらにもう一段、ホスト名パター ンで絞り込みをかけます。 まず、 RegexStr = '^([^ ]*) \S* \S* \[(\S*) \+\d*\] \"\w* ([^\ ]*) \S*\" \d* \d* "http:\/\/.*\b(' + HostsStr + ')\b[^\?]*\?([^"]+)' これを次のようにホスト名部分を分離します。 RegexStr = '^([^ ]*) \S* \S* \[(\S*) \+\d*\] \"\w* ([^\ ]*) \S*\" \d* \d* "http:\/\/[^\?]*\?([^"]+)' CompiledHosts = /\b(goo\.ne\.jp|infoseek\.ne\.jp|infoseek\.com|......)\b/ そしてループ部分を次のように変更します。 if access_log =~ /\?/ && access_log =~ CompiledHosts robothost = $1 if access_log =~ CompiledRegex host, date, target, args = $1, $2, $3, $4 ... end end ruby 版の結果 2秒58 perl 版の結果 3秒57 ついに ruby が逆転しました。それだけ ruby の fastmap は効果があるのでしょ う。perl は何故か 3. のときよりも遅くなっています。 最終的なプログラム http://ruby.freak.ne.jp/goo/goo4.rb ruby 版 これと同等な perl 版 http://ruby.freak.ne.jp/goo/goo4.pl perl 版 perl 版で、試した中では一番速かったもの http://ruby.freak.ne.jp/goo/goo3.pl 5. ruby-1.3.3-990513 では正規表現エンジンが non-POSIX NFA 型になりました。 それで試すとさらにちょっと速くなります。 ruby-1.3.3-990513 の結果 2秒42 (4. と同じスクリプトの結果) ともかく、http://www.netlab.co.jp/ruby/jp/pcjp98/page16.html に「正規表 現ルーチンは Perl が速い」と書いてありますが、そうとばかりもいえないよう です。 注: Perl 版は、Perl に詳しい人が手を入れればきっともっと速くなるでしょう。 Ruby 版も。 また、アクセスログの中身によって、結果は異なったものになる可能性もあ ります。極端な話、全部の行が CompiledRegexp にマッチするものならば 前段の絞り込みは無効になり、perl 版のほうが速くなるかもしれません。 6. 原作者の西さんから、最新版の RobotHostHash を頂きました。これを反映させ たバージョンを http://ruby.freak.ne.jp/goo/goo.rb ruby 版 に置いてあります。