概要
JavaScriptは Fess 15.9以降の既定のスクリプト言語です。 Sai(Fess がDI XMLの式判定にも利用している、CodeLibsによるNashornフォーク)上で 動作し、スクリプトは ECMAScript 6 として実行されます。識別子は javascript で、 js および sai というエイリアスでも指定できます。
スクリプトの評価方法
Fess のスクリプトエンジンは、スクリプト文字列をまず1つの「式」としてコンパイルしようと 試み、それが構文エラーになった場合にのみ「文(ステートメント)」のブロックとして コンパイルし直します。
このため、値を返すだけの単純な式:
も、トップレベルに return 文を含むスクリプト:
も、どちらも問題なく動作します。後者は通常のJavaScriptとしてはトップレベルの return は構文エラーですが、式としてのコンパイルに失敗するため文ブロックとして 再解釈され、有効なスクリプトとして実行されます。
データストアスクリプトのように1行が1つの式として扱われる場面では、複数の文からなる スクリプトは使用できません。一方、スケジュールジョブのようにスクリプト全体が評価される 場面では、複数行の文や let / const の変数宣言、制御構文を自由に使用できます。
警告
文ブロックとしてコンパイルされたスクリプトが値を返すのは、明示的な return を含む場合 だけです。スクリプト文字列が式として解析できなかった場合、その文字列は関数で包まれて文の ブロックとして実行されますが、 return のないブロックの評価結果は null になります。 末尾にセミコロンを1つ付けるだけで、この境界を越えます。
| スクリプト | 結果 | 理由 |
|---|---|---|
content.length() | 11 | 式として解析され、式の値がそのまま結果になります |
content.length(); | null | 文ブロックとしてしか解析されず、 return がありません |
var x = 1; x + 2 | null | 文ブロックとしてしか解析されず、 return がありません |
Groovyでは、最後に評価された文の値がスクリプトの戻り値になるため、上記3つはいずれも値を 返していました。JavaScriptにはこの規則はありません。
これは、移行における唯一の「エラーもログも出ず、フィールドが黙って空になること以外に症状が 出ない」差異です。スクリプトが null を返したデータストアのマッピングは、そのフィールドを 単に設定しません。データストアの フィールド名=式 の各行は末尾のセミコロンを付けずに式 として記述し、スケジュールジョブのスクリプトには必ず明示的な return を記述してください。
基本構文
以下で末尾にセミコロンが付いていない行は 式 であり、データストアの フィールド名=式 の行を含め、どこでも使用できます。 let / const による宣言、 if ブロック、 ループは 文 であり、スケジュールジョブのようにスクリプト全体が評価される場面でのみ 使用できます。その場合も値を返すには明示的な return が必要です。 上記「スクリプトの評価方法」を参照してください。
変数宣言
文字列操作
コレクション操作
条件分岐
ループ処理
データストアスクリプト
データストア設定でのスクリプト例です。
注釈
データストアスクリプトでは、 フィールド名=式 の各行がそれぞれ独立した1つの式として評価されます。 そのため、 let / const による変数宣言文や、複数フィールドをまとめて設定する複数行の制御構文( if ブロックなど)は使用できません。 Javaクラスを利用する場合は完全修飾クラス名(FQCN)を用いて1つの式で記述し、条件分岐はフィールドごとに三項演算子で記述します(例: url=data.published ? data.url : null )。 また、ここで使用している変数名 data は説明用の例であり、実際の変数名は利用するデータストアコネクタによって異なります。詳細は データストアクロール を参照してください。 式は末尾のセミコロンを付けずに記述してください。文ブロックとしてしか解析できない行の評価結果は null になり、そのフィールドは設定されません。 スクリプトの評価方法 を参照してください。
基本的なマッピング
URLの生成
コンテンツの加工
日付の処理
利用可能なオブジェクト
スクリプトの実行コンテキストによって、利用可能なオブジェクトが異なります。
| コンテキスト | オブジェクト | 説明 |
|---|---|---|
| 全コンテキスト | container | DIコンテナ。 container.getComponent("...") でコンポーネントにアクセスする際に使用 |
| スケジュールジョブ | executor | ジョブ実行制御( JobExecutor )。ジョブの停止サポートに必要 |
| データストア | (コネクタ固有) | 各データストアが提供するデータレコード変数。変数名はコネクタによって異なる |
| パスマッピング | url , matcher | 変換対象のURL文字列と正規表現のマッチ結果( Matcher )。置換文字列が javascript: (エイリアス js: , sai: )のように登録済みエンジン名を前置した形式のときに利用可能 |
| ドキュメントブースト | (ドキュメントフィールド) | 対象ドキュメントの各フィールドが変数として利用可能(条件式・ブースト値式で使用) |
スケジュールジョブスクリプト
スケジュールジョブで使用するJavaScriptスクリプトの例です。 スケジュールジョブでは container と executor が利用可能です。 executor をジョブの execute() メソッドに渡すことで、ジョブの停止制御が有効になります。
注釈
スケジュールジョブスクリプトは、スクリプト全体が1つのスクリプトとして評価されます。 スクリプトエンジンはまず式としてのコンパイルを試み、失敗した場合に文(ステートメント)のブロックとして再解釈するため、複数行の文や let / const 宣言、制御構文、トップレベルの return 文を使用できます(詳細は「スクリプトの評価方法」を参照)。 以降の「Javaクラスの使用」「Fessコンポーネントへのアクセス」「エラーハンドリング」「デバッグとログ出力」の例も、この完全なスクリプトのコンテキストを前提としています。
クロールジョブの実行
条件付きクロール
複数のジョブを順番に実行
Javaクラスの使用
JavaScriptスクリプト内では、Sai(Nashorn)のJava相互運用の仕組みにより、Javaの標準ライブラリや Fess のクラスを直接利用できます。JavaScriptには import 文がないため、クラスは常に 完全修飾名(FQCN)で記述します。
日付・時刻
ファイル操作
HTTP通信
警告
外部リソースへのアクセスはパフォーマンスに影響するため、 必要最小限に抑えてください。
Fessコンポーネントへのアクセス
container を使用してFessのコンポーネントにアクセスできます。
システムヘルパー
設定値の取得
検索の実行
エラーハンドリング
JavaScriptには import 文がないため、Groovyのような配置制約はありません。 try-catch で例外を捕捉し、ジョブのエラーを制御できます。
デバッグとログ出力
ログ出力
デバッグ用の出力
変数の内容を手早く確認したい場合は、 JSON.stringify で文字列化してログに出力すると便利です。
Groovyからの移行
既存のGroovyスクリプトをJavaScriptに移植する際は、次の違いに注意してください。
算術演算の精度
JavaScriptの数値演算は常に倍精度浮動小数点数として扱われます。たとえば次の式は、 Groovyでは整数 34 を返しますが、JavaScriptでは浮動小数点数 34.0 を返します。
一方、Java相互運用で呼び出すメソッドの戻り値はJava側の型がそのまま維持されるため、 content.length() は引き続き整数を返します。
Groovy専用構文の書き換え
以下のGroovy専用構文は、JavaScriptでは書き換えが必要です。
| Groovy | JavaScript | 説明 |
|---|---|---|
1000L | 1000 | long型リテラルの L サフィックスは不要(数値リテラルをそのまま記述) |
["a", "b"] as String[] | ["a", "b"] | JavaScriptの配列は String[] を引数に取るメソッドに渡すと自動的にJavaの配列に変換されるため、キャストは不要 |
Java相互運用
Java相互運用の記法自体はNashornに準じており、Groovyとほぼ変わりません。 new java.io.File(...) 、 java.lang.System.getProperty(...) 、 new org.codelibs.fess.job.IndexExportJob() のような完全修飾コンストラクタ呼び出しは そのまま解決されます。
ES6構文
Fess のJavaScriptエンジンはECMAScript 6として動作するため、 let / const 、 アロー関数、テンプレートリテラル、分割代入、 for...of 、 class などのES6構文を 利用できます。ただし、オプショナルチェイニング( ?. )やNull合体演算子( ?? )は ES2020以降の構文のため使用できません。
ベストプラクティス
シンプルに保つ: 複雑なロジックは避け、読みやすいコードを心がける
デフォルト値: Elvis演算子の代わりに論理OR演算子(
||)を活用する例外処理: 適切なtry-catchで予期しないエラーに対応
ログ出力: デバッグしやすいようにログを出力
パフォーマンス: 外部リソースアクセスを最小化
数値演算: 整数を期待する箇所では、Java相互運用のメソッド呼び出し結果をそのまま利用するか、必要に応じて明示的に変換する
参考情報
スクリプティング概要 - スクリプティング概要
Groovyスクリプトガイド - Groovyスクリプトガイド(プラグイン)
データストアクロール - データストア設定ガイド
スケジューラ - スケジューラー設定ガイド