5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GoogleAnalyticsAPIのgem"Legato"でQuery結果をキャッシュして10倍速くする

Last updated at Posted at 2016-01-25

Google Analytics API はそこそこ遅い

Google Analytics APIを使ったことがある人なら「結果帰ってくるの遅いなあ…」とぼやいたことあると思います。

速くするためには期間で絞り込みする、ディメンション(指標)を複雑にしない、結果件数を絞り込む(10件とか)、gzipの指定をする。の方法がありますが、これらを行っても遅いものは遅いのです。

Legato 使っても当然そこそこ遅い

RubyからGoogeAnalyticsAPIを使うには"Legato"がとても便利です。

使い方の説明は同じQiita内の以下記事をご確認ください。

Legato中でOAuth認証とGoogleAnalyticsAPIのエンドポイントへアクセスしているので、当たり前ですがそこそこ遅いです。

クエリー結果をキャッシュする

どのレイヤーでキャッシュするのか?を考えた時にアプリケーションのビューやモデル内も考えられますが、もっとも広範囲で恩恵を得られるのはLegatoの中です。

そういう事でLegato内でクエリー結果をキャッシュする事で高速化を図りましょう。

キャッシュするモンキーパッチ

Railsアプリ内から使うサンプルコードです。以下パスでLegatoに簡易パッチを当てます。

config/initializers/legato_ext.rb

legato_ext.rb
#
# patch on Ver 0.6.2
# https://github.com/tpitale/legato/blob/169d806f9486fed3aceb61a7e42dc04a1c405fcc/lib/legato/request.rb
#
module Legato
  class Request

    def cache_url
       query.base_url + query_string
    end
    
    def cache_key
      prefix = self.class.name.underscore
      [prefix, Digest::MD5.hexdigest(user.access_token.token + cache_url)].join("/_/")
    end
    
    def cache_log
      Rails.logger.info("Cache Legato::Request. key=" + cache_key + ", url=" +  cache_url + ", token=#{user.access_token.token}")
    end
    
    def get(*args)
      raw_response = Rails.cache.fetch(cache_key, expires_in: 8.hours){
        cache_log
        user.access_token.get(*args)
      }
    end    
    
  end
end

#
# patch on Ver 0.6.2
# https://github.com/tpitale/legato/blob/169d806f9486fed3aceb61a7e42dc04a1c405fcc/lib/legato/management/finder.rb
#
module Legato
  module Management
    module Finder
      
      def cache_key(user, uri)
        Digest::MD5.hexdigest(user.access_token.token + uri)
      end
      
      def cache_log(user, uri)
        Rails.logger.info("Cache Legato::Management::Finder. key=" + cache_key(user, uri) + ", uri=" + uri + ", token=#{user.access_token.token}")
      end
      
      def all(user, path=default_path)
        uri = base_uri + path
        json = Rails.cache.fetch(cache_key(user, uri), expires_in: 10.minutes){
          cache_log(user, uri)
          user.access_token.get(uri).body
        }
        items = MultiJson.decode(json).fetch('items', [])
        items.map {|item| new(item, user)}
      end

    end
  end
end

キャッシュを有効にしていない場合は以下のようにcache_storeを指定します。Gemfileにもキャッシュストアを指定します。

ここでは MemCached + Dalli にしています。

config/enviroments/development.rb
Rails.application.configure do
 #...省略
 config.cache_store = :mem_cache_store, "127.0.0.1:11211"
end
Gemfile
gem 'dalli'

コードの説明

このコードでは以下の2つを行っています。

  • クエリー結果(Core Reporting API)のレスポンスをキャッシュ
  • メタ情報(Management API)のレスポンスをキャッシュ

キャッシュキーにアクセストークンとURLを組み合わせた文字列を使うことでセッション違いの同一クエリーと被らないようにしています。

あとLegatoのコードがリファクタリングされて読みやすくなっていました。これならパッチを当てるのもスムーズです。

参照情報

さいごに

質問などあればコメントにお願いします。直接メッセージをしたい方はTwitter宛にお願いします。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?