Skip to main content
このガイドは、/v1 を Power BI に読み込むためのエンドツーエンドの例です。Power Query (M) の接続パターン、/v1/activities 上に構築するスタースキーマのセマンティックモデル、増分更新、そして個人単位のフィッシング成果に reporting プレビューデータセットを使用するタイミングについて説明します。 例では、米国の本番ホスト (https://api.us-east-1.livingsecurity.ai/v1) を使用しています。EU の組織の場合は、Fn_FetchAll と Fn_GetJson の両方で https://api.eu-west-1.livingsecurity.ai/v1 を使用し、データソースの資格情報をそのホストにバインドしてください。リージョンを参照してください。 このガイドでは、API キーを使用して保存された Basic 資格情報を利用します。OAuth クライアントは必要ありません。資格情報の選択肢については認証を、アクセスとセットアップについては Developer Hub を参照してください。

この例の用途

次のような場合にご利用ください。
  • 正しいカーソルページネーションとレート制限時の再試行を用いて、/v1 の一覧エンドポイントを Power BI データセットに読み込む。
  • 「アクティブなエンティティ」や「アクティブなエンティティあたりのアクティビティ数」などのメジャーを、フラットなテーブルの件数集計ではなく、ディメンションを用いて構築するセマンティックモデルを作成する。
  • 増分更新を使用して、スケジュールされた Power BI の更新を、履歴全体の走査から小さな日次ウィンドウへと短縮する。
  • 適切なフィッシングの粒度を選択する。キャンペーンの合計 (運用) か、個人単位の結果と型付きイベント (レポートプレビュー) かを選びます。

前提条件

  • クエリに必要な権限を持つ API キー:
    • 運用の例: activity:read、entity:read、simulation:read。
    • レポートデータセットによる個人単位のフィッシング: reporting:read。 API キーを参照してください。
  • Power BI Desktop、またはセマンティックモデルを作成して更新をスケジュールできる Power BI / Fabric ワークスペース。

適切な粒度の選択

/v1 は、フィッシングに関して関連する 2 つのサーフェスを公開しています。これらは互換ではありません。 以下の Power BI のクエリ例では、運用ルート (/v1/simulations、/v1/simulations/{id}/results、/v1/activities、/v1/entities) を呼び出します。個人単位のフィッシングレポートには、以下の reporting プレビューファミリーを使用することを推奨します。reporting:read のみが付与されたキーでは、運用の /v1/simulation_results を呼び出すことはできません (API は 403 を返します)。

難易度スケール

シミュレーションの難易度は、/v1/simulations (difficulty_level)、/v1/simulation_results (difficulty_level)、/v1/activities プロパティ (difficulty_tier)、および /v1/reporting/simulation_events (difficulty_tier) 上の 1〜5 の整数です。1 が最も易しく、5 が最も難しいレベルです。アダプティブおよびプログレッシブのシミュレーションにはキャンペーンレベルの単一の値がないため、/v1/simulations.difficulty_level は null になりますが、結果上の受信者ごとの difficulty_level は設定される場合があります。従来の low/medium/high のエクスポートに対応付けるには、1–2 を low、3 を medium、4–5 を high として扱ってください。
ドキュメント化されていないダッシュボードのネットワーク呼び出しや、従来の厳選された /api/v1 Public API の概要に対して、新しい BI 連携を構築しないでください。Developer Hub の API キーを使用して、組織のリージョンの /v1 ホストに対して認証してください。リージョンを参照してください。

接続パターン (Power Query)

この例のすべてのクエリは、4 つのルールに基づいています。それぞれ、スタイル上の好みではなく、Power BI サービスによって強制されるものです。
動的な部分はすべて RelativePath と Query に含めてください。Web.Contents の最初の引数は、組織のリージョンの /v1 ルートで終わるリテラル文字列である必要があります。
  • US: https://api.us-east-1.livingsecurity.ai/v1
  • EU: https://api.eu-west-1.livingsecurity.ai/v1
呼び出し側はリソースのみを渡します ("v1/simulations" ではなく "simulations")。EU の組織に US のホストを貼り付けないでください。最初の引数を文字列連結で組み立てると、Power BI サービスはデータソースを静的に特定できず、クエリが Power BI Desktop で動作していても、スケジュールされた更新が「動的データソース」エラーで失敗します。
Power BI が /v1 データソースの資格情報を求めたら、Basic を選択し、API キーをユーザー名として貼り付けます。パスワードフィールドには x などのプレースホルダーを入力してください。API はこのフィールドを無視しますが、Power BI サービスは空のパスワードを拒否します。プレースホルダーのユーザー名にキーをパスワードとして指定する方法でも動作します。M に Authorization ヘッダーを追加しないでください。デスクトップでは動作しますが、キーがクエリファイルに埋め込まれ、スケジュールされた更新とも競合します。
GET /v1 は認証が必要です。有効なキーでは 200 を返し、キーがない場合は 401 を返します。データソースを …/v1 に向け、テストをスキップしないでください。有効なキーは保存され、失効したキーや不正な形式のキーはすぐに失敗します。以前の例では、ベースホストをデータソースとして使用し、GET / が常に 404 を返すためテストをスキップするよう案内していました。これらのモデルは …/v1 に向け直してください。
すべての /v1 一覧エンドポイントのデフォルトのページサイズは 25 です。デフォルトのままにすると、同じデータに対するリクエスト数が増加します。クエリ値はテキストである必要があるため、M では limit = 500 ではなく limit = "500" を使用してください。

共通のページネーション関数

この例のすべてのクエリは、null になるまで next_page_token を走査する単一の Fn_FetchAll を呼び出します (ページネーションを参照)。主な特長は次のとおりです。
  • 静的な /v1 ベース URL と、動的な RelativePath および Query。 スケジュールされた更新と資格情報のテストに必要です。
  • 上限付き再試行を伴う ManualStatusHandling = {429}。 この関数は、Power Query が公開している場合は Retry-After を読み取り、公開していない場合は 30 秒待機します。429 レスポンスが 5 回連続した場合は、更新がタイムアウトするまでループするのではなく、明示的なエラーで終了します。5xx は意図的に再試行されません。サーバーエラーは、部分的なデータセットを黙って生成するのではなく、表面化させる必要があるためです。
  • 60 秒の Timeout。 ページは通常 1 秒未満で応答するため、1 分間応答がない場合はリクエストが失敗していることを意味します。
  • Json.Document の前に Binary.Buffer。 バッファリングしない場合、マッシュアップエンジンがレスポンスストリームを複数回読み取ると、再リクエストすることがあります。
  • baseQuery は反復ごとに変更せずに渡されます。 ページトークンは、組織、資格情報、コントラクトバージョン、およびフィルターと並べ替えのフィンガープリントに紐付けられた、不透明で署名付きのカーソルです。走査の途中でフィルターを変更すると、1 ページ目からやり直されるのではなく、無効なトークンとして拒否されます。
Fn_FetchAll.pq — base and call shape

エンドポイントごとの型付きクエリ

Fn_FetchAll を使用するすべてのクエリは同じ形式に従います。エンドポイントを呼び出し、固定の列リストを射影し、object 判別子を削除し、更新容量のタイムゾーンによって日付メジャーが気付かないうちにずれることがないよう、タイムスタンプを datetimezone として型付けします。
Table.FromRecords で列リストを明示すると、エンドポイントが 0 行を返した場合でもスキーマが安定します。単なる Table.FromRecords({}) では列が 0 のテーブルになり、以降のすべてのステップで存在しないフィールドが原因で失敗します。

Excel

同じ Power Query (M) は、Excel の「データの取得と変換」でも実行できます。Power BI Desktop と同じエンジンです。セマンティックモデルではなく、ワークシートのテーブルが必要な場合に使用してください。 Windows 版 Excel (Microsoft 365、Excel 2024、2021、2019、または 2016) の場合:
  1. データ → データの取得 → その他のデータ ソースから → 空のクエリを選択します。
  2. Power Query エディターで、ホーム → アドバンストエディターを選択します。最初に Fn_FetchAll を貼り付け、そのクエリの名前を Fn_FetchAll に変更します (クエリ設定 → 名前、または [クエリ] ペインで右クリックして 名前の変更)。
  3. Fn_GetJson、続いて各レポートクエリについても同様に繰り返します。
  4. ホーム → 閉じて読み込む → 閉じて次に読み込む…を選択すると、データのインポートダイアログが開きます。Fn_FetchAll と Fn_GetJson (これらはテーブルではなく関数です) には接続の作成のみを選択します。ワークシートに表示したい各レポートクエリにはテーブルを選択します。
  5. 最初の更新時に Basic を選択し、API キーをユーザー名に、x などのプレースホルダーをパスワードに入力します。Excel はデータソース URL ごとに 1 つの資格情報を保存します。同じ /v1 ホストにアクセスする以降のクエリは、それを再利用します。
ブック内で初めてクエリを作成するとき、閉じて次に読み込む…がグレー表示になることがあります。その場合は閉じて読み込むを使用し、Excel でデータ → クエリと接続を選択して、クエリを右クリックし、読み込み先を選択してください。このケースについては Microsoft がこの手順を案内しています。
認証付きソースでは、Power Query から Living-Security-Version を送信できません。これは Power BI と同じ制限です。サービスアカウントを固定するか、クエリレコードで api_version を渡してください。コントラクトバージョンと保存された資格情報を参照してください。 すぐに使用できるレポートクエリ (列マッピングと、以前のプロバイダーのエクスポートとの相違点):

個人別コンプライアンス

個人 × 割り当ての粒度でのトレーニング受講登録。

メールフィッシングログ

イベント単位のフィッシングインタラクション (直近 12 か月)。

最も影響を受けやすいユーザー

個人単位の 12 か月分のクリック、資格情報、報告の集計。

レポートプレビューデータセット (個人単位のフィッシング)

レポートプレビューファミリーは、個人単位のフィッシング用のデータセットを提供します。reporting:read と、組織に対するレポートアクセスが必要です。以下のデータセットカタログを使用して、スキーマとデータポリシーを確認してください。 ライブカタログを確認するには:
各データセットには、粒度、主キー、結合、ウォーターマーク、訂正ポリシー、削除ポリシーが宣言されています。

simulation_results

  • パス: GET /v1/reporting/simulation_results
  • 粒度: エンティティ × シミュレーション
  • フィルター: simulation、entity、updated_after、および limit / page_token
  • ワイヤーオブジェクト: reporting.simulation_result
  • 結合キー: entity_id、simulation_id
ReportingSimulationResults.pq (sketch)
最近のパーティションを更新する際は、updated_after を下限を含むウォーターマークとして使用します。変更可能な結果ディメンションは、同じ id の下でその場で再表現されます。

simulation_events

  • パス: GET /v1/reporting/simulation_events
  • 粒度: 観測されたインタラクションごとに 1 つの型付きファクト
  • フィルター: simulation、entity、event_type、occurred_after、および limit / page_token
  • ワイヤーオブジェクト: reporting.simulation_event
  • イベントタイプ: simulation.delivered、simulation.opened、simulation.link_clicked、simulation.credentials_submitted、simulation.reported などの閉じた公開トークン。生の ClickHouse の phishing.simulation.* アクティビティタイプではありません
  • デバイス: device_type は導出されたクラスです (観測されるトークンには desktop、mobile、tablet、unknown があります)。生の user_agent は /v1 には含まれません。生の IP は /v1 には決して含まれません (永続化されず、ソルト付きの ip_hash のみ)。
ReportingSimulationEvents.pq (sketch)
増分イベント読み込みには occurred_after を使用します。ファクトは追加専用であり、遅れて到着したデータは新しい行になります。

entities

  • パス: GET /v1/reporting/entities
  • 粒度: エンティティごとに現在の 1 行
  • フィルター: type、updated_after、および limit / page_token
  • ワイヤーオブジェクト: reporting.entity
  • 結合キー: id / entity_id (同じ値)
フィッシングのファクトを個人と結合するには、reporting.simulation_results.entity_id = reporting.entities.id を使用します。運用の GET /v1/entities は entity:read に残り、権限が異なります。
ReportingEntities.pq

entity_versions と cohort_memberships

これら 2 つのデータセットには、現在の状態のみを提供するという例外が明示されています。
権威あるバージョン履歴テーブルまたはメンバーシップ履歴テーブルは存在しません。このデータセットは、現在の行を終了日のない 1 つの区間として投影します (valid_to は null、is_current は true)。valid_from は、エンティティバージョンでは created_at、それがなければ updated_at であり、コホートメンバーシップではリクエストの観測時刻です。終了済みの過去の区間は作成されません。
  • entity_versions: GET /v1/reporting/entity_versions。フィルターは entities と同じです。valid_from は created_at、それがなければ updated_at です。両方のタイムスタンプが null のエンティティは除外されます。
  • cohort_memberships: GET /v1/reporting/cohort_memberships。フィルター: cohort、entity、updated_after。updated_at はコホートの最終更新であり、増分更新の整合性が保たれます。valid_from はリクエストの観測時刻です。entity_id を reporting.entities.id に結合します。
ReportingEntityVersions.pq
ReportingCohortMemberships.pq

/v1/activities 上のスタースキーマセマンティックモデル

/v1/activities は、組織のタイムスタンプ付きイベントストリームです。数値メジャーはなく、レポート内のすべての数量が行数であるため、スタースキーマが適しています。
  • Activities は、実際の粒度でのイベントファクトです。アクティビティごとに 1 行です。参加者はここから除外され、独自のテーブルとして再構築されます。
  • ActivityParticipants が存在するのは、参加者が actor や target などのロールを持つ、本質的に 1 対多の関係にあるためです。Activities 上でフラット化すると、アクティビティの行が重複して (すべてのカウントが水増しされて) しまうか、追加の参加者が失われてしまいます。Activities へのリレーションシップは、このモデルで唯一の双方向リレーションシップであり、エンティティのスライサーがファクトテーブルに到達できるようにします。
  • Entities は、参加者に名前を付けるディメンションです。アクティビティ上の参加者行には entity_id とロールはありますが、表示名はありません。
  • Dates は M で生成され (API 呼び出しはゼロ)、モデルの日付テーブルとして指定されます。これにより、DAX のタイムインテリジェンス (DATESINPERIOD、DATEADD) が使用可能になります。月名と曜日名の列は、ビジュアルで月がアルファベット順に並ばないよう、対応する数値列に sortByColumn を宣言しています。
すべてのメジャーは明示的です (モデルは discourageImplicitMeasures を設定しています)。アクティビティ合計、アクティブなエンティティ、アクティブなエンティティあたりのアクティビティ数、アクティビティのあった日数、および 7 日間の末尾日次平均があります。

ブリッジテーブルの構造

ActivityParticipants は /v1/activities を走査し、participants 配列を参加者ごとに 1 行へ展開します。
ActivityParticipants.pq
ActivityParticipants は、Activities クエリを参照するのではなく、/v1/activities を独立して走査します。Power BI では、2 つのテーブルとして読み込まれた 2 つのクエリは、更新時にそれぞれ独立して取得を行います。独立させておくことで、サービスは両方のテーブルのパーティションを並列に更新できます。

増分更新

2 つのファクト粒度のテーブル (Activities と ActivityParticipants) は、どちらも Power BI の増分更新ポリシーを宣言しています。年単位のパーティションを 5 年分保持し、更新のたびに直近 14 日分を再インポートします。 この仕組みは、RangeStart と RangeEnd という 1 組の DateTime パラメーターを使用します。Power BI サービスは、更新時にパーティションごとにこれらを再バインドします。各ファクトクエリは、これらのパラメーターを API の start_date および end_date フィルターに反映させるため、パーティション単位のリクエスト量は、履歴全体ではなくパーティションに比例します。このクエリは、API のウィンドウを両側に 1 分ずつ広げ、半開区間 [RangeStart, RangeEnd) の正確な境界をローカルで再適用します。これにより、サーバーが境界を包含として扱うか除外として扱うかに関係なく、パーティションの正確性が保たれます。
Activities.pq — the fold that makes incremental refresh work
デプロイ後の最初の更新でポリシーが適用され、履歴全体の読み込みが行われるため、時間がかかります。それ以降の更新では、増分ウィンドウのみが処理されます。 約 158,000 件のアクティビティと約 2,300 のエンティティのデータセットでの測定結果:
Power BI のクラシック更新 REST エンドポイント (notifyOption のみを指定した POST .../refreshes) は、更新ポリシーを黙って無視し、毎回全体を走査します。REST API 経由でポリシーを適用するには、拡張更新を使用し、本文に type、commitMode、applyRefreshPolicy を送信してください。Power BI サービスのスケジューラーによって開始される更新では常にポリシーが適用されます。この挙動は REST 呼び出しに固有のものです。
14 日間のウィンドウは、意図的に余裕を持たせています。アクティビティの取り込みは、現在時刻での追加のみではありません。コネクターのバックフィルにより、過去のタイムスタンプを持つイベントが到着します。1〜2 日のウィンドウでは、これらを恒久的に取りこぼします。

更新ウィンドウの API への反映

GET /v1/activities は、Power BI パラメーターが反映される start_date および end_date フィルターを受け付け、event_ts を境界の間でフィルタリングします。Entities はディメンションであるため、この例では増分ではなく毎回全件を更新します。 レポートデータセットでは、アクティビティの日付ウィンドウではなく、独自のウォーターマーク (updated_after、occurred_after) を使用します。

更新中のレート制限

/v1 は、キーごとと IP ごとに別々の予算を適用します (レート制限を参照)。429 + Retry-After に従い、リクエスト予算をモデルにハードコードしないでください。Power BI の更新に関して重要な点が 2 つあります。
  • 単一のテーブルの走査は逐次的です。 各ページリクエストには前のページのトークンが必要なため、ページサイズに関係なく、1 つのテーブルはレイテンシに制約されます。
  • テーブルの同時更新は負荷を増大させます。 複数の大きなテーブルを並列に更新すると上限に達するため、Fn_FetchAll の 429 再試行パスが重要になります。無制限の同時実行を前提とするのではなく、並列テーブル数を抑えることを推奨します。
この再試行は、実際に飽和したリミッターに対して検証されています。並列のワークロードが意図的にキーを上限に保っている間に実行された更新も、問題なく完了し、競合のないベースラインと同じ行数が得られました。再試行では、欠落のない完全なページが返されました。

コントラクトバージョンと保存された資格情報

/v1 は、公開されているコントラクトバージョンを固定するための Living-Security-Version リクエストヘッダーを受け付けます (API クイックスタートを参照)。データソースが保存された資格情報を使用している場合、Power Query はこのヘッダーを送信できません。カスタムヘッダーを使用できるのは匿名データソースのみです。追加すると、更新は次のエラーで失敗します。
キーは Power BI の保存された資格情報に保持し、カスタムヘッダーは省略してください。リクエストでバージョンを明示しない場合、API はサービスアカウントに固定された contract_version を使用し、固定が設定されていない場合は最新の公開バージョンを使用します。更新を公開する前に、API 管理者にアカウントのコントラクトバージョンを確認してください。サポートされているバージョンについては、API 変更履歴を参照してください。 更新の動作が予期しないものになった場合は、API の Living-Security-Version レスポンスヘッダーを確認して、実際にどのコントラクトがリクエストに応答したかを確認してください。

モデルの更新と検証

セマンティックモデルを Power BI ワークスペースに公開し、保存された資格情報をリージョンの /v1 ソースにバインドして、スケジュールを有効にする前に更新を実行してください。更新履歴を確認し、失敗や不完全な読み取りがないかを確認します。 同じフィルターを使用した独立した API の読み取り結果と、行数を照合してください。ページネーションガイドには、完全な結果セットを読み取るための Python と cURL の例が記載されています。最初のページのみを読み取る更新は、小さなデータセットでは成功したように見えることがあります。レポートを信頼する前に件数を比較してください。

モデルの選択

  • キャンペーンの合計と個人単位の結果では、粒度が異なります。 SimulationResults は GET /v1/simulations/{id}/results を呼び出します (実行ごとに 1 回の GET)。個人単位のフィッシングには、GET /v1/reporting/simulation_results および GET /v1/reporting/simulation_events のクエリを追加します (すでに simulation:read をお持ちの場合は、運用の GET /v1/simulation_results でも可)。
  • /v1/simulations 上の vectors は、カンマ区切りの文字列にフラット化されます。 リスト型の列は、実際のディメンションとしてスライスできません。レポートページでベクトルによるフィルタリングが必要な場合は、シミュレーションとベクトルのブリッジテーブルを追加してください。

次のステップ

Developer Hub

Power BI 用のサービスアカウントと API キーを作成します。

API クイックスタート

Basic 認証で /v1 リクエストを認証します。

ページネーション

一覧のエンベロープ、カーソルトークン、走査中のフィルターの安定性。

レート制限

キーごとおよび IP ごとの予算、429 の契約、再試行のガイダンス。