はじめに
NeoCoreサポートセンタを運営し、様々なご質問をいただき日々回答をさせていただいております。まだまだ新しい分野ということもあり、十分なサポートをご提供できていないのではと、精進を心がけています。
いただく、ご質問の中に「どのようにXMLを設計すればよいのか? スキーマレスとはいってもアプリケーションがどのようにXMLを使用するのかはあらかじめ設計する必要がある。」といったものを受け取ることがあります。
NeoCoreXMSはXMLであればすべてDBが受け入れますので、XMLの変更には非常に柔軟に対応することは可能ですが、根幹となるXMLデザインがどうなっているかは少なからず開発に影響を与えます。
ここでは、NeoCoreXMSの特性を踏まえて、どのようにXMLデザインするべきかを簡単な例をあげて一緒に考えさせていただきたいと思います。もちろん設計上や他の要件による制約もありますので、なにが一番よいデザインであるかを決めることは難しい問題です。少しでも皆様の開発の手助けになれば幸いです。
XMLの特徴
いまさら述べるまでもありませんが、RDBで開発してきたものをXML DBで開発するには以下のXMLが持つ特徴を生かしたいと考えられていると思います。
XMLを利用してデータモデルを記述すると、直感的なやり方で記述することができます。それは以下の点のような特徴を持つからです。
● 半構造性
データ単位(RDBでいうレコード)でデータ項目が揃っている必要はありません。情報が存在するときに制約無しに表現ができます。普段は存在しないデータが特定条件のときにN個現れるという場合には有効です。
● 柔軟性
データの長さに対する制限はありません。各データは必要に応じたサイズを利用できます。
● 拡張性
データ構造をあらかじめすべて決定しておく必要はありません。変更を避けるように設計するのではなく取り込めるように設計することができます。
XMLの表現方法
XMLを構成する以下の4つが組み合わさって表現されます。
● タグ
「データ」が何であるかを定義するものです。データの定義がわからなければ「データ要素」が何であるかがわからなくなります。XMLではタグでデータに意味を持たせます。
● 属性
データ要素についての情報やその解釈方法をあらわします。XMLのデザインについてしばしば議論され、明確な方向性が定まっていないのが、この属性のあらわし方です。デザインする上では、タグと属性のポリシーを統一化させておくことが、XMLの可読性をあげるという面では有効と考えます。
※個人的には、あまり属性を使ったデザインは使っていません。データが何であるかを表すことについてはタグと属性の境界があいまいであり、XML階層を深くすることを嫌ったとしか思えないXMLが多いからです。
● データ要素
これまで「データ」として扱ってきたものです。
● 階層
タグ、属性、データ要素を用いてそれぞれのデータ項目が記述できました。データをすべて一度に記述するには階層構造を用います。個々のデータの関係をカテゴライズし、階層構造でデータの定義を表現していることを意識します。
XMLデザインサンプル
商品情報を例に取って考えてみましょう。商品といってもいろいろなものが想定されますので、PCを例に取ってみます。まずは、PCの商品情報の構成要素を洗い出してみます。
・ 名称
・ 品番
・ メーカー名
・ CPU
・ HD
・ RAM
・ バンドルソフト
・ 価格
これらをcomputerというタグで始まるXML設計をしてみましょう。
例1
<computer name="name01" maker="maker01" CPU="Intel01" HD="40GB" RAM="256MB" os="Windows2000" price="\248,000" /> |
これはすべてを1行でPCを表現しています。 また、HDやRAM、priceといったものには、単位と値が混在しています。
例2
<computer> <name>name01</name> <maker>maker01</maker> <CPU>Intel01</CPU> <HD>40</HD> <RAM>40</RAM> <os>Windows2000</os> <price>248000</price> </computer> |
DB(NeoCoreXMS)にとってはどちらのXMLであっても格納可能ですし、検索にかかるコストもほとんど同じです。
それでは、PCの登録台数がどんどん増えていった場合を考えてみます。
検索にヒットするXML文書が増加すると、データの転送速度が増大します。そこで必要なデータのみを抽出することにしますが、例1では対象行が全て抽出されます。(検索結果から必要な属性の値のみ抽出することは可能です)
osがWindows2000のnameのみを抽出したいという場合には以下のように記述しますが、例2の方が効率的です。
【例1】/ND/computer[@os='Windows2000']/@name.text()
【例2】/ND/computer[os='Windows2000']/name
XML構造が複雑になればなるほど、このような状況が予想されます。例えば、HDだけでは何を意味するか分かりませんので「単位」を追加する。「回転数」「接続I/F」を追加するとしていきます。
ところがosがWindows2000のPC名を検索するにはこのHD関連の情報は不要なのです。不要なものを処理しようとすれば、その分処理に時間がかかってしまいます。
つまり、どのような処理(Query)を行うのかを、意識した設計が必要となります。また、実際のQueryの実行であっても、取得するデータ量が小さくなるようにすることを意識します。
次の例では、RDBのjoinの考え方をXMLでも行うことを考えてみます。
最初の例のPCの注文情報のデータを考えます。注文情報の情報としては以下のものがあります。
・ 注文ID
・ 注文日付
・ 注文者名
・ PC名
・ 個数
・ 単価
・ 金額
・ 発送先
・ 注文状態(受付、確定、発送済み)
|
<order ordered="001"> <orderData>2004/07/27</orderDate> <orderInfo> <name>ネオコア </orderInfo> </item> </item> |
注文者の詳細情報やPCの情報をどこまでこの注文情報の中に含めるかが、処理速度の面で差が出てきます。RDBでの開発でも同じですが正規化しすぎたデータは逆に処理効率を落としてしまいます。「注文情報」としたときに、必要な情報は1つのツリーやレコードに納まっている方が処理速度が高速になるのはご理解いただけると思います。
また、このようなログ型の情報ではマスタの変更を注文情報に反映するのではなく、そのトランザクションが発生した時点でのデータを保持しておきたいという要求も多くあります。
PCに商品IDを追加して、coumputerとorderでデータを管理しているXMLを設計してみます。
|
<computer ID="PC001"> <name>name01</name> <maker>maker01</maker> <CPU>Intel01</CPU> <price>248000</price> <orderInfo> <email>taro@neocore.jp</email> </item> </order> |
単価とPC名はcomputerノードより取得することにします。
|
for $order in (/ND/order) let $pcname in (/ND/computer[@ID=$order/item/PC]/name |
--- 必要な形に整形します ---
こうすると注文情報の1item毎にcomputer内のマッチする情報を検索しなければなりません。
これまで見てきたサンプルのようにXMLを設計する上ではどのように処理を行うかといったイメージを持つことが非常に重要です。
NeoCoreXMSはスキーマレスのXML DBですからアプリケーションが使用するXMLがそのまま格納できますので、DBの制約を受けにくいといえます。
ただし、XMLの可読性を高める上では以下の手順も併せて実行されることを推奨します。(NeoCoreXMSの開発元 Xpriori社CTOのChris Brandinが「XML DataManagement」の第1章で述べていることの抜粋です。)
● データ要素を1つずつ(XMLの1行ずつを)見直します。
・ これはデータか、それとも実際にはメタデータ (別のデータ要素についての情報) か?
● すべての属性についても同様にチェックします。
・ 属性を見ると、データ要素について何か分かるか? あるいは、データ要素を解釈、使用、または表現する方法が記述されているか?
・ 属性は本当にメタデータであり、実際にはデータ要素であるということはないか?(属性とデータ要素を混同して使用していないか?)
・ 属性は有効範囲内のすべてのデータ要素に適用されるか?
● すべてのタグを見直します。
・ このタグは、有効範囲内のすべてのデータ要素の内容を記述するのに役立つか?
● XML階層 (兄弟関係) を見直します。
・ グループ内のすべてのメンバーは、親ノードに記述した内容と関連付けられているか?
・ 兄弟間の関係が明瞭か?
もし、今XMLをお持ちでしたら是非上記を頭に浮かべて見直してみてください。きっと読みやすく管理しやすいXMLの姿が見えてくるでしょう。