オイシックスの基盤刷新

普川泰如氏(以下、普川):オイシックスドット大地の普川です。よろしくお願いいたします。

今日はちょうど吉健さんからあったようなデータ分析の話があったんですけど、弊社もここ半年ぐらいで変えてきたので、それの振り返りをまとめて持ってきたのと。あと、一番最近やったデータ分析の事例をご紹介できたらなと思っています。

一応簡単に自分の紹介なんですが、オイシックスで社歴も長くて9年ぐらい、もともとWebエンジニアで入っていて、マネージャーをしながら今はデータ分析もやっています。

あと、個人的にわりと食べるの好きでオイシックスという会社に入ったんですけれども、いまはヘルスケアもなかなかおもしろいなと思っていて。

これはぜんぜん仕事と関係ない自分の個人ワークなんですけど、Fitbitという活動量計が自分の中では熱くて。あれは外にデータを出せるので、自分の睡眠データや行動データから今日のパフォーマンスはどのぐらいなのかをSlackに通知するというのを作っているのが、最近はおもしろいです。すいません、小話です。

本題ですが、一応アジェンダは、簡単に会社の説明をさせていただきたいのと、さっき言った基盤刷新の部分の話とデータ分析事例となっています。あと、事例紹介の時に会社のサービスの内容を理解していただくとわかりやすいので、ちょっとだけ会社の紹介をさせてください。

オイシックスのビジネス

オイシックスドット大地は、基本的にECサイトで安心安全な食材を売っていますが、基本的には、生産者の方と直接つながって、消費者の方と生産者と両方の顔を見ながら商売をしているというところで、日本の食と農をビジネスで解決しようということでやっています。

去年「オイシックス」と「大地を守る会」さんで統合して、いまは「オイシックスドット大地」になっていますが、さらに「らでぃっしゅぼーや」さんともくっついたので、本当はここ3つにしたかったですが、もうちょっとあとで統合なのでそのへんはまだないですという感じです(注:2018年8月現在、オイシックス・ラ・大地(株)に統合済み)。

会社の規模感的には、これは2016年のデータで恐縮ですが、350〜400億ぐらいの売上をあげているかたちです。

ここのところがビジネスモデルで、あとで中でも出てくるのでご紹介なんですけれども。基本的にはWebやアプリで来店していただいて注文すると。注文を受けてから発注をして、農家さんが収穫して、それを配送センターに入れて、発送して、受け取ってというふうなところですね。

オイシックスは、いまはスマホとアプリで展開しているんですけど、どんどんアプリにお客さんが寄っているところが特徴的なのと、「これだけで1日のごはんが全部できてしまうよ」というカット済みの食材とレシピ付きの、いわゆる「Kit Oisix」のお客さんがすごく多く増えています。

大地を守る会は、オイシックスよりももっと生産者の方に寄り添ったというところでブランドを分けています。

データの規模感は後々の説明でわかると思うので、先にご紹介しておきますが、基本的にOisixは食材の宅配でサブスクリプションコマースという部分で、だいたい月2回ぐらい注文をしていただいていて、定期会員は16万人です。

あと、一応スーパーなのでお肉も野菜もお魚も全部買えるので、1回あたりの商品点数が18点とか20点という平均値が出ています。わりと1個の商品を買って購入するということより、購買系の情報が豊富に取れるのが特徴です。

データ刷新を行った理由

データ刷新のところなんですが、まず、そもそもどういった問題意識だったのかという部分なんですが、長年いろいろなデータベースを新しく足したりその中を変えたりしていって、結果、たびたびダウンを起こしてしまったり、データ容量的に「ここもうしんどいね」とかあったりします。

一方で、ビジネス的には「詳細な情報が欲しいです」とか「もっと大量のデータをぐんぐん回して分析したいです」みたいなニーズがけっこうあって、この相反する両方をどうにかして実現できないかということをけっこう考えていました。

一応そこをカテゴリというか、分類して細かく説明すると、けっこうデータの連携のところでは、基幹DBから分析DBへの連携がたびたび止まってしまっていて。「毎週木曜日にレポートを出しましょう」みたいなことが社内では大事だったりするんですが、それが遅れたり間違ったデータになったりみたいなことがあったり、その対応で「けっこう工数かかっちゃってるね」みたいなことが起きていました。

