Overview
Groovy is the default scripting language for Fess. It runs on the Java Virtual Machine (JVM) and, while maintaining high compatibility with Java, allows you to write scripts with a more concise syntax.
Basic Syntax
Variable Declaration
// Type inference (def)
def name = "Fess"
def count = 100
// Explicit type specification
String title = "Document Title"
int pageNum = 1
String Operations
// String interpolation (GString)
def id = 123
def url = "https://example.com/doc/${id}"
// Multi-line strings
def content = """
This is a
multi-line string
"""
// Replacement
title.replace("old", "new")
title.replaceAll(/\s+/, " ") // Regular expression
// Split and join
def tags = "tag1,tag2,tag3".split(",")
def joined = tags.join(", ")
// Case conversion
title.toUpperCase()
title.toLowerCase()
Collection Operations
// Lists
def list = [1, 2, 3, 4, 5]
list.each { println it }
def doubled = list.collect { it * 2 }
def filtered = list.findAll { it > 3 }
// Maps
def map = [name: "Fess", version: "15.6"]
println map.name
println map["version"]
Conditional Branching
// if-else
if (data.status == "active") {
return "Active"
} else {
return "Inactive"
}
// Ternary operator
def result = data.count > 0 ? "Present" : "None"
// Elvis operator (null coalescing operator)
def value = data.title ?: "Untitled"
// Safe navigation operator
def length = data.content?.length() ?: 0
Loop Processing
// for-each
for (item in items) {
println item
}
// Closure
items.each { item ->
println item
}
// Range
(1..10).each { println it }
Data Store Scripts
Examples of scripts for data store configuration.
Basic Mapping
url=data.url
title=data.title
content=data.content
lastModified=data.updated_at
URL Generation
// URL generation based on ID
url="https://example.com/article/" + data.id
// Combination of multiple fields
url="https://example.com/" + data.category + "/" + data.slug + ".html"
// Conditional URL
url=data.external_url ?: "https://example.com/default/" + data.id
Content Processing
// Remove HTML tags
content=data.html_content.replaceAll(/<[^>]+>/, "")
// Combine multiple fields
content=data.title + "\n" + data.description + "\n" + data.body
// Length limitation
content=data.content.length() > 10000 ? data.content.substring(0, 10000) : data.content
Date Processing
// Date parsing (single expression using FQCN)
lastModified=new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(data.date_string)
// Conversion from epoch seconds
lastModified=new Date(data.timestamp * 1000L)
Available Objects
The objects available in scripts vary depending on the execution context.
| Context | Object | Description |
|---|---|---|
| All contexts | container | DI container. Used to access components |
| Scheduled jobs | executor | Job execution control ( JobExecutor ). Required for job stop support |
| Data store | (connector-specific) | Data record variables provided by each data store |
Scheduled Job Scripts
Examples of Groovy scripts used in scheduled jobs. In scheduled jobs, container and executor are available. Passing executor to the job’s execute() method enables job stop control.
Execute Crawl Job
return container.getComponent("crawlJob").logLevel("info").gcLogging().execute(executor);
Conditional Crawling
import java.util.Calendar
def cal = Calendar.getInstance()
def hour = cal.get(Calendar.HOUR_OF_DAY)
// Crawl only outside business hours
if (hour < 9 || hour >= 18) {
return container.getComponent("crawlJob").logLevel("info").gcLogging().execute(executor)
}
return "Skipped during business hours"
Execute Multiple Jobs Sequentially
def results = []
// Index optimization
results << container.getComponent("suggestJob").logLevel("info").sessionId("SUGGEST").execute(executor)
// Execute crawl
results << container.getComponent("crawlJob").logLevel("info").gcLogging().execute(executor)
return results.join("\n")
Using Java Classes
Within Groovy scripts, you can use Java standard libraries and Fess classes.
Date and Time
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
def now = LocalDateTime.now()
def formatted = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
File Operations
import java.nio.file.Files
import java.nio.file.Paths
def content = new String(Files.readAllBytes(Paths.get("/path/to/file.txt")))
HTTP Communication
import java.net.URL
def url = new URL("https://api.example.com/data")
def response = url.text
Warning
Access to external resources affects performance, so keep it to a minimum.
Accessing Fess Components
You can access Fess components using container.
System Helper
def systemHelper = container.getComponent("systemHelper")
def currentTime = systemHelper.getCurrentTimeAsLong()
Getting Configuration Values
def fessConfig = container.getComponent("fessConfig")
def indexName = fessConfig.getIndexDocumentUpdateIndex()
Executing Searches
def searchHelper = container.getComponent("searchHelper")
// Set search parameters and execute search
Error Handling
try {
def result = processData(data)
return result
} catch (Exception e) {
import org.apache.logging.log4j.LogManager
def logger = LogManager.getLogger("script")
logger.error("Error processing data: {}", e.message, e)
return "Error: " + e.message
}
Debugging and Log Output
Log Output
import org.apache.logging.log4j.LogManager
def logger = LogManager.getLogger("script")
logger.debug("Debug message: {}", data.id)
logger.info("Processing document: {}", data.title)
logger.warn("Warning: {}", message)
logger.error("Error: {}", e.message)
Debug Output
// Console output (development only)
println "data.id = ${data.id}"
println "data.title = ${data.title}"
Best Practices
Keep it simple: Avoid complex logic and write readable code
Null checks: Utilize
?.and?:operatorsException handling: Handle unexpected errors with appropriate try-catch
Log output: Output logs for easier debugging
Performance: Minimize external resource access
Reference Information
Scripting Overview - Scripting Overview
Data Store Crawling - Data Store Configuration Guide
Scheduler - Scheduler Configuration Guide