作成者別アーカイブ: kanapom

Amazon Elasticsearch ServiceでKibanaを利用する

Pocket

みなさんこんにちは。配信/インフラチームの佐々木と申します。adstirの配信サーバの開発とインフラを担当しております。

今回はAmazon Elasticsearch ServiceとKibanaを利用したデータの可視化について書きたいと思います。

ElasticsearchとKibanaについて

両方とも有名なミドルウェアなので詳細な説明は省きますが、端的に言うとElasticsearchは全文検索エンジンでKibanaがそれを可視化するためのWEB-GUI(中身はNode.js)になります。

ポイントとしてはElasticsearchもKibanaもオープンソースで公開されているのですが、両方ともAWSのマネージドサービスとしても提供されているため、構築と運用の負担が非常に軽いという点があります。(もちろんEC2を利用する事もできますし、AWS以外の環境でも利用は可能です。) 開発元が同一なため親和性が高く、今後はバージョンも統一されていくようです(現在は5.x) Kibanaは以前のバージョンではダッシュボードは黒をベースとしたUIでしたが、このバージョンは非常にカラフルなデザインになっております。

ちなみに余談ですが正しくは”ElasticSearch”ではなく”Elasticsearch”となります。ですがちょっと長いのでこのブログではESと略させていただきます。

データのフロー

ESはWEB-APIとして動作するのですが、Fluentdでプラグインが用意されているためそれを利用するケースが多いです。 直接POSTしても良いのですが、Fluentdを利用した方が簡単かつフレキシブルに使えます。流れとしては

Fluentd -> ES -> Kibana

となりますが、データをS3に保存する場合は以下のような流れが良さそうです。

Fluentd -> S3 -> Lambda -> ES -> Kibana

今回は前者の手順を記載いたします。

構築手順

1. AmazonESとKibanaのセットアップ

セットアップ自体は非常に簡単で、ものの数分で終わります。(作成の待ち時間がそれなりにありますが)AWSさまさまと言ったところです。

ESのダッシュボードでCreate a new domainをクリックします。 スクリーンショット 2017-06-15 18.36.03

Domain名とバージョンを指定しNextをクリックします。 スクリーンショット 2017-06-15 18.36.59

インスタンス数やスペックなどを指定しNextをクリックします。 スクリーンショット 2017-06-15 18.37.52

最後にアクセスポリシーを設定し、Confirm and createをクリックします。 スクリーンショット 2017-06-15 18.39.40

10分程度待てば作成が完了します。同時にKibanaも使える状態になっています。 スクリーンショット 2017-06-15 18.40.28

2. Fluentd設定

下準備としてはFluentdとfluent-plugin-aws-elasticsearch-serviceをインストールしている必要があります。送信先にESのURLを指定します。

3. ES設定

簡単な使い方をするのであれば設定は特に必要ありません。データがインサートされればそのまま使えるようになります。

4.Kibana設定

まずIndexの設定をする必要があります。ManagementでIndex Patternsをクリックします。 スクリーンショット 2017-06-20 12.40.21

Add Newをクリックします。 スクリーンショット 2017-06-20 12.41.07

作成したインデックスのパターンを入力し、Createをクリックします。 スクリーンショット 2017-06-21 11.58.45

登録したインデックスのデータは、Discoverから確認できます。この例ではscore_Xというランダム数値のデータを使用しています。 スクリーンショット 2017-06-21 11.56.59

次にインデックスからグラフを作成します。今回は折れ線グラフを作成しますので、VisualizeでLine chartを選択します。 スクリーンショット-2017-06-22-12.01.21

対象のインデックスを選択します。 スクリーンショット 2017-06-21 12.01.46

Y-Axisに対象のデータを登録し、X-AxisでDate Histogramを選択すれば時系列の折れ線グラフが出来ます。設定したらSaveをクリックします。 スクリーンショット 2017-06-21 12.23.32

