Fess 15.7のStaticテーマでソースコード検索を分かりやすく表示する

Fessでソースコード検索を手軽に試せるdocker-codesearchを、Fess 15.7に合わせて大きく刷新しました。Fess 15.7とOpenSearch 3.7を組み合わせ、Gitリポジトリをクロールしてソースコードを全文検索できる環境を、docker compose upだけで立ち上げられるようにしています。

今回のポイントは、Fess 15.7で追加された静的テーマ(Static Theme)の仕組みを活用し、ソースコード検索の見た目を分かりやすくしたことです。デフォルトで採用している「Code Search」テーマでは、各検索結果を1ファイルごとのコードカードとして表示し、言語バッジや行番号付きのコードスニペットを備えたGitHubのコード検索に近い画面になっています。これにより、どのリポジトリのどのファイルがヒットしたのかが一目で分かるようになりました。

ソースコード検索とdocker-codesearch

FessはOpenSearchをバックエンドに持つオープンソースの全文検索サーバーです。docker-codesearchは、そのFessをソースコード検索サーバーとして仕立てるためのDocker Compose環境で、自前でホストできるコード検索基盤として使えます。

ソースコードの取り込みにはfess-ds-gitデータストアプラグインを利用します。指定したGitリポジトリをクローンしてファイルを順にインデックスし、リポジトリ名・組織名・パスといったメタデータや、拡張子から判定した言語(filetype)を各ドキュメントに付与します。あわせて各行に行番号を付けてインデックスするため、検索画面側で行番号付きのコードスニペットを表示できるようになっています。

必要な環境

  • Docker および Git
  • Linuxの場合はOpenSearch向けにvm.max_map_countを262144以上に設定(Docker Desktopでは自動設定)

利用する主なコンポーネントは以下のとおりです。

  • Fess 15.7.0
  • OpenSearch 3.7.0(fess-opensearch)
  • fess-ds-git 15.7.0

イメージのバージョンは.envで一元管理しており、アップグレード時はここのFESS_VERSIONOPENSEARCH_VERSIONを書き換えます。

FESS_VERSION=15.7.0
OPENSEARCH_VERSION=3.7.0

セットアップと起動

リポジトリをクローンし、セットアップスクリプトを実行してから起動します。

git clone https://github.com/codelibs/docker-codesearch.git
cd docker-codesearch
bash ./bin/setup.sh
docker compose up -d

bin/setup.shは、データディレクトリの作成、fess-ds-gitプラグインの取得、静的テーマの同期、そしてsystem.propertiesfess_config.propertiesの生成を行います。初回起動時はインデックスの初期化に少し時間がかかります。準備が整えば、検索画面はhttp://localhost:8080/、管理画面はhttp://localhost:8080/admin(初期アカウントはadmin / admin)でアクセスできます。

Staticテーマでソースコード検索を分かりやすくする

今回の刷新で一番大きいのが、検索画面の作り方を変えたことです。以前は独自のJSPテーマ(fess-theme-codesearchプラグイン)で検索画面を組み、バーチャルホストに紐付けてテーマを切り替えていました。今回はFess 15.7で追加された静的テーマ(HTML/CSS/JavaScriptだけで検索画面を構成できる仕組み)に切り替えています。テーマはfess-themesリポジトリからbin/setup.shが同期します。

テーマの有効化は、system.propertiesの1行だけで行えます。以前のようにバーチャルホストの設定を書く必要はありません。

theme.default=codesearch

デフォルトで採用している「Code Search」テーマは、ソースコード検索に特化した作りになっています。

  • 1ファイルごとのコードカード: 検索結果を「組織 / リポジトリ ・ パス」のパンくずと、言語バッジ、行番号付きのコードスニペットとして表示します。マッチした語句はハイライトされ、リポジトリ上の該当箇所を開くリンクも付いています。
  • クエリ内の絞り込み修飾子: 検索ボックスにrepo:(リポジトリ)、org:(組織)、path:(パス)、file:(ファイル名)、lang:(言語)といった修飾子を書くと、そのままフィールド検索になります。たとえばrepo:fess lang:javaのように指定できます。
  • ファセットによる絞り込み: リポジトリ・言語・組織・パスといったファセットが左側に並び、件数を見ながら多段で絞り込めます。選んだ条件はクエリ文字列に反映されるため、検索結果のURLをそのまま共有できます。
  • ダークテーマ主体のIDE風デザイン: コードやパスを等幅フォントで表示するIDEに近い見た目で、ライトテーマへの切り替えにも対応しています。

