blog
ブログ

Salesforce技術ブログ:[Analytics入門]静的ステップとバインド関数を使ってみよう!(相対日付範囲編)

こんにちは、紺レンジャー吉岡です。
最近インフルエンザが大流行していて怖いですね😱運動をして免疫を高めないと!😠
・・・と思ったのですがまだ寒いので春から頑張ります😇
 
さて、今回はEinstein Analyticsのダッシュボードのお話です。
 
皆さんはAnalyticsダッシュボードで日付ウィジェットを使用したことがありますか?
 

 
そう、これです。このウィジェットは選択した期間内でデータを絞り込んでくれるスグレモノです。
しかし、あるプロジェクトで私がAnalyticsダッシュボード構築でこれを使用した時、ある指摘を受けました。
それは「絶対日付や相対日付でカレンダーから選択だと使いにくい」というものでした。
確かにその通りだと思いました。(あと地味にサイズが大きい…)
また、その時作成するダッシュボードでは「よく検索に使用する期間」が決まっていました。(今日、今週、今月の三種類)
でもダッシュボードデザイナ標準のウィジェットでは日付を指定して検索するにはこの日付ウィジェットを使うしかありません。😭
 
もうだめだ…おしまいだぁ…と思ったそこのあなた!ここで登場するのがJSONファイルです。
Analyticsダッシュボードはそれを構成しているJSONファイルを編集することにより、デザイナ標準のコンポーネントでは実現できない高度なカスタマイズを実現することができます!

さぁ、JSONファイルを編集してステップをカスタマイズしてみましょう。

※これから紹介する小技はこんなステップを作るときに時に役に立ちます!
1. よく使う日付が決まっている。
2. その日付を元にデータを検索をしたい。

前準備

 
必要なもの
 
1.Einstein Analyticsが使えるDev環境(ハムスター森さんが書いていた記事を参考に作成してください。)
2.日付項目を持つデータセット(今回は気象庁から東京の気温(2017/1/1~2018/2/12)をデータとして使わせていただきました。)
 

ステップを作成する

 
まず初めに3つのステップを作成します。
日付別の気温(通常SAQL)

みんな大好き折れ線グラフです。
 
検索範囲の開始日用(カスタムSAQL)

 

q = load "EdgeMart1";
q = group q by ('Column1_Year', 'Column1_Month', 'Column1_Day');
q = foreach q generate 'Column1_Year' + "~~~" + 'Column1_Month' + "~~~" + 'Column1_Day' as 'Column1_Year~~~Column1_Month~~~Column1_Day', count() as 'count';
q = order q by 'Column1_Year~~~Column1_Month~~~Column1_Day' asc;
q = limit q 1;

検索している日付の開始日をデータとして取得する用のステップです。(非表示です)
 
検索範囲の終了日用(カスタムSAQL)

 

q = load "EdgeMart1";
q = group q by ('Column1_Year', 'Column1_Month', 'Column1_Day');
q = foreach q generate 'Column1_Year' + "~~~" + 'Column1_Month' + "~~~" + 'Column1_Day' as 'Column1_Year~~~Column1_Month~~~Column1_Day', count() as 'count';
q = order q by 'Column1_Year~~~Column1_Month~~~Column1_Day' desc;
q = limit q 1;

検索している日付の終了日をデータとして取得する用のステップです。(非表示です)
 
データセットを元に作成したステップの作成はここで完了です。
 

静的ステップを作成する

 
次にダッシュボードの右サイドバーから「ステップを作成」ボタンをクリックし、「カスタム値を使用して静的ステップを作成」を選択します。
 

 
アレ?値が入ってないよ?と思う方もいるかもしれませんが、ここで入れた値はすべて文字列扱いになってしまうのでこれでも大丈夫です。
 
作成したグラフと静的ステップをダッシュボードに追加します。(カスタムSAQLのやつは表示しません)
また、左上にテキストウィジェットを追加します。
 

 
左上のテキストウィジェットにはデータが表示されている期間を表示する予定です。
右上のが先ほど作った静的ステップですね。
クリックで選択はできますが、まだハリボテです。
これからこの静的ステップに値を持たせます。
が、その前にバインドとは何か、について説明します。
 

