多層にわたる XML のプログラミング: 第 2 回 XML データベース・サーバーを利用する効率的な Java EE アプリケーションを作成する

JDBC 4.0、SQLXML、WebSphere Application Server XML フィーチャー・パック、そして DB2 pureXML を使用して、XML のみで構成されるソリューションを最適化する

この連載の第 1 回では、アプリケーション・サーバー層とデータベース・サーバー層の両方にわたり、一時 XML データおよび永続 XML データを操作するための宣言型プログラミングの手法を紹介しました。今回は、サーバー・サイドの Java™ アプリケーションで一時 XML データと永続 XML データを操作する方法をさらに詳細に検討します。実例とサンプル・コードに沿って、データベース管理システムでの XML の索引付け機能とクエリー・フィルタリング機能が、大量の XML データを扱う Java EE アプリケーションにとって重要なパフォーマンスのメリットをもたらす仕組みを説明します。さらに、一時 XML データと永続 XML データを結合する方法についても詳しく見ていきます。

Andrew Spyker, Senior Technical Staff Member, IBM

Photo of Andrew SpykerAndrew Spyker は、WebSphere Application Server 開発チームの STSM (Senior Technical Staff Member) です。パフォーマンスの分野で WebSphere Application Server パフォーマンス・チームを率いてきた 5 年間の経験を生かし、パフォーマンス・チームのアドバイザー役を務めています。また、SOA ランタイム・アーキテクトとして、特にベンチマーク・ストラテジー、パフォーマンス、XML 整合性を重点に WebSphere SOA ランタイム全体での一貫性の推進を行っています。さらに、WebSphere ポートフォリオの XML ストラテジーの考案および促進も行っています。最近では、XML フィーチャー・パックのチーフ・アーキテクトを務めました。



Cynthia M. Saracco (saracco@us.ibm.com), Senior Solutions Architect, IBM

Cindy Saracco photoCynthia M. Saracco は、IBM Silicon Valley Laboratory に勤務するシニア・ソリューション・アーキテクトで、新しい技術とデータベース管理の分野を専門としています。ソフトウェア業界で 23 年の経験を積んでいる彼女は、これまで 3 冊の本と 70 を超える技術記事を執筆し、7 つの特許を持っています。


developerWorks
        プロフェッショナル著者レベル

Bert Van Der Linden, Senior Technical Staff Member, IBM

Photo of Bert Van Der LindenRobbert (Bert) Van der Linden は、IBM Silicon Valley Laboratory の STSM (Senior Technical Staff Member) です。2001年に IBM に入社し、最終的に 2006年の DB2 9 リリースへと発展した DB2 pureXML の設計に携わりました。それと並行して多くの顧客とパートナーと交渉し、データベースにおける XML を説得してきました。その活動は、今でも積極的に続けています。IBM に入社する前に勤めていた新興企業、Propel では、スケーラブルな e-commerce アプリケーションをホストする無停止分散ミドルウェアの設計および実装にリーダーとして携わっていました。それ以前は長年 Tandem Computers に勤め、金融業界での多数の重大なアプリケーションを実行するデータベース、NonStop SQL に取り組んできました。



Guogen Zhang, Distinguished Engineer, IBM

Photo of Guogen ZhangGuogen Zhang は、IBM Silicon Valley Laboratory で DB2 for z/OS development 開発に携わる Distinguished Engineer です。DB2 for z/OS での pureXML の実現に責任を持つチーフ・アーキテクト兼開発リーダーであるとともに、高度な SQL 技術のリーダーも務めています。これまで、pureXML、MQT (Materialized Query Table)、XML パブリッシング機能、STAR join、ビューの結合など、DB2 for z/OS の重要な機能の実現に貢献してきました。彼は IOD や IDUG などのカンファレンスで頻繁に講演を行っており、顧客への pureXML ソリューションの提供に深く関わっています。



2010年 10月 11日 (初版 2010年 10月 05日)

2010年 10月 11日 - 「ダウンロード」セクションに fpmldb2was.zip を追加しました。

概要

XML が普及しているなか、プログラマーたちは一時的な XML メッセージと永続的な XML データの両方を効率的に操作する方法を模索するようになっています。Web サービスや他のソフトウェア・コンポーネントは、重要なビジネス・データを含めた一時 XML メッセージを生成することがよくあります。このようなメッセージを処理するとともに、ネイティブ XML データベース管理システムに保管された永続的なビジネス成果物を処理しなければならないアプリケーションの数は次第に多くなってきています。

よく使われる頭字語

  • API: Application Program Interface
  • BLOB: Binary Large Object
  • CLOB: Character Large Object
  • DBMS: Database Management System
  • DOM: Document Object Model
  • JDBC: Java Database Connectivity
  • OEM: Original Equipment Manufacturer
  • SAX: Simple API for XML
  • SOA: Service Oriented Architecture
  • SQL: Structured Query Language
  • URI: Uniform Resource Identifier
  • URL: Uniform Resource Locator
  • W3C: World Wide Web Consortium
  • XHTML: Extensible Hypertext Markup Language
  • XML: Extensible Markup Language
  • XSLT: Extensible Stylesheet Language Transformations

一時 XML データと永続 XML データはどちらも Java オブジェクトにマッピングできることは確かです。けれどもそれには、かなりの深さまでネストされた複雑な XML 構造に取り組まなければならないことになります。しかも、XML データのスキーマがそのうち変更される可能性が高いとすると、アプリケーション・コードにさらなる複雑さがもたらされます。この連載の第 1 回では、命令型プログラミング手法に伴いがちな複雑さを軽減するために、アプリケーション・サーバー層とデータベース・サーバー層の両方にわたって一時 XML データおよび永続 XML データを操作する宣言型プログラミングの手法を紹介しました。

