japan.internet.com
デベロッパー2009年6月12日 10:00

ANSI SQLを用いた階層型構造のリストラクチャリング

この記事のURLhttp://japan.internet.com/developer/20090612/26.html
著者:Michael M. David
海外internet.com発の記事

はじめに

 ナビゲーションレスなデータベース階層処理を用いて行う階層型XMLプロセッシングの新たな手法についての解説も、本稿で3回目になります。1回目の記事では完全なマルチパス階層型データのクエリ処理の基礎を解説し、2回目の記事ではいくつかの階層型構造をより大きな階層型構造に編成する方法および、階層型構造をマッシュアップする新規の強力な手法の具体例を紹介しました。本稿はこの流れを引き継ぎ、マルチパス(非線形)階層型構造に高度な変換を施す新規の手法の具体例について解説します。ここでの操作にて正しい階層型構造を得るには、以前の記事と同様、正しい階層化の原則に従うことが必要です。

 今日のXML構造の変換プロセスにおいて「リストラクチャリング(再編成)」と「リシェイプ(再形成)」はほぼ同じ用語として使われています。しかしながら次のように、これらはXML階層型構造に関するタイプの異なる2つの基本変換なのであり、その本来の意味も得られる結果も使用法も異なるので、両者は個別に取り扱わなくてはなりません。

  • リストラクチャリングの処理は既存データ間のリレーションシップ(relationship:関係)で規定されるのに対して、リシェイプの処理は現状のデータ構造におけるセマンティクス(semantics:意味)で規定される。
  • リストラクチャリングでは新規および未使用のリレーションシップを用いてデータを再編成するのに対して、リシェイプでは現状の構造的なセマンティクスを用いて他の形態の構造に再形成する。
  • リストラクチャリング(データのリレーションシップを基に実行)では新たなセマンティクスの下で新規の構造とデータを生成できるのに対して、リシェイプ(構造のセマンティクスを基に実行)は構造を変化させるだけでデータとそのセマンティクスは変更させない。
 リストラクチャリングもリシェイプも、それぞれに適した用途があります。一般論としては、特定のアプリケーションでの使用に適した構造のマッチングを行う場合はリストラクチャリングを用い、特定のフォーマットに適した構造のマッピングを行う場合はリシェイプを用います。

 本稿で示すリストラクチャリングのSQLサンプルでは、コンストラクトのループ化やナビゲーションを必要とすることなく求めるオペレーションを実行できます。ただし当然ながら、この種の変換用SQLステートメントの記述にあたっては、若干の検討をしなくてはなりません。そうした処理で正常な結果が得られるのは、SQLに指定されるデータ構造の階層型リレーションシップに厳密に従うことで、すべてのオペレーションが階層的に行われるからです。SQLを用いた階層型構造オペレーションは、こうした変換を実装する際にその真価を発揮するもので、エラーの発生を回避しつつ複雑な変換処理の設計を簡易化してくれます。本稿で用いるリストラクチャリングの手法と原則は、他のXMLプロセッサで用いられるナビゲーション的およびプロシージャ(手続き)的な変換についても有効なものですが、ここで解説する完全な非線形変換をプロシージャ方式で実行するのは困難かもしれません。

 本稿のリストラクチャリングの実行例におけるSQLステートメントについては、ANSI SQL Transparent XML Hierarchical Processorのプロトタイプを用いてステートメントの取得と実行をリアルタイムで行うための識別番号が付けられています。こうしたSQLのサンプルは変更可能です。また階層型プロセッサのプロトタイプおよびその使用法はhttp://www.adatinc.com/prototype.htmlから入手できます。

データ間リレーションシップを用いたリストラクチャリング

 図1のサンプルではStoreViewビューを使用しています。これは、丸い枠線で囲まれたCustEmpのサブビューを結合した1つの複合的な階層型構造を形成していますが、これは論理的なリレーションシップまたは物理的なXML構造と見なすこともでき、あるいは異種間の組み合わせとすることも可能です。

