-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Adds a mapper for context aware segments grouping criteria #19233
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
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c542f06
Adds Context aware grouping mapper
shatejas f7ac779
Adds a test for ContextAwareGroupingScript
shatejas d5f920b
Adds ContextAwareGroupingScript support in mockScriptEngine to fix in…
shatejas 3be7f35
Corrects CHANGELOG.md
shatejas 5a9e26c
Fixes LangPainlessClientYamlTestSuiteIT
shatejas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
.../lang-painless/src/test/java/org/opensearch/painless/ContextAwareGroupingScriptTests.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * The OpenSearch Contributors require contributions made to | ||
| * this file be licensed under the Apache-2.0 license or a | ||
| * compatible open source license. | ||
| */ | ||
|
|
||
| package org.opensearch.painless; | ||
|
|
||
| import org.opensearch.common.settings.Settings; | ||
| import org.opensearch.painless.spi.Allowlist; | ||
| import org.opensearch.script.ContextAwareGroupingScript; | ||
| import org.opensearch.script.ScriptContext; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public class ContextAwareGroupingScriptTests extends ScriptTestCase { | ||
|
|
||
| private static PainlessScriptEngine SCRIPT_ENGINE; | ||
|
|
||
| @Override | ||
| public void setUp() throws Exception { | ||
| super.setUp(); | ||
|
|
||
| Map<ScriptContext<?>, List<Allowlist>> contexts = newDefaultContexts(); | ||
| List<Allowlist> allowlists = new ArrayList<>(Allowlist.BASE_ALLOWLISTS); | ||
| contexts.put(ContextAwareGroupingScript.CONTEXT, allowlists); | ||
|
|
||
| SCRIPT_ENGINE = new PainlessScriptEngine(Settings.EMPTY, contexts); | ||
| } | ||
|
|
||
| @Override | ||
| public void tearDown() throws Exception { | ||
| super.tearDown(); | ||
| SCRIPT_ENGINE = null; | ||
| } | ||
|
|
||
| @Override | ||
| protected PainlessScriptEngine getEngine() { | ||
| return SCRIPT_ENGINE; | ||
| } | ||
|
|
||
| public void testContextAwareGroupingScript() { | ||
| String stringConcat = "ctx.value + \"-context-aware\""; | ||
| ContextAwareGroupingScript script = compile(stringConcat); | ||
|
|
||
| assertEquals("value-context-aware", script.execute(Map.of("value", "value"))); | ||
|
|
||
| String integerAddition = "String.valueOf(ctx.value / 100)"; | ||
| ContextAwareGroupingScript integerAdditionScript = compile(integerAddition); | ||
| assertEquals("2", integerAdditionScript.execute(Map.of("value", 200))); | ||
| } | ||
|
|
||
| private ContextAwareGroupingScript compile(String expression) { | ||
| ContextAwareGroupingScript.Factory factory = getEngine().compile( | ||
| expression, | ||
| expression, | ||
| ContextAwareGroupingScript.CONTEXT, | ||
| Collections.emptyMap() | ||
| ); | ||
| return factory.newInstance(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
server/src/main/java/org/opensearch/index/mapper/ContextAwareGroupingFieldMapper.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| /* | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * The OpenSearch Contributors require contributions made to | ||
| * this file be licensed under the Apache-2.0 license or a | ||
| * compatible open source license. | ||
| */ | ||
|
|
||
| package org.opensearch.index.mapper; | ||
|
|
||
| import org.opensearch.script.ContextAwareGroupingScript; | ||
| import org.opensearch.script.Script; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.opensearch.script.Script.DEFAULT_SCRIPT_LANG; | ||
|
|
||
| /** | ||
| * A field mapper to specify context aware grouping mapper creation | ||
| * | ||
| * @opensearch.internal | ||
| */ | ||
| public class ContextAwareGroupingFieldMapper extends ParametrizedFieldMapper { | ||
|
|
||
| public static final String CONTENT_TYPE = "context_aware_grouping"; | ||
|
|
||
| public static final Mapper.TypeParser PARSER = new TypeParser(); | ||
|
|
||
| private static class TypeParser implements Mapper.TypeParser { | ||
|
|
||
| @Override | ||
| public Mapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext context) throws MapperParsingException { | ||
| throw new IllegalStateException("ContextAwareGroupingFieldMapper needs objbuilder to validate node"); | ||
| } | ||
|
|
||
| @Override | ||
| public Mapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext context, ObjectMapper.Builder objBuilder) | ||
| throws MapperParsingException { | ||
| Builder builder = new Builder(name); | ||
| builder.parse(name, context, node); | ||
|
|
||
| if (builder.fields.isConfigured() == false) { | ||
| throw new MapperParsingException("[fields] in context_aware_grouping is required"); | ||
| } | ||
|
|
||
| Set<String> propertyFieldNames = (Set<String>) objBuilder.mappersBuilders.stream() | ||
| .map(b -> ((Mapper.Builder) b).name()) | ||
| .collect(Collectors.toSet()); | ||
|
|
||
| if (propertyFieldNames.containsAll(builder.fields.getValue()) == false) { | ||
| throw new MapperParsingException( | ||
| "[fields] should be from properties: [" + propertyFieldNames + "] but found [" + builder.fields.getValue() + "]" | ||
| ); | ||
| } | ||
|
|
||
| final Script s = builder.script.getValue(); | ||
| if (s != null) { | ||
| ContextAwareGroupingScript.Factory factory = context.scriptService() | ||
| .compile(builder.script.get(), ContextAwareGroupingScript.CONTEXT); | ||
| builder.compiledScript = factory.newInstance(); | ||
| } | ||
| return builder; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Builder for this field mapper | ||
| * | ||
| * @opensearch.internal | ||
| */ | ||
| public static class Builder extends ParametrizedFieldMapper.Builder { | ||
|
|
||
| private static ContextAwareGroupingFieldMapper toType(FieldMapper in) { | ||
| return (ContextAwareGroupingFieldMapper) in; | ||
| } | ||
|
|
||
| private final Parameter<List<String>> fields = new Parameter<>("fields", true, Collections::emptyList, (n, c, o) -> { | ||
| if (!(o instanceof List)) { | ||
| throw new MapperParsingException("Expected [fields] to be a list of strings but got [" + o + "]"); | ||
| } | ||
|
|
||
| List<String> fields = (List<String>) o; | ||
| if (fields.isEmpty()) { | ||
| throw new MapperParsingException("Expected [fields] in context_aware_grouping to have one value"); | ||
| } | ||
|
|
||
| if (fields.size() > 1) { | ||
jed326 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| throw new MapperParsingException("Currently [fields] in context_aware_grouping does not support multiple values"); | ||
| } | ||
|
|
||
| return fields; | ||
| }, m -> toType(m).fields); | ||
|
|
||
| private final Parameter<Script> script = new Parameter<>("script", true, () -> null, (n, c, o) -> { | ||
| if (o == null) { | ||
| return null; | ||
| } | ||
|
|
||
| Script s = Script.parse(o); | ||
| if (!s.getLang().equals(DEFAULT_SCRIPT_LANG)) { | ||
| throw new MapperParsingException("context_aware_grouping only supports painless script"); | ||
| } | ||
| return s; | ||
| }, m -> toType(m).script).acceptsNull(); | ||
|
|
||
| private ContextAwareGroupingScript compiledScript; | ||
|
|
||
| /** | ||
| * Creates a new Builder with a field name | ||
| * | ||
| * @param name | ||
| */ | ||
| protected Builder(String name) { | ||
| super(name); | ||
| } | ||
|
|
||
| protected Builder(String name, List<String> fields, Script script, ContextAwareGroupingScript contextAwareGroupingScript) { | ||
| super(name); | ||
| this.fields.setValue(fields); | ||
| this.script.setValue(script); | ||
| this.compiledScript = contextAwareGroupingScript; | ||
| } | ||
|
|
||
| @Override | ||
| protected List<Parameter<?>> getParameters() { | ||
| return List.of(fields, script); | ||
| } | ||
|
|
||
| @Override | ||
| public ParametrizedFieldMapper build(BuilderContext context) { | ||
| final ContextAwareGroupingFieldType contextAwareGroupingFieldType = new ContextAwareGroupingFieldType( | ||
| this.fields.getValue(), | ||
| this.compiledScript | ||
| ); | ||
| return new ContextAwareGroupingFieldMapper(name, contextAwareGroupingFieldType, this); | ||
| } | ||
| } | ||
|
|
||
| private final List<String> fields; | ||
| private final Script script; | ||
| private final ContextAwareGroupingScript compiledScript; | ||
|
|
||
| /** | ||
| * Creates a new ParametrizedFieldMapper | ||
| * | ||
| * @param simpleName | ||
| * @param mappedFieldType | ||
| * @param builder | ||
| */ | ||
| protected ContextAwareGroupingFieldMapper( | ||
| String simpleName, | ||
| ContextAwareGroupingFieldType mappedFieldType, | ||
| ContextAwareGroupingFieldMapper.Builder builder | ||
| ) { | ||
| super(simpleName, mappedFieldType, MultiFields.empty(), CopyTo.empty()); | ||
| this.fields = builder.fields.getValue(); | ||
| this.script = builder.script.getValue(); | ||
| this.compiledScript = builder.compiledScript; | ||
| } | ||
|
|
||
| @Override | ||
| public Builder getMergeBuilder() { | ||
| return new Builder(CONTENT_TYPE, this.fields, this.script, this.compiledScript); | ||
| } | ||
|
|
||
| @Override | ||
| protected void parseCreateField(ParseContext context) throws IOException { | ||
| throw new MapperParsingException("context_aware_grouping cannot be ingested in the document"); | ||
| } | ||
|
|
||
| public ContextAwareGroupingFieldType fieldType() { | ||
| return (ContextAwareGroupingFieldType) mappedFieldType; | ||
| } | ||
|
|
||
| @Override | ||
| protected String contentType() { | ||
| return CONTENT_TYPE; | ||
| } | ||
| } | ||
60 changes: 60 additions & 0 deletions
60
server/src/main/java/org/opensearch/index/mapper/ContextAwareGroupingFieldType.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * The OpenSearch Contributors require contributions made to | ||
| * this file be licensed under the Apache-2.0 license or a | ||
| * compatible open source license. | ||
| */ | ||
|
|
||
| package org.opensearch.index.mapper; | ||
|
|
||
| import org.apache.lucene.search.Query; | ||
| import org.opensearch.index.query.QueryShardContext; | ||
| import org.opensearch.script.ContextAwareGroupingScript; | ||
| import org.opensearch.search.lookup.SearchLookup; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Field type for context_aware_grouping field mapper | ||
| * | ||
| * @opensearch.internal | ||
| */ | ||
| public class ContextAwareGroupingFieldType extends CompositeMappedFieldType { | ||
|
|
||
| private ContextAwareGroupingScript compiledScript; | ||
|
|
||
| public ContextAwareGroupingFieldType(final List<String> fields, final ContextAwareGroupingScript compiledScript) { | ||
| super( | ||
| ContextAwareGroupingFieldMapper.CONTENT_TYPE, | ||
| false, | ||
| false, | ||
| false, | ||
| TextSearchInfo.NONE, | ||
| Collections.emptyMap(), | ||
| fields, | ||
| CompositeFieldType.CONTEXT_AWARE_GROUPING | ||
| ); | ||
| this.compiledScript = compiledScript; | ||
| } | ||
|
|
||
| public ContextAwareGroupingScript compiledScript() { | ||
| return compiledScript; | ||
| } | ||
|
|
||
| @Override | ||
| public ValueFetcher valueFetcher(QueryShardContext context, SearchLookup searchLookup, String format) { | ||
| throw new UnsupportedOperationException("valueFetcher is not supported for context_aware_grouping field"); | ||
| } | ||
|
|
||
| @Override | ||
| public String typeName() { | ||
| return ContextAwareGroupingFieldMapper.CONTENT_TYPE; | ||
| } | ||
|
|
||
| @Override | ||
| public Query termQuery(Object value, QueryShardContext context) { | ||
| throw new UnsupportedOperationException("Term query is not supported for context_aware_grouping field"); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.