バインドとバインド関数

 
バインドとはあるステップから取得したデータを他のステップの検索条件にしたり、
テキストとして表示するといったことができる機能です。
AnalyticsダッシュボードではJSONファイルを編集することにより、このバインドをカスタマイズすることができます。
 
そしてバインドを行うために、ステップから値を取得するための関数をバインド関数と呼びます。
バインド関数が扱うことのできるデータは3つの種類があります。
1つ目に文字列・数値・nullなどのスカラー値 例:”hoge”、334、 null
2つ目に一次元配列、同じ型のデータが連続して入っている通常の配列です。例:[1,2,3]、[“one”,”two”,”three”]
3つ目に二次元配列、中に配列が入った配列です。 例:[ [1, 2], [3, 4] ]
これらのデータを使用してバインド関数はバインドを行います。
 
さて、バインド関数にも3つの種類があります。
データ選択関数、データ操作関数、データ逐次化関数の3つです。
 
まず初めにデータ選択関数です。
文字通り「ステップのどこからどのデータを取得するのか」、を指定するための関数です。
データ選択関数にはcell関数、row関数、column関数の3つがあります。
下のステップ画像を使ってそれぞれの関数の使い方を説明します。

 
cellの名の通り、ステップのセル単位でしかデータを取得できません。
そのため、使用するにあたってデータを取得する列名、行番号の指定が必須です。

例:cell(セリーグ2018.selection, 5, "Win")で45を取得、cell(セリーグ2018.selection, 3, "Name")で"Giants"を取得

 
続いてrow関数です、こちらは行単位でデータ取得を行います。
行番号と列名の指定は一次元配列で行います。
列名の指定は任意で、列名を指定しない場合は1行のデータすべてが取得されます。
データの順番は列名を指定した順番になります。
しかし指定されなかった場合は順番が保証されないため、注意が必要です。
この関数では取得したデータが一次元配列になります。
 

例:row(セリーグ2018.selection, [1,2], ["Name"])で["Tigers","Baystars"]を取得、
  row(セリーグ2018.selection, [4], [])で["Dragons", 59]を取得

 
最後にcolumn関数です。この関数では列名を指定して、指定した列のすべての行のデータ取得を行います。
列名の指定は一次元配列で行います。
列名の指定は必須ですが、空配列を指定すると全列の全行のデータを取得します。
cell関数同様、データの順番は列名を指定した順番になります。
また指定されなかった場合は順番が保証されません。
取得したデータは単一の列のみ取得した場合は一次元配列、複数列取得した場合は二次元配列になります。
 

例:column(セリーグ2018.selection, ["Name"])で[ "Carp", "Tigers", "Baystars", "Giants", "Dragons", "Swallows"]を取得、
  column(セリーグ2018.selection, [])で[ ["Carp", "Tigers", "Baystars", "Giants", "Dragons", "Swallows"],[88, 78, 73, 72, 59, 45]]を取得。

 

 
次にデータ操作関数は、データ選択関数で取得したデータの形式を変換する関数です。
二次元配列を一次元配列にする、配列を文字列にする、文字列を配列にする等々の処理を行うことができます。
今回は使わないので、説明は割愛します。
 
最後にデータ逐次化関数です。
データ逐次化関数は取得したデータをステップが使えるように形式の変換を行う関数です。
これだけだとデータ操作関数とどう違うの?と思うかもしれませんが、
データ操作関数がスカラー値、一次元配列、二次元配列の間でデータの変換を行うのに対して、
データ逐次化関数はSAQL文で使えるようデータの変換を行います。
これから今回使用する2つの関数を紹介します。
 
1つ目がasDateRange()関数です。
()内には検索条件にしたい日付項目が入ります。
この関数は一次元配列または二次元配列を元に日付検索条件のSAQLクエリを返します。
①文字列の相対日付や②UNIX時間(エポック時間)で検索する際は一次元配列、
③配列の相対日付や④配列の絶対日付で検索する際は二次元配列を使用します。
 