あとはDashboardで作成したグラフを貼り付けます。KibanaはDashboardが自由にカスタマイズ出来、例えばWEBサーバのレイテンシを確認しながら生のログを見るといった使い方が出来ます。 スクリーンショット 2017-06-21 12.44.18

以上が構築手順になります。

最後に

弊社ではアドテクエンジニアを募集しております。広告技術に興味がある方・経験がある方のご応募をお待ちしております。また広告以外の部署やエンジニア以外の職種でも募集しておりますので、興味がある方はぜひご応募くだされば幸いです。

弊社コーポレートサイト
http://united.jp/recruit/information/

Wantedly
https://www.wantedly.com/companies/united/projects/

リフレクションでChrome Custom Tabsを起動する

Pocket

AdStir開発チームの吉田と申します。 SDK・JS開発をメインに担当しています。 本日はJavaのリフレクションで、AndroidのChrome Custom Tabsを呼び出してみたいと思います。

リフレクションとは

リフレクションは動的に、クラスやメソッド、フィールドにアクセスできる機能です。

  • ライブラリが同梱されている場合のみ実行する
  • プライベートなメソッドやフィールドにもアクセスできる

など柔軟な実装ができるようになります。

Chrome Custom Tabs

これまで、アプリからWebページを開く際には、暗黙的Intentを送信してChromeなどのブラウザを起動する方法が一般的でした。 Chrome Custom Tabsを使えば

  • ページ表示が高速化される
  • ブラウザの見た目をカスタムでき、自分のアプリの一部のような表現ができる

といったメリットを享受することができます。

AdStirでは、Chrome Custom Tabsを導入するかしないかを、パブリッシャー様に選択いただけるようにするため、この機能を使用しています。 Chrome Custom Tabsが導入されていれば使用する、されていなければ通常のブラウザを起動する。と言った具合です。

Chrome Custom Tabsの通常の使い方は以下となります。

とても簡単ですが、customtabsが入っていないとビルドすら通りません。 そこで、このコードをリフレクションを使って書き直してみます。

以上となります。 本当は例外処理や、CustomTabsIntentクラスが存在するかのチェックなども必要になりますが、概ねこのようにすることで、リフレクションでChrome Custom Tabsを起動することができます。

リフレクションには

  • メソッドの呼び出しが遅い
  • カプセル化を壊す
  • コードが冗長になる

などのデメリットも存在しますが、AdStirでは「モジュールが入っているときだけ利用できる」というリフレクションのメリットに注目し、今回のCustom Tabsや、メディエーション機能などを実現しています。

本日はこれまで。 どうもありがとうございました。

JARファイルからAARファイルとEclipseライブラリプロジェクトを作成する方法

Pocket

こんにちは。AdStir開発チームの森田と申します。
弊社SSP『AdStir』のSDKを開発しております。

はじめに

 AdStirのSDKでは他社のアドネットワークのSDKをバンドルして配布することがあります。弊社ではその際にメディアさんの利便性を向上するための工夫をしています。
 Android用のSDKは、ライブラリ(JARファイル)、リソースファイル、AndroidManifestがバラバラに配布されることがあります。 その場合、ユーザがJARファイルとリソースファイルをプロジェクトに組み込み、AndroidManifestをマージする必要があります。 AARファイルやEclipseライブラリプロジェクトを使用することでこれらの手間を省くことができます。 そのため一部のSDKをAARファイルやEclipseライブラリプロジェクトにパッケージ化して配布しています。
 今回はJARファイルからAARファイルとEclipseライブラリプロジェクトを作成する手順を紹介します。

JARファイルとは?

Java Archiveの略称で、Javaアプリケーション(Android)のライブラリの配布に使用することがあります。

AARファイルとは?

Android Archiveの略称で、Android Studioに使われるアーカイブです。 ライブラリに加えてリソースファイル・AndroidManifestを含めることができます。

Eclipseライブラリプロジェクトとは?

