Tableau Hyper API使って業績管理ETL作った

1インプレッションから有価証券報告書までのデータの流れをシステムに乗せる事を旨とする

M. Yuasa

証券コード2489 株式会社アドウェイズ

第21期第1四半期連結累計期間、売上高10,003,518,000円(100億)経常利益229,971,000円(2.3億)。
主な事業内容は、広告事業・メディアコンテンツ事業・海外事業の3事業を擁し、売上高の大部分を広告事業が占めている。

国境のないインターネット空間で、弊社は世界を相手に事業をしている。
1インプ(インプ:インプレッション。ネット広告の表示回数の単位)から、流れに流れて、有価証券報告書に流れ着く。
その大きな流れの中に、幾人もの関わっている人たちがいる。
広告の企画営業、デザイナー、エンジニア、経理、バイク便のお兄さんまで。
この大いなる流れをコンピューターシステムに乗せて事業を推進する。
そういうビジネスのデベロップメントもあるのではないだろうか?

挨拶がおくれて申し訳ございません。
ビジネスデベロップメントグループ事業推進ディビジョン、チーフの湯浅です。
最近の業務内容は、1インプから有価証券報告書までの大いなる情報の流れを往来し、業務や経営の意思決定する根拠となる情報を提供しています。

弊社は、手前味噌ではありますが、2020年現在、日本のインターネット広告を取り扱っている企業としては大きいほうで、日本のアドテクの先のほうにいると自負しております。
先にいる宿命としてあるのが、大体のことが前代未聞で前人未踏の課題を、手探りで解決していくことです。
解決策は自分で考え、自分で試行錯誤する以外にないという、解のない世界でのアートです。
この記事は手探りをして見つけた一つの解の共有であり、また手探りをしている方たちへの助けになることを期待して執筆しています。

業績管理用のETL作成

国内広告事業において、1インプから有価証券報告書までの大いなる流れの実態は底なしの泥沼でした。
この流れを整理するために、業績管理用のETLを作りました。
結果をTableau Serverに格納する必要がありました。
予算は0。私と愛機のThinkPadだけです。

Tableau Serverへのデータの格納は二通りあります。
Pull型とPush型です。

Pull型は、Tableau Serverからアクセスの出来るDBをどこかに置く必要があります。
私が好きなのは、Google Spreadsheetに書き出して、Tableau Serverから抽出 です。
お金かからないし、楽です。
業績管理のETLでは、データ量が多いため、この方法は断念しました。
Tableau Serverからアクセスの出来るDBも予算もありませんでした。
ゲームオーバーです。

私がアメリカで聞いたジョークに、こういうのがあります。
Q: プログラムを作るにはどうしたらいい?
A: 部屋にピザとコーラを置いて、エンジニアを招き入れる。部屋に入ったところで、外からドアのカギをしめるんだよ!HAHAHA!
エンジニアにとっては、コーディングはある種のひと時の楽しみであると、たまに思います。

引いてだめなら、押してみる

  • Tableau Hyperを書き出して、Tableau Serverにアップロード

Tableau Hyper APIに私は手を出しました。

Tableau Hyper APIについて調べている貴方は、十中八九、まちがったことをしているかもしれない。
十中二一、きつい制約の中でたどり着いた結果だと推察します。

(なぜ私はHyperファイルを直接触る必要があるのだろうか。有限の資源の中で、これは正しいのだろうか。)
自問自答を繰り返しながら、公式ドキュメントを読みサンプルをいじりました。
そしてサンプルを切り貼りして、便利な形を見つけました。
いずれの日か、この辺が簡単になるPythonのライブラリが出来る事を願って。(じゃ作れよって話なんですけどね)

from tableauhyperapi import Connection, HyperProcess, SqlType, TableDefinition, escape_string_literal, escape_name, NOT_NULLABLE, Telemetry, Inserter, CreateMode, TableName

