-
Notifications
You must be signed in to change notification settings - Fork 25.5k
Adds example plugin for custom ingest processor #112282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
7cdde5f
2d59eac
2bffcc5
3b72cad
82d7e81
16d4bec
e24084e
7ace7c6
c4d019e
2a6e9ac
f701626
727790f
52a4581
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pr: 112282 | ||
summary: Adds example plugin for custom ingest processor | ||
area: Ingest Node | ||
type: enhancement | ||
issues: | ||
- 111539 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
apply plugin: 'elasticsearch.esplugin' | ||
apply plugin: 'elasticsearch.yaml-rest-test' | ||
|
||
esplugin { | ||
name 'custom-processor' | ||
description 'An example plugin showing how to register a custom ingest processor' | ||
classname 'org.elasticsearch.example.customprocessor.ExampleProcessorPlugin' | ||
licenseFile rootProject.file('SSPL-1.0+ELASTIC-LICENSE-2.0.txt') | ||
noticeFile rootProject.file('NOTICE.txt') | ||
} | ||
|
||
dependencies { | ||
yamlRestTestRuntimeOnly "org.apache.logging.log4j:log4j-core:${log4jVersion}" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
package org.elasticsearch.example.customprocessor; | ||
|
||
import org.elasticsearch.ingest.Processor; | ||
import org.elasticsearch.plugins.IngestPlugin; | ||
import org.elasticsearch.plugins.Plugin; | ||
|
||
import java.util.Map; | ||
|
||
import static java.util.Map.entry; | ||
|
||
public class ExampleProcessorPlugin extends Plugin implements IngestPlugin { | ||
|
||
@Override | ||
public Map<String, Processor.Factory> getProcessors(Processor.Parameters parameters) { | ||
return Map.of( | ||
ExampleRepeatProcessor.TYPE, new ExampleRepeatProcessor.Factory() | ||
); | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.elasticsearch.example.customprocessor; | ||
|
||
import org.elasticsearch.ingest.AbstractProcessor; | ||
import org.elasticsearch.ingest.IngestDocument; | ||
import org.elasticsearch.ingest.Processor; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Example of adding an ingest processor with a plugin. | ||
*/ | ||
public class ExampleRepeatProcessor extends AbstractProcessor { | ||
public static final String TYPE = "repeat"; | ||
public static final String FILED_TO_REPEAT = "to_repeat"; | ||
|
||
ExampleRepeatProcessor(String tag, String description) { | ||
super(tag, description); | ||
} | ||
|
||
@Override | ||
public IngestDocument execute(IngestDocument document) { | ||
Object val = document.getFieldValue(FILED_TO_REPEAT, Object.class, true); | ||
|
||
if (val instanceof String string) { | ||
String repeated = string.concat(string); | ||
document.setFieldValue(FILED_TO_REPEAT, repeated); | ||
} | ||
return document; | ||
} | ||
|
||
@Override | ||
public String getType() { | ||
return TYPE; | ||
} | ||
|
||
public static class Factory implements Processor.Factory { | ||
|
||
@Override | ||
public ExampleRepeatProcessor create( | ||
Map<String, Processor.Factory> registry, | ||
String tag, | ||
String description, | ||
Map<String, Object> config | ||
) { | ||
return new ExampleRepeatProcessor(tag, description); | ||
|
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
package org.elasticsearch.example.customprocessor; | ||
|
||
import com.carrotsearch.randomizedtesting.annotations.Name; | ||
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; | ||
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; | ||
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase; | ||
|
||
/** | ||
* {@link ExampleProcessorClientYamlTestSuiteIT} executes the plugin's REST API integration tests. | ||
* <p> | ||
* The tests can be executed using the command: ./gradlew :example-plugins:processor:yamlRestTest | ||
|
||
* <p> | ||
* This class extends {@link ESClientYamlSuiteTestCase}, which takes care of parsing the YAML files | ||
* located in the src/yamlRestTest/resources/rest-api-spec/test/ directory and validates them against the | ||
* custom REST API definition files located in src/yamlRestTest/resources/rest-api-spec/api/. | ||
* <p> | ||
* Once validated, {@link ESClientYamlSuiteTestCase} executes the REST tests against a single node | ||
* integration cluster which has the plugin already installed by the Gradle build script. | ||
* </p> | ||
*/ | ||
public class ExampleProcessorClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase { | ||
|
||
public ExampleProcessorClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) { | ||
super(testCandidate); | ||
} | ||
|
||
@ParametersFactory | ||
public static Iterable<Object[]> parameters() throws Exception { | ||
// The test executes all the test candidates by default | ||
// see ESClientYamlSuiteTestCase.REST_TESTS_SUITE | ||
return ESClientYamlSuiteTestCase.createParameters(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
"Custom processor is present": | ||
- do: | ||
ingest.put_pipeline: | ||
id: pipeline1 | ||
body: > | ||
{ | ||
"processors": [ | ||
{ | ||
"repeat" : {} | ||
} | ||
] | ||
} | ||
- match: { acknowledged: true } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
"Process document": | ||
# create ingest pipeline with custom processor | ||
- do: | ||
ingest.put_pipeline: | ||
id: pipeline1 | ||
body: > | ||
{ | ||
"processors": [ | ||
{ | ||
"repeat" : {} | ||
} | ||
] | ||
} | ||
- match: { acknowledged: true } | ||
|
||
# index a document with field to be processed | ||
- do: | ||
index: | ||
id: doc1 | ||
index: index1 | ||
pipeline: pipeline1 | ||
body: { to_repeat: "foo" } | ||
- match: { result: "created" } | ||
|
||
# validate document is processed | ||
- do: | ||
get: | ||
index: index1 | ||
id: doc1 | ||
- match: { _source: { to_repeat: "foofoo" } } | ||
--- | ||
"Does not process document without field": | ||
# create ingest pipeline with custom processor | ||
- do: | ||
ingest.put_pipeline: | ||
|
||
id: pipeline1 | ||
body: > | ||
{ | ||
"processors": [ | ||
{ | ||
"repeat" : {} | ||
} | ||
] | ||
} | ||
- match: { acknowledged: true } | ||
|
||
# index a document without field to be processed | ||
- do: | ||
index: | ||
id: doc1 | ||
index: index1 | ||
pipeline: pipeline1 | ||
body: { field1: "foo" } | ||
- match: { result: "created" } | ||
|
||
# validate document is not processed | ||
- do: | ||
get: | ||
index: index1 | ||
id: doc1 | ||
- match: { _source: { field1: "foo" } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
FILED_TO_REPEAT
still needs changed toFIELD_TO_REPEAT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I missed this