Skip to content

Commit 42e67f9

Browse files
committed
more stuff
1 parent 05b98f8 commit 42e67f9

8 files changed

+362
-451
lines changed
251 KB
Loading

explore-analyze/scripting/common-script-uses.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ Painless scripting becomes powerful when applied to real-world scenarios. These
1616

1717
# Available tutorials
1818

19-
20-
* [Accessing fields in a document](/explore-analyze/scripting/script-fields-api.md)
2119
* [Accessing document fields and special variables](/explore-analyze/scripting/modules-scripting-fields.md)
20+
* [Accessing fields in a document](/explore-analyze/scripting/script-fields-api.md)
21+
* [Converting data types](/explore-analyze/scripting/modules-scripting-type-casting-tutorial.md)
2222
* [Dissecting data](/explore-analyze/scripting/dissect.md)
23+
* [Extracting fields](/explore-analyze/scripting/scripting-field-extraction.md)
2324
* [Grokking grok](/explore-analyze/scripting/grok.md)
2425
* [Scripts, caching, and search speed](/explore-analyze/scripting/scripts-search-speed.md)
25-
* [Extracting fields](/explore-analyze/scripting/scripting-field-extraction.md)
26-
* [Working with dates](/explore-analyze/scripting/modules-scripting-datetime-tutorial.md)
2726
* [Updating documents](/explore-analyze/scripting/modules-scripting-document-update-tutorial.md)
2827
* [Using Painless regular expressions](/explore-analyze/scripting/modules-scripting-regular-expressions-tutorial.md)
29-
* [Converting data types](/explore-analyze/scripting/modules-scripting-type-casting-tutorial.md)
28+
* [Working with dates](/explore-analyze/scripting/modules-scripting-datetime-tutorial.md)

explore-analyze/scripting/modules-scripting-engine.md

Lines changed: 50 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -10,165 +10,79 @@ products:
1010

1111
# Implementing custom scripting language in Elasticsearch [modules-scripting-engine]
1212

13-
A `ScriptEngine` is a backend for implementing a scripting language. It may also be used to write scripts that need to use advanced internals of scripting. For example, a script that wants to use term frequencies while scoring.
13+
A `ScriptEngine` is a backend for implementing a scripting language in {{es}}.
1414

