【MarkLogic Server】MarkLogic9の新機能TDEを使ってみた

はじめに
===
MarkLogicを利用していると、データベースに格納したデータをSQLで参照したい場合があります。
今回はMarkLogic9の新機能であるTDEを使ってみたので紹介します。

TDEとは
===
TDE（Template Driven Extraction）とは、MarkLogicに格納されている非構造化データに対してRDBのような表形式のビューに変換することで、RDBのように検索することができる機能です。
テンプレートと呼ばれる表形式のビューに変換するルールをXML形式またはJSON形式で作成します。
テンプレートを作成し、スキーマデータベースへテンプレートを挿入することでビューが作成され、行やトリプルが生成できます。
１つのスキーマに対して一意のビューを作成できます。また、スキーマが異なる場合、同名のビューをそれぞれのスキーマに作成することができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/4102d040-01be-55ad-19e1-279a68a87f2b.png)

TDEについて詳しい内容は以下の公式ドキュメント参照ください。
・[https://docs.marklogic.com/guide/app-dev/TDE](https://docs.marklogic.com/guide/app-dev/TDE)
・[http://jp.marklogic.com/wp-content/uploads/2017/05/MarkLogic-Whitepaper-Whats-New-in-MarkLogic-9_ja_JP.pdf](http://jp.marklogic.com/wp-content/uploads/2017/05/MarkLogic-Whitepaper-Whats-New-in-MarkLogic-9_ja_JP.pdf)

TDEの使用例
===

テンプレートの使用例について説明します。

デフォルトでは、テンプレート１つに対して１つのビューが作成されます。
例えば、テンプレートを次のように定義します。
・対象ノードの値を指定した列に設定します。
・テンプレートで定義したノードがドキュメントに存在しない場合、そのドキュメントのビューを作成しません。

以下のドキュメントに対してテンプレートを適用します。

```documentA.xml
<ROOT>
  <ID>0001</ID>
  <NAME>TANAKA</NAME>
  <AGE>20</AGE>
</ROOT>
```

テンプレートは以下のように記載します。

```xml:テンプレート
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/ROOT</context>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>TEST_Schema</schema-name> 
      <!-- ビュー名 -->
      <view-name>TEST_View</view-name>
      <columns>
        <!-- ID -->
        <column>
          <name>ID_I</name>
          <scalar-type>string</scalar-type>
          <val>ID</val>
          <invalid-values>ignore</invalid-values>
        </column>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>NAME</val>
          <invalid-values>ignore</invalid-values>
        </column>
        <!-- 年齢 -->
        <column>
          <name>AGE_I</name>
          <scalar-type>string</scalar-type>
          <val>AGE</val>
          <invalid-values>ignore</invalid-values>
        </column>
      </columns>
    </row>
  </rows>
</template>
```

作成されるビューは以下の通りです。

| ID_I | NAME_I | AGE_I |
|---|---|---|
| 0001 | TANAKA | 20 |

また、テンプレートの設定により、複数のテンプレートから１つのビューを作成することもできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/de4118ce-aa38-9de1-c852-072295bc83ab.png)

上記の図ではテンプレートを次のように定義しています。
・複数のテンプレートで１つのビューを作成できるようにします。
・対象ノードの値を指定した列に設定します。
・テンプレートが適用されたドキュメントで定義されていない列についてはNullが設定されます。

テンプレートAとテンプレートBはそれぞれ以下のように記載します。

```xml:テンプレートA
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/ROOT</context>
　<!-- テンプレートを適用するディレクトリ（documentA.xmlの格納ディレクトリを指定） -->
  <directories>
    <directory>/CompanyA/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>TEST_Schema</schema-name> 
      <!-- ビュー名 -->
      <view-name>TEST_View</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- ID -->
        <column>
          <name>ID_I</name>
          <scalar-type>string</scalar-type>
          <val>ID</val>
          <nullable>true</nullable>
        </column>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>NAME</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>
```

```xml:テンプレートB
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/ROOT</context>
　<!-- テンプレートを適用するディレクトリ（documentB.xmlの格納ディレクトリを指定） -->
  <directories>
    <directory>/CompanyB/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>TEST_Schema</schema-name> 
      <!-- ビュー名 -->
      <view-name>TEST_View</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- ID -->
        <column>
          <name>ID_I</name>
          <scalar-type>string</scalar-type>
          <val>ID</val>
          <nullable>true</nullable>
        </column>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>NAME</val>
          <nullable>true</nullable>
        </column>
         <!-- 性別 -->
        <column>
          <name>SEX_I</name>
          <scalar-type>string</scalar-type>
          <val>SEX</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>
```

実施内容
====
2つのテンプレートを使用して1つのビューを作成します。
実施内容は以下の通りです。

１．ドキュメント（パターン１）のテンプレートを作成
　　１－１．テンプレートの作成
　　１－２．テンプレートを検証
　　１－３．テンプレートを適用
２．ドキュメント（パターン２）のテンプレートを作成
　　２－１．テンプレートの作成
　　２－２．テンプレートを検証
　　２－３．テンプレートを適用
３．SQLでビューを確認

実施環境は以下の通りです。

| 対象MarkLogicバージョン | 対象OS・バージョン |
|---|---|
|9.0-3.1|Windows7|

事前準備
====
実施に必要なデータベースの作成とドキュメントの追加を行います。
TDEのテンプレートはスキーマデータベースに格納されるため、スキーマデータベースも作成します。

### データベース作成
MarkLogicの管理画面よりデータベースを作成します
データベース名とフォレスト名は以下で作成します。

| データベース名 | フォレスト名 |
|---|---|
| TDE_Database | TDE_DBForest|

１．「Configure」→「Databases」に遷移
２．「Create」タブをクリック
３．「triple index」がtrueに設定されていることを確認
４．「database name」に「TDE_Database」を入力し「OK」ボタンをクリック
５．「Database->Forests」のリンクをクリック
６．「Create a Forest」のリンクをクリック
７．「forest name」に「TDE_DBForest」と入力し「OK」ボタンをクリック
８．「Summary」タブをクリック
９．作成した「TDE_DBForest」フォレストのDatabaseを「TDE_Database」に設定し「OK」ボタンをクリック

### スキーマデータベース作成
MarkLogicの管理画面よりスキーマデータベースを作成します
データベース名とフォレスト名は以下で作成します。

| スキーマデータベース名 | フォレスト名 |
|---|---|
| TDE_SchemaDatabase | TDE_SDBForest |

１．「Configure」→「Databases」に遷移
２．「Create」タブをクリック
３．「database name」に「TDE_SchemaDatabase 」を入力し「OK」ボタンをクリック
４．「Database->Forests」のリンクをクリック
５．「Create a Forest」のリンクをクリック
６．「forest name」に「TDE_SDBForest 」と入力し「OK」ボタンをクリック
７．「Summary」タブをクリック
８．作成した「TDE_SDBForest 」フォレストのDatabaseを「TDE_SchemaDatabase 」に設定し「OK」ボタンをクリック
９．「Configure」→「Databases」→「TDE_Database」に遷移
１０．「schema database」で「TDE_SchemaDatabase 」を選択し「OK」ボタンをクリック

### ドキュメント（パターン１）
以下のXMLドキュメントをデータベースに追加します。

```xml:/CompanyA/document_A.xml
<?xml  version="1.0" encoding="UTF-8"?>
<root>
  <!-- ID -->
  <ID>0001</ID>
  <!-- 名前（姓） -->
  <LAST_NAME>田中</LAST_NAME>
  <!-- 名前（名） -->
  <FIRST_NAME>太郎</FIRST_NAME>
  <!-- 年齢 -->
  <AGE>20</AGE>
  <!-- 住所 -->
  <ADDRESS>東京都台東区上野 ABCアパート</ADDRESS>
</root>
```
クエリコンソール画面から以下のXQueryを実行します。

```
xquery version "1.0-ml";

let $xmlData := 
<root>
  <!-- ID -->
  <ID>0001</ID>
  <!-- 名前（姓） -->
  <LAST_NAME>田中</LAST_NAME>
  <!-- 名前（名） -->
  <FIRST_NAME>太郎</FIRST_NAME>
  <!-- 年齢 -->
  <AGE>20</AGE>
  <!-- 住所 -->
  <ADDRESS>東京都台東区上野 ABCアパート</ADDRESS>
</root>

let $uri := "/CompanyA/document_A.xml"

return xdmp:document-insert($uri, $xmlData)
```


### ドキュメント（パターン２）
以下のXMLドキュメントをデータベースに追加します。

```xml:/CompanyB/document_B.xml
<?xml  version="1.0" encoding="UTF-8"?>
<root>
  <!-- 住所 -->
  <ADDRESS>千葉県佐倉市</ADDRESS>
  <items>
    <!-- データ1 -->
    <item>
      <!-- ID -->
      <ID>0004</ID>
      <!-- 名前 -->
      <NAME>千葉次郎</NAME>
      <!-- 性別 -->
      <SEX>男</SEX>
      <!-- アパート名 -->
      <APARTMENT_NAME>DEFアパート</APARTMENT_NAME>
    </item>
    <!-- データ2 -->
    <item>
      <!-- ID -->
      <ID>0007</ID>
      <!-- 名前 -->
      <NAME>臼井花子</NAME>
      <!-- 性別 -->
      <SEX>女</SEX>
      <!-- アパート名 -->
      <APARTMENT_NAME>GHIアパート</APARTMENT_NAME>
    </item>
  </items>
</root>
```
クエリコンソール画面から以下のXQueryを実行します。

```
xquery version "1.0-ml";

let $xmlData := 
<root>
  <!-- 住所 -->
  <ADDRESS>千葉県佐倉市</ADDRESS>
  <items>
    <!-- データ1 -->
    <item>
      <!-- ID -->
      <ID>0004</ID>
      <!-- 名前 -->
      <NAME>千葉次郎</NAME>
      <!-- 性別 -->
      <SEX>男</SEX>
      <!-- アパート名 -->
      <APARTMENT_NAME>DEFアパート</APARTMENT_NAME>
    </item>
    <!-- データ2 -->
    <item>
      <!-- ID -->
      <ID>0007</ID>
      <!-- 名前 -->
      <NAME>臼井花子</NAME>
      <!-- 性別 -->
      <SEX>女</SEX>
      <!-- アパート名 -->
      <APARTMENT_NAME>GHIアパート</APARTMENT_NAME>
    </item>
  </items>
</root>

let $uri := "/CompanyB/document_B.xml"

return xdmp:document-insert($uri, $xmlData)
```

作成したいビュー
===
今回、TDEを利用して作成したいビューは以下の通りです。

| スキーマ名 | ビュー名 |
|---|---|
| IntegratedInfo | PersonalInfo |

作成するビューの項目は以下の通りです。

| 項目名 | 説明 |
|---|---|
| NAME_I | 名前（姓+名）を設定します。 |
| AGE_I | 年齢を設定します。 |
| ADDRESS_I | 住所を設定します。アパート名がある場合は結合します。 |
| SEX_I | 性別を設定します。 |

実施手順
===
追加した２つのドキュメントは構造体が異なるため、テンプレートを２つ作成し１つのビューを作成します。
本手順はクエリコンソール画面上で行っています。

### １．ドキュメント（パターン１）のテンプレートを作成
ドキュメント（パターン１）のテンプレートを作成します。

#### １－１．テンプレートの作成
作成するビューの項目を確認すると、名前が姓と名で結合されているため、LAST_NAMEタグとFIRST_NAMEタグを結合して１つの項目にします。
不足している項目はドキュメント（パターン２）のテンプレートを作成することで追加されるため無視します。

テンプレートは以下のようになります。

```xml
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyA/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>IntegratedInfo</schema-name> 
      <!-- ビュー名 -->
      <view-name>PersonalInfo</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>fn:concat(LAST_NAME, FIRST_NAME)</val>
          <nullable>true</nullable>
        </column>
        <!-- 年齢 -->
        <column>
          <name>AGE_I</name>
          <scalar-type>integer</scalar-type>
          <val>AGE</val>
          <nullable>true</nullable>
        </column>
        <!-- 住所 -->
        <column>
          <name>ADDRESS_I</name>
          <scalar-type>string</scalar-type>
          <val>ADDRESS</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>
```

#### １－２．テンプレートを検証
tde:validate関数を利用して作成したテンプレートが正しい内容であるか確認します。
XQueryで以下のクエリを実行します。

```
xquery version "1.0-ml";

(: テンプレート :)
let $template_pattern1 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyA/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>IntegratedInfo</schema-name> 
      <!-- ビュー名 -->
      <view-name>PersonalInfo</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>fn:concat(LAST_NAME, FIRST_NAME)</val>
          <nullable>true</nullable>
        </column>
        <!-- 年齢 -->
        <column>
          <name>AGE_I</name>
          <scalar-type>integer</scalar-type>
          <val>AGE</val>
          <nullable>true</nullable>
        </column>
        <!-- 住所 -->
        <column>
          <name>ADDRESS_I</name>
          <scalar-type>string</scalar-type>
          <val>ADDRESS</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>


(: テンプレートの検証 :)
return tde:validate($template_pattern1)
```
実行結果よりmap:valueタグの値がtrueであることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/9dbd047d-8aec-a334-1fad-fee504a3021b.png)

