HTMLの差分検知の時間を短縮する方法は?
短い文字列比較の方が高速なのでは?というアイデア
クローラーを作成する時に、対象のURLの内容の変更を検知したいことはよくあるかと思います。
そこで単純にHMTL同士を比較するよりも、ハッシュ関数を利用して作成したダイジェストを比較することで、 時間を短縮することができるのではないかと思い、検証してみました。
ただし、ハッシュ関数を利用する場合、前回取得したダイジェストと今回取得したHTMLをハッシュ関数を利用してダイジェストに変換する処理が必要になるので、 以下のような2ステップ必要すると仮定します。
1: 取得したHTMLをハッシュ関数を利用してダイジェストを求める
2: 保存しておいたダイジェストと今取得したダイジェストを比較する
どのハッシュ関数が良いか?
今回の利用目的では脆弱性は問題とならないので、ダイジェストを作成する時の時間に注目して、ハッシュ関数を選びたいと思います。
require 'benchmark/ips' require 'digest' target = 'hello' * 1000 Benchmark.ips do |x| x.report('Digest::MD5') { Digest::MD5.new.update(target).digest } x.report('Digest::SHA1') { Digest::SHA1.new.update(target).digest } x.report('Digest::SHA512') { Digest::SHA512.new.update(target).digest } x.compare! end
結果です。
Warming up -------------------------------------- Digest::MD5 10.426k i/100ms Digest::SHA1 10.226k i/100ms Digest::SHA512 5.500k i/100ms Calculating ------------------------------------- Digest::MD5 118.802k (± 1.3%) i/s - 594.282k in 5.003149s Digest::SHA1 99.109k (± 1.3%) i/s - 501.074k in 5.056664s Digest::SHA512 53.405k (± 5.2%) i/s - 269.500k in 5.064988s Comparison: Digest::MD5: 118801.8 i/s Digest::SHA1: 99109.1 i/s - 1.20x (± 0.00) slower Digest::SHA512: 53405.4 i/s - 2.22x (± 0.00) slower
※ 「繰り返し回数/時間(i/ms)」で処理を評価します。つまり、数値が大きいほど高速ということを意味しています。
生成するdigestの長さは、MD5: 16文字, SHA1: 20文字, SHA512: 64文字なので妥当な結果だと思われます。
今回の目的では「MD5」を利用するのが良さそうです。
ハッシュ関数 vs 文字列
冒頭で説明したハッシュ関数と単純な文字列を利用した方法の比較です。
require 'benchmark/ips' require 'digest' target = 'hello' * 10000 md5_digest = Digest::MD5.new.update(target).digest def digest_compare(str, digest) digest == Digest::MD5.new.update(str).digest end def str_compare(str1, str2) str1 == str2 end Benchmark.ips do |x| x.report('digest_compare') { digest_compare(target, md5_digest) } x.report('str_compare') { str_compare(target, target) } x.compare! end
結果です。
Warming up -------------------------------------- digest_compare 1.231k i/100ms str_compare 1.485M i/100ms Calculating ------------------------------------- digest_compare 13.293k (± 0.9%) i/s - 66.474k in 5.000995s str_compare 13.957M (± 7.1%) i/s - 69.813M in 5.047691s Comparison: str_compare: 13957048.8 i/s digest_compare: 13293.2 i/s - 1049.94x (± 0.00) slower
単純な文字列比較の方がはやいことがわかります。。。。
これは文字の長さを長くすると、ハッシュ関数の処理時間が増えることが原因か、差はさらに広がります。
結論
単純な文字列比較を行いましょう。