図1 StoreViewビュー: StoreViewビューおよびそれを再編成したCustとEmpの2つのサブビューフラグメントの模式図
図1 StoreViewビュー: StoreViewビューおよびそれを再編成したCustとEmpの2つのサブビューフラグメントの模式図
 このサンプルで行う変換は、こうした連続構造を分離させて構造フラグメントの操作をするというものです。ただし論理的構造も物理的構造も、SQLワーキングセットでは同じ形態を取ります。またここで言う「フラグメント」とは、ルートまたはその下層に位置する特定の階層型構造(複数のパスを設定可能)におけるノード群をまとめた1つのサブセットを意味します。SQLでは、これらの要素を自然かつ自動的に処理することができます。言い換えると、SELECTリストを使ったデータフィールド選択により、このクエリからの出力として選択すべきノードを非プロシージャ的に指定できます。その他の必要なデータフィールドは必要に応じて自動的に参照されます。例えばこの場合のSV1フラグメントは、次のSQLを用いてSV2セグメントに対する階層型なLEFT JOINを実行できます。

   SELECT SV1.EmpID, SV1.DpndID, SV2.CustID, 
          SV2.InvID, SV2.AddrID
   FROM StoreView SV1 
   LEFT JOIN StoreView SV2 ON SV1.EmpCustID=SV2.CustID
 標準的な階層オペレーションの1つであるノードのプロモーション(promotion:昇格)では、構造フラグメント群を連続した存在として扱うことにより、既存のリレーションシップ値を用いた構造再編時の結合操作を簡単化しますが、そのすべてはSQL/XML処理に新たに導入された概念的な高レベル階層にて実行されます。こうしたノードプロモーションはSQLのリレーショナル処理において自動的に処理されますが、それはデータ選択(リレーショナルプロジェクション)の過程にて同様の操作が行われるためです。

 図1には、SQL処理における概念的な高レベル階層も示されています。次のSQLサンプルにて、2つのフラグメントSV1およびSV2(破線の円囲み)をプレフィックス表記する際に用いているのは、相関名「SV1」と「SV2」です。こうしたプレフィックスのJOINステートメントにおける定義法および、SELECTリストでの使用法は、他のサンプルでも共通している点に注意してください。ここではSQLによる名前変更とエイリアス作成をテーブルおよびサブビューレベルにて用いることで、同一構造中のフラグメント群の分離と参照を各自のプレフィックス指定により個別的に実行できるようにしています。図2はその選択プロセスと得られる構造を示した模式図です。

図2 StoreViewの分解と変換: 2つのフラグメント(SV1およびSV2)から特定アイテムを選択して新規の構造に変換するプロセスの模式図
図2 StoreViewの分解と変換: 2つのフラグメント(SV1およびSV2)から特定アイテムを選択して新規の構造に変換するプロセスの模式図
 図2については、階層処理を識別するために各種のシンボルが使われている点に注意してください。これらは本稿を通して使用する記号ですが、それぞれ次の意味を持ちます。

  • 実線の四角い枠 ― 選択対象のノードを示す。
  • 破線の四角い枠 ― 選択対象外のノードを示し、当該クエリの実行結果からは除外される。
  • 実線のライン ― アクティブな構造に含まれるノードとの間をつなぐ。
  • 破線のライン ― アクティブな構造に含まれないノードとの間をつなぐ。
  • 破線の矢印 ― リレーションシップ結合のデータポイントを示す。これが使われていない場合、他の用途および結合(join)を制御するリレーションシップのデータポイントは、実線の矢印により示される。
  • 実線の矢印 ― 結合される構造間でのデータモデリング構造ノードのリンクを示す。これはクエリ処理を規定する構造セマンティクスを示すもので、結合した構造間でのデータ構造の統合はこれを基にして完成することになる。
 これらは本稿を通して使用される記号です。つまり実線の矢印は、結合される構造間でのデータ「モデリング」の構造リンクを示すと同時に、通常はON句によるデータ「リレーションシップ」のリンクポイントも示します。ただしON句によるデータリレーションシップのリンクポイントとデータモデリングを示す実線の矢印とが一致しない場合もあり(詳細は後述)、そうしたケースでのデータリレーションシップのリンクポイント表示に用いられるのが破線の矢印です。

 本稿で用いたリストラクチャリングのサンプルでは、ANSI SQL Transparent Hierarchical XML ProcessorプロトタイプがSQLステートメントの取得と実行をリアルタイムで行うためのSQL識別番号が付けられています。階層型プロセッサのプロトタイプおよびその使用法は各自でダウンロードできるので、必要に応じて、SQLサンプルの変更が処理に与える影響を実地に検証するようにしてください。