今回は、サーバー・サイドの Java™ アプリケーションで一時 XML と永続 XML を操作する方法をさらに掘り下げて検討します。一般的なアプリケーション開発タスクとサンプル・コードを詳しく見ながら、以下の内容を説明します。

  1. 一時 XML データと永続 XML データを効率的に統合する必要のある Java EE アプリケーションからネイティブ XML データベース・サーバー技術を利用する方法
  2. データベース管理システムで XML 索引付け機能とクエリー・フィルタリング機能を使用して、強力なランタイム・パフォーマンスを確実にする方法
  3. 一時 XML データと永続 XML データを結合する方法、および永続 XML 文書の特定の部分を更新する方法

前提条件および製品

この記事を読む前に、XML、XPath、XQuery についてよく理解しておく必要があります。これらの技術については、「参考文献」を参照してください。また、記事に記載する例は WebSphere Application Server V7.0 Feature Pack for XML 1.0 に基づいているので、この連載の第 1 回を読んでおく必要があります。XML データベース管理技術の知識も、記事を理解する上で役立ちます。この記事の例では、DB2® を XML データベース・サーバーとして使用します。

記事で使用するアプリケーション環境とサンプル・データベース

サーバー・サイドの Java プログラマーが一時 XML データと永続 XML データを効率的に操作する方法を探るために、単一の Windows® システムに以下のソフトウェアをインストールしました。

  • WebSphere Application Server 7.0 テスト環境を統合した Rational Application Developer for WebSphere Software V7.5.5
  • フィックスパック 1.0.0.7 を適用した WebSphere Application Server Feature Pack for XML 1.0 (WebSphere Application Server のスタンドアロン・バージョンでも、Rational Application Developer に統合された WebSphere テスト環境でも使用することができます。)
  • DB2 9.7 Enterprise Server Edition

この Rational Application Developer 開発プロジェクトのビルド・パスには、DB2 の JDBC 4.0 ドライバー用の jar ファイルを含めました。具体的には、db2jcc4.jar および db2_license_cu.jar ファイルです。皆さんがプロジェクト内で XML フィーチャー・パックを使用する際には、XML Transformation and Query Project Facet を有効にすることを忘れないでください。それには、プロジェクトを右クリックし、「Project Facets (プロジェクト・ファセット)」を選択して、このファセットを有効にします。または、XML フィーチャー・パックのシン・クライアント jar ファイル (com.ibm.xml.thinclient_1.0.0.jar) をビルド・パスに追加するという方法もあります。DB2 の JDBC 4.0 ドライバー、または XML フィーチャー・パックについての詳細は、「参考文献」を参照してください。

サンプル・データベースには、国際スワップ・デリバティブズ協会 (ISDA: International Swaps and Derivatives Association) が提供しているサンプル XML データをベースとした OTC (Over-The-Counter) デリバティブ取引のレコードが含まれています。このデータは、デリバティブ取引を行う多くの企業でよく使用されている FpML (Financial Products Markup Language) 仕様に従っています。

企業が業界標準の XML 形式に準拠したテスト・データベースを簡単に作成してデータを入力できるように、DB2 では業界に固有の無料ソフトウェア・ダウンロードをいくつも提供しています。これらのバンドルの中には、FpML に対応したものもあります。ここでは、このバンドルをカスタマイズして、記事のポイントをいくつか説明できるようにしました。カスタマイズしたバージョンのバンドルは、「ダウンロード」セクションのリンクからダウンロードすることができます。お使いの Windows システムにサンプル・データベースをセットアップするには、DB2 コマンド・ウィンドウを開いて、start.bat を実行してください。このコマンドによって、必要なデータベース・オブジェクトが作成され、サンプル FpML データがロードされます。

記事の例では、FPMLADMIN.FPML43 テーブルを使用します。このテーブルには 2 つのリレーショナル列 (ID および COMMENT) と、1 つの XML 列 (DOCUMENT) があります。XML 列に保管されているのは、各種デリバティブ取引の完全な FpML レコードです。企業が 1 つのテーブルにリレーショナル・データと XML データの両方を保管することはかなり一般的になっているので、この例でも両方のタイプの列を参照します。図 1 に、このテーブルの構造を示します。

図 1. 2 つのリレーショナル列 (ID および COMMENT) と 1 つの XML 列 (DOCUMENT) からなる FPMLADMIN.FPML43 テーブル
サンプル FPMLADMIN.FPML43 テーブル。2 つのエントリーの ID、短いコメント、FpML 文書が示されています。

FpML レコードに含まれる構造体はかなりの深さまでネストされており、構造体の要素と属性はそれぞれが表現する取引のタイプによって異なります。図 2 に示すのは、クレジット・デフォルト・スワップ取引を表すサンプル FpML レコードのごく一部です。

図 2. クレジット・デフォルト・スワップ取引に対応する FpML レコードの一部
クレジット・デフォルト・スワップ取引に対応する FpML レコードの一部を示すスクリーン・キャプチャー

サンプル・テーブルには、サイズが 2KB のものから 125KB を超えるものまで複数の FpML 文書が格納されています。さらに、このテーブルでは、3 つの異なるバージョンの FpML スキーマをベースとした取引文書が同じ 1 つの XML 列に保管されます (具体的には、FpML 4.2、4.3、および 4.7 をベースとした取引文書が保管されています)。XML Schema はビジネス・ニーズの変化に伴って進化していく傾向があるため、異なるスキーマに従った複数の文書を 1 つの XML 列に保管するのは、ビジネス要件としては一般的です。


永続 XML データに対するクエリー

Java EE プログラマーがデータベース層に保管された永続 XML データを取得し、そのデータをアプリケーション・サーバー層で操作しなければならないことはよくあります。このような場合を具体的に説明する例として、これから XML フィーチャー・パック API と組み込み DB2 サポートを使用して XML データに対するクエリーを実行してみます。どちらのオファリングも、XQuery 式と XPath 式を含め、XML データに対するクエリーの業界標準をサポートします。