以前のBootstrapベースの汎用的な検索画面と比べて、コード検索に必要な情報(言語・リポジトリ・行番号・該当箇所へのリンク)が最初から画面に並ぶため、検索結果がぐっと読み取りやすくなりました。

リポジトリの登録とクロール

検索対象のリポジトリは、Fessの公式CLIであるfessctlを使って登録します。docker-codesearchには、GitHubリポジトリを登録するためのbin/register_github.shラッパーも用意しています。デフォルトブランチの自動判定に対応し、冪等に登録できます。

export FESS_ENDPOINT=http://localhost:8080
export FESS_ACCESS_TOKEN=<管理画面のアクセストークン>

# 例: codelibs/fess-suggest を登録
./bin/register_github.sh codelibs fess-suggest

アクセストークンは管理画面の/admin/accesstoken/で発行できます。登録後にクローラーを実行すれば、リポジトリのソースコードがインデックスされ、検索できるようになります。

まとめ

docker-codesearchをFess 15.7 + OpenSearch 3.7に対応させ、docker compose upだけでソースコード検索を試せるようにしました。さらに、Fess 15.7のStaticテーマ「Code Search」を採用することで、1ファイルごとのコードカードや言語バッジ、行番号付きスニペット、repo:lang:といった修飾子が使えるようになり、ソースコード検索の結果が格段に分かりやすくなっています。

詳細やソースコードはdocker-codesearchを参照してください。

Fess 15.7のStaticテーマでマルチモーダル検索をギャラリー表示する

Fessでは、画像とテキストを横断して検索できるマルチモーダル検索を利用できます。ただ、通常のテキストリスト形式の検索結果画面では、画像とドキュメントが混在した結果が直感的にわかりにくいという課題がありました。そこで、Fess 15.7で強化されたStaticテーマ(テーマ)の仕組みを使い、検索結果をサムネイルのギャラリーとして表示するmosaicテーマを用意しました。これにより、マルチモーダル検索の結果を一目で把握できるようになります。

この記事では、docker-multimodalsearchのDocker環境を例に、mosaicテーマを使ってマルチモーダル検索をわかりやすく見せる方法を紹介します。

マルチモーダル検索とは

マルチモーダル検索は、テキストのキーワード一致だけでなく、意味的な近さ(画像とテキストの関連度)でも検索できる仕組みです。docker-multimodalsearchでは、以下の2つの検索を組み合わせています。

  • キーワード検索(BM25): 従来の全文検索。ページやPDF、Officeドキュメントの本文にマッチします。
  • ベクトル検索(CLIP): CLIPモデルで生成した埋め込みベクトルによるkNN検索。テキストのクエリから、意味的に近い画像を見つけられます。

たとえば「山の夕日」や「mountain sunset」といったテキストで検索すると、キーワードにマッチしたドキュメントに加えて、CLIPが「山の夕日らしい」と判断した画像も同時にヒットします。日本語・英語のどちらのクエリでも画像検索できるのが特徴です。

Fessはこの2つの検索をdefault(BM25)とmulti_modal(CLIP)というサーチャーとして扱い、ハイブリッドなランク融合で1つの検索結果にまとめます。

Staticテーマ(mosaicテーマ)とは

マルチモーダル検索の結果は、画像とドキュメントが混在します。これを通常のテキストリストで表示すると、どれが画像でどれがドキュメントなのか、なぜヒットしたのかがわかりにくくなります。

そこで用意したのがmosaicテーマです。Fessのテーマ(Static Theme)機構を利用したギャラリーUIで、次のような見た目にしています。

  • サムネイルを敷き詰めたメーソンリー(masonry)グリッドで表示
  • 画像をクリックするとライトボックスで拡大表示
  • 各結果に Keyword / Visual / Blend のバッジを表示し、キーワード(BM25)・ベクトル(CLIP)・その両方のどれでマッチしたかを可視化

バッジによって「この画像はベクトル検索でヒットした」「このドキュメントはキーワードと画像の両方でマッチした」といったことが一目でわかります。

mosaicテーマの本体はcodelibs/fess-themesリポジトリで管理されており、後述のセットアップスクリプトが同期して配置します。

環境構築

docker-multimodalsearchは.env駆動で、Docker Composeだけでマルチモーダル検索環境を起動できます。手順は次の通りです。

1. 取得と設定

git clone https://github.com/codelibs/docker-multimodalsearch.git
cd docker-multimodalsearch
cp .env.example .env

.envにはテーマやモデルの設定がまとまっています。テーマ関連は次の項目です。

# Theme
THEME_NAME=mosaic
FESS_THEMES_REPO=https://github.com/codelibs/fess-themes.git
FESS_THEMES_REF=main
# FESS_THEMES_DIR=/absolute/path/to/local/fess-themes   # dev: use a local checkout instead of cloning