ライブラリとして使用できるEclipse用のプロジェクトです。 メインプロジェクトのライブラリに追加することで、ライブラリとリソースを追加できます。

AAR作成方法

Android Studioを使用してJARファイル・リソースファイル・AndroidManifestからAARファイルを作成します。

1. モジュールの作成

File -> New -> New Module -> Android Libraryでモジュールを作成します。 aar-01

aar-02

2. ファイルの追加

作成したモジュールにJARファイル・リソースファイル・AndroidManifestを追加します。 libsフォルダにjarファイルをresフォルダにリソースファイルを追加し、AndroidManifestを記載します。 aar-03

3. AARファイルの作成

作成したモジュールを選択して、Build -> Make Module ‘モジュール名’でAARを作成します。 aar-04

’モジュール名’ -> build -> outputs -> aar フォルダに AARファイルが生成されています。 aar-05

debug/releaseの両方のaarが必要な場合、appのbuild.gradleのdependenciesに下記を追加してMake Projectをします。

Eclipseライブラリプロジェクト作成方法

Eclipseを使用してJARファイル・リソースファイルからライブラリプロジェクトを作成します。

1. プロジェクトの作成

File -> New -> Android Application Projectでプロジェクトを作成します。 Mark this project as a libraryにチェックを入れ、Create Activityのチェックを外します。 eclipse-01 eclipse-02

2. ファイルの追加

作成したプロジェクトにJARファイルとリソースファイルを追加します。 libsフォルダにJARファイルをresフォルダにリソースファイルを追加します。フォルダがない場合は作成してください。 eclipse-03

3. ライブラリプロジェクトの作成

作成したプロジェクトを選択し、Export -> Java -> JAR file で以下の項目を選択を選択します。

  • res
  • libs
  • .classpath
  • .project
  • AndroidManifest
  • proguard-project.txt
  • project.properties

Export Jar source files and resourcesのみ選択し、Optionは全てチェック選択します。 エクスポート先を指定してFinishをクリックします。 eclipse-04

作成したjarを解凍してライブラリプロジェクト完成です。

まとめ

今回はJARファイルからAARファイル・Eclipseライブラリプロジェクトを作成する手順を紹介しました。1度作成すると簡単に取り扱えるようになるので、同じライブラリを色々なプロジェクトで使う場合ではオススメです。

AWS利用におけるIAMの設計

Pocket

こんにちは。配信/インフラチームの石田です。
現在DACから出向でユナイテッドでお世話になっております。
DACでも社内/サービス側両方のインフラ担当を担っております。

弊社では、AWSをDSP/SSPのサービスの基盤として利用しております。
また、AWSの利用者も、インフラチームや開発者、データ解析チームまで様々です。
「皆が同じルートアカンウトでログインし、全操作可能な状態」はセキュリティ的に問題があると考えております。

今回は、AWSのリソースアクセスコントロールを行い、セキュリティを向上する目的で導入したIAMの設計を紹介します。ルートアカウントでのAWSログインの廃止、CloudTrailでの操作ログ取得を実施するまでの過程を紹介します。

■IAMとは

IAMとは、Identity and Access Managementのことです。
ユーザーに対してAWSへのアクセスを安全に制御するための仕組みで、無料で導入できるのが魅力です。簡単に言うと、「AWSアカウントの中で、だれが何をできるかをコントロールするためのサービス」です。

■認証情報の種類

AWSにおける認証情報の種類としてはと下記の4つのクレデンシャルがあります。

  • AWSアカウントのパスワード
  • AWSアカウントのAPIキー
  • IAMユーザのパスワード
  • IAMユーザのAPIキー

■前提方針

前提条件としては、下記2つです。当然ですが、AWSルートカウントを利用しない方針でなければCloudTrailでの操作ログとして成立しません。

  • AWSルートアカウントはパスワードを変更し、利用しない。
    登録情報等の管理と請求関連操作にだけ使う。
  • AWSルートアカウントのAPIキーは利用しない。

■設計