tde:node-data-extract関数を利用し、指定したドキュメントのリストから行データの抽出結果を確認します。

```
xquery version "1.0-ml";

(: テンプレート :)
let $template_pattern1 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyA/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>IntegratedInfo</schema-name> 
      <!-- ビュー名 -->
      <view-name>PersonalInfo</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>fn:concat(LAST_NAME, FIRST_NAME)</val>
          <nullable>true</nullable>
        </column>
        <!-- 年齢 -->
        <column>
          <name>AGE_I</name>
          <scalar-type>integer</scalar-type>
          <val>AGE</val>
          <nullable>true</nullable>
        </column>
        <!-- 住所 -->
        <column>
          <name>ADDRESS_I</name>
          <scalar-type>string</scalar-type>
          <val>ADDRESS</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>

(: テンプレート確認用データ :)
let $docs :=
(
  fn:doc("/CompanyA/document_A.xml"),
  fn:doc("/CompanyB/document_B.xml")
)
return tde:node-data-extract($docs, $template_pattern1)
```

上記のクエリを実行すると以下の結果となります。
「/CompanyA」配下のドキュメントにテンプレートが適用され、「/CompanyB」の配下のドキュメントにテンプレートが適用されていないことがわかります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/20307d73-b63f-b867-66ac-a7aa85682bec.png)

