AlteryxのIterativeマクロ(反復マクロ)を使って、ぐるなびAPIから奈良県中西部の飲食店情報を取得してみた(ついでにTableauで可視化してみた)#alteryx #tableau

AlteryxのIterativeマクロ(反復マクロ)を使って、ぐるなびAPIから奈良県中西部の飲食店情報を取得してみた(ついでにTableauで可視化してみた)#alteryx #tableau

奈良県は飲食店が少ない
Clock Icon2019.02.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

どうも。DI部@大阪オフィスのtamaです。

Alteryxは一切コードを書かずに各種APIからデータを引っ張ってこれます。そして、取得したデータは、そのままAlteryx上で整形したり分析できたりするので、すごい便利です。

しかし、世の中に公開されているAPIは、1回のリクエストで取得できるデータ件数が限られていることが多いです。データ分析が目的でAPIからデータを取得する場合、基本的には全件ほしいという場合がほとんどだと思います。同じリクエストを、パラメータを変えて繰り返し実行する必要があります。

こういう時、エンジニアの方であれば、サクッとコードを書いて処理するだけですが、非エンジニアの方が、Alteryxだけで何らかのAPIからデータを持ってこようとしたとき、「んお、繰り返してワークフローを回すには、どうすればよいのだ」と若干困惑するかもしれません。

そういう時に役立つのがIterativeマクロになります。ってわけでIterativeマクロを使って、私が住んでいるところらへんの飲食店情報を、コードは書かずに、Alteryxだけで取得してみました。

使用したAlteryx

Alteryx Designer v2019.1 Japanese

事前に読みたいIterativeマクロの参考情報

ぐるなびAPIを準備する

上記を参考にぐるなびAPIの利用申請を行い、アクセスキーを取得します。

ワークフロー全体

ぐるなびAPIが利用できるようになったら、さっそくAlteryx Designerでワークフローを作ります。先に、まず完成図をどうぞ。

本体

マクロ側(Iterativeマクロ本体)

Iterativeマクロの設定方法

流れ

  1. まず繰り返したい処理のワークフローを先に作成します。
  2. 作成直後は1回きりのワークフローとなっているので、これをIterativeマクロに変更する設定を行います。
  3. そのIterativeマクロを使用して本体ワークフローを作成します。

個人的な考えですが、Iterativeマクロを使う場合は、大体このような流れになるのではないかと思います。

まず普通にワークフローを作る

上記のマクロの中身の画像は完成形なのですが、普通にワークフローを作ると、入力と出力の部分は、画像のようにならず、下記のようになると思います。

普通の入力ツールと出力ツールを使ってると思います。これをIterativeマクロにする(繰り返し処理にする)場合は、Iterativeマクロの設定を行わないとダメです。

ワークフローの設定を「Iterativeマクロ」に変更する

画面左のメニューから「Workflow」のタブを選択し「反復マクロ」を選択します。これで、このワークフローは「Iterativeマクロ」とみなされました。

入力と出力をマクロ用のものに変更する

入力ツールを右クリックして「マクロ入力に変換する」を選択します。すると、マクロ用の入力ツールに変わります。詳細を確認すると、マクロ用に変わってはいますが、変わらず元の入力ツールとしての設定もできることがわかります。

同様に、出力もマクロ用に変えておきます。マクロ出力ツールは、ツール検索で「マクロ」と打つとすぐ出てきます(入力の方も、ここから配置できます)。

インターフェースデザイナーで設定する

インターフェースデザイナーで、繰り返し処理の対象となるマクロ入力と出力を指定します。「反復入力」と「反復出力」に指定した入力と出力が、繰り返し処理を繋ぎます。ここがIterativeマクロのちょっとややこしいところなのですが、反復出力されたデータがそのまま次の入力になると考えましょう。つまり反復出力と反復入力は、同じデータ構成(列の数や名前など)である必要があります。

ちなみに、反復出力に指定されなかったマクロ出力は、ループしません(出しっぱなし)。この仕様を考慮して、フィルターツール等で分岐を作り、片方はループ、もう片方は別処理を行う…という感じでワークフローを作成します。