THEME_NAMEで使用するテーマ名を指定します。デフォルトはmosaicです。

2. セットアップスクリプトの実行

bash bin/setup.sh

このスクリプトはホスト側の準備を行うもので、bind-mount用ディレクトリの作成、system.propertiesの初期化、そしてfess-themesリポジトリからのmosaicテーマの同期を行います。同期先は./data/fess/usr/share/fess/app/themes/mosaicで、これがそのままFessコンテナにマウントされます。

テーマはsystem.propertiestheme.defaultで有効化されます。テンプレートには以下が設定されています。

theme.default=mosaic
thumbnail.enabled=true
suggest.search.log.enabled=true
suggest.document.enabled=true
login.required=false

3. スタックの起動

docker compose up -d
docker compose ps

初回起動時はCLIPの埋め込みサーバー用イメージのビルドと、CLIPモデル(約1.6GB)のダウンロードが行われるため、数分かかります。

4. サンプルコンテンツの投入とクロール

サンプル画像やドキュメントを配置してクロールします。

bash bin/fetch-sample-images.sh

その後、http://localhost:8080/admin/(初期ユーザーはadmin / admin)にログインし、クローラーでhttp://content/をクロールすると、検索対象のインデックスが作成されます。

5. 検索する

http://localhost:8080/を開いて検索してみましょう。多言語モデルを使っているため、日本語・英語のどちらでも試せます。

  • 英語: mountain sunset
  • 日本語: 山の夕日

mosaicテーマにより、CLIPがマッチした画像とキーワードでマッチしたページやPDFが、サムネイルのギャラリーとして一緒に表示されます。

サムネイル表示には-nobleイメージが必須

ギャラリー表示はサムネイルが主役です。ここで注意したいのが、使用するFessイメージです。デフォルトのAlpineベースのghcr.io/codelibs/fess:15.7.0イメージには、ImageMagick・poppler・LibreOfficeが含まれていません。これらが無いと、画像・PDF・Officeドキュメントのサムネイルが生成されず、ギャラリーが空のタイルだらけになってしまいます。

そのため、docker-multimodalsearchではこれら3つを同梱したUbuntu Nobleベースの-nobleバリアントを使用しています。

FESS_IMAGE=ghcr.io/codelibs/fess:15.7.0-noble

サムネイルのサイズはFESS_JAVA_OPTSで指定しています。

-Dthumbnail.width=512
-Dthumbnail.height=512

テーマ更新時の注意点

Fessはテーマのファイルをメモリにキャッシュします(StaticThemeResponder)。そのため、mosaicテーマのファイルを更新した場合は、Fessコンテナを再起動しないと変更が反映されません。

docker compose restart fess01

なお、.envFESS_THEMES_DIRにローカルのfess-themesチェックアウトを指定すると、リポジトリをcloneせずローカルのテーマを使えます。テーマ自体を改修しながら見た目を調整したい場合に便利です。

まとめ

Fess 15.7のStaticテーマ機構を使ったmosaicテーマを利用することで、画像とドキュメントが混在するマルチモーダル検索の結果を、サムネイルのギャラリーとして直感的に表示できるようになりました。Keyword / Visual / Blendのバッジで「なぜヒットしたのか」も可視化されるため、マルチモーダル検索の挙動を理解しやすくなっています。

docker-multimodalsearchはDocker Composeだけで一式を起動できるので、マルチモーダル検索を試してみたい方はぜひ活用してみてください。

Fess 15.7のStaticテーマでセマンティック検索を分かりやすく可視化する

Fessでセマンティック(ベクトル)検索を手軽に試せるように、docker-semanticsearchを大きく刷新しました。Fess 15.7とOpenSearch 3.7を組み合わせ、docker compose upだけで、BM25(キーワード検索)とベクトル検索を組み合わせたハイブリッド検索が動く環境をそのまま立ち上げられるようにしています。

今回のポイントは、Fess 15.7で追加された静的テーマ(Static Theme)の仕組みを活用し、検索結果の見た目を分かりやすくしたことです。デフォルトで採用している「SemanticLens」テーマでは、各検索結果がキーワード検索・セマンティック検索・ハイブリッドのどれによってヒットしたのかをバッジで表示します。これにより、セマンティック検索が実際にどう効いているのかが一目で分かるようになりました。

セマンティック検索とハイブリッド検索