今回弊社では、「管理者・開発者・運用者の役割を設け、開発者の自由度を考慮した設計案」を採用しました。基本的には、個人にポリシーを付与する形ではなく、グループにポリシーを付与する形式をとっております。また、ポリシーを個別に作成することも可能ですが、AWS側であらかじめ準備しているポリシーを利用します。

◉グループ
弊社では、AWS利用ユーザを3分類し、開発者の自由度を高く設計しております。

  • 管理者(Admin)
    →全サービス操作可能

  • 開発者(Developers)
    →IAM以外全サービスの操作可能

  • 運用者(Operators)
    →全サービスの参照のみ可能

◉ポリシー
今回は下記5つのポリシーを上記グループに付与する形で権限管理を行っております。

  • ”Administrator Access”
    →AWSアカウントに代わる強力な権限。全操作可能(既存)

  • ”Power User Access”
    →上記、Admin用からIAM操作権が省かれたポリシー(既存)

  • ”Read Only Access”
    →参照用ユーザ向けポリシー(既存)

  • ”ViewBilling”
    →請求情報参照用ポリシー(独自)

  • ”ChangePassword”
    →初回ログインPW変更可能ポリシー(独自)

◉グループとポリシーの関係
最終的なグループへの付与ポリシーは下記の通りです。

  • 管理者(Admin)
    ”Administrator Access”, ”ChangePassword”

  • 開発者(Developers)
    ”Power User Access”,”ChangePassword”

  • 運用者(Operators)
    ”Read Only Access”,”ChangePassword”,”ViewBilling”

■設定手順

–ユーザ作成編–

1)ルートアカウントでログインする。

2)IAMに移動し、ユーザを作成する。ユーザ名を入力し、「ユーザごとにアクセスキーを生成」にチェックを入れる。
iam-05

3)「認証情報をダウンロード」を選択し、アクセスキー、シークレットキーを保管する。

4)作成したユーザを選択し、認証情報タブを開き、「パスワードの管理」を選択する。
iam-06

5)初回ログイン時に必要になるユーザのパスワードを生成する。「自動作成パスワードの割り当て」を選択する。また、「次回のサインインで新しいパスワードを作成するようにユーザに求める」にチェックを入れる。
iam-07

6)「認証情報ダウンロード」から発行したパスワードを保管する。

–ポリシー作成編–

1)ルートアカウントでログインする。

2)アカウント>請求情報に対するIAMユーザアクセスの編集を選択する。
iam-01

3)請求情報に対するIAMユーザアクセスの「IAMアクセスのアクティブ化」にチェックする。
iam-02

4)IAMに移動し、ViewBillingポリシーの作成を行う。

5)ポリシーの作成>Policy Generatorを選択する。

6)アクセス許可の編集にて効果「許可」、AWSサービス「AWS Billing」、アクション「ViewAccount」「ViewBilling」にチェックを入れ, ステートメントを追加を選択する。
iam-03

7)ポリシードキュメントが作成されるので、「ポリシーの検証」を実行後、作成する。今回のポリシー名は「ViewBilling」とする。
iam-04

–グループ作成編–
1)ルートアカウントでログインする。

2)IAMに移動し、グループ>新しいグループの作成を選択する。

3)Admin には”Administrator Access”と”ChangePassword”を付与する。

4)Developersには”Power User Access”と”ChangePassword”を付与する。

5)Operatorsには”Read Only Access” と”ViewBilling”と”ChangePassword”を付与する。

–Cloud Trail編–
1)ルートアカウントでログインする。

2)Cloud Trailを選択する。
iam-07

3)証跡名、S3バケットを指定することでログ取得が可能になる。
iam-06

■まとめ

AWSのルートアカウントでのログインを行っている人もまだまだ、多いと思います。
例えば、退職者が発生する度にAWSのルートアカウントのパスワードを変更するといった運用を続けるのはどうなのでしょうか。 AWSといった責任共有モデルでは、個々のセキュリティレベルの意識によってセキュリティレベルも大きく変わってきます。 今回のIAMの導入は、ユーザ、グループ、ポリシーといったコアな機能のみで構成されており、既存のポリシーを生かしつつ、簡単に導入できます。

