Aviator は、Dianping(大众点评)が公開したJava式計算エンジンです。このエンジンは、文字列形式の式(例:`"a + b > 10 ? 'pass' : 'fail'"`)を実行時に動的に解析し、評価します。Aviator は、ルールエンジン、リスク管理、動的ロジック、レポート計算などさまざまな場面で活用されています。
QLExpress と似ていますが、Aviator は設計がシンプルで、特に数値計算において優れた性能を発揮します。また、関数プログラミングスタイルに対応しています。
1. 基本仕組み
Aviator は以下の3つのフェーズを経て式を評価します。
[文字列表式]
↓ (トークン解析)
[Tokens:変数、演算子、数値、括弧...]
↓ (構文解析 + 編作文字列)
[AviatorFunction(内部表現)]
↓ (実行 / JIT 最適化)
[評価結果]
- **コンパイルフェーズ**:式を `AviatorFunction` オブジェクトにコンパイル(キャッシュ可能)
- **実行フェーズ**:変数コンテキスト(Map)を渡して `execute()` を呼び出し、結果を得る
- **反射なし**:予め定義された演算子や関数を用いるため、実行時の反射コストを抑えます
**Aviator の特徴**:
- 式を一度だけコンパイルし、複数回実行しても効率が良い
- **型推論**:int/long/double 等の数値型を自動的に処理
- **安全な評価**:デフォルトではJavaメソッドへのアクセスを制限
| 特徴 | 説明 |
| **高性能** | 単一式のQPSは50万以上(Groovy/JSR223を大幅に上回る) |
| **軽量** | JARサイズは約300KB、外部依存なし |
| **多様な文法** | 算術、論理、三項演算、正規表現、コレクション操作をサポート |
| **カスタム関数** | Java Lambdaまたはメソッドを関数として登録可能 |
| **安全な制御** | デフォルトで反射を禁止、ホワイトリスト関数のみ許可 |
| **組み込み関数ライブラリ** | `string`, `math`, `regex`, `date` 等の便利な関数を提供 |
2. 初心者向け例
2.1 Maven 依存関係の追加
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>5.4.1</version> <!-- 最新バージョン推奨 -->
</dependency>
GitHubリポジトリ:https://github.com/killme2008/aviator
2.2 基本的な式計算
import com.googlecode.aviator.AviatorEvaluator;
public class BasicExample {
public static void main(String[] args) {
// 即時評価(生産環境では使用しない)
Object result = AviatorEvaluator.execute("1 + 2 * 3");
System.out.println(result); // 7
// コンパイルして再利用(推奨!)
Expression exp = AviatorEvaluator.compile("a + b * 2");
Map<String, Object> env = new HashMap<>();
env.put("a", 10);
env.put("b", 20);
Object res = exp.execute(env);
System.out.println(res); // 50
}
}
**注意**:生産環境では `compile()` + `execute(env)` を使用してください。
2.3 条件判断と三項演算
Expression exp = AviatorEvaluator.compile("score >= 90 ? '優秀' : (score >= 60 ? '合格' : '不合格')");
Map<String, Object> env = Map.of("score", 85);
System.out.println(exp.execute(env)); // 合格
2.4 カスタム関数の登録(重要な機能)
方式1:Lambda を使って関数登録(推奨)
// max(a, b) 関数の登録
AviatorEvaluator.addFunction(new AbstractFunction() {
@Override
public String getName() { return "max"; }
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Number a = FunctionUtils.getNumberValue(arg1, env);
Number b = FunctionUtils.getNumberValue(arg2, env);
return AviatorNumber.valueOf(Math.max(a.doubleValue(), b.doubleValue()));
}
});
// 使用例
Expression exp = AviatorEvaluator.compile("max(x, y)");
Map<String, Object> env = Map.of("x", 10, "y", 20);
System.out.println(exp.execute(env)); // 20.0
方式2:静态メソッドの登録(Aviator 5.0+)
// ツールクラスの定義
public class MathUtils {
@AviatorFunction("str_len") // 関数名
public static long strLen(String s) {
return s == null ? 0 : s.length();
}
}
// 関数の自動スキャン(有効にする必要があります)
AviatorEvaluator.setOption(Options.FUNCTION_SCAN_PACKAGE, "com.yourpkg");
AviatorEvaluator.loadFunctions(); // @AviatorFunction を持つクラスをスキャン
// 使用例
System.out.println(AviatorEvaluator.execute("str_len('hello')")); // 5
2.5 複雑なオブジェクト(POJO)の操作
public class User {
private String name;
private int age;
// getter メソッドはpublicにする必要があります!
public String getName() { return name; }
public int getAge() { return age; }
}
// 使用例
User user = new User();
user.name = "Alice";
user.age = 25;
Map<String, Object> env = Map.of("user", user);
Object res = AviatorEvaluator.execute("user.age > 18 && user.name == 'Alice'", env);
System.out.println(res); // true
Aviator はgetter メソッドを通じてオブジェクトのプロパティにアクセスします(例:`user.age` → `user.getAge()`)
3. 高度な使い方
3.1 組み込み関数ライブラリ(登録不要)
// 文字列操作
AviatorEvaluator.execute("string.contains('hello', 'll')"); // true
AviatorEvaluator.execute("string.length('world')"); // 5
// 数学関数
AviatorEvaluator.execute("math.sqrt(16)"); // 4.0
AviatorEvaluator.execute("math.round(3.7)"); // 4
// 正規表現
AviatorEvaluator.execute("'abc123' =~ /\\d+/"); // true
// コレクション操作
AviatorEvaluator.execute("count([1,2,3])"); // 3
AviatorEvaluator.execute("include([1,2,3], 2)"); // true
全ての組み込み関数のリスト:https://github.com/killme2008/aviator#built-in-functions
3.2 コレクションと配列操作
List<Integer> scores = Arrays.asList(85, 90, 78);
Map<String, Object> env = Map.of("scores", scores);
// 平均点の計算
Object avg = AviatorEvaluator.execute("reduce(scores, 0, (acc, x) -> acc + x) / count(scores)", env);
System.out.println(avg); // 84.333...
// 高得点のフィルタリング
Object highScores = AviatorEvaluator.execute("filter(scores, x -> x > 80)", env);
System.out.println(highScores); // [85, 90]
Aviator 5.0+ ではLambda式をサポートしています。
3.3 性能チューニング:式のキャッシュ
// グローバルキャッシュ(デフォルト有効) AviatorEvaluator.setOption(Options.EXPRESSION_CACHE_SIZE, 1000); // 手動キャッシュ Map<String, Expression> cache = new ConcurrentHashMap<>(); String exprStr = "a + b"; Expression exp = cache.computeIfAbsent(exprStr, AviatorEvaluator::compile); exp.execute(env);
3.4 安全性制御
// 危険な操作を無効化(デフォルトでは無効) AviatorEvaluator.setOption(Options.ALLOW_ACCESS_STATIC_FIELD, false); AviatorEvaluator.setOption(Options.ALLOW_CLASS_LOADER, false); // ホワイトリスト関数のみ許可(addFunction を使って管理)
4. 代表的な使用例
| シナリオ | 式例 |
| **リスク管理** | `"user.riskLevel == 'HIGH' && order.amount > 10000"` |
| **動的価格設定** | `"basePrice * (1 + discountRate) - couponValue"` |
| **ゲームスキル計算** | `"player.hp -= enemy.attack * 1.5"` |
| **データフィルタリング** | `"include(user.tags, 'VIP') && user.balance > 100"` |
| **しきい値設定** | `"metric.value > config.threshold"` |
5. QLExpress との比較
| 特徴 | Aviator | QLExpress |
| **性能** | ⭐⭐⭐⭐⭐(数値計算が速い) | ⭐⭐⭐⭐ |
| **文法の簡潔性** | 数学式に近い | if/for 等の制御文をサポート |
| **関数登録** | Lambda / アノテーション | 反射を用いた登録 |
| **学習曲線** | 平緩 | やや急 |
| **コミュニティ活性度** | 中程度 | Aliyun 言語、活発 |
| **適切な使用例** | 頻繁な計算、シンプルなルール | 複雑なスクリプトロジック |
**選択の参考**:
- 純粋な式計算(式、条件判断)→ **Aviator**
- if/for/while 等の制御文が必要 → **QLExpress**
6. 最佳プラクティス
- **式をコンパイルするようにする**:`compile()` を使う代わりに `execute(String)` を使わない
- **Expression オブジェクトをキャッシュする**:再コンパイルを避ける
- **組み込み関数を優先する**:`math.sqrt()` を使う代わりにカスタム関数を作らない
- **POJO に getter メソッドを定義する**:プロパティにアクセス可能にする
- **例外処理を行う**:`ExpressionRuntimeException` をキャッチする
try {
exp.execute(env);
} catch (ExpressionRuntimeException e) {
log.error("式評価エラー: {}", e.getMessage());
}
7. 完整な例:リアルタイムリスク管理
public class RiskEngine {
private final Map<String, Expression> ruleCache = new ConcurrentHashMap<>();
public boolean evaluate(String rule, Map<String, Object> context) {
Expression exp = ruleCache.computeIfAbsent(rule, AviatorEvaluator::compile);
try {
Object result = exp.execute(context);
return Boolean.TRUE.equals(result);
} catch (Exception e) {
log.warn("ルール評価失敗: {}", rule, e);
return false; // 安全性のためにfalseを返す
}
}
}
// 使用例
RiskEngine engine = new RiskEngine();
Map<String, Object> ctx = Map.of(
"ip", "192.168.1.100",
"amount", 15000,
"isVip", true
);
boolean blocked = engine.evaluate("amount > 10000 || !isVip", ctx);
8. 結論
Aviator は高性能、安全、シンプルな文法を備えたJava式エンジンです。特に頻繁に呼ばれるルール計算に適しています。適切なコンパイルキャッシュ、組み込み関数、カスタム関数の利用により、業務ロジックを柔軟に動的に管理できます。
**公式ドキュメント**:https://github.com/killme2008/aviator