Azure DevOps 向けの OData Analytics クエリのガイドライン
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
拡張機能開発者は、Azure DevOps 用の Analytics に対する効率的な OData クエリを設計するために、この記事に記載されているガイドラインに従うことでメリットを得ることができます。 これらのガイドラインに従うと、クエリの実行時間とリソース消費に対するパフォーマンスが向上します。 これらのガイドラインに準拠していないクエリでは、レポートの待機時間が長い、許可されたリソース消費を超えるクエリ、サービスのブロックなど、パフォーマンスが低下する可能性があります。
Note
Analytics サービスは、すべての Azure DevOps Services で自動的に有効になり、運用環境でサポートされます。 Power BI の統合 Analytics サービスの OData フィード へのアクセスが一般公開されています。 お使いいただき、フィードバックをお寄せください。
使用可能なデータはバージョンによって異なります。 サポートされている最新バージョンが v2.0
され、最新のプレビュー バージョンが v4.0-preview
。 詳細については、 OData API のバージョン管理に関するページを参照してください。
Note
Analytics サービスは、Azure DevOps Server 2020 以降のすべての新しいプロジェクト コレクションに対して、運用環境で自動的にインストールされ、サポートされます。 Power BI の統合 Analytics サービスの OData フィード へのアクセスが一般公開されています。 お使いいただき、フィードバックをお寄せください。 Azure DevOps Server 2019 からアップグレードした場合は、アップグレード中に Analytics サービスをインストールできます。
使用可能なデータはバージョンによって異なります。 サポートされている最新バージョンが v2.0
され、最新のプレビュー バージョンが v4.0-preview
。 詳細については、 OData API のバージョン管理に関するページを参照してください。
Note
Analytics サービスは、Azure DevOps Server 2019 のプレビュー段階です。 プロジェクト コレクション 有効またはインストール できます。 Power BI 統合 Analytics Service の OData フィード へのアクセスはプレビュー段階です。 お使いいただき、フィードバックをお寄せください。
使用可能なデータはバージョンによって異なります。 サポートされている最新バージョンが v2.0
され、最新のプレビュー バージョンが v4.0-preview
。 詳細については、 OData API のバージョン管理に関するページを参照してください。
これらのガイドラインには、 DO、 CONSIDER、 AVOID、 、 DON'Tという用語が付いています。 Analytics によって適用される制限付きルールには、 [BLOCKED] プレフィックスが含まれています。 異なるソリューション間のトレードオフを理解する必要があります。 特定の状況では、1 つ以上のガイドラインに違反することを強制するデータ要件が存在する可能性があります。 このようなケースはまれです。 このような決定を行う明確で説得力のある理由を持っていることをお勧めします。
ヒント
このドキュメントに示されている例は、Azure DevOps Services URL に基づいています。 オンプレミスのバージョンでは置換を使用します。
https://{servername}:{port}/tfs/{OrganizationName}/{ProjectName}/_odata/{version}/
エラーと警告メッセージ
✔️ DO OData 応答の警告を確認する
実行する各クエリは、定義済みの一連のルールに対してチェックされます。 違反は、 @vsts.warnings
の後に OData 応答を返します。 クエリを改善する方法に関する現在の情報と状況依存の情報が提供されるため、これらの警告を確認します。
{
"@odata.context": "https://{OrganizationName}.tfsallin.net/_odata/v1.0/$metadata#WorkItems",
"@vsts.warnings": [
"The specified query does not include a $select or $apply clause which is recommended for all queries."
],
...
}
✔️ OData エラー メッセージを確認する
OData エラー ルールに違反するクエリでは、400 (無効な要求) 状態コードで応答が失敗します。 関連付けメッセージは、 @vsts.warnings
プロパティ内には表示されません。 代わりに、JSON 応答の message
プロパティにエラー メッセージが生成されます。
{
"error": {
"code": "0",
"message": "The query specified in the URI is not valid. The Snapshot tables in Analytics are intended to be used only in an aggregation."
}
}
制限
推奨
- ✔️ アクセスできるプロジェクトにクエリを制限する
- ✔️ 展開にアクセスできない可能性がある他のプロジェクトにデータが含まれる可能性がある場合は、
$expand
句内でプロジェクト フィルターを指定します - ✔️ クエリが使用制限を超えた場合に操作を待機または停止する
- ✔️ クエリがタイムアウトで失敗した場合に操作を待機または停止する
- ✔️ スナップショット テーブルを集計するときに、
groupby
句にDateSK
またはDateValue
列を含める - ✔️ フィルター句を使用してエンティティを明示的にアドレス指定する
- ✔️ エンティティ セット
WorkItemRevisions
使用して、特定の作業項目のすべてのリビジョンを読み込む - ✔️ 長いクエリにバッチ エンドポイントを使用する
- ✔️ 日付列でフィルター処理するときにタイム ゾーンを指定する
次の例を考えてみましょう
ブロック済み
- ❌ [ブロック]集計以外にスナップショット エンティティを使用しない
- ❌ [ブロック]エンティティ アドレス指定にリソース パスでエンティティ キーを使用しない
- ❌[ブロック]エンティティの
Revisions
を展開しないWorkItem
- ❌ [ブロック]個別の列にグループ化しない
- ❌ [ブロック]
countdistinct
集計を使用しない - ❌ [ブロック]複数のクエリを送信するためにバッチ エンドポイントを使用しない
- ❌ [ブロック]800 列を超えるクエリを使用しないでください
回避
✔️ アクセスできるプロジェクトにクエリを制限する
クエリがアクセス権を持たないプロジェクトのデータを対象とする場合、クエリは "Project access denied" メッセージを返します。 アクセス権を持っていることを確認するには、クエリを実行するすべてのプロジェクトに対して View analytics アクセス許可が [許可] に設定されていることを確認します。 詳細については、「 Analytics にアクセスするために必要なアクセス許可」を参照してください。
プロジェクトにアクセスできない場合は、次のメッセージが表示されます。
クエリ結果には、アクセス権のない 1 つ以上のプロジェクトのデータが含まれます。 1 つ以上のプロジェクト フィルターを追加して、'WorkItems' エンティティにアクセスできるプロジェクトを指定します。 $expandプロパティまたはナビゲーション プロパティを使用している場合は、それらのエンティティにプロジェクト フィルターが必要です。
この問題を回避するには、プロジェクト フィルターを明示的に追加するか、この記事で後述するようにプロジェクト スコープエンドポイントを使用します。
たとえば、次のクエリは、 {projectSK1}
および {projectSK2}
という名前のプロジェクトに属する作業項目をフェッチします。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=ProjectSK eq {projectSK1} or ProjectSK eq {projectSK2}
&$select=WorkItemId, Title
✔️ 展開にアクセスできない可能性がある他のプロジェクトにデータが含まれる可能性がある場合は、 $expand
句内でプロジェクト フィルターを指定します
ナビゲーション プロパティを展開すると、アクセスできない他のプロジェクトのデータを参照する可能性があります。 アクセスできないデータを参照すると、前に示したエラー メッセージと同じエラー メッセージが表示されます。 "クエリ結果には、1 つ以上のプロジェクトのデータが含まれます。.." が表示されます。 同様に、展開されたデータを制御する明示的なプロジェクト フィルターを追加することで、この問題を解決できます。
これは、単純なナビゲーション プロパティの通常の $filter
句で行うことができます。 たとえば、次のクエリでは、リンクとそのターゲットの両方が同じプロジェクト内に存在する WorkItemLinks
を明示的に要求します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemLinks?
$filter=ProjectSK eq {projectSK} and TargetWorkItem/ProjectSK eq {projectSK}
&$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
&$expand=TargetWorkItem($select=WorkItemId, Title)
代わりに、$expand
句でフィルター$filter
展開オプションに移動できます。 ただし、クエリのセマンティックが変更されます。 たとえば、次のクエリは、特定のプロジェクトからすべてのリンクを取得し、条件に応じてターゲットが同じプロジェクトに存在する場合にのみ展開します。 有効ですが、この方法では、プロパティが null
またはフィルターで除外されたために、プロパティが展開されていないかどうかを判断するのが難しい場合があるため、混乱を招く可能性があります。この特定の動作が本当に必要な場合にのみ、このソリューションを使用してください。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemLinks?
$filter=ProjectSK eq {projectSK}
&$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
&$expand=TargetWorkItem($filter=ProjectSK eq {projectSK}; $select=WorkItemId, Title)
$filter
展開オプションは、エンティティ セットでChildren
などの展開コレクション プロパティWorkItems
使用する場合に便利です。 たとえば、次のクエリは、特定のプロジェクトのすべての作業項目と、同じプロジェクトに属するすべての子を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=ProjectSK eq {projectSK}
&$select=WorkItemId, Title
&$expand=Children($filter=ProjectSK eq {projectSK}; $select=WorkItemId, Title)
次のいずれかのプロパティを展開する場合は、フィルターを指定します。
WorkItems
エンティティ セット:Parent
、Children
WorkItemLinks
エンティティ セット:TargetWorkItem
。
✔️ プロジェクト スコープ エンドポイントを使用したクエリの検討
1 つのプロジェクトのデータに関心がある場合は、プロジェクト スコープの OData エンドポイント (/{ProjectName}/_odata/v1.0
) を使用することをお勧めします。 前の 2 つのセクションで説明した問題を回避し、1 つのプロジェクト、参照されるエンティティ セット、およびすべての展開されたナビゲーション プロパティに対して暗黙的にデータをフィルター処理します。
この簡略化により、前のセクションのクエリを次の形式に書き直すことができます。 expand 句のフィルターが消えただけでなく、メイン エンティティ セットにフィルターを適用する必要もありません。
https://analytics.dev.azure.com/{OrganizationName}/{ProjectName}/_odata/{version}//WorkItemLinks?
&$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
&$expand=TargetWorkItem($select=WorkItemId, Title)
作業項目の子のクエリも、はるかに短く簡単です。
https://analytics.dev.azure.com/{OrganizationName}/{ProjectName}/_odata/{version}//WorkItems?
&$select=WorkItemId, Title
&$expand=Children($select=WorkItemId, Title)
このソリューションは、フォーカスが 1 つのプロジェクトのデータである場合にのみ適用できます。 プロジェクト間レポートの場合は、前のセクションで説明したフィルター戦略を使用する必要があります。
✔️ クエリが使用制限を超えた場合に操作を待機または停止する
多数のクエリを実行する場合、またはクエリの実行に多くのリソースが必要な場合は、サービスの制限を超えて一時的にブロックされる可能性があります。 サービスの制限を超えた場合は、送信する次のクエリが同じエラー メッセージで失敗する可能性が高いので、操作を停止します。
名前空間 '{namespace}' のリソース '{resource}' の使用量を超えたため、要求がブロックされました。
レート制限の詳細については、「 レート制限」を参照してください。 効率的な OData クエリを設計する方法については、この記事で後述する パフォーマンス ガイドライン を参照してください。
✔️ クエリがタイムアウトで失敗した場合に操作を待機または停止する
使用制限の超過と同様に、クエリがタイムアウトになった場合は、操作を待機または停止する必要があります。 一時的な問題を通知する可能性があるため、1 回再試行して問題が解決するかどうかを確認できます。 ただし、永続的なタイムアウトは、クエリの実行にコストがかかりすぎる可能性があることを示します。 再試行を行うと、使用制限を超えるだけでブロックされます。
TF400733: 要求が取り消されました:要求が要求のタイムアウトを超えました。もう一度やり直してください。
タイムアウトは、クエリに最適化が必要であることを示します。 効率的な OData クエリを設計する方法については、この記事で後述する パフォーマンス ガイドライン を参照してください。
❌ [ブロック]集計以外にスナップショット エンティティを使用しない
Snapshot
サフィックスを持つスナップショット エンティティ セットは、daily スナップショットとしてモデル化されるため、特別です。 それらを使用して、過去の各日の終わりに存在していたエンティティの状態を取得できます。 たとえば、 WorkItemSnapshot
クエリを実行して 1 つの WorkItemId
にフィルター処理した場合、作業項目が作成されてから 1 日ごとに 1 つのレコードが取得されます。 このデータをすべて直接読み込むとコストが高くなり、使用制限を超え、ブロックされる可能性が最も高くなります。 ただし、これらのエンティティの集計はどちらも許可され、推奨されます。 実際、スナップショット エンティティ セットは集計シナリオを念頭に置いて設計されています。
たとえば、次のクエリでは、2020 年 1 月にどのように成長したかを確認するために、日付ごとの作業項目の数を取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemSnapshot?
$apply=
filter(DateSK ge 20200101 and DateSK le 20200131)/
groupby((DateSK), aggregate($count as Count))
集計の詳細については、「 Aggregate data」を参照してください。
✔️ スナップショット テーブルを集計するときに、groupby
句にDateSK
列またはDateValue
列を含める
すべてのスナップショット エンティティは daily スナップショット テーブルとしてモデル化されるためグループ化句には常に日のプロパティ (DateSK
または DateValue
) のいずれかを含める必要があります。 そうしないと、結果が正しく表示されない可能性があります。
たとえば、 WorkItemSnapshot
を AssignedTo
プロパティのみでグループ化し、カウントで集計した場合、ユーザーに割り当てられた作業項目のすべての数に、各割り当てがアクティブだった日数が乗算されます。 望む結果になる状況はありますが、そのようなケースはまれです。
❌ [ブロック]エンティティ アドレス指定にリソース パスでエンティティ キーを使用しない
OData 構文は、URL セグメントにキーを直接含めることで、特定のエンティティにアクセスする方法を提供します。 詳細については、 OData バージョン 4.0 を参照してください。パート 2: URL 規則 - 4.3 エンティティのアドレス指定。 OData ではこのようなアドレス指定が可能ですが、Analytics によってブロックされます。 クエリ内に含めると、次のエラーが発生します。
URI で指定されたクエリが無効です。 Analytics では、WorkItems(Id) や WorkItem(Id)/AssignedTo などのキーやプロパティのナビゲーションはサポートされていません。 PowerBI でそのエラーが発生した場合は、N+1 の問題を引き起こす正しくない折りたたみを避けるためにクエリを書き直してください。
エラー メッセージのヒントとして、特定のクライアント ツールが直接エンティティのアドレス指定を悪用する可能性があります。 このようなクライアントは、1 つの要求ですべてのデータを読み込む代わりに、エンティティごとに個別にクエリを実行することを選択できます。 要求の数が多くなる可能性があるため、この方法はお勧めしません。 代わりに、次のセクションで説明するように、明示的なエンティティ アドレス指定を使用することをお勧めします。
✔️ フィルター句を使用してエンティティを明示的にアドレス指定する
1 つのエンティティのデータをフェッチする場合は、エンティティのコレクションと同じ方法を使用し、 $filter
句でフィルターを明示的に定義する必要があります。
たとえば、次のクエリは、識別子によって 1 つの作業項目を取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=WorkItemId eq {id}
&$select=WorkItemId, Title
このようなフィルターに含める必要があるプロパティがわからない場合は、メタデータで検索できます。 「 Analytics の OData クエリを構成する」、メタデータに対してクエリを実行する URL コンポーネントを参照してください。 プロパティは、EntityType
のKey
要素にあります。 たとえば、 WorkItemId
と Revision
は、 WorkItemRevision
エンティティのキー列です。
<EntityType Name="WorkItemRevision">
<Key>
<PropertyRef Name="WorkItemId"/>
<PropertyRef Name="Revision"/>
</Key>
[...]
</EntityType>
❌[ブロック]WorkItem
エンティティでRevisions
を展開しない
Analytics データ モデルでは、特定の種類の拡張が許可されません。 そのうちの 1 つは、WorkItem
エンティティのRevisions
コレクション プロパティです。 このプロパティを展開しようとすると、次のエラー メッセージが表示されます。
URI で指定されたクエリが無効です。 プロパティ 'Revisions' は、$expand クエリ オプションでは使用できません。
この制限は、次のセクションで説明するように、 WorkItemRevisions
からリビジョンをフェッチする推奨ソリューションの使用をすべてのユーザーに促すために設定されました。
✔️ エンティティ セット WorkItemRevisions
使用して、特定の作業項目のすべてのリビジョンを読み込む
作業項目または作業項目のコレクションの完全な履歴をフェッチするたびに、 WorkItemRevisions
を使用します。
たとえば、次のクエリは、 {id}
識別子を持つ作業項目のすべてのリビジョンを返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemRevisions?
$filter=WorkItemId eq {id}
&$select=WorkItemId, Title
特定の条件に一致するすべての作業項目の完全な履歴を気にする場合は、 WorkItem
ナビゲーション プロパティのフィルターを使用して表します。 たとえば、次のクエリは、現在アクティブなすべての作業項目のすべてのリビジョンを取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemRevisions?
$filter=WorkItem/State eq 'Active'
&$select=WorkItemId, Title
❌ [ブロック]個別の列にグループ化しない
グループ化操作を使用して、レコードの数を減らします。 groupby
句で個別の列を使用すると問題が示され、クエリはすぐに失敗します。 この状況が誤って発生した場合は、次のエラー メッセージが表示されます。
このクエリの groupby 句で指定された 1 つ以上の列は推奨されません。
この問題を解決するには、 groupby
句から個別の列を削除します。
❌ [ブロック] countdistinct
集計を使用しない
OData ではサポートされていますが、Analytics では countdistinct
関数はサポートされません。 今後サポートを追加する予定ですが、現時点では利用できません。 この関数を含むクエリは、次のエラー メッセージを返します。
集計とは異なるカウントを適用するクエリはサポートされていません。
❌ 算術オーバーフローが発生する可能性がある AVOID 集計
まれに、集計クエリで算術オーバーフローの問題が発生することがあります。 たとえば、作業項目エンティティの StackRank
など、合計を意図していない数値プロパティを合計すると発生する可能性があります。 OData Extension for Data Aggregation標準では、プロパティを別の型にキャストする方法が提供されないため、この問題を解決する唯一の方法は、問題のあるプロパティを集計から削除することです。
✔️ 長いクエリにバッチ エンドポイントを使用する
長いクエリで問題が発生する可能性があります。 特に、次の場合に問題が発生する可能性があります。
- 多くのユーザー設定フィールドを使用してプロジェクトにクエリを実行します。
- クエリはプログラムによって構築されます。
HTTP GET
で送信される OData クエリの現在の制限は 3,000 文字です。 この値を超えると、"404 Not Found" 応答が返されます。
HTTP/1.1 404 Not Found
Content-Length: 0
この問題を解決するには、仕様「 OData バージョン 4.0」で説明されているように、OData バッチ エンドポイントを使用します。パート 1: プロトコル - 11.7 バッチ要求。 Batch 機能は、主に複数の操作を 1 つの HTTP
要求ペイロードにグループ化するように設計されましたが、クエリの長さの制限の回避策として使用することもできます。 HTTP POST
要求を送信することで、任意の長さのクエリを渡し、サービスがそれを正しく解釈できます。
❌ [ブロック]複数のクエリを送信するためにバッチ エンドポイントを使用しない
バッチ エンドポイントの使用は、複数の要求のバッチ処理から制限されます。 1 つの要求に含めることができるクエリは 1 つだけです。 複数のクエリのバッチを送信しようとすると、操作は失敗し、次のエラー メッセージが表示されます。 唯一の解決策は、クエリを複数の要求に分割することです。
Analytics では、現在のバッチ メッセージに含まれる複数の操作の処理はサポートされていません。 分析では、POST 要求をサポートするために OData バッチを使用しますが、操作を 1 つの要求に制限する必要があります。
❌ [ブロック]800 列を超えるクエリを使用しないでください
800 列を超えるクエリを制限します。 クエリで返される列が十分に選択されていない場合は、次のエラー メッセージが表示される可能性があります。
VS403670: 指定したクエリは、許容される 800 列の制限を超える 'N' 列を返します。 明示的な$select ($expand内を含む) オプションを使用して、列の数を制限してください。
$select句をクエリに追加し、クエリの操作を$expandして、この制限を超えないようにします。
❌ 長いクエリの作成を回避する
長いクエリを作成するたびに、アプローチを評価することをお勧めします。 長いクエリ (複雑なフィルターやプロパティの長いリストなど) が必要なシナリオは多数ありますが、通常は最適でない設計の早期インジケーターを提供します。
クエリに多数のエンティティ キー (たとえば、 WorkItemId eq {id 1} or WorkItemId eq {id 2} or ...
) が含まれている場合は、おそらくそれを書き換えることができます。 識別子を渡す代わりに、同じエンティティ セットを選択する他の条件を定義してみてください。 プロセスを変更する必要がある場合 (たとえば、新しいフィールドやタグを追加する)、通常は価値があります。 より抽象的なフィルターを使用するクエリは保守が容易になり、より適切に機能する可能性が高くなります。
長いクエリを生成する傾向があるもう 1 つのシナリオは、多数の個別の日付 (たとえば、 DateSK eq {dateSK 1} or DateSK eq {dateSK 2} or ...
) を含めると発生します。 より抽象的なフィルターを作成するために使用できる別のパターンを探します。 たとえば、次のクエリは、月曜日に作成されたすべての作業項目を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedOn/DayOfWeek eq 2
&$select=WorkItemId, Title, State
✔️ 日付列でフィルター処理するときにタイム ゾーンを指定する
タイム ゾーン (Edm.DateTimeOffset
) は、 organization のタイム ゾーン設定に一致するオフセットを持つすべての日時情報を公開します。 このデータは正確で簡単に同時に解釈できます。 もう 1 つの悪い結果は、すべてのフィルターがタイム ゾーン情報も渡す必要があるということです。 スキップすると、次のエラー メッセージが表示されます。
URI で指定されたクエリが無効です。 datetime オフセットが指定されませんでした。 オフセットを指定するには、次のいずれかの形式の YYYY-MM-ddZ を使用して、午前 0 時以降のすべてを指定するか、yyyy-MM-ddThh:mm-hh:mm (ISO 8601 標準の日付と時刻の表記) を指定してください。
この問題を解決するには、タイム ゾーン情報を追加します。 たとえば、"(UTC-08:00) 太平洋標準時 (米国およびカナダ)" タイム ゾーンにデータを表示するように組織が構成されている場合、次のクエリでは、2020 年初めから作成されたすべての作業項目が取得されます。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedDate ge 2020-01-01T00:00:00-08:00
&$select=WorkItemId, Title, State
正のオフセットを持つタイム ゾーンでも同じソリューションが機能しますが、プラス文字 (+
) は URI に特別な意味を持ち、正しく処理する必要があります。 開始点として 2020-01-01T00:00:00+08:00
( +
文字) を指定すると、次のエラーが発生します。
URI で指定されたクエリが無効です。 'CreatedDate ge 2020-01-01T0000 08:00' の位置 31 の構文エラー。
これを解決するには、 +
文字をエンコードされたバージョンの %2B
に置き換えます。 たとえば、組織が "(UTC+08:00) 北京、重慶、香港、ウルムチ" タイム ゾーンでデータを表示するように構成されていると仮定すると、次のクエリは、2020 年初めから作成されたすべての作業項目を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedDate ge 2020-01-01T00:00:00%2B08:00
&$select=WorkItemId, Title, State
別の方法として、タイム ゾーン情報を保持しないため、日付サロゲート キー プロパティを使用します。 たとえば、次のクエリは、組織の設定に関係なく、2020 年の初めから作成されたすべての作業項目を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedDateSK ge 20200101
&$select=WorkItemId, Title, State
パフォーマンスに関するガイドライン
推奨
- ✔️ パフォーマンス ガイドラインの実装の効果を測定する
- ✔️ 集計拡張機能を使用する
- ✔️
$select
句で列を指定する - ✔️
$expand
句内の$select
expand オプションで列を指定する - ✔️ 作業項目の履歴データ (
WorkItemRevisions
またはWorkItemSnapshot
エンティティ セット) を照会するときに、RevisedDateSK
にフィルターを定義する - ✔️ 長い期間にわたる傾向クエリには、週単位または月単位のスナップショットを使用してください
- ✔️ タグでフィルター処理するときに、作業項目
Tags
コレクション プロパティを使用する - ✔️ 作業項目のすべてのタグをテキストとして表示する場合は、
TagNames
プロパティを使用してください - ✔️ サーバー駆動型ページングを使用する
- ✔️ クエリ オプション
$top
使用してレコードの数を制限する
次の方法を使用しないでください。
- ❌ 大文字と小文字を区別しない比較を行うために
tolower
関数とtoupper
関数を使用しないでください - ❌ 無制限の拡張を使用しない
$levels=max
- ❌
$top
および$skip
クエリ オプションを使用してクライアント駆動型ページングを実装しないでください
次の例を考えてみましょう
- ✔️ 少数のレコードを返すクエリの記述を検討する
- ✔️ 選択したプロパティの数を最小に制限することを検討してください
- ✔️ 日付サロゲート キープロパティ (
DateSK
サフィックス) でのフィルター処理を検討する - ✔️ 代理キー列でのフィルター処理を検討する
- ✔️ ヘッダー
vsts.analytics.maxsize
優先設定を渡すことを検討してください
回避
✔️ パフォーマンス ガイドラインの実装の効果を測定する
パフォーマンスに関する推奨事項と同様に、それらを盲目的に実装しないでください。 代わりに、常にベースラインをキャプチャし、 変更の効果 確認します。 すべてのガイドラインは、特定の要件と課題を抱えている Analytics のクライアントとの対話に基づいて作成されました。 これらの推奨事項は一般的と見なされ、同様のクエリを設計するユーザーにとって役立つ可能性があります。 ただし、まれに、ガイドラインに従ってもパフォーマンスに影響を与えたり、悪影響を及ぼしたりする可能性があります。 それに気づくには、違いを測定する必要があります。 このような場合は、 Developer Community ポータルでフィードバックをお寄せください。
パフォーマンスを測定するオプションは多数あります。 最も簡単な方法は、2 つのバージョンの同じクエリをブラウザーで直接実行することです。 開発者ツールにかかった時間を確認します。 たとえば、Microsoft Edge F12 開発者ツール) の Network パネルを使用できます。 もう 1 つのオプションは、 Fiddler Web デバッガー ツールを使用してこの情報をキャプチャすることです。
方法が何であれ、両方のクエリを複数回実行します。 たとえば、クエリをそれぞれ 30 回実行して、十分に大きなサンプル セットを作成します。 次に、パフォーマンスの特性を把握します。 Analytics はマルチテナント アーキテクチャに従います。 そのため、同時に発生する他の操作は、クエリの期間に影響する可能性があります。
✔️ 集計拡張機能を使用する
クエリのパフォーマンスを向上させるために実行できる最善の方法は、集計拡張機能 ( OData Extension for Data Aggregation を使用することです。 集計拡張機能を使用して、サービスにデータ サーバー側を集計し、同じ関数クライアント側を適用してフェッチできる応答よりも小さい応答を返すように要求します。 最後に、Analytics はこの種類のクエリ用に最適化されているため、それを利用します。
詳細については、「 Aggregate data」を参照してください。
✔️ $select
句で列を指定する
$select
句で、注意する列を指定します。 Analytics は、 Columnstore Index テクノロジに基づいて構築されています。 つまり、データはストレージとクエリの両方の処理が列ベースです。 プロパティのセットを減らすことで、 $select
句で参照することで、スキャンする必要がある列の数を減らし、クエリの全体的なパフォーマンスを向上させることができます。
たとえば、次のクエリでは、作業項目の列を指定します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$select=WorkItemId, Title, State
Note
Azure DevOps では、プロセスのカスタマイズがサポートされています。 一部の管理者はこの機能を使用し、何百ものユーザー設定フィールドを作成します。 $select
句を省略すると、クエリはユーザー設定フィールドを含むすべてのフィールドを返します。
✔️ $expand
句内の $select
expand オプションで列を指定する
$select
句のガイドラインと同様に、$expand
句内の $select
expand オプションでプロパティを指定します。 忘れるのは簡単ですが、省略した場合、応答には展開されたオブジェクトのすべてのプロパティが含まれます。
たとえば、次のクエリでは、作業項目とその親の両方の列を指定します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$select=WorkItemId, Title, State
&$expand=Parent($select=WorkItemId, Title, State)
✔️ 作業項目の履歴データ (WorkItemRevisions
またはWorkItemSnapshot
エンティティ セット) を照会するときに、RevisedDateSK
にフィルターを定義する
履歴データのクエリを実行すると、最新の期間 (30 日、90 日など) に関心がある可能性があります。 作業項目エンティティの実装方法のため、このようなクエリを記述して優れたパフォーマンスを得るには便利な方法があります。 作業項目を更新するたびに、新しいリビジョンが作成され、このアクションが System.RevisedDate
フィールドに記録されるため、履歴フィルターに最適です。
Analytics では、変更後の日付が RevisedDate
(Edm.DateTimeOffset
) プロパティと RevisedDateSK
(Edm.Int32
) プロパティに表示されます。 パフォーマンスを最大限に高めるには、後者を使用します。 これは、 urrogate キーの日付であり リビジョンが作成された日付、またはアクティブで不完全なリビジョンに対して null
された日付を表します。 以降のすべての日付が必要な場合は {startDate}
、クエリに次のフィルターを追加します。
RevisedDateSK eq null or RevisedDateSK gt {startDateSK}
たとえば、次のクエリは、2020 年の初め以降の各日の作業項目の数を返します。 DateSK
列の明確なフィルターとは別に、RevisedDateSK
に 2 つ目のフィルターがあることに注意してください。 冗長に見えるかもしれませんが、クエリ エンジンがスコープ内にないリビジョンを除外し、クエリのパフォーマンスを大幅に向上させることができます。
https://analytics.dev.azure.com/{OrganizationName}/_odata/v1.0/WorkItemSnapshot?
$apply=
filter(DateSK gt 20200101)/
filter(RevisedDateSK eq null or RevisedDateSK gt 20200101)/
groupby(
(DateValue),
aggregate($count as Count)
)
Note
バーンダウン ウィジェットに取り組んでいたときに、この推奨事項を思い付きました。 最初は、 DateSK
に対してのみフィルターを定義しましたが、大規模なデータセットを持つ組織では、このクエリを適切にスケーリングできませんでした。 クエリ プロファイル中に、 DateSK
がリビジョンを適切にフィルター処理できないことに気付きました。 RevisedDateSK
にフィルターを追加して初めて、大規模なパフォーマンスを得ることができました。
~ 製品チーム
✔️ 長い期間にわたる傾向クエリには、週単位または月単位のスナップショットを使用してください
既定では、すべてのスナップショット テーブルは daily スナップショット ファクト テーブルとしてモデル化されます。 時間範囲に対してクエリを実行すると、各日の値が取得されます。 時間範囲が長い場合、多数のレコードが生成されます。 このような高精度が必要ない場合は、毎週または毎月のスナップショットを使用できます。
他のフィルター式でこれを行うと、特定の週または月が終了しない日を削除できます。 このシナリオを念頭に置いて Analytics に追加された IsLastDayOfPeriod
プロパティを使用します。 このプロパティは Microsoft.VisualStudio.Services.Analytics.Model.Period
型であり、1 日が異なる期間 (週、月など) で終了するかどうかを判断できます。
<EnumType Name="Period" IsFlags="true">
<Member Name="None" Value="0"/>
<Member Name="Day" Value="1"/>
<Member Name="WeekEndingOnSunday" Value="2"/>
<Member Name="WeekEndingOnMonday" Value="4"/>
<Member Name="WeekEndingOnTuesday" Value="8"/>
<Member Name="WeekEndingOnWednesday" Value="16"/>
<Member Name="WeekEndingOnThursday" Value="32"/>
<Member Name="WeekEndingOnFriday" Value="64"/>
<Member Name="WeekEndingOnSaturday" Value="128"/>
<Member Name="Month" Value="256"/>
<Member Name="Quarter" Value="512"/>
<Member Name="Year" Value="1024"/>
<Member Name="All" Value="2047"/>
</EnumType>
Microsoft.VisualStudio.Services.Analytics.Model.Period
はフラグを持つ列挙型として定義されているため、OData has
演算子を使用し、ピリオド リテラルの完全な型を指定します。
IsLastDayOfPeriod has Microsoft.VisualStudio.Services.Analytics.Model.Period'Month'
たとえば、次のクエリは、毎月の最終日に定義された作業項目の数を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemSnapshot?
$apply=
filter(IsLastDayOfPeriod has Microsoft.VisualStudio.Services.Analytics.Model.Period'Month')/
groupby(
(DateValue),
aggregate($count as Count)
)
✔️ タグでフィルター処理するときに、作業項目 Tags
コレクション プロパティを使用する
contains
関数で TagNames
プロパティを使用して、作業が特定のタグでマークされているかどうかを確認できます。 ただし、この方法では、特に複数のタグを同時にチェックする場合に、クエリが遅くなる可能性があります。 最適なパフォーマンスと結果を得るには、代わりに Tags
ナビゲーション プロパティを使用します。
たとえば、次のクエリは、 {tag}
でタグ付けされたすべての作業項目を取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=Tags/any(t:t/TagName eq '{tag}')
&$select=WorkItemId, Title, State
この方法は、複数のタグでフィルター処理する必要がある場合にも適しています。 たとえば、次のクエリは、 {tag1}
or でタグ付けされたすべての作業項目を返します {tag2}
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=Tags/any(t:t/TagName eq {tag1} or t/TagName eq {tag2})
&$select=WorkItemId, Title, State
これらのフィルターを "and" 演算子と組み合わせることもできます。 たとえば、次のクエリでは、 {tag1}
and の両方でタグ付けされたすべての作業項目が取得されます {tag2}
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=Tags/any(t:t/TagName eq {tag1}) and Tags/any(t:t/TagName eq {tag2})
&$select=WorkItemId, Title, State
✔️ 作業項目のすべてのタグをテキストとして表示する場合は、 TagNames
プロパティを使用してください
前のセクションで説明したナビゲーション プロパティ Tags
は、フィルター処理に適しています。 ただし、クエリが入れ子になったコレクション内のタグを返すので、それらを操作するといくつかの課題が発生します。 データ モデルには、 TagNames
プリミティブ プロパティ (Edm.String
) も含まれており、タグの使用シナリオを簡略化するために追加しました。 セミコロン "; " 区切り記号と組み合わせたすべてのタグの一覧を含む 1 つのテキスト値です。 このプロパティは、タグをまとめて表示する場合に使用します。 これは、前に説明したタグ フィルターと組み合わせることができます。
たとえば、次のクエリは、 {tag}
でタグ付けされたすべての作業項目を取得します。 作業項目 ID、タイトル、状態、および結合されたタグのテキスト表現が返されます。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=Tags/any(t:t/TagName eq '{tag}')
&$select=WorkItemId, Title, State, TagNames
重要
プロパティ TagNames
の長さの制限は 1024 文字です。 その制限内に収まるタグのセットが含まれています。 作業項目に多数のタグがある場合、またはタグが非常に長い場合は、 TagNames
完全なセットが含まれていないため、代わりに Tag
ナビゲーション プロパティを使用する必要があります。
❌ 大文字と小文字を区別しない比較を行うために tolower
関数と toupper
関数を使用しないでください
他のシステムで作業したことがある場合は、大文字と小文字を区別しない比較に tolower
または toupper
関数を使用することが予想される場合があります。 Analytics では、すべての文字列比較で既定では大文字と小文字が区別されないため、明示的に処理するために関数を適用する必要はありません。
たとえば、次のクエリは、"QUALITY"、"quality"、またはこの単語のその他のケースの組み合わせでタグ付けされたすべての作業項目を取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=Tags/any(t:t/TagName eq 'quality')
&$select=WorkItemId, Title, State, TagNames
❌ 無制限の拡張を使用しない $levels=max
OData には、階層構造のすべてのレベルを拡張する機能があります。 たとえば、作業項目の追跡には、無制限の拡張を適用できるエンティティがいくつかあります。 この操作は、少量のデータを持つ組織でのみ機能します。 大規模なデータセットに対しては適切にスケーリングされません。 次の場合は、まったく使用しないでください。
- 大規模なデータセットを操作しています。
- ウィジェットを開発していて、ウィジェットがインストールされる場所を制御できない。
✔️ サーバー駆動型ページングを使用する
1 つの応答で送信するには大きすぎるセットを要求すると、Analytics によってページングが適用されます。 応答には、部分セットと、次の項目の部分的なセットを取得できるリンクのみが含まれます。 この戦略については、OData 仕様 ( OData バージョン 4.0) で説明されています。パート 1: プロトコル - サーバー駆動ページング。 サービスがページングを制御できるようにすることで、 skiptoken
が各エンティティにできるだけ効率的に設計されているため、最高のパフォーマンスが得られます。
次のページへのリンクは、 @odata.nextLink
プロパティに含まれています。
{
"@odata.context": "https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/$metadata#WorkItems(*)",
"value": [
...
],
"@odata.nextLink":"https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?$skiptoken=12345"}
Note
ほとんどの既存の OData クライアントは、サーバー駆動型ページングを自動的に処理できます。 たとえば、この戦略は、Power BI、SQL Server Integration Services、Azure Data Factory の各ツールで既に使用されています。
❌$top
および$skip
クエリ オプションを使用してクライアント駆動型ページングを実装しないでください
他の REST API では、 $top
および $skip
クエリ オプションを使用してクライアント駆動型ページングを実装している可能性があります。 Analytics では使用しないでください。 このアプローチにはいくつかの問題があり、パフォーマンスはその 1 つです。 代わりに、前のセクションで説明したサーバー駆動型ページング戦略を採用してください。
✔️ クエリ オプション $top
使用してレコードの数を制限する
クエリ オプション $top
は、 $skip
と共に使用する場合にのみ推奨されます。 レポートのシナリオでレコードのサブセット (サンプルなど) のみが必要な場合は、クエリ オプション $top
使用しても問題ありません。 さらに、いくつかの条件に従ってレコードをランク付けする必要がある場合は、常に $top
を $orderby
と組み合わせて使用して、上位のランク付けされたレコードで安定した結果を得る必要があります。
✔️ 少数のレコードを返すクエリを記述することを検討してください
少数のレコードを返すクエリを記述することは、最も直感的なガイドラインです。 常に、本当に関心があるデータのみをフェッチすることを目指してください。 これを実現するには、OData クエリ言語で強力なフィルター処理機能を利用できるようにします。
✔️ 選択したプロパティの数を最小限に制限することを検討してください
一部のプロジェクト管理者は、カスタム フィールドを追加してプロセスを大幅にカスタマイズします。 カスタマイズが多いと、ワイド エンティティ ( WorkItems
など) で使用可能なすべての列をフェッチするときにパフォーマンスの問題が発生する可能性があります。 Analytics は、 Columnstore Index テクノロジに基づいて構築されています。 つまり、データはストレージとクエリの両方の処理が列ベースです。 そのため、クエリが参照するプロパティが多いほど、処理コストが高くなります。 常に、クエリ内のプロパティのセットを、レポートシナリオで本当に気にしているものに制限することを目指してください。
✔️ 日付サロゲート キープロパティ (DateSK
サフィックス) でのフィルター処理を検討する
日付フィルターを定義する方法は多数あります。 日付プロパティ (たとえば、 CreatedDate
)、対応するナビゲーション ( CreatedOnDate
など)、または代理キー表現 ( CreatedDate
など) を直接フィルター処理できます。 最後のオプションは、最適なパフォーマンスを実現し、レポート要件で可能な場合に推奨されます。
たとえば、次のクエリは、2020 年の初めから作成されたすべての作業項目を取得します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedDateSK ge 20200101
✔️ 代理キー列でのフィルター処理を検討する
関連オブジェクトの値 (プロジェクト名の作業項目のフィルター処理など) でデータをフィルター処理する場合は、常に 2 つの選択肢があります。 ナビゲーション プロパティ ( Project/ProjectName
など) を使用するか、 surrogate キーを事前にキャプチャして クエリで直接使用できます (たとえば、 ProjectSK
)。
ウィジェットを構築する場合は、後者のオプションを使用することをお勧めします。 キーがクエリの一部として渡されると、タッチする必要があるエンティティ セットの数が減り、パフォーマンスが向上します。
たとえば、次のクエリ フィルター WorkItems
ナビゲーション プロパティではなく、 ProjectSK
プロパティを使用 Project/ProjectName
。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=ProjectSK eq {projectSK}
❌$filter
句または $expand
句でParent
、Children
、またはRevisions
プロパティを使用しないようにする
作業項目は、データ モデル全体で最もコストの高いエンティティです。 関連する作業項目 ( Parent
、 Children
、 Revisions
) にアクセスするために使用できるナビゲーション プロパティがいくつかあります。 ただし、クエリ内でそれらを使用するたびに、パフォーマンスの低下が予想されます。 これらのプロパティのいずれかが本当に必要な場合は常に質問し、設計を更新する可能性があります。
たとえば、 Parent
を展開する代わりに、より多くの作業項目をフェッチし、 ParentWorkItemId
プロパティを使用して完全階層クライアント側を再構築できます。 このような最適化は、ケース バイ ケースで実行します。
✔️ ヘッダー VSTS.Analytics.MaxSize
優先設定を渡すことを検討してください
クエリを実行すると、クエリから返されるレコードの数がわかりません。 集計を使用して別のクエリを送信するか、次のすべてのリンクに従ってデータセット全体をフェッチします。 分析では、 VSTS.Analytics.MaxSize
優先設定が考慮されるため、データセットがクライアントが受け入れ可能なものよりも大きいインスタンスで高速に失敗できます。
このオプションは、データエクスポートのシナリオで役立ちます。 これを使用するには、HTTP 要求 Prefer
ヘッダーを追加し、 VSTS.Analytics.MaxSize
を負以外の値に設定する必要があります。 VSTS.Analytics.MaxSize
値は、許容できるレコードの最大数を表します。 0 に設定すると、既定値の 200 K が使用されます。
たとえば、次のクエリは、データセットが 1000 レコード以下の場合に作業項目を返します。
GET https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems HTTP/1.1
User-Agent: {application}
Prefer: VSTS.Analytics.MaxSize=1000
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Host: analytics.dev.azure.com/{OrganizationName}
データセットが 1000 レコードの制限を超えた場合、クエリはすぐに失敗し、次のエラーが発生します。
クエリ結果には 1,296 行が含まれており、許可される最大サイズが 1000 を超えています。 追加のフィルターを適用して、レコードの数を減らしてください
最大ページ サイズの設定については、「 ODataPreferenceHeader.MaxPageSize プロパティを参照してください。
クエリ スタイルのガイドライン
- ✔️ 集計メソッド
$count
仮想プロパティを使用する - ❌ URL セグメント
$count
仮想プロパティを使用しないようにする - ❌ 1 つのクエリで
$apply
句と$filter
句を混在させないようにする - ✔️ パラメーター エイリアスを使用してクエリの揮発性部分を分離することを検討する
- ✔️ OData 評価順序に一致するようにクエリを構造化することを検討してください
- ✔️ メタデータ注釈で説明されている OData 機能の確認を検討する
✔️ 集計メソッド $count
仮想プロパティを使用する
一部のエンティティは Count
プロパティを公開します。 データが別のストレージにエクスポートされる場合、一部のレポート シナリオが簡単になります。 ただし、OData クエリの集計では、これらの列を使用しないでください。 代わりに、 $count
仮想プロパティを使用してください。
たとえば、次のクエリは、作業項目の合計数を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$apply=aggregate($count as Count)
❌ URL セグメント $count
仮想プロパティを使用しないようにする
OData 標準ではエンティティ セット $count
仮想プロパティ ( _odata/v1.0/WorkItems/$count
など) を使用できますが、すべてのクライアントが応答を正しく解釈できるわけではありません。 そのため、代わりに集計を使用することをお勧めします。
たとえば、次のクエリは、作業項目の合計数を返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$apply=aggregate($count as Count)
✔️ パラメーター エイリアスを使用してクエリの揮発性部分を分離することを検討する
パラメーター エイリアスは、メイン クエリ テキストからパラメーター値などの揮発性の部分を抽出するエレガントなソリューションを提供します。 これらを評価する式で使用できます。
- プリミティブ値
- 複合値
- プリミティブ値または複合値のコレクション。
詳細については、 OData バージョン 4.0 を参照してください。パート 2: URL 規則 - 5.1.1.13 パラメーターエイリアス。 パラメーターは、ユーザーが指定した値でインスタンス化できるテンプレートとしてクエリ テキストを使用する場合に便利です。
たとえば、次のクエリでは、 @createdDateSK
パラメーターを使用して値をフィルター式から分離します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=CreatedDateSK ge @createdDateSK
&$select=WorkItemId, Title, State
&@createdDateSK=20200101
❌ 1 つのクエリで $apply
句と $filter
句を混在させないようにする
クエリに filter
を追加する場合は、2 つのオプションがあります。 $filter
句または$apply=filter()
の組み合わせで行うことができます。 これらのオプションはそれぞれ単独でうまく機能しますが、それらを組み合わせると予期しない結果が生じる可能性があります。
予想される場合でも、OData は評価の順序を明確に定義します。 また、 $apply
句は $filter
よりも優先されます。 このため、1 つまたは複数を選択する必要がありますが、1 つのクエリではこれら 2 つのフィルター オプションは使用しないでください。 クエリが自動的に生成される場合は重要です。
たとえば、次のクエリでは、最初に StoryPoint gt 5
によって作業項目がフィルター処理され、結果がパスによって集計され、最後に StoryPoints gt 2
によって結果がフィルター処理されます。 この評価順序では、クエリは常に空のセットを返します。
https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
$filter=StoryPoints gt 2
$apply=
filter(StoryPoints gt 5)/
groupby(
(Area/AreaPath),
aggregate(StoryPoints with sum as StoryPoints)
)
✔️ OData 評価順序に一致するようにクエリを構造化することを検討してください
1 つのクエリで $apply
句と filter
句を混在させると混乱が生じる可能性があるため、評価順序に合わせてクエリ句を構成することをお勧めします。
$apply
$filter
$orderby
$expand
$select
$skip
$top
✔️ メタデータ注釈で説明されている OData 機能の確認を検討する
Analytics でサポートされている OData 機能がわからない場合は、メタデータで注釈を検索できます。 TC GitHub リポジトリの OASIS Open Data Protocol (OData) 技術委員会では使用可能な注釈の一覧が保持されます。
たとえば、サポートされているフィルター関数の一覧は、エンティティ コンテナー Org.OData.Capabilities.V1.FilterFunctions
注釈で使用できます。
<Annotation Term="Org.OData.Capabilities.V1.FilterFunctions">
<Collection>
<String>contains</String>
<String>endswith</String>
[...]
</Collection>
</Annotation>
もう 1 つの便利な注釈は Org.OData.Capabilities.V1.ExpandRestrictions
であり、 $expand
句で使用できないナビゲーション プロパティについて説明します。 たとえば、次の注釈は、WorkItems
エンティティ セット内のRevisions
を展開できないことを説明しています。
<EntitySet Name="WorkItems" EntityType="Microsoft.VisualStudio.Services.Analytics.Model.WorkItem">
[...]
<Annotation Term="Org.OData.Capabilities.V1.ExpandRestrictions">
<Record>
<PropertyValue Property="Expandable" Bool="true"/>
<PropertyValue Property="NonExpandableProperties">
<Collection>
<NavigationPropertyPath>Revisions</NavigationPropertyPath>
</Collection>
</PropertyValue>
</Record>
</Annotation>
</EntitySet>