Share via


表形式モデル定義言語 (TMDL)

適用対象:SQL Server 2016 以降の Analysis Services Azure Analysis Services Fabric/Power BI Premium

重要

表形式モデル定義言語 (TMDL) は現在プレビュー段階です。 プレビュー段階では、機能とドキュメントが変更される可能性があります。

表形式モデル定義言語 (TMDL) は、互換性レベル 1200 以上の表形式データ モデルのオブジェクト モデル定義構文です。

TMDL の主な要素は次のとおりです。

  • 表形式オブジェクト モデル (TOM) 全体との完全な互換性。 すべての TMDL オブジェクトは、TOM と同じプロパティを公開します。
  • テキストベースで、人間との対話と読みやすさのために最適化されています。 TMDL では、YAML に似た文法構文が使用されます。 各 TMDL オブジェクトは、最小限の区切り記号でテキストで表され、インデントを使用して親子関係をマークします。
  • 編集エクスペリエンスが向上しました。特に、データ分析式 (DAX) や M など、さまざまなコンテンツ タイプの埋め込み式を含むプロパティに関するページ。
  • 各モデル オブジェクトが個々のファイル表現を持ち、ソース管理がわかりやすくなるため、共同作業に適しています。

TMDL の重要な側面は、TOM オブジェクト構造を示すために空白インデントを使用することです。 次の例は、TMDL を使用する場合に表形式モデルを表す方法を示しています。

database Sales
	compatibilityLevel: 1567	

model Model    
    culture: en-US    

table Sales
    
    partition 'Sales-Partition' = m
        mode: import
        source = 
            let
                Source = Sql.Database(Server, Database)
                …
    
    measure 'Sales Amount' = SUMX('Sales', 'Sales'[Quantity] * 'Sales'[Net Price])
        formatString: $ #,##0
   
    column 'Product Key'
        dataType: int64
        isHidden
        sourceColumn: ProductKey
        summarizeBy: None
 
    column Quantity
        dataType: int64
        isHidden
        sourceColumn: Quantity
        summarizeBy: None

    column 'Net Price'
        dataType: int64
        isHidden
        sourceColumn: "Net Price"
        summarizeBy: none

table Product
    
    partition 'Product-Partition' = m
        mode: import
        source = 
            let
                Source = Sql.Database(Server, Database),
                …

    column 'Product Key'
        dataType: int64
        isKey
        sourceColumn: ProductKey
        summarizeBy: none

relationship cdb6e6a9-c9d1-42b9-b9e0-484a1bc7e123
    fromColumn: Sales.'Product Key'
    toColumn: Product.'Product Key'

role Role_Store1
    modelPermission: read

    tablePermission Store = 'Store'[Store Code] IN {1,10,20,30}

expression Server = "localhost" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]

expression Database = "Contoso" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]

TMDL フォルダー構造

TMSL とは異なり、TMDL はフォルダー構造を使用します。 既定のフォルダー構造にはサブ フォルダーのレベルが 1 つだけあり、すべて .tmdl ファイルが含まれています。

  • cultures
  • パースペクティブ
  • roles
  • テーブル

次の ルート ファイル も含まれます。

  • database
  • model
  • relationships
  • datasources

TMDL フォルダーの例を次に示します。

モデルの TMDL 表現を含むフォルダー

定義には次のものが含まれます。

  • データベース定義用の 1 つのファイル。
  • モデル定義用の 1 つのファイル。
  • モデル 内のすべての データソースに対して 1 つのファイル。
  • モデル 内のすべての 式に対して 1 つのファイル。
  • モデル 内のすべての リレーションシップに対して 1 つのファイル。
  • カルチャ言語スキーマ ごとに 1 つのファイル。
  • パースペクティブごとに 1 つのファイル。
  • ロールごとに 1 つのファイル。
  • テーブルごとに 1 つのファイル。
  • テーブルのすべての内部メタデータ プロパティ (列、階層、パーティション,...) は、親テーブル TMDL ファイルに格納されます。

TMDL API

表形式モデル スクリプト言語 (TMSL) と同様に、TMDL シリアル化を処理するクラスがあります。 TMDL の場合、クラスは Microsoft.AnalysisServices.Tabular 名前空間の下にある TmdlSerializer です。

TmdlSerializer クラスは、TMDL ドキュメントをシリアル化および逆シリアル化するメソッドを公開します。

フォルダーのシリアル化

