カカリアスタジオブログ

Happy Elementsのゲームブランド「カカリアスタジオ」の公式ブログです。

あんさんぶるガールズ!のイメージソングCD「ときめき☆アンサンブル」を頂きました!

エンジニアの草苅です。

4月29日に開催されたM3で、ななひらさんによるあんさんぶるガールズ!のイメージソングCD「ときめき☆アンサンブル」が頒布されました!

弊社は京都の会社ですので、どうにかして手に入れられないか、当日東京に行く人はいないのかと話合っていたのですが、ななひらさんのご厚意によりプレゼントして頂けることになりました!

そして、プレゼントして頂いたCDがこちらです!



届いた日は、朝からあんガルチームの部屋で流して、チーム一同聞き入っていました!
ななひらさんのかわいい歌声や、曲の完成度の高さに加えて、あんガルのカード枠を再現したパッケージなどもとても凝っていて、チーム一同感動しっぱなしでした!

CDの1曲目に収録されている「ダニエルは女の子です!」は、現在ニコニコ動画でも公開されており、ニコニコインディーズ総合順位1位になっているようです。すごい!まだの方はぜひ下のリンクから聞いてみてください。

ななひら x U-ske - ダニエルは女の子です! ‐ ニコニコ動画(原宿)


あんガル運営チームは二次創作を応援します!

今後、あんガルの二次創作がさらに盛り上がっていくといいなと感じています。

現在、公式サイトにて二次創作ガイドラインを公開する準備をしており、より多くの方に二次創作で楽しんで頂けるような仕組み作りや、二次創作をやりやすくするための素材公開も検討中です。

続報は公式ツイッターアカウントでご報告しますので、よろしければぜひフォローお願いします。



さいごに少し宣伝…

あんさんぶるガールズ!を一緒に作りませんか?

Happy Elements 株式会社ではイラストレーター・デザイナーを募集中です。
中の人になって、京都で一緒にあんガルを作ってみませんか?社員・アルバイトどちらでも、ご応募お待ちしています!

fluentdとMongoDBでユーザー行動を見える化

はじめに

エンジニアの@ryooo321です。
よろしくお願いします。
今回は弊社で運用中の全アプリで利用している行動分析プラットフォームについてご紹介したいと思います。
2012年の6月に作ってから、約9ヶ月ほど運用しています。

特徴

・手がかからないデータストア
・さまざまな問い合わせ対応で利用できる柔軟なクエリ
・機敏なMap/Reduceによる集計
・集計結果をCSVやグラフで可視化

目的

・ユーザーの問い合わせに効率的に対応し、アプリの企画・開発に集中するため
・ユーザーの行動を抽象化・可視化することでPDCAの質を向上させるため


行動ログのフロー

1. ユーザーからRuby on Rails製のソーシャルゲームにリクエスト

2. Railsからローカルのfluentdにログ出力(fluent-logger-ruby)

3. ローカルのfluentdから行動分析プラットフォームのfluentdにログ転送(fluentd)

4. 行動分析プラットフォームのfluentdに集約後、MongoDBにinsert(fluent-mongo)

5. MongoDB上でMap/Reduce集計し、集計結果をMongoDBに保存

6. 集計結果をCSVやグラフ出力



目次

1. アプリについて

2. fluentdの利用

3. MongoDBの利用

4. 行動をミクロな視点でみる

5. 行動をマクロな視点でみる

6. fluentdとmongo連携でのはまりどころ



1. アプリについて

現在メインで担当しているアプリは、全webサーバーで6,300,000req/dayほどの規模です。
アプリはRuby on Railsで作っており、Cassandra + MySQL + Memcacheを組み合わせて利用しています。



2. fluentdの利用

fluentdはイベントログの転送をするためのツールです。
起動やログを出力する方法は公式githubでご覧ください。

fluentdにはさまざまなプラグインが用意されていますので、
多種多様な言語・構成・目的を楽に乗り越えて活躍してくれるプロダクトだと思います。


起動/死活監視

GODを使っているのですが、fluentdは高負荷がかかっても落ちず高い可用性を発揮してくれます。


出力タイミング

サーバーのログからtailしつつ収集する方法もありますが、弊社ではRailsアプリから直接fluentdにログを送っています
Rubyのhashの形式のままfluentdを通じてMongoDBに保存できます。
fluentdは高負荷や落ちている場合でも処理をブロックしないので、アプリには影響が出ません。

弊社の場合Google analyticsも利用しているので、リクエスト統計などはそちらで収集しています。