#### １－３．テンプレートを適用
作成したテンプレートをtde:template-insert関数を利用してデータベースに適用します。
テンプレートはスキーマデータベースに格納されますが、tde:template-insert関数はスキーマデータベースをアタッチしているデータベースに対して実行する必要があるので注意が必要です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/e92cc202-d54a-91e0-5726-1199983e18e9.png)

以下のクエリを実行します。

```
xquery version "1.0-ml";
import module "http://marklogic.com/xdmp/tde" at "/MarkLogic/tde.xqy";

(: テンプレート :)
let $template_pattern1 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyA/</directory>
  </directories>
  <rows> 
    <row>
      <!-- スキーマ名 -->
      <schema-name>IntegratedInfo</schema-name> 
      <!-- ビュー名 -->
      <view-name>PersonalInfo</view-name>
      <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
      <view-layout>sparse</view-layout>
      <columns>
        <!-- 名前 -->
        <column>
          <name>NAME_I</name>
          <scalar-type>string</scalar-type>
          <val>fn:concat(LAST_NAME, FIRST_NAME)</val>
          <nullable>true</nullable>
        </column>
        <!-- 年齢 -->
        <column>
          <name>AGE_I</name>
          <scalar-type>integer</scalar-type>
          <val>AGE</val>
          <nullable>true</nullable>
        </column>
        <!-- 住所 -->
        <column>
          <name>ADDRESS_I</name>
          <scalar-type>string</scalar-type>
          <val>ADDRESS</val>
          <nullable>true</nullable>
        </column>
      </columns>
    </row>
  </rows>
</template>

(: ビューを生成する :)
return tde:template-insert("/tde_統合_パターン１.xml", $template_pattern1)
```