public static void SerializeDatabaseToFolder (Database database, string path)

  • TOM データベース オブジェクトと TMDL 出力パスを受け取ります。
  • TOM データベースを TMDL フォルダー表現にシリアル化します。

フォルダーにシリアル化する方法の詳細については、こちらを参照してください。

public static Database DeserializeDatabaseFromFolder (string path)

  • TMDL フォルダーへの完全なパスを受け取ります。
  • TMDL フォルダーの TOM データベース オブジェクト表現を返します。

フォルダーから逆シリアル化する方法の詳細については、こちらを参照してください。

文字列のシリアル化

public static string SerializeObject (MetadataObject object, bool qualifyObject = true)

  • TOM オブジェクトを受け取り、TMDL テキスト表現を返します。

オブジェクトを文字列にシリアル化する方法の詳細については、こちらを参照してください。

ストリームのシリアル化

TMDL をストリーム間でシリアル化/逆シリアル化できるため、TOM オブジェクトをバイト ストリームに変換して、プラットフォーム間でのストレージ、転送、相互運用性を実現できます。 Stream API を使用すると、どの TMDL ドキュメントを読み込み、どの TMDL ドキュメントを出力するかを制御することもできます。

TMDL ストリームのシリアル化は、 MetadataSerializationContext クラスによって処理されます。

ストリームを使用して TMDL 間でシリアル化する方法の詳細を確認してください。

TMDL 言語

オブジェクト宣言

Server オブジェクトを除き、TMDL は Microsoft.AnalysisServices.Tabular 名前空間内の TOM データベース オブジェクト ツリー全体を公開します。

TMDL オブジェクトは、TOM オブジェクトの種類とその名前を指定することによって宣言されます。 次のコード例では、各オブジェクトの種類は modeltablecolumn の後にオブジェクト名が続きます。

model Model    
    culture: en-US    

table Sales
    
    measure Sales = SUM(…)
        formatString: $ #,##0

    column 'Customer Key'
        datatype: int64
        sourceColumn: CustomerKey

measure などのpartitionオブジェクトにはオブジェクト宣言の同じ行または複数行の次の行で等しい (=) 区切り記号の後に割り当てることができる既定のプロパティがあります。

table Sales

    partition Sales-Part1 = m
        mode: import
        ...        
    
    measure Sales = SUM(…)
        formatString: $ #,##0

    measure 'Sales (ly)' = 
            var ly = ...
            return ly
        formatString: $ #,##0

