日本語の検索性能を向上させるモジュール Search API Japanese Tokenizer 2 をリリースしました

こんにちは。スタジオ・ウミの大野です。この記事は、以前紹介した「Drupalの日本語検索を改善!自然言語処理を活用したSearch API Japanese Tokenizerモジュールの紹介」の続報です。日本語検索の課題やモジュールの基本的な役割については、前回の記事をご覧ください。
最初のα版を公開してから、およそ1年半が経ちました。ありがたいことに、α版は大きなバグの報告もなく安定して動作していました。利用しているサイトの数は決して多くありません。それでも、私の知らないどこかで誰かの役に立っているはずです。そう考えると、公開した甲斐があったと感じます。そうしたなかで、日本語の自然言語処理は検索インデックスの作成だけでなく、他の用途にも活用できると考えるようになりました。そこで処理の土台から見直し、このたびSearch API Japanese Tokenizerの新しいメジャーバージョンとして2.0.0-beta1をリリースしました。α版から一歩進んでβ版となり、内部のアーキテクチャも大きく刷新しています。この記事では、2.0で何が変わったのかを紹介します。
2.0での主な変更点
まず、今回のリリースの要点を整理します。
- 自然言語処理の機能を新しいJNLP
モジュールに切り出した(他のモジュールからも再利用できる基盤に)
- 新しいトークナイザーとしてIgo-phpを追加した(外部インストール不要の形態素解析)
- 解析器のパス設定をプロセッサー設定から
settings.phpへ移動した - α版からβ版へと安定度が上がった
それぞれ順番に見ていきましょう。
自然言語処理を担う基盤モジュールJNLPの誕生
1.xでは、日本語を単語に分割する自然言語処理のロジックを、本モジュールが内部に抱え込んでいました。しかし、日本語のテキスト解析は検索インデックスの作成以外にも、関連コンテンツの抽出やタグの自動生成など、さまざまな場面で使いたくなる汎用的な機能です。
そこで2.0では、自然言語処理の部分をJNLP(Japanese Natural Language Processing)という独立したモジュールとして切り出しました。本モジュールは「Search API
とJNLPをつなぐ橋渡し」に専念し、実際のテキスト処理はJNLPが担います。役割を分離したことで、それぞれのモジュールが見通しよくなり、JNLPは他のモジュールからも再利用できる日本語処理の基盤になりました。
JNLPモジュール自体の設計や使い方については、別途詳しく紹介する記事を用意する予定です。この記事では「自然言語処理はJNLPが担当するようになった」という点だけ押さえていただければ大丈夫です。
新トークナイザーIgo-phpの追加
今回のリリースで、利用者にとって最も分かりやすい変更が、新しいトークナイザーIgo-phpの追加です。
前回の記事では、本モジュールが利用できる自然言語処理としてTinySegmenter・MeCab
・Sudachi
の3つを紹介しました。これらには、それぞれ次のようなトレードオフがありました。
- TinySegmenter
は純粋なPHP実装なので手軽に使えるが、機械学習ベースのため品詞解析や原型化ができない
- MeCab
やSudachi
は形態素解析により高精度で品詞解析や原型化もできるが、サーバーへの別途インストールが必要
つまり、「外部インストールなしで形態素解析を使いたい」というニーズには応えられていませんでした。ここを埋めるのがIgoの純粋PHP実装であるIgo-phpです。
Igo-phpは形態素解析エンジンでありながら、PHPライブラリとしてComposerでインストールできるため、MeCabやSudachiのように実行ファイルをサーバーへ用意する必要がありません。VPSなどアプリケーションを自由にインストールできない環境でも、品詞解析や動詞の原型化といった形態素解析の恩恵を受けられます。
各トークナイザーの特徴を、Igo-phpを加えて改めて比較すると次のようになります。
| TinySegmenter | Igo-php | MeCab | Sudachi | |
|---|---|---|---|---|
| 方法 | 機械学習 | 形態素解析 | 形態素解析 | 形態素解析 |
| 品詞解析 | なし | あり | あり | あり |
| 速度 | 速め | 普通 | 速い | 遅い |
| 精度 | 低い | 普通 | 普通 | 高い |
| 正規化機能 | なし | あり(基本形) | あり(基本形) | あり |
| 外部インストール | 不要 | 不要 | 必要 | 必要 |
Igo-phpは純粋PHP実装のため、ネイティブのバイナリーで動作するMeCab
に比べると処理速度は劣ります。また、辞書はライブラリに同梱されたIPA辞書のみで、カスタム辞書には対応していません。
さらに注意したいのが、開発状況です。ベースとなったオリジナルのIgoは配布がすでに終了しており、Igo-php自体も活発なメンテナンスが続いているとはいえません。開発が事実上止まっているライブラリである点は、採用にあたっての難点として理解しておく必要があります。
とはいえ、「外部インストール不要で形態素解析を使える」というのは大きな魅力で、TinySegmenterとMeCab
のちょうど中間を埋める選択肢になります。用途や環境に合わせて使い分けるとよいでしょう。
なお、Igo-php用のトークナイザーを利用するには、対応するサブモジュール
search_api_igo_phpを有効化してください。
解析器のパス設定をsettings.phpへ移動
1.xでは、MeCabの実行ファイルやSudachiのJARファイルなど、解析器のパスをプロセッサーの設定画面から指定していました。2.0では、これらのパス設定をsettings.phpで行うように変更しています。
この変更は、どちらかというとセキュリティー上の理由によるものです。解析器のパスは、サーバー上で起動する実行ファイルやJARファイルそのものを指し示す値です。これをプロセッサー設定として保持すると、管理画面や構成のインポート経由で書き換えられる余地が生まれます。もし悪意のある値に差し替えられれば、意図しないプログラムが実行されてしまう恐れもあります。settings.phpはサーバーのファイルシステムに直接アクセスできる人しか編集できないため、こうしたパスの管理場所として安全です。あわせて、環境によって異なるパスを構成のエクスポートから切り離せるという利点もあります。設定例は次のとおりです。
$settings['jnlp_mecab_executable'] = '/usr/bin/mecab';
$settings['jnlp_sudachi_jar_path'] = '/opt/sudachi/sudachi.jar';
指定できるキーの一覧はSearch API Japanese TokenizerおよびJNLP
のREADMEを参照してください。
1.xからのアップグレード
すでに1.xをお使いの場合は、次の手順でアップグレードできます。自然言語処理をJNLPへ委譲した都合上、いくつか注意点があるため順番に説明します。
1. JNLPの先行取得
本モジュールが依存するJNLPは、現時点でβ版のみを公開しています。まずは、このJNLPを次のコマンドで先にインストールしてください。
composer require 'drupal/jnlp:@beta'
なぜJNLPだけを先にインストールするのか、少し補足します。Composerはデフォルトで安定版(stable)しかインストールしません。β版を許可するには@betaという指定が必要です。ただし、この指定が有効なのはプロジェクト直下のcomposer.jsonだけで、依存パッケージ側に書かれた指定は無視される仕様になっています。本モジュールのcomposer.jsonにもJNLPを@betaで読み込む指定はありますが、依存パッケージ側の指定なので効きません。そのため、先ほどのコマンドでJNLPの@betaをプロジェクト直下に登録し、β版がインストールできる状態にしておく必要があるのです。
2. モジュールの更新
本モジュールを更新します。
composer require 'drupal/search_api_japanese_tokenizer:^2.0@beta'
3. データベースの更新
データベースを更新します。この更新では、必要なJNLPサブモジュールが自動でインストールされ、あわせて使われなくなったパス設定を保存済みのインデックスから取り除きます。データを失うような処理ではありません。そのため、それほど身構える必要はないでしょう。
ひとつだけ注意点があります。コードを更新した手順2の直後は、まだJNLPサブモジュールが有効になっていません。この状態では検索やインデックス作成が一時的にエラーになるため、手順2に続けて速やかに実行してください。
drush updatedb
4. パス設定の移行
MeCabやSudachiのパスをプロセッサー設定で指定していた場合は、前述のとおりsettings.phpで再設定します。旧設定は自動的に削除され、データベース更新の際に報告されます。
5. 構成のエクスポート
更新した構成をエクスポートします。
drush config:export
α版からβ版へ
前回の記事では、本モジュールをα版として紹介しました。今回のリリースでアーキテクチャの整理が一段落し、β版へと歩みを進めています。α版に比べて仕様が安定してきたので、より安心してお試しいただけるようになりました。
もちろんβ版ですので、まだ改善の余地はあります。お使いいただくなかで気づいた点があれば、ぜひDrupal.orgのイシューキューからフィードバックをお寄せください。
おすすめのプロセッサー順序
最後に、本モジュールを使ううえで見落としがちな設定のポイントを紹介します。それがプロセッサーの実行順序です。
Search APIは、インデックス作成時と検索時に複数のプロセッサーを上から順に適用します。日本語トークナイザーは、他のプロセッサーによる前処理を済ませたテキストを受け取れるよう、順序のできるだけ最後に配置するのがおすすめです。
次の図は、Sudachi tokenizerを使う場合のおすすめの順序設定です。

