LIVESENSE Data Analytics Blog

リブセンスのデータ分析、機械学習、分析基盤に関する取り組みをご紹介するブログです。

LivesenseDataAnalyticsBlog

MENU

分析基盤のバッチ処理構成を考える

データプラットフォームチームの橋本です。 日頃は分析基盤LivesenseAnalytics(LA)の保守・運用を担当しているエンジニアです。最近は専ら、バッチ処理のリファクタリングを懇々と進めていました。今回はその内容をまとめてみます。

分析基盤のバッチ処理

LAのバッチ処理基盤についてはこのへんを見ていただくとして、私が着手しているのはその中でもairflow-workerと呼称しているバッチ処理の集まりになります。その昔、Airflow導入以前に、cronでバッチ処理を運用していた頃から使い続けているrakeタスクの集まりで、類似の分析基盤を保守しているプロジェクトではよくある感じのバッチ処理集になっています。AirflowはDAGで設定された定時、ないしは任意のタイミング(ユーザーからのキック)で、airflow-workerのrakeタスクを起動します。この時、起動されるrakeタスクのIOは、概ね以下のようになります。

f:id:livesense-analytics:20180611112817p:plain

ところで、このairflow-worker。かつて、cronで運用されていた時代から引き継いだタスクの集まりで、チーム内では追加・修正の頻度が最も多いコードの1つなのですが、その分歴史と修正の積み重ねも厚く、多くの問題を抱えるようになっていました。具体的には、

  • 処理がrake直書きになっていて、テストが書けない
  • コンポーネントの配置やディレクトリ構造、命名に一貫性がなく、見通しが悪い
    • コードリーディングで繰り返される grep -r
    • 違う名前で機能が重複する実装
  • DRYじゃない・繰り返されるコード
    • task_env = ENV["task_env"] || "development"
    • エラーハンドリングと通知
  • dryrunできない・実装を逐一書かねばならない

などなどです。もともと素朴な定時処理から始まっているコードであるがゆえ、リリースの即時性に重きをおいて運用してきたため無理もないのですが、このまま可読性・保守性を犠牲にして拡張を続けると、

  • 新規参入エンジニアの立ち上がりコスト増加・属人化
  • 拡張コストの増加
  • バグの温床化

といったデメリットが考えられたので、思い切って大規模なリファクタリングを敢行しました。

リファクタリングの方針と改善のポイント

まず次の2点を大まかな方針としました。

  • 細かい問題点はたくさんあるが、大きな問題を優先して期間内に終わらせる
  • 理想形には近づけるが、完璧にしない

リファクタリングの作業自体は重要な仕事ですが、理想形を目指し続けると際限がないので、とにかく大きな問題点をザックリ改善し、今後の継続的なコード改善への足がかりにする方針としました。 上記のIOの図の通り、定時のバッチ処理は概ね

  • 日時やタスク名、スキーマ名などのパラメータを受けてタスクがキックされる
  • テンプレートからクエリを発行したり、日付の範囲をとったAPIに投げるパラメータを作る
  • 実際に処理を行うマネージドサービスのAPIを呼び出す、あるいはクエリを投入する

の3ステップで構成されています。そこで、バッチ処理のコンポーネントを図のように3つに分割しました。

f:id:livesense-analytics:20180611124506p:plain

改善のポイントは

  • コンポーネントの構成を整理
  • rakeタスクの処理を別のクラスへ委譲:rakeタスクとLATaskクラス
    • バッチ処理のインターフェースとロジックを分離する
    • ロジックに対してユニットテストを導入する余地を作る
  • APIアクセスをFacadeにまとめる
    • 可能な限りAPIアクセスをdryrunできるようにする
  • 分割しにくい部分や広域なスコープで共通化された処理等は、思い切ってUtilsとして切り出す

としました。以下、その内容をもう少し具体的に見ていきます。

クラスとパッケージの構成

f:id:livesense-analytics:20180530163538p:plain

クラス構成はザックリ上記の様な感じにしました。モジュールは大きく4つに分けて、以下の構成にしました。

  • API
    • API呼び出しを行うFacadeのモジュール
    • dryrunの機能をここに集約する
    • このパッケージのクラスは状態を保持しないようにする
  • LATask
    • 処理の実装を持つクラスのモジュール
    • 親クラスにエラーハンドリングやロギング、環境変数の参照などを集約する
  • rakeタスク
    • rakeタスクは各々のタスクに対応するLATaskクラスへ処理を委譲する
    • LATaskのインスタンスを呼び出し、パラメータを渡して処理を実行するだけ
  • Utils
    • バッチ処理全体で頻発する処理や、分割しきれなかった塊をとりあえず置いておくモジュール
    • 状態を保持しない、関数の集まりにしておく