15-
The plugin [documentation](elasticsearch://extend/index.md) has more information on how to write a plugin so that Elasticsearch will properly load it. To register the `ScriptEngine`, your plugin should implement the `ScriptPlugin` interface and override the `getScriptEngine(Settings settings)` method.
15+
## How it works
1616

17-
The following is an example of a custom `ScriptEngine` which uses the language name `expert_scripts`. It implements a single script called `pure_df` which may be used as a search script to override each document’s score as the document frequency of a provided term.
17+
Custom script engines integrate with {{es}} scripting framework through the `ScriptEngine` interface. To register the `ScriptEngine`, your plugin should implement the `ScriptPlugin` interface and override the `getScriptEngine(Settings settings)` method during plugin initialization.
18+
19+
## When to implement
20+
21+
Consider implementing a custom script engine when you need to use advanced internals of scripting, such as scripts that require term frequencies while scoring, or when implementing specialized scripting languages with custom syntax beyond standard Painless capabilities.
22+
23+
## Example implementation
24+
25+
The plugin [documentation](elasticsearch://extend/index.md) has more information on how to write a plugin so {{es}} will properly load it. For the complete ScriptEngine interface reference, refer to the [official implementation](https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/script/ScriptEngine.java).
26+
27+
### What this script does
28+
29+
This code creates a custom script engine that allows you to use `expert_scripts` as the language name and `pure_df` as the script source in your {{es}} queries. The script calculates document scores using term frequency data instead of {{es}} standard scoring algorithm.
30+
31+
The following example shows the essential parts of implementing a custom `ScriptEngine`:
1832

1933
```java
2034
private static class MyExpertScriptEngine implements ScriptEngine {
35+
36+
// 1. Define your custom language name
2137
@Override
2238
public String getType() {
23-
return "expert_scripts";
39+
return "expert_scripts"; // This becomes your "lang" value
2440
}
2541

42+
// 2. Define your script source and compilation
2643
@Override
27-
public <T> T compile(
28-
String scriptName,
29-
String scriptSource,
30-
ScriptContext<T> context,
31-
Map<String, String> params
32-
) {
33-
if (context.equals(ScoreScript.CONTEXT) == false) {
34-
throw new IllegalArgumentException(getType()
35-
+ " scripts cannot be used for context ["
36-
+ context.name + "]");
37-
}
38-
// we use the script "source" as the script identifier
44+
public <T> T compile(String scriptName, String scriptSource,
45+
ScriptContext<T> context, Map<String, String> params) {
46+
// This recognizes "pure_df" as your script source
3947
if ("pure_df".equals(scriptSource)) {
4048
ScoreScript.Factory factory = new PureDfFactory();
4149
return context.factoryClazz.cast(factory);
4250
}
43-
throw new IllegalArgumentException("Unknown script name "
44-
+ scriptSource);
45-
}
46-
47-
@Override
48-
public void close() {
49-
// optionally close resources
51+
throw new IllegalArgumentException("Unknown script: " + scriptSource);
5052
}
53+
54+
// ... (additional required methods)
55+
}
5156

57+
// 3. Where the actual score calculation happens
58+
private static class ScoreScriptImpl extends ScoreScript {
5259
@Override
53-
public Set<ScriptContext<?>> getSupportedContexts() {
54-
return Set.of(ScoreScript.CONTEXT);
55-
}
56-
57-
private static class PureDfFactory implements ScoreScript.Factory,
58-
ScriptFactory {
59-
@Override
60-
public boolean isResultDeterministic() {
61-
// PureDfLeafFactory only uses deterministic APIs, this
62-
// implies the results are cacheable.
63-
return true;
64-
}
65-
66-
@Override
67-
public LeafFactory newFactory(
68-
Map<String, Object> params,
69-
SearchLookup lookup
70-
) {
71-
return new PureDfLeafFactory(params, lookup);
60+
public double execute(ExplanationHolder explanation) {
61+
// This is where you define your custom scoring logic
62+
// In this example: return term frequency as the score
63+
try {
64+
return postings.freq(); // Custom score calculation
65+
} catch (IOException e) {
66+
return 0.0d;
7267
}
7368
}
69+
}
7470

75-
private static class PureDfLeafFactory implements LeafFactory {
76-
private final Map<String, Object> params;
77-
private final SearchLookup lookup;
78-
private final String field;
79-
private final String term;
80-
81-
private PureDfLeafFactory(
82-
Map<String, Object> params, SearchLookup lookup) {
83-
if (params.containsKey("field") == false) {
84-
throw new IllegalArgumentException(
85-
"Missing parameter [field]");
86-
}
87-
if (params.containsKey("term") == false) {
88-
throw new IllegalArgumentException(
89-
"Missing parameter [term]");
90-
}
91-
this.params = params;
92-
this.lookup = lookup;
93-
field = params.get("field").toString();
94-
term = params.get("term").toString();
95-
}
71+
```
9672

97-
@Override
98-
public boolean needs_score() {
99-
return false; // Return true if the script needs the score
100-
}
73+
### Key points
10174

102-
@Override
103-
public boolean needs_termStats() {
104-
return false; // Return true if the script needs term statistics via get_termStats()
105-
}
75+
* **Language Definition**: The `getType()` method returns `expert_scripts`, which becomes the value you use for the `lang` parameter in your scripts.
76+
* **Script Recognition:** The `compile()` method identifies `pure_df` as a valid script source, which becomes the value you use for the `source` parameter.
77+
* **Custom Scoring:** The `execute()` method replaces {{es}} standard scoring with your custom logic. In this case, using term frequency as the document score.
10678

107-
@Override
108-
public ScoreScript newInstance(DocReader docReader)
109-
throws IOException {
110-
DocValuesDocReader dvReader = DocValuesDocReader) docReader); PostingsEnum postings = dvReader.getLeafReaderContext() .reader().postings(new Term(field, term;
111-
if (postings == null) {
112-
/*
113-
* the field and/or term don't exist in this segment,
114-
* so always return 0
115-
*/
116-
return new ScoreScript(params, lookup, docReader) {
117-
@Override
118-
public double execute(
119-
ExplanationHolder explanation
120-
) {
121-
if(explanation != null) {
122-
explanation.set("An example optional custom description to explain details for this script's execution; we'll provide a default one if you leave this out.");
123-
}
124-
return 0.0d;
125-
}
126-
};
127-
}
128-
return new ScoreScript(params, lookup, docReader) {
129-
int currentDocid = -1;
130-
@Override
131-
public void setDocument(int docid) {
132-
/*
133-
* advance has undefined behavior calling with
134-
* a docid <= its current docid
135-
*/
136-
if (postings.docID() < docid) {
137-
try {
138-
postings.advance(docid);
139-
} catch (IOException e) {
140-
throw new UncheckedIOException(e);
141-
}
142-
}
143-
currentDocid = docid;
144-
}
145-
@Override
146-
public double execute(ExplanationHolder explanation) {
147-
if(explanation != null) {
148-
explanation.set("An example optional custom description to explain details for this script's execution; we'll provide a default one if you leave this out.");
149-
}
150-
if (postings.docID() != currentDocid) {
151-
/*
152-
* advance moved past the current doc, so this
153-
* doc has no occurrences of the term
154-
*/
155-
return 0.0d;
156-
}
157-
try {
158-
return postings.freq();
159-
} catch (IOException e) {
160-
throw new UncheckedIOException(e);
161-
}
162-
}
163-
};
164-
}
165-
}
166-
}
167-
```
79+
**For the complete implementation, refer to the [official script engine example](https://github.com/elastic/elasticsearch/blob/main/plugins/examples/script-expert-scoring/src/main/java/org/elasticsearch/example/expertscript/ExpertScriptPlugin.java).**
80+
81+
### Usage example
16882

169-
You can execute the script by specifying its `lang` as `expert_scripts`, and the name of the script as the script source:
83+
This example shows how to use your custom script engine in a search query:
17084

171-
```console
85+
```json
17286
POST /_search
17387
{
17488
"query": {
@@ -195,5 +109,7 @@ POST /_search
195109
}
196110
}
197111
}
112+
198113
```
199114

115+

explore-analyze/scripting/modules-scripting-painless.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ Painless provides three core benefits across all scripting contexts:
7272
## Where to write in Painless
7373

7474
:::{image} /explore-analyze/images/elasticsearch-painless-where-to-write.png
75-
:alt: A view of the Discover app
76-
:screenshot:
75+
:alt: A graphic showing six different options of where to write Painless scripts
7776
:::
7877

7978
You can use Painless in multiple contexts throughout {{es}}:

0 commit comments

Comments
 (0)