出力するログの例

ユーザーのリクエスト毎(主にpost/delete系)に、下記のようなログを0〜数件出力しています。
document:
  _id: yyyymm_user_id_xxxxxxxxx
  user_id: xxxxxx
  category: ログ種別(user/payment/card/mission etc..)
  type: ログタイプ(in/out/use/get etc..)
  platform: xxx
  request:
    page: payment/finish
    viewer_id: xxxxxx
    request_id: 同じリクエストで複数ログを出すときは、先頭のログの_idを入れる
  device: xxx
  info:
    ここにログ種別ごとの詳細な情報をhashで出力
  condition:
    ログ出力時点でのユーザーの状態をすべてのログで出力
    level: xxx
    st: xxx
    bp: xxx
    max_st: xxx
    max_bp: xxx
    gacha_pt: xxx
    cards_count: xxx
    friends_count: xxx
    leader_card_id: xxx
    training_card_id: xxx
    joined_at: xxx
  time: ログ出力日時(fluentdが付与)
このようなログが1,000,000 rec/dayほど出力され、fluentdによりMongoDBに保存されます。



3. MongoDBの利用


Capped collectionを利用

MongoDBにはCapped collectionという固定サイズのコレクションを持つ仕組みがあります。
・固定サイズでアロケートされた領域にデータを書き込むため、通常のinsertより高速。
・固定サイズまでデータが溜まった場合、古いデータから自動で削除されていきます。

メリット

弊社ではこの仕組みを使うことで、チャンクの監視・手動のシャーディングを行わないで済むようにしています。
Capped collectionを使うことで運用から手が離れることのメリットが大きいです。

デメリット

一方で決して小さくないデメリットもあります。
・Capped collectionではデータのシャーディング(水平分割)ができませんので、Map/Reduceの分散処理の利点が十分に活かせません。
現在、1,000,000ほどの日次レコードを150ほどのMap/Reduceスクリプトで分析するのに、約30〜45分ほどかかっています。
レプリカセットという仕組みでの分散はできるのですが、MapReduceの利用には制限がかかります。(結果保存できずinlineでしか使えない)

・古いデータが削除されてしまう。
前述のログで600byte/レコードです。1日1,000,000レコードで0.6GBほどになります。
現在、100GBのCapped collectionを用意しているので、5ヶ月ほどは消えません。

また、古いデータが削除されてしまうため、MapReduceによる過去分の集計はできなくなります。
しかし、日次のMapReduceの結果を保存しておき、その結果は5ヶ月以上残し、MapReduceの結果に対してMapReduceで集計することで過去分の集計ができます。
そのため、データの持ち方や集計フローの設計が非常に重要になります。



4. 行動をミクロな視点でみる

行動調査

MongoDBでは、user_idとtimeにindexを貼っています。
これにより、ユーザーの行動は時系列で並べて調査できます。


出力したログはリクエストや対象モデルごとに絞り込みができるほか、json形式のログの全内容を確認することももちろん可能です。


行動ログの出力タイミング

ログはリクエストの最後にまとめて出力するのではなく、CassandraやMySQLに対してデータを処理した直後に都度出力しています。

これにより下記のようなメリットがあります。
スキーマのデータ構造をシンプルに保て、検索や集計をシンプルに行えます。
・エラーなどによる出力漏れの可能性がほぼなくなりログの信頼性が大きく向上しました。



5. 行動をマクロな視点でみる

Map Reduceで集計

MongoDBのサーバー上にjavascriptで書いたMapReduceスクリプトを配置し、バッチで全scriptを実行しています。

共通ファンクション群のロード

下記のようにすることで、いくつかの便利なファンクション群をMapReduceスクリプトで使えるようにしています。
load(pwd() + '/map_reduces/lib.js')

MongoDBのmapReduceメソッドのscopeオプションを渡すことでこのメソッド群をmapファンクションやreduceファンクションでも利用できます。

集計の元ドキュメント

{
  category: 'payment',
  info: {
    price: 100,
    item_id: 20,
    count: 1
  },
  time: xxx,
  condition: {
    level: 10,
    joined_at: xxx,
  },・・・
}

一次集計されたドキュメント

_idが同じもののvalueを足し合わせてくれる単純なMapReduce集計を利用し、元ログを下記のように一次集計します。
一次集計することで、重い元データの集計を最低限にしています。
// 日付・購入物・属性の組み合わせごとに集計された状態です。
{
  _id: {
    ymd: '20130318',
    item_id: 20,
    level: 10,
    play_term: 20,
  },
  value: {
    count: 1,
    price: 100,
    arppu: 100,
  }
}