以下、rakeタスクからの処理フローを、サンプルのソースコード上で追いかけてみます。

rakeタスク

require 'la_tasks/foo/foo_task'

namespace :foo do
  desc 'Foo関連のタスク'
  task :foo_task, %i(schema table column) do |task, args|
    LATask::Foo::FooTask.new(task).foo_task(
      args[:schema],
      args[:table],
      args[:column]
    )   
  end 
end

rakeタスク上では引数のチェックすらせず、LATaskクラスに処理を丸投げします。この様にrakeタスクの名前と実装を切り離しておくと、後から実装の差し替えや改名等がしやすくなります。

LATaskクラス

LATask - 親クラス

require 'path/to/messenger'

module LATask
  class Base
    def initialize(task_name)
      @messenger = Messenger.new
      @task_env = ENV['TASK_ENV'] || 'development'
      fail "Wrong TASK_ENV: #{@task_env}" unless ['production', 'development'].include? @task_env
      @task_name = "#{task_name}:#{@task_env}"
    end
        
    protected
        
    def exec
        notify("Task Start - #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}")
        yield
        notify("Task End - #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}")
      rescue => e 
        error_action(e)
        @messenger.alert("#{@task_name}: #{e}", e)
    end
        
    def error_action(e)
      # 何かあればoverrideして使う
    end 
        
    def alert(message, e)
      @messenger.alert("#{@task_name}: #{message}", e)
    end
  end
end

LATaskクラスの親クラスには、ロギングやエラーハンドリング、通知、環境変数チェック等、全タスク共通で頻発する処理をシンプルにまとめておきました。これにより、子クラスの実装がかなりスッキリしました。

LATask - 子クラス

require 'api/aws/sqs'

class LATask::Foo::FooTask < LATask::Base
  def initialize(task_name)
    super(task_name)
    @sqs = API::AWS::SQS.new
  end

   def foo_task(schema, table, column)
    exec do
      # ここに処理本体を記述
      alert("task_env is #{@task_env}")
      @sqs.send_msg(@task_name)
    end
  end

  def bar_task
    exec do
      # ここに処理本体を記述
    end
  end

  private

  def private_func
    # このタスク限定の処理など
  end
end

LATaskの子クラスに、タスクの実装を書きます。この時、execに渡すプロック内で全てのタスクの処理を記述することにより、ロギング、エラーハンドリングを親クラスの実装に一元化できます。パラメータのチェックを行う場合も、ここに記述します。また、タスクのロジックをrakeタスクにベタ書きせず、クラスに切り出した事で、各々の関数に対してテストが書けるようになりました。

APIクラス

API - 親クラス

require 'utils/utils'                                                                                                 

module API                                                                                                             
  include Utils
  def check_dry_run_then(param)                                                                                        
    if dry_run?                                                                                                        
      puts "### DRY_RUN ###"
      pp param
    else
      yield
    end
  end                                                                                                                  
end
equire 'api/api'

module API 
  module AWS 
    include API 
    require 'aws-sdk-core'
  end 
end

APIの親クラスに、dryrunの処理を実装しています。こうすることで、LATaskのロジック本体からdryrunに関連する処理を取り除けるようになり、コードが簡潔になりました。

API - 子クラス

require 'api/aws'                                                                                                     
require 'yaml'                                                                                                         
                                                                                                                       
class API::AWS::SQS                                                                                                    
  include API::AWS                                                                                                     
                                                                                                                       
  def initialize(region = AWS_REGION)                                                                                  
    @sqs = Aws::SQS::Client.new(                                                                                       
      region: region,                                                                                                  
      access_key_id: AWS_ACCESS_KEY_ID,                                                                         
      secret_access_key: AWS_SECRET_ACCESS_KEY                                                          
    )                                                                                                                  
    @conf = YAML.load_file('config/aws.yml')[task_env][:sqs]                                                    
  end                                                                                                                  
                                                                                                                       
  def send_msg(data)                                                                                                   
    check_dry_run_then("[sqs.send_msg] #{data}") do                                                                     
      @sqs.send_message(data)                                                      
    end                                                                                                                
  end                                                                                                                  

  private

  AWS_REGION = "ap-northeast-1"
end