あと、データの連携のつなぎ込みも属人的というか、スクリプトに書いてみたいなことがちょっと前まであって、そのへんで毎回工数かかっています。

あと、わりと全部を一元して俯瞰して見れるようにできていなかったので、TDのスケジューラーはけっこう便利でどんどん使っていたんですが、「結局、なにがいつどこで起きているんだっけ?」みたいなことが自分たちでよくわからないみたいな状況が起きていました。

基盤の構成部分でいうと、DBをいくつか使っているんですが、役割定義が曖昧になって、とくに中心となる分析のDBの役割が肥大化してしまっているみたいなことが起きるとか。あとは、分析DBにアドホックなクエリを投げたときに、それが普通にバッチで動いているクエリに影響を与えちゃうとか。

あとは、DWH的なテーブルの最適化が若干できていなくて、そのへんであとあと分析するクエリが大変になってしまうということが起きていました。

一応、これはbefore/afterのbeforeなんですが、こんな構造でした。簡単に説明すると、WebとかそれからコアDBにデータが入ります。線が埋もれちゃってるんですけど。あとは行動データを直接Treasure Dataに入れてました。

それからDBMotoという製品を介してMySQLで分析データを入れてたんですけど、それと別でレコメンドだけは別のMySQLを立てて分析していたり、さらに一部はTreasure Data側で分析しているみたいなことが起きていて。

基盤刷新における要件

問題点は、まずここのデータ連携がけっこう落ちてしまっている部分。あと、この人を中心的に作ってたんですけど、この人のDWHの設計がイマイチというところと。あと、分析用のDBをいくつも作っちゃった結果、「どこでどれをやっているんだっけ?」「どこにどのデータがあるんだっけ?」みたいなことがけっこう起きてしまいました。

というわけで、基盤刷新をしましょうとなった時の要件としては、だいたいこんな形になりました。

データ連携の部分は、当然安定性という部分と、ワークフローで一元管理して「なにがいつ動くんだっけ?」みたいなことをちゃんと見えるようにしましょうというところ。

基盤構成は全体的に、保存する場所とデータを変換する場所と活用する場所はちゃんと意識して分けましょうというのと。あと、さっき言ったやつですけど、アドホックな分析は自由にできるんだけど、「ちゃんと定常的なバッチが安定して流れるよね」みたいな状態を作るというのと。

あとDWHのテーブルをちゃんと見直して、ファクトテーブルをちゃんと一元化。いわゆるスタースキーマとか呼ばれるようなことを意識してもう1回設計し直すということをしています。

刷新はこういう感じです。本当はもうちょっといくつかあるんですけども、わかりやすさのためにシンプルな部分だけ抜き出してきています。

基本的に、さっきも言ったとおり、収集する役割とデータを分析する役割とデータの利用をきっちり分けて意識した上で使いましょうというところです。

データ連携の仕組み

データの連携の部分から説明すると、DB間のデータ連携はAWSのDMSとEmbulkで統一していて。いろいろやった結果、弊社では、フル同期はDMSがいいんだけど、差分の同期はEmbulkがいいねというようなかたちになって、いまのところ安定するようになりました。

あとDigdagの導入がけっこうよかったなです。懸案だったデータの移動や同期の見える化ができた部分と、その前はLuigiを使っていたんですが、それだと記述がPythonでインフラのみなさんはとっつきづらい感じだったので、yamlになってやりやすくなりました。あとはEmbulkとDigdagのつなぎ込みは当然とてもすばらしいという感じです。

TDのイベントなのでお願いをすると、Digdagの最初の管理画面がもうちょっとダッシュボード的なUIになるとすごくいいなということだけひとこと言っておきたいです。でも、概ねDigdagとEmbulkがすばらしいなと思っています。

基板設計における特徴

基盤設計の部分は、先ほども言ったとおり3層構造に分けたということと、一次集計をデータのプラットフォーム化というのがあって。これは切り口別で「顧客」や「商品」「顧客×商品」など、分析したデータを各所に簡単に配れるようにするという感じです。