例:
相対日付一次元配列 ①["1 day ago","current day"]
相対日付二次元配列 ③[["day", -1], ["day", 0]]
絶対日付一次元配列 ②[1518274800,1518361200]
絶対日付二次元配列 ④[[2018, 2, 11], [2018, 2, 12]]

 
これらの日付がasDateRange()によって変換され、バインドが評価されることによって

相対日付 in ["1 day ago".."current day"]
絶対日付 in [dateRange([2018, 2, 11], [2018, 2, 12])]

というSAQL文に変わり、ステップの表示されるデータもこの条件に一致するもののみになります。
 
2つ目がasObject()関数です。
この関数はデータの逐次化を行わずにデータを渡す関数です。
より正確に言えばデータを文字の配列としてデータを渡します。
そのため、先ほど登場した

[["day", -1], ["day", 0]]

がasObject()によって変換されても

["day", -1], ["day", 0]

になるだけです。

これでバインドの説明は終わりです。

 

静的ステップに持たせる

[Ctrl] + [E]でJSONファイルを開きます。
※注意!JSONファイルは誤った構文で保存すると二度と開けなくなる場合があります!できればバックアップをテキストエディタに取りましょう。
 
静的ステップのID「static_1」で検索すると下記のようになっています。
 

            "static_1": {
                "broadcastFacet": true,
                "groups": [],
                "label": "期間選択",
                "numbers": [],
                "selectMode": "single",
                "strings": [],
                "type": "staticflex",
                "values": [
                    {
                        "display": "今週"
                    },
                    {
                        "display": "今月"
                    },
                    {
                        "display": "今年"
                    }
                ]
            }

 
“values”メンバを書き換えます。
 

                "values": [
                    {
                        "display": "今週",
                        "value": [
                            [
                                [
                                    "week",
                                    0
                                ],
                                [
                                    "week",
                                    0
                                ]
                            ]
                        ],
                        "range": [
                            "current week",
                            "current week"
                        ]
                    },
                    {
                        "display": "今月",
                        "value": [
                            [
                                [
                                    "month",
                                    0
                                ],
                                [
                                    "month",
                                    0
                                ]
                            ]
                        ],
                        "range": [
                            "current month",
                            "current month"
                        ]
                    },
                    {
                        "display": "今年",
                        "value": [
                            [
                                [
                                    "year",
                                    0
                                ],
                                [
                                    "year",
                                    0
                                ]
                            ]
                        ],
                        "range": [
                            "current year",
                            "current year"
                        ]
                    }
                ]

 
“value”で指定したのが通常SAQL文で使用する二次元配列の相対日付範囲、”range”で指定したのがカスタムSAQL文で使用する一次元配列の日付範囲です。
値は全く同じですが、書き方がだいぶ違いますね。
 
これで静的ステップに値を持たせることができました。
次にステップに静的ステップの値をバインドします。
 

