/[hyperestraier]/upstream/0.5.3/doc/pguide-ja.html
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /upstream/0.5.3/doc/pguide-ja.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Wed Aug 3 15:25:48 2005 UTC (18 years, 10 months ago) by dpavlin
File MIME type: text/html
File size: 57453 byte(s)
import of upstream 0.5.3

1 dpavlin 2 <?xml version="1.0" encoding="UTF-8"?>
2    
3     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4    
5     <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
6    
7     <head>
8     <meta http-equiv="Content-Language" content="ja" />
9     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
10     <meta http-equiv="Content-Style-Type" content="text/css" />
11     <meta name="author" content="Mikio Hirabayashi" />
12     <meta name="keywords" content="Hyper Estraier, Estraier, full-text search, API" />
13     <meta name="description" content="API specifications of Hyper Estraier" />
14     <link rel="contents" href="./" />
15     <link rel="alternate" href="pguide-en.html" hreflang="en" title="the English version" />
16     <link rel="stylesheet" href="common.css" />
17     <link rel="icon" href="icon16.png" />
18     <link rev="made" href="mailto:mikio@users.sourceforge.net" />
19     <title>Programming Guide of Hyper Estraier Version 1 (Japanese)</title>
20     </head>
21    
22     <body>
23    
24     <h1>プログラミングガイド</h1>
25    
26     <div class="note">Copyright (C) 2004-2005 Mikio Hirabayashi</div>
27 dpavlin 10 <div class="note">Last Update: Mon, 01 Aug 2005 00:50:38 +0900</div>
28 dpavlin 2 <div class="navi">[<a href="pguide-en.html" hreflang="en">English</a>] [<a href="index.ja.html">HOME</a>]</div>
29    
30     <hr />
31    
32     <h2 id="tableofcontents">目次</h2>
33    
34     <ol>
35     <li><a href="#introduction">はじめに</a></li>
36     <li><a href="#architecture">アーキテクチャ</a></li>
37     <li><a href="#building">ビルド</a></li>
38     <li><a href="#estdoc">文書を扱うAPI</a></li>
39     <li><a href="#estcond">検索条件を扱うAPI</a></li>
40     <li><a href="#estdb">データベースを扱うAPI</a></li>
41     <li><a href="#gatherer">ギャザラのサンプル</a></li>
42     <li><a href="#searcher">サーチャのサンプル</a></li>
43     <li><a href="#paralleling">並列性</a></li>
44     <li><a href="#tips">助言</a></li>
45     </ol>
46    
47     <hr />
48    
49     <h2 id="introduction">はじめに</h2>
50    
51     <p>この文書では、Hyper EstraierのAPIの詳細な使い方を説明します。<a href="uguide-ja.html">ユーザガイド</a>をまだお読みでない場合は先にそちらに目を通しておいてください。</p>
52    
53     <p>全文検索システムの機能要件は様々ですが、代表的なものを挙げてみましょう。</p>
54    
55     <dl>
56     <dt>リポジトリへの要求</dt>
57     <dd>ファイルシステム、メールボックス、Web、Wiki、RDBMS、各社の文書管理システムなどへの対応。</dd>
58     <dt>文書形式への要求</dt>
59     <dd>プレーンテキスト、HTML、MIME、PDF、RTF、MS-Word、MP3、各種の画像(OCR)などへの対応。</dd>
60     <dt>言語や語彙への要求</dt>
61     <dd>日本語、英語、中国語などの各種言語対応。類義語の正規化。表記揺れの正規化。</dd>
62     <dt>ユーザインターフェイスへの要求</dt>
63     <dd>検索条件の指定方法。結果の表示方法。クライアントの種類。応答時間。同時接続数。</dd>
64     <dt>管理機能への要求</dt>
65     <dd>対象文書の規模。文書の差分登録。無停止運用。バックアップ。移植性。</dd>
66     </dl>
67    
68     <p>考え得る全ての要求に応えることはできませんが、estcmdやestseek.cgiを使うだけでは不可能だった多くのことが、ライブラリを組み込んだアプリケーションを作ることで可能になります。estcmdではファイルとして存在している文書しか扱えませんでしたが、ライブラリを使えば、リレーショナルデータベースに格納されたレコードを文書として扱うアプリケーションを作ることもできます。estseek.cgiはWebブラウザで使うものでしたが、ライブラリを使えば、ネイティブOSのGUIを備えた検索アプリケーションを作ることもできます。</p>
69    
70     <p>Hyper Estraierが提供する「コアAPI」は、転置インデックスというデータ構造を実現する機能を提供するだけです。つまり、文書を取得したり解釈したりする処理はアプリケーションに任されます。検索結果を表示するための処理もアプリケーションに任されます。繰り返しになりますが、Hyper Estraierはリポジトリ(対象文書の格納場所)の種類には依存しませんし、文書形式にも依存しませんし、ユーザインターフェイスにも依存しません。それらはアプリケーション作者が好きなように設計・実装することができます。</p>
71    
72     <p>Hyper EstraierはUnicode(UCS-2)の文字セットを扱い、UTF-8で表現します。したがって、現在世界で日常的に使われているほとんどの言語の文字が利用できます。また、テキストから検索キーを切り出すにあたってN-gram法を用いるので、言語の語彙に依存しません。</p>
73    
74     <p>スケーラビリティ(大規模な文書群を扱う能力)が高いことは、Hyper Estraierの特徴の一つです。スケーラビリティを向上するための工夫はコアAPIの内部でやってくれるので、アプリケーション作者は文書規模のことをそれほど気にしないで済みます。</p>
75    
76     <p>この文書ではコアAPIについて説明しますが、Hyper EstraierはP2Pアーキテクチャに基づく「ノードAPI」も提供しています。ノードAPIについては<a href="nguide-ja.html">P2Pガイド</a>をご覧ください。</p>
77    
78     <hr />
79    
80     <h2 id="architecture">アーキテクチャ</h2>
81    
82     <p>ここでは、Hyper EstraierのコアAPIのアーキテクチャについて説明します。</p>
83    
84     <h3>ギャザラとフィルタ</h3>
85    
86     <p>検索対象の文書のデータをインデックスに登録する機能を「ギャザラ(gatherer)」と呼ぶことにします。ギャザラはアプリケーションが実装します。例えば、estcmdにはファイルシステムを探索して文書のデータを集めてくる機能がありますが、そこでは以下のような処理をしています。</p>
87    
88     <ul>
89     <li>コマンドライン引数を解析して、インデックスの名前や探索の開始点を取得します。</li>
90     <li>インデックスを開きます。</li>
91     <li>ファイルシステムを探索して、登録対象のファイルのパスを特定します。</li>
92     <li>上記でリストアップした個々のファイルに対して‥‥<ul>
93     <li>ファイル名の接尾辞によって文書の種類を判別します。</li>
94     <li>サポートしている種類であれば、ファイルを読み込みます。</li>
95     <li>文書の種類に応じたフィルタ機能を呼んで文書オブジェクトを作成します。</li>
96     <li>文書オブジェクトをインデックスに登録します。</li>
97     </ul></li>
98     <li>インデックスを閉じます。</li>
99     </ul>
100    
101     <p>ファイルなどから文書の属性と本文を取り出す機能を「フィルタ(filter)」と呼びます。フィルタはアプリケーションが実装します。アプリケーションが独自の解析処理を実装してもいいですし、巷に転がっているライブラリを使ってもいいでしょう。あるいは、外部のコマンドを呼び出してその出力を加工してもいいでしょう。</p>
102    
103     <h3>サーチャ</h3>
104    
105     <p>インデックスに検索をかけて該当する文書の情報を取得し、それを表示する機能を「サーチャ(searcher)」と呼びます。サーチャはアプリケーションが実装します。例えば、estseek.cgiはWebサーバ上からCGIで呼び出されて検索結果をHTMLとして生成する機能を持ちますが、それは以下のような処理をしています。</p>
106    
107     <ul>
108     <li>インデックスの名前や各種の表示設定を設定ファイルから読み込みます。</li>
109     <li>CGIのパラメータを解析して、ユーザが入力した検索条件を取得します。</li>
110     <li>インデックスを開きます。</li>
111     <li>全文検索の検索式、属性条件式、順序指定を持たせた検索条件オブジェクトを生成します。</li>
112     <li>インデックスに検索条件オブジェクトを渡して、該当する文書IDのリストを取得します。</li>
113     <li>上記でリストアップした個々の文書IDに対して‥‥<ul>
114     <li>インデックスに文書IDを渡して文書オブジェクトを取得します。</li>
115     <li>文書の属性やスニペットをHTMLに加工してから出力します。</li>
116     </ul></li>
117     <li>インデックスを閉じます。</li>
118     </ul>
119    
120     <p>検索結果をわかりやすくするために、各文書のスニペット(紹介文)を表示した方がいいでしょう。本文から検索語の周辺を抜き出したスニペットを作る機能がコアAPIによって提供されますが、アプリケーションが独自に実装してもかまいません。自然言語処理を行って内容の要約をしてもいいでしょう。本文中の頻出語をキーワードとして表示してもいいでしょう。</p>
121    
122     <h3>典型的なシステム構成</h3>
123    
124     <p>システム構成の典型例を以下に図示します。これはあくまで概念的なもので、実際のアプリケーションではサーチャとギャザラを一つのモジュールで実現してもいいですし、リポジトリにギャザラやサーチャを組み込んでもいいでしょう。</p>
125    
126     <div class="illust"><img src="coreframe.png" width="720" height="550" alt="[framework]" /></div>
127    
128     <hr />
129    
130     <h2 id="building">ビルド</h2>
131    
132     <p>Hyper EstraierのコアAPIはC言語のAPIですので、アプリケーションの実装言語はCまたはC++になります。ただし、将来的には他の言語(JavaまたはRuby)のバインディングも提供される予定です。ここでは、C言語のライブラリを使ったアプリケーションをビルドする方法を説明します。</p>
133    
134     <h3>ヘッダの取り込み</h3>
135    
136 dpavlin 10 <p>コアAPIを使うアプリケーションのソースコードでは、estraier.hとcabin.hとstdlib.hをインクルードしてください。estraier.hはHyper Estraierのヘッダファイルで、cabin.hはQDBMのヘッダファイルです。cabin.hが提供する機能については<a href="http://qdbm.sourceforge.net/spex-ja.html#cabinapi">QDBMの文書</a>をご覧ください。</p>
137 dpavlin 2
138     <pre>#include &lt;estraier.h&gt;
139     #include &lt;cabin.h&gt;
140     #include &lt;stdlib.h&gt;
141     </pre>
142    
143     <h3>コンパイルとリンク</h3>
144    
145     <p>デフォルトではHyper Estraierのヘッダは「/usr/local/include」の中、ライブラリは「/usr/local/lib」にインストールされ、-lestraierの他に前提となるライブラリとして-lqdbm、-lz、-liconv、-lm、-lcを利用します。したがって、Hyper Estraierを組み込んだアプリケーションをビルドするには、以下のようなコマンドを実行すればよいことになります。</p>
146    
147     <pre>gcc -I/usr/local/include -o foobar foobar.c \
148     -L/usr/local/lib -lestraier -lqdbm -lz -liconv -lm -lc
149     </pre>
150    
151     <p>しかし、上記はHyper Estraierのインストール先を変えた場合にはうまく動きません。インテグレーションを自動化する場合には、estconfigコマンドの出力を埋め込むようにして、保守性を向上させましょう。以下のようにします。</p>
152    
153     <pre>gcc `estconfig --cflags` -o foobar foobar.c `estconfig --ldflags` `estconfig --libs`
154     </pre>
155    
156     <h3>インテグレーション用コマンド</h3>
157    
158     <p>estconfigは、Hyper Estraierを使ったシステムやアプリケーションのインテグレーションを行う際に役立つユーティリティコマンドです。Hyper Estraierのビルド時の設定を後で参照するために使います。</p>
159    
160     <dl>
161     <dt><kbd>estconfig --version</kbd></dt>
162     <dd>バージョン情報を出力します。</dd>
163     <dt><kbd>estconfig --prefix</kbd></dt>
164     <dd>全体のインストール先の接頭辞を出力します。</dd>
165     <dt><kbd>estconfig --execprefix</kbd></dt>
166     <dd>プラットフォーム依存ファイルのインストール先の接頭辞を出力します。</dd>
167     <dt><kbd>estconfig --headdir</kbd></dt>
168     <dd>ヘッダファイルのインストール先の接頭辞を出力します。</dd>
169     <dt><kbd>estconfig --libdir</kbd></dt>
170     <dd>ライブラリのインストール先の接頭辞を出力します。</dd>
171     <dt><kbd>estconfig --bindir</kbd></dt>
172     <dd>コマンドのインストール先の接頭辞を出力します。</dd>
173     <dt><kbd>estconfig --libexecdir</kbd></dt>
174     <dd>CGIスクリプトのインストール先の接頭辞を出力します。</dd>
175     <dt><kbd>estconfig --datadir</kbd></dt>
176     <dd>各種設定ファイルのインストール先の接頭辞を出力します。</dd>
177     <dt><kbd>estconfig --cflags</kbd></dt>
178     <dd>アプリケーションのビルド時に指定すべきコンパイラオプションを出力します。</dd>
179     <dt><kbd>estconfig --ldflags</kbd></dt>
180     <dd>アプリケーションのビルド時に指定すべきリンカオプションを出力します。</dd>
181     <dt><kbd>estconfig --libs</kbd></dt>
182     <dd>アプリケーションのビルド時に指定すべきライブラリを出力します。</dd>
183     <dt><kbd>estconfig --sklibs</kbd></dt>
184     <dd>アプリケーションのビルド時に指定すべきソケット用のライブラリを出力します。</dd>
185     </dl>
186    
187     <p>estconfigは常に0を終了ステータスにします。</p>
188    
189     <hr />
190    
191     <h2 id="estdoc">文書を扱うAPI</h2>
192    
193     <p>ここでは、検索対象の文書を扱うためのAPIについて説明します。</p>
194    
195     <h3>機能</h3>
196    
197     <p>構造体型 `ESTDOC' は、文書を抽象化したものです。一つの文書は、複数の属性と複数の本文の集合です。`ESTDOC' の実体が直接参照されることはなく、必ずポインタを介して間接参照されます。このポインタおよびその参照先を総じて文書オブジェクトと呼びます。文書オブジェクトは関数 `est_doc_new' によって生成され、`est_doc_delete' によって破棄されます。生成された文書オブジェクトは必ず破棄してください。</p>
198    
199     <p>検索対象となる文書は、文書オブジェクトとして表現した上で、予めデータベースに登録しておきます。登録済みの文書オブジェクトにはIDが割り当てられます。検索時にはそのIDを元にデータベースに問い合わせて、登録してある文書オブジェクトを取り出すことになります。なお、文書オブジェクトに付加する属性や本文の文字コードはUTF-8にしてください。</p>
200    
201     <p>文書オブジェクトの典型的なライフサイクルを以下に示します。</p>
202    
203     <pre>ESTDOC *doc;
204    
205     /* 生成する */
206     doc = est_doc_new();
207    
208     /* URIとタイトルを属性として付加する */
209     est_doc_add_attr(doc, "@uri", "http://foo.bar/baz.txt");
210     est_doc_add_attr(doc, "@title", "Now Scream");
211    
212     /* 本文を付加する */
213     est_doc_add_text(doc, "Give it up, Yo! Give it up, Yo!");
214     est_doc_add_text(doc, "Check it out, come on!");
215    
216     /* ここでデータベースに登録したり、画面に表示したりする */
217    
218     /* 破棄する */
219     est_doc_delete(doc);
220     </pre>
221    
222     <h3>API</h3>
223    
224     <p>文書オブジェクトを生成するには、関数 `est_doc_new' を用います。</p>
225    
226     <dl>
227     <dt><kbd>ESTDOC *est_doc_new(void);</kbd></dt>
228     <dd>戻り値は文書オブジェクトです。</dd>
229     </dl>
230    
231     <p>文書ドラフトのデータから文書オブジェクトを生成するには、関数 `est_doc_new_from_draft' を用います。</p>
232    
233     <dl>
234     <dt><kbd>ESTDOC *est_doc_new_from_draft(const char *<var>draft</var>);</kbd></dt>
235     <dd>`draft' は文書ドラフトの文字列を指定します。戻り値は文書オブジェクトです。</dd>
236     </dl>
237    
238     <p>文書オブジェクトを破棄するには、関数 `est_doc_delete' を用います。</p>
239    
240     <dl>
241     <dt><kbd>void est_doc_delete(ESTDOC *<var>doc</var>);</kbd></dt>
242     <dd>`doc' は文書オブジェクトを指定します。</dd>
243     </dl>
244    
245     <p>文書オブジェクトに属性を追加するには、関数 `est_doc_add_attr' を用います。</p>
246    
247     <dl>
248     <dt><kbd>void est_doc_add_attr(ESTDOC *<var>doc</var>, const char *<var>name</var>, const char *<var>value</var>);</kbd></dt>
249     <dd>`doc' は文書オブジェクトを指定します。`name' は属性名を指定します。`value' は属性値を指定しますが、`NULL' の場合は属性を削除します。</dd>
250     </dl>
251    
252     <p>文書オブジェクトに本文の一文を追加するには、関数 `est_doc_add_text' を用います。</p>
253    
254     <dl>
255     <dt><kbd>void est_doc_add_text(ESTDOC *<var>doc</var>, const char *<var>text</var>);</kbd></dt>
256     <dd>`doc' は文書オブジェクトを指定します。`text' は本文の一文を指定します。</dd>
257     </dl>
258    
259     <p>文書オブジェクトに隠しテキストの一文を追加するには、関数 `est_doc_add_hidden_text' を用います。</p>
260    
261     <dl>
262     <dt><kbd>void est_doc_add_hidden_text(ESTDOC *<var>doc</var>, const char *<var>text</var>);</kbd></dt>
263     <dd>`doc' は文書オブジェクトを指定します。`text' は隠しテキストの一文を指定します。</dd>
264     </dl>
265    
266     <p>文書オブジェクトのID番号を取得するには、関数 `est_doc_id' を用います。</p>
267    
268     <dl>
269     <dt><kbd>int est_doc_id(ESTDOC *<var>doc</var>);</kbd></dt>
270     <dd>`doc' は文書オブジェクトを指定します。戻り値は文書オブジェクトのID番号です。もしそのオブジェクトがまだ登録されていない場合、-1が返されます。</dd>
271     </dl>
272    
273     <p>文書オブジェクトの属性名のリストを取得するには、関数 `est_doc_attr_names' を用います。</p>
274    
275     <dl>
276     <dt><kbd>CBLIST *est_doc_attr_names(ESTDOC *<var>doc</var>);</kbd></dt>
277     <dd>`doc' は文書オブジェクトを指定します。戻り値は文書オブジェクトの属性名のリストです。戻り値のオブジェクトは `cblistopen' で生成されているので、不要になったら `cblistclose' で破棄してください。</dd>
278     </dl>
279    
280     <p>文書オブジェクトの属性の値を取得するには、関数 `est_doc_attr' を用います。</p>
281    
282     <dl>
283     <dt><kbd>const char *est_doc_attr(ESTDOC *<var>doc</var>, const char *<var>name</var>);</kbd></dt>
284     <dd>`doc' は文書オブジェクトを指定します。`name' は属性名を指定します。戻り値は属性値ですが、該当する属性がない場合は `NULL' が返されます。戻り値の文字列の寿命は文書オブジェクトのそれと同期します。</dd>
285     </dl>
286    
287     <p>文書オブジェクトの本文のリストを取得するには、関数 `est_doc_texts' を用います。</p>
288    
289     <dl>
290     <dt><kbd>const CBLIST *est_doc_texts(ESTDOC *<var>doc</var>);</kbd></dt>
291     <dd>`doc' は文書オブジェクトを指定します。戻り値は本文のリストオブジェクトです。戻り値のオブジェクトの寿命は文書オブジェクトのそれと同期します。</dd>
292     </dl>
293    
294     <p>文書オブジェクトの本文を連結した文字列を取得するには、関数 `est_doc_cat_texts' を用います。</p>
295    
296     <dl>
297     <dt><kbd>char *est_doc_cat_texts(ESTDOC *<var>doc</var>);</kbd></dt>
298     <dd>`doc' は文書オブジェクトを指定します。戻り値は本文を連結した文字列のデータです。戻り値の領域は `malloc' で生成されているので、不要になったら `free' で破棄してください。</dd>
299     </dl>
300    
301     <p>文書オブジェクトから文書ドラフトを生成するには、関数 `est_doc_dump_draft' を用います。</p>
302    
303     <dl>
304     <dt><kbd>char *est_doc_dump_draft(ESTDOC *<var>doc</var>);</kbd></dt>
305     <dd>`doc' は文書オブジェクトを指定します。戻り値は文書ドラフトのデータです。戻り値の領域は `malloc' で生成されているので、不要になったら `free' で破棄してください。</dd>
306     </dl>
307    
308     <p>文書オブジェクトの本文のスニペットを生成するには、関数 `est_doc_make_snippet' を用います。</p>
309    
310     <dl>
311     <dt><kbd>char *est_doc_make_snippet(ESTDOC *<var>doc</var>, const CBLIST *<var>words</var>, int <var>wwidth</var>, int <var>hwidth</var>, int <var>awidth</var>);</kbd></dt>
312     <dd>`doc' は文書オブジェクトを指定します。`words' はハイライトすべき語句のリストオブジェクトを指定します。`wwitdh' は結果全体の幅(≒文字数)を指定します。`hwitdh' は本文の冒頭から抽出する幅を指定します。`awitdh' はハイライトされる語の周辺から抽出する幅を指定します。戻り値は文書オブジェクトのスニペットの文字列です。その形式はタブ区切り文字列(TSV)です。その各行は表示すべき文字列です。ほとんどの行は単一のフィールドしか持ちませんが、いくつかは二つのフィールドを持ちます。もし第2フィールドが存在したならば、第1フィールドはハイライトして表示すべき文字列で、第2フィールドはその正規化された文字列です。戻り値の領域は `malloc' で生成されているので、不要になったら `free' で破棄してください。</dd>
313     </dl>
314    
315     <p>文書オブジェクトの本文に指定した語が全て含まれるか調べるには、関数 `est_doc_scan_words' を用います。</p>
316    
317     <dl>
318     <dt><kbd>int est_doc_scan_words(ESTDOC *<var>doc</var>, const CBLIST *<var>words</var>);</kbd></dt>
319     <dd>`doc' は文書オブジェクトを指定します。`word' は検査すべき語句のリストオブジェクトを指定します。戻り値は、全ての語が見つかれば真、そうでなければ偽です。</dd>
320     </dl>
321    
322     <hr />
323    
324     <h2 id="estcond">検索条件を扱うAPI</h2>
325    
326     <p>ここでは、検索条件を扱うためのAPIについて説明します。</p>
327    
328     <h3>機能</h3>
329    
330     <p>構造体型 `ESTCOND' は、検索条件を抽象化したものです。一つの検索条件は、一つの検索フレーズと複数の属性検索条件と一つの順序指定の集合です。`ESTCOND' の実体が直接参照されることはなく、必ずポインタを介して間接参照されます。このポインタおよびその参照先を総じて検索条件オブジェクトと呼びます。検索条件オブジェクトは関数 `est_cond_new' によって生成され、`est_cond_delete' によって破棄されます。生成された検索条件オブジェクトは必ず破棄してください。</p>
331    
332     <p>検索条件オブジェクトをデータベースに渡すことにより、その条件に該当する文書IDのリストを取得することができます。各種の条件式の書式については<a href="uguide-ja.html#searchcond">ユーザガイドの検索条件式の項目</a>を参照してください。なお、各種の条件式の文字コードはUTF-8にしてください。</p>
333    
334     <p>検索条件オブジェクトの典型的なライフサイクルを以下に示します。</p>
335    
336     <pre>ESTCOND *cond;
337    
338     /* 生成する */
339     cond = est_cond_new();
340    
341     /* 本文に「check」と「out」を含むと指定する */
342     est_cond_set_phrase(cond, "check AND out");
343    
344     /* URIが「.txt」で終わると指定する */
345     est_cond_add_attr(cond, "@uri ISTREW .txt");
346    
347     /* ここでデータベースに問い合わせを行う */
348    
349     /* 破棄する */
350     est_cond_delete(cond);
351     </pre>
352    
353     <h3>API</h3>
354    
355     <p>検索条件オブジェクトを生成するには、関数 `est_cond_new' を用います。</p>
356    
357     <dl>
358     <dt><kbd>ESTCOND *est_cond_new(void);</kbd></dt>
359     <dd>戻り値は検索条件オブジェクトです。</dd>
360     </dl>
361    
362     <p>検索条件オブジェクトを破棄するには、関数 `est_cond_delete' を用います。</p>
363    
364     <dl>
365     <dt><kbd>void est_cond_delete(ESTCOND *<var>cond</var>);</kbd></dt>
366     <dd>`cond' は検索条件オブジェクトを指定します。</dd>
367     </dl>
368    
369     <p>検索条件オブジェクトに検索フレーズを設定するには、関数 `est_cond_set_phrase' を用います。</p>
370    
371     <dl>
372     <dt><kbd>void est_cond_set_phrase(ESTCOND *<var>cond</var>, const char *<var>phrase</var>);</kbd></dt>
373     <dd>`cond' は検索条件オブジェクトを指定します。`phrase' は検索フレーズを指定します。</dd>
374     </dl>
375    
376     <p>検索条件オブジェクトに属性検索条件を追加するには、関数 `est_cond_add_attr' を用います。</p>
377    
378     <dl>
379     <dt><kbd>void est_cond_add_attr(ESTCOND *<var>cond</var>, const char *<var>expr</var>);</kbd></dt>
380     <dd>`cond' は検索条件オブジェクトを指定します。`expr' は属性検索条件の式を指定します。</dd>
381     </dl>
382    
383     <p>検索条件オブジェクトに順序指定を設定するには、関数 `est_cond_set_order' を用います。</p>
384    
385     <dl>
386     <dt><kbd>void est_cond_set_order(ESTCOND *<var>cond</var>, const char *<var>expr</var>);</kbd></dt>
387     <dd>`cond' は検索条件オブジェクトを指定します。`expr' 順序指定の式を指定します。デフォルトでは、順序はスコアの降順です。</dd>
388     </dl>
389    
390     <p>検索条件オブジェクトに取得文書数の最大数を設定するには、関数 `est_cond_set_max' を用います。</p>
391    
392     <dl>
393     <dt><kbd>void est_cond_set_max(ESTCOND *<var>cond</var>, int <var>max</var>);</kbd></dt>
394     <dd>`cond' は検索条件オブジェクトを指定します。`max' は取得文書数の最大数を指定します。デフォルトでは、取得文書数は無制限です。</dd>
395     </dl>
396    
397     <p>検索条件オブジェクトに検索オプションを設定するには、関数 `est_cond_set_options' を指定します。</p>
398    
399     <dl>
400     <dt><kbd>void est_cond_set_options(ESTCOND *<var>cond</var>, int <var>options</var>);</kbd></dt>
401     <dd>`cond' は検索条件オブジェクトを指定します。`options' はオプションを指定します。`ESTCONDSURE' だと全てのN-gramキーを検索します。`ESTCONDUSU' はデフォルトですが、N-gramのキーを1個置きで検査します。`ESTCONDFAST' だとN-gramのキーを2個置き、`ESTCONDAGIT' だと3個置きで検査します。`ESTCONDNOIDF' だとTF-IDF法による重みづけを省略します。`ESTCONDSIMPLE' だと検索フレーズを簡便法のものとして扱います。それぞれのオプションはビット和で同時に指定できます。N-gramのキーの検査が省略されればされるほど、検索速度は向上しますが、検索精度は低下します。</dd>
402     </dl>
403    
404     <hr />
405    
406     <h2 id="estdb">データベースを扱うAPI</h2>
407    
408     <p>ここでは、データベースを扱うためのAPIについて説明します。</p>
409    
410     <h3>機能</h3>
411    
412     <p>構造体型 `ESTDB' は、データベースの参照手段を抽象化したものです。データベースは、転置インデックスと書誌情報とメタデータを保持します。データベースに接続する際には、リーダ(読み込み専用)かライタ(読み書き両用)の2つのモードのどちらかを選択します。`ESTDB' の実体が直接参照されることはなく、必ずポインタを介して間接参照されます。このポインタおよびその参照先を総じてデータベースオブジェクトと呼びます。データベースオブジェクトは関数 `est_db_open' によって生成され、`est_db_close' によって破棄されます。生成されたデータベースオブジェクトは必ず破棄してください。</p>
413    
414     <p>各種の操作によってデータベースに起きたエラーは、関数 `est_db_error' によって取得することができます。各エラーコードの意味は、エラーコードを関数 `est_err_msg' に渡して知ることもできます。</p>
415    
416     <p>データベースオブジェクトの典型的なライフサイクルを以下に示します。</p>
417    
418     <pre>
419     ESTDB *db
420     int ecode;
421    
422     /* ライタとして開く */
423     if(!(db = est_db_open("casket", ESTDBWRITER | ESTDBCREAT, &amp;ecode))){
424     /* 失敗した場合、エラーメッセージを出して終了する */
425     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
426     return -1;
427     }
428    
429     /* ここで文書を登録したり、検索を行ったりする */
430    
431     /* データベースを閉じる */
432     if(!est_db_close(db, &amp;ecode)){
433     /* 失敗した場合、エラーメッセージを出して終了する */
434     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
435     return -1;
436     }
437     </pre>
438    
439     <h3>API</h3>
440    
441     <p>エラーコードの値として以下の定数が定義されています。</p>
442    
443     <ul>
444     <li><kbd>ESTENOERR</kbd> : エラーが起きていない。</li>
445     <li><kbd>ESTEINVAL</kbd> : 引数が妥当でない。</li>
446     <li><kbd>ESTEACCES</kbd> : アクセスが禁止されている。</li>
447     <li><kbd>ESTELOCK</kbd> : ロックに失敗した。</li>
448     <li><kbd>ESTEDB</kbd> : データベースに問題がある。</li>
449     <li><kbd>ESTEIO</kbd> : 入出力に失敗した。</li>
450     <li><kbd>ESTENOITEM</kbd> : 該当のアイテムがない。</li>
451     <li><kbd>ESTEMISC</kbd> : その他のエラー。</li>
452     </ul>
453    
454     <p>エラーコードに対応した文字列を取得するには、関数 `est_err_msg' を用います。</p>
455    
456     <dl>
457     <dt><kbd>const char *est_err_msg(int <var>ecode</var>);</kbd></dt>
458     <dd>`ecode' はエラーコードを指定します。戻り値はエラーコードに対応した文字列です。</dd>
459     </dl>
460    
461     <p>データベースを開いてデータベースオブジェクトを生成するには、関数 `est_db_open' を用います。</p>
462    
463     <dl>
464     <dt><kbd>ESTDB *est_db_open(const char *<var>name</var>, int <var>omode</var>, int *<var>ecp</var>);</kbd></dt>
465     <dd>`name' はデータベースのディレクトリ名を指定します。`mode' はオープンモードを指定します。`ESTDBWRITER' ならライタ(書き込みモード)で、`ESTDBREADER' ならリーダ(読み込みモード)です。ライタの場合、ビット和で次のものを指定できます。`ESTDBCREAT' ならデータベースが存在しない場合に新規に作成することを指示し、`ESTDBTRUNC' ならデータベースが既存だった場合にも新規に作りなおすことを指示します。リーダでもライタでも `ESTDBNOLCK' または `ESTDBLCKNB' をビット和で指定することができますが、前者はファイルロックをかけないでデータベースを開くことを指示し、後者はブロックせずにロックをかけることを指示します。その場合は排他制御の責任はアプリケーションが負います。`ESTDBCREAT' に `ESTDBPERFNG' をビット和で加えてデータベースを作成すると、文書の欧文も完全なN-gram法で処理されるようになります。`ecp' はエラーコードを格納する変数へのポインタを指定します。戻り値はデータベースオブジェクトか、エラーの場合は `NULL' です。</dd>
466     </dl>
467    
468     <p>データベースを閉じてデータベースオブジェクトを破棄するには、関数 `est_db_close' を用います。</p>
469    
470     <dl>
471     <dt><kbd>int est_db_close(ESTDB *<var>db</var>, int *<var>ecp</var>);</kbd></dt>
472     <dd>`db' はデータベースオブジェクトを指定します。`ecp' はエラーコードを格納する変数へのポインタを指定します。戻り値は成功なら真、エラーなら偽です。</dd>
473     </dl>
474    
475     <p>データベースに直前に起きたエラーコードを取得するには、関数 `est_db_error' を用います。</p>
476    
477     <dl>
478     <dt><kbd>int est_db_error(ESTDB *<var>db</var>);</kbd></dt>
479     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースに直前に起きたエラーコードです。</dd>
480     </dl>
481    
482     <p>データベースに致命的エラーがあったかどうか検査するには、関数 `est_db_fatal' を用います。</p>
483    
484     <dl>
485     <dt><kbd>int est_db_fatal(ESTDB *<var>db</var>);</kbd></dt>
486     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースに致命的エラーがあれば真、そうでなければ偽です。</dd>
487     </dl>
488    
489     <p>データベースのキャッシュ内の索引語をフラッシュするには、関数 `est_db_flush' を用います。</p>
490    
491     <dl>
492     <dt><kbd>int est_db_flush(ESTDB *<var>db</var>, int <var>max</var>);</kbd></dt>
493     <dd>`db' はライタとして接続したデータベースオブジェクトを指定します。`max' はフラッシュする語の最大数を指定しますが、0以下ならば全ての索引語がフラッシュされます。戻り値はデータベースに致命的エラーがあれば真、そうでなければ偽です。</dd>
494     </dl>
495    
496     <p>データベースの更新内容を同期させるには、関数 `est_db_sync' を用います。</p>
497    
498     <dl>
499     <dt><kbd>int est_db_sync(ESTDB *<var>db</var>);</kbd></dt>
500     <dd>`db' はライタとして接続したデータベースオブジェクトを指定します。戻り値は成功なら真、エラーなら偽です。</dd>
501     </dl>
502    
503     <p>データベースを最適化するには、関数 `est_db_optimize' を用います。</p>
504    
505     <dl>
506     <dt><kbd>int est_db_optimize(ESTDB *<var>db</var>, int <var>options</var>);</kbd></dt>
507     <dd>`db' はライタとして接続したデータベースオブジェクトを指定します。`options' はオプションを指定します。`ESTOPTNOPURGE' は削除された文書の情報を消去する処理を省略することを指示し、`ESTOPTNODBOPT' はデータベースファイルの最適化を省略することを指示します。オプションはビット和で同時に指定できます。戻り値は成功なら真、エラーなら偽です。</dd>
508     </dl>
509    
510     <p>データベースに文書を追加するには、関数 `est_db_put_doc' を用います。</p>
511    
512     <dl>
513     <dt><kbd>int est_db_put_doc(ESTDB *<var>db</var>, ESTDOC *<var>doc</var>, int <var>options</var>);</kbd></dt>
514     <dd>`db' はライタとして接続したデータベースオブジェクトを指定します。`doc' は文書オブジェクトを指定します。文書オブジェクトはURI属性を持っていなければなりません。`options' はオプションを指定します。`ESTPDCLEAN' は上書きされた文書の領域を整理することを指示します。戻り値は成功なら真、エラーなら偽です。指定された文書オブジェクトのURI属性がデータベース内の既存の文書と一致する場合、既存の方は削除されます。</dd>
515     </dl>
516    
517     <p>データベースから文書を削除するには、関数 `est_db_out_doc' を用います。</p>
518    
519     <dl>
520     <dt><kbd>int est_db_out_doc(ESTDB *<var>db</var>, int <var>id</var>, int <var>options</var>);</kbd></dt>
521     <dd>`db' はライタとして接続したデータベースオブジェクトを指定します。`id' は登録文書のID番号を指定します。`options' はオプションを指定します。`ESTODCLEAN' は削除された文書の領域を整理することを指示します。戻り値は成功なら真、エラーなら偽です。</dd>
522     </dl>
523    
524     <p>データベースから文書を取得するには、関数 `est_db_get_doc' を用います。</p>
525    
526     <dl>
527     <dt><kbd>ESTDOC *est_db_get_doc(ESTDB *<var>db</var>, int <var>id</var>, int <var>options</var>);</kbd></dt>
528     <dd>`db' はデータベースオブジェクトを指定します。`id' は登録文書のID番号を指定します。`options' はオプションを指定します。`ESTGDNOATTR' は属性を取得しないことを指示し、`ESTGDNOTEXT' は本文を取得しないことを指示します。オプションはビット和で同時に指定できます。戻り値は文書オブジェクトか、エラーなら `NULL' です。戻り値のオブジェクトは `est_doc_new' で生成されているので、不要になったら `est_doc_close' で破棄してください。</dd>
529     </dl>
530    
531     <p>データベースから文書の属性を取得するには、関数 `est_db_get_doc_attr' を用います。</p>
532    
533     <dl>
534     <dt><kbd>char *est_db_get_doc_attr(ESTDB *<var>db</var>, int <var>id</var>, const char *<var>name</var>);</kbd></dt>
535     <dd>`db' はデータベースオブジェクトを指定します。`id' は登録文書のID番号を指定します。`name' は属性名を指定します。戻り値は属性値ですが、該当する文書か属性がない場合は `NULL' が返されます。戻り値の領域は `malloc' で生成されているので、不要になったら `free' で破棄してください。</dd>
536     </dl>
537    
538     <p>URIに対応する文書のID番号を取得するには、関数 `est_db_uri_to_id' を用います。</p>
539    
540     <dl>
541     <dt><kbd>int est_db_uri_to_id(ESTDB *<var>db</var>, const char *<var>uri</var>);</kbd></dt>
542     <dd>`db' はデータベースオブジェクトを指定します。`uri' は登録文書のURIを指定します。戻り値は文書のID番号であるか、エラーなら-1です。</dd>
543     </dl>
544    
545     <p>文書オブジェクトからキーワードを抽出するには、関数 `est_db_etch_doc' を用います。</p>
546    
547     <dl>
548     <dt><kbd>CBMAP *est_db_etch_doc(ESTDB *<var>db</var>, ESTDOC *<var>doc</var>, int <var>max</var>);</kbd></dt>
549     <dd>`db' はTF-IDFによる重みづけに用いるデータベースオブジェクトを指定しますが、`NULL' なら使われません。`doc' は文書オブジェクトを指定します。`max' は抽出する語の最大数を指定します。戻り値は文書オブジェクトのキーワードおよびそのスコアの10進数文字列のマップです。戻り値のオブジェクトは `cbmapopen' で生成されているので、不要になったら `cbmapclose' で破棄してください。</dd>
550     </dl>
551    
552     <p>データベースのイテレータを初期化するには、関数 `est_db_iter_init' を用います。</p>
553    
554     <dl>
555     <dt><kbd>int est_db_iter_init(ESTDB *<var>db</var>);</kbd></dt>
556     <dd>`db' はデータベースオブジェクトを指定します。戻り値は成功なら真、エラーなら偽です。</dd>
557     </dl>
558    
559     <p>データベースのイテレータから次の文書のIDを取得するには、関数 `est_db_iter_next' を用います。</p>
560    
561     <dl>
562     <dt><kbd>int est_db_iter_next(ESTDB *<var>db</var>);</kbd></dt>
563     <dd>`db' はデータベースオブジェクトを指定します。戻り値は次のIDです。それ以上文書がないない場合は0が返される。エラーなら-1が返される。</dd>
564     </dl>
565    
566     <p>データベースの名前を取得するには、関数 `est_db_name' を用います。</p>
567    
568     <dl>
569     <dt><kbd>const char *est_db_name(ESTDB *<var>db</var>);</kbd></dt>
570     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースの名前です。戻り値の文字列の寿命はデータベースオブジェクトのそれと同期します。</dd>
571     </dl>
572    
573     <p>データベースに登録された文書の数を取得するには、関数 `est_db_doc_num' を用います。</p>
574    
575     <dl>
576     <dt><kbd>int est_db_doc_num(ESTDB *<var>db</var>);</kbd></dt>
577     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースに登録された文書の数です。</dd>
578     </dl>
579    
580     <p>データベースに登録された異なり語の数を取得するには、関数 `est_db_word_num' を用います。</p>
581    
582     <dl>
583     <dt><kbd>int est_db_word_num(ESTDB *<var>db</var>);</kbd></dt>
584     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースに登録された異なり語の数です。</dd>
585     </dl>
586    
587     <p>データベースのサイズを取得するには、関数 `est_db_size' を用います。</p>
588    
589     <dl>
590     <dt><kbd>double est_db_size(ESTDB *<var>db</var>);</kbd></dt>
591     <dd>`db' はデータベースオブジェクトを指定します。戻り値はデータベースのサイズです。</dd>
592     </dl>
593    
594     <p>検索条件に該当する文書の一覧を取得するには、関数 `est_db_search' を用います。</p>
595    
596     <dl>
597     <dt><kbd>int *est_db_search(ESTDB *<var>db</var>, ESTCOND *<var>cond</var>, int *<var>nump</var>, CBMAP *<var>hints</var>);</kbd></dt>
598     <dd>`db' はデータベースオブジェクトを指定します。`cond' は検索条件オブジェクトを指定します。`nump' は戻り値の配列の要素数を格納する変数へのポインタです。`hints' は各検索語に該当する文書数を格納するマップオブジェクトを指定しますが、`NULL' なら無視されます。否定条件の中の語の該当数は負数になります。マップ内の空文字列のキーには全体の該当数が関連づけられます。戻り値は該当した文書のIDを格納した配列です。この関数は決してエラーになりません。もし該当する文書がない場合にも、空の配列が返されます。戻り値の領域は `malloc' で生成されているので、不要になったら `free' で破棄してください。</dd>
599     </dl>
600    
601     <p>データベースのキャッシュメモリの最大サイズを指定するには、関数 `est_db_set_cache_size' を用います。</p>
602    
603     <dl>
604     <dt><kbd>void est_db_set_cache_size(ESTDB *<var>db</var>, size_t <var>size</var>, int <var>anum</var>, int <var>tnum</var>);</kbd></dt>
605     <dd>`db' はデータベースオブジェクトを指定します。`size' はインデックス用のキャッシュメモリの最大サイズを指定します。デフォルトは64MBです。0以下の値を指定すると、現状の設定を変更しません。`anum' は文書の属性用のキャッシュのレコード数を指定します。デフォルトは8192個です。0以下の値を指定すると、現状の設定を変更しません。`tnum' は文書のテキスト用のキャッシュのレコード数を指定します。デフォルトは1024個です。0以下の値を指定すると、現状の設定を変更しません。</dd>
606     </dl>
607    
608     <hr />
609    
610     <h2 id="gatherer">ギャザラのサンプル</h2>
611    
612     <p>最も単純なギャザラの実装を以下に示します。全文検索システムがこんなに短いコードで実現できるなんて、便利な世の中になったものです。</p>
613    
614     <pre>#include &lt;estraier.h&gt;
615     #include &lt;cabin.h&gt;
616     #include &lt;stdlib.h&gt;
617     #include &lt;stdio.h&gt;
618    
619     int main(int argc, char **argv){
620     ESTDB *db;
621     ESTDOC *doc;
622     int ecode;
623    
624     /* データベースを開く */
625     if(!(db = est_db_open("casket", ESTDBWRITER | ESTDBCREAT, &amp;ecode))){
626     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
627     return 1;
628     }
629    
630     /* 文書オブジェクトを生成する */
631     doc = est_doc_new();
632    
633     /* 文書オブジェクトに属性を追加する */
634 dpavlin 9 est_doc_add_attr(doc, "@uri", "http://estraier.gov/example.txt");
635 dpavlin 2 est_doc_add_attr(doc, "@title", "Over the Rainbow");
636    
637     /* 文書オブジェクトに本文を追加する */
638     est_doc_add_text(doc, "Somewhere over the rainbow. Way up high.");
639     est_doc_add_text(doc, "There's a land that I heard of once in a lullaby.");
640    
641     /* 文書オブジェクトをデータベースに登録する */
642     if(!est_db_put_doc(db, doc, ESTPDCLEAN))
643     fprintf(stderr, "error: %s\n", est_err_msg(est_db_error(db)));
644    
645     /* 文書オブジェクトを破棄する */
646     est_doc_delete(doc);
647    
648     /* データベースを閉じる */
649     if(!est_db_close(db, &amp;ecode)){
650     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
651     return 1;
652     }
653    
654     return 0;
655     }
656     </pre>
657    
658     <p>コアAPIでは、データベースの概念が重要になります。転置インデックスや登録文書などのデータを参照するための手段を抽象化したものです。データベースを開く際には、読み込みモードか書き込みモードを指定します。いずれにしても、開いたデータベースは必ず閉じてください。特に書き込みモードの場合、適切にデータベースを閉じないとデータベースが壊れてしまいます。</p>
659    
660     <p>データベースオブジェクトに限らず、Hyper Estraierにおける大抵のオブジェクトは、生成するための関数と破棄するための関数を備えています。生成したオブジェクトは必ず破棄してください。そうしないとメモリリークになります。</p>
661    
662     <p><kbd>est_db_open</kbd>はデータベースを開く関数です。第1引数はデータベースの名前を指定しています。第2引数はオープンモードです。<kbd>ESTDBWRITER</kbd>は書き込みモードであることを意味し、<kbd>ESTDBCREAT</kbd>はデータベースが存在しない場合に新しく作成することを意味します。第3引数はエラーコードを受け取る変数へのポインタを指定します。戻り値はデータベースオブジェクトですが、エラーがあった場合はNULLです。データベースを閉じるには、<kbd>est_db_close</kbd>関数を使います。</p>
663    
664     <p>この例では、エラーが起きた際にはエラーメッセージを出力しています。データベースを開いたり閉じたりする関数ではエラーコードを受け取る変数へのポインタを引数で指定し、その他の関数でエラーが起きた場合にはデータベースオブジェクトの中にエラーコードがセットされます。その値は<kbd>est_db_error</kbd>という関数を使って取得できます。<kbd>est_err_msg</kbd>という関数を使うとエラーコードに対応する文字列を取得できます。</p>
665    
666     <p>文書オブジェクトは、各種の文書を抽象化したものです。文書オブジェクトには属性と本文を登録できます。この例ではそれらを文字列定数で指定していますが、実際のアプリケーションでは、ファイルを読むなどして取得したデータを指定することでしょう。<kbd>est_doc_new</kbd>は文書オブジェクトを作り、<kbd>est_doc_add_attr</kbd>は属性を追加し、<kbd>est_doc_add_text</kbd>は本文を追加し、<kbd>est_doc_delete</kbd>は文書オブジェクトを破棄する関数です。文書の属性、本文とも文字コードはUTF-8にしてください。</p>
667    
668     <p>文書オブジェクトを作ったら、それを<kbd>est_db_put_doc</kbd>関数に渡して登録します。登録する文書は必ずURI属性("@uri")を備えている必要があります。そうでない場合はエラーになります。また、既に登録してある文書のURIと重複した場合は、上書き(既存の文書が削除)されます。ここでは、削除された領域を整理するために、オプションで<kbd>ESTPDCLEAN</kbd>を指示しています。</p>
669    
670     <hr />
671    
672     <h2 id="searcher">サーチャのサンプル</h2>
673    
674     <p>最も単純なサーチャの実装を以下に示します。サーチャはギャザラに比べると少し長いですが、やっていることはそれほど難しくはありません。</p>
675    
676     <pre>#include &lt;estraier.h&gt;
677     #include &lt;cabin.h&gt;
678     #include &lt;stdlib.h&gt;
679     #include &lt;stdio.h&gt;
680    
681     int main(int argc, char **argv){
682     ESTDB *db;
683     ESTCOND *cond;
684     ESTDOC *doc;
685     const CBLIST *texts;
686     int ecode, *result, resnum, i, j;
687     const char *value;
688    
689     /* データベースを開く */
690     if(!(db = est_db_open("casket", ESTDBREADER, &amp;ecode))){
691     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
692     return 1;
693     }
694    
695     /* 検索条件オブジェクトを生成する */
696     cond = est_cond_new();
697    
698     /* 検索条件オブジェクトに検索式を設定する */
699     est_cond_set_phrase(cond, "rainbow AND lullaby");
700    
701     /* データベースから検索結果を得る */
702     result = est_db_search(db, cond, &amp;resnum, NULL);
703    
704     /* 各該当文書を取得して表示する */
705     for(i = 0; i &lt; resnum; i++){
706    
707     /* 文書オブジェクトを取得する */
708     if(!(doc = est_db_get_doc(db, result[i], 0))) continue;
709    
710     /* 属性を表示する */
711     if((value = est_doc_attr(doc, "@uri")) != NULL)
712     printf("URI: %s\n", value);
713     if((value = est_doc_attr(doc, "@title")) != NULL)
714     printf("Title: %s\n", value);
715    
716     /* 本文を表示する */
717     texts = est_doc_texts(doc);
718     for(j = 0; j &lt; cblistnum(texts); j++){
719     value = cblistval(texts, j, NULL);
720     printf("%s\n", value);
721     }
722    
723     /* 文書オブジェクトを破棄する */
724     est_doc_delete(doc);
725    
726     }
727    
728     /* 検索結果を破棄する */
729     free(result);
730    
731     /* 検索条件オブジェクトを破棄する */
732     est_cond_delete(cond);
733    
734     /* データベースを閉じる */
735     if(!est_db_close(db, &amp;ecode)){
736     fprintf(stderr, "error: %s\n", est_err_msg(ecode));
737     return 1;
738     }
739    
740     return 0;
741     }
742     </pre>
743    
744     <p>ヘッダのインクルードやデータベースの開閉についてはギャザラと同じです。ただし、サーチャの場合、データベースは読み込みモードで開きます。書き込みモードでも検索はできるのですが、読み込みモードの場合は、プロセスがクラッシュしてもデータベースが壊れないという利点と、複数のプロセスが同時にデータベースを開けるという利点があります。</p>
745    
746     <p>検索を行う前に、検索条件を抽象化した検索条件オブジェクトを準備します。<kbd>est_cond_new</kbd>で生成して、<kbd>est_cond_set_phrase</kbd>で検索式を指定して、使いおわったら<kbd>est_cond_delete</kbd>で破棄します。</p>
747    
748     <p>検索条件オブジェクトを渡して<kbd>est_db_search</kbd>関数を呼ぶことで、条件に該当する文書のIDの配列を得ることができます。配列の要素数は第3引数のポインタが指す変数に格納されます。第4引数は今は気にしないでください。</p>
749    
750     <p>検索結果が得られたら、あとはそれに含まれる個々の文書を取り出してから表示します。<kbd>est_db_get_doc</kbd>はIDに対応した文書オブジェクトを取り出す関数です。既に削除した文書がヒットすることもあるので、その場合にはNULLが返されます。NULLの場合は単に無視して次の周回に進みます。<kbd>est_doc_get_attr</kbd>は属性を取得する関数です。<kbd>est_doc_get_texts</kbd>は本文のリストを取得する関数です。この関数の戻り値、QDBMのcabin.hが提供するリストオブジェクトです。<kbd>cblistnum</kbd>関数で要素の数を得たり、<kbd>cblistval</kbd>関数で特定の番号の要素を取り出すことができます。この例では、取り出した属性や本文の値をそのまま画面に出力しています。</p>
751    
752     <hr />
753    
754     <h2 id="paralleling">並列性</h2>
755    
756     <p>Hyper Estraierのデータベースは、ファイルロックによって保護されます。読み込みモードで接続された場合は共有ロックがかかり、書き込みモードで接続された場合は排他ロックがかかります。したがって、読み込みモード同士であれば複数のプロセスが同じデータベースを同時に開くことができますが、書き込みモードで接続できるのは一つのデータベースに対して一つのプロセスだけです。</p>
757    
758     <p>読み込みモードの場合、複数のプロセスが同一のデータベースを開くだけでなく、読み込みモードでデータベースを開いたプロセスをforkさせることもできます。また、複数のスレッドが単一のデータベースに対するコネクション(ESTDBのインスタンス)をそれぞれ生成して利用することもできます。なお、コアAPIの各関数はリエントラントですが、コネクションはマルチスレッドセーフではありませんので、スレッド毎にコネクションを割り当てるか、mutexで各コネクションを保護するかしてください。</p>
759    
760     <p>マルチプロセスであってもマルチスレッドであっても、書き込みモードのコネクションは単一のデータベースに対しては同時に一つしか生成できません。複数生成するとデータベースが壊れます。したがって、マルチスレッドで更新を行う場合は、スレッド間でコネクションを共有するとともに、グローバルなmutexでコネクションを保護する必要があります。</p>
761    
762     <p>コネクションを自分で保護するのは面倒な場合は、Hyper EstraierのスレッドAPIを使うとよいでしょう。コアAPIのデータベース管理機能をマルチスレッドセーフにしたものです。スレッドAPIはコアAPIと全く同じ機能を提供しますが、以下の点が異なります。なお、データベース関連以外の機能(ESTDOCとESTCOND)はコアAPIとスレッドAPIで共通です。</p>
763    
764     <ul>
765     <li>estraier.hだけでなくestmtdb.hもインクルードする。</li>
766     <li>`ESTDB' へのポインタではなく `ESTMTDB' へのポインタをコネクションとして利用する。</li>
767     <li>関数名の接頭辞が「est_db_」でなく「est_mtdb_」である。</li>
768     </ul>
769    
770     <p>基本的にはスレッドAPIはコネクションに対する排他制御をグローバルに行いますが、QDBMをビルドする際に「--enable-pthread」をつけてスレッド対応にさせていた場合は、コネクション単位で排他制御が行われます。どちらでも動作に支障はありませんが、QDBMがスレッド対応している方が並列性は大幅に向上します。</p>
771    
772     <hr />
773    
774     <h2 id="tips">助言</h2>
775    
776     <p>ここでは、ライブラリとしてのHyper Estraierを活用するためのコツをいくつか紹介します。</p>
777    
778     <h3>CGIスクリプトでの利用</h3>
779    
780     <p>Webインターフェイスの検索アプリケーションをCGIスクリプトとして実装することも多いかと思います。そこで注意してほしいのは、書き込みモードでデータベースを開いてはならないということです。</p>
781    
782     <p>CGIのプロセスは、呼び出し側のサーバによっていつ殺されるかわかりません。データの転送中にネットワークが切断された場合(ユーザが停止ボタンを押した場合)には、SIGPIPEによって殺される可能性があります。サーバが停止または再起動する場合、SIGTERMによって殺される可能性があります。プロセスサイズの制限や実行時間の制限に触れたことよってSIGKILLで殺される可能性もあります。</p>
783    
784     <p>そのような不慮の停止の際に書き込みモードでデータベースを開いていた場合、データベースが壊れてしまいます。したがって、CGIスクリプトは更新処理には不向きです。それでも敢えてCGIで更新作業を行うならば、必ずバックアップを取りながら運用するようにしてください。</p>
785    
786     <h3>検索サーバ</h3>
787    
788     <p>コマンドラインインターフェイスでもWebインターフェイスでも、検索要求を処理する度にデータベースを開いたり閉じたりするのは非効率です(estcmdやestseek.cgiではそうしていますが)。データベースに接続する際にはそれなりのオーバーヘッドがかかるので、同時接続数が増えると負荷が高まり、ひいては検索速度の低下を招きます。したがって、なるべくなら、常駐型のプロセスを実装して、データベースのコネクションを使いまわすようにしてください。それが面倒ならば、ノードAPIの利用を検討してみるのもよいでしょう。</p>
789    
790     <h3>裏API</h3>
791    
792     <p>実は、この文書で紹介した以外にも関数がたくさん提供されています。それらはちょっと使い方が難しい、いわばハッカー用のAPIです。興味を持たれた方は、estraier.hを覗いてみてください。</p>
793    
794     <h3>ミニライブラリ</h3>
795    
796     <p>libestraier.a等のライブラリはPOSIXスレッドに依存する構成になっています。一方で、組み込み系ではPOSIXスレッドが実装されていないこともあります。コアAPIはスレッドの機能を一切使っていませんので、そういった環境にも移植することができます。「make corelib」を実行すると、コアAPIのオブジェクトファイルのみを含んだライブラリであるlibestcore.aが生成されます。libestcore.aはlibiconvとlibzとlibmとlibcに依存するのみですので、多くの環境で利用することができるでしょう。</p>
797    
798     <h3>言語バインディング</h3>
799    
800     <p>C言語以外のプログラミング言語からHyper Estraierを使うためのバインディングを作るプロジェクトも進行中です。あなたが新たな言語のバインディングを作ってくれるのも歓迎します。その際には、estraier.idlファイルに記述してあるインターフェイスを参考にしてください。各種のバインディングのインターフェイスはなるべく似ている方が覚えやすいですよね。</p>
801    
802     <hr />
803    
804     </body>
805    
806     </html>
807    
808     <!-- END OF FILE -->

  ViewVC Help
Powered by ViewVC 1.1.26