スキーマデータベースにテンプレートが格納されていることを確認します（Databaseでスキーマデータベースを選択し「Explore」ボタンをクリックする）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/196a2076-e5c0-accb-92bf-f1af6cd3c778.png)

### ２．ドキュメント（パターン２）のテンプレートを作成
ドキュメント（パターン２）のテンプレートを作成します。

#### ２－１．テンプレートの作成
ドキュメント（パターン２）は１ドキュメントの中に複数データ設定されています。
そのため、templetesタグを利用して1データを1レコードとなるようテンプレートを作成します。
また、住所を変数で定義して利用してみます。

テンプレートは以下のようになります。

```xml
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- 変数を定義 -->
  <vars>
    <!-- 住所を格納する変数を定義 -->
    <var>
      <name>var_address</name>
      <val>./ADDRESS</val>
    </var>
  </vars>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyB/</directory>
  </directories>
  <templates>
    <template>
      <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード（/root以降のパスを指定） -->
      <context>items/item</context>
      <rows> 
        <row>
          <!-- スキーマ名 -->
          <schema-name>IntegratedInfo</schema-name> 
          <!-- ビュー名 -->
          <view-name>PersonalInfo</view-name>
          <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
          <view-layout>sparse</view-layout>
          <columns>
            <!-- 名前 -->
            <column>
              <name>NAME_I</name>
              <scalar-type>string</scalar-type>
              <val>NAME</val>
              <nullable>true</nullable>
            </column>
            <!-- 性別 -->
            <column>
              <name>SEX_I</name>
              <scalar-type>string</scalar-type>
              <val>SEX</val>
              <nullable>true</nullable>
            </column>
            <!-- 住所 -->
            <column>
              <name>ADDRESS_I</name>
              <scalar-type>string</scalar-type>
              <!-- 変数を使い住所とアパート名を結合する -->
              <val>fn:concat($var_address, " ", APARTMENT_NAME)</val>
              <nullable>true</nullable>
            </column>
          </columns>
        </row>
      </rows>
    </template>
  </templates>
</template>
```

