Fessの実験的なBacklog連携で課題を検索し、権限と削除を管理する

Backlogの課題、コメント、Wiki、ドキュメント、添付・共有ファイルをFessから検索するための実験的なデータストアが用意されています。今回のPRでは、実験的な提供であることと設定上の注意が明記され、HTTP 429後の待機を最低1秒にする改善がマージされました。

Fess本体15.9.0は正式公開済みですが、fess-ds-backlogは実環境での検証を広げている段階です。特にドキュメント・共有ファイルのURLや一部の添付取得には実スペースで未検証の項目があり、事前検証を前提として導入します。

プラグインと専用アカウントを準備する

Fess 15.9に対応するプラグインJARを管理画面の「システム」→「プラグイン」でローカルファイルとして導入するか、app/WEB-INF/plugin/へ配置して再起動します。データストア設定のハンドラーでBacklogDataStoreを選びます。

Backlogにはクロール専用ユーザーを用意し、対象プロジェクトへ参加させてAPIキーを発行します。管理者でも未参加プロジェクトをすべて取得する設定ではありません。閲覧のみ等の制限ロールでは添付や共有ファイルが403となり、該当機能がスキップされる場合があります。

Fessのパラメーターは、まず小さな1プロジェクトに限定して設定します。

api_key=REPLACE_WITH_BACKLOG_API_KEY
space_url=https://example.backlog.com
project_keys=EXAMPLE
script_type=javascript

space_urlはHTTPSのスキームとホストを指定します。対応するホストは*.backlog.com、*.backlog.jp、*.backlogtool.comです。APIキーは専用ヘッダーで送信され、リダイレクトは追跡しません。Javaのorg.codelibs.curlロガーをFINEへ上げると専用ヘッダーが記録される可能性があるため、診断時も注意してください。

スクリプトには次を設定します。権限同期には最後の行が必要です。

title=backlog.title
content=backlog.content
url=backlog.url
mimetype=backlog.mimetype
created=backlog.created
last_modified=backlog.updated
role=backlog.roles

データストアのスクリプト種類が未設定だとGroovyになります。Groovyは15.9本体に同梱されないため、この例ではscript_type=javascriptを明示しています。

初期値と所要時間を確認する

パラメーター初期値
project_keys空(APIユーザーが参照できる全プロジェクト)
include_archivedfalse
include_issues / include_comments / include_wikistrue
include_documents / include_attachments / include_shared_filestrue
permission_synctrue
default_permissions空
max_file_size10485760バイト
request_interval200ミリ秒
search_request_interval1000ミリ秒
max_retry_count5

毎回全件クロールします。課題ごとにコメント取得があるため、10万件なら200ミリ秒の待機だけでも約5.5時間かかり、実際には一覧・添付取得等の時間が加わります。レート制限はAPIキー単位ではなくユーザー単位で共有されるため、同じユーザーの別処理も考慮します。

429ではX-RateLimit-Resetに従って1〜120秒待機し、ヘッダーがなければ60秒待機します。今回の修正は、サーバー時刻との差等でリセット時刻が過去になっても再試行を即座に使い切らないためのものです。

プロジェクト権限を検索へ反映する

permission_sync=trueでは、プロジェクトメンバーのメールアドレスとユーザーIDから{user}権限を作ります。Fessのログイン名がBacklogの識別子に対応していることが前提です。別人が同じログイン名を持つ環境では、そのまま対応付けてはいけません。

Fess管理画面の「アクセス権限」に初期入力される{role}guestは削除してください。これを残すと同期した権限へ追加され、匿名検索を含む全員が検索できる構成になります。role=backlog.rolesも忘れず設定します。

検索権限はプロジェクト単位です。Backlogで添付をダウンロードできない閲覧専用メンバーでも、Fess側では同プロジェクトの取得済み添付を検索できる場合があります。元サービスの機能別権限まで再現するものではありません。メンバー取得に失敗したプロジェクトは権限なしで登録せず、スキップして失敗URLへ記録します。

削除とメンバー変更は即時反映とは限らない

標準では文書に有効期限が付き、初期値3日で期限切れ後に削除されます。元データを削除した場合やメンバーが脱退した場合も、古い権限の文書が約3日残る可能性があります。権限を含む文書IDが変わるため、残ったメンバーには重複結果が見える場合もあります。

クロール終了時に未再登録文書を削除したい場合は、次を検討します。

keep_expires_docs=false