商品ごとの集計結果

一次集計した結果を元に、下記のように再集計します。
// 日付・購入物ごとにいくらの売上があったかの集計です。
{
  _id: {
    ymd: '20130318',
    item_id: 20,
  },
  value: {
    count: 1,
    price: 100,
    arppu: 100,
  }
}

プレイ日数ごとの集計結果

一次集計した結果を元に、下記のように再集計します。
※ レベルやプレイ日数は1単位ごとに集計してもよいのですが、あまり意味がないので5や10ごとに丸めて集計しています。
// 日付・プレイ日数ごとにいくらの売上があったかの集計です。
{
  _id: {
    ymd: '20130318',
    play_term: 20,
  },
  value: {
    count: 1,
    price: 100,
    arppu: 100,
  }
}

このような形で、さまざまな切り口での売上、商品のin/out、ユーザー数など、150ほどの集計を行っています。


さまざまなグラフによる可視化

日次で集計した結果を毎日必要なものをグラフやCSVで取得できます。




ルール

MapReduceした結果を簡単にCSVで出力したりグラフ化するに当たって、データを汎用的に取り扱うためいくつかのルールを決めました。
・_idとvalueの値は一次元のハッシュとすること
このルールにより、CSVやグラフの出力をシンプルに行えています。

・_idに必ずymdを持つこと
CSVの出力期間はymdでフィルターし、グラフ化のX軸はymdとし、Y軸はymd以外の_id値としています。
valueに複数のキーがあっても、valueのキーごとにグラフを出力します。
集計は日次単位でしか行っておらず、過去分の分析は通常行っていません。
※ 先ほどの例だと、X軸がymd、Y軸がプレイ日数、値がpriceのグラフなどが見れます。



6. fluentdとmongo連携でのはまりどころ

・fluent-mongoでMongoDBにデータを流すにあたって、MongoDBのRubyドライバでBSONエンコードできないデータを流すと「__broken_data」として登録されます。
例えばハッシュのキーがintだと「__broken_data」になります。

・fluentdからCapped collectionに流す
collectionに流す際は、fluentdの設定ファイルで「capped」指定と「capped_size」指定が必要です。



一緒に働きたい方、絶賛 募集中

京都でスキルアップしたいエンジニアの皆さん、ご応募お待ちしています!
京都でスキルアップしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
大阪、滋賀、神戸から通勤実績あり


以上、長文にお付き合い下さいましてありがとうございました。

「あんさんぶるガールズ!」がGREE Technology Award 2013を受賞しました!

エンジニアの草苅です。


あんさんぶるガールズ!」が3月8日に開催された GREE Technology Conference 2013 で GREE Technology Award 2013 CTO賞を受賞しました!

今回、技術系の賞を頂いたということで、技術ネタでいきたかったのですが、前回の記事でシステム面について少し紹介したことと、あまりいいネタが思いつかなかったということもあり、今回はまだ開発に入る前の段階の企画書を公開してみます!


あんさんぶるガールズ!」は昨年8月から企画を始めて、9月から開発を開始、11月22日にGREEで公開しました。

この企画書では他社が権利をもっているコンテンツ名などが出てくる箇所は黒く塗りつぶしている他、一部ページを削除しているものの、大枠はわかる内容となっているかと思います。昨年の8月の時点でちあき、ちよ、あいかのキャラ設定・イラストはもうここまでできていたのですね!(学年や名前の設定は最終的なものと少し違います)。

この企画書に出てくるR・SRカードは現在お蔵入りとなっており、アプリには出てきません。Rに関しては制作ルールの関係でお蔵入りとなり、SR以上のカードについては、後に「ゲーム内のシナリオに登場する場面をカード絵にする」というルールとしたことから、当初制作していたSR以上のカードはシナリオの場面に合わせて制作し直しています。

ちなみに、この頃はまだ日日日先生にシナリオを書いて頂けることは決まっておらず、様々なラノベを読みながら、どの作家さんに書いて頂けたらおもしろいアプリになるだろうと思いを膨らませつつ、シナリオ依頼を送らせて頂く作家さんを検討していました。


最後に宣伝