#### ２－２．テンプレートを検証
tde:validate関数を利用して作成したテンプレートが正しい内容であるか確認します。
XQueryで以下のクエリを実行します

```
xquery version "1.0-ml";

let $template_pattern2 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- 変数を定義 -->
  <vars>
    <!-- 住所を格納する変数を定義 -->
    <var>
      <name>var_address</name>
      <val>./ADDRESS</val>
    </var>
  </vars>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyB/</directory>
  </directories>
  <templates>
    <template>
      <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード（/root以降のパスを指定） -->
      <context>items/item</context>
      <rows> 
        <row>
          <!-- スキーマ名 -->
          <schema-name>IntegratedInfo</schema-name> 
          <!-- ビュー名 -->
          <view-name>PersonalInfo</view-name>
          <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
          <view-layout>sparse</view-layout>
          <columns>
            <!-- 名前 -->
            <column>
              <name>NAME_I</name>
              <scalar-type>string</scalar-type>
              <val>NAME</val>
              <nullable>true</nullable>
            </column>
            <!-- 性別 -->
            <column>
              <name>SEX_I</name>
              <scalar-type>string</scalar-type>
              <val>SEX</val>
              <nullable>true</nullable>
            </column>
            <!-- 住所 -->
            <column>
              <name>ADDRESS_I</name>
              <scalar-type>string</scalar-type>
              <!-- 変数を使い住所とアパート名を結合する -->
              <val>fn:concat($var_address, " ", APARTMENT_NAME)</val>
              <nullable>true</nullable>
            </column>
          </columns>
        </row>
      </rows>
    </template>
  </templates>
</template>

(: テンプレートの検証 :)
return tde:validate($template_pattern2)
```
実行結果よりmap:valueタグの値がtrueであることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/9dbd047d-8aec-a334-1fad-fee504a3021b.png)

tde:node-data-extract関数を利用し、指定したドキュメントのリストから行データの抽出結果を確認します。

```
xquery version "1.0-ml";

let $template_pattern2 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- 変数を定義 -->
  <vars>
    <!-- 住所を格納する変数を定義 -->
    <var>
      <name>var_address</name>
      <val>./ADDRESS</val>
    </var>
  </vars>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyB/</directory>
  </directories>
  <templates>
    <template>
      <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード（/root以降のパスを指定） -->
      <context>items/item</context>
      <rows> 
        <row>
          <!-- スキーマ名 -->
          <schema-name>IntegratedInfo</schema-name> 
          <!-- ビュー名 -->
          <view-name>PersonalInfo</view-name>
          <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
          <view-layout>sparse</view-layout>
          <columns>
            <!-- 名前 -->
            <column>
              <name>NAME_I</name>
              <scalar-type>string</scalar-type>
              <val>NAME</val>
              <nullable>true</nullable>
            </column>
            <!-- 性別 -->
            <column>
              <name>SEX_I</name>
              <scalar-type>string</scalar-type>
              <val>SEX</val>
              <nullable>true</nullable>
            </column>
            <!-- 住所 -->
            <column>
              <name>ADDRESS_I</name>
              <scalar-type>string</scalar-type>
              <!-- 変数を使い住所とアパート名を結合する -->
              <val>fn:concat($var_address, " ", APARTMENT_NAME)</val>
              <nullable>true</nullable>
            </column>
          </columns>
        </row>
      </rows>
    </template>
  </templates>
</template>

(: テンプレート確認用データ :)
let $docs :=
(
  fn:doc("/CompanyA/document_A.xml"),
  fn:doc("/CompanyB/document_B.xml")
)
return tde:node-data-extract($docs, $template_pattern2)
```