check_dry_run_thenのブロックで、APIにアクセスしています。dryrunの際にはこのブロックの処理が実行されず、代わりにcheck_dry_run_thenの引数で与えられる文字列が表示されます。他のAPIアクセスについても同様に記述しておくことで、簡単にdryrunが実装できます。

Utilクラス

module Utils
  def dry_run?
    !ENV['DRY_RUN'].nil?
  end
end

システム横断でよく使われる処理をまとめた関数群ですが、なるべく使わないようにしています。

リファクタリングを途中までやってみて

下記の様なメリットを感じつつあります。

  • 全体が一貫性を持った構成、書き方で統一できた(可読性・保守性の向上)
  • テストを書く余地ができた
  • ディレクトリ構成でコンポーネントが一目瞭然(もうgrepしない)
  • LATaskクラスにシンプルなロジックを記述するだけでも、概ね全部のタスクにdryrunモードが実装できそう
  • エラーハンドリングとロギングが集約できた

当初、課題として挙げていた部分はまずまず解決できそうな見込みです。一方で、

  • まだイマイチな実装が細々とたくさん残ってる
  • 本当は思い切って名前を変えて、タスクの分類体系も再編したい
  • 想定通りとは言え、分解しきれずUtilsに残ってしまった塊

といった点が、課題として見えてきました。

まとめ

サンプルにある通りかなりシンプルな実装ですが、コードの見通しの良さを保ったまま課題としていた事を概ね克服しつつあるので、良かったと感じています。

  • 実装の難易よりも、課題をシンプルに解決できる事が大切
  • 課題の本質を、しっかり見定めることが同様に大切

という学びとリファクタリングの経験を得られました。新しいことも奇抜なこともないリファクタリングでしたが、よい学びと経験が得られたと感じています。

BigData-JAWS勉強会でAirflowのことを話してきました

データプラットフォームチームのよしたけです。

さて先日のBigData-JAWS 勉強会 #12にて、「リブセンスのデータ分析基盤を支えるRedshiftとAirflow」というタイトルで発表させていただきました。

Airflowについては、このブログでも Airflow を用いたデータフロー分散処理 でご紹介させていただきましたが、今回、弊社での活用事例を交えてお話させていただきました。

発表後のQAや懇親会で、Airflowの導入を検討しているが実際どういうところが大変なのか? とか運用上のつらみ、とかそういうところを気にされている方が多かった印象でした。

AirflowはPythonでデータフローを記述するため、柔軟に何でもできるという強みがあり、反面、やりすぎると改修が大変になり運用しづらくなるデメリットもあるように思います。 私たちはDAG側にはロジックを盛り込まずRake側でロジックを組み上げていくような運用をしているため、比較的変更、修正はカジュアルに回せていると思いますが、 反面、Airflowの豊富なオペレータや機能が使いこなせていないというジレンマもあったりします。 このあたりの加減は今後も改善を進めていきたいなと思っています。

競争優位性構築のための人間中心機械学習〜CVRからUXへ〜 

テクノロジカルマーケティング部データマーケティンググループにてデータサイエンティスト兼UXアーキテクトをしている新保と申します。普段は機械学習を中心としたデータ活用の推進や新規機能のユーザ体験の設計をしています。ここ1年程リブセンスではサービスの戦略レイヤーや主要機能と結合度の高い領域に対して機械学習を適用していくことに挑戦しており、今回はそれらを実際にどのように行っているかをご紹介したいと思います。

パッチ型機械学習の成功体験とその限界

 本題に入る前にリブセンスのデータ活用の歴史について少しお話しします。以前に別のメンバーが投稿した記事に詳しい説明がありますがリブセンスでは2014年にデータ活用の専門組織を立ち上げてから現在に至るまで機械学習のビジネス活用を継続的に行っています。初期の頃は既存サービスの枠組みの中でサービスとの結合度が出来る限り低く、かつ利益インパクトが大きい領域に機械学習を適用することからスタートし、比較的早い段階で成功を収めています。2015年にはレコメンドシステムやアトリビューションモデルなどが主要サービスに本格導入され、当時の全社売上50億円規模に対して安定的に年間1〜2億円程度の利益インパクトを残せるようになりました。一方で成功を収めたことでより高次の新しい課題が見え始めたのもこの時期です。課題の1つは機械学習の開発環境の整備です。こちらについては過去の記事に詳しく解説されていますので

マルチコンテナ構成による機械学習アルゴリズムとアプリケーションの疎結合化 - LIVESENSE Data Analytics Blog

などを御覧ください。