あんさんぶるガールズ!」では現在3年生の人気投票イベントを開催中です。人気投票で1位になった生徒は来月開催のイベントで、日日日先生の書き下ろしシナリオと共に、URカードとして登場します!
また、14日からはホワイトデーイベントも始まります。こちらも日日日先生書き下ろしのホワイトデーシナリオを用意していますので乞うご期待!
あんさんぶるガールズ!」はApp StoreGoogle PlayGREEで公開中ですので、まだ遊んだことがない方はぜひ一度プレイしてみて下さい!

「あんさんぶるガールズ!」をリリースしました!


エンジニアの草苅です。



僕が8月頃からPM兼プログラマーとして関わっているアプリ「あんさんぶるガールズ!」が11月22日にGREEプラットフォームでリリースされました!

あんさんぶるガールズ!」の売りは何といっても、人気作家日日日さんに書いて頂いたシナリオと、総勢60人のかわいい女の子達なわけですが、システム面でも新しい取り組みを多く入れた意欲作となっていますので、手前味噌ながら今回はそのあたりを紹介させて頂きたいと思います。


Zepto.js による軽快な動的ローディング

あんさんぶるガールズ!」では、多くのソーシャルアプリが採用している jQuery ではなく、Zepto.js を採用することでネットワーク負荷や初期化処理時間を軽減しています。
また、動的ローディングによる部分書き換えを積極的に利用することで、ユーザービリティの向上を図っており、この部分にも Zepto.js は効果を発揮しています。
ソーシャルアプリの場合、iframe 内での画面遷移となるため、それ起因で動的ローディングはいろいろと問題が発生していたのですが、リリース直前で問題が解消され、なんとか日の目を見ることができました。


CreateJS によるハイパフォーマンスなHTML5アニメーション

あんさんぶるガールズ!」では CreateJS を利用してすべてのアニメーションを制作しており、Andoroid 端末であっても Flash を利用せず、すべて Canvas でアニメーションを処理しています。
これにより、Flash変換ツールを使ったアニメーションと比較して圧倒的に高速で軽快なアニメーションを実現することができました。
未プレイの方はぜひアプリをプレイ(クエストなど)して頂けると、変換ツールや Flash のアニメーションと何が違うか、どのくらい違うのかが実感頂けると思います。

例えば、クエストであれば複数のアニメーションを連続実行する際、アニメーション実行前に、必要なアニメーションの画像をプリロードすることで、通信がアニメーションの連続実行を妨げることがないようにしています。また、クエスト中に全画面読み直しが発生することがなく、アニメーションに必要があれば差分の画像を読み込むだけという作りになっています。

また、CreateJS に未実装なものや不具合に対応するため EaselJS、PreloadJS にパッチを当てたり、Retina Display への対応や MovieClip を再利用しやすくするため、独自の拡張なども行っています。


CoffeeScript による開発効率化

弊社のすべてのアプリは Ruby on Rails 上に構築されており、「あんさんぶるガールズ!」では特に Rails らしい書き方となるように意識してソースコードを書くようにしています。
より Rails らしくという方向性ということもあり、JavaScript の記述には Rails 標準である CoffeeScript を採用しています。
CoffeeScript によって JavaScriptバッドノウハウをあまり意識しなくてよくなり、可読性が上がり、結果的にチーム開発の効率が上がったと思います。
1~2時間程度で習得できて、それなりに効率が上がるところが CoffeeScript の良いところだと思います。


Less による css 記述の効率化

Rails 標準であれば Sass なところですが、「あんさんぶるガールズ!」では Less を採用しています。
これは css を一番書くデザイナーさんの希望によるものです。Rail に乗ることも重要ですが、一番 css を書く人に決めてもらうのが一番だという判断となりました。


Asset Pipeline によるアセット集約

Rails の Asset Pipeline 機能により、アプリの production 環境への deploy 時にアセットの precompile (集約と圧縮)を行っています。
これにより development 環境では .coffee、.less を編集し、production 環境では js、css はそれぞれ1ファイルにまとめられ、minify化されたファイルが nginx 経由で転送される形となっています。
Rails 標準では画像もアセットに含まれるのですが、「あんさんぶるガールズ!」はカードゲームで画像が大量にあるということもあり、今回は画像をアセットから外し、画像に関しては Rails 3.0 までの timestamp をつけてURLを生成するように対応しています。こちらも基本的には Rail に乗りつつも臨機応変にという形です。


まとめ

今回は「あんさんぶるガールズ!」のフロント周りの概要をご紹介しました。

あんさんぶるガールズ!」では今日の夜頃からクリスマスイベントが始まります。ぜひプレイしてみて下さい!


© Happy Elements K.K