自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。
Ruby言語やLinuxのネタが多いです。
January 20, 2006 [おもひで]
■ [Ruby] 保存しておいた文字列を高速に検索する
同じHTTPリファラから10回以上のアクセスがあった場合、それ以上(11回目から)のアクセスができないようにするためにはどのような実装が良いのかな。
■ まずは、リファラのURLをHashのキーとして持つことを考えてみた。
@deny_urls = Hash.new
def allow?(referer)
ret = true
if @deny_urls[referer]
if @deny_urls[referer] >= 10
ret = false
else
@deny_urls[referer] += 1
end
else
@deny_urls[referer] = 1
end
ret
end
s = Time.now
(0...10000).each do |i|
(0...15).each do
allow?("http://www.yotabanana.com/#{i}")
allow?("http://www.yahoo.com/#{i}")
allow?("http://www.google.com/#{i}")
end
end
p Time.now - s
なんだか、if文だらけになっちゃったし、使用例の部分もいまいちだけど、まぁいっか。
■ まぁ、ともかく、次に、keyに文字列のhashを使ってみる(ってかRubyのHashってこういう使い方しても大丈夫なんだっけ?(^^;))。
def allow?(referer)
ret = true
hash = referer.hash #(1)
if @deny_urls[hash]
if @deny_urls[hash] >= 10
ret = false
else
@deny_urls[hash] += 1
end
else
@deny_urls[hash] = 1
end
ret
end
allow?メソッドのとこだけ書き換え。他は同じね。
■ で、両者の性能を測ると
% ruby test.rb 4.146538 % ruby test2.rb 3.488657
うーん、もうちょっと高速化したいなぁ。他に高速化する方法ってある?
ポイントとしては、以下の感じ。Rubyクイズスタート!応募はツッコミ欄で!!ちなみに応募しても何も出ません(ってオイ(^^;))
- (1)のような数値化はallow?メソッドの中で実行する必要がある。(ループの外には出せない)
- 別にデータ構造自体Hashでなくてもいい。
- だいたい(90%以上で良いかな)うまくいけばOK。
- データは不可逆でOK。

ret = falseの前のifは本当はunlessでしょうか?それはそうとおもしろそうなので応募してみたいでーす。眠くなるのとどっちが早いか!?
こんなのはどうでしょう?
@deny_urls = Hash.new( 0 )
def allow?(referer)
hash = referer.hash
if @deny_urls[hash] < 10
@deny_urls[hash] += 1
end
end
ifの返り値を使うのがいやらしい感じ。
あ、ごめんなさい。<と>間違えて書いてました。直しておきました。
#手書きなんです・・・(苦笑)。
うーん、すごい。
zundaさん案のif文を整理しただけでも高速化するんですね!
% ruby test3.rb
3.202119
いやぁ、条件分岐、しっかり考えなきゃダメだってことですねぇ<自分。(苦笑)
ありがとうございましたm(__)m。