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

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

表形式モデル定義言語 (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 ファイルが含まれています。

  • 文化
  • 視点
  • 役割
  • テーブル

次のルート ファイル します。

  • データベース
  • モデル
  • 関係
  • データソース

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 言語

オブジェクト宣言

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

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

model Model    
    culture: en-US    

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

    column 'Customer Key'
        datatype: int64
        sourceColumn: CustomerKey

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

table Sales

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

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

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

  • ドット (.)
  • Equals (=)
  • コロン (:)
  • 単一引用符 (')
  • 空白 ( )

オブジェクト名に一重引用符 (') が含まれている場合は、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.sortByColumnlevel.columnperspectiveMeasure.measureperspectiveTable.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 表現 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 表現 M
MPartitionSource 表現 M
CalculatedPartitionSource 表現 DAX
JsonExtendedProperty 価値 Json
注釈 価値 テキスト
StringExtendedProperty 価値 テキスト
DataSource 種類 DataSourceType 列挙型
分割 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 キーワードの後にオブジェクトの種類と名前を指定して、別の TMDL オブジェクトを参照できます。

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

ref table Table1
	column Column1
		datatype: int64
		sourceColumn: Column1

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

ref キーワードは、TOM <> TMDL ラウンドトリップでのコレクション順序の定義と保持にも使用されます。 テーブル、ロール、カルチャ、パースペクティブという個々のファイルにシリアル化される TMDL オブジェクトでは、ソース管理の相違を回避することが特に重要です。 親オブジェクト TMDL ファイルで ref キーワードを使用して、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 キーワードを使用して参照されます。
    • 項目が 1 つだけのコレクションでは、ref は出力されません。
    • 同じオブジェクト型の場合、ref の間に空白行は出力されません。

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

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

  • Equals (=)

    • 既定のプロパティ (複数行と 1 行) オブジェクト宣言で使用されます
    • partition.expression など、すべての 式プロパティで使用されます
  • コロン (:)

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

圧入

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

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

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

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

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

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

  • モデル
  • テーブル
  • 共有式
  • 役割
  • 文化
  • 視点
  • 関係
  • データ ソース
  • クエリ グループ
  • モデル レベルの注釈
  • モデル レベルの拡張プロパティ

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

空白

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

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

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

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

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

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