基本的なリストラクチャリング

 このセクションで解説する階層型構造変換は、「構造リストラクチャリング」あるいはより簡潔に「リストラクチャリング」と呼ばれるものです。物理的あるいは論理的な階層型構造のリストラクチャリングは、個々のフラグメントを抽出してから個別に再構成することで行われます。個々のフラグメントの抽出時に行うべき処理は、構造を論理的に複製し、各構造の識別とアクセスを行うための名前やプレフィックスを割り当てておくことです。このように独立して操作可能な複数のフラグメントを用意することで、オリジナル構造の変換が実行可能となります。ここでは、図2の構造を作成するSQLクエリの指定が極めて直観的かつ単純な手法で記述でき、階層型処理との親和性が非常に高い点に注目してください。

 論理的および物理的なデータ構造の分解と変換を標準SQLを用いて実行するには、SQLのエイリアス処理とフラグメント処理の組み合わせにより、クエリによる構造ビューへの任意回数の独立したアクセスを行えるようにしなければなりません。図2では、2つのフラグメント(図1の破線の円囲み)に対する単一のソースとしてStoreViewビューを用いています。これらが反映するのはCustViewおよびEmpViewの構成データです。ここで行われる本質的な処理は、これらのフラグメントによりStoreViewをいったん分解してからリモデリングを施すことで、データモデルのリシェイプを行うというものです。こうしたリシェイプは、構造中の他のデータ値のリレーションシップを基に、構造フラグメントを階層的に再結合(join)することで実行されます(通常は個別に実行)。

 論理的な構造は各種の方法で自由にモデリングできますが、物理的なインプット構造については、アクセスされる外部構造を反映するようにモデリングする必要があります。図2のStoreViewでは階層型構造を簡易的にモデリングしており、この例の場合は物理的なXMLあるいは論理的なリレーショナル構造とすることが可能ですが、行セット(rowset)にて両者は同一の表現となっています。このサンプルを見ると分かるように物理的な構造の再編成では、それを含む行セットから固定フラグメントを個別に選択した後にメインの構造(統合したビュー)に個別に結合させることで、論理的な構造の有す柔軟性を反映させることも可能です。またエイリアス機能を用いると、こうした新規のテーブルやビューに名前を付けることができ、SELECT句にて高レベルのプレフィックスとして参照させることができます。名称変更後のオブジェクト間では同じ名前が使われる可能性もあるため、こうしたプレフィックスを使用することで、オブジェクト参照の精密な指定が可能となるはずです。

ビューにおける構造リストラクチャリングとエイリアスの使用

 図3のサンプルは、XML変換に利用可能な各種のSQL処理を実演するために用意したものです。

図3 静的なリストラクチャリング: Transformビューにて全フィールドを選択することで得られる構造
図3 静的なリストラクチャリング: Transformビューにて全フィールドを選択することで得られる構造
 1つ目は、リストラクチャリング用のSQLクエリ(前述のもの)をSQLビュー中に配置することで実行が簡便化されるというもので、これにより抽象的に柔軟な使用ができることが分かるでしょう。2つ目は、InvIDおよびAddrIDという列名に対して、生成するXMLに反映されるエイリアス名を付けられることです。具体的なコードは次のように記述されますが、ここでは先のサンプルを変更して、エイリアス名を付けた上で1つのビュー中に配置するようにしてあります。

   CREATE View Transform AS
   SELECT SV1.EmpID EmpID, SV1.DpndID DpndID, SV2.CustID 
          CustID, SV2.InvID Invoice, SV2.AddrID Address
   FROM StoreView SV1 
   LEFT JOIN StoreView SV2 ON SV1.EmpCustID=SV2.CustID
 このSQLでは、InvIDおよびAddrID列にInvoiceおよびAddressというエイリアスを割り当てています。これらの新しい名前は、生成後の構造のもたらすXMLでも反映されるようになるはずです。

 この指定による変換結果はTransformという名前のSQLビューに格納されるため、簡単に呼び出すことができ、その他のビューと同様の使用も可能となっています。これが正常に動作するかを検証するにはSELECT * FROM Transformというクエリを実行すればよく、これにより図3の構造が得られるはずです。後述するサンプルでは、呼び出し時に変換ビューを動的に変更する方法を説明します。

