From d945a246f6071699790119f07a66fb4c5505cee2 Mon Sep 17 00:00:00 2001 From: Joel Bernstein Date: Thu, 9 Mar 2017 20:48:14 -0500 Subject: [PATCH] SOLR-10257: Add logarithm StreamEvaluator --- .../apache/solr/handler/StreamHandler.java | 3 +- .../solrj/io/eval/NaturalLogEvaluator.java | 60 ++++++++++++ .../stream/eval/NaturalLogEvaluatorTest.java | 98 +++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/NaturalLogEvaluator.java create mode 100644 solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/NaturalLogEvaluatorTest.java diff --git a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java index 06e59b6e194..e69f52be17b 100644 --- a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java @@ -42,6 +42,7 @@ import org.apache.solr.client.solrj.io.eval.IfThenElseEvaluator; import org.apache.solr.client.solrj.io.eval.LessThanEqualToEvaluator; import org.apache.solr.client.solrj.io.eval.LessThanEvaluator; import org.apache.solr.client.solrj.io.eval.MultiplyEvaluator; +import org.apache.solr.client.solrj.io.eval.NaturalLogEvaluator; import org.apache.solr.client.solrj.io.eval.NotEvaluator; import org.apache.solr.client.solrj.io.eval.OrEvaluator; import org.apache.solr.client.solrj.io.eval.RawValueEvaluator; @@ -197,7 +198,7 @@ public class StreamHandler extends RequestHandlerBase implements SolrCoreAware, .withFunctionName("div", DivideEvaluator.class) .withFunctionName("mult", MultiplyEvaluator.class) .withFunctionName("sub", SubtractEvaluator.class) - + .withFunctionName("log", NaturalLogEvaluator.class) // Conditional Stream Evaluators .withFunctionName("if", IfThenElseEvaluator.class) ; diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/NaturalLogEvaluator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/NaturalLogEvaluator.java new file mode 100644 index 00000000000..19709e61cd8 --- /dev/null +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/NaturalLogEvaluator.java @@ -0,0 +1,60 @@ +/* + * 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.solr.client.solrj.io.eval; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Locale; + +import org.apache.solr.client.solrj.io.Tuple; +import org.apache.solr.client.solrj.io.stream.expr.StreamExpression; +import org.apache.solr.client.solrj.io.stream.expr.StreamFactory; + +public class NaturalLogEvaluator extends NumberEvaluator { + protected static final long serialVersionUID = 1L; + + public NaturalLogEvaluator(StreamExpression expression, StreamFactory factory) throws IOException{ + super(expression, factory); + + if(1 != subEvaluators.size()){ + throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expecting one value but found %d",expression,subEvaluators.size())); + } + } + + @Override + public Number evaluate(Tuple tuple) throws IOException { + + List results = evaluateAll(tuple); + + // we're still doing these checks because if we ever add an array-flatten evaluator, + // one found in the constructor could become != 1 + if(1 != results.size()){ + throw new IOException(String.format(Locale.ROOT,"%s(...) only works with a 1 value but %d were provided", constructingFactory.getFunctionName(getClass()), results.size())); + } + + if(null == results.get(0)){ + return null; + } + + return Math.log(results.get(0).doubleValue()); + } + +} diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/NaturalLogEvaluatorTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/NaturalLogEvaluatorTest.java new file mode 100644 index 00000000000..c4ae127f4ee --- /dev/null +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/NaturalLogEvaluatorTest.java @@ -0,0 +1,98 @@ +/* + * 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.solr.client.solrj.io.stream.eval; + +import java.io.IOException; +import java.util.Map; + +import junit.framework.Assert; + +import org.apache.commons.collections.map.HashedMap; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.solr.client.solrj.io.Tuple; +import org.apache.solr.client.solrj.io.eval.AddEvaluator; +import org.apache.solr.client.solrj.io.eval.NaturalLogEvaluator; +import org.apache.solr.client.solrj.io.eval.StreamEvaluator; +import org.apache.solr.client.solrj.io.stream.expr.StreamFactory; +import org.junit.Test; + +public class NaturalLogEvaluatorTest extends LuceneTestCase { + + StreamFactory factory; + Map values; + + public NaturalLogEvaluatorTest() { + super(); + + factory = new StreamFactory() + .withFunctionName("log", NaturalLogEvaluator.class).withFunctionName("add", AddEvaluator.class); + values = new HashedMap(); + } + + @Test + public void logOneField() throws Exception{ + StreamEvaluator evaluator = factory.constructEvaluator("log(a)"); + Object result; + + values.clear(); + values.put("a", 100); + result = evaluator.evaluate(new Tuple(values)); + Assert.assertTrue(result instanceof Double); + Assert.assertTrue(result.equals(Math.log(100))); + + } + + @Test + public void logNestedField() throws Exception{ + StreamEvaluator evaluator = factory.constructEvaluator("log(add(50,50))"); + Object result; + + values.clear(); + result = evaluator.evaluate(new Tuple(values)); + Assert.assertTrue(result instanceof Double); + Assert.assertTrue(result.equals(Math.log(100))); + + } + + @Test(expected = IOException.class) + public void logNoField() throws Exception{ + factory.constructEvaluator("log()"); + } + + @Test(expected = IOException.class) + public void logTwoFields() throws Exception{ + factory.constructEvaluator("log(a,b)"); + } + + @Test + public void logNoValue() throws Exception{ + StreamEvaluator evaluator = factory.constructEvaluator("log(a)"); + + values.clear(); + Object result = evaluator.evaluate(new Tuple(values)); + assertNull(result); + } + @Test + public void logNullValue() throws Exception{ + StreamEvaluator evaluator = factory.constructEvaluator("log(a)"); + + values.clear(); + values.put("a", null); + Object result = evaluator.evaluate(new Tuple(values)); + assertNull(result); + } +}