Lookerのfilterパラメーターを理解して、Looker Serverのパフォーマンスを最適化する
Lookerのパフォーマンスを最適化する
Optimize Looker Server Performance
LookMLで開発をするにあたり、最適解として使えるベストプラクティスが以下の記事にまとめられています。
記事の後半に、Optimize Looker Server Performanceという項があり、その中でconditionally_filter
やsql_always_where
を使用しすることでメモリをくわないようにする方法がベストプラクティスの一つとして推奨されています。
概要
ビジネスユーザーにフィルターをかけた状態でSQLを実行させる、という機能を持つパラメータがLookerでは、4つ用意されています。各場面で適材適所に配置するのには、各パラメーターの特徴を理解しておく必要があるので、それぞれのパラメータのできることとできないことを以下の表にまとめました。
conditionally_filter | always_filter | sql_always_where | access_filter | |
---|---|---|---|---|
フィルターする列の上書き | ○ | × | × | × |
フィルターする値の上書き | ○ | ○ | × | × |
適用するユーザー | 全ユーザー | 全ユーザー | 全ユーザー | ユーザー毎 |
それでは、それぞれのパラメーターの詳細を確認します。
conditionally_filter
公式ドキュメント
概要
ユーザーに2択を迫ります:filters: [・・・]
に記載されている値まで決められているフィルターを使うか、然もなくばunless:[・・・]
に記載されている値はユーザが設定できるフィルターを使うんだ!
This parameter is typically used to prevent users from accidentally creating very large queries that may be too expensive to run on your database.
と公式ドキュメントにもあるとおり、ユーザーがうっかり大きなクエリーを走らせてしまうことを防ぎます。
使ってみよう
まずは、modelファイルにconditionally_filter
を定義します。
explore: order_items { label: "(1) オーダー、アイテム、ユーザー関連" view_name: order_items view_label: "オーダー" conditionally_filter: { filters: [status: "プロセス中"] unless: [created_date] }
(1) オーダー、アイテム、ユーザー関連のExploreの画面を開くと、既に オーダー ステータス にプロセス中
のフィルターが設定されています。
次に、unless要素のcreated_date
をフィルターに設定すると、先ほどはなかった×印が オーダー ステータス フィルターの横に出現します。これで消せるようになりました。
また、filtersで指定しているフィルターする値はユーザーが変更することができます。
always_filter
公式ドキュメント
概要
conditionally_filterのunlessを使わないバージョン。ユーザーはこのフィルルターからも逃れることはできない。
If You Want to Use conditionally_filter without unless, Just Use always_filter Instead
上述の通り、conditionally_filterの公式ドキュメントにunlessを使わないなら、always_filterを使いましょうという記述があります。
使ってみよう
まずは、modelファイルにalways_filter
を定義します。
explore: order_items { label: "(1) オーダー、アイテム、ユーザー関連" view_name: order_items view_label: "オーダー" always_filter: { filters: [created_date: "last 90 days"] }
(1) オーダー、アイテム、ユーザー関連のExploreの画面を開くと オーダー 受注 Date に in the past 90 days
のフィルターが設定されています。
このフィルターは他のfieldをフィルターに加えても、消すことはできません。
ただ、フィルターの値を変えることはできます。
sql_always_filter
公式ドキュメント
概要
ユーザーは消せない、変えられない、逃れられない。
The restriction will be inserted into the WHERE clause of the underlying SQL that Looker generates, for all queries on the Explore where sql_always_where is used.
公式ドキュメントにはこのように記載があったので、always_filterはどうなのだろう?と思い、確認してみました。
sql_always_where
always_filter
どちらもwhere句が生成されていることが確認できます。
sql_always_where
の名前の通り、フィルターではないので、Exploreのフィルターに表示されない(=ユーザーは触ることすらできない)というのが特徴でしょうか。
平等の名の下に、全てのユーザーのクエリに等しく制限をかけたい場合に使用するというのがユースケースでしょうか。
使ってみよう
まずは、modelファイルにsql_always_where
を定義します。
explore: order_items { label: "(1) オーダー、アイテム、ユーザー関連" description: "あり!" view_name: order_items view_label: "オーダー" sql_always_where: ${status} = 'プロセス中' ;;
(1) オーダー、アイテム、ユーザー関連のExploreの画面を開くと通常通りのExplore画面が表示されます。
フィールドピッカーからいつもの通りfirldを選んで実行すると、
ステータスが「プロセス中」のものが返されます。
access_filter
公式ドキュメント
概要
sql_always_whereと同様、ユーザーは消せない、変えられない、逃れられない。
違いは、where句の条件をユーザー毎に設定できる点。
また、user_attributeの設定が必要な点も特徴的です。
使ってみよう
まず、user_attributeを作成します。
brand_accessというuser_attributeを作成して、自分に「Calvin Klein」というvalueを設定しました。
そして、modelファイルにaccess_filter
を定義します。
explore: order_items { label: "(1) オーダー、アイテム、ユーザー関連" view_name: order_items view_label: "オーダー" access_filter: { field: products.brand user_attribute: brand_access }
(1) オーダー、アイテム、ユーザー関連のExploreの画面を開くと通常通りのExplore画面が表示されます。(sql_always_whereと同様のため、画像は省略します。)
フィールドピッカーからbrandを選択して、SQLを表示させると、
フィルター部分で何も設定していないのに、brandがCalvin Kleinを返すSQLが生成されています。
この段階では自分にしかuser_attributeのvalueを設定していないので、他人になり代わった場合どのような動きをするのかを確認します。
画面上部の赤いラインが他人になり代わっているというお知らせなのですが、この場合、brandを選択してもwhere句がfalseになっているのがわかります。
access_filterはexploreのサブパラメーターのため、explore単位で定義する必要があります。細かな設定ができる = 細かな設定が必要ということですね。抜けがないようしっかりと設計する必要がありそうです。
検証するぞ
本当に逃げられないのか?諦めるのは早くないか?生きてさえいれば、自由になれるんじゃないか?
というのは、conditionally_filterの公式ドキュメントにはこのような記載があるのです。
There Is a Method to Apply conditionally_filter to a Subset of Users
やり方は、conditionally_filterを設定しているmodelと設定しないmodelの2つを用意して、ユーザー毎にどちらのmodelへアクセスするかを設定するだけ。(結構ややこしい)
まずは、conditionally_filterありmodelのみにアクセスを許可したrole(test_for_conditionally_filter_ari
)を作成します。
そして、テスト用のユーザーにtest_for_conditionally_filter_ari
のみを付与します。
次に、conditionally_filterを設定しているmodelと設定しないmodelの2つを用意します。
conditionally_filterあり
conditionally_filterなし
どちらがありで、どちらがなしかを判別できるように、descriptionで「あり!」と「なし!」と定義しました。
そして、テスト用のユーザーになり代わってExploreへアクセスします。
あり!のExploreのみが表示され、
filter部分には、見づらいかもしれませんが、Conditionally Requiredと表示されています。
ここで本題、この秘技modelを分けちゃうよ!はconditionally_filterのドキュメントにしかその方法が記載されていないのですが、他のfilterでも同様のことができるのではないでしょうか?
今回は、sql_always_filter
で検証してみます。
まずはmodelファイルを書き換えます。(conditionally_filter -> sql_always_where)
explore: order_items { label: "(1) オーダー、アイテム、ユーザー関連" description: "あり!" view_name: order_items view_label: "オーダー" sql_always_where: ${status} = 'プロセス中' ;;
そして、先ほども使用したこのmodelのみにアクセス権のあるユーザーになり代わってExploreを表示させます。
先ほどと同様選択できるExploreが一つだけですが、filter部分に何も表示がありません。
フィールドピッカーから適当に選択してSQLを覗いてみると、
問題なく強制的にwhere句が出現しました。
この方法を使えば、対象を一部のユーザーにすることができますね。
まとめ
以上、filterパラメーターのご紹介でした。途中のどこかにも書きましたが、細かい設定ができる仕様になっており、権限と合わせて用法容量を正しく理解し、設定していく必要がありそうです。