出力されるリストラクチャリングビューの動的な変更

 今日使われている大部分のXML変換は静的なものであるため、最終的なXML構造に特定の値を含めるか除外させる場合には、そのための変更を事前に施しておかなくてはなりません。これに対してSQLベースの変換では静的なXMLフォーマッティング用の処理を必要としませんが、それは動的なSELECTリストを用いることで、図4に示したような単純かつ動的なデータアイテム出力の取り込みや除外が行えるためです。

図4 動的なリストラクチャリング: Custノードをクエリに選択させないことで当該ノードを削除させ、InvoiceおよびAddressノードのプロモーションを行わせる
図4 動的なリストラクチャリング: Custノードをクエリに選択させないことで当該ノードを削除させ、InvoiceおよびAddressノードのプロモーションを行わせる
 具体的な処理としては下記のようなSQLクエリを用いることになります。

   SELECT EmpID, DpndID, Invoice, Address 
   FROM Transform
 このクエリについてはSELECTにてCustノードを取り込んでいない点に注意してください。これによりCustノードが排除され、その位置にInvoiceおよびAddrノードがプロモーションされるという、変換済み構造に対してのさらなる変更が施されます。こうした動的なSELECTリストはクエリごとに変更でき、その際にTransformationビューに組み込む変換ロジックを修正する必要はありません。つまりこの方式を用いれば、操作性と柔軟性と再利用性を有す、非常に強力な動的変換が行えるのです。

レッグ順の変更とノードの複製

 次のサンプルでは(図5を参照)、図1に示したオリジナルのStoreViewデータ構造を基にして、各種の変換を施しています。図5におけるStoreViewビューを構成しているのは、CustViewEmpViewの2つのビューです。ここでの変換処理で行う作業は、各ノードを分離することでStoreViewからCustViewを抽出することです。その次に行うのはCustビューの再構成で、その際には結合(join)の実行順を変更することでAddrInvoiceのレッグ(leg)の順番を意図的に変更していますが、これが機能するのは、この構造が上から下および左から右の方向に構成されているためです。これがどのような変更となるかは、サンプルの構造図を比較することで確認してください。

図5 レッグ順の変更: この複数回の結合(join)を用いたクエリ処理では、StoreViewからのCustビューの抽出後その再構成を行い、AddressとInvoiceのレッグを入れ換えて、Addrの下にもう1つの追加ノードInvoiceを付加している
図5 レッグ順の変更: この複数回の結合(join)を用いたクエリ処理では、StoreViewからのCustビューの抽出後その再構成を行い、AddressとInvoiceのレッグを入れ換えて、Addrの下にもう1つの追加ノードInvoiceを付加している
   SELECT Cust.custid, Invoice.invid, Invoice.invcustid, Addr.addrid,
          Addr.addrcustid, invoice2.invid NewInv
   FROM Storeview Cust
   LEFT JOIN StoreView Addr ON Cust.custid=Addr.addrcustid
   LEFT JOIN StoreView Invoice ON Cust.custid=Invoice.invcustid
   LEFT JOIN StoreView Invoice2 ON Addr.addrcustid=Invoice2.invcustid
 EmpViewCustviewデータの組み合わせで生じる複製データは、出力データがXML化される際に自動的に取り除かれます。またこの変換では、追加ノードのInvoiceを選択して、図5におけるAddrノードの下に配置するようにしています。

 先に見たリストラクチャリングのサンプルでは、フラグメントを用いてデータの移動を行っていました。それに対してこのサンプルでは、ノードレベルでの処理を行っています。ノードレベル方式は詳細な制御を施せる反面、フラグメント方式は一般的に扱いが簡単であり、またノードレベルにはない重要な機能が利用できます。通常、1つのグループに属すノード群は最適化された構造にまとめられているケースが多く、再結合に使用可能な値(外部キーなど)が当該グループ中に残されていない場合があります。そうした際のソリューションとなるのがフラグメント方式であり、次のサンプルで見るようにこの方式では、移動対象を変化させることなく1つのグループとして操作できるのです。