DB2 は XML データをファーストクラス・データ型として認識し、サポートするため、プログラマーは XML データをラージ・オブジェクト (LOB) として操作するのではなく、XML 形式のまま直接操作することができます。XML を複数のソフトウェア層で使用できるということは、プログラミング・ロジックが単純になり、開発コストが削減されるということです。その上、DB2 のネイティブ XML サポートにより、文書の特定の部分 (XML ノード) に効率的にアクセスすることもできます。これは、ラージ・オブジェクトではできない話です。

クエリーのシナリオ

例えば、Java EE アプリケーションで特定の取引によるクレジット・デフォルト・スワップ・データにアクセスしなければならないという状況を考えてみてください。この場合、アプリケーションに取引データを一時 XML メッセージとして渡せば、アプリケーションは単純に XML フィーチャー・パックが提供するサービスを使用してメッセージに XPath 式を実行することができます。このような XPath 式の定義は、リスト 1 のとおりです。

リスト 1. XML フィーチャー・パック API を使用した一時 XML の操作
// This XPath expression obtains the credit default swap data for a given trade.  
// For simplicity, we omitted declaring a specific namespace here.
  
String myXpath = "*:FpML/*:trade/*:creditDefaultSwap;
. . .

あらゆるアプリケーションが一時 XML メッセージに依存するわけではありません。企業取引ポートフォリオを処理して投資戦略の分析、リスク管理、あるいはその他のビジネス機能を行うように設計されたアプリケーションの場合には、取引データを永続 XML リポジトリーから取得する必要があるかもしれません。

永続 XML 取引データのフラグメントを返すクエリー・サンプル

リスト 2 に、目的の企業に関連するクレジット・デフォルト・スワップ取引データを、XPath 式を使用してデータベース (この例では DB2) から取得する方法を説明します。