上記のクエリを実行すると以下の結果となります。
「/CompanyB」配下のドキュメントにテンプレートが適用され、「/CompanyA」の配下のドキュメントにテンプレートが適用されていないことがわかります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/ac535820-8c47-5b1d-5f75-2a004cc7e1d3.png)


#### ２－３．テンプレートを適用
作成したテンプレートをtde:template-insert関数を利用してデータベースに適用します。
ドキュメント（パターン１）の時と同様、tde:template-insert関数はスキーマデータベースをアタッチしているデータベースに対して実行する必要があるので注意が必要です。

以下のクエリを実行します。

```
xquery version "1.0-ml";
import module "http://marklogic.com/xdmp/tde" at "/MarkLogic/tde.xqy";

let $template_pattern2 :=
<template xmlns="http://marklogic.com/xdmp/tde">
  <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード -->
  <context>/root</context>
  <!-- 変数を定義 -->
  <vars>
    <!-- 住所を格納する変数を定義 -->
    <var>
      <name>var_address</name>
      <val>./ADDRESS</val>
    </var>
  </vars>
  <!-- テンプレートを適用するディレクトリ -->
  <directories>
    <directory>/CompanyB/</directory>
  </directories>
  <templates>
    <template>
      <!-- テンプレートのアクティブ化とデータ抽出に使用される参照ノード（/root以降のパスを指定） -->
      <context>items/item</context>
      <rows> 
        <row>
          <!-- スキーマ名 -->
          <schema-name>IntegratedInfo</schema-name> 
          <!-- ビュー名 -->
          <view-name>PersonalInfo</view-name>
          <!-- 複数のテンプレートを１つのビューにするためsparseを設定 -->
          <view-layout>sparse</view-layout>
          <columns>
            <!-- 名前 -->
            <column>
              <name>NAME_I</name>
              <scalar-type>string</scalar-type>
              <val>NAME</val>
              <nullable>true</nullable>
            </column>
            <!-- 性別 -->
            <column>
              <name>SEX_I</name>
              <scalar-type>string</scalar-type>
              <val>SEX</val>
              <nullable>true</nullable>
            </column>
            <!-- 住所 -->
            <column>
              <name>ADDRESS_I</name>
              <scalar-type>string</scalar-type>
              <!-- 変数を使い住所とアパート名を結合する -->
              <val>fn:concat($var_address, " ", APARTMENT_NAME)</val>
              <nullable>true</nullable>
            </column>
          </columns>
        </row>
      </rows>
    </template>
  </templates>
</template>

(: ビューを生成する :)
return tde:template-insert("/tde_統合_パターン２.xml", $template_pattern2)
```

スキーマデータベースにテンプレートが格納されていることを確認します（Databaseでスキーマデータベースを選択し「Explore」ボタンをクリックする）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/48f1e1e8-2805-515e-02d1-081b59bfd408.png)

### ３．SQLでビューを確認
作成されたビューを確認します。
クエリコンソール上で以下を実行します。

```sql
select * from PersonalInfo
```

SQLを実行するとビューの内容が表示されます。
PersonalInfoビューにドキュメント（パターン１）とドキュメント（パターン２）の内容がテンプレートで定義した内容で追加されていることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188643/caff4c8b-2a9d-ed23-8a7f-d5f9ae9b43ba.png)


以上でビューの作成が完了です。

おわりに
===
TDEを利用することでデータ統合が容易に行えます。
また、作成されたビューは、MarkLogicが提供しているオプティックAPIと呼ばれるJavaScript、XQuery、Java、REST APIで利用できるクエリインターフェースからも実行可能です。
非構造化データをRDBのように利用できるようになるのはとても便利ですね。

```math
\def\textsmall#1{%
  {\rm\scriptsize #1}
}
```

------------------------------------------------------------------------

**免責事項**

​​​​​$\textsmall{当ユーザ会は本文書及びその内容に関して、いかなる保証もするものではありません。}$
​​​​​$\textsmall{万一、本文書の内容に誤りがあった場合でも当ユーザ会は一切責任を負いかねます。}$
​​​​​$\textsmall{また、本文書に記載されている事項は予告なしに変更または削除されることがありますので、予めご了承ください。}$