読者です 読者をやめる 読者になる 読者になる

メモりメモる

ハトいエンジニアのアメリカ生活と技術のメモ。

rubyでgoogle Custom Search API入門。複数キーワードのマッチング。

f:id:hatyone:20121021223632p:plain


下記のクラシックの3曲のうち、ショパンに最も関連ある曲は何でしょう?

・Fantaisieantaisie Impromptu(幻想即興曲)
・Quasi una Fantasia(月光)
・Klaviersonate Nr.11 A‐dur(トルコ行進曲)



少し音楽がわかる方なら一発で答えられるかもしれませんが、これが3曲じゃなく3000曲とかだったらどうしましょう。
ショパンの次はモーツァルトベートーヴェンと、いくつか問題がある場合はどうしましょうか。

なるべく自動でやってみたいと思い、googleの検索エンジンを利用してみました。
「対象名 候補名」のセットで検索をしてヒット件数をみるという、お手軽な方法です。

普通に"foo bar"と検索しても良いのですが、英語の場合は"foo is similar to bar"といった要領で検索してみたら、とても良い感じの結果を得られました。



■幻想即興曲の場合。
検索キーワード: "Chopin is similar to Fantaisieantaisie Impromptu"
ヒット件数: 4,450,000件
f:id:hatyone:20121021224206p:plain


■月光の場合。
検索キーワード: "Chopin is similar to Quasi una Fantasia"
ヒット件数: 36,600件
f:id:hatyone:20121021224213p:plain


トルコ行進曲の場合。
検索キーワード: "Chopin is similar to Klaviersonate Nr.11 A‐dur"
ヒット件数: 132,000件
f:id:hatyone:20121021224218p:plain

そんなこんなで、ショパンはこの3曲の中だと幻想即興曲との関連が最も強いということがわかります。


  • Custom Search APIを使ってみる。

APIs Console - Google CodeからAPIキーを取得します。
"Services"メニューから、"Custom Search API"の項目をONにします。
f:id:hatyone:20121021233259p:plain

"API Access"メニューの"Simple API Access"に、APIキーが書かれてあります。


  • サンプルソース

対象名(category1.ym)と候補名(category2.yml)のyamlファイルを用意します。

require "rubygems"
require "net/http"
require "uri"
require "json"
require "pp"
require 'yaml'
require 'cgi'

GOOGLE_KEY = "API KEY"
categories1 = YAML.load_file("category1.yml")
categories2 = YAML.load_file("category2.yml")

api_path = "http://ajax.googleapis.com/ajax/services/search/web"
api = URI.parse(api_path)
headers = {'Referer' => 'http://hoge.fuga.net/'}

categories1.each do |category1|
   max_count = 0
   category = ""

   categories2.each do |category2|
        data = "?v=1.0&key=#{GOOGLE_KEY}&q="+ CGI.escape(category1.to_s+" is similar to "+category2.to_s)
        apicall = Net::HTTP.new(api.host)
        response = apicall.get2(api.path + data, headers)
        
        data = JSON.parse(response.body)
        if data['responseStatus'] == 403
          exit
        end

        count = data['responseData']['cursor']['estimatedResultCount']
        count = count.to_i
        if max_count < count 
            max_count = count
            category = category2.to_s
        end
   end
   
   pp category1 + " is " + category

end

アレとコレが一致するか? — Gist


  • 注意したいこと

100 requests/dayなので、案外すぐに制限がきてしまいます。
データ量が多い場合は、 割とすぐに403が返ってくるので、根気よく、時間をかけてゆっくりスクリプトをまわすと良いと思います。
対象名300・候補名20くらいのデータだと、3日くらいかかりました。