いままでは先ほどの図だと、分析場所が分散していたので、なにかあったときに、それぞれにつなぐみたいなことが発生してたんですが、今回Auroraにそこを集約しました。

例えば、顧客のレコメンド情報をここで作り出して、「このお客さんにはこの商品をおすすめしよう」みたいなときに、その情報はまず、DomoというBIツールに使っているんですが、そこで施策を打つ企画側の人がちゃんと見れるようにできています。

プッシュ配信はそのデータをもとにできて、かつ、その情報をもってプッシュされたデータを見てWebやアプリに来たお客さんがちゃんとそこで出し分けがなされて。このお客さんにそれをリコメンドするということが行われます。

以前は毎回それぞれつなぎこんでデータも作っていましたが、もいまは一元化でローデータから一次加工したものを全部作っておいて、それを配布することができるようになりました。ほかの施策での使い回しも簡単にできるようになった部分です。

DWHのテーブル設計も変えました。簡単に説明すると、まず、更新が前まで2時間ごと更新だったのをなんとか1時間ごと更新にまで持ってこれました。

やったこととしては、毎回主要なテーブルも全部Delete、Insertだったのを差分更新に変えました。あと、集計するエリアとデータを保管するエリアを分けてtruncateとかをサクサクできるようにしました。

そこのデータを集計するクエリもわりと複雑だったので整理をしたんですけど。とくに意識したこととしては、週の集計と時間の集計、あとは日の集計もあるんですが、それぞれの役割をきれいに整理することで、1時間あたりの更新のときはそんなに全部を更新しなくていいよね、みたいなことをしました。

あと、テーブルを1回InsertしたあとにUpdateしまくってDWHのテーブル作っていたんですが、それだとUpdateの本数もすごいし、あとから見たときに「で、結局どうなってんだっけ?」みたいになっちゃうので、1回中間テーブルで吐き出してInsertするみたいな方向に変えています。

また、分析のクエリを書きやすくできるようにしました。行動データや購買データとか、いくつかキーとなるテーブルが1テーブルに落ちていなかったので、そこは集約して。ファクトのデータ、プラス、なにかセグメントを切るなりするというデータのジョインに絞れるようにしました。

課題感としては、まだ全部Digdagで管理できていなかったりするので、そのへんは地道にやっていく必要があるなという感じで。期間的にも構想段階から半年ぐらいかけているので、やっぱり時間がかかるなということを学びました。

分析事例

分析事例を2つだけ簡単にご紹介させていただきます。

まず、SMSの配信時間の最適化を行ないました。課題としては、Oisixの特徴として「定期ボックス」というものをお客様に毎週週1回作ってお渡しするんですけれども、普通のECと違うのは、普通は自分でカートに商品入れて注文完了ってやるんですけど、Oisixの場合は、1回Oisixのおすすめの商品を定期ボックスというものに入れてお客様に公開します。注文がなければもうそのまま届けちゃいますとしています。

なので、リピートするという観点ではすごい良いんですけれども、そのまま届いちゃう場合、自分でそうしたいというお客様はいいんですけど、「いや、変えたかったのにそのまま届いちゃう……」みたいな感じだと、即解約されてしまうことが多くて、そのリマインドはかなりやっています。

それで、今回は時間を最適化しました。訪問者数でいうと10パーセントぐらいアップができたので、そこの簡単な説明をします。

基本、今週の提案があって、出し入れ、変更や削除は自由なんですが、締切が来てしまうとそのまま届きます。すうると解約率が3倍まで増えてしまうので、ここについてはリマインドを、2日前・前日と、締切の2時間前・締切後というところで配信しています。

配信も、SMS以外にLINEやプッシュ通知もやっているんですけども、今回はSMSが一番反応がよかったので、さらにそれをよくできないかというところと。

あとは時間です。お客さんの行動を見てると、最初は夜の7時半にしか送っていなかったんですけど、いまは日中もパラパラ来てるので、そのへんちゃんとお客さんが来る時間を捉えて送れないかということを考えていました。