ポイントは次の3つです。
- HTMLフィルターは日本語トークナイザーより前に置く。HTMLタグを取り除いてから解析することで、タグがノイズとして混ざるのを防げる
- Japanese Normalizer(Search API Japanese Normalizer
)は日本語トークナイザーの直前に置く。表記揺れを正規化してから単語に分割することで、解析精度が高まる
- 日本語トークナイザーは、テキストを変換するプロセッサーのなかでいちばん最後(下)に置く。図の「コンテンツへのアクセス権限」のようにテキストを変換しないプロセッサーは、トークナイザーより後ろにあってもかまわない
このように前処理を済ませてから最後にトークナイズすることで、日本語検索の精度をさらに引き上げられます。表記揺れを吸収するSearch API Japanese Normalizerモジュールとの併用もぜひ検討してみてください。
まとめ
今回のリリースでは、自然言語処理をJNLPモジュールへ切り出してアーキテクチャを整理し、新たに外部インストール不要の形態素解析トークナイザーIgo-php
を追加しました。これまで環境の制約で形態素解析をあきらめていた方も、Igo-php
なら手軽に試せます。Drupalで日本語検索を扱う機会があれば、ぜひ一度お試しください。
次回は、今回切り出したJNLPモジュールそのものについて、設計の狙いや使い方を詳しく紹介する予定です。
謝辞
本モジュールは外部のライブラリやソフトウェアを利用しています。自然言語処理の分野は高度で複雑なため、これらの技術なしに高精度な処理を実現するのは困難です。OSSとして公開し、貢献してくださっている開発者の皆様に心より感謝申し上げます。




