METRON-1461 MIN MAX stellar function should take a stats or list object and return min/max (MohanDV via nickwallen) closes apache/metron#942
Project: http://git-wip-us.apache.org/repos/asf/metron/repo Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/d7edce97 Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/d7edce97 Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/d7edce97 Branch: refs/heads/feature/METRON-1090-stellar-assignment Commit: d7edce974341a6fca0e8e87b11baed5ad0d5d0c1 Parents: ca4644b Author: MohanDV <mohan...@gmail.com> Authored: Wed May 9 16:33:32 2018 -0400 Committer: nickallen <nickal...@apache.org> Committed: Wed May 9 16:33:32 2018 -0400 ---------------------------------------------------------------------- .../metron/statistics/StatisticsProvider.java | 6 +-- .../metron/stellar/dsl/functions/Ordinal.java | 36 +++++++++++++++ .../stellar/dsl/functions/OrdinalFunctions.java | 48 +++++++++++++------- .../dsl/functions/OrdinalFunctionsTest.java | 41 ++++++++++++++++- 4 files changed, 110 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metron/blob/d7edce97/metron-analytics/metron-statistics/src/main/java/org/apache/metron/statistics/StatisticsProvider.java ---------------------------------------------------------------------- diff --git a/metron-analytics/metron-statistics/src/main/java/org/apache/metron/statistics/StatisticsProvider.java b/metron-analytics/metron-statistics/src/main/java/org/apache/metron/statistics/StatisticsProvider.java index 860aa4e..e737484 100644 --- a/metron-analytics/metron-statistics/src/main/java/org/apache/metron/statistics/StatisticsProvider.java +++ b/metron-analytics/metron-statistics/src/main/java/org/apache/metron/statistics/StatisticsProvider.java @@ -20,14 +20,14 @@ package org.apache.metron.statistics; +import org.apache.metron.stellar.dsl.functions.Ordinal; + /** * Provides statistical functions. */ -public interface StatisticsProvider { +public interface StatisticsProvider extends Ordinal{ void addValue(double value); long getCount(); - double getMin(); - double getMax(); double getMean(); double getSum(); double getVariance(); http://git-wip-us.apache.org/repos/asf/metron/blob/d7edce97/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/Ordinal.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/Ordinal.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/Ordinal.java new file mode 100644 index 0000000..d3bd9ce --- /dev/null +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/Ordinal.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.metron.stellar.dsl.functions; + +/** + * Interface that provides the statistical function get max and min from the implementing object. + */ +public interface Ordinal { + + /** + * get the min value + * @return min value + */ + double getMin(); + + /** + * get the max value + * @return max value + */ + double getMax(); +} http://git-wip-us.apache.org/repos/asf/metron/blob/d7edce97/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctions.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctions.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctions.java index 49e9369..6ac9ff5 100644 --- a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctions.java +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctions.java @@ -22,12 +22,10 @@ import com.google.common.collect.Iterables; import org.apache.metron.stellar.common.utils.ConversionUtils; import org.apache.metron.stellar.dsl.BaseStellarFunction; import org.apache.metron.stellar.dsl.Stellar; - -import java.util.Collections; import java.util.List; import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.stream.Collectors; +import static org.apache.metron.stellar.common.utils.ConversionUtils.convert; + public class OrdinalFunctions { @@ -37,19 +35,29 @@ public class OrdinalFunctions { * Return the maximum value of a list of input values in a Stellar list */ @Stellar(name = "MAX" - , description = "Returns the maximum value of a list of input values" - , params = {"list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)" + + , description = "Returns the maximum value of a list of input values or from a statistics object" + , params = {"stats - The Stellar statistics object" + ,"list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)" + " Multi type numeric comparisons are supported: MAX([10,15L,15.3]) would return 15.3, but MAX(['23',25]) will fail and return null as strings and numbers can't be compared."} - , returns = "The maximum value in the list, or null if the list is empty or the input values were not comparable.") + , returns = "The maximum value in the list or from stats, or null if the list is empty or the input values were not comparable.") public static class Max extends BaseStellarFunction { @Override public Object apply(List<Object> args) { if (args.size() < 1 || args.get(0) == null) { - throw new IllegalStateException("MAX function requires at least a Stellar list of values"); + throw new IllegalStateException("MAX function requires at least one argument"); + } + Object firstArg = args.get(0); + if(firstArg instanceof Ordinal) { + Ordinal stats = convert(firstArg, Ordinal.class); + return stats.getMax(); + } else if (firstArg instanceof Iterable) { + Iterable<Comparable> list = (Iterable<Comparable>) args.get(0); + return orderList(list, (ret, val) -> ret.compareTo(val) < 0, "MAX"); + } else { + throw new IllegalStateException("MAX function expects either 'a StatisticsProvider object' or 'Stellar list of values'"); } - Iterable list = (Iterable<Object>) args.get(0); - return orderList(list, (ret, val) -> ret.compareTo(val) < 0, "MAX"); + } } @@ -60,18 +68,26 @@ public class OrdinalFunctions { */ @Stellar(name = "MIN" , description = "Returns the minimum value of a list of input values" - , params = {"list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)" + + , params = {"stats - The Stellar statistics object" + ,"list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)" + " Multi type numeric comparisons are supported: MIN([10,15L,15.3]) would return 10, but MIN(['23',25]) will fail and return null as strings and numbers can't be compared."} - , returns = "The minimum value in the list, or null if the list is empty or the input values were not comparable.") + , returns = "The minimum value in the list or from stats, or null if the list is empty or the input values were not comparable.") public static class Min extends BaseStellarFunction { @Override public Object apply(List<Object> args) { if (args.size() < 1 || args.get(0) == null) { - throw new IllegalStateException("MIN function requires at least a Stellar list of values"); + throw new IllegalStateException("MIN function requires at least one argument"); + } + Object firstArg = args.get(0); + if(firstArg instanceof Ordinal) { + Ordinal stats = convert(firstArg, Ordinal.class); + return stats.getMin(); + } else if (firstArg instanceof Iterable){ + Iterable<Comparable> list = (Iterable<Comparable>) args.get(0); + return orderList(list, (ret, val) -> ret.compareTo(val) > 0, "MIN"); + } else { + throw new IllegalStateException("MIN function expects either 'a StatisticsProvider object' or 'Stellar list of values' "); } - Iterable<Comparable> list = (Iterable<Comparable>) args.get(0); - return orderList(list, (ret, val) -> ret.compareTo(val) > 0, "MIN"); - } } http://git-wip-us.apache.org/repos/asf/metron/blob/d7edce97/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctionsTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctionsTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctionsTest.java index 5e06fdd..e405c7f 100644 --- a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctionsTest.java +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/OrdinalFunctionsTest.java @@ -20,7 +20,6 @@ package org.apache.metron.stellar.dsl.functions; import com.google.common.collect.ImmutableMap; -import org.adrianwalker.multilinestring.Multiline; import org.apache.metron.stellar.common.StellarProcessor; import org.apache.metron.stellar.dsl.Context; import org.apache.metron.stellar.dsl.DefaultVariableResolver; @@ -28,7 +27,6 @@ import org.apache.metron.stellar.dsl.StellarFunctions; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import java.util.*; @@ -220,6 +218,45 @@ public class OrdinalFunctionsTest { } } + + @Test + public void testMaxOfStats() throws Exception { + Ordinal provider = new Ordinal() { + @Override + public double getMin() { + return 10; + } + + @Override + public double getMax() { + return 100; + } + }; + + Object res = run("MAX(input_list)", ImmutableMap.of("input_list", provider)); + Assert.assertNotNull(res); + Assert.assertTrue(res.equals(100.0d)); + } + + @Test + public void testMinOfStats() throws Exception { + Ordinal provider = new Ordinal() { + @Override + public double getMin() { + return 10; + } + + @Override + public double getMax() { + return 100; + } + }; + + Object res = run("MIN(input_list)", ImmutableMap.of("input_list", provider)); + Assert.assertNotNull(res); + Assert.assertTrue(res.equals(10.0d)); + } + public Object run(String rule, Map<String, Object> variables) throws Exception { StellarProcessor processor = new StellarProcessor(); return processor.parse(rule, new DefaultVariableResolver(x -> variables.get(x), x -> variables.containsKey(x)), StellarFunctions.FUNCTION_RESOLVER(), context);