もう1つの課題はデータ活用(機械学習含む)によってCVR向上を通して利益貢献に結びけることに成功した一方で、既存サービスにパッチを当てるような機械学習の使い方ではその成果がサービスの競争優位性構築に結びつけるまでには至らなかったことです。そこで利益貢献を維持しながらデータ活用によってCVR向上よりも大きな成果、サービス自体の競争優位性構築に貢献することが2016年以降のグループのテーマになっていきます。これは現時点で100のサービスをを105にするためではなく中長期的に200、300に延ばしていくために機械学習を始めとするデータ活用を進めて行くということです。

パッチからデザインへ

この方針のもと2016年以降はアルゴリズムの洗練化
を継続しつつ、ユーザ体験の設計段階まで踏み込むプロジェクトを継続的に立ち上げています。これは機械学習がサービスと切り離された機能として提供されるのではなく、サービスの中核を担う行動デザインとインタラクションデザインのレイヤーから関わることを意味します。少し前にGoogle Design blogの記事「Humuman-centerd Machine learning と類似した取組みをリブセンスにおいても約1年前から行っており、次のようなプロセスでプロジェクトを回しています。

f:id:livesense-analytics:20180319193618p:plain

このプロセスのポイントは「既存のデータから機械学習で出来ることを考える」から「コンセプトを先に決めて必要なデータをすべて取る」という方式に変更した点です。Webサービスにおいて機械学習はあくまでユーザへの価値提供を実現するための強力な選択肢の1つであると考え、機械学習ありきではなくユーザへの価値提供を最上位におき、提供価値の具体化と行動デザインのフェーズで機械学習の活用を検討している点で人間中心な機械学習と言えるでしょう。

人間中心の機械学習の実施プロセス

 ここからはフェーズ①〜②においてリブセンスで実際に行っている具体的なプロセスをご紹介します。基本的にはISO9241-210にて定義されているHCDのプロセスをベースにしています。まだまだ試行錯誤の日々ですが現在我々のチームでは次のステップで進めています。

  1. ターゲットセグメントの決定
    まず最初にターゲットになりうるユーザを対象に幅広くデプスインタビュー行い、定性分析によるユーザセグメンテーションを行います。セグメントの軸には様々な方法がありますが我々のチームでは行動パターンの類似性で切り分けた後にメインターゲットとするセグメントを決定しています。

  2. ユーザの価値抽出
    ターゲットセグメントに属するユーザの価値感の抽出分析を行います。デプスインタビューで得た発言録からユーザの行為と意図を抽出して分析を行うことでユーザのもつ本質的欲求を分析します。手法はいくつかありますが、時間がないときは上位下位関係分析、余裕があるときはKJ法やKA法などを用いることが多いです。その後As-isのカスタマージャーニーマップを作成して現在のユーザ行動やタッチポイントごとの課題を可視化します。期間と予算の関係上分析のデータソースとしてはstep1で行ったデプスインタビューの結果を再利用することが多いです。

  3. コンセプト設計とユーザ体験の可視化
    提供するユーザ体験のコアとなるコンセプトをプロジェクトメンバー全員で出し合います。この段階では提供価値にフォーカスしたいため一旦技術的なことは忘れます。次にコンセプトアイディアを「ユーザへの提供価値の大きさ」と「機械学習を使うことによる付加価値大きさ」の二次元マップ上に配置します。ここで高い提供価値を与えるアイディアの機械学習依存度が高い場合はデータサイエンティストとや機械学習エンジニアと実現可能性について検討を行います。ただしこの時点での確認はアイディアが荒唐無稽すぎたり、AIがなんとかするといった抽象的すぎるものになってないかなどの確認であって、具体的なアルゴリズム検討には踏み込みません。また機械学習依存度の低いアイディアの提供価値が一番大きいと判断された場合や機械学習を使うことにより効果が小さい場合は機械学習を使わない選択をすることも多いです。 仮コンセプト確定後は構造化シナリオ法を用いてユーザのサイト上における行動シナリオを可視化します。

    f:id:livesense-analytics:20180320103257p:plain

  4. コンセプト評価とプロトタイピング
    ユーザインタビューによってコンセプト評価を行い、フィードバックを反映してコンセプトを修正していきます。例えば昨年度実施した転職会議の新機能のコンセプト設計では計3回のコンセプト修正と評価を行っています。定性だけで確信が持てない場合はコンセプトが固まった時点で定量アンケート調査で量的な担保を取る場合も多いです。また、プロトタイピングツールを使用してコンセプトをUIに落とし込んで実際にユーザ使ってもらった上での感想も聞いています。プロトの段階でアルゴリズムを開発するとコストが掛かりすぎるためレコメンドシステムであれば予めユーザに好みを聞いておいて人手で選んだ求人を見せたり、チャットボットであればUI上はボットに見せて裏側では人がやりとするようにして極力アルゴリズムを開発せずに擬似的な体験を提供してユーザ評価を行うようにします。   

  5. 開発プロジェクトへの展開
    サービスリリースに向けてデザインプロセスに関わったメンバーを中心に開発プロジェクトを立ち上げます。この段階で機械学習エンジニアをプロジェクトメンバーに本格的にアサインして具体的なアルゴリズムの検討を開始します。