やったことと振り返りとしては、基盤刷新をしたおかげで、分析した結果をSMSで配信するというつなぎ込みもけっこうスムーズで、企画してから2週間ぐらいでできました。

あとは、最初1時間おきに10パターンぐらいで最適化してたんですけど、いろいろやったら4パターンぐらいでよかったので、そこも管理がしやすくなってよかった部分です。

でもやってる内容としては、Webの訪問時間をお客さんごとに捉えて「その人はこの時間がよさそう」とやっているんですけど、この予測の精度アップはまだ余地がありそうです。

あと、お客さんが反応しがちなチャネルがあるってことはわかっているんですけれども、そこまではまだいけてないので、次回はそこも意識してやりたいなと思っています。という事例です。

Kit Oisixの注文数を予測する

もう1個成功事例としてよかったのが、オイシックスで主力商品となりつつあるKit OisixというミールKitの注文数予測です。

これは自社で製造しているんですが、Oisixは注文した翌日に出荷、2日後にお客さんに届きますって感じなんですが、注文を締め切った段階から作り始めてるとぜんぜん間に合わないので、だいだい締切の24時間前から作り始めます。

製造のラインの都合上、作り始めるタイミングに作る数をFIXしないと作れないという制約がありまして。もともとは、最初から作り始めてはいるんだけど、時間を締め切ってFIXした段階で残りをもう1回ちょっとだけ作るみたいなことをやっていました。

この製造のラインがあって、別のkit商品に切り替えるみたいなことがけっこうオーバーヘッドで、「そこの時間があるから、ちゃんと24時間前に注文数を決めて作らないといけません」というのが製造側からの要望としてあったので、その最適化を行ないました。

使用したデータとしては、購買データを当週分と過去分を使っていて。ざっくり月100万弱ぐらいのインパクトと書いているんですけど、それぐらいの精度が出ているという感じです。精度アップという観点では、最初は担当者が勘で予測してた時と比べると10パーセント程度よくなっています。

ここも振り返りを行なうと、当初Kit Oisixの商品属性や売り場など、そうした情報を説明変数にして「じゃあ何個出るね」みたいなことにしてたんですけど、もっとシンプルなロジックにしたことで一気に精度も上がってリリースができました。

具体的には、そうした商品属性からの予測はやめて、わりと注文開始時間からの時間の推移と販売数の単回帰みたいな部分と。あとはRandomForestを使って過去の同時間帯の数量の予測と合わせたもので係数かけて出すみたいなかたちにしたんですけど、それがわりとよかったです。

難しいロジックを作ってしまった場合、なにかあったときのチューニングが大変になってしまいますが、これだとわかりやすいので、あとでなにかあった時にも追いやすいのもよかった点です。

ですが、課題としてはやっぱり運用メンテコストが想定よりもありました。具体的には、やっぱり製造現場って、365日動いていて、システム止まると、「製造数何個かわかりません」みたいな状況になってしまいます。でも予測するタイミングは、そうはいってもギリギリまで引っ張ったほうが、時間の推移で予測しているので精度は上がるというトレードオフがあって。

予測するタイミングをギリギリまで引っ張っているので、止まったときにすぐに復帰しなきゃいけない部分がけっこうあったので、そこが最初のタイミングで想定できていなかったのでわりとコストに跳ねている部分がありました。

あとは、やはりお正月やお盆は特異な動きをするんですが、データが年に1回しかたまらないのでそこはわりとしんどくて、ここはいまでも人力に頼ってしまっています。

分析において気をつけるべきこと

というわけで、けっこう分析をいくつかやってた時の「こういうパターンはけっこう気をつけたほうがいいぞ」というポイントをご紹介しておくと、分析者の業務理解度が高いというのはけっこう大事です。

まず、課題があって「じゃあここでなにか予測しましょう」みたいな部分をしたときに、「その数字がなんなんでしたっけ?」みたいな意味合いを出すのを、業務担当の人と一緒にやると、週1回のミーティングで「じゃあやって」「次チューニングしてきて」「また次で……」みたいな感じでやると、けっこう遅くなってしまいます。分析者がそこもを把握できるとPDCAを回すのが速いですという感じはありました。

