Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8396488
Script: Add Metadata to ingest context.
stu-elastic Jun 1, 2022
7393951
Update docs/changelog/87309.yaml
stu-elastic Jun 1, 2022
a9d6267
spotless
stu-elastic Jun 1, 2022
e078901
Merge branch 'pain_wfield-ingest-doc-meta' of github.com:stu-elastic/…
stu-elastic Jun 1, 2022
60a0c96
Merge branch 'master' of github.com:elastic/elasticsearch into pain_w…
stu-elastic Jun 2, 2022
f02f66a
use primitive long for version
stu-elastic Jun 6, 2022
502aac2
Merge branch 'master' of github.com:elastic/elasticsearch into pain_w…
stu-elastic Jun 6, 2022
e352d3d
meta() -> metadata(), add some javadocs
stu-elastic Jun 9, 2022
699731e
Merge branch 'master' of github.com:elastic/elasticsearch into pain_w…
stu-elastic Jun 9, 2022
41273d0
Remove chaining, remove map size constructor
stu-elastic Jun 9, 2022
ae37ff6
rm unused import
stu-elastic Jun 9, 2022
ceae2d3
spotless
stu-elastic Jun 9, 2022
43e4b56
remove meta.txt, change Metadata.versionType to a string
stu-elastic Jun 13, 2022
64539fc
Update yamlRestTest with string versionType
stu-elastic Jun 13, 2022
0991e62
Merge branch 'master' of github.com:elastic/elasticsearch into pain_w…
stu-elastic Jun 13, 2022
ab51551
rm removeVersion and hasVersion
stu-elastic Jun 13, 2022
cda471d
Merge branch 'master' of github.com:elastic/elasticsearch into pain_w…
stu-elastic Jun 14, 2022
aa5eb57
Merge branch 'master' of github.com:stu-elastic/elasticsearch into pa…
stu-elastic Jun 28, 2022
8c308c5
Move test and use IngestSourceAndMetadata as Metadata
stu-elastic Jun 28, 2022
5b053da
Merge branch 'master' of github.com:stu-elastic/elasticsearch into pa…
stu-elastic Jun 28, 2022
45cfa2b
Better javadoc on Metadata.java
stu-elastic Jun 28, 2022
942b45d
Metadata doesn't extend Map, pass ctx and Metadata separately
stu-elastic Jun 29, 2022
a71a601
Merge branch 'master' of github.com:stu-elastic/elasticsearch into pa…
stu-elastic Jun 29, 2022
8bf32c3
Use getMetadataMap in DotExpanderProcessorTests
stu-elastic Jun 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/87309.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 87309
summary: "Script: Add Metadata to ingest context"
area: Infra/Scripting
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,26 @@ public final class ScriptProcessor extends AbstractProcessor {

private final Script script;
private final ScriptService scriptService;
private final IngestScript precompiledIngestScript;
private final IngestScript.Factory precompiledIngestScriptFactory;

/**
* Processor that evaluates a script with an ingest document in its context
* @param tag The processor's tag.
* @param description The processor's description.
* @param script The {@link Script} to execute.
* @param precompiledIngestScript The {@link Script} precompiled
* @param precompiledIngestScriptFactory The {@link Script} precompiled script
* @param scriptService The {@link ScriptService} used to execute the script.
*/
ScriptProcessor(
String tag,
String description,
Script script,
@Nullable IngestScript precompiledIngestScript,
@Nullable IngestScript.Factory precompiledIngestScriptFactory,
ScriptService scriptService
) {
super(tag, description);
this.script = script;
this.precompiledIngestScript = precompiledIngestScript;
this.precompiledIngestScriptFactory = precompiledIngestScriptFactory;
this.scriptService = scriptService;
}

Expand All @@ -71,14 +71,11 @@ public final class ScriptProcessor extends AbstractProcessor {
@Override
public IngestDocument execute(IngestDocument document) {
document.doNoSelfReferencesCheck(true);
final IngestScript ingestScript;
if (precompiledIngestScript == null) {
IngestScript.Factory factory = scriptService.compile(script, IngestScript.CONTEXT);
ingestScript = factory.newInstance(script.getParams());
} else {
ingestScript = precompiledIngestScript;
IngestScript.Factory factory = precompiledIngestScriptFactory;
if (factory == null) {
factory = scriptService.compile(script, IngestScript.CONTEXT);
}
ingestScript.execute(document.getSourceAndMetadata());
factory.newInstance(script.getParams(), document.getMetadata(), document.getSourceAndMetadata()).execute();
return document;
}

Expand All @@ -91,8 +88,8 @@ Script getScript() {
return script;
}

IngestScript getPrecompiledIngestScript() {
return precompiledIngestScript;
IngestScript.Factory getPrecompiledIngestScriptFactory() {
return precompiledIngestScriptFactory;
}

public static final class Factory implements Processor.Factory {
Expand Down Expand Up @@ -120,16 +117,17 @@ public ScriptProcessor create(
Arrays.asList("id", "source", "inline", "lang", "params", "options").forEach(config::remove);

// verify script is able to be compiled before successfully creating processor.
IngestScript ingestScript = null;
IngestScript.Factory ingestScriptFactory = null;
try {
final IngestScript.Factory factory = scriptService.compile(script, IngestScript.CONTEXT);
if (ScriptType.INLINE.equals(script.getType())) {
ingestScript = factory.newInstance(script.getParams());
ingestScriptFactory = scriptService.compile(script, IngestScript.CONTEXT);
if (ScriptType.STORED.equals(script.getType())) {
// do not cache stored scripts lest they change and invalidate the cached value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a change in current behavior? It might be worth pulling this out into a separate PR, only so that it can be noted (perhaps as a bugfix) in the release notes, whereas if it goes in within this enhancement/addition to the fields API it would be hidden.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the current behavior, it's just the instance used to be cached. This change is due to a failed unit test when I switched to the compiled script rather than the instance.

ingestScriptFactory = null;
}
} catch (ScriptException e) {
throw newConfigurationException(TYPE, processorTag, null, e);
}
return new ScriptProcessor(processorTag, description, script, ingestScript, scriptService);
return new ScriptProcessor(processorTag, description, script, ingestScriptFactory, scriptService);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void testEscapeFields() throws Exception {
processor = new DotExpanderProcessor("_tag", null, null, "foo.bar");
processor.execute(document);
assertThat(document.getSource().size(), equalTo(1));
assertThat(document.getMetadata().size(), equalTo(1)); // the default version
assertThat(document.getMetadataMap().size(), equalTo(1)); // the default version
assertThat(document.getFieldValue("foo.bar", List.class).size(), equalTo(2));
assertThat(document.getFieldValue("foo.bar.0", String.class), equalTo("baz2"));
assertThat(document.getFieldValue("foo.bar.1", String.class), equalTo("baz1"));
Expand All @@ -60,7 +60,7 @@ public void testEscapeFields() throws Exception {
processor = new DotExpanderProcessor("_tag", null, null, "foo.bar");
processor.execute(document);
assertThat(document.getSource().size(), equalTo(1));
assertThat(document.getMetadata().size(), equalTo(1)); // the default version
assertThat(document.getMetadataMap().size(), equalTo(1)); // the default version
assertThat(document.getFieldValue("foo.bar", List.class).size(), equalTo(2));
assertThat(document.getFieldValue("foo.bar.0", Integer.class), equalTo(1));
assertThat(document.getFieldValue("foo.bar.1", String.class), equalTo("2"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.ingest.IngestDocument;
import org.elasticsearch.ingest.TestIngestDocument;
import org.elasticsearch.script.IngestScript;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.Script;
Expand Down Expand Up @@ -155,9 +157,10 @@ public void testInlineIsCompiled() throws Exception {
assertThat(processor.getScript().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG));
assertThat(processor.getScript().getType(), equalTo(ScriptType.INLINE));
assertThat(processor.getScript().getParams(), equalTo(Collections.emptyMap()));
assertNotNull(processor.getPrecompiledIngestScript());
Map<String, Object> ctx = new HashMap<>();
processor.getPrecompiledIngestScript().execute(ctx);
assertNotNull(processor.getPrecompiledIngestScriptFactory());
IngestDocument doc = TestIngestDocument.emptyIngestDocument();
Map<String, Object> ctx = TestIngestDocument.emptyIngestDocument().getIngestSourceAndMetadata();
processor.getPrecompiledIngestScriptFactory().newInstance(null, doc.getMetadata(), ctx).execute();
assertThat(ctx.get("foo"), equalTo("bar"));
}

Expand All @@ -171,6 +174,6 @@ public void testStoredIsNotCompiled() throws Exception {
assertNull(processor.getScript().getLang());
assertThat(processor.getScript().getType(), equalTo(ScriptType.STORED));
assertThat(processor.getScript().getParams(), equalTo(Collections.emptyMap()));
assertNull(processor.getPrecompiledIngestScript());
assertNull(processor.getPrecompiledIngestScriptFactory());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ScriptProcessorTests extends ESTestCase {

private ScriptService scriptService;
private Script script;
private IngestScript ingestScript;
private IngestScript.Factory ingestScriptFactory;

@Before
public void setupScripting() {
Expand All @@ -53,7 +53,7 @@ public void setupScripting() {
() -> 1L
);
script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptName, Collections.emptyMap());
ingestScript = scriptService.compile(script, IngestScript.CONTEXT).newInstance(script.getParams());
ingestScriptFactory = scriptService.compile(script, IngestScript.CONTEXT);
}

public void testScriptingWithoutPrecompiledScriptFactory() throws Exception {
Expand All @@ -64,7 +64,7 @@ public void testScriptingWithoutPrecompiledScriptFactory() throws Exception {
}

public void testScriptingWithPrecompiledIngestScript() {
ScriptProcessor processor = new ScriptProcessor(randomAlphaOfLength(10), null, script, ingestScript, scriptService);
ScriptProcessor processor = new ScriptProcessor(randomAlphaOfLength(10), null, script, ingestScriptFactory, scriptService);
IngestDocument ingestDocument = randomDocument();
processor.execute(ingestDocument);
assertIngestDocument(ingestDocument);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,45 @@ teardown:
}
}
- match: { error.root_cause.0.reason: "Failed to generate the source document for ingest pipeline [my_pipeline]" }

---
"Test metadata":
- do:
ingest.put_pipeline:
id: "my_pipeline"
body: >
{
"description": "metadata",
"processors": [
{
"script" : {
"lang": "painless",
"source" : "Metadata m = metadata(); m.index += '2'; m.id += 'extra'; m.routing = 'myRouting'; m.versionType = 'external'; m.version = 5"
}
}
]
}
- match: { acknowledged: true }

- do:
index:
index: test2
id: "1extra"
version: 4
version_type: "external"
body: {source_field: "foobar"}

- do:
index:
index: test
id: "1"
pipeline: "my_pipeline"
body: {source_field: "bazqux"}

- do:
get:
index: test2
id: "1extra"
- match: { _source.source_field: "bazqux" }
- match: { _version: 5 }
- match: { _routing: "myRouting" }
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,26 @@ class org.elasticsearch.painless.api.Json {
String dump(def)
String dump(def, boolean)
}

class org.elasticsearch.script.Metadata {
String getIndex()
void setIndex(String)

String getId()
void setId(String)

String getRouting()
void setRouting(String)

long getVersion()
void setVersion(long)

String getVersionType()
void setVersionType(String)

ZonedDateTime getTimestamp()
}

class org.elasticsearch.script.IngestScript {
Metadata metadata()
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public void testSimulate() throws Exception {
source.put("processed", true);
IngestDocument ingestDocument = new IngestDocument("index", "id", Versions.MATCH_ANY, null, null, source);
assertThat(simulateDocumentBaseResult.getIngestDocument().getSource(), equalTo(ingestDocument.getSource()));
assertThat(simulateDocumentBaseResult.getIngestDocument().getMetadata(), equalTo(ingestDocument.getMetadata()));
assertThat(simulateDocumentBaseResult.getIngestDocument().getMetadataMap(), equalTo(ingestDocument.getMetadataMap()));
assertThat(simulateDocumentBaseResult.getFailure(), nullValue());

// cleanup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ final class WriteableIngestDocument implements Writeable, ToXContentFragment {
"ingest_document",
true,
a -> {
Map<String, Object> sourceAndMetadata = Maps.newHashMapWithExpectedSize(5);
Map<String, Object> source = (Map<String, Object>) a[5];
Map<String, Object> sourceAndMetadata = Maps.newHashMapWithExpectedSize(5 + source.size());
sourceAndMetadata.putAll(source);
sourceAndMetadata.put(Metadata.INDEX.getFieldName(), a[0]);
sourceAndMetadata.put(Metadata.ID.getFieldName(), a[1]);
if (a[2] != null) {
Expand All @@ -54,7 +56,6 @@ final class WriteableIngestDocument implements Writeable, ToXContentFragment {
if (a[4] != null) {
sourceAndMetadata.put(Metadata.VERSION_TYPE.getFieldName(), a[4]);
}
sourceAndMetadata.putAll((Map<String, Object>) a[5]);
Map<String, Object> ingestMetadata = (Map<String, Object>) a[6];
return new WriteableIngestDocument(new IngestDocument(sourceAndMetadata, ingestMetadata));
}
Expand Down Expand Up @@ -106,7 +107,7 @@ IngestDocument getIngestDocument() {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(DOC_FIELD);
Map<String, Object> metadataMap = ingestDocument.getMetadata();
Map<String, Object> metadataMap = ingestDocument.getMetadataMap();
for (Map.Entry<String, Object> metadata : metadataMap.entrySet()) {
if (metadata.getValue() != null) {
builder.field(metadata.getKey(), metadata.getValue().toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,17 +733,24 @@ public Map<String, Object> getSourceAndMetadata() {
/**
* Get source and metadata map as {@link IngestSourceAndMetadata}
*/
IngestSourceAndMetadata getIngestSourceAndMetadata() {
public IngestSourceAndMetadata getIngestSourceAndMetadata() {
return sourceAndMetadata;
}

/**
* Get all Metadata values in a Map
*/
public Map<String, Object> getMetadata() {
public Map<String, Object> getMetadataMap() {
return sourceAndMetadata.getMetadata();
}

/**
* Get the strongly typed metadata
*/
public org.elasticsearch.script.Metadata getMetadata() {
return sourceAndMetadata;
}

/**
* Get all source values in a Map
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.elasticsearch.common.util.Maps;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.Metadata;

import java.time.ZonedDateTime;
import java.util.AbstractCollection;
Expand Down Expand Up @@ -40,7 +41,7 @@
*
* The map is expected to be used by processors, server code should the typed getter and setters where possible.
*/
class IngestSourceAndMetadata extends AbstractMap<String, Object> {
class IngestSourceAndMetadata extends AbstractMap<String, Object> implements Metadata {
protected final ZonedDateTime timestamp;

/**
Expand Down
26 changes: 22 additions & 4 deletions server/src/main/java/org/elasticsearch/script/IngestScript.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
public abstract class IngestScript {

public static final String[] PARAMETERS = { "ctx" };
public static final String[] PARAMETERS = {};

/** The context used to compile {@link IngestScript} factories. */
public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>(
Expand All @@ -33,18 +33,36 @@ public abstract class IngestScript {
/** The generic runtime parameters for the script. */
private final Map<String, Object> params;

public IngestScript(Map<String, Object> params) {
/** The metadata available to the script */
private final Metadata metadata;

/** The metadata and source available to the script */
private final Map<String, Object> ctx;

public IngestScript(Map<String, Object> params, Metadata metadata, Map<String, Object> ctx) {
this.params = params;
this.metadata = metadata;
this.ctx = ctx;
}

/** Return the parameters for this script. */
public Map<String, Object> getParams() {
return params;
}

public abstract void execute(Map<String, Object> ctx);
/** Provides backwards compatibility access to ctx */
public Map<String, Object> getCtx() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some javadocs would be nice on the new methods here, eg explaing this method provides backcompat for ctx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

return ctx;
}

/** Return the ingest metadata object */
public Metadata metadata() {
return metadata;
}

public abstract void execute();

public interface Factory {
IngestScript newInstance(Map<String, Object> params);
IngestScript newInstance(Map<String, Object> params, Metadata metadata, Map<String, Object> ctx);
}
}
Loading