レベル: 初級 David Mertz, Ph.D (mertz@gnosis.cx), Author, Gnosis Software, Inc.
2001年 5月 01日 XML文書保管形式は、特に散文的で単純な文書向けに普及してきました。しかし、それにつれて、XML文書の集合内の内容を探す作業は難しくなってきています。このコラムでは、XML固有の検索および索引付け機能を含めて、Mertz氏の「魅力的なPython第15回」のコラムで提示された汎用全文検索システム (indexer) について解説します。このコラムでは、このツール設計が、いかにXML階層ノード構造の利点を生かす索引付けに取り組んだかについて議論します。
数千のページで構成される巨大なメガバイト単位の文書は、企業や政府機関の世界では珍しくありません。ライターや技術者は、SGML (Standard Generalized Markup Language)形式の大量の製品仕様、規制要件、コンピューター・システム文書などを日常的に作成しています。技術的な意味では、XMLは、SGMLを簡素化、特殊化したものです。かつて最初の予定では、XML文書は、SGML文書としても有効になるはずでした。
しかし、文化的にXMLは、異なる方向から発展してきました。ある面で、XMLは、EDIの後継者です。別の面では、HTMLの後継者です。XMLは、SGMLとは違う文化的歴史を持っており、XMLはツール開発過程の途上にあります。XMLは、以前にも増して普及してきているので、(通常は) 形式に沿っていないHTML文書と(通常は) 形式に沿ったSGML文書は両方ともXML形式-- 特にDocBookなど、XMLの方言を使用するXML形式の文書 -- の方向にますますマイグレーションしているようです。
しかし、XMLは、その文化の中で、膨大なXML文書内の内容を効果的かつ効率的に探すツールをまだ育てていません。Unixのgrep のような一般的なファイル検索ツールや、他プラットフォーム向けの似たようなツールは、プレーン・テキストであるXML文書を完全に読むことができますが、簡単なgrep 検索では、(または複雑な検索でも)XML文書の構造を見落とすことがあります。
数千ページの文書を格納するファイルの内容を検索する際、単語、句または正規表現で指定できるよりも多くのことを知りたくなるものです。たとえば、農業報告書の内、June Apple氏が書いたものはどれでしょうか?grep のようなきめの粗いツールは、通常、関心のないものまでたくさん探し出してきます。さらに、grep のようなその場その場で特定のものを検索するツールは、動作自体、非常に効率的ですが、検索を実行するつど、毎回巨大なファイルの内容全体を検査しなければなりません。検索するたびに、ファイル全体を検索するのは効率的ではありません。
indexer の拡張
上述の必要性に応えるため、私はパブリック・ドメイン・ユーティリティーxml_indexer を作りました。このPythonモジュールは、ランタイム・ユーティリティーとして使うことができ、そのサービスを使用するカスタム・アプリケーションで容易に拡張できます。モジュールxml_indexer は、以前私がIBM developerWorksの記事indexer およびxml_objectify (参考文献 を参照) で説明した2つのパブリック・ドメイン・ユーティリティーのサービスに依存します。
xml_indexer が使用する「技巧」は、XPathが使うものと同じです。XML文書を、単にファイル・システムの「もの」として扱うよりも、私は、XML文書の階層ノードを、階層ファイル・システムのように見せ掛けることにしました。索引付けのためには、ファイル・システム・パスからXPathを区別するための小さな構文を必要とする以外に、XMLノードを、それ自体がテキスト・ファイルであるかのように扱うだけで済みます。幸運にも、私は、テキストを索引付けする任意のIDを使用できる、十分な柔軟性を持つindexer を設計することができました。検索結果をいくつか見てみましょう。
リスト1. XMLノードに対する索引による検索
[D:\articles] indexer ibm
/articles/tutor/cryptology3.xml::/section[1]/panel[2]/body/text_column/p[1]
/temp/Benchmark/Data/addr2.xml::/person[4]/contact_info/email/@address
/temp/Benchmark/Data/addr2.xml::/person[2]/contact_info/email/@address
/tools/addr2.xml::/person[4]/contact_info/email/@address
/tools/addr2.xml::/person[2]/contact_info/email/@address
5 file matched wordlist: ['ibm']
Processed in 0.320 seconds (SlicedZPickleIndexer)
|
XPathの場合と同様、@ マークは、属性値の前に付け、番号の付いた兄弟ノードは大括弧で囲みます。この文脈では、XML文書のファイル・システム・パスは、ネームスペースのようなものとしてXPath軸のように振る舞います。比較のために、ファイル・データベースに対して、似たような索引による検索を実行してみましょう(検索結果リストを適切なものにするため特定の追加の検索用語を使用します)。
リスト2. 電子メール・メッセージの索引による検索
[D:\articles] indexer ibm python xml indexer
D:\archive\mail\messages\tenco.cp15.2001-03-06.13+50+35
D:\archive\mail\messages\tenco.cp15.2001-03-01.07+57+26
D:\archive\mail\messages\tenco.cp15.2001-02-28.23+25+26
3 file matched wordlist: ['ibm', 'python', 'xml', 'indexer']
Processed in 2.530 seconds (SlicedZPickleIndexer)
|
最初の検索では、ごく小さな量のテスト・データを検索しましたが、2番目の検索では、アーカイブされた電子メール・メッセージ (ファイル当たり1メッセージがファイル・システムに保管される) に対する「実用規模」の索引を使用します。100 MBのファイルを検索するのに、ほんの数秒しか掛からなかったのは、(複数語の同時出現を検索していることを思えば)かなり速いと思います。
さらに、この検索で、異なるインデックス・データベースを使用する限り、(xml_indexer のテスト中に検索するので) テキスト・ファイルやXMLノードの複合索引を作成しない理由はありません。このような場合、各XMLファイルをノードの集まりおよびプレーン・テキストの両方 として索引付けすることができます(これは有益であることが多いでしょう)。これにより、検索結果には、ファイル・システムIDと一緒に両方のIDのタイプが示されます。ファイル・システムIDの方は、ネームスペースにあるXPathが示すのとまったく同じIDです。リスト3に例を挙げます。
リスト3. 電子メール・メッセージの索引による検索
[D:\articles] indexer actresses
/temp/Benchmark/Data/addr_break.xml
/temp/Benchmark/Data/addr_break.xml::/person[3]/misc_info
2 file matched wordlist: ['actresses']
Processed in 0.070 seconds (SlicedZPickleIndexer)
|
索引の作成
読者は、検索を実行している上記の例で、xml_indexer に触れずに indexer を使っていることに注目してください。これは、xml_indexer およびindexer の両方により作成される索引データベースを検索するのに、まったく同じ検索ツールを使用できるからです。事実、indexer は、OSに合ったやり方でコマンド行の引き数を渡し、python indexer.py ... を単に呼び出すだけです。indexer を用いて、テキスト・ファイルの索引を作成ないし拡張することができます (必要な引き数とスイッチの内訳を知るために「indexer --help」または「indexer /?」を実行してください)。索引にファイルを追加すると、ディレクトリー構造の中で再帰的に呼び出すことができます。他のスイッチにより、あるパターンに合致する名前を持つファイルだけを追加するよう索引付けを制限することもできます (regexまたはblobのいずれか)。
少なくとも今のところ、私はもっと簡単なxml_indexer.py スクリプトを使用して XMLノードの索引データベースを作成できます。この記事を書いている時点で、私は、コマンド行の引き数として文書名を指定すれば、1つのXML文書のノードを一度に索引データベースに追加できます。しかし、読者がこの記事を読むころまでに、私は多分indexer.py に似たxml_indexer.py のコマンド行構文を改良しているでしょう。それを使用する前に、python xml_indexer.py --help の出力を見てください。
XPathの指定
検索結果にXPathと同様のワイルドカードの機能を使えるようにするため、私はindexer に-filter オプションを追加しましたが、検索そのものにXPathの機能をサポートしようとしているわけではありません。有益で明らかな副次的作用として、特定のパターンを満たすファイル名だけを知りたい場合に、パス表現をファイル名にまとめるために使えます。
基本的に、/filter オプションは、期待通りに動作します(シェル間で異なる引用構文に調整してください)。フィルターにダブル・コロンを用いればXPathの結果のみに関心があるということを指定できます。
リスト4. XPath検索結果のみを戻す
[D:\articles] indexer "/filter=*::*" actresses
/temp/Benchmark/Data/addr_break.xml::/person[3]/misc_info
1 file matched wordlist: ['actresses']
Processed in 0.050 seconds (SlicedZPickleIndexer)
|
リスト5. ファイルとしてXML文書のみを戻す
[D:\articles] indexer "/filter=*.xml" actresses
/temp/Benchmark/Data/addr_break.xml
1 file matched wordlist: ['actresses']
Processed in 0.050 seconds (SlicedZPickleIndexer)
|
より複雑なXPath指定子を得るためは、必要なサブエレメントと順序を指定してください。
リスト6. 索引内のすべての一致する単語を表示する。
[D:\articles] indexer symmetric
/tutor/cryptology1.xml::/section[2]/panel[8]/title
/tutor/cryptology1.xml::/section[2]/panel[8]/body/text_column/code_listing
/tutor/cryptology1.xml::/section[2]/panel[7]/title
/tutor/cryptology1.xml::/section[2]/panel[7]/body/text_column/p[1]
4 file matched wordlist: ['symmetric']
Processed in 0.100 seconds (SlicedZPickleIndexer)
|
リスト7. 一致をタイトル・エレメント内のものに制限する。
[D:\articles] indexer "-filter=*::/*/title" symmetric
/tutor/cryptology1.xml::/section[2]/panel[8]/title
/tutor/cryptology1.xml::/section[2]/panel[7]/title
2 file matched wordlist: ['symmetric']
Processed in 0.080 seconds (SlicedZPickleIndexer)
|
要約
xml_indexer の設計では、indexer の設計にかかわるオブジェクト指向の原則が、大きな助けになることが分かりました。GenericIndexer クラスのいくつかのメソッドをオーバーライドすることによって、(実際は、その子孫であるSlicedZPickleIndexer -- ですが、実在のIndexerクラスに容易に混合できます)IDやデータ・ソースの新しい集合全体が使用できるようになります。
読者ご自身の大きなPythonプロジェクトの一部としてxml_indexer を使いたいと考える方は、さらなる特殊化が同様に簡単であることを理解してください。私は、皆さんがこのように有益な基本indexクラスをどのように使用するか見るのを楽しみにしています。
参考文献
-
xml_indexerモジュール をダウンロードすることができます。
- 魅力的なPython第15回:Pythonによる全文検索システムの開発 には、
indexer モジュールの背景となる一般的な議論があります。
-
indexer モジュール自体をご覧ください。
- 再帰的かつ容易にXMLノードをたどるために、私は、
xml_objectify により提供されるPython的で高レベルのインターフェースを使用しました。しかし、最近までこのオプションは、実際的ではありませんでした。xml_objectify の古いバージョンは、XMLファイルを読むのにDOMを使用していました。これは、大きなXML文書にはかなり遅いことが分かりました (責任の一部は、xml_objectify がDOMを処理する方法にあります)。Costas Malamasは、expat パーサーとストリーム指向テクノロジーを利用する代わりの解析メソッドを提供しています。この新しいテクノロジーは、特定の複雑なXML文書には不向きですが、ほとんどの場合正しく速く動作します。
xml_objectify
をオンラインで見られます。
- David Mertzの以前の「XMLの論考」コラムをご覧ください。
-
XMLの論考 第1回 : Python xml_pickleオブジェクトの紹介
-
XMLの論考 第2回 : XML文書を "Python風"に処理する方法 (II)
-
XMLの論考 第3回 : XMLの派生語であるDocBookの紹介
-
XMLの論考 第4回 : DocBookのXML版を楽しむ
-
XMLの論考 第5回 : XSLTを使ってDocBook文書を変換する方法
-
XMLの論考 第6回 : 大量のテキストに適したエディターの見地から、半ダースのXMLエディターを比較する
-
XMLの論考 第7回 : DTD対XMLのスキーマを評価し、開発者がDTDに固執して成長途上のW3C XMLスキーマ仕様を嫌う場合に提案を送る
-
XMLの論考 第8回 : コンピューター科学者によって概念化されたデータ・モデル の抽象理論が、いかに特定の複数表現データ・フローの開発を助けるか議論する
-
XMLの論考 第9回 : 移植可能なXML結果セットの、RDBMSから独立した生成を可能にするパブリック・ドメインsql2dtdおよびsql2xmlユーティリティーを議論する
著者について  | 
|  | David Mertz氏は多くの分野で活躍しています。ソフトウェア開発や、それについて著述もしています。その他、学術政策理念について分野を問わず、関係する雑誌に記事も書いています。かなり以前には、超限集合論、ロジック、モデル理論などを研究していました。その後、労働組合組織者として活動していました。そして、David Mertz氏自身は人生の半ばにもまだ達していないと思っているので、これから何かほかの仕事をするかもしれません。 |
記事の評価
|