このプロセスでは機械学習の利用を前提とせず提供価値に着目していますが、一方で最初から機械学習の活用アイディアがあるケースもよくあるかと思います。その場合は調査からスタートすると時間がかかりすぎるのでstep1〜step3をプラグマティックペルソナで代替して高速にアイディアの検証とピボットを繰り返していくことで効率的にプロジェクトを進めていく方法をとるのが良いのではないかと考えています。

以上がリブセンスで行っている機械学習を活用したおおまかな体験設計のプロセスです。直近の事例では就活会議での就活生と企業のマッチング機能をこのプロセスを採用して設計しています。アルゴリズム改善のみでマッチング精度を上げるのではなく、就活会議に訪れたユーザが適性な企業とのマッチングに至るまでに必要なユーザの体験設計を最初に行い、ユーザ体験がユーザに刺さるかどうかを事前検証後に必要な機能・アルゴリズム・データを収集・開発しています。就活会議における具体的なサービス設計の事例についてはまた別の機会にご紹介できればと思います。

技術×マーケでメールマーケティングを進めていくぞ!という気持ち

はじめに

こんにちは。テクノロジカルマーケティング部でアナリストをしております、高橋です。

さて、今回のテーマはメールマーケティングです。とその前に、我々の部署名の由来についてご紹介します。「テクノロジカルマーケティング」には、単なる技術開発にとどまることなく技術をビジネス価値に転換する、あるいは技術のチカラでお客様を幸せにするサービスを創る、そんな想いが込められております。

このような思想のもと、メールマガジンの在り方や運用を見直し、テクノロジーとマーケティングの両面から変革していこうとする取り組みが、今年の1月にスタートしました。本記事ではその概要と、何を目指していきたいかについてお話しできればと思います。これまで本ブログでも紹介してきました、LivesenseAnalytics(データウェアハウス、以降LA)やLivesenseBrain(機械学習プラットフォーム、以降LB)の実践事例となります。

背景

舞台となりますのは、弊社が運用している中途採用メディアです。求人情報を載せたメールを求職者様に配信し、開封、URLクリックを経て、応募までいけば無事コンバージョンとなります。同メディアにおけるメールマーケティングの歴史は比較的古く、以前から協調フィルタリングやコンテンツベースのレコメンドアルゴリズムも採用されていました。

ただ、こうしたアルゴリズムをもとにしたレコメンドメールは、既存のメールとは独立にラインナップに追加されてきており、既存メールの中には全配信に近いメールも存在していました。またレコメンドメール自体も、リリース後数年を経過して十分なメンテナンスが出来ておらず、当初ほどのパフォーマンスが出なくなっていました。他にも同じような形で個々にメールマーケティングのテコ入れが行われてきた結果として、メールの送りすぎや、それに起因すると思われるオプトアウトの増加が発生していたというのがプロジェクト発足時の状況です。

新しいメールマーケティングの目指す姿

そこで、この取り組みでどういう状態にしていきたいかを検討し、以下の3点を目指す姿として定義しました。

1) 適切な求人

求人数はそれほど潤沢にあるわけでもないので、モデルの精度よりもルールベースに近い形でシンプルかつ柔軟に調整が効くロジックを採用。職種や勤務地、その他の条件(社風や給与など)ごとのマッチングを実現でき、メールのテーマに合わせてそれぞれのマッチングの強弱を変えることで、希望条件に合わせつつバリエーションを確保できる状態。どのメールにも何らかのマッチングロジックを適用し、全体の求人紹介精度を高い水準に保つ。

2) 適切な頻度

アクセスログや過去のメール反応をもとに、メールでのアプローチが有効と判断されるお客様には高頻度に、そうでない方にはあまり出しすぎないようにしながら、全体の配信数をコントロール可能。主力となるメールは優先的に高頻度に配信され、一方でお客様を飽きさせないよう様々な切り口から求人を紹介できるバリエーション豊かな構成。オプトアウトが低減され配信対象者数が増えることで、じわりじわりとCV期待値が上がっていく状態。

