分析系システムの業務的なメモ

最近、分析系のシステムに携わっている。

色々と学ぶことがあったのでここにメモする。

分析システムの種類

分析システムをニーズから分類すると、「定型レポート」と「データの特徴量や関係性をデータマイニングするツール」に大別できるらしい。(受け売り)

定型レポート系

定型レポートは、アクセス実績とかの定型的な数字を出すためのツール。

例えば特集ページを打ったりしてイベントを実施して、キャンペーン対象のページのアクセスが普段よりこれぐらい上がりましたよー、などの数字を出したり、もっと一般的には、日常的なユニークユーザー(UU)数、コンバージョン(CV)数などを出したりして経営のコンディションを判断したり、サラリーマン的なできたよアピールにつかったりする。

知る限りでは、特定の業態にあった検索フォームを作成して、CSVかなんかにしたりグラフィカルな図に出力したりするツール。SalesforceとかWebForcusとかがパッケージとして有名かな?

データマイニングツール系

もう一つの大きい分野が、データサイエンスちっくに細かく傾向を割り出すツール。

「この商品購入するユーザーって、〇〇にも興味あったりするよね」など、レポーティングシステム化されていないが蓄積データから分析できそうなことをディメンションから切っていくのが主な使い方。

ある程度の規模に収まるんだったら「SQL叩けよ」で済みそうな気もするが、ベンダー間保守契約とか資産管理とかセキュリティとかそもそもそんな人材確保できんの?的な観点で、こういうのもツール化することが多いらしい。

用途的にSQLたたきたーい!みたいなことに近いので、下手にオレオレ製品を作るのはあまりないのかな?(調査不足) 今のところでいうと、 Tableauという製品が流行りのようだ。(今の仕事で使っているし、記事にも紹介が頭から出ていた。) (ガチ勢はSQLやらHadoopやら叩けるんだろうが、前述の通り云々)

基本的なアーキテクチャ戦略

グレーな範囲で今の現場のシステムの基本的な戦略を紹介。

多分バレたら怒られると思うけど、正直ショボいし一般的なものだと思うので大丈夫かもしれない。

分析用DBとデータ移送

データ5万件とかそういう規模だと別に気にしなくてもよいが、ある程度の規模になると、「業務用DB」と「分析用DB」でDBが物理的に分かれる。

理由は2つあって、

  • 1つは参照ロックで業務影響を与えないようにすること。分析のクエリって10分ロックかけるような重いものが普通で、分析システムにて秒でコミットガンガン飛ばそうとしているのに更新待ちになったりタイムアウトしたりと致命的なレベルで問題が発生するため。
  • 2つは分析データの時間軸確定のため。リアルタイム更新するデータを参照しちゃうと、1つめの検索と2つめの検索でちょっとデータ量や数値違って「これ何?」って上司や客先にいわれちゃう。なので、夜間に昨日までのデータだけコピーして集計!みたいなことをする。

DBを分けると、データ移送が必要になる。要するに、業務DBと分析DBで同じテーブル作ってデータをコピーする処理のこと。

データ量によって、全件移送(分析DBを一度クリアして全件コピー)、差分移送(最後に分析DBにコピーした時点から、現在までの更新分だけをコピー・過去データ更新する)の2つを選択する。

差分移送にはいくつか注意点がある。

  • 〇〇時以降のデータのみコピー!が基本的な考えになるが、検索の境界値となるタイムスタンプや連番の最小値を取ってからすぐ移送を開始してはいけない。一度トランザクションを終了し、業務システムが確実にコミットするであろう期間をあけて移送を開始する。
    • DBはコミットするまで更新後データは他のクエリ上から見えない。長引くトランザクションの影響で「2017/01/01 00:11」時点では「2017/01/01 00:10」のタイムスタンプが刻まれた処理が未コミットで移送漏れが起きるかもしれない。
    • Oracleなどトランザクションを切らないとトランザクション中に他のクエリが更新した内容が見れないこともある
  • 異常終了のリカバリをミスると、データが重複してインポートしてしまうことが考えられる。主キー重複だと辛い。
    • 更新キーを予め設定するのもありかな。

集計処理

毎日の夜とか月1とかでよく流す。以下の目的をもって作られる。

  • その日時点の業務データを集計 or 変換して日ごとに蓄積する。(次の日でレコード更新するとデータが変わってしまうため)
  • 分析クエリが複雑になったり無理のあるテーブルのjoinなどでパフォーマンス劣化が考えられるとき、あらかじめ問題になりそうなデータを集計しておく。

気を付けたいのが、集計期間を指定するときに、WHERE句などの中にCURRENT_DATEとか組み込まないで外部パラメータ化すること。

例えば、日付用のテーブルとして「集計開始タイムスタンプ = 2017/01/01 00:00:00」「集計終了タイムスタンプ = 2017/01/02 00:00:00」という値を設定してそこを参照するようにすると、 障害でその日集計できなかったとしても、上記パラメータを設定して後日再集計ができる。