PowerCMS X ブログ

2025-11-12

大規模なウェブサイトのサイト内検索の設定と運用の改善

先週リリースした PowerCMS X ver.4.03では、サイト内検索 (SearchEstraierプラグイン/DocumentSearchプラグイン) についての大規模なアップデートが含まれています。その背景と具体的な設定の方法についてご紹介します。

大量文書の検索インデックスの作成

改修のきっかけは大きく2つありました。ひとつめは、大量の文書がある環境で検索インデックスの作成(洗い替え)が終わらない(長時間かかる)ことです。

従来の検索インデックスの初期作成・洗い替え処理の流れは以下のようになっています(追加された環境変数「searchestraier_permanent_document」の指定がない場合、この流れに変更はありません)。

  1. 検索インデックスのパスごとに work_dir配下に一時ディレクトリを生成します。※1
  2. SearchEstraierが対象となるアーカイブタイプの URLオブジェクトに対応する HTMLファイルを処理して文書ドラフトファイルを生成し、ディレクトリ配下に「URLオブジェクトのID.est」ファイル名で保存します。
  3. SearchEstraierの処理が終わったら DocumentSearchプラグインが指定されたモデル、指定された ファイルタイプのURLオブジェクトに対応するファイルからテキストを抽出して、supportディレクトリ配下の cache/document_cacheに「ファイルパスのmd5ハッシュ.est」ファイル名で保存します。※2
  4. そのまま抽出した文書とオブジェクトのメタデータを付与した文書ドラフトを生成してディレクトリ配下に「URLオブジェクトのID.est」ファイル名で保存します。
  5. すべてのファイルの処理が終わったらそのディレクトリに対して estcmd gatherコマンドでインデックスを作ります。
  6. 作業ディレクトリは破棄します。

※1 スペースごとではなく、インデックスのパスごとに生成されます。複数のスペースで同じインデックスを利用しているケースがあるためです。
※2 すでに抽出されたテキストがある場合は処理をスキップします。

URLオブジェクトをループしてすべての対象ファイルを処理していますので、文書の数が多ければ多いほど時間がかかるようになります。そこで、数十万ドキュメントが対象になっているような環境でも検索インデックスの構築や洗い替えが高速に行えるように改修しました。改修の方針は以下のようなものです。

  • 使い捨てをやめる(永続化)※PowerCMSは永続化されている
  • 処理を分割して実行できるように(一気通貫でなく、ステップごとに)

設定と準備

  • 環境変数「searchestraier_permanent_document」に「true」を指定します。

検索インデックスを作成するツールとして新たに Plugins/SearchEstraier/tools/searchIndexTools.php が追加されています。

※ searchIndexTools.php のマニュアルについては  Plugins/SearchEstraier/docs/README-searchIndexTools.md にあるほか、searchIndexTools.php --help で参照できます。

検索インデックスの作成には、このスクリプトを使います。以下の手順で実行することで検索インデックスの作成・洗い替えができます。(--typeに指定している document は DocumentSearchプラグインが有効な時にのみ指定)

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive,document
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type gather

--type archive(,document)は、検索インデックスの元となる中間ファイル(文書ドラフト)を作成するコマンドです。実行すると以下のパスにファイルが生成されます(a6a7c92c7a28cc1fb7ce89e4cbb85227は検索インデックスのパスの md5ハッシュ値)。

<mt:property name="support_dir">/search/document_draft/a6a7c92c7a28cc1fb7ce89e4cbb85227/

生成されるファイルはテキストファイルで、以下のように「URLオブジェクトのID.est」というファイル名になります。

1.est
2.est
3.est...

これらのファイルですが、CMSの操作でオブジェクトが更新された場合は更新され、新規作成されたり下書きにされたものが再び公開された時には追加されます。削除されたときは、削除ではなく、以下のディレクトリに移動されます(その後、スケジュールタスクで一定時間経過しているものは削除されます)。

<mt:property name="support_dir">/search/document_unlink/a6a7c92c7a28cc1fb7ce89e4cbb85227/

分割して実行する

上記の例では文書ドラフトの作成と、estcmd gather コマンドの実行を分けていますが、大量の文書がある場合、文書ドラフトの作成に時間がかかりますので、これを分割して行うことができます。HTMLなどのアーカイブと、DocumentSearchによるPDFなどの文書ドラフト作成を分けるには、以下のように --typeに1つずつ指定して各々実行します。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document

その他に、--workspace_ids, --models, --extensions の指定ができます。例えば、以下のように細かく分割して実行することができます。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive --workspace_ids 1 --models entry
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive --workspace_ids 1 --models page
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 1 --extensions pdf
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 1 --extensions xls,xlsx
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 1 --extensions doc,docx
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 1 --extensions ppt,pptx
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive --workspace_ids 2 --models entry
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type archive --workspace_ids 2 --models page
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 2 --extensions pdf
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 2--extensions xls,xlsx
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 2 --extensions doc,docx
sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --workspace_ids 2 --extensions ppt,pptx

 この例では、スペースごとに記事、ページ、PDF文書、Excel文書、Word文書、PowerPoint文書という単位に分割して実行しています。さらに、limit / offsetを指定することもできますので、更新のない夜間に実行する場合などであれば、さらに細かく分割して実行できます。並列して処理を行うことで総時間を短くすることもできます。単一のPHPスクリプトで大量の文書を処理すると、どうしても後半になるとスピードが落ちていくからです。