ただし、途中の403、一覧取得失敗、プロジェクトのスキップ、中断でも到達できなかった既存文書が削除対象になります。即時削除を優先するか、一時障害中も結果を保持するかを決めて設定してください。

失敗項目があってもジョブ全体は成功する場合があります。「クローラー」→「失敗URL」とfess-crawler.log、利用者ごとの検索結果、結果リンクの遷移を確認します。未知の共有ファイル種別は警告を出してスキップします。まず課題・Wikiなどの小さな範囲で、権限と更新・削除の動作まで検証するのがよいでしょう。

関連PR

FessのデータクロールでJavaScriptの日付を登録する

データストアのスクリプトでnew Date(...)を返すと、日付ではなくJavaScriptのオブジェクトとして登録され、日付フィールドの型エラーになる場合がありました。FessのJavaScriptエンジンで、評価結果の日付をjava.util.Dateへ変換する修正がマージされました。

最終更新日時のフィールド名

インデックスのフィールド名はlast_modifiedです。lastModifiedという別の名前では、最終更新日時を設定できません。

JavaScriptで実行するデータストア設定のスクリプト欄で、timestampという変数にエポック秒が入っている例です。変数名は利用しているデータストアが公開する名前に合わせてください。

last_modified=new java.util.Date(Number(timestamp) * 1000)

java.util.DateはすでにJavaの日付なので、この修正による変換は不要です。修正を含むビルドでは、次の組み込みDateを返す書き方もJavaの日付へ変換されます。

last_modified=new Date(Number(timestamp) * 1000)

15.9開発版ではJavaScriptが既定のスクリプトエンジンです。ただしデータストア設定で選択するエンジンを確認してください。Groovyなどの別エンジンへ同じ例をそのまま適用する説明ではありません。秒をミリ秒へ変換するために1000倍しており、元データがミリ秒なら掛け算は不要です。

変換の範囲と制限

変更の対象はJavaScriptエンジンの評価結果そのものがDateである場合です。オブジェクトや配列の内側にあるDateを再帰的に変換する処理は追加していません。無効なDateはエポック時刻ではなくnullになります。文字列などDate以外の結果はそのままです。

修正前の型エラーでは、その文書を含む一括登録が失敗することがあります。失敗したデータは自動的に復元されるわけではないため、スクリプトを直して対象を再クロールし、障害URLやクロールログ、実際のlast_modifiedを確認してください。PRでは変換処理の単体テストを実施していますが、実CSVクロールによる検証は未実施とされています。

関連PR

外部OpenSearchを使うFessのsystemd起動条件が改善される

OpenSearchを別ホストやコンテナーで運用していても、Fessのsystemdサービスを起動できるようにする変更がマージされました。ローカルのopensearch.serviceが存在しないだけで、Fessのプロセスが起動前に止まる問題への対応です。

起動依存関係の変更

従来のサービス定義はRequires=opensearch.serviceを指定していました。このユニットがローカルにない場合、systemctl start fess.serviceが「Unit opensearch.service not found」で失敗し、Fessは起動しません。

修正後はWants=opensearch.serviceへ変更します。After=opensearch.serviceは維持されるため、ローカルにOpenSearchのユニットがある構成では、その起動を要求し、順序を付けます。外部接続構成では、ローカルユニットがなくてもFessの起動が阻止されなくなります。

この変更に新しい接続先の初期値はありません。利用中の検索エンジンに合わせた既存の設定を使います。

運用時に確認すること

導入後はサービスの状態とFessログを確認します。

systemctl status fess.service
journalctl -u fess.service

ローカルOpenSearchの停止・再起動に合わせてFessも停止・再起動させる従来の依存関係は弱まります。Fessは動作を続け、自身のHTTPクライアントで再接続します。監視ではFessのプロセス状態だけでなく、検索エンジンへの疎通や実際の検索処理も確認してください。

追加修正#3628では、debの設定処理で、systemdが稼働しsystemctlがある場合にsystemctl daemon-reloadを実行します。更新済みユニットがディスクにあっても旧定義が読み込まれたままになる問題を防ぎます。systemdが動いていないコンテナーやinit.dだけの環境では実行しません。インストール直後にFessを自動起動する変更ではなく、接続先の確認も別途必要です。

#3602単体の確認はスタブを使ったサービス起動試験でしたが、#3628ではDebian 12のsystemd環境で15.8からのdeb更新後の依存関係とNeedDaemonReloadを検証しています。Fess本体の検索動作を確認した試験ではないため、導入先でもサービス定義と実際の検索を確認してください。

関連PR