Below-the-Root方式のリンクによるリストラクチャリング

 次のサンプルでは、2つのマルチパス構造フラグメントを、下位フラグメントのルートの下でリンクさせます。このサンプルを検討してみると、この方式のリンクによって多様なフラグメント結合が可能になることが分かるでしょう。問題は、「ルート下へのリンクが可能であるか」と「可能な場合それはセマンティクス的にどう処理されるか」というものです。このようなリンクが可能であることは既にわかっています。なぜなら、以前の解説記事で説明した「ルート下へのリンク」と同じ原則で機能するからです。下位構造のルートもやはり階層型モデリングのリンクポイントと考えられます。

 次のサンプルコードは、それぞれ「SV1」と「SV2」のプレフィックスで示されるEmpCustの2つのフラグメントを分離するSQL処理です。このクエリが行うフラグメント間リンクは、EaddrAddrノードにおけるEaddrIDAddrIDのデータ値に対するマッチングに基づいて処理されます。そうした処理が行われると、下位レベルフラグメントのCustルートがデータモデリングのエントリポイントとして使用されます(図6を参照)。

   SELECT SV1.EmpID, SV1.DpndID, SV2.InvID, SV2.AddrID
   FROM   StoreView SV1 LEFT JOIN StoreView SV2 
          ON SV1.EaddrID= SV2.AddrID 
図6 Below-the-Root方式のリンクによるリストラクチャリング: ここでのクエリ処理はCustルートノードに依存するが、出力時に当該ノードは選択されない
図6 Below-the-Root方式のリンクによるリストラクチャリング: ここでのクエリ処理はCustルートノードに依存するが、出力時に当該ノードは選択されない
 このサンプルで興味深いのは、このクエリ処理はCustルートノードに基づいているのに、このノードを出力用に指定する必要はないという点です。そのため、先に触れた検討事項は、「Invoiceノードはどう処理されるか」という問題になってきます。なぜなら、InvoiceAddrノードと間接的な関係を持つだけで、その関係の基になる共通の上位レベルノード(Custノード)は出力時には排除されるからです。この場合、内部的には、下位フラグメントはEaddrノードからその下位のCustルートノードまでの上位フラグメントに結び付けられます。その後、選択されなかったCustおよびEaddrノードを排除したノードコレクションが作成されて、InvoiceおよびAddrノードはその次の上位レベルであるEmpノードに接続されます。なおノードコレクションという概念については以前の解説記事での説明も参照してください。このサンプルは、階層型オペレーションの組み合わせでどのような処理が可能となり、どのようにして階層型セマンティクスが維持されるかを例示するために用意したものです。

 図6の破線の矢印は2つのフラグメント間のデータリンクを示し、実線の矢印は結果として得られる構造を示しています。

リレーションシップを用いない構造のリシェイプ

 ここまでに見たサンプルで行っていたのは、データ間のリレーションシップを基に必要な結合(join)をするリストラクチャリングという処理でした。そしてこうしたデータ間のリレーションシップが利用できないケースであっても、データ構造のセマンティクスを基にして目的とするノード(群)を構造上の特定位置に移動する、という変換方法が存在します。この方式は任意構造のリシェイプを可能としますが、そこで行われる操作は先に見たリストラクチャリングとは異なる処理であり、得られる結果も異なってくるのが普通です。「リストラクチャリング」が構造中に内在するデータ間リレーションシップを基に新たなセマンティクスを導入するのに対して、「リシェイプ」ではデータの基本的なセマンティクスは保持したまま階層型構造の形態を変更することになります。つまり、目的とする構造データセマンティクスを得られるのがリストラクチャリングであり、データのセマンティクスを変えることなく目的とするデータ構造を得られるのがリシェイプという処理だと考えればいいでしょう。

 単一構造のリシェイプをする際には、当該構造の複製をいくつか作成したうえで、自分自身を比較対象としたLEFT JOINを上位ノードに対して施し、必要とするすべてのノードあるいはフラグメントに対してこうした処理を繰り返すことで最終的な構造を形成させます。図7のサンプルは次のSQLを用いて、非線形なマルチパス構造を線形構造にリシェイプするという処理例ですが、その際に構造に内在するリレーションシップのマッチングは利用していません。