インターフェースデザイナーは、他にも、最大ループ回数やマクロとして使った時のアイコン画像を指定することができます。

マクロ側の処理について

ワークフローのIterativeマクロ化についてわかったところで、実際にマクロ側の処理を作っていきます。

マクロの大まかな流れ

  1. ぐるなびAPIにリクエストを投げて、データを取得する
  2. 取得した件数が、総該当件数(total_hit_count)を超えない場合は、反復処理を続行し、再度APIにリクエストを投げて、データを取得する
  3. 取得した件数が、総該当件数(total_hit_count)を超えた場合は、反復処理を停止し、取得したデータを出力(ExcelでもDBでも)する

ぐるなびAPIからデータを取得する部分

テキスト入力ツール

AlteryxからAPIにアクセスするためには、ダウンロードツールを使うのですが、その前に、API側に渡す値を、テキスト入力ツールで用意しておきます。

どういう値が必要なのかは、ぐるなびAPIの仕様を確認しましょう。今回は奈良県葛城市の飲食店データを取得したいので、urlは「レストラン検索API」のものを使用します。また、areacode_sを奈良県中部のものに指定しておきます。

ここで大事なのはhit_per_pageoffset_pageです。hit_per_pageの解説をぐるなびAPIのサイトで確認すると、以下のように書かれています。

一度リクエストで得るレスポンスデータの最大件数(デフォルト:10、上限:100)

つまり、このAPIの1リクエストで得られる最大件数は100件です。ですので、該当データが100件以上ある場合、100件取得する処理を、全件取得するまで、繰り返す必要があります。そこで大事になってくるのがoffset_pageです。詳細は後ほど出てきますので、とりあえずここでは1を指定しておきます。

ダウンロードツール

ぐるなびAPIはシンプルです。使用したいAPIのURLにアクセスキーと指定したい値を投げればそれでOKです。今回は上記のように設定します。

JSONパースツール

レスポンスはJSON形式で返却するよう指定しているので、返ってきたJSONをこのツールでパースします。指定するフィールドはDownloadDataです。

「テキストを列に分割」ツール

パース後のカラム「JSON_Name」に入っている項目名が.で連結しているので、区切り文字を.に指定して3列に分割します。

飲食店データ取得部分

「テキストを列に分割」ツールの後はフローを2つに分岐します。まず、APIから取得した飲食店データを整形する部分を見ていきます。

選択ツール

色々なカラムがあると思いますが、ここでほしいのは飲食店データ…つまり返ってきたJSONだけです。余計なカラムはここで外しておきます。

クロスタブツール

パース後のJSONデータは縦方向に連なってるので、クロスタブで整形します。

フィルタツール

純粋な飲食店データだけがほしいので、JSON_Namerestのみにフィルタします。

マクロ出力

取得したデータは、最終的にマクロの外に出さないといけないので、マクロ出力ツールを配置します。

繰り返し処理部分について

処理を反復させるためには、反復させるかどうかを判定する処理が必要となります。その判定をするための材料は、そのAPIのレスポンスに含まれる値で決まってきます。今回のAPIのレスポンスのパラメータに、total_hit_countというものがあります。これはリクエストした条件に該当するデータの総件数です。この総件数をきっかけに、何回処理を繰り返すか…を実装していくのが良いと思ったので、今回はそれで行きます。

  • リクエストパラメータhit_per_pageはMAX値の100件を設定している
  • リクエストパラメータoffset_pageで取得開始ページを設定できる
  • total_hit_countで総該当件数がわかる
  • 「1000件を超えている場合、上位1000件までのデータが返却される」という仕様

これらを踏まえて、offset_page × 100total_hit_countを超えない限り、データを取得し続けるようにすればいいと考えました。

ここで一点注意しないといけないのは、offset_pagetotal_hit_countを超えた状態でリクエストを投げた時です。