Fessのセマンティック検索は、埋め込みモデルで文章をベクトル化し、意味の近さで検索するベクトル検索です。従来のBM25によるキーワード検索と組み合わせ、RRF(Reciprocal Rank Fusion)で両者のランキングを統合することで、表記ゆれや言い換えに強いハイブリッド検索を実現します。docker-semanticsearchでは、多言語対応の埋め込みモデルparaphrase-multilingual-MiniLM-L12-v2(384次元)をデフォルトで使用します。

必要な環境

  • Docker および Git
  • Linuxの場合はOpenSearch向けにvm.max_map_countを262144以上に設定(Docker Desktopでは自動設定)

利用する主なコンポーネントは以下のとおりです。

  • Fess 15.7.0
  • OpenSearch 3.7.0(fess-opensearch)
  • fess-webapp-semantic-search 15.7.0

セットアップと起動

リポジトリをクローンし、セットアップスクリプトを実行してから起動します。

git clone https://github.com/codelibs/docker-semanticsearch.git
cd docker-semanticsearch
bash ./bin/setup.sh
docker compose up -d

bin/setup.shは、データディレクトリの作成、system.propertiesの初期生成、そして静的テーマの同期を行います。初回起動時はOpenSearchが埋め込みモデルをダウンロードするため、準備が整うまで数分かかります。進捗は次のコマンドで確認できます。

docker compose logs -f init-semantic init-fess-index
docker compose ps -a

fess01がhealthyになり、セットアップ用のコンテナが正常終了すれば準備完了です。検索画面はhttp://localhost:8080/、管理画面はhttp://localhost:8080/admin(初期アカウントはadmin / admin)でアクセスできます。あとは管理画面のクローラー設定でクロール対象を登録してクロールを実行すれば、取り込んだドキュメントが自動的にベクトル化され、検索できるようになります。

Staticテーマで検索結果を可視化する

今回の刷新で一番大きいのが、検索画面の作り方を変えたことです。以前は独自のJSPテーマで検索画面を組んでいましたが、Fess 15.7で追加された静的テーマ(HTML/CSS/JavaScriptだけで検索画面を構成できる仕組み)に切り替えました。テーマはfess-themesリポジトリからbin/setup.shが同期します。

利用するテーマは.envTHEME_NAMEで指定でき、デフォルトはsemanticlens(SemanticLens)です。SemanticLensは、各検索結果に「その結果がどの検索器(keyword / semantic / hybrid)によって生成されたか」を示すバッジと凡例を表示します。ハイブリッド検索では複数の検索器のランキングが統合されるため、通常のテーマでは「なぜこの結果が出てきたのか」までは分かりません。SemanticLensを使うと、セマンティック検索で拾えた結果とキーワード検索でヒットした結果を見分けられるので、動作の理解やチューニングに役立ちます。

SemanticLens以外にも、以下の静的テーマが選べます。

  • semanticlens(デフォルト。検索器バッジを表示)
  • nomadkit
  • docsearch
  • docuforge
  • rawblock
  • voicebox

テーマを切り替えるときは.envTHEME_NAMEを変更してからbin/setup.shを実行します。なお、bin/setup.shは既存のsystem.propertiesを上書きしないため、すでに起動済みの環境でテーマを変える場合は、data/fess/opt/fess/system.propertiestheme.defaultを直接書き換える(または管理画面のAdmin > Generalで変更する)必要があります。

セマンティック検索は自動でセットアップされる

以前のdocker-semanticsearchは、モデルの登録や設定値の手貼り、再インデックスといった手順をすべて手動で行う必要がありました。今回のバージョンでは、これらをコンテナ起動時に自動化しています。

  • セマンティック検索プラグインは、FessのFESS_PLUGINS環境変数で自動的にインストールされます。
  • init-semanticコンテナが、OpenSearchに埋め込みモデルを登録・デプロイし、チャンク分割と埋め込みを行うニューラル取り込みパイプライン(neural_pipeline)を作成します。
  • 生成されたモデルIDは、Fess起動時にJVMのシステムプロパティとして自動的に注入されます。
  • init-fess-indexコンテナが、ドキュメントインデックスにベクトル用のマッピングを付与するための再インデックスを一度だけ実行します。

これらはいずれも冪等に作られているので、docker compose upを実行するだけで、管理画面での手作業なしにハイブリッド検索が使える状態になります。

まとめ

docker-semanticsearchをFess 15.7 + OpenSearch 3.7に対応させ、docker compose upだけでセマンティック検索(ハイブリッド検索)を試せるようにしました。さらに、Fess 15.7のStaticテーマ「SemanticLens」を採用することで、どの検索器で結果がヒットしたのかがバッジで分かるようになり、セマンティック検索の挙動を見た目でつかめるようになっています。

詳細やソースコードはdocker-semanticsearchを参照してください。