Introduction: The Evolution of Elasticsearch Scripting
Elasticsearch has long supported scripting to enable dynamic queries, custom scoring, and document transformations. But not all scripting languages are equal. Groovy was once the default choice, while Painless is now Elastic’s recommended language.
Why does this matter?
- Performance: Painless is 5-10x faster than Groovy.
- Security: Groovy had major vulnerabilities (remote code execution risks).
- Maintenance: Groovy is deprecated in newer Elasticsearch versions.
In this guide, we’ll compare:
Syntax differences (Groovy vs Painless examples)
Performance benchmarks
Security risks (and why Groovy was disabled by default)
When to use each (migration tips for legacy systems)
1. Groovy vs Painless: Key Differences
Feature | Painless | Groovy |
---|---|---|
Speed | ⚡ JIT-compiled (near-native Java speed) | Interpreted (slower) |
Security | 🔒 Strict sandbox (no RCE risks) | Risky (remote code execution flaws) |
Syntax | Java-like, simplified | Groovy-style (dynamic typing) |
Elasticsearch Support | ✅ Default in ES 5.0+ | ❌ Deprecated since ES 6.0 |
Use Cases | Scoring, ETL, aggregations | Legacy systems (pre-6.0) |
2. Performance Comparison: Painless is Faster
Benchmark Test: Computing a Weighted Score
// Groovy _score * (doc['price'].value / params.max_price) // Painless def normalizedPrice = doc['price'].value / params.max_price; return _score * normalizedPrice;
Results (100k docs):
- Painless: ~50ms
- Groovy: ~300ms
Why?
- Painless compiles to JVM bytecode (like Java).
- Groovy interprets scripts at runtime.
3. Security: Why Groovy Was Disabled
Groovy had critical vulnerabilities:
- Arbitrary code execution (malicious scripts could run
System.exit()
or delete files). - No sandboxing by default (required manual restrictions).
Example of a Dangerous Groovy Script:
// Could delete files or crash the node! new File("/critical/system_file").delete()
Painless fixes this with:
✔ No filesystem access
✔ No reflection
✔ Strict API whitelisting
4. Syntax Comparison (Side-by-Side Examples)
Example 1: Conditional Field Update
// Groovy if (ctx._source.price > 100) { ctx._source.discount = 0.1 }
// Painless if (ctx._source.price > 100) { ctx._source.discount = 0.1; }
Verdict: Almost identical—Painless is easier to migrate from Groovy.
Example 2: Looping Through an Array
// Groovy def names = ['Alice', 'Bob']; names.each { name -> println name.toUpperCase() }
// Painless def names = ['Alice', 'Bob']; for (name in names) { emit(name.toUpperCase()); }
Key Difference:
- Painless uses Java-style loops (
for
instead of Groovy’seach
).
5. When Should You Still Use Groovy?
Only if:
- You’re maintaining pre-6.0 Elasticsearch clusters.
- You have legacy scripts not yet migrated.
For everyone else: Painless is the future.
6. Migrating from Groovy to Painless
Step 1: Identify Groovy Scripts
GET _scripts/legacy_groovy_script
Step 2: Rewrite in Painless
// Old Groovy doc['price'].value * 0.9 // New Painless def discount = doc['price'].value * 0.9; return discount;
Step 3: Test Performance Gains
Use the Kibana Painless debugger to validate.
7. Painless Wins—Here’s Why
Factor | Painless | Groovy |
---|---|---|
Speed | ✅ Winner | ❌ Slower |
Security | ✅ Sandboxed | ❌ Risky |
Future-Proof | ✅ Supported | ❌ Deprecated |
Conclusion: Painless is the Clear Choice
- For new projects: Always use Painless.
- For legacy systems: Migrate Groovy scripts ASAP.
Need help? Try Elastic’s Scripting Migration Guide.
FAQs
Q: Is Groovy still supported in Elasticsearch 8.x?
A: No. Groovy was removed in Elasticsearch 6.0+.
Q: Can I run Painless and Groovy together?
A: Not in newer versions. Painless replaced Groovy entirely.
Q: Which is easier to learn, Painless or Groovy?
A: Painless (simpler syntax, better docs).