AWS Lambda上で鯖(Mackerel)の曖昧性問題を機械学習で解決しよう

この記事は、はてなエンジニア Advent Calendar 2017の1日目の記事です。

サービスに関連する言及のみを観測したい

こんにちは。Mackerelチームでアプリケーションエンジニアをやっているid:syou6162です。サービスを運営していると、サービスに関するtweetをslackに流して定期的に観測しているといった方は多いと思います。観測するモチベーションは様々ですが

  • サービスの不具合に一早く気が付ける
    • もちろんテストや動作確認はやっているのが前提だと思いますが、それでも気づけないものも出てきます
  • 新しい機能を出した際にユーザーの反応が直に見れるため、開発者としてはモチベーションが上がる
    • 問い合わせまではないが、どういう機能要望などがあるか知ることができる

などが挙げられると思います。

問題点

Mackerelチームでもサービスに関するtweetを定期的に観測しています。余談ですが、Mackerelはサーバー(鯖)の監視/管理のサービスで、鯖の英語からMackerelというサービス名になっています。この名前ゆえに「サービスに関連するtweetのみ」を観測するというのが難しくなっています。

  • 魚の鯖に関するtweetが混じる
    • slackのチャンネルが鯖の飯テロ状態になるときがある
    • 最近だとローソンの燻製さばサンドが人気で困ります
      • 当然ながら燻製さばサンドに罪はありません
  • mackerelは多様な連語がある
    • mackerel skyやholy mackerelなど

少し脱線しますが、このエントリの内容を社内の技術勉強会で紹介したところ、イカリングにもいくつかの曖昧性があることを教えてもらいました。こういった曖昧性はサービスに特有の問題ですが、それ以外にも以下のような問題があります。こちらは他のサービス運営者で困っている方も多いのではないでしょうか。

  • ユーザー名にサービス名が入っている方のtweetが混じる
  • meetupなどのイベントが盛り上がりトレンドに入ると、公式のハッシュタグに関係ない内容を混ぜてくるspammerに遭遇する場合がある

以上のようなサービスに関連しないtweetを除外するために、これまではfluentdのfilterに正規表現を頑張って書いていました。しかし、ルールの整備は大変で段々と古びていきます。また、fluentdの障害とサービスの障害の時間が被ると、障害時のユーザーの反応が分からないといった問題点もあります。

解決方法

こういった背景から、サーバーレス(AWS Lambda)で機械学習を使ってMackerelのサービスに関連するtweetのみをSlackに定期的に流すコードを書きました。

sabaとついていますが、検索クエリと教師データ(自分の場合は秋の夜長に600件ほどアノテーションしました)を変えてあげれば他のものでも動くと思います。AWS Lambda上で動作するため、サーバーを用意する必要なく簡単に始められますし、fluentdが万が一障害の場合も問題なく動きます。

工夫点

tweetのjsonから特徴量を作り、平均化パーセプトロンで分類しているだけなので、機械学習的な面白みはほとんどありません。しかし、AWS Lambdaで動作させるための工夫が多少あるので、紹介します。

軽量な形態素解析器を使う

自然言語処理といえば最近ではPython一色になりつつあります。はてなでも機械学習関連のプロジェクトではPythonを使うことが増えてきています。日本語を扱う自然言語処理ではMeCabを扱うことが多いですが、Lambda上でMeCabを動かすのは一手間必要なようです。

サイドプロジェクトでやろうと思ったため、もっと手間をかけずお手軽にやろうということもあり、PythonではなくGo言語を使うことにしました。Go言語での形態素解析器ではkagomeがあり、apexを使うとkagomeも含んだシングルバイナリでAWS Lambdaまで送り込めるので便利です。これで一件落着かと思いきや、AWS Lambdaにはアップロードできるパッケージのサイズ制限(50Mb)があり、kagomeを含めてビルドしたバイナリは56Mbで少し足が出てしましました。どうしたものか困っていたところ、kagomeの作者の@ikawahaさんにIPADicのみのコンパクトなバージョンがあることを教えていただきました(kagomeのAWS Lambdaでの実績解除:tada:)。

こちらを使うとバイナリのサイズが20Mb程度まで小さくなったため、AWS Lambdaへのデプロイも問題なくできました。高精度に動くリッチなモデルに注意が行きがちですが、高速に動く/消費リソースが少ないモデルも実世界では重要ですね。

軽量かつシンプルな分類器を使う

はてな社内でも深層学習の手法であるCNNやLSTMをベースにした分類手法の実験を行なっています。今回の用途の場合、深層学習を用いると学習後のモデルサイズが大きくなりがちという問題点があります(もちろん、パラメータをスパースにしてモデルをコンパクトにするという研究も多数行なわれています)。今回は古典的な教師あり学習の方法の一つである平均化パーセプトロンを用いました。自前でtweetを600件ほどアノテーションを行ない交差検定で実験した結果、十分な精度が出ていると判断したためこれ以上複雑な方法を取るのはやめました(関連エントリ)。

学習した重みベクトルはgo-bindataを使ってGoのコードに変換します。Goのコードに変換できればシングルバイナリにしやすいので、deployが簡単です。deployはapexを使ってapex deployで簡単にdeployできます。

AWS Lambda上での動作の監視を行なう

Mackerelチームに所属しているので完全に宣伝ですが、MackerelではAWSインテグレーションによりLambdaのメトリックを取得したり、それを元に監視/アラートの通知といったことが簡単にできます。是非使ってみてください!

おわりに

SNS上での自社サービスの言及を必要なものだけにフィルタリングして継続的に観察する仕組みについて簡単に紹介しました。細かいところではありますが、ユーザーの声を取り込みつつサービスをよりいいものにしていきたいですね。

明日のアドベントカレンダーはid:y_uukiさんです!