/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 <?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 <div class="note">Last Update: Mon, 01 Aug 2005 00:50:38 +0900</div>
28 <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 <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
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 est_doc_add_attr(doc, "@uri", "http://estraier.gov/example.txt");
635 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