アドサーバの実装にGo言語を用いるメリット

Pocket

こんにちは。配信・インフラチームの川住です。

先日の記事にもありますが、最近、弊社DSP『Bypass』のRTB入札サーバはGo言語で実装されたものに完全にリプレイスされました。以前の入札サーバはLuaとC言語で実装されていましたが、規模の拡大に伴ってより大量のリクエストを高速に捌く必要が出てきたため、弊社SSP『AdStir』での開発・運用実績があり、Luaより処理が高速で、かつ比較的容易にHTTPサーバを実装できるGo言語へのリプレイスに至りました。

今回は、アドサーバの実装にGo言語を用いるメリットをいくつか紹介します。

リクエスト処理時のリソース消費がNginx+Luaの構成に比べて少ない

従来のLua実装では、ngx_luaモジュールを使用しており、Nginxの各プロセス内でLuaのプログラムを実行する形を取っていました。したがって、比較的大きなサイズのプロセスがforkされてしまうため、メモリ消費量が非常に多くなっていました。それに対して、Go言語を用いたサーバでは、プロセスをforkすることなくリクエストを並行して処理できるため、メモリ消費量がLua実装に比べて非常に少なく済んでいます。

強力なキャッシュモジュールの存在

RTBの入札サーバでは、大量のリクエストを高速に捌く必要があります。そのため、memcachedなどのKVSとの通信にかかるコスト (通信回数, データサイズ etc.) も考慮しなければなりません。Go言語には『go-cache』という強力なインメモリキャッシュのライブラリがあり、こちらを使用することで、KVSから取得したデータをプロセス内に保持でき、KVSとの通信コストを減らせます。Go言語のサーバ自体は1プロセスで動作しているため、キャッシュデータの共有も比較的容易に行えます。

以下にgo-cacheを用いたデータの取得と格納のコードを掲載します。

上記のように、Get関数とSet関数を用いて簡単にデータの取得や格納を行えます。データの格納時にはTTLも設定できます。しかし、go-cacheではデータの取得や格納を行う際にMutexを用いた排他制御を行っています。そのため、RTBの入札サーバのようにデータの読み書きが頻繁な環境で使用すると、go-cacheへのアクセス自体がボトルネックとなるため性能が低下してしまいます。このような環境では、go-cacheのインスタンスを複数生成しておき、キーによってシャーディングするなどして同一資源へのアクセスを分散させる必要があります。以下にシャーディング処理の一例を掲載します。

まとめ

Go言語を用いることで、高速に動作するアドサーバを比較的容易に実装できます。ただし、Go言語のサーバでは1プロセスで処理を行うため、共有資源の排他制御がボトルネックとなる可能性があり、その点を考慮しつつ実装する必要があります。

アドサーバ開発でのLuaの利用 連載(3)

Pocket

こんにちは。ユナイテッドの技術開発部で部長をしている伊良子です。

ユナイテッドでのアドサーバ開発では、Go, Lua, C言語(nginxモジュール)が主に使われる言語ですが、ここ1年ほどで急速にGoを利用するケースが増えています。新規でNginxのCモジュールを開発することはここ数年では皆無ですし、Luaで書かれているアドサーバをGoにリプレースするケースも出てきている状況です。最近ですと、数年前に私がLua+C言語で書いた弊社DSP『Bypass』のRTB入札サーバも、今ではGoに完全にリプレースされており、Luaが大好きだった私としては少々寂しいところです。 しかしながら、保守性の高さからLuaを選択するアドバンテージは高いですし、また速度面でも(弊社内でのベンチマークではありますが)シンプルな処理であるほどLuaが勝るケースが多いため、シンプルなAPIサーバなど、利用の用途はまだまだあると考えています。