図7 構造のリシェイプ: データ間のリレーションシップを使用せず、オリジナルの構造におけるデータの基本的なセマンティクスも変更しないリシェイプ
図7 構造のリシェイプ: データ間のリレーションシップを使用せず、オリジナルの構造におけるデータの基本的なセマンティクスも変更しないリシェイプ
   SELECT SV1.EaddrID, SV2.EmpID, SV2.DpndID
   FROM   EmpView SV1 LEFT JOIN EmpView SV2 
          ON SV1.EaddrID = SV2.EaddrID 
 図7を見ると、リシェイプ後の構造における1つ目のルートノードはEaddrとなっているので、こうした構造を得るにあたっては最初にこのノードの移動をしておかなくてはなりません。次に行うのは当該プロセスにおける最初の比較処理であり、ここではEaddrIDを自身のコピーと比較することで、コピー間にて位置の同期をさせるという処理を行っています。こうして同期したコピーからは、LEFT JOINを用いて2つ目のノードとなるEmpを取得し、Eaddrの下にEmpを配置させるようにします。このプロセスの要となるのは下位構造のルート下部に対するリンクですが、こうした方式が正常に機能するのは、大部分の操作における追跡対象がルート以外のノードとなるからです。

 最終的にこのプロセスは、Empノードに対する同期をして、Dpndノードを所定の位置に配置するまで繰り返さなくてはなりません。ただし必要な全ノードを配置するに当たっては、処理のステップ数を削減するためのショートカットが存在します。このショートカットを用いない場合、最終的な構造を得るには特定数の処理ステップが常に必要であり、その数は出力する構造のノード数マイナス1となるはずです。ところが図7を見ると、DpndノードはEmpノードの下位に最初から配置されているので、Empノードの移動時にこのノードも一緒に移動させておけば同期用の結合ステップを1つ分省略できることになります。実際、先のSQLにおけるSELECTステートメントではこのショートカットを利用しており、EmpIDおよびDpndIDでは下位レベルのSV2プレフィックスを使用することで、両者をまとめて選択させています。

 ここでも実線の四角い枠は、選択対象のアイテムを示しています。そして非選択ノードを示す破線の四角い枠は、出力される構造からは除外されます。このように組み合わされた構造における選択フィールド群を見比べることで、どのような仕組みでリシェイプが行われるかを確認してください。ここでのLEFT JOINは、データのモデリングおよび必要なデータの配置という2つの処理を担っているのです。

 リシェイプの詳細については「ANSI SQL Semantically Controlled Any-to-Any Data Structure Reshaping」を参照してください。

著者紹介

Michael M. David(Michael M. David)
 Advanced Data Access Technologies, Incの創設者であり、それ以前はNCR/Teradataのスタッフ研究員および主任XML設計者として活動し、ANSI SQLX Groupの代表も務める。フラット、リレーショナル、階層型データを用いた非プロシージャ方式による異種データベース階層型クエリ処理の商用製品の研究と設計に関する25年以上の経験を有しており、『Advanced ANSI SQL Data Modeling and Structure Processing』の執筆者である他、同分野に関係する論文や記事も多数執筆。階層型データの構造と原則、ナビゲーションレス処理、自動処理などについては、追加情報およびデモンストレーションを参照のこと。
japan.internet.comのウエブサイトの内容は全て、国際法、日本国内法の定める著作権法並びに商標法の規定によって保護されており、その知的財産権、著作権、商標の所有者はインターネットコム株式会社、インターネットコム株式会社の関連会社または第三者にあたる権利者となっています。
本サイトの全てのコンテンツ、テキスト、グラフィック、写真、表、グラフ、音声、動画などに関して、その一部または全部を、japan.internet.comの許諾なしに、変更、複製、再出版、アップロード、掲示、転送、配布、さらには、社内LAN、メーリングリストなどにおいて共有することはできません。
ただし、コンテンツの著作権又は所有権情報を変更あるいは削除せず、利用者自身の個人的かつ非商業的な利用目的に限ってのみ、本サイトのコンテンツをプリント、ダウンロードすることは認められています。

Copyright 2014 internet.com K.K. (Japan) All Rights Reserved.