ドキュメントのキャッシュのみを先に生成する

DocumentSearchプラグインでは、以下のディレクトリにPDFなどの文書から抽出したテキストデータを文書ドラフト形式でキャッシュします。

<mt:property name="support_dir">/cache/document_cache/

このキャッシュのみを先に生成することができます。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --cache_only --skip_exists

--skip_exists 指定をすると、すでにキャッシュファイルや文書ドラフトが生成されている場合は処理をスキップします。その分実行時間を短縮することができます。ですので、最初の検索インデックスの構築後、運用時は常に --skip_exists を付けて実行すると良いと思います。

これを実行した後で --cache_only 指定なしで以下を実行することで DocumentSearchによる文書ドラフトの生成が完了します。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type document --skip_exists

最後に --type gatherでインデックスを生成する

すべての文書ドラフトが生成されたら、--type gatherを実行します。このとき、キャッシュサイズを指定することで、インデックスの作成を高速化できます。また、文書ドラフトの生成はすでに済んでいますので、これまでの洗い替えと比較して圧倒的に短時間で処理が終了するはずです。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type gather --cache_size 1200

公式ドキュメントには以下の記載があります。searchIndexTools.php では初期値を 400に設定しています。あまり大きな数値を指定しても効果は限定的ではありますので、実際に計測して数値を設定すると良いでしょう。環境変数「searchestraier_gather_cache_size」に数値を設定すると、その数値が自動的に使われます。また、-xlオプションや-xhオプションなどは、searchIndexTools.phpが自動的に適用するようになっています。

文書を登録する処理では、インデックスの内部で持っているデータベースに膨大な量の書き込みを行います。データベースを参照するオーバーヘッドを抑えるために、Hyper Estraierは処理中のデータをメモリ上にキャッシュする仕組みを持っています。キャッシュが大きい方が登録処理は高速になりますが、スワップが起きるとかえって効率が落ちますので、実メモリの4割程度の大きさにするとよいようです。例えば1GBの実メモリを搭載しているマシンで作業をする場合、400MB程度が適切でしょう。また、10万件以上の文書を登録する場合、インデックスを作成する際に大規模用のチューニングをするように指定すると処理効率が向上します。

estcmdの-csオプションを使うとキャッシュサイズの指定ができます。サイズはメガバイト単位で指定します。デフォルトは64MBです。また、-xlオプションや-xhオプションを使うと大規模用のチューニングがなされます。

属性検索の高速化

ここまでで、一つ目の課題、大量の文書がある環境で検索インデックスの作成(洗い替え)が終わらない(長時間かかる)問題は解決できます。続いてもう一点、大量の文書が対象のサイト内検索で属性検索が遅い問題についてです。

公式ドキュメントには下記のようにあります。

属性検索は属性データベースにおける全てのレコードを検査するために多くの時間がかかります。属性インデックスを作成すると、検査するレコードを絞り込むことによって属性検索を高速化することができます。属性インデックスはestcmd createコマンドで作成します。「-attr」オプションで対象となる属性名とデータ型を指定します。

この属性インデックスは新しいSearchEstraierプラグインのプラグイン設定で指定できます。適切に設定を行うと、劇的に検索速度が改善します(今回の改修のきっかけとなった案件ではおおよそ20倍速になりました!!)

SearchEstraierのプラグイン設定モーダルのスクリーンショット

@model str,@mime_type str,@workspace_id num,@suffix str,@mdate seq

STROREQやSTREQ などを使うものは「str」、NUMEQなどを使うものは「num」、ソート順に利用するものは「seq」としてください。複数のスペースで同じインデックスのパスを設定している場合は、どこか1つのスペースで設定すればよく、すべてのスペースで指定する必要はありません。プラグイン設定ではもう一点、属性キーの設定も可能です。

運用時の設定

一度文書ドラフトを作成して検索インデックスを構築すれば、CMSの運用時の追加更新削除は都度反映されるので、洗い替えを実行したいタイミングで(1日1回早朝や、週1回など) --type gatherを実行するように cronを設定すれば良いでしょう。

そのとき、cronに設定している worker.php に --exclude_ids searchestraier_update_idx,documentsearch_update_idx を指定して、不要な洗い替えが実行されないようにしてください。

冗長化構成の時のヒント

共有ディスクに検索インデックスを置いている場合は特に注意する必要はありませんが、検索インデックスを各々のマシンの高速なディスクに設置すると検索のパフォーマンスを上げることができます。その場合は例えば15分おきに各マシンで以下を実行することで各マシンの検索インデックスに差分を反映できます。

この時、検索インデックスのパスを「<mt:property name="support_dir">/search/index」などの共有ディスクではなく、各マシンの高速なディスク上のパスに変更して、各マシンでコマンドを実行するようにします(共有ディスクのインデックスが大きくなると、複製に失敗することがあるため)。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type update --update_within 1000

※  --update_within はその秒以降に更新されたものを対象にするので、15分=900 ですが、少しバッファを見て1000などを指定すると良いでしょう。

同じく、洗い替えも各マシンで1日1回、週1回など実行するように設定してください。

sudo -u apache php Plugins/SearchEstraier/tools/searchIndexTools.php --type gather

カテゴリー:技術情報 | プラグイン

投稿者:Junnama Noda

ブログ内検索

アーカイブ


日本語
ふりがな付き
English
简体中文
繁體中文
한국어