今回は、Luaを利用する上で、便利なモジュールを幾つかご紹介したいと思います。

lsyslog

https://github.com/remakeelectric/lsyslog

Luaからsyslogを使うラッパーモジュールです。C言語でコンパイルされたモジュールなので高速に動作しますし、rsyslogの設定と連携することでカスタムされたログを安定的に出力することが可能です。設定も簡単です。

一例として、Luaのサンプルコードと、それに対応したrsyslogの設定を下記します。

rsyslog.confでは、テンプレート設定とルールを設定します。 この例の場合、時間ごとにファイルを切り替え、出力時間を先頭に付加した上で、プログラムから受け取った文字列を展開しています。

lua-cjson

http://www.kyne.com.au/~mark/software/lua-cjson.php

LuaからJSONを扱うモジュールです。C言語でコンパイルされているため非常に高速です。 アドサーバは直接データベースを参照するケースは稀で、memcached等のオンメモリデータを参照するケースが多いのですが、その際データをアドサーバに対して受け渡すのに手軽な方法がJSONです。弊社では他にもバイナリにするケースや、messagepackを用いるケースもありますが、手軽さと視認性の高さからJSONを使うことが最も多いです。JSONを採用する上で問題になるのがデコードにかかるコストなのですが、様々なモジュールや方法を試した結果、最も良好な速度だったのが、このlua-cjsonです。

サンプルコードは下記のような形になります。

まとめ

Luaは自分でC言語のモジュールを作ることが出来るので、Cのライブラリがあれば自分で高速なモジュールを作ることも可能です。弊社では、

  • hiredisライブラリを利用したRedis操作モジュール
  • libmemcachedを利用したmemcached操作モジュール
  • opensslライブラリを利用した、暗号/複合化モジュール

などで利用しています。 C言語と連携しないと複雑な処理を高速に実行することが難しいのがLua言語の特徴ですが、今回ご紹介したような鉄板モジュールが開発チーム内で定まっていれば、C言語を扱えないプログラマでも手軽にLuaでアドサーバを書くことが可能になります。

Hadoop / Spark Conference 2016 参加報告

Pocket

こんにちは。データサイエンスチームの西岡です。

先週月曜におこなわれたHadoop/Spark Conference Japan 2016に参加しましたので、 参加報告をさせていただきます。

聴講した発表は以下です。

  • 午前- 基調講演
  • 13:00- 次世代アーキテクチャから見たHadoop/Sparkの位置づけ (D会場)
  • 13:45- KuduによるHadoopのトランザクションアクセスと分析パフォーマンスのトレードオフ解消 (B会場)
  • 14:30- さくらインターネットが構築した、Apache Sparkによる原価計算システムの仕組みとその背景 (C会場)
  • 15:15- SparkによるGISデータを題材とした時系列データ処理 (D会場)
  • 16:00- Hive On Sparkを活用した高速データ分析 (D会場)

内容を簡単にまとめたスライドも公開しています。

全体を通して受けた印象を一言で言うと、「ますます進化・浸透していくHadoop」です。

開発開始当時(2004年頃)に一般的な構成だったCPU・メモリ・HDDを前提とした作りとなっていましたが、 今やストレージとして普及したSSDや、深層学習などの計算インテンシブなタスクに用いられるGPU・FPGAなど、 新しいハードウェアに対応できるようHadoopの開発を進めていくということでした。

しかしその一方、少数ノードで事足りる環境にはHadoopは不向きであるという指摘もあり、 Hadoopではカバーできない環境を補完するようなプロダクトの登場を予感させる発表もありました。

これからの分散データ処理がどうなっていくのか、1エンジニアとして注目していきたいと思います。

Redisにおけるデータの大量挿入手法

Pocket

こんにちは。Bypass開発チームの川住と申します。
今回はRedisにおけるデータの大量挿入手法について紹介します。

Redisとは?

