From 2d2c15dc4c394aae7b7dbcc6359bce166562a8e4 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 8 Nov 2023 15:21:15 -0500 Subject: [PATCH] add tests and changelog Signed-off-by: Stephen Crawford --- CHANGELOG.md | 1 + .../common/DeleteFieldResponseProcessor.java | 139 ++++++++++++++++++ .../opensearch/common/regex/RegexTests.java | 8 + 3 files changed, 148 insertions(+) create mode 100644 modules/search-pipeline-common/src/main/java/org/opensearch/search/pipeline/common/DeleteFieldResponseProcessor.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1e4c12e5041..0622e13f3cb79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Return 409 Conflict HTTP status instead of 503 on failure to concurrently execute snapshots ([#8986](https://github.com/opensearch-project/OpenSearch/pull/5855)) - Add task completion count in search backpressure stats API ([#10028](https://github.com/opensearch-project/OpenSearch/pull/10028/)) - Performance improvement for Datetime field caching ([#4558](https://github.com/opensearch-project/OpenSearch/issues/4558)) +- Use iterative approach to evaluate Regex.simpleMatch ([#11060](https://github.com/opensearch-project/OpenSearch/pull/11060)) ### Deprecated diff --git a/modules/search-pipeline-common/src/main/java/org/opensearch/search/pipeline/common/DeleteFieldResponseProcessor.java b/modules/search-pipeline-common/src/main/java/org/opensearch/search/pipeline/common/DeleteFieldResponseProcessor.java new file mode 100644 index 0000000000000..5241b25c84683 --- /dev/null +++ b/modules/search-pipeline-common/src/main/java/org/opensearch/search/pipeline/common/DeleteFieldResponseProcessor.java @@ -0,0 +1,139 @@ +/* + * 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.search.pipeline.common; + +import org.opensearch.action.search.SearchRequest; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.document.DocumentField; +import org.opensearch.common.xcontent.XContentHelper; +import org.opensearch.core.common.bytes.BytesReference; +import org.opensearch.core.xcontent.MediaType; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.ingest.ConfigurationUtils; +import org.opensearch.search.SearchHit; +import org.opensearch.search.pipeline.AbstractProcessor; +import org.opensearch.search.pipeline.Processor; +import org.opensearch.search.pipeline.SearchRequestProcessor; +import org.opensearch.search.pipeline.SearchResponseProcessor; + +import java.util.Map; + +/** + * This is a {@link SearchRequestProcessor} that renames a field before returning the search response + */ +public class DeleteFieldResponseProcessor extends AbstractProcessor implements SearchResponseProcessor { + + private final String field; + private final boolean ignoreMissing; + + /** + * Key to reference this processor type from a search pipeline. + */ + public static final String TYPE = "delete_field"; + + /** + * Constructor that takes a target field to be deleted + * + * @param tag processor tag + * @param description processor description + * @param ignoreFailure option to ignore failure + * @param field name of field to delete + * @param ignoreMissing if true, do not throw error if oldField does not exist within search response + */ + public DeleteFieldResponseProcessor(String tag, String description, boolean ignoreFailure, String field, boolean ignoreMissing) { + super(tag, description, ignoreFailure); + this.field = field; + this.ignoreMissing = ignoreMissing; + } + + @Override + public String getType() { + return TYPE; + } + + /** + * Get the provided field to be deleted + * @return oldField + */ + public String getField() { + return field; + } + + /** + * Getter function for ignoreMissing + * @return ignoreMissing + */ + public boolean isIgnoreMissing() { + return ignoreMissing; + } + + @Override + public SearchResponse processResponse(SearchRequest request, SearchResponse response) throws Exception { + boolean foundField = false; + + SearchHit[] hits = response.getHits().getHits(); + for (SearchHit hit : hits) { + Map fields = hit.getFields(); + if (fields.containsKey(field)) { + foundField = true; + DocumentField old = hit.removeDocumentField(field); + } + + if (hit.hasSource()) { + BytesReference sourceRef = hit.getSourceRef(); + Tuple> typeAndSourceMap = XContentHelper.convertToMap( + sourceRef, + false, + (MediaType) null + ); + + Map sourceAsMap = typeAndSourceMap.v2(); + if (sourceAsMap.containsKey(field)) { + foundField = true; + Object val = sourceAsMap.remove(field); + XContentBuilder builder = XContentBuilder.builder(typeAndSourceMap.v1().xContent()); + builder.map(sourceAsMap); + hit.sourceRef(BytesReference.bytes(builder)); + } + } + + if (!foundField && !ignoreMissing) { + throw new IllegalArgumentException("Document with id " + hit.getId() + " is missing field " + field); + } + } + + return response; + } + + /** + * This is a factory that creates the DeleteFieldResponseProcessor + */ + public static final class Factory implements Processor.Factory { + + /** + * Constructor for factory + */ + Factory() {} + + @Override + public DeleteFieldResponseProcessor create( + Map> processorFactories, + String tag, + String description, + boolean ignoreFailure, + Map config, + PipelineContext pipelineContext + ) throws Exception { + String field = ConfigurationUtils.readStringProperty(TYPE, tag, config, "field"); + boolean ignoreMissing = ConfigurationUtils.readBooleanProperty(TYPE, tag, config, "ignore_missing", false); + return new DeleteFieldResponseProcessor(tag, description, ignoreFailure, field, ignoreMissing); + } + } +} diff --git a/server/src/test/java/org/opensearch/common/regex/RegexTests.java b/server/src/test/java/org/opensearch/common/regex/RegexTests.java index 12df1f173719e..d18359ee0fe68 100644 --- a/server/src/test/java/org/opensearch/common/regex/RegexTests.java +++ b/server/src/test/java/org/opensearch/common/regex/RegexTests.java @@ -98,6 +98,14 @@ public void testDoubleWildcardMatch() { assertTrue(Regex.simpleMatch("fff*******ddd", "FffAbcdDd", true)); assertFalse(Regex.simpleMatch("fff*******ddd", "FffAbcdDd", false)); assertFalse(Regex.simpleMatch("fff******ddd", "fffabcdd")); + assertTrue(Regex.simpleMatch("abCDefGH******ddd", "abCDefGHddd", false)); + assertTrue(Regex.simpleMatch("******", "a")); + assertTrue(Regex.simpleMatch("***WILDcard***", "aaaaaaaaWILDcardZZZZZZ", false)); + assertFalse(Regex.simpleMatch("***xxxxx123456789xxxxxx***", "xxxxxabcdxxxxx", false)); + assertFalse(Regex.simpleMatch("***xxxxxabcdxxxxx***", "xxxxxABCDxxxxx", false)); + assertTrue(Regex.simpleMatch("***xxxxxabcdxxxxx***", "xxxxxABCDxxxxx", true)); + assertTrue(Regex.simpleMatch("**stephenIsSuperCool**", "ItIsTrueThatStephenIsSuperCoolSoYouShouldLetThisIn", true)); + assertTrue(Regex.simpleMatch("**w**X**y**Z**", "abcdeFGHIJKLMNOPqrstuvwabcdeFGHIJKLMNOPqrstuvwXabcdeFGHIJKLMNOPqrstuvwXyabcdeFGHIJKLMNOPqrstuvwXyZ", false)); } public void testSimpleMatch() {