[GENERIC] Zend_Translate:
[zend.git] / documentation / manual / ja / module_specs / Zend_Search_Lucene-BestPractice.xml
blob56edd5c846de27ffa284fc5a2568c4d97b83f7a9
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <!-- EN-Revision: 20854 -->
4 <sect1 id="zend.search.lucene.best-practice">
5     <title>ベストプラクティス</title>
7     <sect2 id="zend.search.lucene.best-practice.field-names">
8         <title>フィールド名</title>
10         <para>
11             <classname>Zend_Search_Lucene</classname> では、フィールド名に関する制限は特にありません。
12         </para>
14         <para>
15             しかし、できれば '<emphasis>id</emphasis>'
16             および '<emphasis>score</emphasis>' という名前は使用を控えるようにしましょう。
17             これらを使用すると、<code>QueryHit</code>
18             のプロパティ名と区別しにくくなります。
19         </para>
21         <para>
22             <classname>Zend_Search_Lucene_Search_QueryHit</classname> のプロパティ
23             <code>id</code> と <code>score</code> はそれぞれ、Lucene
24             ドキュメントが内部で使用する ID、検索結果の
25             <link linkend="zend.search.lucene.searching.results-scoring">スコア</link>
26             を表します。もしドキュメントでこれらと同じ名前のフィールドを使っているのなら、
27             そのフィールドにアクセスするには <methodname>getDocument()</methodname>
28             メソッドを使う必要があります。
30             <programlisting language="php"><![CDATA[
31 $hits = $index->find($query);
33 foreach ($hits as $hit) {
34     // 'title' フィールドを取得します
35     $title = $hit->title;
37     // 'contents' フィールドを取得します
38     $contents = $hit->contents;
40     // Lucene ドキュメントの内部 ID を取得します
41     $id = $hit->id;
43     // 検索結果のスコアを取得します
44     $score = $hit->score;
46     // 'id' フィールドを取得します
47     $docId = $hit->getDocument()->id;
49     // 'score' フィールドを取得します
50     $docId = $hit->getDocument()->score;
52     // 'title' フィールドもこの方法で取得できます
53     $title = $hit->getDocument()->title;
55 ]]></programlisting>
56         </para>
57     </sect2>
59     <sect2 id="zend.search.lucene.best-practice.indexing-performance">
60         <title>インデックス作成のパフォーマンス</title>
62         <para>
63             インデックス作成のパフォーマンスは、
64             リソースの消費量と所要時間、
65             そしてインデックスの品質との兼ね合いで決まります。
66         </para>
68         <para>
69             インデックスの品質とは、要するにインデックスセグメントの数のことです。
70         </para>
72         <para>
73             各インデックスセグメントはデータ部とは独立しています。
74             つまり、インデックスに含まれるセグメントが多くなればなるほど
75             検索に要するメモリと時間は増加します。
76         </para>
78         <para>
79             インデックスの最適化を行うと、
80             複数のセグメントをまとめて新しいひとつのセグメントを作成します。
81             完全に最適化されたインデックスは、セグメントひとつだけで構成されます。
82         </para>
84         <para>
85             インデックスの最適化を行うには <methodname>optimize()</methodname> メソッドを使用します。
86             <programlisting language="php"><![CDATA[
87 $index = Zend_Search_Lucene::open($indexPath);
89 $index->optimize();
90 ]]></programlisting>
91         </para>
93         <para>
94             インデックスの最適化はデータストリーム上で行われるので、
95             それほどメモリは消費しません。ただ、CPU
96             リソースをかなり消費し、時間もかかります。
97         </para>
99         <para>
100             Lucene のインデックスセグメントは、その性質上
101             更新はできません (更新するには、
102             セグメントファイルを新たに作りなおす必要があります)。
103             したがって、新しいドキュメントがインデックスに追加されるたびに
104             新しいセグメントが作成されることになります。
105             その結果、インデックスの品質は下がっていきます。
106         </para>
108         <para>
109             セグメントが作成されるたびにインデックスの自動最適化が行われ、
110             一部のセグメントは自動的にマージされます。
111         </para>
113         <para>
114             自動最適化の設定は、次の 3 つのオプションで変更できます
115             (<link linkend="zend.search.lucene.index-creation.optimization">インデックスの最適化</link>
116             を参照ください)。
117             <itemizedlist>
118                 <listitem>
119                     <para><emphasis>MaxBufferedDocs</emphasis>
120                           は、メモリ内のバッファに保持されるドキュメントの最大数です。
121                           この数を超えると、新しいセグメントを作成して
122                           ハードディスクに書き込みます。</para>
123                 </listitem>
124                 <listitem>
125                     <para><emphasis>MaxMergeDocs</emphasis>
126                           は、自動最適化によって新しいセグメントへのマージを行う基準となる
127                           ドキュメント数です。</para>
128                 </listitem>
129                 <listitem>
130                     <para><emphasis>MergeFactor</emphasis>
131                           は、自動最適化を行う頻度を指定します。</para>
132                 </listitem>
133             </itemizedlist>
134             <note>
135                 <para>
136                     これらのオプションはすべて <classname>Zend_Search_Lucene</classname>
137                     オブジェクトのプロパティであり、インデックスのプロパティではありません。
138                     したがって、この設定は現在使用中の
139                     <classname>Zend_Search_Lucene</classname> オブジェクトに対してのみ働くようになり、
140                     スクリプトによって設定は異なります。
141                 </para>
142             </note>
143         </para>
145         <para>
146             <emphasis>MaxBufferedDocs</emphasis> は、
147             スクリプトを一回実行するたびにひとつのドキュメントしか扱わない場合は
148             何の影響も及ぼしません。
149             逆に、バッチ処理の場合にはこの設定が非常に重要になります。
150             値を大きくするとインデックス作成の速度が上がりますが、
151             同時に大量のメモリを消費するようになります。
152         </para>
154         <para>
155             <emphasis>MaxBufferedDocs</emphasis>
156             パラメータの値として最適なものを計算する公式はありません。
157             これはドキュメントのサイズや解析器、使用できるメモリ量などに依存するからです。
158         </para>
160         <para>
161             最適な設定値を取得するには、
162             扱うであろうドキュメントの中で最もサイズが大きいものを用いて
163             何度かテストをしてみましょう
164             <footnote>
165               <para>
166                 <methodname>memory_get_usage()</methodname>
167                 や <methodname>memory_get_peak_usage()</methodname>
168                 で、メモリの使用量を確認します。
169               </para>
170             </footnote>。
171             使用可能なメモリのうち半分を超えない程度のメモリ消費量に抑えておくことをお勧めします。
172         </para>
174         <para>
175             <emphasis>MaxMergeDocs</emphasis> はセグメントの大きさ
176             (これはドキュメントの大きさによって決まります) を制限します。
177             これにより、自動最適化の時間を短縮できます。
178             つまり、<methodname>addDocument()</methodname> メソッドが
179             ある時間以上は実行されなくなります。
180             これは、対話的なアプリケーションで重要になります。
181         </para>
183         <para>
184             <emphasis>MaxMergeDocs</emphasis> の設定値を小さくすると、
185             バッチ処理のパフォーマンスもあがります。
186             インデックスの自動最適化は対話的な処理であり、
187             ひとつひとつ順を追って実行していきます。
188             小さなセグメントたちがひとつの大きなセグメントにまとめられ、
189             さらにまたそれが他のセグメントとまとまってより大きなセグメントになり、
190             といった具合です。インデックスの最適化を完全に行うと、
191             処理が非常に効率的になります。
192         </para>
194         <para>
195             セグメントのサイズを小さくするとインデックスの品質が下がり、
196             大量のセグメントができあがってしまいます。場合によっては、OS
197             の制限に引っかかって "オープンしているファイルが多すぎる"
198             というエラーが発生するかもしれません
199             <footnote>
200               <para>
201                 <classname>Zend_Search_Lucene</classname> は、セグメントファイルをずっとオープンしたままにしておきます。
202                 これによって検索の効率を上げています。
203               </para>
204             </footnote>。
205         </para>
207         <para>
208             したがって、バックグラウンドでのインデックスの最適化は対話モードで行い、
209             バッチ処理用の <emphasis>MaxMergeDocs</emphasis>
210             はあまり小さくしすぎないようにしなければなりません。
211         </para>
213         <para>
214             <emphasis>MergeFactor</emphasis> は自動最適化の頻度に影響を及ぼします。
215             値を小さくすると、最適化されていないインデックスの品質が上がります。
216             値を大きくするとインデックス作成の策度が上がりますが、
217             セグメントの数も増えます。何度も言いますが、これは
218             "オープンしているファイルが多すぎる" エラーの原因となりえます。
219         </para>
221         <para>
222             <emphasis>MergeFactor</emphasis> は、以下の条件を満たす大きさで
223             インデックスセグメントをグループ化します。
224             <orderedlist>
225                 <listitem><para><emphasis>MaxBufferedDocs</emphasis> 以下</para></listitem>
226                 <listitem><para><emphasis>MaxBufferedDocs</emphasis> より大きいが
227                                 <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis> を超えない</para></listitem>
228                 <listitem><para><emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis> より大きいが
229                 <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>*<emphasis>MergeFactor</emphasis> を超えない</para></listitem>
230                 <listitem><para>...</para></listitem>
231             </orderedlist>
232         </para>
234         <para>
235             Zend_Search_Lucene は、<methodname>addDocument()</methodname>
236             をコールするたびにセグメントの状況を調べ、
237             いくつかのセグメントをまとめて次のグループの新しいセグメントに移動できるかどうかを確認します。
238             できる場合はマージを行います。
239         </para>
241         <para>
242             つまり、N 個のグループからなるインデックスには <emphasis>MaxBufferedDocs</emphasis> + (N-1)*<emphasis>MergeFactor</emphasis>
243             のセグメントが含まれ、少なくとも
244             <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis><superscript>(N-1)</superscript>
245             のドキュメントが存在することになります。
246         </para>
248         <para>
249             この式で、インデックス内のセグメントの概数を求めることができます。
250         </para>
251         <para>
252             <emphasis>NumberOfSegments</emphasis> &lt;= <emphasis>MaxBufferedDocs</emphasis> + <emphasis>MergeFactor</emphasis>*log
253             <subscript><emphasis>MergeFactor</emphasis></subscript> (<emphasis>NumberOfDocuments</emphasis>/<emphasis>MaxBufferedDocs</emphasis>)
254         </para>
256         <para>
257             <emphasis>MaxBufferedDocs</emphasis> は、使用できるメモリ量によって決まります。
258             MergeFactor を適切に設定することで、セグメントの数を調整できます。
259         </para>
261         <para>
262             バッチ処理においては、<emphasis>MergeFactor</emphasis>
263             パラメータを調整するほうが <emphasis>MaxMergeDocs</emphasis>
264             を調整するよりも効率的です。しかし、微調整はできず大雑把なものとなります。
265             そこで、まず上の公式をもとに <emphasis>MergeFactor</emphasis> を調整し、
266             それから <emphasis>MaxMergeDocs</emphasis> を微調整してパフォーマンスを最適化しましょう。
267         </para>
268     </sect2>
270     <sect2 id="zend.search.lucene.best-practice.shutting-down">
271         <title>インデックスの終了時処理</title>
273         <para>
274             <classname>Zend_Search_Lucene</classname> オブジェクトは、
275             終了時にちょっとした作業を行います。
276             これは、インデックスにドキュメントが追加されたけれども
277             新しいセグメントに書き込まれていないという場合に行われます。
278         </para>
280         <para>
281             また、場合によっては自動最適化も行います。
282         </para>
284         <para>
285             インデックスオブジェクトは、自分自身および QueryHit
286             オブジェクトがすべてスコープ外に出た時点で自動的に終了処理を行います。
287         </para>
289         <para>
290             インデックスオブジェクトがグローバル変数に格納されている場合は、
291             スクリプトの終了時に破棄されます
292             <footnote>
293               <para>
294                 インデックスや QueryHit オブジェクトが複合データ型から参照されている場合にもこれは起こりえます。
295                 たとえば、循環参照を含むオブジェクトはスクリプトの終了時まで破棄されません。
296               </para>
297             </footnote>。
298         </para>
300         <para>
301             <acronym>PHP</acronym> の例外処理もここで終了します。
302         </para>
304         <para>
305             これは通常のインデックス終了処理を妨げることはありませんが、
306             何かエラーが発生した際に正しいエラー情報を取得できなくなる可能性があります。
307         </para>
309         <para>
310             この問題を回避する方法はふたつあります。
311         </para>
313         <para>
314             まずは、強制的にスコープ外に出す方法です。
315             <programlisting language="php"><![CDATA[
316 $index = Zend_Search_Lucene::open($indexPath);
320 unset($index);]]></programlisting>
321         </para>
323         <para>
324             そしてもうひとつは、スクリプトの終了前にコミット操作を行うことです。
325             <programlisting language="php"><![CDATA[
326 $index = Zend_Search_Lucene::open($indexPath);
328 $index->commit();
329 ]]></programlisting>
330             これについては、このドキュメントの
331             "<link linkend="zend.search.lucene.advanced.static">応用: 静的プロパティとしてのインデックスの使用</link>"
332             でも説明しています。
333         </para>
334     </sect2>
336     <sect2 id="zend.search.lucene.best-practice.unique-id">
337         <title>一意な ID によるドキュメントの取得</title>
339         <para>
340             ドキュメントの一意な ID、たとえば URL やパス、データベース上の ID
341             などをインデックスに保存しておくとよいでしょう。
342         </para>
344         <para>
345             <classname>Zend_Search_Lucene</classname> には <methodname>termDocs()</methodname>
346             というメソッドがあり、指定した単語を含むドキュメントを取得できます。
347         </para>
349         <para>
350             これは <methodname>find()</methodname> メソッドよりも効率的です。
351             <programlisting language="php"><![CDATA[
352 // find() メソッドでクエリ文字列を指定することによるドキュメントの取得
353 $query = $idFieldName . ':' . $docId;
354 $hits  = $index->find($query);
355 foreach ($hits as $hit) {
356     $title    = $hit->title;
357     $contents = $hit->contents;
358     ...
362 // find() メソッドでクエリ API を使用することによるドキュメントの取得
363 $term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
364 $query = new Zend_Search_Lucene_Search_Query_Term($term);
365 $hits  = $index->find($query);
366 foreach ($hits as $hit) {
367     $title    = $hit->title;
368     $contents = $hit->contents;
369     ...
374 // termDocs() メソッドによるドキュメントの取得
375 $term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
376 $docIds  = $index->termDocs($term);
377 foreach ($docIds as $id) {
378     $doc = $index->getDocument($id);
379     $title    = $doc->title;
380     $contents = $doc->contents;
381     ...
383 ]]></programlisting>
384         </para>
385     </sect2>
387     <sect2 id="zend.search.lucene.best-practice.memory-usage">
388         <title>メモリの使用法</title>
390         <para>
391             <classname>Zend_Search_Lucene</classname> は、比較的メモリを消費するモジュールです。
392         </para>
394         <para>
395             各種の情報をキャッシュしたり、検索やインデックス作成の速度を上げたりするために、メモリを使用しています。
396         </para>
398         <para>
399             メモリに関する挙動は、モードによって異なります。
400         </para>
402         <para>
403             単語辞書のインデックスは、検索時にメモリに読み込まれます。
404             これは、実際の辞書に登録されている単語が 128件
405             <footnote><para>
406                 Lucene のファイルフォーマットでは、この件数を変更することもできます。しかし
407                 <classname>Zend_Search_Lucene</classname> の <acronym>API</acronym> ではそれをサポートしていません。
408                 別の Lucene 実装を使用してインデックスをサポートすれば、
409                 この値を変更することも可能です。
410             </para></footnote>
411             に達するごとに作成されます。
412         </para>
414         <para>
415             したがって、単語の数が増えれば増えるほどメモリの消費量も増加します。
416             トークン化していないフレーズをフィールドの値として使用したり、
417             テキスト以外の情報を大量にインデックスとして使用したりすると、
418             単語の数が増えることになります。
419         </para>
421         <para>
422             最適化されていないインデックスは、複数のセグメントで構成されます。
423             これも、メモリ消費量の増加の要因となります。
424             各セグメントは独立しているので、それぞれ独自に単語辞書と辞書インデックスを持っています。
425             ひとつのインデックスの中に <emphasis>N</emphasis> 個のセグメントがあったとすると、
426             メモリの消費量は最悪で <emphasis>N</emphasis> 倍になってしまいます。
427             インデックスの最適化を行ない、セグメントをひとつにまとめましょう。
428         </para>
430         <para>
431             インデックスは、検索処理とドキュメントのバッファリングに同じメモリを使用します。
432             このメモリの使用量は、パラメータ <emphasis>MaxBufferedDocs</emphasis>
433             で指定します。
434         </para>
436         <para>
437             インデックスの最適化 (完全最適化、部分最適化の両方)
438             はストリーム上で行なわれるので、あまりメモリを消費しません。
439         </para>
440     </sect2>
442     <sect2 id="zend.search.lucene.best-practice.encoding">
443         <title>エンコーディング</title>
445         <para>
446             <classname>Zend_Search_Lucene</classname> は、内部で UTF-8 文字列を使用しています。
447             したがって、Zend_Search_Lucene が返す文字列は、すべて UTF-8
448             でエンコードされています。
449         </para>
451         <para>
452             単なる <acronym>ASCII</acronym> データのみを扱うのであればエンコーディングを気にする必要はありません。
453             しかしそれ以外の場合は要注意です。
454         </para>
456         <para>
457             間違ったエンコーディングを使用すると、
458             エンコーディングの変換時にエラーが発生したりデータを失ってしまったりする可能性があります。
459         </para>
461         <para>
462             <classname>Zend_Search_Lucene</classname> は、ドキュメントやクエリのエンコーディングとしてさまざまなものに対応しています。
463         </para>
465         <para>
466             フィールドを作成するメソッドで、エンコーディングをオプションのパラメータによって指定できます。
467             <programlisting language="php"><![CDATA[
468 $doc = new Zend_Search_Lucene_Document();
469 $doc->addField(Zend_Search_Lucene_Field::Text('title',
470                                               $title,
471                                               'iso-8859-1'));
472 $doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
473                                                   $contents,
474                                                   'utf-8'));
475 ]]></programlisting>
476             エンコーディングの指定をはっきりさせるという意味で、これが最も良い方法です。
477         </para>
479         <para>
480             このエンコーディング指定を省略すると、現在のロケールをもとに判断を行ないます。
481             ロケールの指定時に、言語だけでなく文字セットも指定できます。
482             <programlisting language="php"><![CDATA[
483 setlocale(LC_ALL, 'fr_FR');
486 setlocale(LC_ALL, 'de_DE.iso-8859-1');
489 setlocale(LC_ALL, 'ja_JP.UTF-8');
491 ]]></programlisting>
492         </para>
494         <para>
495             クエリ文字列のエンコーディングも、同じ方式で指定します。
496         </para>
498         <para>
499             エンコーディングを何らかの方法で指定しなかった場合は、
500             現在のロケールにもとづいて判断を行ないます。
501         </para>
503         <para>
504             検索の前にクエリのパースを行なう場合、
505             エンコーディングはオプションのパラメータとして指定できます。
506             <programlisting language="php"><![CDATA[
507 $query =
508     Zend_Search_Lucene_Search_QueryParser::parse($queryStr, 'iso-8859-5');
509 $hits = $index->find($query);
511 ]]></programlisting>
512         </para>
514         <para>
515             デフォルトのエンコーディングを指定するには <methodname>setDefaultEncoding()</methodname>
516             メソッドを使用します。
517             <programlisting language="php"><![CDATA[
518 Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-1');
519 $hits = $index->find($queryStr);
521 ]]></programlisting>
522             空の文字列は、'現在のロケール' を意味します。
523         </para>
525         <para>
526             正しいエンコーディングを指定すれば、解析器はそれを正しく処理できます。
527             実際の挙動は、使用する解析器によって異なります。詳細は
528             <link linkend="zend.search.lucene.charset">文字セット</link>
529             についての説明を参照ください。
530         </para>
531     </sect2>
533     <sect2 id="zend.search.lucene.best-practice.maintenance">
534         <title>インデックスの保守</title>
536         <para>
537             まずはっきりさせておくべきなのは、<classname>Zend_Search_Lucene</classname> やその他の
538             Lucene 実装は決して "データベース" ではないということです。
539         </para>
541         <para>
542             つまり、データを保存するものとして使用してはいけません。
543             通常のデータベース管理システムのように、バックアップ/リストア
544             やジャーナル処理、ログの記録、トランザクションといった機能は持っていません。
545         </para>
547         <para>
548             しかし、<classname>Zend_Search_Lucene</classname> はインデックスの一貫性を保持するための機能は持っています。
549         </para>
551         <para>
552             インデックスのバックアップ/リストアは、オフラインでインデックスフォルダをコピーすることで行ないます。
553         </para>
555         <para>
556             何らかの理由でインデックスが壊れてしまった場合は、
557             インデックスをリストアするか再構築しなければなりません。
558         </para>
560         <para>
561             そこで、大きなインデックスは、どこかに手動でバックアップしておき、
562             何かあったときに手動で復元できるようにしておきましょう。
563             そうすれば、障害からの復旧にかかる時間が短縮できます。
564         </para>
566     </sect2>
567 </sect1>