def export_to_hyper():
  path_to_csv = "himitsu.csv"
  path_to_hyper = "himitsu.hyper"
  with HyperProcess(Telemetry.SEND_USAGE_DATA_TO_TABLEAU) as hyper:
    print("Hyperプロセス開始.")
    connection_parameters = {"lc_time": "en_US", "date_style": "YMD"}
    with Connection(hyper.endpoint, path_to_hyper, CreateMode.NONE, parameters=connection_parameters) as connection:
      print("Hyperファイルに接続.")
      schema_name = connection.catalog.get_schema_names()[0]
      tb_name = connection.catalog.get_table_names(schema_name)[0]
      tb_def = connection.catalog.get_table_definition(tb_name)
      connection.execute_command(command=f"DELETE FROM {tb_def.table_name}")
      connection.execute_command(command=f"COPY {tb_def.table_name} from {escape_string_literal(path_to_csv)} with "f"(format csv, NULL '', delimiter ',', header)")
      print("アップデート完了.")
    print("接続の解除.")
  print("Hyperプロセス終了.")

基本的な概念

  1. Hyper APIライブラリをインポートする
  2. Hyperプロセスを開始する
  3. Hyperファイルに接続する
  4. Table定義を行う
  5. コマンドを実行する

前提として、Python3系です。必要なライブラリはpipで入れてください。
この記事では、4について詳しく書きます。
1・2・3はたいして難しい問題ではないです。日付データがあるならば、parametersで日付のフォーマットを指定したほうが良いです。
1Hyperファイルにつき、1スキーマ、1テーブルという暗黙の前提があります。

4のテーブル定義が、非常に面倒でした。
そもそも、スキーマ名もテーブル名、Tableau DesktopでHyper作ったため不明です。(Hyperが作成された環境によって抽出だったり、Extractだったりする)

connection.catalog で接続してるHyperの情報が手に入ります。
Catalogのソース を確認してください。
get_schema_names()でスキーマ名を動的に取得します。
get_table_names(schema_name)でテーブル名を動的に取得します。
get_table_definition(tb_name)でテーブル定義を動的に取得します。
こうすることで、非常に長いテーブル定義を書くことを放棄しました。
私は、この後テーブルの中身を一回消して、COPYコマンドでCSVを流し込んでます。 connection.execute_command(command=f"")で、SQLの実行をHyperに対して行います。

この方法をとると、Tableau DesktopでHyperを作って、そのファイルに対して処理を行うことが可能になります。
それは、Table定義を書くという面倒な作業をカットできます。
こうして、Tableau Hyperを書き出して、TabcmdでTableau Serverにアップロードをすれば完成です。

Tableau Hyper APIについての記事は、執筆時点の2020年7月現在、あまり見ませんでした。
企業活動においての情報をシステムに乗せる仕事は、デジタルトランスフォーメーションそのものであると思っています。

最近、フォードVSフェラーリを観ました。
内燃機関ってのは、非常に不思議で、金属の塊を削って組み立てて、揮発性の液体のガスを入れたら、いい感じに動くんです。
シリンダーの中で、ピストンが上下して、コンロッドを通じてクランクシャフトが回転する。
その回転エネルギーをギアが伝える。マシンはタイヤを伝って地面を走る。

主人公のケンは、エンジニアでありレーサーで、彼の頭の中には、マシンというシステムが入っているのです。
アクセルを踏めば、ガソリンがキャブレターに流れ込み、気化して、それがシリンダーに入り込み、爆発しピストンを上げ下げする。
ピストンの運動量が増え、エンジンの回転数が上がり、エンジン音が大きくなっていき、スピードも上がっていく。
レースに勝つためには、極限までのチューニングを必要とする。
システムの不具合も出てくる。部品が壊れる、外れる、意図しない動きをする。
エネルギーの大きな流れを邪魔することなく、きれいに流していく。
とても美しい。

企業活動においての情報の流れをシステムに乗せる仕事は、これに似てる。
1インプの先から有価証券報告書の先までの、巨大な情報空間を一気通貫に電子システムで制御する。
そのシステムの中に人の手が入れば入るほど、遅くなります。
そういう世界になっているんだなぁ、と映画を観ながら、JFKからHNDへの便の中で私は思い、筆を執ったのでした。

いいか、息子よ。自分のやりたいことを知ってるヤツは本当にラッキーだ。そいつは人生の中で1日も働かないからね。

Mangold, James. Ford v Ferrari. 2019.