リスト 2. リレーショナル述部と XML 述部を使用したSQL/XML クエリー
SELECT XMLQUERY('declare default element namespace 
   "http://www.fpml.org/2009/FpML-4-7";
   $fpml/FpML/trade/creditDefaultSwap' passing document as "fpml")
FROM fpmladmin.fpml43 
WHERE comment LIKE ‘cd%’ 
AND 
XMLEXISTS('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
   $fpml/FpML/trade/creditDefaultSwap/generalTerms/referenceInformation
   /referenceEntity[entityName="Agrium Inc."]' passing document as "fpml")

上記のクエリー (DB2 コマンド行インターフェースまたはグラフィカル・クエリー・ツールを使用して、インタラクティブに実行することができます) は標準 SQL 文で、XML に固有の 2 つの関数を呼び出します。最初に呼び出す XMLQUERY() 関数がクエリーで返すデータ (creditDefaultSwap ノードにあるデータ) を識別し、2 番目の XMLEXISTS() 関数がクエリー結果を特定のエントリー (Agrium Inc.) を参照する FpML 4.7 文書に制限します。

ほとんどの SQL 文と同じように、この例でも SELECT column(s) . . . FROM table(s) . . . WHERE condition(s) という標準 SQL 構文に従っています。このクエリーの詳細をひと通り説明した後、Java コード・サンプルを詳しく見ながら、同じく XML フィーチャー・パックを使用するアプリケーションでこのクエリーを呼び出す方法を説明します。

クエリーの最初の行で実行しているのは、業界標準の SQL 関数 (XMLQUERY) を呼び出す SQL SELECT 文です。XMLQUERY() を呼び出すには、まず対象とするターゲット名前空間 (http://www.fpml.org/2009/FpML-4-7) を宣言します。前述したように、このサンプル DB2 テーブルでは異なるバージョンの FpML レコードをまとめて 1 つの列に保管していますが、ここで必要なのは FpML 4.7 のレコードだけです。

XMLQuery 関数に対してデフォルトの名前空間を宣言した後、XPath 式で取得するデータ ($fpml/FpML/trade/creditDefaultSwap) を指定しています。XPath 式に続く passing 節では、$fpml 変数がテーブル内の DOCUMENT 列を表していることを明確に指定しています。したがって、リスト 2 の最初の 3 行は、DOCUMENT 列に保管されている取引データのうち、FpML 4.7 バージョンの取引データのサブセットのみを取得するという意味になります。このサブセットとはクレジット・デフォルト・スワップ・データのことであり、FpML はこれを複数の子ノードを含む XML ノードとして表します (図 2 を参照)。SQL FROM 節が FPMLADMIN.FPML43 テーブルを対象のテーブルとして特定します。

SQL WHERE 節は、クレジット・デフォルト取引に関する結果だけが必要であることを示しています。このサンプル・テーブルでは、DOCUMENT 列 (XML 列) に記録されている取引のタイプを区別する手段として、COMMENT 列 (リレーショナル列) の値を使用することができます。COMMENT 列の値のうち、cd で始まる値がクレジット・デフォルト取引を表します。

残りの行で呼び出している業界標準の XMLEXISTS() 関数は、クエリーの実行結果を Agrium Inc. という特定の企業体に関連するスワップに制限します。この XMLEXISTS 関数をよく見てみると、該当する名前空間が宣言された後に、XPath 式が組み込まれていることがわかります。データベース・サーバーはこの XPath 式を、テーブルの DOCUMENT 列に含まれるデータに対して実行します。

最適なランタイム・パフォーマンスを得るために、Java EE プログラマーはクエリーをコーディングする際に、できるだけ選択クエリーになるようにします。上記のサンプル・クエリーで取得するのは、XML データの必要な部分だけです (具体的に言うと、XMLQUERY 関数は取引ドキュメントの特定の XML ノードだけを取得します)。さらに、このクエリーは WHERE 節でリレーショナルおよび XML 述部を指定して対象の行を限定します。このようにクエリーを作成することで、データベース・サーバー層とアプリケーション・サーバー層の間で転送されるデータの量を最小限にすることができます (この例では DB2 に保管された 1 つの XML 取引レコードのサブセットを取得していますが、これよりも一般的なクエリーにはすべてのクレジット・デフォルト・スワップ取引が関連します。その場合、完全な 40 の取引レコードが返されることになります)。この後説明するように、さらに DB2 に適切な XML 索引を定義すれば、クエリーのランタイム・パフォーマンスを向上させることもできます。

クエリー・シナリオのサンプル Java EE コード

このデータベース・クエリーを Java EE アプリケーションに組み込むのは難しいことではありません。その一例として、データベースから必要な XML データを取得し、そのデータをアプリケーション・サーバーで操作する手順を追っていきましょう。

リスト 3 に示すのは、データベース・クエリーを定義するサーブレットからの抜粋です。ここで定義されたクエリーが、XML フィーチャー・パックの適切なコレクション・リゾルバーによって実行されます。

リスト 3. メモリーに読み込まれた DB2 pureXML® データに XQuery プログラムを適用する Java EE アプリケーション
// Excerpt from our sample servlet. 
//  
// First, the servlet sets up the database query. 
// Here, a String named "getCreditDefaultSwapsByEntityName" will be mapped to our query, 
// which extracts the creditDefaultSwap node from qualifying trades.

dbStatements = new HashMap<String, String>();
dbStatements.put("getCreditDefaultSwapsByEntityName",
 "select " +
   "xmlquery("'declare default element namespace " + 
     "\"http://www.fpml.org/2009/FpML-4-7\"; " + 
     "$DOCUMENT/FpML/trade/creditDefaultSwap' ) " +
  "from fpmladmin.fpml43 " + 
  "where comment like ? and " +
  "xmlexists("'declare default element namespace " + 
    "\"http://www.fpml.org/2009/FpML-4-7\"; " +
    "$fpml/FpML/trade/creditDefaultSwap/generalTerms/" + 
    "referenceInformation/referenceEntity[entityName=$name]' " +
    "passing document as \"fpml\", " +
    "cast (? as varchar(100)) as \"name\")"
);
...

// Next, another method in this servlet creates the XQuery executable.     
// This method then uses our JDBC resolver to execute it, 
// providing an appropriate value for the entityName variable. 

Source source = 
   new Source(FpMLServlet.class.getResource("/getCreditDefaultSwaps.xq").toString());
XQueryExecutable getCreditDefaultSwapsXQ = factory.prepareXQuery(source, staticContext);
...
JDBCCollectionResolver inputResolver =
  new JDBCCollectionResolver(getConnection(), dbStatements);
dynamicContext.setCollectionResolver(inputResolver);
dynamicContext.bind(new QName("http://com.ibm.xml.samples",entityName"), name);
XSequenceCursor output = getCreditDefaultSwapsXQ.execute(dynamicContext);

リスト 3 の前半部分のクエリーは、インタラクティブに実行されるリスト 2 のクエリーとほとんど同じで、以下の点が異なるだけです。

  • ハード・コーディングされていた述部の値は、より柔軟なクエリーになるように疑問符 (?) で示されたパラメーター・マーカーに置き換えられています。
  • 二重引用符が適切にエスケープされています。

名前付きクエリー・プロパティーが定義されていれば、アプリケーションはそのクエリーを実行し、クエリーによって返された結果にビジネス・ロジックを適用することができます。単純にするため、この例に示すビジネス・ロジックは、表面利率の他、対象の取引に関連付けられた社債情報を取得するだけにすぎません。本番アプリケーションの場合には、これよりも複雑なビジネス・ロジックが含まれることになります。

リスト 3 の後半部分には、データベース・サーバーから適切な XML データを取得して、アプリケーション・サーバーでデータを操作するロジックが記載されています。このコーディング・パターンが従っている手法は、連載の第 1 回で一例として紹介した手法と同じです (「参考文献」を参照)。まず、このアプリケーションは、DB2 から返された XML 取引レコードの一部に対して XML フィーチャー・パックが実行する XQuery 実行可能オブジェクトを作成します。次に、適切なコレクション・リゾルバーを指定します。このリゾルバーが DB2 データベースに接続し、クエリーのパラメーター・マーカーに適切なデータ値 (取引で参照されるエンティティーの名前) を渡してクエリーを実行します。

サンプルのリゾルバー実装は、連載第 1 回のリスト 8 で説明したリゾルバーとまったく同じなので、ここでは詳細を繰り返しませんが、このリゾルバーは jdbc:// という URI スキームで始まるコレクションを処理し、名前付きクエリーを使用して URI の残りの部分を解決して、適切なロジックを実行します。記事で説明する残りのサンプル・コードと同じく、このリゾルバーもダウンロードすることができます。リンクについては、「ダウンロード」を参照してください。

ここで使用しているリゾルバーの設計は、XML フィーチャー・パックに同梱されているサンプルをベースとしており、ネイティブ XML データベースへのアクセス (DB2 pureXML など) を提供する方法の 1 つでしかないことに注意してください。このコードを本番アプリケーションで使用する場合には、必要に応じてサンプルを変更または拡張する必要があります。また、連載第 1 回でも、他に考えられるリゾルバーの設計手法を簡単に説明しています。その一例としては、第 1 回のリスト 14 を見てください (「参考文献」を参照)。

データベースから適切なクレジット・デフォルト・スワップ・データを取得した後、アプリケーションは必要に応じてさらにデータを操作することが可能です。例えば、リスト 4 に記載する XQuery 関数をアプリケーション・サーバーで実行すると、データベースから返された各取引データで参照されている社債の証券 ID、表面利率、満期日が抽出されます。

リスト 4. 取引データから社債情報を取得する XML フィーチャー・パックの XQuery プログラム、getCreditDefaultSwaps.xq からの抜粋
declare variable $my:entityName as xs:string external;

declare variable $databaseURI := 
   concat('jdbc://getCreditDefaultSwapsByEntityName?cd%&', $my:entityName); 
declare variable $creditDefaultSwaps := collection($databaseURI);

for $bond in $creditDefaultSwaps//fpml:bond
     return
<tr>
     <td>{ $bond/fpml:instrumentId }</td>
     <td>{ $bond/fpml:couponRate }</td>
     <td>{ $bond/fpml:maturity }</td>
</tr>

ランタイム・パフォーマンスの向上を目的とした索引の作成

データベースから適切な XML データを取得して中間層で操作するためのロジックを理解できたところで、今度はパフォーマンスに目を向けます。このクエリーがデータベース層で効率的に実行されるように、FPMADMIN.FPML43 テーブルに以下の 2 つの索引を作成しました。

  • FPMLADMIN.COMMENTX: リレーショナル COMMENT 列に付ける索引
  • FPMLADMIN.ENTITYNAME: XML DOCUMENT 列の特定のノードに付ける索引

この後すぐにわかるように、DB2 はこの両方の索引を使用して、クエリーの効率的なアクセス・パスを生成することができます。リスト 5 に、これらの索引を作成する方法を示します。このリストでは、最初の文でリレーショナル索引を定義し、2 番目の文で XML 索引を定義しています。

リスト 5. リレーショナル索引および XML 索引の作成
create index fpmladmin.commentx on fpmladmin.fpml43(comment)

create index fpmladmin.entityname on fpmadmin.fpml43(document) 
generate key using xmlpattern  
  'declare default element namespace "http://www.fpml.org/2009/FpML-4-7"; 
  /FpML/trade/creditDefaultSwap/generalTerms/referenceInformation
       /referenceEntity/entityName' 
as sql varchar(1000)

これらの索引を作成した理由は、サンプル・データベースの FPMLADMIN.FPML43 テーブルは 4MB のサイズで、900 近くもの行があるためです。そのうち、ターゲットの企業 (Agrium Inc.) を名前付きエンティティーとして参照するクレジット・デフォルト・スワップ関連のデータはほんのわずかしかありません。リレーショナル索引と XML 索引の両方を使うことで、DB2 は対象のデータを素早く特定することができます。したがって、テーブル内のすべての行をスキャンしてパフォーマンスに大きな負担をかけなくても済みます。

DB2 の組み込み RUNSTATS 機能を使用して適切な統計データが収集された後、DB2 がサンプル・クエリーのために選択したアクセス・プランは図 3 のとおりです。この図を下から上に辿っていくと、DB2 が両方の索引を使用して、サンプル・アプリケーションによって要求されたデータを素早く取得することがわかります。

図 3. DB2 がリレーショナル索引と XML 索引の両方を使用して効率的にデータにアクセスする様子
FPMLADMIN.COMMENTX 索引と FPMLADMIN.ENTITYNAME 索引の両方を使用する DB2 のスクリーン・キャプチャー

DB2 データ・アクセス・プランを表示し、解釈する方法についての詳細は、「参考文献」を参照してください。


一時 XML データと永続 XML データに対するクエリー

XML フィーチャー・パックでは、(おそらく Web サービスや Java アプリケーションで生成された) 一時 XML データと永続 XML データを結合する XQuery 式を作成することも可能です。ご想像のとおり、それにはさまざまな方法があります。その 1 つの方法を、これから詳しく説明します。

結合のシナリオ

例えば、デリバティブの投資を分析しなければならないアプリケーションがあるとします。この場合、このアプリケーションの 1 つの側面で、クレジット・デフォルト・スワップ取引で参照されている企業に関する現行のマーケット・データを取得しなければならないことが考えられます。そのようなマーケット・データの単純な例は、株価の現在値に関する情報などです。DB2 にデリバティブ取引レコードが保管されていて、株式情報を Web サービスから取得できるとすれば、このアプリケーションは永続 XML データと一時 XML データを結合しなければなりません。

結合シナリオのサンプル Java EE コード

リスト 6 に示すのは、XML フィーチャー・パックを使用して必要な作業を行う 1 つの例です。DB2 からクレジット・デフォルト・スワップを取得するためのクエリーはリスト 3 と同じなので説明は省きます。また、適切なリゾルバーを使用してクエリーを実行する方法についても、前のシナリオとほとんど同じです。

リスト 6 で何が新しいかと言うと、別の XQuery 実行可能オブジェクトが定義されていることです。具体的には、XML フィーチャー・パックの結合を処理する XQuery 関数が定義されています。さらにリスト 6 では、DB2 に保管された適切な取引データと結合される一時 XML データを表すための StreamSource オブジェクトを作成しています。説明を単純にするため、StreamSource には assets.xml という名前のファイルからデータを取り込みます。このデータを使用して、ポートフォリト分析に役立つ一時マーケット・データを表します (ただし本番アプリケーションでは、この XML データは Web サービスやメッセージ・キューから生成されることになるはずです)。

リスト 6. 一時 XML データと永続 XML データを結合する Java EE アプリケーション
// Create the XQuery executable.   
Source source = 
    new Source(FpMLServlet.class.getResource("/joinCreditDefaultSwap.xq").toString());
XQueryExecutable joinCreditDefaultSwapsXQ = factory.prepareXQuery(source, staticContext);
...

// Declare the resolver and execute the join. 
// The resolver will issue the DB2 query, and WebSphere software will join its output 
// with XML data in the StreamSource object. 
JDBCCollectionResolver inputResolver = 
    new JDBCCollectionResolver(getConnection(), dbStatements);
dynamicContext.setCollectionResolver(inputResolver);
StreamSource source = 
    new StreamSource(FpMLServlet.class.getResourceAsStream("/assets.xml"));
dynamicContext.bind(new QName("http://com.ibm.xml.samples", "entityName"), name);
XSequenceCursor output = joinCreditDefaultSwapsXQ.execute(source, dynamicContext);

assets.xml ファイルの内容は、リスト 7 のとおりです。

リスト 7. このサンプルでの一時 XML データを表す assets.xml の内容
<?xml version="1.0" encoding="UTF-8"?>
<assets>
     <equity>
          <symbol>AGU</symbol>
          <name>Agrium Inc.</name>
          <currency>USD</currency>
          <high>64.06</high>
          <low>62.79</low>
     </equity>
     <equity>
          <symbol>STM-FP</symbol>
          <name>STMicroelectronics N.V.</name>
          <currency>EUR</currency>
          <high>6.92</high>
          <low>7.2</low>
     </equity>
</assets>

リスト 8 に、一時 XML データと永続 XML データを結合する XQuery 関数を記載します。

リスト 8. 結合を行う XML フィーチャー・パックの XQuery プログラム、joinCreditDefaultSwaps.xq からの抜粋
declare variable $my:entityName as xs:string external;

declare variable $databaseURI := 
    concat('jdbc://getCreditDefaultSwapsByEntityName?cd%&', $my:entityName); 
declare variable $creditDefaultSwaps := collection($databaseURI);

declare function local:equityRows($root) {
     for $equity in $root//equity
     let $referenceEntity := $creditDefaultSwaps//fpml:referenceEntity
     where $equity/name = $referenceEntity/fpml:entityName
     return
          <tr xmlns="http://www.w3.org/1999/xhtml">
               <td>{ $equity/*:symbol/text() }</td>
               <td>{ $equity/*:name/text() }</td>
               <td>{ $equity/*:high/text() }</td>
               <td>{ $equity/*:currency/text() }</td>
          </tr>
};

<table border="1">
<tr>
     <th>Ticker Symbol</th>
     <th>Company Name</th>
     <th>High</th>
     <th>Currency</th>
</tr>
{ local:equityRows(/) }
</table>

この関数の FOR 節が一時 XML データに含まれるエンティティー・ノードをループし、LET 節が、リスト 6 に定義された名前付きクエリーを DB2 が実行した後に返すクレジット・デフォルト・スワップ・データのコレクションから、参照されているエンティティー情報を抽出します。そして WHERE 節が、アセット名に基づいて一時 XML データと永続 XML データを結合するという仕組みです。この関数は、DB2 から返されたクレジット・デフォルト・スワップで参照されているすべての企業の銘柄記号、企業名、高値、通貨などに関する情報を XHTML 形式で返します。

一時 XML データと永続 XML データを結合する場合には、結合を行う場所について考慮することが重要です。あるソフトウェア層に存在する大量のデータと別のソフトウェア層に存在するわずかな量のデータと結合しなければならないとしたら、通常は大量のデータを持つ層で結合を行うほうが効率的です。


永続 XML データの更新

XML ベースの Java EE アプリケーションに一般的な要件には、永続 XML データの更新が関係する要件もあります。連載の第 1 回では、永続 XML 文書を、メモリーに保管された別の文書と置き換える方法を示すサンプル・コードを記載しました。このような文書全体の更新が役立つ場合もあることは確かですが、多くのアプリケーションで必要となるのは、XML 文書を部分的にだけ更新することです。その方法を今から説明します。

DB2 がサポートする XQuery Update Facility は、プログラマーが特定の XML ノードをさまざまな方法で更新できるように標準化された XQuery の拡張です。この標準では例えば、プログラマーが新しいノードを追加したり、ノードを削除したりできるだけでなく、要素の値や属性値の更新などといったタイプの更新を行うことができます。例えば、サブ文書の更新がランタイム・パフォーマンスの向上に役立つことはよくあります。この場合、プログラマーが行うのは XML 文書の特定の部分に対する変更を指定することだけです。DB2 はこれらの更新をサーバー上で直接行うため、アプリケーション・プログラミング・ロジックも、行わなければならないデータ転送も最小限となります。これとは対照的に、CLOB や BLOB に依存して XML を管理する DBMS には、データベースから XML 文書を取得して構文解析し、必要に応じて文書を更新してから再びデータベースに書き込むというアプリケーションが必要です。大規模な XML 文書のほんのわずかな部分だけを変更すればよい場合には、このようなアプリケーションを使用することで生じるパフォーマンスの低下はかなりなものになる場合があります。

更新のシナリオ

アプリケーションが XML ノードの値を変更しなければならない場合を考えてみてください。例えば、クレジット・デフォルト・スワップ取引の両当事者が、取引の予定終了日に関する条件を再交渉するとします。取引の予定終了日は FpML 取引レコードで 1 つのノードとして表現されているので、データベースに保管された該当する FpML 取引レコードを更新して、新しい条件を反映させなければなりません。新しい条件は、一時 XML メッセージとして Java EE アプリケーションに渡すことができます。

コンプライアンス上の理由から、デリバティブ取引に携わる企業は多くの場合、変更された取引レコードをデータベース内で新しいレコードとして表現しますが、ここではチュートリアルとして、元の FpML レコードを直接変更する方法を説明します。

永続 XML データのサブ文書を更新する例

インタラクティブに実行されるリスト 9 の SQL 文は、FPMLADMIN.FPML43 テーブルの DOCUMENT 列に含まれる XML データを更新します。

リスト 9. DB2 に保管された文書の XML ノードの更新
update FPMLADMIN.FPML43 
set document = 
  xmlquery ('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
    transform copy $new := $x 
    modify do replace 
      $new/FpML/trade/creditDefaultSwap/generalTerms/scheduledTerminationDate 
    with 
      <scheduledTerminationDate xmlns="http://www.fpml.org/2009/FpML-4-7">
         <adjustableDate>
            <unadjustedDate>2011-05-05</unadjustedDate>
            <dateAdjustments>
               <businessDayConvention>FOLLOWING</businessDayConvention>
            </dateAdjustments>
         </adjustableDate>
         <comment>This is new.</comment>
      </scheduledTerminationDate>
    return $new' passing document as "x")
where comment like 'cd-ex10-long-us-corp-fixreg-47%'and
  xmlexists('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
    $fpml/FpML/trade/creditDefaultSwap/generalTerms
    /referenceInformation/referenceEntity[entityName="Agrium Inc."]' 
    passing document as "fpml")

この更新は、WHERE 節によって、Agrium Inc. に関係する特定のクレジット・デフォルト・スワップ取引に制限されます。この節のロジックは、前のシナリオで説明したロジックとほとんど同じなので、ここでは説明を省きます。

このクエリーの興味深い部分は、XMLQuery() 関数呼び出しに含まれている式です。適切なデフォルト名前空間が宣言された後、この式は元の XML 文書の値 (図 2 を参照) を $new 変数にコピーします。MODIFY 節は予定終了日のノードを新しいノードで置換します。この新しいノードは実質的に、以下に示す 4 点の変更を元のノードに対して行います。

  1. 未調整日 (子ノード) の値が新しい日付 (2011年 5月 5日) に変更されます。
  2. 休日調整 (子ノード) の値が「FOLLOWING」に変更されます。
  3. ビジネス・センターに対応する子ノードが削除されます (その結果、ビジネス・センター・ノードの子ノードが削除されます)。
  4. 新しい子ノードがコメントに追加されます。

そして最後に、RETURN 節が予定終了日を表す新しいノードを返し、DB2 がこの変更後のデータで DOCUMENT 列のデータを更新します。

更新シナリオのサンプル Java EE コード

上記の更新操作を Java EE アプリケーションに実装する方法を考えてみてください。ご想像のとおり、このクエリーをアプリケーションに組み込むときには、パラメーター・マーカーとエスケープ文字を使用しなければなりません。リスト 10 の最初の部分には、インタラクティブに実行される UPDATE 文 (リスト 9) を Java EE アプリケーションの名前付きクエリーに変換する方法を示してあります。これまでのシナリオと同じく、この例でもリボルバーに依存してデータベース操作を実行します。

リスト 10. DB2 pureXML による XML 要素の置換
// Define the database query. 
// In this case, the named query will update part of an FpML trade record. 
dbStatements = new HashMap<String, String>();
dbStatements.put(
  "updateScheduledTerminationDateByEnityName",
  "update fpmladmin.fpml43 set document = " + 
  "xmlquery('" +
    "declare default element namespace " + 
       "\"http://www.fpml.org/2009/FpML-4-7\"; " +
     "transform copy $new := $x " +
     "modify do replace " +
       "$new/FpML/trade/creditDefaultSwap/generalTerms/scheduledTerminationDate with $d "+
     "return $new' " +
     "passing cast (? as xml) " +
     "as \"d\", " +
     "document as \"x\"" +
  ") " +			
  "where comment like ? and " +
    "xmlexists(" +
        "'declare default element namespace " + 
            "\"http://www.fpml.org/2009/FpML-4-7\"; " +
        "$fpml/FpML/trade/creditDefaultSwap/generalTerms" +
            "/referenceInformation/referenceEntity[entityName=$name]'" +
        "passing document as \"fpml\", cast (? as varchar(100)) as \"name\"" +
     ")"
);
...

// Create an XSLT executable and execute it with the JDBC resolver 
Source source = 
  new Source(FpMLServlet.class.getResource("/updateCreditDefaultSwap.xsl").toString());
XSLTExecutable updateCreditDefaultSwapXSL = 
  factory.prepareXSLT(source, staticContext);
...
JDBCResultsResolver resultsResolver = 
  new JDBCResultsResolver(getConnection(), dbStatements);
dynamicContext.setResultResolver(resultsResolver);
dynamicContext.bind(new QName("http://com.ibm.xml.samples","entityName"),"Agrium Inc.");
dynamicContext.bind(new QName("http://com.ibm.xml.samples","tradeType"),"cd-ex10-long%");
dynamicContext.bind(new QName("http://com.ibm.xml.samples","updateOrRestore"),"update");
...

// "newDate" is XML and comes from a non-DB2 XML data source
XItemView newDate = getUpdatedTerminationDate();
dynamicContext.bind(new QName("http://com.ibm.xml.samples",
   "updatedScheduledTermination"), newDate);
...
StreamResult result = new StreamResult(servletResponse.getOutputStream());
updateCreditDefaultSwapXSL.execute((Source)null, dynamicContext, result);

これまでのシナリオでは XQuery プログラムを使用しましたが、この例では代わりに XSLT 2.0 スタイルシートを使用しました。リスト 11 に、この XSLT コードの一部を記載します。

リスト 11. 永続 XML 文書の一部を更新するための XSLT
<xsl:param name="my:entityName" as="xs:string" />
<xsl:param name="my:tradeType" required="yes" as="xs:string" />
<xsl:param name="my:updateOrRestore" required="yes" as="xs:string" />
<xsl:param name="my:updatedScheduledTermination" as="node()" />

<xsl:variable name="updateCreditDefaultSwapURL"
    select="concat('jdbc://updateScheduledTerminationDateByEnityName?--XML--&', 
       $my:tradeType, '&', $my:entityName)" />

<xsl:when test="$my:updateOrRestore eq 'update'">
    <xsl:result-document href="{$updateCreditDefaultSwapURL}" method="xml" indent="yes">
    <xsl:copy-of select="$my:updatedScheduledTermination" />
  </xsl:result-document>
</xsl:when>

新しい XML 文書での XML データおよびリレーショナル・データの統合

Java EE プログラマーがデータベース層から取得したリレーショナル・データと XML データの XML 表現のみを必要とする場合、この目標を達成するのに役立つのは、DB2 のサブ文書更新サポートです。

プログラマーはこの更新サポートを使用して、例えば DB2、Oracle、あるいは他の DBMS に保管されたテーブルのリレーショナル列から抽出した情報を XML データに追加する単一の文を作成することができます。プログラマーが複数のシステムにまたがる XML データとリレーショナル・データを統合することを可能にするこの機能は、さまざまな状況で役立ちます。このシナリオは、記事のダウンロードとして用意されているサンプル・コードには含まれていませんが、このようなクエリーを実行する方法は、今まで説明してきた例での方法と同じです。

DB2 のサブ文書更新サポートを使用して XML データとリレーショナル・データを統合する方法を理解するには、例えばサンプル FpML データベースに、デリバティブ取引に頻繁に関与する関係者の連絡先情報を記録する従来のリレーショナル・テーブルが含まれていると想像してください。このテーブルの定義は、リスト 12 のとおりです。

リスト 12. FPMLADMIN.PARTYCONTACTINFO テーブルの作成
CREATE TABLE FPMLADMIN.PARTYCONTACTINFO (
          PARTYID VARCHAR(40) PRIMARY KEY NOT NULL,
          PARTYNAME VARCHAR(100),
          PHONENO BIGINT,
          EMAILID VARCHAR(100),
          ADDRESS1 VARCHAR(100),
          ADDRESS2 VARCHAR(100),
          CITY VARCHAR(100),
          ZIPCODE BIGINT,
          STATE VARCHAR(100),
          COUNTRY VARCHAR(100)
     )

大抵、FpML 取引レコードにはデリバティブ取引の関係者に関する限られた情報しか含まれていませんが、それでも取引確認 (契約) には詳細な情報が必要になることがよくあります。リスト 13 に示されているように、DB2 に対するたった 1 つのステートメントで簡単にリレーショナル・データをXML 要素に変換し、これらの要素を XML 文書の適切なノードに挿入して、処理用の新しい XML 文書を返すことができます。

リスト 13. リレーショナル・データで構成される FpML 取引レコードを XML 文書にする
select xmlquery ('declare default element namespace "http://www.fpml.org/2009/FpML-4-7"; 
  transform 
  copy $new := $message 
  modify for $i in $new/FpML/party
  return
    do insert 
      db2-fn:sqlquery("select 
         XMLELEMENT(NAME ""ContactInfo"", 
         XMLELEMENT(NAME ""Address1"", p.ADDRESS1), 
         XMLELEMENT(NAME ""Address2"", p.ADDRESS2), 
         XMLELEMENT(NAME ""CITY"", p.CITY), 
         XMLELEMENT(NAME ""STATE"", p.STATE), 
         XMLELEMENT(NAME ""COUNTRY"", p.COUNTRY),
         XMLELEMENT(NAME ""PHONE"", p.PHONENO)
         ) 
         from FPMLADMIN.PARTYCONTACTINFO p 
         where partyId=parameter(1)", $i/partyId/text()) 
         as last into $i
         return <newroot>{$new}</newroot>'
  passing F.DOCUMENT as "message") 
FROM FPMLADMIN.FPML43 f  
where id=47022

リレーショナル・データがリモート DB2 や OEM データベース内に置かれているとしても、該当するリモート・テーブルのニックネームをデータベースに作成すればよいのです。ニックネームはローカル DB2 サーバーに対してリモート・データベースのオブジェクトを示すため、プログラマーはこれらのオブジェクトをローカル DB2 テーブルであるかのように扱うことができます。したがって、リモートにある DB2 や Oracle、あるいは他のデータベースにデータが保管されているとしても、リスト 13 のクエリーには何の変わりもありません。

さらに、情報が増補された取引データを DB2 データベースの XML 列に挿入するようにクエリーを変更するのも簡単なことで、リスト 13SELECT 節の直前に INSERT INTO . . . 節を組み込むだけでよいのです (リスト 9 のクエリーでも、元の取引レコードはそのまま保持し、変更後の取引データを新しい文書としてデータベースに挿入したいとしたら、これと同様の方法を使用することができます)。


まとめ

この連載の第 2 回では、Java EE プログラマーがアプリケーション・サーバー層とデータベース・サーバー層でネイティブに XML を操作する方法を、いくつかのサンプル・アプリケーションを使用して説明しました。大量の一時 XML データと永続 XML データをサーバー・サイドの Java アプリケーションで処理するには、この記事で行ったように XML データとリレーショナル・データの両方に索引機能およびクエリー・フィルタリング機能を使用します。また、永続 XML データのサブセットを操作する方法として、データベースから対象とする XML ノードだけを抽出する方法、文書内の特定の XML ノードだけを更新する方法もサンプル・アプリケーションで説明しました。永続 XML 文書のフラグメントを操作することで、アプリケーション・サーバー層とデータベース・サーバー層の間での不要なデータ転送を避けられるとともに、アプリケーション・サーバーで行わなければならない処理を減らすことができます。記事では最後に、プログラマーが一時 XML データと永続 XML データを結合する方法についても説明しました。この方法は、多くのソフトウェア・コンポーネントで XML が広く使用されているようになっている現在では、ますます普遍的になってきているプログラミング要件です。

謝辞

この記事をレビューしてくれた Lee Ackerman 氏と Matthias Nicola 氏に感謝いたします。また、この記事のダウンロードに含まれる DB2 スクリプトの開発に協力してくれた、Susan Malaika 氏と彼女の同僚にも感謝いたします。


ダウンロード

内容ファイル名サイズ
Sample Java code using the XML feature packFpML-Sample-WASXMLFEP-DB2pureXML.zip5MB
Sample FpML data and DB2 scriptfpmldb2was.zip2MB

参考文献

学ぶために

製品や技術を入手するために

  • DB2 Express-C: pureXML が含まれる無料の DB2 Express C エディションをダウンロードしてください。
  • WebSphere Application Server: IBM WebSphere Application Server for Developers は完全にライセンス交付された製品で、無料でダウンロードできます。
  • IBM 製品の評価版: DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードするか、IBM SOA Sandbox のオンライン試用版を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Information Management, WebSphere
ArticleID=617696
ArticleTitle=多層にわたる XML のプログラミング: 第 2 回 XML データベース・サーバーを利用する効率的な Java EE アプリケーションを作成する
publish-date=10112010