例えばtotal_hit_countが555件あった場合、APIへのリクエストは6回繰り返す必要があります。言い換えると、7回目のリクエストを投げた時点で、ループ処理を終わらせる必要があるのですが、今回のAPIは、データが存在しない場合は、total_hit_countというパラメータは返ってきません。

ですので、処理としては、まずtotal_hit_countカラムがあるかどうかをチェックし、もしカラム自体がない場合は、total_hit_countを0にして、offset_page × 100(1ページにつき100件取得するため)が必ずtotal_hit_countを超えるようにして、反復処理を終わらせるようにします。

total_hit_countが存在するか判定する

  1. total_hit_countの値がとりたいので、サンプルツールで該当レコードだけ抜き出し、クロスタブツールで整形します。クロスタブツールの処理時に、リクエストで投げたパラメータにあたる列も取得しておきます(繰り返し処理時に必要)
  2. フィールド情報ツールでカラム情報を取得し、カラム名の一覧に total_hit_countがあった場合はTrueを返す(結果は新規列として追加)処理をフォーミュラツールで行います。

  1. 上記で追加された列をサマライズツールで集計します。Bool型なので、total_hit_countが存在していれば1、存在していなければ0になるはずです。
  2. この列を、フィールド付加ツールで、先程APIから取得したデータにくっつけます(列名をtotal_hit_count_existsに変更)。

後は、このtotal_hit_count_existsという列をフィルターツールで判別してやれば、total_hit_countが存在するかどうかで処理を分けることができます。

total_hit_countが無い場合は0にしてループ終了

先程生成したtotal_hit_count_existsという列が0だった場合、APIからのレスポンスにtotal_hit_countが無い=これ以上取得できるデータは無い、ということなので、フォーミュラツールでtotal_hit_countという列を新たに作り、値を0にします。

残データがある場合は繰り返し処理

ここが今回のマクロの肝になります。

offset_page × 100total_hit_countを超えない限り、データを取得し続けるようにすればいいと考えました。

ですので、フィルターツールに上記の式を設定します。超えない場合、次のデータ取得を行うために反復する必要がある=再度リクエストを投げる必要があるため、セレクトツールで体裁を整えて(この出力がそのままリクエストパラメータとなるため)、次の処理をループさせます。

本体側の処理について

やっとのこさIterativeマクロが作成できたら、ゴールまであと少しです。このマクロに対して入力と出力を与えてあげるだけです。

テキスト入力ツール

ぐるなびAPIに渡すリクエストパラメータを設定します。端的にいうと、Iterativeマクロの入力と同じようにします。

さっき作ったIterativeマクロ

リクエストパラメータを、苦労して作ったIterativeマクロに渡します。後は、マクロ内で繰り返し処理が実行され、指定したリクエストに該当する飲食店データを全て取得できます。

マクロから出力される飲食店データを整形して出力

今回のIterativeマクロですが、そのマクロからほしいのは、ぐるなびAPIから取得する店舗データです。

Iterativeマクロのマクロ出力ツールの設定に「アンカー省略形」というものがあります。ここにはアルファベット1文字を指定できるのですが、これはマクロを配置した時の出力アンカーの記号と対応しています。

今回のIterativeマクロで、飲食店データを出力するマクロ出力はdなので、dのアンカーから線をつないでいきます。後は、セレクトツール等で体裁を整えて、欲しいデータ形式に出力します。

結果

奈良県中西部の飲食店データは334件あるみたいですが、ちゃんと4回繰り返し処理がされました!

ついに奈良県中西部の飲食店情報をゲットだぜ

ついでにTableauで可視化してみた

せっかくなので、このワークフローで得た飲食店データを使ってビューを作ってみました。

地図上に店舗位置を可視化し、URLアクションを使って、無駄に詳細情報がわかるようにしました。いや〜私の自宅の近く、飲食店すくない!

おわりに

正直、マクロ内のワークフローは、もっとスマートな方法があると思っていますが、現時点での私にはこれが限界でした…。精進します。

Alteryx Designerで何らかのAPIからデータをとってくるとき、Iterativeマクロはめちゃくちゃ役に立つと思います。ぜひ他のAPIでもご活用ください。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.