まず、Redisについて少し紹介します。
Redisとは、メモリ上に Key-Value Store(KVS)を構築できるソフトウェアです(http://redis.io/)。
同系統のソフトウェアにはmemcached (http://memcached.org/) などがあります。
memcachedと比較すると、

  • シングルスレッドでクエリを処理する
  • データを永続化できる
  • ハッシュやリストなど、様々なデータ型を利用できる

といった特徴があります。

これらのソフトウェアを用いると、
メモリ上にデータを保持しており、かつ処理がシンプルであるため、
高速にデータの取得(格納)可能なKVSを構築できます。

データの大量挿入

本題に移ります。
Redisのデータの格納はとても高速ですが、シングルスレッドでクエリを処理するため、
データ数に比例して処理に時間がかかってしまいます。

そこで、大量のデータを挿入する時には、
「1件あたりのデータの挿入にかかる時間」をできるだけ短くする必要があります。

弊社では、Perlスクリプトでデータを加工し、Redisに大量のデータを格納しています。
この時、PerlのRedisモジュールを用いて1件ずつデータを格納してしまうと、

  • Redisとのデータの送受信で発生するRTT (Round-Trip Time)
  • Redisからのレスポンスをパースし、Perlのデータ型に加工する時間

が問題になります。そこで、

  • 複数のコマンドの一括送信
  • Redisからのレスポンスの破棄
    • socketやnc (netcat) でコマンドを送信し、レスポンスを/dev/null等に捨てる

を行い、処理時間を削減します。

処理時間の計測

下記の手法で10万件のデータの格納にかかった時間をそれぞれ計測しました。

  • PerlのRedisモジュールを使う(手法1)

  • socketを用いてデータを流し込む(手法2)

  • ncを用いてデータを流し込む(手法3)

計測結果

同端末で各手法5回ずつ試行し、その平均を処理時間としました。

手法 処理時間 (sec) ロス率
手法1 (module) 59.710145 0%
手法2 (socket) 2.978576 0%
手法3 (netcat) 2.626164 18%

複数のデータの格納コマンドを一括で送信し、
レスポンスのパースを行わないことによって処理時間を大幅に削減できます。
socketを用いる場合は送信(受信)バッファの管理を行わないと、
バッファ溢れによってデータロスが発生してしまいます。

まとめ

今回はRedisにおけるデータの大量insert手法を紹介しました。
目的に合わせて最適な手法を選択することでより効率的にデータを処理できるようになります。
(参考URL: http://redis.io/topics/mass-insert

基本統計量について社内勉強会で発表しました

Pocket

こんにちは。データサイエンティストチームの西岡です。

先日、統計入門ということで基本統計量について社内勉強会で発表しました。

「平均」は恐らく誰もがご存知の統計指標だと思いますが、 平均だけに頼っていてはデータの特徴が見えなくなることもあるよ、ということに伝えるために基本統計量について紹介しました。

基本統計量には大きく分けて

  • 代表値 (representative value)
  • 散布度 (dispersion)

の2種類があります。

代表値は平均値・中央値・最頻値など、文字通りデータを1つの値で示す指標であり、 散布度は分散・標準偏差など、データのバラつき具合を表す指標です。

代表値として平均値ではなく中央値や最頻値を使ったほうが適切な場合もありますし、散布度と合わせるとベターです。

平均値に騙されず、より正確にデータの特徴を掴んでいきましょう。

Pythonでテスト 連載(2) ユニットテストの書き方

Pocket

こんにちは。技術開発部データサイエンティストチームの西岡です。

前回の連載ではなぜユニットテストを書くのかについて述べました。
今回は実際にPythonのunittestモジュールを使用しながら、テストの書き方を説明しようと思います。

Pythonのユニットテストの話ではありますが、ユニットテストの思想自体は他言語でも通用するものでもありますし、Pythonの使用者以外の方も自身のよく使われる言語のユニットテストフレームワークと照らし合わせながら読んでいただければと思います。

なお、ここではPython3を使用しています。

テストケース

calc.pyはテスト対象のスクリプト、test_calc.pyはテストスクリプトです。

calc.py

tests/test_calc.py

ディレクトリ構造は以下のようであるとします。

test_calc.pyでは、calc.pyのadd_three関数にある入力を渡し、その出力が期待通りであるかをテストしています。 これをテストケースと呼びます。

unittestには

  • unittest.TestCaseクラスを継承したクラスにテストメソッドを記述
  • テストメソッドはtest_*で始める

というルールがありますが、これさえ守ればコマンドラインからテストを実行することができます。

この例ではもちろん5+3≠7なので、

上のようにテストが失敗します。 テストが通ったときは下のような表示になります。

テストフィクスチャ

ここで、Rectangleという長方形を表すクラスがあるとします。 Rectangleクラスには、

  • 長方形の幅・高さを取得するgetメソッド
  • 長方形の幅・高さを設定するsetメソッド
  • 長方形の面積を取得するareaメソッド

があり、インスタンスの使用が終わるとfinalizeメソッドで幅と高さをNoneにしなければならないものとします。

階層構造

rect.py

tests/test_rect.py

という感じになるかと思います。

しかし、これではrec = rect.Rectangle(5, 3)rec.finalize()を全テストメソッドで書かなければならず、非常に手間です。

unittestでは、このようなテストに伴って発生する初期化処理・終了処理をまとめるためにsetUp・tearDownメソッドを使用します。

tests/test_rect.py

これにより初期化・終了処理をまとめることができ、すっきりしたテストコードになります。

ただし、setUpとtearDownによってインスタンスの生成が1回にまとまったわけではないことに注意が必要です(以下の実行結果を参照)。

これはテストが以前におこなわれた何らかの実行に依存しないようにするためです。

テストの書き方

テスト対象の関数が複数のことをおこなう場合

テストの書き方は、テスト対象のコードにより大きく書き方が変わります。

以下の関数をどうテストすればよいかを考えてみましょう。

このcalc_average_bmi関数では、全員のBMIの平均を返します(BMIが何かについては、こちらのサイトを参照)。

この関数をテストする際に問題が起こりうる箇所は2つあります。

  • 返される平均の値が正しくないとき、BMI計算が間違っているのか平均計算が間違っているのか特定できない

  • 引数に空の配列が渡された時、平均計算においてZeroDivisionErrorになる

  • person.height == 0のときにBMI計算においてZeroDivisionErrorになる

下2つの「引数に空の配列が渡される」「身長が0である」といった例外はcatchすれば済みますが、そもそもcalc_average_bmi関数は

  • 平均計算
  • BMI計算

の2つのことをやっているため、関数自身はどんどん読みづらく、肥大化していきます。

そこで、BMI計算と平均計算を分離しましょう。

bmi.py

test_bmi.py

と分離すれば、bmi計算と平均計算は各々のメソッドで完結し、calc_average_bmiはほぼユニットテストを書く必要もないほど単純なコードになりました。

ここでは省きましたが、身長の単位がセンチメートルかメートルかもこのメソッドの中でテストすることができます。

メソッドに1つのことだけをさせるように変更すれば、テストもその1つのことだけを確認すればよくなるため、テストが非常に書きやすくなり、またテスト漏れも防ぐことができます。

プログラムをテスタブルにするため、テストが書きやすいようにプロダクションコードの設計から見直すことが重要です。

外部サービスのテスト

ここでいう外部サービスとは、データベースやWeb APIなどです。

git commit時のテストで毎回データベースを丸々スキャンするようなクエリを流すわけにもいきませんし、外部APIは(あまり無いかとは思いますが)落ちている可能性もあるので、外部サービスとの連携テストにはモックオブジェクトを使用するのが一般的です。

今回はモックを使用したテストについては述べませんが、いずれ取り上げてみたいと思います。

まとめ

テスタブルなコードを書くことでバグを減らし、より高速な開発をおこなっていきましょう。