TMDL オブジェクト名には、次のいずれかの文字が含まれている場合は、単一引用符 (') で囲む必要があります。

  • ドット (.)
  • 等しい (=)
  • コロン (:)
  • 単一引用符 (')
  • 空白文字 ( )

オブジェクト名に一重引用符 (') が含まれている場合は、2 つの単一引用符を使用してエスケープします。

オブジェクトのプロパティ

オブジェクト プロパティは、オブジェクト宣言またはオブジェクトの既定のプロパティの複数行式の後に指定されます。 オブジェクト プロパティの値は、コロン (:) 区切り記号の後に指定されます。 例:

table Sales
    lineageTag: e9374b9a-faee-4f9e-b2e7-d9aafb9d6a91    

    column Quantity
        dataType: int64
        isHidden
        isAvailableInMdx: false
        sourceColumn: Quantity

    measure 'Sales Amount' = 
            var result = SUMX(...)
            return result
  formatString: $ #,##0
  displayFolder: " My ""Amazing"" Measures"

プロパティ値には、次の規則が適用されます。

  • 値はコロンの後の同じ行に含まれている必要があり、複数行を含めることはできません。

  • Text プロパティの値

    • 先頭と末尾の二重引用符は省略可能であり、シリアル化中に自動的に削除されます。
    • テキストに末尾または先頭の空白文字が含まれている場合は、二重引用符 (") で囲む必要があります。
    • 二重引用符で囲んだ場合、値に二重引用符が含まれている場合は、2 つの二重引用符を使用してエスケープします (上記のコード例の プロパティを参照)。displayFolder
  • ブール型プロパティ は、前の例の プロパティと 'isAvailableInMdx' 同様に、標準のキー/値ペア構文を使用して設定できます。 プロパティ名のみが宣言され、暗黙的に指定される true ショートカット構文を使用して設定することもできます。 前の例の 'isHidden' プロパティを参照してください。

名前付きオブジェクト参照

一部のオブジェクト プロパティは、他のモデル オブジェクトへの参照を保持します。次に例を示します。

  • 階層レベルの列参照。
  • 各テーブル列の sortByColumn 参照。
  • パースペクティブのテーブル/列/メジャー参照。

TMDL では、参照はオブジェクト名を使用して作成され、オブジェクト宣言の同じエスケープと単一引用符 (') の外側の要件に従います。 次のコード例では、別のオブジェクトへの参照を保持するオブジェクト column.sortByColumnプロパティ 、 level.columnperspectiveMeasure.measure および perspectiveTable.tableが表示されます。


table Product

    column Category
        sortByColumn: 'Category Order'    

 hierarchy 'Product Hierarchy'

  level Category   
   column: Category  
 

perspective Product

 perspectiveTable Product

        perspectiveMeasure '# Products'

完全修飾名を参照する必要がある場合、TMDL は ドット 表記を使用してオブジェクトを参照します。次に例を示します。 'Table 1'.'Column 1'

子オブジェクト

TOM オブジェクト ツリーには、さまざまな場所と異なるレベルの子オブジェクトが含まれています。 例:

  • モデル オブジェクトには、テーブル、ロール、および式オブジェクトが含まれます。
  • テーブル オブジェクトには、列、メジャー、および階層オブジェクトが含まれます。

TMDL は子コレクションを明示的に宣言しません。 代わりに、それぞれの親のスコープ内のすべての適用可能な子要素が、対応するコレクションの要素を暗黙的に構成します。 たとえば、次に示すように、特定のテーブルのスコープ内のすべての列要素は、TOM のそのテーブルの列コレクションの要素になります。

table Sales

    measure 'Sales Amount' = SUMX('Sales', [Quantity] * [Net Price])

    measure 'Total Quantity' = SUM('Sales'[Quantity])

    measure 'Sales Amount YTD' = TOTALYTD([Sales Amount], 'Calendar'[Date])    

子オブジェクトは連続している必要はありません。 たとえば、列とメジャーを任意の順序で宣言し、混在させることができます。

既定のプロパティ

一部のオブジェクト型には、ほとんどの場合 、式のように扱われる既定のプロパティがあります。 既定のプロパティはオブジェクト型固有です。 該当する場合、プロパティの値または式は、セクション宣言の後に等しい (=) 区切り記号の後に指定されます。

サポートされている構文:

  • 値は、セクション ヘッダーと同じ行に指定されます。
  • 値は、セクション ヘッダーの後に複数行式として指定されます。

次のコード例では、メジャー Sales Amount とパーティション Sales-Partition1 は 1 行で、メジャー Quantity は複数行です。

table Sales

    measure 'Sales Amount' = SUM(...)
        formatString: $ #,##0

    measure Quantity = 
            var result = SUMX (...)
            return result
        formatString: #,##0

    partition Sales-Partition1 = m
  mode: import
  source =
   let
       ...
   in
       finalStep

TOM のテキスト プロパティである一方で、TMDL で特別な解析を行うオブジェクト プロパティがあります。 M 式や DAX 式に引用符や角かっこなどの特殊文字を含めることができるため、テキスト全体が逐語的に読み取られます。 式には、複数行または単一行を指定できます。 複数行の場合は、プロパティまたはオブジェクト宣言の直後の行に配置する必要があります。

TMDL の式の値は、次の例のように、等しい (=) 区切り記号の後に指定されます。

table Table1

    partition 'partition 1' = m
        mode: import
        source =
            let
            ...
            in
                finalStep
    
    measure Measure1 = SUM(...)

    measure Measure2 =
            var result = SUMX ( 
                ...
            )
            return result
        formatString: $ #,##0

式には、次の特殊な規則が適用されます。

  • 複数行の式は、親オブジェクトのプロパティの 1 レベル深くインデントする必要があり、式全体がそのインデント レベル内にある必要があります。
  • 外側のすべてのインデント空白文字は、親オブジェクトのインデント レベルを超えて削除されます。
  • 垂直方向の空白 (空白のない空白行) を使用でき、式の一部と見なされます。
  • 末尾の空白行と空白文字は削除されます。
  • 別のインデントを適用したり、末尾の空白行や空白を保持したりするには、3 つのバッククォーク (```) を囲むを使用します。
  • 既定では、TMDL シリアライザーは、式の値にラウンドトリップで変更を引き起こす可能性のあるもの (末尾の空白、空白の空白行など) が含まれている場合、バッククォークで囲みます。

3 つのバックティック (```) で囲まれた式は、インデント、空白行、空白文字など、逐語的に読み取られます。 区切り記号は、等号 (=) の直後と式の後の行に適用する必要があり、次の例のように、その後に何も含めることはできません。

table Table1

    partition partition1 = m
        mode: import
        source = ```
            let
            ...
            in
                finalStep

            ```

    measure Measure1 = ```
                var myVar = Today()
                …
                return result
            ```

3 つのバッククォーク (```) 区切り記号の使用は省略可能であり、一意の状況でのみ必要です。 ほとんどの場合、正しいインデントとオブジェクト宣言を使用すると、プロパティに追加する式が正しく解析されます。

式がバックティックス内で囲まれている場合は、次の規則が適用されます。

  • 3 つのバッククォーク (```) 間のすべてがマルチブロック式の一部と見なされ、TMDL インデント規則は適用されません。 終了区切り記号は、式内のインデントを決定します。
  • 式内の相対的なインデントは保持されます。 終了区切り記号 (```) は、式の左の境界を決定します (前の例の 'Measure1' を参照)。

次のプロパティは式として扱われます。

オブジェクトの型 プロパティ 式言語
メジャー DAX
MPartitionSource Expression M
CalculatedPartitionSource DAX
QueryPartitionSource クエリ NativeQuery
CalculationItem DAX
BasicRefreshPolicy SourceExpression、PollingExpression M
KPI StatusExpression、TargetExpression、TrendExpression DAX
LinguisticMetadata コンテンツ XML または Json
JsonExtendedProperty Json
FormatStringDefintion DAX
DataCoverageDefinition DAX
CalculationGroupExpression DAX
NamedExpression DAX
DetailRowsDefinition DAX
TablePermission FilterExpression DAX
CalculatedColumn DAX

オブジェクトの種類別の既定のプロパティ

次の表は、オブジェクトの種類別の既定のプロパティと式の言語を示しています。

オブジェクトの種類 既定のプロパティ 式言語
メジャー DAX
CalculatedColumn DAX
CalculationItem DAX
FormatStringDefinition DAX
DetailRowsDefinition DAX
CalculationExpression DAX
DataCoverageDefinition DAX
TablePermission FilterExpression DAX
ColumnPermission MetadataPermission MetadataPermission 列挙型
NamedExpression Expression M
MPartitionSource Expression M
CalculatedPartitionSource DAX
JsonExtendedProperty Json
Annotation Text
StringExtendedProperty Text
DataSource DataSourceType 列挙型
Partition SourceType PartitionSourceType 列挙型
ChangedProperty プロパティ プロパティ テキスト
ExternalModelRoleMember MemberType RoleMemberType 列挙型
任意のカスタム JSON プロパティ (DataAccessOptions など) JSON ドキュメント Json
LinguisticMetadata コンテンツ Json

説明

TMDL では、説明に対するファースト クラスのサポートが提供されます。 モデル ドキュメントの目的で、ベスト プラクティスは、TOM オブジェクトごとに説明を提供することです。 TMDL では、明示的な構文サポートを備えた特別なプロパティとして説明が扱われます。 他の多くの言語の例に従って、各オブジェクト宣言の上にトリプルスラッシュ (///) 構文を使用して説明を指定します。

description ブロックの末尾とオブジェクト型トークンの間に空白は使用できません。

説明は複数の行に分割できます。 TMDL シリアライザーは、オブジェクトの説明を複数行に分割して、出力されたドキュメント行を最大長で保持します。 既定の最大長は 80 文字です。

/// Table Description
table Sales

    /// This is the Measure Description
    /// One more line
    measure 'Sales Amount'' = SUM(...)
        formatString: #,##0

部分宣言

TMDL は、同じドキュメント内のオブジェクト宣言を強制しません。 ただし、複数のファイル間でオブジェクト定義を分割できる C# 部分クラス と同様です。 たとえば、[table].tmdl ファイルでテーブル定義を宣言し、次に示すように、すべてのテーブルのすべてのメジャーを 1 つの [measures].tmdl ファイルで定義できます。

table Sales

    measure 'Sales Amount' = SUM(…)
        formatString: $ #,##0

table Product

    measure CountOfProduct = COUNTROWS(…)

解析エラーを回避するために、同じプロパティを 2 回宣言することはできません。 たとえば、2 つの異なる TMDL ドキュメントで同じテーブルに対して同じ名前の 2 つのメジャーを宣言すると、エラーが発生します。

オブジェクト参照

ref キーワード (keyword)の後にオブジェクトの種類と名前を付けて、別の TMDL オブジェクトを参照できます。

たとえば、文字列シリアル化 API を使用して Column オブジェクトをシリアル化すると、結果は次のようになります。

ref table Table1
	column Column1
		datatype: int64
		sourceColumn: Column1

確定的なコレクションの順序付け

ref キーワード (keyword)は、TOM <> TMDL ラウンドトリップでのコレクション順序の定義と保持にも使用されます。 個々のファイル (テーブル、ロール、カルチャ、パースペクティブ) にシリアル化される TMDL オブジェクトのソース管理diffを回避することが特に重要です。 ref キーワード (keyword)は、親オブジェクト TMDL ファイルで使用され、TOM からの項目の順序付けを宣言します。


model Model

ref table Calendar
ref table Sales
ref table Product
ref table Customer
ref table About

ref culture en-US
ref culture pt-PT

ref role 'Stores Cluster 1'
ref role 'Stores Cluster 2'

次の規則が適用されます。

  • TMDL 逆シリアル化中:
    • TMDL で参照されているが、TMDL ファイルがないオブジェクトは無視されます。
    • オブジェクトは参照されず、既存の TMDL ファイルと共にコレクションの末尾に追加されます。
  • TMDL シリアル化中:
    • TOM のすべてのコレクション オブジェクトは、ref キーワード (keyword)を使用して参照されます。
    • 項目が 1 つだけのコレクションでは、ref は出力されません。
    • 同じオブジェクト型の場合、ref の間に空白行は出力されません。

プロパティ値の区切り記号

プロパティ値を割り当てる区切り記号/記号は 2 つだけです。

  • 等しい (=)

  • コロン (:)

    • 式以外のすべての プロパティ値に使用されます。 モデル参照を保持するプロパティを含む。

[インデント幅]

TMDL では、TOM 階層の構造を表すために、厳密な空白インデント規則が使用されます。 TMDL ドキュメントでは、既定の 1 つの タブ インデント規則が使用されます。

各オブジェクトには、次の 3 つのレベルのインデントを設定できます。

  • レベル 1 - オブジェクト宣言
    • レベル 2 - オブジェクトのプロパティ
      • レベル 3 - オブジェクト プロパティの複数行式

TMDL ドキュメント内では、次の場合にインデントが適用されます。

  • オブジェクト セクション ヘッダーとオブジェクトのプロパティ (テーブル -> プロパティ) の間。

    table Sales
        isHidden
        lineageTag: 9a48bea0-e5fb-40fa-9e81-f61288e31a02
    
  • オブジェクトとその子オブジェクト (テーブル -> メジャー) の間。

    table Sales
    
        measure 'Sales Amount' = SUMX(...)
    
        measure 'Total Quantity' = SUM(...)
    
  • オブジェクトとその複数行式 (テーブル - メジャー ->> 式) の間。

    table Sales
    
        measure 'Sales Amount' = 
                var result = SUMX(...)
                return result
            formatString: $ #,##0
    
  • 複数行式は、オブジェクト プロパティよりも 1 レベル深くインデントする必要があり、式全体がそのインデント レベル内にある必要があります ( を参照)。

Model のデータベース オブジェクトと直接子オブジェクトは、ルート Model または Database の下に暗黙的に入れ子になっていると想定されるため、インデントする必要はありません。

  • model
  • テーブル
  • 共有式
  • roles
  • cultures
  • パースペクティブ
  • relationships
  • データ ソース
  • クエリ グループ
  • モデル レベルの注釈
  • モデル レベルの拡張プロパティ

これらのインデント規則に従わないと、解析エラーが発生します。

空白

TMDL は、既定では、バッククォート () または二重引用符 (```") で囲まれていない場合に、プロパティと式の値内の空白に次の規則を適用します。

  • プロパティ値では、先頭と末尾の空白文字がトリミングされます。
  • 式では、式の末尾にある空白行が削除されます。
  • 空白行は空の行にトリミングされます (スペースやタブはありません)。

大文字小文字の区別

既定では、シリアル化/書き込み時の TMDL API では、 camelCase を使用し、次の対象に適用されます。

  • オブジェクトの型
  • キーワード
  • 列挙型の値

逆シリアル化/読み取りでは、TMDL API では大文字と小文字が区別されません。

考慮事項と制限事項

TMDL について理解したら、「 TMDL の概要 」を参照して、Power BI セマンティック モデルの TMDL モデル表現を取得してデプロイする方法を確認してください。