3) 適切な手段

顧客データの細かな分析結果(特に求人案件を閲覧するときの行動を中心に)に基づき、メールの件名・本文、配信する時間帯、文体やデザインのトンマナ、求人の数や掲載項目(属性)などをお客様ごとに変えていく、いわゆるパーソナライズがなされた状態。これらについては常にA/Bテストが走り、KPIを日々モニタリングしながら改善PDCAが並列超高速で回っている状態。パフォーマンスを上げるためのノウハウが蓄積され、将来的に他のメディアでの展開を見据える。

これらを仕組みとして用意することで、冒頭に述べたような技術とマーケの両輪でメール価値の最大化を実現できると考えています。メールマーケティング自体は比較的シンプルなマネタイズ構造ですので、ここをチューニングすることで早期のビジネスインパクトが見込めると判断しました。

取り組み内容

まだ一部実装が追いついていない箇所も含みますし、今後変更になる可能性も大いにあるのですが、少しだけ中身をお見せしたいと思います。

PLAN

週に一回の会議で、新規メールのアイデア出しをしたり、既存メールの改善点やA/Bテストテーマの検討を行います。新しいメールは最低でも週に一本投入するようにしていて、良好な結果が出ればそのままラインナップ入りとなります。改善やテストはスピードと数を重視していて、思いついたら即実行のスタンスで動いています。メディアの価値・信頼を毀損せず、なおかつ尖った内容の文面を書くというのは意外と大変なのですが、本文を少し変えただけでも結果が大きく変わるのがメールの面白いところです。現在は約60種類のメールが稼働しており、この数はさらに増えていく予定です。

DO

メール配信のキモである、リスト作成(誰にどの案件を紹介するか)はLBのインフラ上で実行されます。テーマに沿って求職者や求人案件をLAから抽出し、いくつかのマッチングやレスポンス予測を経て、リストが出力されるこの一連の処理は現在のところR言語で記述しています(試験フェーズのため)。使っているのはランダムフォレストやコサイン類似度などで、機械学習の初学者にも馴染みのあるものばかりです。これらの処理は全メールで共通のものになっていて、個々のマッチングを使うかどうかと、スコアの閾値設定を各メールで自由に設定できるようになっています。また、マッチングの際に算出されたスコアなどはLAに連携され、すぐに検証することが可能です。

CHECK

週に一回の会議で、データを見ながら翌週のラインナップを編成します。顧客セグメントごとに、曜日や時間帯などある程度決められた配信枠を設けてあり、そこにどのメールを当てはめていくかを検討します。ちょうど某アイドルグループの総選挙のような形で、神セブンと呼ばれるパフォーマンスTOP7メールがゴールデンタイムでの配信を勝ち取ります。改善の結果、頻繁に順位が入れ替わるので、総選挙は毎週行っています。正直を言うと、そのたびに設定を変えるのは面倒なところもあるのですが、飽きずに楽しむ秘訣と割り切って対応しています。

ラインナップ編成のイメージ
ラインナップ編成のイメージ

おわりに ~今後の展望~

始まったばかりの取り組みで今後の展望を語るのは時期尚早かもしれませんが、いくつか構想はあります。

まずは他のメディアへの横展開。テクマのような全社横断組織で運用している意義がここにあります。次に他のチャネルへの縦展開。メール以外でもお客様にアプローチできる手段は色々あるかと思いますので、それらを併用しながら相乗効果を狙っていくのが一つの目標です。また、営業との連携。メールマーケティングの取り組み自体をクライアントに興味を持ってもらうことで、求人案件を掲載したいと思っていただける状態を作りたい。そして最後に、利用してくださるお客様の幸せな転職の機会を少しでも増やせるようになればと思いながら、これから頑張っていきます。

それでは続きはまた次回に。最後までお読みいただき、ありがとうございました。

Developers Summit 2018 発表資料

こんにちは。テクノロジカルマーケティング部の谷村です。

本日、私と田中の2名で デブサミ2018において、データを活かす組織の作りかた、事業に寄り添う分析・機械学習基盤の育てかたというタイトルでお話する機会をいただきました。

早速ですが、発表資料についてそのまま公開させていただいています。

前半:Livesenseの場合のデータを活かす組織の作りかた(谷村)

後半:事業に寄り添うデータ基盤の育て方(田中)