あと、「どんなデータを使用したらいいんでしたっけ?」とか「このセグメントのほうが絶対効くから、こっち」とか、もうデータの使う部分とかの絞り込みが一気に進んでチューニングできる範囲がけっこう狭くなるので、その部分はいいかなという部分もありつつ。業務担当者との関係性づくりも、社内で進めていたときは大事で、そこがあると一気に進みます。

弊社の場合データがそんなにない場合もまだまだあるので、そこがないとスタートが遅くなるなみたいなのと。データの安定性は大事です。

先ほどの需要予測の例でも、結局1時間ごとに何個売れたかみたいなデータを集計してたんですけど、その部分はそれまではなかったので「じゃあどういうふうにデータ取ろうか?」みたいなところから設計したので、わりとその部分で時間がかかっているというのがあります。

あと、施策への落としやすさは大事です。需要予測は単純に出た数字で「じゃあ製造しましょう」になるからけっこう実行に落としやすいんですけど、「お客さん側にレコメンドします」とか「どういう施策にします」みたいな部分だと、Webのページやアプリで機能を作り込むみたいなのが発生すると、やっぱりその部分で時間がかかったり。

そんなにそのページなり売り場なりが見られていないから、そもそもすごい質の高い提案をしても、思ったよりも動かないみたいな。分析の精度とは別の部分で影響が及ぼせないとやっぱりしんどいなという部分があったというところです。

持ってきた資料としては今回はこれぐらいなんですけども。今後の我々のやりたいことというと、オイシックスの場合、農家さんから繋がっていて、配送も自分たちで全部やっているので、そのへんの業務改善におけるデータ分析もわりとやりたいなと思っています。

いまはWeb周り・アプリの分析がメインなんですけど、どれぐらいの数量かの予測とか、配送周りで最適化できないかとか、あと倉庫内の動き方の予測とかをけっこうしていきたいなと思っています。

ということで、ご清聴ありがとうございました。

(会場拍手)

メンテナンス性について

司会者:普川様、ありがとうございました。質疑応答のお時間とさせていただきます。会場からご質問あれば、挙手いただけたらと思いますが、いかがでしょうか?

質問者:すいません。おもしろいお話ありがとうございました。途中の図とか聞き逃したのかもしれないんですけど。3層のところ……、これですね。需要予測とかは、TreasureでいうとHivemallがあったりすると思いますけど、それで行なわれている感じなんですかね?

あと、メンテナンス性が大幅にアップというお話があったと思うんですけど、もしそこらへんもHivemallとかでやっているのであれば、ジョブとして組んでおけば自動化できそうな気がしているんですけど。そのあたりどういうところがメンテナンス性が上がったのかをおうかがいしたいです。

普川:まず需要予測の場所としては、データはTreasure Dataにいったん入れて。やり方としては、Hivemallはまず使ってません。ほかのやつで1回使ったことがあるんですけど、今回に関してはPythonで基本的なコードは組み、データはここに入れて、Pythonからクエリをこっちで回す。あと一部データをPython側に持ってきてやっていますという感じですね。

需要予測の部分ではまだあまり褒められたほどのメンテナンス性は上がっていないんですけど、繰り返しになってしまいますがメンテナンス性が上がった部分としては、まずここのつなぎ込みのデータがこのへんのDigdagとかEmbulkを入れてからは落ちなくなっているので、そこのエンジニアのコストは、あんまり工数かからなくなったよという話と。

あと、さっきも言ったんですけど、ここの1回分析したデータから全部、もう「ここからここにする」という連携の線を決めてしまうことで、「ここで作ったこのテーブルはもうこっち連携するよ」という決めごとを作っておいて、あとは決まった流れでデータが一気にここに動いていくので、そこらへんがメンテナンスコストが下がりました。

前は、1個新しく増やしたら「じゃあここに対して、ここに対して」ってスクリプトを書いてちまちま連携してたので、そこの部分はけっこうよくなっていますね。

質問者:わかりました。ありがとうございました。