ステップに値をバインドする

 
通常SAQLのステップのIDである「Column1_Year_Column1_1」をJSONファイルから検索すると下記のようになっています。
 

            "Column1_Year_Column1_1": {
                "broadcastFacet": false,
                "datasets": [
                    {
                        "id": "0Fb7F0000008ZoZSAU",
                        "label": "東京の気温",
                        "name": "EdgeMart1",
                        "url": "/services/data/v42.0/wave/datasets/0Fb7F0000008ZoZSAU"
                    }
                ],
                "isGlobal": false,
                "label": "東京の気温(日別)",
                "query": {
                    "measures": [
                        [
                            "avg",
                            "Column2"
                        ],
                        [
                            "max",
                            "Column2"
                        ],
                        [
                            "min",
                            "Column2"
                        ]
                    ],
                    "groups": [
                        [
                            "Column1_Year",
                            "Column1_Month",
                            "Column1_Day"
                        ]
                    ]
                },
(後略)

 
SAQLをカスタムしていない場合はこのように、”query”メンバ内にあるメンバがグルーピングや表示項目を決めています。
“query”メンバ内に”filters”メンバを追記します。
 

                "query": {
                    "measures": [
                        [
                            "avg",
                            "Column2"
                        ],
                        [
                            "max",
                            "Column2"
                        ],
                        [
                            "min",
                            "Column2"
                        ]
                    ],
                    "groups": [
                        [
                            "Column1_Year",
                            "Column1_Month",
                            "Column1_Day"
                        ]
                    ],
                    "filters": [
                        [
                            "Column1",
                            "{{cell(static_1.selection, 0, "value").asObject()}}"
                        ]
                    ]
                }

 
cell関数はstatic_1.selection(静的ステップ選択値)の持つメンバ名”value”の値を取得し、
asObject()関数で逐次化せず値を渡しています。
 
次にカスタムSAQLですがそれぞれのID「________1」「_______1」を検索すると下記のようになっています。
 

"query": "q = load "EdgeMart1";
        nq = group q by ('Column1_Year', 'Column1_Month', 'Column1_Day');
        nq = foreach q generate 'Column1_Year' + "~~~" + 'Column1_Month' + "~~~" + 'Column1_Day' as 'Column1_Year~~~Column1_Month~~~Column1_Day', count() as 'count';
        nq = order q by 'Column1_Year~~~Column1_Month~~~Column1_Day' asc;nq = limit q 1;",

※コードを整形しています。

 
という風に”query”メンバにそのままSAQLクエリが書かれており、通常のSAQLとは異なることがわかります。
 
“query”メンバを下記のように書き換えます。
 

"query": "q = load "EdgeMart1";
        nq = filter q by {{cell(static_1.selection, 0, "range").asDateRange("date('Column1_Year', 'Column1_Month', 'Column1_Day')")}};
        nq = group q by ('Column1_Year', 'Column1_Month', 'Column1_Day');
        nq = foreach q generate 'Column1_Year' + "/" + 'Column1_Month' + "/" + 'Column1_Day' as 'Column1_Year~~~Column1_Month~~~Column1_Day', count() as 'count';
        nq = order q by 'Column1_Year~~~Column1_Month~~~Column1_Day' asc;nq = limit q 1;",

※コードを整形しています。

 
こちらはcell関数でstatic_1.selection(静的ステップ選択値)の持つメンバ名”range”の値を取得し、
asRange()関数でColumn1の範囲で検索するよう指定しています。
 
追記した文はそれぞれ
 

"filters" = filter q(検索条件)
"Column1" = "date('Column1_Year', 'Column1_Month', 'Column1_Day')" (検索対象の項目)
"{{cell(static_1.selection, 0, "value").asObject()}}" = by cell(static_1.selection, 0, "range")(検索値)

 
という対応関係になります。
 
これでバインドが完了です。
 

テキストウィジェットを編集する

 
テキストウィジェットのID「text_1」で検索します。
 

            "text_1": {
                "type": "text",
                "parameters": {
                    "text": "yyyy/mm/dd~yyyy/mm/dd",
                    "textAlignment": "center",
                    "textColor": "#091A3E",
                    "fontSize": 20,
                    "tooltip": ""
                }

 
“text”メンバを書き換えます。
 

"text": "{{column(_______1.result, ["Column1_Year~~~Column1_Month~~~Column1_Day"]).asObject()}} ~ {{column(________1.result, ["Column1_Year~~~Column1_Month~~~Column1_Day"]).asObject()}}"

 
column関数で検索結果の日付の値を取得し、asObject()関数でそのまま表示されるようにしています。
 
完成したものがこちらになります!
 

 
JSONファイルを編集するのは大変ですがハマると楽しいですね。😇
 
みなさんもぜひダッシュボードで遊んでみてください。😉
 
参考:Analytics バインド開発者ガイド

contact

ご相談・ご質問等ございましたら、お気軽にお問い合わせください。

翻訳