You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dp...@apache.org on 2017/06/28 18:17:24 UTC
[01/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Repository: lucene-solr
Updated Branches:
refs/heads/master 85a27a231 -> d5963bebc
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasCloudTest.java
new file mode 100644
index 0000000..427b50d
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasCloudTest.java
@@ -0,0 +1,253 @@
+/*
+ * 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.analytics.facet;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class FieldFacetExtrasCloudTest extends AbstractAnalyticsFacetCloudTest {
+ public static final int INT = 21;
+ public static final int LONG = 22;
+ public static final int FLOAT = 23;
+ public static final int DOUBLE = 24;
+ public static final int DATE = 25;
+ public static final int STRING = 26;
+ public static final int NUM_LOOPS = 100;
+
+ //INT
+ static ArrayList<ArrayList<Integer>> intLongTestStart;
+ static ArrayList<ArrayList<Integer>> intFloatTestStart;
+ static ArrayList<ArrayList<Integer>> intDoubleTestStart;
+ static ArrayList<ArrayList<Integer>> intStringTestStart;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ setupCluster();
+
+ //INT
+ intLongTestStart = new ArrayList<>();
+ intFloatTestStart = new ArrayList<>();
+ intDoubleTestStart = new ArrayList<>();
+ intStringTestStart = new ArrayList<>();
+
+ UpdateRequest req = new UpdateRequest();
+
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT;
+ long l = j%LONG;
+ float f = j%FLOAT;
+ double d = j%DOUBLE;
+ int dt = j%DATE;
+ int s = j%STRING;
+
+ List<String> fields = new ArrayList<>();
+ fields.add("id"); fields.add("1000"+j);
+ fields.add("int_id"); fields.add("" + i);
+ fields.add("long_ld"); fields.add("" + l);
+ fields.add("float_fd"); fields.add("" + f);
+ fields.add("double_dd"); fields.add("" + d);
+ fields.add("date_dtd"); fields.add((1800+dt) + "-12-31T23:59:59.999Z");
+ fields.add("string_sd"); fields.add("abc" + s);
+ req.add(fields.toArray(new String[0]));
+
+ //Long
+ if (j-LONG<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intLongTestStart.add(list1);
+ } else {
+ intLongTestStart.get((int)l).add(i);
+ }
+ //String
+ if (j-FLOAT<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intFloatTestStart.add(list1);
+ } else {
+ intFloatTestStart.get((int)f).add(i);
+ }
+ //String
+ if (j-DOUBLE<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intDoubleTestStart.add(list1);
+ } else {
+ intDoubleTestStart.get((int)d).add(i);
+ }
+ //String
+ if (j-STRING<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intStringTestStart.add(list1);
+ } else {
+ intStringTestStart.get(s).add(i);
+ }
+ }
+
+ req.commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ @Test
+ public void limitTest() throws Exception {
+ String[] params = new String[] {
+ "o.lr.s.mean", "mean(int_id)",
+ "o.lr.s.median", "median(int_id)",
+ "o.lr.s.count", "count(int_id)",
+ "o.lr.s.percentile_20", "percentile(20,int_id)",
+ "o.lr.ff.long_ld", "long_ld",
+ "o.lr.ff.long_ld.ss", "mean",
+ "o.lr.ff.long_ld.sd", "asc",
+ "o.lr.ff.long_ld.limit", "5",
+ "o.lr.ff.float_fd", "float_fd",
+ "o.lr.ff.float_fd.ss", "median",
+ "o.lr.ff.float_fd.sd", "desc",
+ "o.lr.ff.float_fd.limit", "3",
+ "o.lr.ff.double_dd", "double_dd",
+ "o.lr.ff.double_dd.ss", "count",
+ "o.lr.ff.double_dd.sd", "asc",
+ "o.lr.ff.double_dd.limit", "7",
+ "o.lr.ff.string_sd", "string_sd",
+ "o.lr.ff.string_sd.ss", "percentile_20",
+ "o.lr.ff.string_sd.sd", "desc",
+ "o.lr.ff.string_sd.limit", "1"
+ };
+
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ Collection<Double> lon = getValueList(response, "lr", "fieldFacets", "long_ld", "mean", false);
+ assertEquals(responseStr, lon.size(),5);
+ Collection<Double> flo = getValueList(response, "lr", "fieldFacets", "float_fd", "median", false);
+ assertEquals(responseStr, flo.size(),3);
+ Collection<Long> doub = getValueList(response, "lr", "fieldFacets", "double_dd", "count", false);
+ assertEquals(responseStr, doub.size(),7);
+ Collection<Integer> string = getValueList(response, "lr", "fieldFacets", "string_sd", "percentile_20", false);
+ assertEquals(responseStr, string.size(),1);
+ }
+
+ @Test
+ public void offsetTest() throws Exception {
+ String[] params = new String[] {
+ "o.offAll.s.mean", "mean(int_id)",
+ "o.offAll.ff", "long_ld",
+ "o.offAll.ff.long_ld.ss", "mean",
+ "o.offAll.ff.long_ld.sd", "asc",
+ "o.offAll.ff.long_ld.limit", "7",
+
+ "o.off0.s.mean", "mean(int_id)",
+ "o.off0.ff", "long_ld",
+ "o.off0.ff.long_ld.ss", "mean",
+ "o.off0.ff.long_ld.sd", "asc",
+ "o.off0.ff.long_ld.limit", "2",
+ "o.off0.ff.long_ld.offset", "0",
+
+ "o.off1.s.mean", "mean(int_id)",
+ "o.off1.ff", "long_ld",
+ "o.off1.ff.long_ld.ss", "mean",
+ "o.off1.ff.long_ld.sd", "asc",
+ "o.off1.ff.long_ld.limit", "2",
+ "o.off1.ff.long_ld.offset", "2",
+
+ "o.off2.s.mean", "mean(int_id)",
+ "o.off2.ff", "long_ld",
+ "o.off2.ff.long_ld.ss", "mean",
+ "o.off2.ff.long_ld.sd", "asc",
+ "o.off2.ff.long_ld.limit", "3",
+ "o.off2.ff.long_ld.offset", "4"
+ };
+
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ Collection<Double> lon;
+
+ List<Double> all = new ArrayList<>();
+ lon = getValueList(response, "off0", "fieldFacets", "long_ld", "mean", false);
+ assertEquals(responseStr, lon.size(),2);
+ assertArrayEquals(new Double[]{ 1.5, 2.0 }, lon.toArray(new Double[0]));
+ all.addAll(lon);
+
+ lon = getValueList(response, "off1", "fieldFacets", "long_ld", "mean", false);
+ assertEquals(responseStr, lon.size(),2);
+ assertArrayEquals(new Double[]{ 3.0, 4.0 }, lon.toArray(new Double[0]));
+ all.addAll(lon);
+
+ lon = getValueList(response, "off2", "fieldFacets", "long_ld", "mean", false);
+ assertEquals(responseStr, lon.size(),3);
+ assertArrayEquals(new Double[]{ 5.0, 5.75, 6.0 }, lon.toArray(new Double[0]));
+ all.addAll(lon);
+
+ lon = getValueList(response, "offAll", "fieldFacets", "long_ld", "mean", false);
+ assertEquals(responseStr, lon.size(),7);
+ assertArrayEquals(all.toArray(new Double[0]), lon.toArray(new Double[0]));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void sortTest() throws Exception {
+ String[] params = new String[] {
+ "o.sr.s.mean", "mean(int_id)",
+ "o.sr.s.median", "median(int_id)",
+ "o.sr.s.count", "count(int_id)",
+ "o.sr.s.percentile_20", "percentile(20,int_id)",
+ "o.sr.ff", "long_ld",
+ "o.sr.ff.long_ld.ss", "mean",
+ "o.sr.ff.long_ld.sd", "asc",
+ "o.sr.ff", "float_fd",
+ "o.sr.ff.float_fd.ss", "median",
+ "o.sr.ff.float_fd.sd", "desc",
+ "o.sr.ff", "double_dd",
+ "o.sr.ff.double_dd.ss", "count",
+ "o.sr.ff.double_dd.sd", "asc",
+ "o.sr.ff", "string_sd",
+ "o.sr.ff.string_sd.ss", "percentile_20",
+ "o.sr.ff.string_sd.sd", "desc"
+ };
+
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ Collection<Double> lon = getValueList(response, "sr", "fieldFacets", "long_ld", "mean", false);
+ ArrayList<Double> longTest = calculateNumberStat(intLongTestStart, "mean");
+ Collections.sort(longTest);
+ assertEquals(responseStr, longTest,lon);
+
+ Collection<Double> flo = getValueList(response, "sr", "fieldFacets", "float_fd", "median", false);
+ ArrayList<Double> floatTest = calculateNumberStat(intFloatTestStart, "median");
+ Collections.sort(floatTest,Collections.reverseOrder());
+ assertEquals(responseStr, floatTest,flo);
+
+ Collection<Long> doub = getValueList(response, "sr", "fieldFacets", "double_dd", "count", false);
+ ArrayList<Long> doubleTest = (ArrayList<Long>)calculateStat(intDoubleTestStart, "count");
+ Collections.sort(doubleTest);
+ assertEquals(responseStr, doubleTest,doub);
+
+ Collection<Integer> string = getValueList(response, "sr", "fieldFacets", "string_sd", "percentile_20", false);
+ ArrayList<Integer> stringTest = (ArrayList<Integer>)calculateStat(intStringTestStart, "perc_20");
+ Collections.sort(stringTest,Collections.reverseOrder());
+ assertEquals(responseStr, stringTest,string);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasTest.java
index fc7df4b..a7e0012 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetExtrasTest.java
@@ -26,7 +26,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
public class FieldFacetExtrasTest extends AbstractAnalyticsFacetTest {
- static String fileName = "/analytics/requestFiles/fieldFacetExtras.txt";
+ static String fileName = "fieldFacetExtras.txt";
public static final int INT = 21;
public static final int LONG = 22;
@@ -44,7 +44,7 @@ public class FieldFacetExtrasTest extends AbstractAnalyticsFacetTest {
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
h.update("<delete><query>*:*</query></delete>");
//INT
@@ -104,7 +104,6 @@ public class FieldFacetExtrasTest extends AbstractAnalyticsFacetTest {
setResponse(h.query(request(fileToStringArr(FieldFacetExtrasTest.class, fileName))));
}
- @SuppressWarnings("unchecked")
@Test
public void limitTest() throws Exception {
@@ -118,7 +117,6 @@ public class FieldFacetExtrasTest extends AbstractAnalyticsFacetTest {
assertEquals(getRawResponse(), string.size(),1);
}
- @SuppressWarnings("unchecked")
@Test
public void offsetTest() throws Exception {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetTest.java
index bf67213..59f4d88 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetTest.java
@@ -24,10 +24,11 @@ import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.w3c.dom.Node;
public class FieldFacetTest extends AbstractAnalyticsFacetTest{
- static String fileName = "/analytics/requestFiles/fieldFacets.txt";
+ static String fileName = "fieldFacets.txt";
public static final int INT = 71;
public static final int LONG = 36;
@@ -87,7 +88,7 @@ public class FieldFacetTest extends AbstractAnalyticsFacetTest{
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
h.update("<delete><query>*:*</query></delete>");
defaults.put("int", new Integer(0));
@@ -478,46 +479,6 @@ public class FieldFacetTest extends AbstractAnalyticsFacetTest{
@SuppressWarnings("unchecked")
@Test
- public void sumOfSquaresFacetAscTest() throws Exception {
- //Int Date
- Collection<Double> intDate = getDoubleList("sumOfSquares","fieldFacets", "date_dtd", "double", "int");
- ArrayList<Double> intDateTest = calculateNumberStat(intDateTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),intDate,intDateTest);
- //Int String
- Collection<Double> intString = getDoubleList("sumOfSquares","fieldFacets", "string_sd", "double", "int");
- ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),intString,intStringTest);
-
- //Long Date
- Collection<Double> longDate = getDoubleList("sumOfSquares","fieldFacets", "date_dtd", "double", "long");
- ArrayList<Double> longDateTest = calculateNumberStat(longDateTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),longDate,longDateTest);
- //Long String
- Collection<Double> longString = getDoubleList("sumOfSquares","fieldFacets", "string_sd", "double", "long");
- ArrayList<Double> longStringTest = calculateNumberStat(longStringTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),longString,longStringTest);
-
- //Float Date
- Collection<Double> floatDate = getDoubleList("sumOfSquares","fieldFacets", "date_dtd", "double", "float");
- ArrayList<Double> floatDateTest = calculateNumberStat(floatDateTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),floatDate,floatDateTest);
- //Float String
- Collection<Double> floatString = getDoubleList("sumOfSquares","fieldFacets", "string_sd", "double", "float");
- ArrayList<Double> floatStringTest = calculateNumberStat(floatStringTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),floatString,floatStringTest);
-
- //Double Date
- Collection<Double> doubleDate = getDoubleList("sumOfSquares","fieldFacets", "date_dtd", "double", "double");
- ArrayList<Double> doubleDateTest = calculateNumberStat(doubleDateTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),doubleDate,doubleDateTest);
- //Double String
- Collection<Double> doubleString = getDoubleList("sumOfSquares","fieldFacets", "string_sd", "double", "double");
- ArrayList<Double> doubleStringTest = calculateNumberStat(doubleStringTestStart, "sumOfSquares");
- assertEquals(getRawResponse(),doubleString,doubleStringTest);
- }
-
- @SuppressWarnings("unchecked")
- @Test
public void stddevFacetAscTest() throws Exception {
//Int Date
ArrayList<Double> intDate = getDoubleList("stddev","fieldFacets", "date_dtd", "double", "int");
@@ -1037,31 +998,33 @@ public class FieldFacetTest extends AbstractAnalyticsFacetTest{
public void missingFacetTest() throws Exception {
//int MultiDate
String xPath = "/response/lst[@name='stats']/lst[@name='missingf']/lst[@name='fieldFacets']/lst[@name='date_dtdm']/lst[@name='(MISSING)']";
- assertNotNull(getRawResponse(), getNode(xPath));
+ Node missingNodeXPath = getNode(xPath);
+ assertNotNull(getRawResponse(), missingNodeXPath);
ArrayList<Double> string = getDoubleList("missingf", "fieldFacets", "date_dtdm", "double", "mean");
- string.remove(0);
+ //super.removeNodes(xPath, string);
ArrayList<Double> stringTest = calculateNumberStat(multiDateTestStart, "mean");
assertEquals(getRawResponse(), string,stringTest);
-
+
//Int String
xPath = "/response/lst[@name='stats']/lst[@name='missingf']/lst[@name='fieldFacets']/lst[@name='string_sd']/lst[@name='(MISSING)']";
- assertNotNull(getRawResponse(), getNode(xPath));
+ missingNodeXPath = getNode(xPath);
+ String missingNodeXPathStr = xPath;
+ assertNotNull(getRawResponse(), missingNodeXPath);
xPath = "/response/lst[@name='stats']/lst[@name='missingf']/lst[@name='fieldFacets']/lst[@name='string_sd']/lst[@name='str0']";
assertNull(getRawResponse(), getNode(xPath));
+
List<Double> intString = getDoubleList("missingf", "fieldFacets", "string_sd", "double", "mean");
- intString.remove(0);
+ //removeNodes(missingNodeXPathStr, intString);
ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "mean");
assertEquals(getRawResponse(), intString,intStringTest);
-
+
//Int Date
Collection<Double> intDate = getDoubleList("missingf", "fieldFacets", "date_dtd", "double", "mean");
ArrayList<ArrayList<Double>> intDateMissingTestStart = (ArrayList<ArrayList<Double>>) intDateTestStart.clone();
ArrayList<Double> intDateTest = calculateNumberStat(intDateMissingTestStart, "mean");
assertEquals(getRawResponse(),intDate,intDateTest);
-
-
}
private void checkStddevs(ArrayList<Double> list1, ArrayList<Double> list2) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetCloudTest.java
new file mode 100644
index 0000000..42b5abe
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetCloudTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.analytics.facet;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class QueryFacetCloudTest extends AbstractAnalyticsFacetCloudTest {
+ private static final int INT = 71;
+ private static final int LONG = 36;
+ private static final int FLOAT = 93;
+ private static final int DOUBLE = 49;
+ private static final int DATE = 12;
+ private static final int STRING = 7;
+ private static final int NUM_LOOPS = 100;
+
+ private static ArrayList<ArrayList<Integer>> int1TestStart = new ArrayList<>();
+ private static ArrayList<ArrayList<Integer>> int2TestStart = new ArrayList<>();
+ private static ArrayList<ArrayList<Long>> longTestStart = new ArrayList<>();
+ private static ArrayList<ArrayList<Float>> floatTestStart = new ArrayList<>();
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ setupCluster();
+
+ //INT
+ int1TestStart.add(new ArrayList<Integer>());
+ int2TestStart.add(new ArrayList<Integer>());
+
+ //LONG
+ longTestStart.add(new ArrayList<Long>());
+ longTestStart.add(new ArrayList<Long>());
+
+ //FLOAT
+ floatTestStart.add(new ArrayList<Float>());
+ floatTestStart.add(new ArrayList<Float>());
+ floatTestStart.add(new ArrayList<Float>());
+
+ UpdateRequest req = new UpdateRequest();
+
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT;
+ long l = j%LONG;
+ float f = j%FLOAT;
+ double d = j%DOUBLE;
+ int dt = j%DATE;
+ int s = j%STRING;
+
+ List<String> fields = new ArrayList<>();
+ fields.add("id"); fields.add("1000"+j);
+ fields.add("int_id"); fields.add("" + i);
+ fields.add("long_ld"); fields.add("" + l);
+ fields.add("float_fd"); fields.add("" + f);
+ fields.add("double_dd"); fields.add("" + d);
+ fields.add("date_dtd"); fields.add((1000+dt) + "-01-01T23:59:59Z");
+ fields.add("string_sd"); fields.add("abc" + s);
+ req.add(fields.toArray(new String[0]));
+
+ if (f<=50) {
+ int1TestStart.get(0).add(i);
+ }
+ if (f<=30) {
+ int2TestStart.get(0).add(i);
+ }
+ if (s == 1) {
+ longTestStart.get(0).add(l);
+ }
+ if (s == 2) {
+ longTestStart.get(1).add(l);
+ }
+ if (l>=30) {
+ floatTestStart.get(0).add(f);
+ }
+ if (d<=50) {
+ floatTestStart.get(1).add(f);
+ }
+ if (l>=20) {
+ floatTestStart.get(2).add(f);
+ }
+ }
+
+ req.commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void queryTest() throws Exception {
+ String[] params = new String[] {
+ "o.ir.s.sum", "sum(int_id)",
+ "o.ir.s.mean", "mean(int_id)",
+ "o.ir.s.median", "median(int_id)",
+ "o.ir.s.percentile_8", "percentile(8,int_id)",
+ "o.ir.qf", "float1",
+ "o.ir.qf.float1.q", "float_fd:[* TO 50]",
+ "o.ir.qf", "float2",
+ "o.ir.qf.float2.q", "float_fd:[* TO 30]",
+
+ "o.lr.s.sum", "sum(long_ld)",
+ "o.lr.s.mean", "mean(long_ld)",
+ "o.lr.s.median", "median(long_ld)",
+ "o.lr.s.percentile_8", "percentile(8,long_ld)",
+ "o.lr.qf", "string",
+ "o.lr.qf.string.q", "string_sd:abc1",
+ "o.lr.qf.string.q", "string_sd:abc2",
+
+ "o.fr.s.sum", "sum(float_fd)",
+ "o.fr.s.mean", "mean(float_fd)",
+ "o.fr.s.median", "median(float_fd)",
+ "o.fr.s.percentile_8", "percentile(8,float_fd)",
+ "o.fr.qf", "lad",
+ "o.fr.qf.lad.q", "long_ld:[20 TO *]",
+ "o.fr.qf.lad.q", "long_ld:[30 TO *]",
+ "o.fr.qf.lad.q", "double_dd:[* TO 50]"
+ };
+
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int One
+ ArrayList<Double> int1 = getValueList(response, "ir", "queryFacets", "float1", "sum", false);
+ ArrayList<Double> int1Test = calculateNumberStat(int1TestStart, "sum");
+ assertEquals(responseStr, int1, int1Test);
+ //Int Two
+ ArrayList<Integer> int2 = getValueList(response, "ir", "queryFacets", "float2", "percentile_8", false);
+ ArrayList<Integer> int2Test = (ArrayList<Integer>)calculateStat(int2TestStart, "perc_8");
+ assertEquals(responseStr, int2, int2Test);
+
+ //Long
+ ArrayList<Double> long1 = getValueList(response, "lr", "queryFacets", "string", "median", false);
+ ArrayList<Double> long1Test = calculateNumberStat(longTestStart, "median");
+ assertEquals(responseStr,long1,long1Test);
+
+ //Float
+ ArrayList<Double> float1 = getValueList(response, "fr", "queryFacets", "lad", "mean", false);
+ ArrayList<Double> float1Test = calculateNumberStat(floatTestStart, "mean");
+ assertEquals(responseStr, float1, float1Test);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetTest.java
index f62a82b..e892dc9 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/QueryFacetTest.java
@@ -23,7 +23,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
public class QueryFacetTest extends AbstractAnalyticsFacetTest {
- static String fileName = "/analytics/requestFiles/queryFacets.txt";
+ static String fileName = "queryFacets.txt";
public final int INT = 71;
public final int LONG = 36;
@@ -35,7 +35,7 @@ public class QueryFacetTest extends AbstractAnalyticsFacetTest {
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
}
@SuppressWarnings("unchecked")
@@ -81,13 +81,13 @@ public class QueryFacetTest extends AbstractAnalyticsFacetTest {
if (new Integer(s).toString().charAt(0)=='2') {
longTestStart.get(1).add(l);
}
- if (l>=20) {
+ if (l>=30) {
floatTestStart.get(0).add(f);
}
- if (l>=30) {
+ if (d<=50) {
floatTestStart.get(1).add(f);
}
- if (d<=50) {
+ if (l>=20) {
floatTestStart.get(2).add(f);
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetCloudTest.java
new file mode 100644
index 0000000..880324d
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetCloudTest.java
@@ -0,0 +1,588 @@
+/*
+ * 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.analytics.facet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+public class RangeFacetCloudTest extends AbstractAnalyticsFacetCloudTest{
+ public static final int INT = 71;
+ public static final int LONG = 36;
+ public static final int FLOAT = 93;
+ public static final int DOUBLE = 48;
+ public static final int DATE = 52;
+ public static final int STRING = 28;
+ public static final int NUM_LOOPS = 100;
+
+ //INT
+ static ArrayList<ArrayList<Integer>> intLongTestStart;
+ static ArrayList<ArrayList<Integer>> intDoubleTestStart;
+ static ArrayList<ArrayList<Integer>> intDateTestStart;
+
+ //FLOAT
+ static ArrayList<ArrayList<Float>> floatLongTestStart;
+ static ArrayList<ArrayList<Float>> floatDoubleTestStart;
+ static ArrayList<ArrayList<Float>> floatDateTestStart;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ setupCluster();
+
+ //INT
+ intLongTestStart = new ArrayList<>();
+ intDoubleTestStart = new ArrayList<>();
+ intDateTestStart = new ArrayList<>();
+
+ //FLOAT
+ floatLongTestStart = new ArrayList<>();
+ floatDoubleTestStart = new ArrayList<>();
+ floatDateTestStart = new ArrayList<>();
+
+ UpdateRequest req = new UpdateRequest();
+
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT;
+ long l = j%LONG;
+ float f = j%FLOAT;
+ double d = j%DOUBLE;
+ int dt = j%DATE;
+ int s = j%STRING;
+
+ List<String> fields = new ArrayList<>();
+ fields.add("id"); fields.add("1000"+j);
+ fields.add("int_id"); fields.add("" + i);
+ fields.add("long_ld"); fields.add("" + l);
+ fields.add("float_fd"); fields.add("" + f);
+ fields.add("double_dd"); fields.add("" + d);
+ fields.add("date_dtd"); fields.add((1000+dt) + "-01-01T23:59:59Z");
+ fields.add("string_sd"); fields.add("abc" + s);
+ req.add(fields.toArray(new String[0]));
+
+ //Longs
+ if (j-LONG<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intLongTestStart.add(list1);
+ ArrayList<Float> list2 = new ArrayList<>();
+ list2.add(f);
+ floatLongTestStart.add(list2);
+ } else {
+ intLongTestStart.get((int)l).add(i);
+ floatLongTestStart.get((int)l).add(f);
+ }
+ //Doubles
+ if (j-DOUBLE<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intDoubleTestStart.add(list1);
+ ArrayList<Float> list2 = new ArrayList<>();
+ list2.add(f);
+ floatDoubleTestStart.add(list2);
+ } else {
+ intDoubleTestStart.get((int)d).add(i);
+ floatDoubleTestStart.get((int)d).add(f);
+ }
+ //Dates
+ if (j-DATE<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ list1.add(i);
+ intDateTestStart.add(list1);
+ ArrayList<Float> list2 = new ArrayList<>();
+ list2.add(f);
+ floatDateTestStart.add(list2);
+ } else {
+ intDateTestStart.get(dt).add(i);
+ floatDateTestStart.get(dt).add(f);
+ }
+ }
+
+ req.commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void rangeTest() throws Exception {
+ String[] params = new String[] {
+ "o.ri.s.sum", "sum(int_id)",
+ "o.ri.s.mean", "mean(int_id)",
+ "o.ri.s.median", "median(int_id)",
+ "o.ri.s.count", "count(int_id)",
+ "o.ri.rf", "long_ld",
+ "o.ri.rf.long_ld.st", "5",
+ "o.ri.rf.long_ld.e", "30",
+ "o.ri.rf.long_ld.g", "5",
+ "o.ri.rf.long_ld.ib", "lower",
+ "o.ri.rf.long_ld.or", "all",
+ "o.ri.rf", "double_dd",
+ "o.ri.rf.double_dd.st", "3",
+ "o.ri.rf.double_dd.e", "39",
+ "o.ri.rf.double_dd.g", "7",
+ "o.ri.rf.double_dd.ib", "upper",
+ "o.ri.rf.double_dd.ib", "outer",
+ "o.ri.rf.double_dd.or", "all",
+ "o.ri.rf", "date_dtd",
+ "o.ri.rf.date_dtd.st", "1007-01-01T23:59:59Z",
+ "o.ri.rf.date_dtd.e", "1044-01-01T23:59:59Z",
+ "o.ri.rf.date_dtd.g", "+7YEARS",
+ "o.ri.rf.date_dtd.ib", "lower",
+ "o.ri.rf.date_dtd.ib", "edge",
+ "o.ri.rf.date_dtd.ib", "outer",
+ "o.ri.rf.date_dtd.or", "all",
+
+ "o.rf.s.sum", "sum(float_fd)",
+ "o.rf.s.mean", "mean(float_fd)",
+ "o.rf.s.median", "median(float_fd)",
+ "o.rf.s.count", "count(float_fd)",
+ "o.rf.rf", "long_ld",
+ "o.rf.rf.long_ld.st", "0",
+ "o.rf.rf.long_ld.e", "29",
+ "o.rf.rf.long_ld.g", "4",
+ "o.rf.rf.long_ld.ib", "all",
+ "o.rf.rf.long_ld.or", "all",
+ "o.rf.rf", "double_dd",
+ "o.rf.rf.double_dd.st", "4",
+ "o.rf.rf.double_dd.e", "47",
+ "o.rf.rf.double_dd.g", "11",
+ "o.rf.rf.double_dd.ib", "edge",
+ "o.rf.rf.double_dd.or", "all",
+ "o.rf.rf", "date_dtd",
+ "o.rf.rf.date_dtd.st", "1004-01-01T23:59:59Z",
+ "o.rf.rf.date_dtd.e", "1046-01-01T23:59:59Z",
+ "o.rf.rf.date_dtd.g", "+5YEARS",
+ "o.rf.rf.date_dtd.ib", "upper",
+ "o.rf.rf.date_dtd.ib", "edge",
+ "o.rf.rf.date_dtd.or", "all"
+ };
+
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Long
+ ArrayList<Long> intLong = getValueList(response, "ri", "rangeFacets", "long_ld", "count", false);
+ ArrayList<Long> intLongTest = calculateStat(transformLists(intLongTestStart, 5, 30, 5
+ , false, true, false, false, false), "count");
+ assertEquals(responseStr, intLong,intLongTest);
+ //Int Double
+ ArrayList<Double> intDouble = getValueList(response, "ri", "rangeFacets", "double_dd", "mean", false);
+ ArrayList<Double> intDoubleTest = calculateNumberStat(transformLists(intDoubleTestStart, 3, 39, 7
+ , false, false, true, false, true), "mean");
+ assertEquals(responseStr, intDouble,intDoubleTest);
+ //Int Date
+ ArrayList<Long> intDate = getValueList(response, "ri", "rangeFacets", "date_dtd", "count", false);
+ ArrayList<Long> intDateTest = (ArrayList<Long>)calculateStat(transformLists(intDateTestStart, 7, 44, 7
+ , false, true, false, true, true), "count");
+ assertEquals(responseStr, intDate,intDateTest);
+
+ //Float Long
+ ArrayList<Double> floatLong = getValueList(response, "rf", "rangeFacets", "long_ld", "median", false);
+ ArrayList<Double> floatLongTest = calculateNumberStat(transformLists(floatLongTestStart, 0, 29, 4
+ , false, true, true, true, true), "median");
+ assertEquals(responseStr, floatLong,floatLongTest);
+ //Float Double
+ ArrayList<Long> floatDouble = getValueList(response, "rf", "rangeFacets", "double_dd", "count", false);
+ ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, 11
+ , false, false, false, true, false), "count");
+ assertEquals(responseStr, floatDouble,floatDoubleTest);
+ }
+
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void hardendRangeTest() throws Exception {
+ String[] params = new String[] {
+ "o.hi.s.sum", "sum(int_id)",
+ "o.hi.s.mean", "mean(int_id)",
+ "o.hi.s.median", "median(int_id)",
+ "o.hi.s.count", "count(int_id)",
+ "o.hi.rf", "long_ld",
+ "o.hi.rf.long_ld.st", "5",
+ "o.hi.rf.long_ld.e", "30",
+ "o.hi.rf.long_ld.g", "5",
+ "o.hi.rf.long_ld.he", "true",
+ "o.hi.rf.long_ld.ib", "lower",
+ "o.hi.rf.long_ld.or", "all",
+ "o.hi.rf", "double_dd",
+ "o.hi.rf.double_dd.st", "3",
+ "o.hi.rf.double_dd.e", "39",
+ "o.hi.rf.double_dd.g", "7",
+ "o.hi.rf.double_dd.he", "true",
+ "o.hi.rf.double_dd.ib", "upper",
+ "o.hi.rf.double_dd.ib", "outer",
+ "o.hi.rf.double_dd.or", "all",
+ "o.hi.rf", "date_dtd",
+ "o.hi.rf.date_dtd.st", "1007-01-01T23:59:59Z",
+ "o.hi.rf.date_dtd.e", "1044-01-01T23:59:59Z",
+ "o.hi.rf.date_dtd.g", "+7YEARS",
+ "o.hi.rf.date_dtd.he", "true",
+ "o.hi.rf.date_dtd.ib", "lower",
+ "o.hi.rf.date_dtd.ib", "edge",
+ "o.hi.rf.date_dtd.ib", "outer",
+ "o.hi.rf.date_dtd.or", "all",
+
+ "o.hf.s.sum", "sum(float_fd)",
+ "o.hf.s.mean", "mean(float_fd)",
+ "o.hf.s.median", "median(float_fd)",
+ "o.hf.s.count", "count(float_fd)",
+ "o.hf.rf", "long_ld",
+ "o.hf.rf.long_ld.st", "0",
+ "o.hf.rf.long_ld.e", "29",
+ "o.hf.rf.long_ld.g", "4",
+ "o.hf.rf.long_ld.he", "true",
+ "o.hf.rf.long_ld.ib", "all",
+ "o.hf.rf.long_ld.or", "all",
+ "o.hf.rf", "double_dd",
+ "o.hf.rf.double_dd.st", "4",
+ "o.hf.rf.double_dd.e", "47",
+ "o.hf.rf.double_dd.g", "11",
+ "o.hf.rf.double_dd.he", "true",
+ "o.hf.rf.double_dd.ib", "edge",
+ "o.hf.rf.double_dd.or", "all",
+ "o.hf.rf", "date_dtd",
+ "o.hf.rf.date_dtd.st", "1004-01-01T23:59:59Z",
+ "o.hf.rf.date_dtd.e", "1046-01-01T23:59:59Z",
+ "o.hf.rf.date_dtd.g", "+5YEARS",
+ "o.hf.rf.date_dtd.he", "true",
+ "o.hf.rf.date_dtd.ib", "upper",
+ "o.hf.rf.date_dtd.ib", "edge",
+ "o.hf.rf.date_dtd.or", "all"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Long
+ ArrayList<Double> intLong = getValueList(response, "hi", "rangeFacets", "long_ld", "sum", false);
+ ArrayList<Double> intLongTest = calculateNumberStat(transformLists(intLongTestStart, 5, 30, 5
+ , true, true, false, false, false), "sum");
+ assertEquals(responseStr, intLong,intLongTest);
+ //Int Double
+ ArrayList<Double> intDouble = getValueList(response, "hi", "rangeFacets", "double_dd", "mean", false);
+ ArrayList<Double> intDoubleTest = calculateNumberStat(transformLists(intDoubleTestStart, 3, 39, 7
+ , true, false, true, false, true), "mean");
+ assertEquals(responseStr, intDouble,intDoubleTest);
+ //Int Date
+ ArrayList<Long> intDate = getValueList(response, "hi", "rangeFacets", "date_dtd", "count", false);
+ ArrayList<Long> intDateTest = (ArrayList<Long>)calculateStat(transformLists(intDateTestStart, 7, 44, 7
+ , true, true, false, true, true), "count");
+ assertEquals(responseStr, intDate,intDateTest);
+
+ //Float Long
+ ArrayList<Double> floatLong = getValueList(response, "hf", "rangeFacets", "long_ld", "median", false);
+ ArrayList<Double> floatLongTest = calculateNumberStat(transformLists(floatLongTestStart, 0, 29, 4
+ , true, true, true, true, true), "median");
+ assertEquals(responseStr, floatLong,floatLongTest);
+ //Float Double
+ ArrayList<Long> floatDouble = getValueList(response, "hf", "rangeFacets", "double_dd", "count", false);
+ ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, 11
+ , true, false, false, true, false), "count");
+ assertEquals(responseStr, floatDouble,floatDoubleTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void multiGapTest() throws Exception {
+ String[] params = new String[] {
+ "o.mi.s.sum", "sum(int_id)",
+ "o.mi.s.mean", "mean(int_id)",
+ "o.mi.s.median", "median(int_id)",
+ "o.mi.s.count", "count(int_id)",
+ "o.mi.rf", "long_ld",
+ "o.mi.rf.long_ld.st", "5",
+ "o.mi.rf.long_ld.e", "30",
+ "o.mi.rf.long_ld.g", "4,2,6,3",
+ "o.mi.rf.long_ld.ib", "lower",
+ "o.mi.rf.long_ld.or", "all",
+ "o.mi.rf", "double_dd",
+ "o.mi.rf.double_dd.st", "3",
+ "o.mi.rf.double_dd.e", "39",
+ "o.mi.rf.double_dd.g", "3,1,7",
+ "o.mi.rf.double_dd.ib", "upper",
+ "o.mi.rf.double_dd.ib", "outer",
+ "o.mi.rf.double_dd.or", "all",
+ "o.mi.rf", "date_dtd",
+ "o.mi.rf.date_dtd.st", "1007-01-01T23:59:59Z",
+ "o.mi.rf.date_dtd.e", "1044-01-01T23:59:59Z",
+ "o.mi.rf.date_dtd.g", "+2YEARS,+7YEARS",
+ "o.mi.rf.date_dtd.ib", "lower",
+ "o.mi.rf.date_dtd.ib", "edge",
+ "o.mi.rf.date_dtd.ib", "outer",
+ "o.mi.rf.date_dtd.or", "all",
+
+ "o.mf.s.sum", "sum(float_fd)",
+ "o.mf.s.mean", "mean(float_fd)",
+ "o.mf.s.median", "median(float_fd)",
+ "o.mf.s.count", "count(float_fd)",
+ "o.mf.rf", "long_ld",
+ "o.mf.rf.long_ld.st", "0",
+ "o.mf.rf.long_ld.e", "29",
+ "o.mf.rf.long_ld.g", "1,4",
+ "o.mf.rf.long_ld.ib", "all",
+ "o.mf.rf.long_ld.or", "all",
+ "o.mf.rf", "double_dd",
+ "o.mf.rf.double_dd.st", "4",
+ "o.mf.rf.double_dd.e", "47",
+ "o.mf.rf.double_dd.g", "2,3,11",
+ "o.mf.rf.double_dd.ib", "edge",
+ "o.mf.rf.double_dd.or", "all",
+ "o.mf.rf", "date_dtd",
+ "o.mf.rf.date_dtd.st", "1004-01-01T23:59:59Z",
+ "o.mf.rf.date_dtd.e", "1046-01-01T23:59:59Z",
+ "o.mf.rf.date_dtd.g", "+4YEARS,+5YEARS",
+ "o.mf.rf.date_dtd.ib", "upper",
+ "o.mf.rf.date_dtd.ib", "edge",
+ "o.mf.rf.date_dtd.or", "all"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Long
+ ArrayList<Double> intLong = getValueList(response, "mi", "rangeFacets", "long_ld", "sum", false);
+ ArrayList<Double> intLongTest = calculateNumberStat(transformLists(intLongTestStart, 5, 30, "4,2,6,3"
+ , false, true, false, false, false), "sum");
+ assertEquals(responseStr, intLong,intLongTest);
+ //Int Double
+ ArrayList<Double> intDouble = getValueList(response, "mi", "rangeFacets", "double_dd", "mean", false);
+ ArrayList<Double> intDoubleTest = calculateNumberStat(transformLists(intDoubleTestStart, 3, 39, "3,1,7"
+ , false, false, true, false, true), "mean");
+ assertEquals(responseStr, intDouble,intDoubleTest);
+ //Int Date
+ ArrayList<Long> intDate = getValueList(response, "mi", "rangeFacets", "date_dtd", "count", false);
+ ArrayList<Long> intDateTest = (ArrayList<Long>)calculateStat(transformLists(intDateTestStart, 7, 44, "2,7"
+ , false, true, false, true, true), "count");
+ assertEquals(responseStr, intDate,intDateTest);
+
+ //Float Long
+ ArrayList<Double> floatLong = getValueList(response, "mf", "rangeFacets", "long_ld", "median", false);
+ ArrayList<Double> floatLongTest = calculateNumberStat(transformLists(floatLongTestStart, 0, 29, "1,4"
+ , false, true, true, true, true), "median");;
+ assertEquals(responseStr, floatLong,floatLongTest);
+ //Float Double
+ ArrayList<Long> floatDouble = getValueList(response, "mf", "rangeFacets", "double_dd", "count", false);
+ ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, "2,3,11"
+ , false, false, false, true, false), "count");
+ assertEquals(responseStr, floatDouble,floatDoubleTest);
+ }
+
+ private <T> ArrayList<ArrayList<T>> transformLists(ArrayList<ArrayList<T>> listsStart, int start, int end, int gap
+ , boolean hardend, boolean incLow, boolean incUp, boolean incEdge, boolean incOut) {
+ int off = (end-start)%gap;
+ if (!hardend && off>0) {
+ end+=gap-off;
+ }
+
+ ArrayList<ArrayList<T>> lists = new ArrayList<>();
+ ArrayList<T> between = new ArrayList<>();
+ if (incLow && incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i; j<=i+gap && j<=end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start; i<listsStart.size() && i<=end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else if (incLow && !incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i; j<i+gap && j<end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start; i<listsStart.size() && i<end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else if (!incLow && incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i+1; j<=i+gap && j<=end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start+1; i<listsStart.size() && i<=end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i+1; j<i+gap && j<end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start+1; i<listsStart.size() && i<end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ }
+
+ if (incEdge && !incLow && start>=0) {
+ lists.get(0).addAll(listsStart.get(start));
+ between.addAll(listsStart.get(start));
+ }
+ if (incEdge && !incUp && end<listsStart.size()) {
+ lists.get(lists.size()-1).addAll(listsStart.get(end));
+ between.addAll(listsStart.get(end));
+ }
+ ArrayList<T> before = new ArrayList<>();
+ ArrayList<T> after = new ArrayList<>();
+ if (incOut || !(incLow||incEdge)) {
+ for (int i = 0; i<=start; i++) {
+ before.addAll(listsStart.get(i));
+ }
+ } else {
+ for (int i = 0; i<start; i++) {
+ before.addAll(listsStart.get(i));
+ }
+ }
+ if (incOut || !(incUp||incEdge)) {
+ for (int i = end; i<listsStart.size(); i++) {
+ after.addAll(listsStart.get(i));
+ }
+ }
+ else {
+ for (int i = end+1; i<listsStart.size(); i++) {
+ after.addAll(listsStart.get(i));
+ }
+ }
+ lists.add(before);
+ lists.add(after);
+ lists.add(between);
+ return lists;
+ }
+
+ private <T> ArrayList<ArrayList<T>> transformLists(ArrayList<ArrayList<T>> listsStart, int start, int end, String gapString
+ , boolean hardend, boolean incLow, boolean incUp, boolean incEdge, boolean incOut) {
+ String[] stringGaps = gapString.split(",");
+ int[] gaps = new int[stringGaps.length];
+ for (int i = 0; i<gaps.length; i++) {
+ gaps[i] = Integer.parseInt(stringGaps[i]);
+ }
+ int bigGap = 0;
+ int last = gaps[gaps.length-1];
+ for (int i = 0; i<gaps.length-1; i++) {
+ bigGap += gaps[i];
+ }
+ int off = (end-start-bigGap)%last;
+ if (!hardend && off>0) {
+ end+=last-off;
+ }
+
+ ArrayList<ArrayList<T>> lists = new ArrayList<>();
+ ArrayList<T> between = new ArrayList<>();
+ int gap = 0;
+ int gapCounter = 0;
+ if (incLow && incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ if (gapCounter<gaps.length) {
+ gap = gaps[gapCounter++];
+ }
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i; j<=i+gap && j<=end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start; i<listsStart.size() && i<=end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else if (incLow && !incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ if (gapCounter<gaps.length) {
+ gap = gaps[gapCounter++];
+ }
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i; j<i+gap && j<end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start; i<listsStart.size() && i<end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else if (!incLow && incUp) {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ if (gapCounter<gaps.length) {
+ gap = gaps[gapCounter++];
+ }
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i+1; j<=i+gap && j<=end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start+1; i<listsStart.size() && i<=end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ } else {
+ for (int i = start; i<end && i<listsStart.size(); i+=gap) {
+ if (gapCounter<gaps.length) {
+ gap = gaps[gapCounter++];
+ }
+ ArrayList<T> list = new ArrayList<>();
+ for (int j = i+1; j<i+gap && j<end && j<listsStart.size(); j++) {
+ list.addAll(listsStart.get(j));
+ }
+ lists.add(list);
+ }
+ for (int i = start+1; i<listsStart.size() && i<end; i++) {
+ between.addAll(listsStart.get(i));
+ }
+ }
+
+ if (incEdge && !incLow && start>=0) {
+ lists.get(0).addAll(listsStart.get(start));
+ between.addAll(listsStart.get(start));
+ }
+ if (incEdge && !incUp && end<listsStart.size()) {
+ lists.get(lists.size()-1).addAll(listsStart.get(end));
+ between.addAll(listsStart.get(end));
+ }
+ ArrayList<T> before = new ArrayList<>();
+ ArrayList<T> after = new ArrayList<>();
+ if (incOut || !(incLow||incEdge)) {
+ for (int i = 0; i<=start; i++) {
+ before.addAll(listsStart.get(i));
+ }
+ } else {
+ for (int i = 0; i<start; i++) {
+ before.addAll(listsStart.get(i));
+ }
+ }
+ if (incOut || !(incUp||incEdge)) {
+ for (int i = end; i<listsStart.size(); i++) {
+ after.addAll(listsStart.get(i));
+ }
+ }
+ else {
+ for (int i = end+1; i<listsStart.size(); i++) {
+ after.addAll(listsStart.get(i));
+ }
+ }
+ lists.add(before);
+ lists.add(after);
+ lists.add(between);
+ return lists;
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetTest.java
index cda8202..24a7ea2 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/RangeFacetTest.java
@@ -24,7 +24,7 @@ import org.junit.Test;
public class RangeFacetTest extends AbstractAnalyticsFacetTest {
- static String fileName = "/analytics/requestFiles/rangeFacets.txt";
+ static String fileName = "rangeFacets.txt";
public static final int INT = 71;
public static final int LONG = 36;
@@ -46,7 +46,7 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
h.update("<delete><query>*:*</query></delete>");
//INT
@@ -145,11 +145,6 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, 11
, false, false, false, true, false), "count");
assertEquals(getRawResponse(), floatDouble,floatDoubleTest);
- //Float Date
- ArrayList<Double> floatDate = getDoubleList("rf", "rangeFacets", "date_dtd", "double", "sumOfSquares");
- ArrayList<Double> floatDateTest = calculateNumberStat(transformLists(floatDateTestStart, 4, 46, 5
- , false, false, true, true, false), "sumOfSquares");
- assertEquals(getRawResponse(), floatDate,floatDateTest);
}
@@ -182,11 +177,6 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, 11
, true, false, false, true, false), "count");
assertEquals(getRawResponse(), floatDouble,floatDoubleTest);
- //Float Date
- ArrayList<Double> floatDate = getDoubleList("hf", "rangeFacets", "date_dtd", "double", "sumOfSquares");
- ArrayList<Double> floatDateTest = calculateNumberStat(transformLists(floatDateTestStart, 4, 46, 5
- , true, false, true, true, false), "sumOfSquares");
- assertEquals(getRawResponse(), floatDate,floatDateTest);
}
@SuppressWarnings("unchecked")
@@ -218,11 +208,6 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
ArrayList<Long> floatDoubleTest = (ArrayList<Long>)calculateStat(transformLists(floatDoubleTestStart, 4, 47, "2,3,11"
, false, false, false, true, false), "count");
assertEquals(getRawResponse(), floatDouble,floatDoubleTest);
- //Float Date
- ArrayList<Double> floatDate = getDoubleList("mf", "rangeFacets", "date_dtd", "double", "sumOfSquares");
- ArrayList<Double> floatDateTest = calculateNumberStat(transformLists(floatDateTestStart, 4, 46, "4,5"
- , false, false, true, true, false), "sumOfSquares");
- assertEquals(getRawResponse(), floatDate,floatDateTest);
}
private <T> ArrayList<ArrayList<T>> transformLists(ArrayList<ArrayList<T>> listsStart, int start, int end, int gap
@@ -309,15 +294,9 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
after.addAll(listsStart.get(i));
}
}
- if (before.size()>0) {
- lists.add(before);
- }
- if (after.size()>0) {
- lists.add(after);
- }
- if (between.size()>0) {
- lists.add(between);
- }
+ lists.add(before);
+ lists.add(after);
+ lists.add(between);
return lists;
}
@@ -429,15 +408,9 @@ public class RangeFacetTest extends AbstractAnalyticsFacetTest {
after.addAll(listsStart.get(i));
}
}
- if (before.size()>0) {
- lists.add(before);
- }
- if (after.size()>0) {
- lists.add(after);
- }
- if (between.size()>0) {
- lists.add(between);
- }
+ lists.add(before);
+ lists.add(after);
+ lists.add(between);
return lists;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/util/valuesource/FunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/util/valuesource/FunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/util/valuesource/FunctionTest.java
deleted file mode 100644
index 5981cc0..0000000
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/util/valuesource/FunctionTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-
-import org.apache.solr.analytics.AbstractAnalyticsStatsTest;
-import org.apache.solr.analytics.facet.AbstractAnalyticsFacetTest;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class FunctionTest extends AbstractAnalyticsStatsTest {
- static String fileName = "/analytics/requestFiles/functions.txt";
-
- static public final int INT = 71;
- static public final int LONG = 36;
- static public final int FLOAT = 93;
- static public final int DOUBLE = 49;
- static public final int DATE = 12;
- static public final int STRING = 28;
- static public final int NUM_LOOPS = 100;
-
- @BeforeClass
- public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
- h.update("<delete><query>*:*</query></delete>");
-
- for (int j = 0; j < NUM_LOOPS; ++j) {
- int i = j%INT+1;
- long l = j%LONG+1;
- float f = j%FLOAT+1;
- double d = j%DOUBLE+1;
- double d0 = j%DOUBLE;
- String dt = (1800+j%DATE) + "-06-30T23:59:59Z";
- String s = "str" + (j%STRING);
-
- double add_if = (double)i+f;
- double add_ldf = (double)l+d+f;
- double mult_if = (double)i*f;
- double mult_ldf = (double)l*d*f;
- double div_if = (double)i/f;
- double div_ld = (double)l/d;
- double pow_if = Math.pow(i,f);
- double pow_ld = Math.pow(l,d);
- double neg_i = (double)i*-1;
- double neg_l = (double)l*-1;
- String dm_2y = (1802+j%DATE) + "-06-30T23:59:59Z";
- String dm_2m = (1800+j%DATE) + "-08-30T23:59:59Z";
- String concat_first = "this is the first"+s;
- String concat_second = "this is the second"+s;
- String rev = new StringBuilder(s).reverse().toString();
-
- assertU(adoc(AbstractAnalyticsFacetTest.filter("id", "1000" + j, "int_id", "" + i, "long_ld", "" + l, "float_fd", "" + f,
- "double_dd", "" + d, "date_dtd", dt, "string_sd", s,
- "add_if_dd", ""+add_if, "add_ldf_dd", ""+add_ldf, "mult_if_dd", ""+mult_if, "mult_ldf_dd", ""+mult_ldf,
- "div_if_dd", ""+div_if, "div_ld_dd", ""+div_ld, "pow_if_dd", ""+pow_if, "pow_ld_dd", ""+pow_ld,
- "neg_i_dd", ""+neg_i, "neg_l_dd", ""+neg_l, "const_8_dd", "8", "const_10_dd", "10", "dm_2y_dtd", dm_2y, "dm_2m_dtd", dm_2m,
- "const_00_dtd", "1800-06-30T23:59:59Z", "const_04_dtd", "1804-06-30T23:59:59Z", "const_first_sd", "this is the first", "const_second_sd", "this is the second",
- "concat_first_sd", concat_first, "concat_second_sd", concat_second, "rev_sd", rev, "miss_dd", ""+d0 )));
-
-
- if (usually()) {
- assertU(commit()); // to have several segments
- }
- }
-
- assertU(commit());
-
- setResponse(h.query(request(fileToStringArr(FunctionTest.class, fileName))));
- }
-
- @Test
- public void addTest() throws Exception {
- double result = (Double)getStatResult("ar", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("ar", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- // TODO checfk why asserted 2times
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("ar", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("ar", "meanc", VAL_TYPE.DOUBLE);
- assertTrue(result==calculated);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void multiplyTest() throws Exception {
- double result = (Double)getStatResult("mr", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("mr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("mr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("mr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void divideTest() throws Exception {
- Double result = (Double)getStatResult("dr", "sum", VAL_TYPE.DOUBLE);
- Double calculated = (Double)getStatResult("dr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("dr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("dr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void powerTest() throws Exception {
- double result = (Double)getStatResult("pr", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("pr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("pr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("pr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void negateTest() throws Exception {
- double result = (Double)getStatResult("nr", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("nr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("nr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("nr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void absoluteValueTest() throws Exception {
- double result = (Double)getStatResult("avr", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("avr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("avr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("avr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void constantNumberTest() throws Exception {
- double result = (Double)getStatResult("cnr", "sum", VAL_TYPE.DOUBLE);
- double calculated = (Double)getStatResult("cnr", "sumc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- assertEquals(getRawResponse(), result, calculated, 0.0);
-
- result = (Double)getStatResult("cnr", "mean", VAL_TYPE.DOUBLE);
- calculated = (Double)getStatResult("cnr", "meanc", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- assertEquals(getRawResponse(), result, calculated, 0.0);
- }
-
- @Test
- public void dateMathTest() throws Exception {
- String result = (String)getStatResult("dmr", "median", VAL_TYPE.DATE);
- String calculated = (String)getStatResult("dmr", "medianc", VAL_TYPE.DATE);
- assertEquals(getRawResponse(), result, calculated);
-
- result = (String)getStatResult("dmr", "max", VAL_TYPE.DATE);
- calculated = (String)getStatResult("dmr", "maxc", VAL_TYPE.DATE);
- assertEquals(getRawResponse(), result, calculated);
- }
-
- @Test
- public void constantDateTest() throws Exception {
- String result = (String)getStatResult("cdr", "median", VAL_TYPE.DATE);
- String calculated = (String)getStatResult("cdr", "medianc", VAL_TYPE.DATE);
- assertEquals(getRawResponse(), result, calculated);
- assertEquals(getRawResponse(), result, calculated);
-
- result = (String)getStatResult("cdr", "max", VAL_TYPE.DATE);
- calculated = (String)getStatResult("cdr", "maxc", VAL_TYPE.DATE);
- assertEquals(getRawResponse(), result, calculated);
- }
-
- @Test
- public void constantStringTest() throws Exception {
- String result = (String)getStatResult("csr", "min", VAL_TYPE.STRING);
- String calculated = (String)getStatResult("csr", "minc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
-
- result = (String)getStatResult("csr", "max", VAL_TYPE.STRING);
- calculated = (String)getStatResult("csr", "maxc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
- }
-
- @Test
- public void concatenateTest() throws Exception {
- String result = (String)getStatResult("cr", "min", VAL_TYPE.STRING);
- String calculated = (String)getStatResult("cr", "minc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
-
- result = (String)getStatResult("cr", "max", VAL_TYPE.STRING);
- calculated = (String)getStatResult("cr", "maxc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
- }
-
- @Test
- public void reverseTest() throws Exception {
- String result = (String)getStatResult("rr", "min", VAL_TYPE.STRING);
- String calculated = (String)getStatResult("rr", "minc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
-
- result = (String)getStatResult("rr", "max", VAL_TYPE.STRING);
- calculated = (String)getStatResult("rr", "maxc", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), result, calculated);
- }
-
- @Test
- public void missingTest() throws Exception {
- double min = (Double)getStatResult("ms", "min", VAL_TYPE.DOUBLE);
- double max = (Double)getStatResult("ms", "max", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), 48.0d, max, 0.0);
- assertEquals(getRawResponse(), 1.0d, min, 0.0);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
index e5eaff9..8e9477b 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
@@ -60,6 +60,7 @@ public class ResponseBuilder
public boolean doExpand;
public boolean doStats;
public boolean doTerms;
+ public boolean doAnalytics;
public MergeStrategy mergeFieldHandler;
private boolean needDocList = false;
@@ -173,6 +174,8 @@ public class ResponseBuilder
StatsInfo _statsInfo;
TermsComponent.TermsHelper _termsHelper;
SimpleOrderedMap<List<NamedList<Object>>> _pivots;
+ Object _analyticsRequestManager;
+ boolean _isOlapAnalytics;
// Context fields for grouping
public final Map<String, Collection<SearchGroup<BytesRef>>> mergedSearchGroups = new HashMap<>();
[05/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValue.java
new file mode 100644
index 0000000..54a3003
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValue.java
@@ -0,0 +1,55 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+
+/**
+ * A single-valued analytics value.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getObject()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface AnalyticsValue extends AnalyticsValueStream {
+ /**
+ * Check whether the current value exists.
+ * <br>
+ * NOTE: The result of this method is only guaranteed after any {@code get<Type>()} method is called.
+ *
+ * @return whether the current value exists
+ */
+ boolean exists();
+ /**
+ * Get the object representation of the current value.
+ *
+ * @return the current value
+ */
+ Object getObject();
+
+ /**
+ * An abstract base for {@link AnalyticsValue} that automatically casts to castable types.
+ */
+ public static abstract class AbstractAnalyticsValue implements AnalyticsValue {
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object value = getObject();
+ if (exists()) {
+ cons.accept(value);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValueStream.java
new file mode 100644
index 0000000..0c02115
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/AnalyticsValueStream.java
@@ -0,0 +1,133 @@
+/*
+ * 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.analytics.value;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A multi-valued analytics value, the super-type of all Analytics value types.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamObjects},
+ * resulting in different values on each call.
+ */
+public interface AnalyticsValueStream {
+ /**
+ * Get the name of function or value.
+ *
+ * @return the name of function/value
+ */
+ String getName();
+ /**
+ * Get the expression string of the analytics value stream. Must be unique to the expression.
+ * If passed to {@link ExpressionFactory#createExpression(String)}, the exact same expression should be created.
+ *
+ * @return the name of function/value
+ */
+ String getExpressionStr();
+ /**
+ * Stream the object representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamObjects(Consumer<Object> cons);
+
+ /**
+ * The types of expressions.
+ */
+ static enum ExpressionType {
+ CONST (true, true),
+ FIELD (true, false),
+ UNREDUCED_MAPPING (true, false),
+ REDUCTION (false, true),
+ REDUCED_MAPPING (false, true);
+
+ private final boolean unreduced;
+ private final boolean reduced;
+
+ ExpressionType(boolean unreduced, boolean reduced) {
+ this.unreduced = unreduced;
+ this.reduced = reduced;
+ }
+
+ public boolean isUnreduced() {
+ return unreduced;
+ }
+ public boolean isReduced() {
+ return reduced;
+ }
+ }
+
+ /**
+ * Get the type of the expression that this class represents.
+ *
+ * @return the expression type
+ */
+ ExpressionType getExpressionType();
+
+ /**
+ * Helper to create an expression string for a function.
+ *
+ * @param funcName the name of the function
+ * @param params the parameters of the function
+ * @return a valid expression string for the function.
+ */
+ static String createExpressionString(String funcName,
+ AnalyticsValueStream... params) {
+ return String.format(Locale.ROOT, "%s(%s)",
+ funcName,
+ Arrays.stream(params).
+ map(param -> param.getExpressionStr()).
+ reduce((a, b) -> a + "," + b).orElseGet(() -> ""));
+ }
+
+ /**
+ * Determine whether the expression is a unreduced mapping expression, a reduced mapping expression, or a constant.
+ *
+ * @param exprString the string representing the expression, used when creating exceptions
+ * @param params the parameters
+ * @return the expression type
+ * @throws SolrException if the params are incompatable types,
+ * for example if reduced and unreduced params are both included
+ */
+ static ExpressionType determineMappingPhase(String exprString, AnalyticsValueStream... params) throws SolrException {
+ boolean unreduced = true;
+ boolean reduced = true;
+ for (AnalyticsValueStream param : params) {
+ unreduced &= param.getExpressionType().isUnreduced();
+ reduced &= param.getExpressionType().isReduced();
+ }
+ if (unreduced && reduced) {
+ return ExpressionType.CONST;
+ }
+ else if (unreduced) {
+ return ExpressionType.UNREDUCED_MAPPING;
+ }
+ else if (reduced) {
+ return ExpressionType.REDUCED_MAPPING;
+ }
+ else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following expression contains incorrect parameters. " +
+ "(ReductionFunctions cannot be in the paramters of other ReductionFunctions): " + exprString);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValue.java
new file mode 100644
index 0000000..5d58a8b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValue.java
@@ -0,0 +1,85 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+/**
+ * A single-valued analytics value that can be represented as a boolean.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getBoolean()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface BooleanValue extends BooleanValueStream, AnalyticsValue {
+ /**
+ * Get the boolean representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ boolean getBoolean();
+
+ /**
+ * An interface that represents all of the types a {@link BooleanValue} should be able to cast to.
+ */
+ public static interface CastingBooleanValue extends BooleanValue, StringValue, ComparableValue {}
+
+ /**
+ * An abstract base for {@link CastingBooleanValue} that automatically casts to all types if {@link #getBoolean()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractBooleanValue implements CastingBooleanValue {
+ @Override
+ public String getString() {
+ boolean val = getBoolean();
+ return exists() ? Boolean.toString(val) : null;
+ }
+ @Override
+ public Object getObject() {
+ boolean val = getBoolean();
+ return exists() ? val : null;
+ }
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean val = getBoolean();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Boolean> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValueStream.java
new file mode 100644
index 0000000..0827aea
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/BooleanValueStream.java
@@ -0,0 +1,55 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a boolean.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamBooleans},
+ * resulting in different values on each call.
+ */
+public interface BooleanValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the boolean representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamBooleans(BooleanConsumer cons);
+
+ /**
+ * An interface that represents all of the types a {@link BooleanValueStream} should be able to cast to.
+ */
+ public static interface CastingBooleanValueStream extends BooleanValueStream, StringValueStream {}
+
+ /**
+ * An abstract base for {@link CastingBooleanValueStream} that automatically casts to all types if {@link #streamBooleans} is implemented.
+ */
+ public static abstract class AbstractBooleanValueStream implements CastingBooleanValueStream {
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamBooleans((boolean val) -> cons.accept(Boolean.toString(val)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamBooleans((boolean val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/ComparableValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/ComparableValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/ComparableValue.java
new file mode 100644
index 0000000..93cae48
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/ComparableValue.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.value;
+
+import org.apache.solr.analytics.facet.compare.FacetResultsComparator;
+
+/**
+ * A single-valued analytics value that can be compared and used to sort a facet.
+ */
+public interface ComparableValue extends AnalyticsValue {
+ /**
+ * Create an entry comparator used to sort the facet-value buckets of a facet.
+ *
+ * @param expression the name of the expression in the results array
+ * @return a comparator to sort the buckets with
+ */
+ FacetResultsComparator getObjectComparator(String expression);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValue.java
new file mode 100644
index 0000000..b105d58
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValue.java
@@ -0,0 +1,102 @@
+/*
+ * 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.analytics.value;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+
+/**
+ * A single-valued analytics value that can be represented as a date.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getDate()} and {@link #exists()},
+ * resulting in different values on each call.
+ * <p>
+ * NOTE: Most date expressions work with the {@code long} representation of the date, so that less
+ * objects need to be created during execution.
+ */
+public interface DateValue extends DateValueStream, LongValue {
+ /**
+ * Get the date representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ Date getDate();
+
+ /**
+ * An interface that represents all of the types a {@link DateValue} should be able to cast to.
+ */
+ public static interface CastingDateValue extends DateValue, LongValue, StringValue, ComparableValue {}
+
+ /**
+ * An abstract base for {@link CastingDateValue} that automatically casts to all types if {@link #getLong()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractDateValue implements CastingDateValue {
+ @Override
+ public Date getDate() {
+ long val = getLong();
+ return exists() ? new Date(val) : null;
+ }
+ @Override
+ public String getString() {
+ long val = getLong();
+ return exists() ? Instant.ofEpochMilli(val).toString() : null;
+ }
+ @Override
+ public Object getObject() {
+ long val = getLong();
+ return exists() ? new Date(val) : null;
+ }
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ Date val = getDate();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long val = getLong();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Date> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValueStream.java
new file mode 100644
index 0000000..f709264
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DateValueStream.java
@@ -0,0 +1,62 @@
+/*
+ * 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.analytics.value;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a date.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamDates},
+ * resulting in different values on each call.
+ * <p>
+ * NOTE: Most date expressions work with the {@code long} representation of the date, so that less
+ * objects need to be created during execution.
+ */
+public interface DateValueStream extends LongValueStream {
+ /**
+ * Stream the date representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamDates(Consumer<Date> cons);
+
+ /**
+ * An interface that represents all of the types a {@link DateValueStream} should be able to cast to.
+ */
+ public static interface CastingDateValueStream extends DateValueStream, LongValueStream, StringValueStream {}
+
+ /**
+ * An abstract base for {@link CastingDateValueStream} that automatically casts to all types if {@link #streamLongs} is implemented.
+ */
+ public static abstract class AbstractDateValueStream implements CastingDateValueStream {
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ streamLongs((long val) -> cons.accept(new Date(val)));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs((long val) -> cons.accept(Instant.ofEpochMilli(val).toString()));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs((long val) -> cons.accept(new Date(val)));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValue.java
new file mode 100644
index 0000000..ba527f0
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValue.java
@@ -0,0 +1,86 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+
+/**
+ * A single-valued analytics value that can be represented as a date.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getDouble()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface DoubleValue extends DoubleValueStream, AnalyticsValue {
+ /**
+ * Get the double representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ double getDouble();
+
+ /**
+ * An interface that represents all of the types a {@link DoubleValue} should be able to cast to.
+ */
+ public static interface CastingDoubleValue extends DoubleValue, StringValue, ComparableValue {}
+
+
+ /**
+ * An abstract base for {@link CastingDoubleValue} that automatically casts to all types if {@link #getDouble()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractDoubleValue implements CastingDoubleValue {
+ @Override
+ public String getString() {
+ double val = getDouble();
+ return exists() ? Double.toString(val) : null;
+ }
+ @Override
+ public Object getObject() {
+ double val = getDouble();
+ return exists() ? val : null;
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double val = getDouble();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Double> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValueStream.java
new file mode 100644
index 0000000..a50c834
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/DoubleValueStream.java
@@ -0,0 +1,54 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a boolean.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamDoubles},
+ * resulting in different values on each call.
+ */
+public interface DoubleValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the double representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamDoubles(DoubleConsumer cons);
+
+ /**
+ * An interface that represents all of the types a {@link DoubleValueStream} should be able to cast to.
+ */
+ public static interface CastingDoubleValueStream extends DoubleValueStream, StringValueStream {}
+
+ /**
+ * An abstract base for {@link CastingDoubleValueStream} that automatically casts to all types if {@link #streamDoubles} is implemented.
+ */
+ public static abstract class AbstractDoubleValueStream implements CastingDoubleValueStream {
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamDoubles((double val) -> cons.accept(Double.toString(val)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamDoubles((double val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValue.java
new file mode 100644
index 0000000..16883d5
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValue.java
@@ -0,0 +1,97 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+/**
+ * A single-valued analytics value that can be represented as a float.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getFloat()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface FloatValue extends FloatValueStream, AnalyticsValue {
+ /**
+ * Get the float representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ float getFloat();
+
+ /**
+ * An interface that represents all of the types a {@link FloatValue} should be able to cast to.
+ */
+ public static interface CastingFloatValue extends FloatValue, DoubleValue, StringValue, ComparableValue {}
+
+ /**
+ * An abstract base for {@link CastingFloatValue} that automatically casts to all types if {@link #getFloat()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractFloatValue implements CastingFloatValue {
+ @Override
+ public double getDouble() {
+ return getFloat();
+ }
+ @Override
+ public String getString() {
+ float val = getFloat();
+ return exists() ? Float.toString(val) : null;
+ }
+ @Override
+ public Object getObject() {
+ float val = getFloat();
+ return exists() ? val : null;
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float val = getFloat();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double val = getDouble();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Float> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValueStream.java
new file mode 100644
index 0000000..cf15a21
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/FloatValueStream.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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a float.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamFloats},
+ * resulting in different values on each call.
+ */
+public interface FloatValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the float representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamFloats(FloatConsumer cons);
+
+ /**
+ * An interface that represents all of the types a {@link FloatValueStream} should be able to cast to.
+ */
+ public static interface CastingFloatValueStream extends FloatValueStream, DoubleValueStream, StringValueStream { }
+
+ /**
+ * An abstract base for {@link CastingFloatValueStream} that automatically casts to all types if {@link #streamFloats} is implemented.
+ */
+ public static abstract class AbstractFloatValueStream implements CastingFloatValueStream {
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamFloats((float val) -> cons.accept(val));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamFloats((float val) -> cons.accept(Float.toString(val)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamFloats((float val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValue.java
new file mode 100644
index 0000000..5688357
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValue.java
@@ -0,0 +1,121 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+/**
+ * A single-valued analytics value that can be represented as an int.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getInt()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface IntValue extends IntValueStream, AnalyticsValue {
+ /**
+ * Get the int representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ int getInt();
+
+ /**
+ * An interface that represents all of the types a {@link IntValue} should be able to cast to.
+ */
+ public static interface CastingIntValue extends IntValue, LongValue, FloatValue,DoubleValue, StringValue, ComparableValue { }
+
+ /**
+ * An abstract base for {@link CastingIntValue} that automatically casts to all types if {@link #getInt()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractIntValue implements CastingIntValue {
+ @Override
+ public long getLong() {
+ return getInt();
+ }
+ @Override
+ public float getFloat() {
+ return getInt();
+ }
+ @Override
+ public double getDouble() {
+ return getInt();
+ }
+ @Override
+ public String getString() {
+ int val = getInt();
+ return exists() ? Integer.toString(val) : null;
+ }
+ @Override
+ public Object getObject() {
+ int val = getInt();
+ return exists() ? val : null;
+ }
+ @Override
+ public void streamInts(IntConsumer cons) {
+ int val = getInt();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long val = getLong();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float val = getFloat();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double val = getDouble();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Integer> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValueStream.java
new file mode 100644
index 0000000..9cbe28c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/IntValueStream.java
@@ -0,0 +1,71 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a int.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamInts},
+ * resulting in different values on each call.
+ */
+public interface IntValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the int representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamInts(IntConsumer cons);
+
+ /**
+ * An interface that represents all of the types a {@link IntValueStream} should be able to cast to.
+ */
+ public static interface CastingIntValueStream extends IntValueStream, LongValueStream, FloatValueStream,
+ DoubleValueStream, StringValueStream {}
+
+ /**
+ * An abstract base for {@link CastingIntValueStream} that automatically casts to all types if {@link #streamInts} is implemented.
+ */
+ public static abstract class AbstractIntValueStream implements CastingIntValueStream {
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ streamInts((int val) -> cons.accept(val));
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ streamInts((int val) -> cons.accept(val));
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamInts((int val) -> cons.accept(val));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamInts((int val) -> cons.accept(Integer.toString(val)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamInts((int val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValue.java
new file mode 100644
index 0000000..623cd13
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValue.java
@@ -0,0 +1,97 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+
+/**
+ * A single-valued analytics value that can be represented as a long.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getLong()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface LongValue extends LongValueStream, AnalyticsValue {
+ /**
+ * Get the long representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ long getLong();
+
+ /**
+ * An interface that represents all of the types a {@link LongValue} should be able to cast to.
+ */
+ public static interface CastingLongValue extends LongValue, DoubleValue, StringValue, ComparableValue {}
+
+ /**
+ * An abstract base for {@link CastingLongValue} that automatically casts to all types if {@link #getLong()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractLongValue implements CastingLongValue {
+ @Override
+ public double getDouble() {
+ return getLong();
+ }
+ @Override
+ public String getString() {
+ long val = getLong();
+ return exists() ? Long.toString(val) : null;
+ }
+ @Override
+ public Object getObject() {
+ long val = getLong();
+ return exists() ? val : null;
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long val = getLong();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double val = getDouble();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String val = getString();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object val = getObject();
+ if (exists()) {
+ cons.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<Long> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValueStream.java
new file mode 100644
index 0000000..d18cb03
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/LongValueStream.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.analytics.value;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a long.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamLongs},
+ * resulting in different values on each call.
+ */
+public interface LongValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the long representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamLongs(LongConsumer cons);
+
+ /**
+ * An interface that represents all of the types a {@link LongValueStream} should be able to cast to.
+ */
+ public static interface CastingLongValueStream extends LongValueStream, DoubleValueStream,
+ StringValueStream { }
+
+ /**
+ * An abstract base for {@link CastingLongValueStream} that automatically casts to all types if {@link #streamLongs} is implemented.
+ */
+ public static abstract class AbstractLongValueStream implements CastingLongValueStream {
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamLongs((long val) -> cons.accept(val));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs((long val) -> cons.accept(Long.toString(val)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs((long val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValue.java
new file mode 100644
index 0000000..7baf18e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValue.java
@@ -0,0 +1,71 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+
+/**
+ * A single-valued analytics value that can be represented as a string.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #getString()} and {@link #exists()},
+ * resulting in different values on each call.
+ */
+public interface StringValue extends StringValueStream, AnalyticsValue {
+ /**
+ * Get the String representation of the current value.
+ * <p>
+ * NOTE: The value returned is not valid unless calling {@link #exists()} afterwards returns {@code TRUE}.
+ *
+ * @return the current value
+ */
+ String getString();
+
+ /**
+ * An interface that represents all of the types a {@link StringValue} should be able to cast to.
+ */
+ public static interface CastingStringValue extends StringValue, ComparableValue {}
+
+ /**
+ * An abstract base for {@link CastingStringValue} that automatically casts to all types if {@link #getString()} and {@link #exists()} are implemented.
+ */
+ public static abstract class AbstractStringValue implements CastingStringValue {
+ @Override
+ public String getObject() {
+ return getString();
+ }
+ @Override
+ public void streamStrings(Consumer<String> func) {
+ String val = getString();
+ if (exists()) {
+ func.accept(val);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> func) {
+ Object val = getObject();
+ if (exists()) {
+ func.accept(val);
+ }
+ }
+ @Override
+ public ExpressionComparator<String> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValueStream.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValueStream.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValueStream.java
new file mode 100644
index 0000000..2269ac4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/StringValueStream.java
@@ -0,0 +1,49 @@
+/*
+ * 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.analytics.value;
+
+import java.util.function.Consumer;
+
+/**
+ * A multi-valued analytics value that can be represented as a String.
+ * <p>
+ * The back-end production of the value can change inbetween calls to {@link #streamStrings},
+ * resulting in different values on each call.
+ */
+public interface StringValueStream extends AnalyticsValueStream {
+ /**
+ * Stream the String representations of all current values, if any exist.
+ *
+ * @param cons The consumer to accept the values
+ */
+ void streamStrings(Consumer<String> cons);
+
+ /**
+ * An interface that represents all of the types a {@link StringValueStream} should be able to cast to.
+ */
+ public static interface CastingStringValueStream extends StringValueStream {}
+
+ /**
+ * An abstract base for {@link CastingStringValueStream} that automatically casts to all types if {@link #streamStrings} is implemented.
+ */
+ public static abstract class AbstractStringValueStream implements CastingStringValueStream {
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamStrings((String val) -> cons.accept(val));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantBooleanValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantBooleanValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantBooleanValue.java
new file mode 100644
index 0000000..aeccaaa
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantBooleanValue.java
@@ -0,0 +1,91 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValue.CastingBooleanValue;
+
+/**
+ * A constant {@link BooleanValue}. Every call to {@link #getBoolean()} and other methods will return the same constant value.
+ */
+public class ConstantBooleanValue extends ConstantValue implements CastingBooleanValue {
+ private final boolean value;
+ private final String valueStr;
+ public static final String name = "const_bool";
+ private final String exprStr;
+
+ public ConstantBooleanValue(boolean value) {
+ this.value = value;
+ this.valueStr = Boolean.toString(value);
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDateValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDateValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDateValue.java
new file mode 100644
index 0000000..5614d6c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDateValue.java
@@ -0,0 +1,103 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValue.CastingDateValue;
+
+/**
+ * A constant {@link DateValue}. Every call to {@link #getDate()} and other methods will return the same constant value.
+ */
+public class ConstantDateValue extends ConstantValue implements CastingDateValue {
+ private final long value;
+ private final Date valueDate;
+ private final String valueStr;
+ public static final String name = "const_date";
+ private final String exprStr;
+
+ public ConstantDateValue(long value) {
+ this.value = value;
+ this.valueDate = new Date(value);
+ this.valueStr = Instant.ofEpochMilli(value).toString();
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+
+ @Override
+ public long getLong() {
+ return value;
+ }
+ @Override
+ public Date getDate() {
+ return valueDate;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return valueDate;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ cons.accept(valueDate);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(valueDate);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDoubleValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDoubleValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDoubleValue.java
new file mode 100644
index 0000000..cf5682a
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantDoubleValue.java
@@ -0,0 +1,90 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValue.CastingDoubleValue;
+
+/**
+ * A constant {@link DoubleValue}. Every call to {@link #getDouble()} and other methods will return the same constant value.
+ */
+public class ConstantDoubleValue extends ConstantValue implements CastingDoubleValue {
+ private final double value;
+ private final String valueStr;
+ public static final String name = "const_double";
+ private final String exprStr;
+
+ public ConstantDoubleValue(double value) {
+ this.value = value;
+ this.valueStr = Double.toString(value);
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+ @Override
+ public double getDouble() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantFloatValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantFloatValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantFloatValue.java
new file mode 100644
index 0000000..ec495a4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantFloatValue.java
@@ -0,0 +1,99 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValue.CastingFloatValue;
+
+/**
+ * A constant {@link FloatValue}. Every call to {@link #getFloat()} and other methods will return the same constant value.
+ */
+public class ConstantFloatValue extends ConstantValue implements CastingFloatValue {
+ private final float value;
+ private final String valueStr;
+ public static final String name = "const_float";
+ private final String exprStr;
+
+ public ConstantFloatValue(float value) {
+ this.value = value;
+ this.valueStr = Float.toString(value);
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+ @Override
+ public float getFloat() {
+ return value;
+ }
+ @Override
+ public double getDouble() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantIntValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantIntValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantIntValue.java
new file mode 100644
index 0000000..1e43359
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantIntValue.java
@@ -0,0 +1,118 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValue.CastingIntValue;
+
+/**
+ * A constant {@link IntValue}. Every call to {@link #getInt()} and other methods will return the same constant value.
+ */
+public class ConstantIntValue extends ConstantValue implements CastingIntValue {
+ private final int value;
+ private final String valueStr;
+ public static final String name = "const_int";
+ private final String exprStr;
+
+ public ConstantIntValue(int value) {
+ this.value = value;
+ this.valueStr = Integer.toString(value);
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+
+ @Override
+ public int getInt() {
+ return value;
+ }
+ @Override
+ public long getLong() {
+ return value;
+ }
+ @Override
+ public float getFloat() {
+ return value;
+ }
+ @Override
+ public double getDouble() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantLongValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantLongValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantLongValue.java
new file mode 100644
index 0000000..d4c54d0
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantLongValue.java
@@ -0,0 +1,100 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValue.CastingLongValue;
+
+/**
+ * A constant {@link LongValue}. Every call to {@link #getLong()} and other methods will return the same constant value.
+ */
+public class ConstantLongValue extends ConstantValue implements CastingLongValue {
+ private final long value;
+ private final String valueStr;
+ public static final String name = "const_long";
+ private final String exprStr;
+
+ public ConstantLongValue(long value) {
+ this.value = value;
+ this.valueStr = Long.toString(value);
+ this.exprStr = ConstantValue.createExpressionString(this, valueStr);
+ }
+
+
+ @Override
+ public long getLong() {
+ return value;
+ }
+ @Override
+ public double getDouble() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return valueStr;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(valueStr);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantStringValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantStringValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantStringValue.java
new file mode 100644
index 0000000..c32a2a3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantStringValue.java
@@ -0,0 +1,79 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.facet.compare.ConstantComparator;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValue.CastingStringValue;
+
+/**
+ * A constant {@link StringValue}. Every call to {@link #getString()} and other methods will return the same constant value.
+ */
+public class ConstantStringValue extends ConstantValue implements CastingStringValue {
+ String value;
+ public static final String name = "const_str";
+ private final String exprStr;
+
+ public ConstantStringValue(String value) {
+ this.value = value;
+ this.exprStr = ConstantValue.createExpressionString(this, value);
+ }
+
+ @Override
+ public String getString() {
+ return value;
+ }
+ @Override
+ public Object getObject() {
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ cons.accept(value);
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ cons.accept(value);
+ }
+
+ @Override
+ public ConstantComparator getObjectComparator(String expression) {
+ return new ConstantComparator();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.CONST;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantValue.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantValue.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantValue.java
new file mode 100644
index 0000000..2e364b1
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/ConstantValue.java
@@ -0,0 +1,128 @@
+/*
+ * 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.analytics.value.constant;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.solr.analytics.ExpressionFactory.ConstantFunction;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * The parent class of all constant Analytics values.
+ * <p>
+ * Constant values can be specified in the following ways in analytics requests:
+ * <ul>
+ * <li> Constant booleans must match one of the following in any case: true, t, false, f
+ * <li> Constant strings must be surrounded with "s or 's
+ * <li> Constant numbers do not have to be surrounded with anything
+ * <li> Constant dates must match one of the following patterns
+ * <ul>
+ * <li> yyyy-MM-dd
+ * <li> yyyy-MM-ddXXX
+ * <li> yyyy-MM-dd'T'HH:mm:ssZ
+ * <li> yyyy-MM-dd'T'HH:mm:ssXXX
+ * <li> yyyy-MM-dd'T'HH:mm:ss.SSSZ
+ * <li> yyyy-MM-dd'T'HH:mm:ss.SSSXXX
+ * </ul>
+ * </li>
+ * </ul>
+ */
+public abstract class ConstantValue {
+ private static final Pattern truePattern = Pattern.compile("^true|t$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern falsePattern = Pattern.compile("^false|f$", Pattern.CASE_INSENSITIVE);
+ private static final SimpleDateFormat dateParserBase = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
+ private static final SimpleDateFormat dateParser1 = new SimpleDateFormat("yyyy-MM-ddZ", Locale.ROOT);
+ private static final SimpleDateFormat dateParser2 = new SimpleDateFormat("yyyy-MM-ddXXX", Locale.ROOT);
+ private static final SimpleDateFormat dateParser3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT);
+ private static final SimpleDateFormat dateParser4 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ROOT);
+ private static final SimpleDateFormat dateParser5 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ROOT);
+ private static final SimpleDateFormat dateParser6 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ROOT);
+
+ public static final ConstantFunction creatorFunction = (param -> {
+ param = param.trim();
+
+ // Try to create a string
+ if ((param.charAt(0)=='"' && param.charAt(param.length()-1)=='"')
+ || (param.charAt(0)=='\'' && param.charAt(param.length()-1)=='\'')) {
+ return new ConstantStringValue(param.substring(1, param.length()-1));
+ }
+
+ // Try to create a boolean
+ Matcher m = truePattern.matcher(param);
+ if (m.matches()) {
+ return new ConstantBooleanValue(true);
+ }
+ m = falsePattern.matcher(param);
+ if (m.matches()) {
+ return new ConstantBooleanValue(false);
+ }
+
+ // Try to create a number
+ try {
+ AnalyticsValue value = new ConstantDoubleValue(Double.parseDouble(param));
+ try {
+ value = new ConstantLongValue(Long.parseLong(param));
+ value = new ConstantIntValue(Integer.parseInt(param));
+ } catch (NumberFormatException e) {
+ value = new ConstantFloatValue(Float.parseFloat(param));
+ }
+ return value;
+ } catch (NumberFormatException e) {
+ // The constant is not a number
+ }
+
+ // Try to create a date
+ try {
+ AnalyticsValue value = new ConstantDateValue(dateParserBase.parse(param).getTime());
+ try {
+ return new ConstantDateValue(dateParser1.parse(param).getTime());
+ } catch (Exception e) {}
+ try {
+ return new ConstantDateValue(dateParser2.parse(param).getTime());
+ } catch (Exception e) {}
+ try {
+ return new ConstantDateValue(dateParser3.parse(param).getTime());
+ } catch (Exception e) {}
+ try {
+ return new ConstantDateValue(dateParser4.parse(param).getTime());
+ } catch (Exception e) {}
+ try {
+ return new ConstantDateValue(dateParser5.parse(param).getTime());
+ } catch (Exception e) {}
+ try {
+ return new ConstantDateValue(dateParser6.parse(param).getTime());
+ } catch (Exception e) {}
+ return value;
+ } catch (Exception e) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The parameter "+param+" could not be cast to any constant.");
+ }
+
+ });
+
+ static String createExpressionString(AnalyticsValueStream func,
+ Object param) {
+ return String.format(Locale.ROOT,"%s(%s)",
+ func.getName(),
+ param.toString());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/package-info.java
new file mode 100644
index 0000000..eb6f29d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/constant/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Constant values to be used in analytics expressions.
+ */
+package org.apache.solr.analytics.value.constant;
+
+
[04/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/package-info.java
new file mode 100644
index 0000000..247b592
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/value/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Value types for analytics expressions.
+ */
+package org.apache.solr.analytics.value;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/handler/AnalyticsHandler.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/handler/AnalyticsHandler.java b/solr/contrib/analytics/src/java/org/apache/solr/handler/AnalyticsHandler.java
new file mode 100644
index 0000000..64eb321
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/handler/AnalyticsHandler.java
@@ -0,0 +1,147 @@
+/*
+ * 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.handler;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import org.apache.lucene.search.MatchNoDocsQuery;
+import org.apache.lucene.search.Query;
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.AnalyticsRequestManager;
+import org.apache.solr.analytics.AnalyticsRequestParser;
+import org.apache.solr.analytics.ExpressionFactory;
+import org.apache.solr.analytics.stream.AnalyticsShardResponseParser;
+import org.apache.solr.client.solrj.io.ModelCache;
+import org.apache.solr.client.solrj.io.SolrClientCache;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.handler.component.AnalyticsComponent;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.AnalyticsShardResponseWriter;
+import org.apache.solr.response.AnalyticsShardResponseWriter.AnalyticsResponse;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.search.DocSet;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.QParserPlugin;
+import org.apache.solr.search.QueryParsing;
+import org.apache.solr.search.SolrIndexSearcher;
+import org.apache.solr.search.SyntaxError;
+import org.apache.solr.security.AuthorizationContext;
+import org.apache.solr.security.PermissionNameProvider;
+import org.apache.solr.util.plugin.SolrCoreAware;
+
+/**
+ * Handler for Analytics shard requests. This handler should only be called by the {@link AnalyticsComponent}
+ * since the response is written in a bit-stream, formatted by the {@link AnalyticsShardResponseWriter}
+ * that can only be read by the {@link AnalyticsShardResponseParser}.
+ */
+public class AnalyticsHandler extends RequestHandlerBase implements SolrCoreAware, PermissionNameProvider {
+ public static final String NAME = "/analytics";
+ private IndexSchema indexSchema;
+
+ static SolrClientCache clientCache = new SolrClientCache();
+ static ModelCache modelCache = null;
+
+ @Override
+ public PermissionNameProvider.Name getPermissionName(AuthorizationContext request) {
+ return PermissionNameProvider.Name.READ_PERM;
+ }
+
+ @Override
+ public void inform(SolrCore core) {
+ core.registerResponseWriter(AnalyticsShardResponseWriter.NAME, new AnalyticsShardResponseWriter());
+
+ indexSchema = core.getLatestSchema();
+ AnalyticsRequestParser.init();
+ }
+
+ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+ try {
+ DocSet docs;
+ try {
+ docs = getDocuments(req);
+ } catch (SyntaxError e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
+ }
+ // The olap-style requests are converted to the current format in the AnalyticsComponent
+ // so the AnalyticsHandler only needs to handle current format requests.
+ AnalyticsRequestManager manager = AnalyticsRequestParser.parse(req.getParams().get(AnalyticsRequestParser.analyticsParamName),
+ new ExpressionFactory(indexSchema),
+ false);
+ // Collect the reduction data for the request
+ SolrIndexSearcher searcher = req.getSearcher();
+ Filter filter = docs.getTopFilter();
+ AnalyticsDriver.drive(manager, searcher, filter, req);
+
+ // Do not calculate results, instead export the reduction data for this shard.
+ rsp.addResponse(new AnalyticsResponse(manager));
+ } catch (SolrException e) {
+ rsp.addResponse(new AnalyticsResponse(e));
+ }
+ }
+
+ /**
+ * Get the documents returned by the query and filter queries included in the request.
+ *
+ * @param req the request sent to the handler
+ * @return the set of documents matching the query
+ * @throws SyntaxError if there is a syntax error in the queries
+ * @throws IOException if an error occurs while searching the index
+ */
+ private DocSet getDocuments(SolrQueryRequest req) throws SyntaxError, IOException {
+ SolrParams params = req.getParams();
+ ArrayList<Query> queries = new ArrayList<>();
+
+ // Query Param
+ String queryString = params.get( CommonParams.Q );
+
+ String defType = params.get(QueryParsing.DEFTYPE, QParserPlugin.DEFAULT_QTYPE);
+
+ QParser parser = QParser.getParser(queryString, defType, req);
+ Query query = parser.getQuery();
+ if (query == null) {
+ // normalize a null query to a query that matches nothing
+ query = new MatchNoDocsQuery();
+ }
+ queries.add(query);
+
+ // Filter Params
+ String[] fqs = req.getParams().getParams(CommonParams.FQ);
+ if (fqs!=null) {
+ for (String fq : fqs) {
+ if (fq != null && fq.trim().length()!=0) {
+ QParser fqp = QParser.getParser(fq, req);
+ queries.add(fqp.getQuery());
+ }
+ }
+ }
+ return req.getSearcher().getDocSet(queries);
+ }
+
+ @Override
+ public String getDescription() {
+ return NAME;
+ }
+
+ public String getSource() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java b/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
index 505533b..71c6c92 100644
--- a/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
+++ b/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
@@ -18,58 +18,128 @@ package org.apache.solr.handler.component;
import java.io.IOException;
-import org.apache.solr.analytics.plugin.AnalyticsStatisticsCollector;
-import org.apache.solr.analytics.request.AnalyticsStats;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.metrics.MetricsMap;
-import org.apache.solr.metrics.SolrMetricManager;
-import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.AnalyticsRequestManager;
+import org.apache.solr.analytics.AnalyticsRequestParser;
+import org.apache.solr.analytics.ExpressionFactory;
+import org.apache.solr.analytics.stream.AnalyticsShardRequestManager;
+import org.apache.solr.analytics.util.OldAnalyticsParams;
+import org.apache.solr.analytics.util.OldAnalyticsRequestConverter;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
-public class AnalyticsComponent extends SearchComponent implements SolrMetricProducer {
+/**
+ * Computes analytics requests.
+ */
+public class AnalyticsComponent extends SearchComponent {
public static final String COMPONENT_NAME = "analytics";
- private final AnalyticsStatisticsCollector analyticsCollector = new AnalyticsStatisticsCollector();;
+
+ @Override
+ public void init(NamedList args) {
+ AnalyticsRequestParser.init();
+ }
@Override
public void prepare(ResponseBuilder rb) throws IOException {
- if (rb.req.getParams().getBool(AnalyticsParams.ANALYTICS,false)) {
- rb.setNeedDocSet( true );
+ // First check to see if there is an analytics request using the current format
+ String analyticsRequest = rb.req.getParams().get(AnalyticsRequestParser.analyticsParamName);
+ rb._isOlapAnalytics = false;
+ rb.doAnalytics = false;
+ if (analyticsRequest != null) {
+ rb.doAnalytics = true;
+ rb._analyticsRequestManager = AnalyticsRequestParser.parse(analyticsRequest, new ExpressionFactory(rb.req.getSchema()), rb.isDistrib);
+ }
+ // If there is no request in the current format, check for the old olap-style format
+ else if (rb.req.getParams().getBool(OldAnalyticsParams.OLD_ANALYTICS,false)) {
+ rb._analyticsRequestManager = AnalyticsRequestParser.parse(OldAnalyticsRequestConverter.convert(rb.req.getParams()), new ExpressionFactory(rb.req.getSchema()), rb.isDistrib);
+ rb._isOlapAnalytics = true;
+ rb.doAnalytics = true;
+ }
+
+ if (rb.doAnalytics) {
+ AnalyticsRequestManager reqManager = (AnalyticsRequestManager)rb._analyticsRequestManager;
+ // Check to see if the request is distributed
+ if (rb.isDistrib) {
+ reqManager.sendShards = true;
+ reqManager.shardStream = new AnalyticsShardRequestManager(rb.req.getParams(), reqManager);
+ } else {
+ reqManager.sendShards = false;
+ rb.setNeedDocSet( true );
+ }
}
}
@Override
public void process(ResponseBuilder rb) throws IOException {
- if (rb.req.getParams().getBool(AnalyticsParams.ANALYTICS,false)) {
- SolrParams params = rb.req.getParams();
- AnalyticsStats s = new AnalyticsStats(rb.req, rb.getResults().docSet, params, analyticsCollector);
- rb.rsp.add( "stats", s.execute() );
+ if (!rb.doAnalytics) {
+ return;
}
+ AnalyticsRequestManager reqManager = (AnalyticsRequestManager)rb._analyticsRequestManager;
+ // Collect the data and generate a response
+ AnalyticsDriver.drive(reqManager, rb.req.getSearcher(), rb.getResults().docSet.getTopFilter(), rb.req);
+
+ if (rb._isOlapAnalytics) {
+ rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER, reqManager.createOldResponse());
+ } else {
+ rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_HEADER, reqManager.createResponse());
+ }
+
+ rb.doAnalytics = false;
}
- /*
+
@Override
public int distributedProcess(ResponseBuilder rb) throws IOException {
+ if (!rb.doAnalytics || rb.stage != ResponseBuilder.STAGE_EXECUTE_QUERY) {
+ return ResponseBuilder.STAGE_DONE;
+ }
+ AnalyticsRequestManager reqManager = (AnalyticsRequestManager)rb._analyticsRequestManager;
+ if (!reqManager.sendShards){
+ return ResponseBuilder.STAGE_DONE;
+ }
+
+ // Send out a request to each shard and merge the responses into our AnalyticsRequestManager
+ reqManager.shardStream.sendRequests(rb.req.getCore().getCoreDescriptor().getCollectionName(),
+ rb.req.getCore().getCoreContainer().getZkController().getZkServerAddress());
+
+ reqManager.sendShards = false;
+
return ResponseBuilder.STAGE_DONE;
}
@Override
public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) {
- // TODO Auto-generated method stub
+ // We don't want the shard requests to compute analytics, since we send
+ // separate requests for that in distributedProcess() to the AnalyticsHandler
+ sreq.params.remove(AnalyticsRequestParser.analyticsParamName);
+ sreq.params.remove(OldAnalyticsParams.OLD_ANALYTICS);
+
super.modifyRequest(rb, who, sreq);
}
@Override
public void handleResponses(ResponseBuilder rb, ShardRequest sreq) {
- // TODO Auto-generated method stub
+
+ // NO-OP since analytics shard responses are handled through the AnalyticsResponseParser
+
super.handleResponses(rb, sreq);
}
@Override
public void finishStage(ResponseBuilder rb) {
- // TODO Auto-generated method stub
+ if (rb.doAnalytics && rb.stage == ResponseBuilder.STAGE_GET_FIELDS) {
+ AnalyticsRequestManager reqManager = (AnalyticsRequestManager)rb._analyticsRequestManager;
+ // Generate responses from the merged shard data
+ if (rb._isOlapAnalytics) {
+ rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER, reqManager.createOldResponse());
+ } else {
+ rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_HEADER, reqManager.createResponse());
+ }
+ }
+
super.finishStage(rb);
}
- */
+
@Override
public String getName() {
@@ -81,9 +151,8 @@ public class AnalyticsComponent extends SearchComponent implements SolrMetricPro
return "Perform analytics";
}
- @Override
- public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
- MetricsMap metrics = new MetricsMap((detailed, map) -> map.putAll(analyticsCollector.getStatistics()));
- manager.registerGauge(this, registry, metrics, true, getClass().getSimpleName(), getCategory().toString(), scope);
- }
+ /*@Override
+ public NamedList getStatistics() {
+ return analyticsCollector.getStatistics();
+ }*/
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/handler/package.html
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/handler/package.html b/solr/contrib/analytics/src/java/org/apache/solr/handler/package.html
new file mode 100644
index 0000000..6a5c2c3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/handler/package.html
@@ -0,0 +1,28 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<!--
+ 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.
+-->
+<!-- not a package-info.java, because we already defined this package in core/ -->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+<body>
+<p>
+Handler for distributed analytics requests to shards.
+</p>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/response/AnalyticsShardResponseWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/response/AnalyticsShardResponseWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/response/AnalyticsShardResponseWriter.java
new file mode 100644
index 0000000..52c71ee
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/response/AnalyticsShardResponseWriter.java
@@ -0,0 +1,91 @@
+/*
+ * 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.response;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.solr.analytics.AnalyticsRequestManager;
+import org.apache.solr.analytics.stream.AnalyticsShardResponseParser;
+import org.apache.solr.client.solrj.impl.BinaryResponseParser;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.request.SolrQueryRequest;
+
+/**
+ * Writes the reduction data of a analytics shard request to a bit-stream to send to the originating shard.
+ * The response must be parsed by the {@link AnalyticsShardResponseParser} initialized with the same analytics request
+ * as the shard request was sent.
+ */
+public class AnalyticsShardResponseWriter implements BinaryQueryResponseWriter {
+ public static final String NAME = "analytics_shard_stream";
+ public static final String ANALYTICS_MANGER = "analyticsManager";
+
+ @Override
+ public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse response) throws IOException {
+ ((AnalyticsResponse)response.getResponse()).write(new DataOutputStream(out));;
+ }
+
+ @Override
+ public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException {
+ throw new RuntimeException("This is a binary writer , Cannot write to a characterstream");
+ }
+
+ @Override
+ public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
+ return BinaryResponseParser.BINARY_CONTENT_TYPE;
+ }
+
+ @Override
+ public void init(NamedList args) {}
+
+ /**
+ * Manages the streaming of analytics reduction data if no exception occurred.
+ * Otherwise the exception is streamed over.
+ */
+ public static class AnalyticsResponse {
+ private final AnalyticsRequestManager manager;
+ private final SolrException exception;
+
+ private final boolean requestSuccessful;
+
+ public AnalyticsResponse(AnalyticsRequestManager manager) {
+ this.manager = manager;
+ this.exception = null;
+ this.requestSuccessful = true;
+ }
+
+ public AnalyticsResponse(SolrException exception) {
+ this.manager = null;
+ this.exception = exception;
+ this.requestSuccessful = false;
+ }
+
+ public void write(DataOutputStream output) throws IOException {
+ output.writeBoolean(requestSuccessful);
+ if (requestSuccessful) {
+ manager.exportShardData(output);
+ } else {
+ new ObjectOutputStream(output).writeObject(exception);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/response/package.html
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/response/package.html b/solr/contrib/analytics/src/java/org/apache/solr/response/package.html
new file mode 100644
index 0000000..dd24f82
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/response/package.html
@@ -0,0 +1,28 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<!--
+ 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.
+-->
+<!-- not a package-info.java, because we already defined this package in core/ -->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+<body>
+<p>
+Response Writer for distributed analytics response from a shard.
+</p>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/expressions.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/expressions.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/expressions.txt
deleted file mode 100644
index 329d32d..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/expressions.txt
+++ /dev/null
@@ -1,70 +0,0 @@
-o.ar.s.sum=sum(int_id)
-o.ar.s.unique=unique(long_ld)
-o.ar.s.su=add(sum(int_id),unique(long_ld))
-o.ar.s.mean=mean(int_id)
-o.ar.s.count=count(long_ld)
-o.ar.s.median=median(int_id)
-o.ar.s.mcm=add(mean(int_id),count(long_ld),median(int_id))
-
-o.mr.s.sum=sum(int_id)
-o.mr.s.unique=unique(long_ld)
-o.mr.s.su=mult(sum(int_id),unique(long_ld))
-o.mr.s.mean=mean(int_id)
-o.mr.s.count=count(long_ld)
-o.mr.s.median=median(int_id)
-o.mr.s.mcm=mult(mean(int_id),count(long_ld),median(int_id))
-
-o.dr.s.sum=sum(int_id)
-o.dr.s.unique=unique(long_ld)
-o.dr.s.su=div(sum(int_id),unique(long_ld))
-o.dr.s.mean=mean(int_id)
-o.dr.s.count=count(long_ld)
-o.dr.s.mc=div(mean(int_id),count(long_ld))
-
-o.pr.s.sum=sum(int_id)
-o.pr.s.unique=unique(long_ld)
-o.pr.s.su=pow(sum(int_id),unique(long_ld))
-o.pr.s.mean=mean(int_id)
-o.pr.s.count=count(long_ld)
-o.pr.s.mc=pow(mean(int_id),count(long_ld))
-
-o.nr.s.sum=sum(int_id)
-o.nr.s.s=neg(sum(int_id))
-o.nr.s.count=count(long_ld)
-o.nr.s.c=neg(count(long_ld))
-
-o.avr.s.sum=sum(int_id)
-o.avr.s.s=abs(neg(sum(int_id)))
-o.avr.s.count=count(long_ld)
-o.avr.s.c=abs(neg(count(long_ld)))
-
-o.cnr.s.c8=const_num(8)
-o.cnr.s.c10=const_num(10)
-
-o.dmr.s.median=median(date_dtd)
-o.dmr.s.cme=const_str(+2YEARS)
-o.dmr.s.dmme=date_math(median(date_dtd),const_str(+2YEARS))
-o.dmr.s.max=max(date_dtd)
-o.dmr.s.cma=const_str(+2MONTHS)
-o.dmr.s.dmma=date_math(max(date_dtd),const_str(+2MONTHS))
-
-o.cdr.s.cd1=const_date(1800-12-31T23:59:59Z)
-o.cdr.s.cs1=const_str(1800-12-31T23:59:59Z)
-o.cdr.s.cd2=const_date(1804-06-30T23:59:59Z)
-o.cdr.s.cs2=const_str(1804-06-30T23:59:59Z)
-
-o.csr.s.cs1=const_str(this is the first)
-o.csr.s.cs2=const_str(this is the second)
-o.csr.s.cs3=const_str(this is the third)
-
-o.cr.s.csmin=const_str(this is the first)
-o.cr.s.min=min(string_sd)
-o.cr.s.ccmin=concat(const_str(this is the first),min(string_sd))
-o.cr.s.csmax=const_str(this is the second)
-o.cr.s.max=max(string_sd)
-o.cr.s.ccmax=concat(const_str(this is the second),max(string_sd))
-
-o.rr.s.min=min(string_sd)
-o.rr.s.rmin=rev(min(string_sd))
-o.rr.s.max=max(string_sd)
-o.rr.s.rmax=rev(max(string_sd))
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacetExtras.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacetExtras.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacetExtras.txt
deleted file mode 100644
index 3979f57..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacetExtras.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-o.sr.s.mean=mean(int_id)
-o.sr.s.median=median(int_id)
-o.sr.s.count=count(int_id)
-o.sr.s.percentile_20=percentile(20,int_id)
-o.sr.ff=long_ld
-o.sr.ff.long_ld.ss=mean
-o.sr.ff.long_ld.sd=asc
-o.sr.ff=float_fd
-o.sr.ff.float_fd.ss=median
-o.sr.ff.float_fd.sd=desc
-o.sr.ff=double_dd
-o.sr.ff.double_dd.ss=count
-o.sr.ff.double_dd.sd=asc
-o.sr.ff=string_sd
-o.sr.ff.string_sd.ss=percentile_20
-o.sr.ff.string_sd.sd=desc
-
-o.lr.s.mean=mean(int_id)
-o.lr.s.median=median(int_id)
-o.lr.s.count=count(int_id)
-o.lr.s.percentile_20=percentile(20,int_id)
-o.lr.ff=long_ld
-o.lr.ff.long_ld.ss=mean
-o.lr.ff.long_ld.sd=asc
-o.lr.ff.long_ld.limit=5
-o.lr.ff=float_fd
-o.lr.ff.float_fd.ss=median
-o.lr.ff.float_fd.sd=desc
-o.lr.ff.float_fd.limit=3
-o.lr.ff=double_dd
-o.lr.ff.double_dd.ss=count
-o.lr.ff.double_dd.sd=asc
-o.lr.ff.double_dd.limit=7
-o.lr.ff=string_sd
-o.lr.ff.string_sd.ss=percentile_20
-o.lr.ff.string_sd.sd=desc
-o.lr.ff.string_sd.limit=1
-
-
-
-o.offAll.s.mean=mean(int_id)
-o.offAll.ff=long_ld
-o.offAll.ff.long_ld.ss=mean
-o.offAll.ff.long_ld.sd=asc
-o.offAll.ff.long_ld.limit=7
-
-o.off0.s.mean=mean(int_id)
-o.off0.ff=long_ld
-o.off0.ff.long_ld.ss=mean
-o.off0.ff.long_ld.sd=asc
-o.off0.ff.long_ld.limit=2
-o.off0.ff.long_ld.offset=0
-
-o.off1.s.mean=mean(int_id)
-o.off1.ff=long_ld
-o.off1.ff.long_ld.ss=mean
-o.off1.ff.long_ld.sd=asc
-o.off1.ff.long_ld.limit=2
-o.off1.ff.long_ld.offset=2
-
-o.off2.s.mean=mean(int_id)
-o.off2.ff=long_ld
-o.off2.ff.long_ld.ss=mean
-o.off2.ff.long_ld.sd=asc
-o.off2.ff.long_ld.limit=3
-o.off2.ff.long_ld.offset=4
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacets.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacets.txt
deleted file mode 100644
index 5ba5953..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/fieldFacets.txt
+++ /dev/null
@@ -1,132 +0,0 @@
-o.sum.s.int=sum(int_id)
-o.sum.s.long=sum(long_ld)
-o.sum.s.float=sum(float_fd)
-o.sum.s.double=sum(double_dd)
-o.sum.ff=string_sd
-o.sum.ff=date_dtd
-
-o.mean.s.int=mean(int_id)
-o.mean.s.long=mean(long_ld)
-o.mean.s.float=mean(float_fd)
-o.mean.s.double=mean(double_dd)
-o.mean.ff=string_sd
-o.mean.ff=date_dtd
-
-o.sumOfSquares.s.int=sumofsquares(int_id)
-o.sumOfSquares.s.long=sumofsquares(long_ld)
-o.sumOfSquares.s.float=sumofsquares(float_fd)
-o.sumOfSquares.s.double=sumofsquares(double_dd)
-o.sumOfSquares.ff=string_sd
-o.sumOfSquares.ff=date_dtd
-
-o.stddev.s.int=stddev(int_id)
-o.stddev.s.long=stddev(long_ld)
-o.stddev.s.float=stddev(float_fd)
-o.stddev.s.double=stddev(double_dd)
-o.stddev.ff=string_sd
-o.stddev.ff=date_dtd
-
-o.median.s.int=median(int_id)
-o.median.s.long=median(long_ld)
-o.median.s.float=median(float_fd)
-o.median.s.double=median(double_dd)
-o.median.ff=string_sd
-o.median.ff=date_dtd
-
-o.percentile_20n.s.int=percentile(20,int_id)
-o.percentile_20n.s.long=percentile(20,long_ld)
-o.percentile_20n.s.float=percentile(20,float_fd)
-o.percentile_20n.s.double=percentile(20,double_dd)
-o.percentile_20n.ff=string_sd
-o.percentile_20n.ff=date_dtd
-
-o.percentile_20.s.str=percentile(20,string_sd)
-o.percentile_20.s.date=percentile(20,date_dtd)
-o.percentile_20.ff=int_id
-o.percentile_20.ff=long_ld
-
-o.percentile_60n.s.int=percentile(60,int_id)
-o.percentile_60n.s.long=percentile(60,long_ld)
-o.percentile_60n.s.float=percentile(60,float_fd)
-o.percentile_60n.s.double=percentile(60,double_dd)
-o.percentile_60n.ff=string_sd
-o.percentile_60n.ff=date_dtd
-
-o.percentile_60.s.str=percentile(60,string_sd)
-o.percentile_60.s.date=percentile(60,date_dtd)
-o.percentile_60.ff=int_id
-o.percentile_60.ff=long_ld
-
-o.minn.s.int=min(int_id)
-o.minn.s.long=min(long_ld)
-o.minn.s.float=min(float_fd)
-o.minn.s.double=min(double_dd)
-o.minn.ff=string_sd
-o.minn.ff=date_dtd
-
-o.min.s.str=min(string_sd)
-o.min.s.date=min(date_dtd)
-o.min.ff=int_id
-o.min.ff=long_ld
-
-o.maxn.s.int=max(int_id)
-o.maxn.s.long=max(long_ld)
-o.maxn.s.float=max(float_fd)
-o.maxn.s.double=max(double_dd)
-o.maxn.ff=string_sd
-o.maxn.ff=date_dtd
-
-o.max.s.str=max(string_sd)
-o.max.s.date=max(date_dtd)
-o.max.ff=int_id
-o.max.ff=long_ld
-
-o.countn.s.int=count(int_id)
-o.countn.s.long=count(long_ld)
-o.countn.s.float=count(float_fd)
-o.countn.s.double=count(double_dd)
-o.countn.ff=string_sd
-o.countn.ff=date_dtd
-
-o.count.s.str=count(string_sd)
-o.count.s.date=count(date_dtd)
-o.count.ff=int_id
-o.count.ff=long_ld
-
-o.uniquen.s.int=unique(int_id)
-o.uniquen.s.long=unique(long_ld)
-o.uniquen.s.float=unique(float_fd)
-o.uniquen.s.double=unique(double_dd)
-o.uniquen.ff=string_sd
-o.uniquen.ff=date_dtd
-
-o.unique.s.str=unique(string_sd)
-o.unique.s.date=unique(date_dtd)
-o.unique.ff=int_id
-o.unique.ff=long_ld
-
-o.missingn.s.int=missing(int_id)
-o.missingn.s.long=missing(long_ld)
-o.missingn.s.float=missing(float_fd)
-o.missingn.s.double=missing(double_dd)
-o.missingn.ff=string_sd
-o.missingn.ff=date_dtd
-
-o.missing.s.str=missing(string_sd)
-o.missing.s.date=missing(date_dtd)
-o.missing.ff=int_id
-o.missing.ff=long_ld
-
-o.multivalued.s.mean=mean(int_id)
-o.multivalued.ff=long_ldm
-o.multivalued.ff=string_sdm
-o.multivalued.ff=date_dtdm
-
-o.missingf.s.mean=mean(int_id)
-o.missingf.ff=date_dtd
-o.missingf.ff.date_dtd.dim=true
-o.missingf.ff=string_sd
-o.missingf.ff.string_sd.dim=true
-o.missingf.ff.string_sd.sm=true
-o.missingf.ff=date_dtdm
-o.missingf.ff.date_dtdm.sm=true
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/functions.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/functions.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/functions.txt
deleted file mode 100644
index e4930b6..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/functions.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-o.ar.s.sum=sum(add(int_id,float_fd))
-o.ar.s.sumc=sum(add_if_dd)
-o.ar.s.mean=mean(add(long_ld,double_dd,float_fd))
-o.ar.s.meanc=mean(add_ldf_dd)
-
-o.mr.s.sum=sum(mult(int_id,float_fd))
-o.mr.s.sumc=sum(mult_if_dd)
-o.mr.s.mean=mean(mult(long_ld,double_dd,float_fd))
-o.mr.s.meanc=mean(mult_ldf_dd)
-
-o.dr.s.sum=sum(div(int_id,float_fd))
-o.dr.s.sumc=sum(div_if_dd)
-o.dr.s.mean=mean(div(long_ld,double_dd))
-o.dr.s.meanc=mean(div_ld_dd)
-
-o.pr.s.sum=sum(pow(int_id,float_fd))
-o.pr.s.sumc=sum(pow_if_dd)
-o.pr.s.mean=mean(pow(long_ld,double_dd))
-o.pr.s.meanc=mean(pow_ld_dd)
-
-o.nr.s.sum=sum(neg(int_id))
-o.nr.s.sumc=sum(neg_i_dd)
-o.nr.s.mean=mean(neg(long_ld))
-o.nr.s.meanc=mean(neg_l_dd)
-
-o.avr.s.sum=sum(abs(neg(int_id)))
-o.avr.s.sumc=sum(int_id)
-o.avr.s.mean=mean(abs(neg(int_id)))
-o.avr.s.meanc=mean(int_id)
-
-o.cnr.s.sum=sum(const_num(8))
-o.cnr.s.sumc=sum(const_8_dd)
-o.cnr.s.mean=mean(const_num(10))
-o.cnr.s.meanc=mean(const_10_dd)
-
-o.dmr.s.median=median(date_math(date_dtd,const_str(+2YEARS)))
-o.dmr.s.medianc=median(dm_2y_dtd)
-o.dmr.s.max=max(date_math(date_dtd,const_str(+2MONTHS)))
-o.dmr.s.maxc=max(dm_2m_dtd)
-
-o.cdr.s.median=median(const_date(1800-06-30T23:59:59Z))
-o.cdr.s.medianc=median(const_00_dtd)
-o.cdr.s.max=max(const_date(1804-06-30T23:59:59Z))
-o.cdr.s.maxc=max(const_04_dtd)
-
-o.csr.s.min=min(const_str(this is the first))
-o.csr.s.minc=min(const_first_sd)
-o.csr.s.max=max(const_str(this is the second))
-o.csr.s.maxc=max(const_second_sd)
-
-o.cr.s.min=min(concat(const_str(this is the first),string_sd))
-o.cr.s.minc=min(concat_first_sd)
-o.cr.s.max=max(concat(const_str(this is the second),string_sd))
-o.cr.s.maxc=max(concat_second_sd)
-
-o.rr.s.min=min(rev(string_sd))
-o.rr.s.minc=min(rev_sd)
-o.rr.s.max=max(rev(string_sd))
-o.rr.s.maxc=max(rev_sd)
-
-o.ms.s.min=min(miss_dd)
-o.ms.s.max=max(miss_dd)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/noFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/noFacets.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/noFacets.txt
deleted file mode 100644
index b3d9163..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/noFacets.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-o.sr.s.int_id=sum(int_i)
-o.sr.s.long_ld=sum(long_l)
-o.sr.s.float_fd=sum(float_f)
-o.sr.s.double_dd=sum(double_d)
-
-o.sosr.s.int_id=sumofsquares(int_id)
-o.sosr.s.long_ld=sumofsquares(long_ld)
-o.sosr.s.float_fd=sumofsquares(float_fd)
-o.sosr.s.double_dd=sumofsquares(double_dd)
-
-o.mr.s.int_id=mean(int_id)
-o.mr.s.long_ld=mean(long_ld)
-o.mr.s.float_fd=mean(float_fd)
-o.mr.s.double_dd=mean(double_dd)
-
-o.str.s.int_id=stddev(int_id)
-o.str.s.long_ld=stddev(long_ld)
-o.str.s.float_fd=stddev(float_fd)
-o.str.s.double_dd=stddev(double_dd)
-
-o.medr.s.int_id=median(int_id)
-o.medr.s.long_ld=median(long_ld)
-o.medr.s.float_fd=median(float_fd)
-o.medr.s.double_dd=median(double_dd)
-o.medr.s.date_dtd=median(date_dtd)
-
-o.p2r.s.int_id=percentile(20,int_id)
-o.p2r.s.long_ld=percentile(20,long_ld)
-o.p2r.s.float_fd=percentile(20,float_fd)
-o.p2r.s.double_dd=percentile(20,double_dd)
-o.p2r.s.date_dtd=percentile(20,date_dtd)
-o.p2r.s.string_sd=percentile(20,string_sd)
-
-o.p6r.s.int_id=percentile(60,int_id)
-o.p6r.s.long_ld=percentile(60,long_ld)
-o.p6r.s.float_fd=percentile(60,float_fd)
-o.p6r.s.double_dd=percentile(60,double_dd)
-o.p6r.s.date_dtd=percentile(60,date_dtd)
-o.p6r.s.string_sd=percentile(60,string_sd)
-
-o.mir.s.int_id=min(int_id)
-o.mir.s.long_ld=min(long_ld)
-o.mir.s.float_fd=min(float_fd)
-o.mir.s.double_dd=min(double_dd)
-o.mir.s.date_dtd=min(date_dtd)
-o.mir.s.string_sd=min(string_sd)
-
-o.mar.s.int_id=max(int_id)
-o.mar.s.long_ld=max(long_ld)
-o.mar.s.float_fd=max(float_fd)
-o.mar.s.double_dd=max(double_dd)
-o.mar.s.date_dtd=max(date_dtd)
-o.mar.s.string_sd=max(string_sd)
-
-o.cr.s.int_id=count(int_id)
-o.cr.s.long_ld=count(long_ld)
-o.cr.s.float_fd=count(float_fd)
-o.cr.s.double_dd=count(double_dd)
-o.cr.s.date_dtd=count(date_dtd)
-o.cr.s.string_sd=count(string_sd)
-
-o.ur.s.int_id=unique(int_id)
-o.ur.s.long_ld=unique(long_ld)
-o.ur.s.float_fd=unique(float_fd)
-o.ur.s.double_dd=unique(double_dd)
-o.ur.s.date_dtd=unique(date_dtd)
-o.ur.s.string_sd=unique(string_sd)
-
-o.misr.s.int_id=missing(int_id)
-o.misr.s.long_ld=missing(long_ld)
-o.misr.s.float_fd=missing(float_fd)
-o.misr.s.double_dd=missing(double_dd)
-o.misr.s.date_dtd=missing(date_dtd)
-o.misr.s.string_sd=missing(string_sd)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/queryFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/queryFacets.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/queryFacets.txt
deleted file mode 100644
index 6be4a4e..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/queryFacets.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-o.ir.s.sum=sum(int_id)
-o.ir.s.mean=mean(int_id)
-o.ir.s.median=median(int_id)
-o.ir.s.percentile_8=percentile(8,int_id)
-o.ir.ff=string_sd
-o.ir.ff.string_sd.h=true
-o.ir.qf=float1
-o.ir.qf.float1.q=float_fd:[* TO 50]
-o.ir.qf=float2
-o.ir.qf.float2.q=float_fd:[* TO 30]
-
-o.pr.s.sum=sum(int_id)
-o.pr.s.mean=mean(int_id)
-o.pr.s.median=median(int_id)
-o.pr.s.q1=concat(const_str(float_fd:[), percentile(10,int_id), const_str( TO ), median(int_id), const_str(]))
-o.pr.hs.q2=concat(const_str(float_fd:[), percentile(30,int_id), const_str( TO ), median(int_id), const_str(]))
-o.pr.hs.q3=concat(const_str(float_fd:[), percentile(40,int_id), const_str( TO ), median(int_id), const_str(]))
-o.pr.s.percentile_8=percentile(8,int_id)
-o.pr.ff=string_sd
-o.pr.ff.string_sd.h=true
-o.pr.qf=float3
-o.pr.qf.float3.q=result(q1)
-o.pr.qf.float3.q=result(q2)
-o.pr.qf.float3.q=result(q3)
-o.pr.qf.float3.q=result(q1,string_sd,abc2)
-o.pr.qf=float4
-o.pr.qf.float4.d=float3
-o.pr.qf.float4.q=qresult(q1,float3,result(q1))
-
-o.lr.s.sum=sum(long_ld)
-o.lr.s.mean=mean(long_ld)
-o.lr.s.median=median(long_ld)
-o.lr.s.percentile_8=percentile(8,long_ld)
-o.lr.qf=string
-o.lr.qf.string.q=string_sd:abc1
-o.lr.qf.string.q=string_sd:abc2
-
-o.fr.s.sum=sum(float_fd)
-o.fr.s.mean=mean(float_fd)
-o.fr.s.median=median(float_fd)
-o.fr.s.percentile_8=percentile(8,float_fd)
-o.fr.qf=lad
-o.fr.qf.lad.q=long_ld:[20 TO *]
-o.fr.qf.lad.q=long_ld:[30 TO *]
-o.fr.qf.lad.q=double_dd:[* TO 50]
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestFiles/rangeFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestFiles/rangeFacets.txt b/solr/contrib/analytics/src/test-files/analytics/requestFiles/rangeFacets.txt
deleted file mode 100644
index cbfe052..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestFiles/rangeFacets.txt
+++ /dev/null
@@ -1,170 +0,0 @@
-o.ri.s.sum=sum(int_id)
-o.ri.s.mean=mean(int_id)
-o.ri.s.median=median(int_id)
-o.ri.s.count=count(int_id)
-o.ri.s.sumOfSquares=sumofsquares(int_id)
-o.ri.rf=long_ld
-o.ri.rf.long_ld.st=5
-o.ri.rf.long_ld.e=30
-o.ri.rf.long_ld.g=5
-o.ri.rf.long_ld.ib=lower
-o.ri.rf.long_ld.or=all
-o.ri.rf=double_dd
-o.ri.rf.double_dd.st=3
-o.ri.rf.double_dd.e=39
-o.ri.rf.double_dd.g=7
-o.ri.rf.double_dd.ib=upper
-o.ri.rf.double_dd.ib=outer
-o.ri.rf.double_dd.or=all
-o.ri.rf=date_dtd
-o.ri.rf.date_dtd.st=1007-01-01T23:59:59Z
-o.ri.rf.date_dtd.e=1044-01-01T23:59:59Z
-o.ri.rf.date_dtd.g=+7YEARS
-o.ri.rf.date_dtd.ib=lower
-o.ri.rf.date_dtd.ib=edge
-o.ri.rf.date_dtd.ib=outer
-o.ri.rf.date_dtd.or=all
-
-o.rf.s.sum=sum(float_fd)
-o.rf.s.mean=mean(float_fd)
-o.rf.s.median=median(float_fd)
-o.rf.s.count=count(float_fd)
-o.rf.s.sumOfSquares=sumofsquares(float_fd)
-o.rf.rf=long_ld
-o.rf.rf.long_ld.st=0
-o.rf.rf.long_ld.e=29
-o.rf.rf.long_ld.g=4
-o.rf.rf.long_ld.ib=all
-o.rf.rf.long_ld.or=all
-o.rf.rf=double_dd
-o.rf.rf.double_dd.st=4
-o.rf.rf.double_dd.e=47
-o.rf.rf.double_dd.g=11
-o.rf.rf.double_dd.ib=edge
-o.rf.rf.double_dd.or=all
-o.rf.rf=date_dtd
-o.rf.rf.date_dtd.st=1004-01-01T23:59:59Z
-o.rf.rf.date_dtd.e=1046-01-01T23:59:59Z
-o.rf.rf.date_dtd.g=+5YEARS
-o.rf.rf.date_dtd.ib=upper
-o.rf.rf.date_dtd.ib=edge
-o.rf.rf.date_dtd.or=all
-
-o.hi.s.sum=sum(int_id)
-o.hi.s.mean=mean(int_id)
-o.hi.s.median=median(int_id)
-o.hi.s.count=count(int_id)
-o.hi.s.sumOfSquares=sumofsquares(int_id)
-o.hi.rf=long_ld
-o.hi.rf.long_ld.st=5
-o.hi.rf.long_ld.e=30
-o.hi.rf.long_ld.g=5
-o.hi.rf.long_ld.he=true
-o.hi.rf.long_ld.ib=lower
-o.hi.rf.long_ld.or=all
-o.hi.rf=double_dd
-o.hi.rf.double_dd.st=3
-o.hi.rf.double_dd.e=39
-o.hi.rf.double_dd.g=7
-o.hi.rf.double_dd.he=true
-o.hi.rf.double_dd.ib=upper
-o.hi.rf.double_dd.ib=outer
-o.hi.rf.double_dd.or=all
-o.hi.rf=date_dtd
-o.hi.rf.date_dtd.st=1007-01-01T23:59:59Z
-o.hi.rf.date_dtd.e=1044-01-01T23:59:59Z
-o.hi.rf.date_dtd.g=+7YEARS
-o.hi.rf.date_dtd.he=true
-o.hi.rf.date_dtd.ib=lower
-o.hi.rf.date_dtd.ib=edge
-o.hi.rf.date_dtd.ib=outer
-o.hi.rf.date_dtd.or=all
-
-o.hf.s.sum=sum(float_fd)
-o.hf.s.mean=mean(float_fd)
-o.hf.s.median=median(float_fd)
-o.hf.s.count=count(float_fd)
-o.hf.s.sumOfSquares=sumofsquares(float_fd)
-o.hf.rf=long_ld
-o.hf.rf.long_ld.st=0
-o.hf.rf.long_ld.e=29
-o.hf.rf.long_ld.g=4
-o.hf.rf.long_ld.he=true
-o.hf.rf.long_ld.ib=all
-o.hf.rf.long_ld.or=all
-o.hf.rf=double_dd
-o.hf.rf.double_dd.st=4
-o.hf.rf.double_dd.e=47
-o.hf.rf.double_dd.g=11
-o.hf.rf.double_dd.he=true
-o.hf.rf.double_dd.ib=edge
-o.hf.rf.double_dd.or=all
-o.hf.rf=date_dtd
-o.hf.rf.date_dtd.st=1004-01-01T23:59:59Z
-o.hf.rf.date_dtd.e=1046-01-01T23:59:59Z
-o.hf.rf.date_dtd.g=+5YEARS
-o.hf.rf.date_dtd.he=true
-o.hf.rf.date_dtd.ib=upper
-o.hf.rf.date_dtd.ib=edge
-o.hf.rf.date_dtd.or=all
-
-o.mi.s.sum=sum(int_id)
-o.mi.s.mean=mean(int_id)
-o.mi.s.median=median(int_id)
-o.mi.s.count=count(int_id)
-o.mi.s.sumOfSquares=sumofsquares(int_id)
-o.mi.rf=long_ld
-o.mi.rf.long_ld.st=5
-o.mi.rf.long_ld.e=30
-o.mi.rf.long_ld.g=4,2,6,3
-o.mi.rf.long_ld.ib=lower
-o.mi.rf.long_ld.or=all
-o.mi.rf=double_dd
-o.mi.rf.double_dd.st=3
-o.mi.rf.double_dd.e=39
-o.mi.rf.double_dd.g=3,1,7
-o.mi.rf.double_dd.ib=upper
-o.mi.rf.double_dd.ib=outer
-o.mi.rf.double_dd.or=all
-o.mi.rf=date_dtd
-o.mi.rf.date_dtd.st=1007-01-01T23:59:59Z
-o.mi.rf.date_dtd.e=1044-01-01T23:59:59Z
-o.mi.rf.date_dtd.g=+2YEARS,+7YEARS
-o.mi.rf.date_dtd.ib=lower
-o.mi.rf.date_dtd.ib=edge
-o.mi.rf.date_dtd.ib=outer
-o.mi.rf.date_dtd.or=all
-
-o.mf.s.sum=sum(float_fd)
-o.mf.s.mean=mean(float_fd)
-o.mf.s.median=median(float_fd)
-o.mf.s.count=count(float_fd)
-o.mf.s.sumOfSquares=sumofsquares(float_fd)
-o.mf.rf=long_ld
-o.mf.rf.long_ld.st=0
-o.mf.rf.long_ld.e=29
-o.mf.rf.long_ld.g=1,4
-o.mf.rf.long_ld.ib=all
-o.mf.rf.long_ld.or=all
-o.mf.rf=double_dd
-o.mf.rf.double_dd.st=4
-o.mf.rf.double_dd.e=47
-o.mf.rf.double_dd.g=2,3,11
-o.mf.rf.double_dd.ib=edge
-o.mf.rf.double_dd.or=all
-o.mf.rf=date_dtd
-o.mf.rf.date_dtd.st=1004-01-01T23:59:59Z
-o.mf.rf.date_dtd.e=1046-01-01T23:59:59Z
-o.mf.rf.date_dtd.g=+4YEARS,+5YEARS
-o.mf.rf.date_dtd.ib=upper
-o.mf.rf.date_dtd.ib=edge
-o.mf.rf.date_dtd.or=all
-
-o.pf.s.mean=mean(float_fd)
-o.pf.hs.min=min(date_dtd)
-o.pf.hs.max=max(date_dtd)
-o.pf.hs.gap=const_str(+5YEARS)
-o.pf.rf=date_dtd
-o.pf.rf.date_dtd.st=result(min)
-o.pf.rf.date_dtd.e=result(max)
-o.pf.rf.date_dtd.g=result(gap)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/expressions.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/expressions.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/expressions.xml
deleted file mode 100644
index 2ce8abf..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/expressions.xml
+++ /dev/null
@@ -1,285 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>Add Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>unique</name>
- </statistic>
- <statistic>
- <expression>add(sum(int(int_id)),unique(long(long_ld)))</expression>
- <name>add sum and unique</name>
- </statistic>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>add(mean(int(int_id)),count(long(long_ld)),median(int(int_id)))</expression>
- <name>add mean and count and median</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Multiply Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>unique</name>
- </statistic>
- <statistic>
- <expression>mult(sum(int(int_id)),unique(long(long_ld)))</expression>
- <name>multiply sum and unique</name>
- </statistic>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>mult(mean(int(int_id)),count(long(long_ld)),median(int(int_id)))</expression>
- <name>multiply mean and count and median</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Divide Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>unique</name>
- </statistic>
- <statistic>
- <expression>div(sum(int(int_id)),unique(long(long_ld)))</expression>
- <name>divide sum by unique</name>
- </statistic>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>div(mean(int(int_id)),count(long(long_ld)))</expression>
- <name>divide mean by count</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Power Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>unique</name>
- </statistic>
- <statistic>
- <expression>pow(sum(int(int_id)),unique(long(long_ld)))</expression>
- <name>power sum by unique</name>
- </statistic>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>pow(mean(int(int_id)),count(long(long_ld)))</expression>
- <name>power mean by count</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Negate Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>neg(sum(int(int_id)))</expression>
- <name>negate of sum</name>
- </statistic>
-
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>neg(count(long(long_ld)))</expression>
- <name>negate of count</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Const Num Request</name>
-
- <statistic>
- <expression>const_num(8)</expression>
- <name>constant 8</name>
- </statistic>
- <statistic>
- <expression>const_num(10)</expression>
- <name>constant 10</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Date Math Request</name>
-
- <statistic>
- <expression>median(date(date_dtd))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>const_str(+2YEARS)</expression>
- <name>constant str median</name>
- </statistic>
- <statistic>
- <expression>date_math(median(date(date_dtd)),const_str(+2YEARS))</expression>
- <name>date math median</name>
- </statistic>
-
- <statistic>
- <expression>max(date(date_dtd))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>const_str(+2MONTHS)</expression>
- <name>constant str max</name>
- </statistic>
- <statistic>
- <expression>date_math(max(date(date_dtd)),const_str(+2MONTHS))</expression>
- <name>date math max</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Constant Date Request</name>
-
- <statistic>
- <expression>const_str(1800-12-31T23:59:59Z)</expression>
- <name>const str 1</name>
- </statistic>
- <statistic>
- <expression>const_date(1800-12-31T23:59:59Z)</expression>
- <name>const date 1</name>
- </statistic>
- <statistic>
- <expression>const_str(1804-06-30T23:59:59Z)</expression>
- <name>const str 2</name>
- </statistic>
- <statistic>
- <expression>const_date(1804-06-30T23:59:59Z)</expression>
- <name>const date 2</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Constant String Request</name>
-
- <statistic>
- <expression>const_str(this is the first)</expression>
- <name>const str 1</name>
- </statistic>
- <statistic>
- <expression>const_str(this is the second)</expression>
- <name>const str 2</name>
- </statistic>
- <statistic>
- <expression>const_str(this is the third)</expression>
- <name>const str 3</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Concatenate Request</name>
-
- <statistic>
- <expression>const_str(this is the first)</expression>
- <name>const str min</name>
- </statistic>
- <statistic>
- <expression>min(str(string_sd))</expression>
- <name>min</name>
- </statistic>
- <statistic>
- <expression>concat(const_str(this is the first),min(str(string_sd)))</expression>
- <name>concat const and min</name>
- </statistic>
-
- <statistic>
- <expression>const_str(this is the second)</expression>
- <name>const str max</name>
- </statistic>
- <statistic>
- <expression>max(str(string_sd))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>concat(const_str(this is the second),max(str(string_sd)))</expression>
- <name>concat const and max</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Reverse Request</name>
-
- <statistic>
- <expression>min(str(string_sd))</expression>
- <name>min</name>
- </statistic>
- <statistic>
- <expression>rev(min(str(string_sd)))</expression>
- <name>reverse min</name>
- </statistic>
-
- <statistic>
- <expression>max(str(string_sd))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>rev(max(str(string_sd)))</expression>
- <name>reverse max</name>
- </statistic>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacetExtras.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacetExtras.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacetExtras.xml
deleted file mode 100644
index 68b5be9..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacetExtras.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>sort request</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>perc(20,int(int_id))</expression>
- <name>perc_20</name>
- </statistic>
-
- <fieldFacet>
- <field>long_ld</field>
- <sortSpecification>
- <statName>mean</statName>
- <direction>asc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet>
- <field>float_fd</field>
- <sortSpecification>
- <statName>median</statName>
- <direction>desc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet>
- <field>double_dd</field>
- <sortSpecification>
- <statName>count</statName>
- <direction>asc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet>
- <field>string_sd</field>
- <sortSpecification>
- <statName>perc_20</statName>
- <direction>desc</direction>
- </sortSpecification>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>limit request</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>perc(20,int(int_id))</expression>
- <name>perc_20</name>
- </statistic>
-
- <fieldFacet limit="5">
- <field>long_ld</field>
- <sortSpecification>
- <statName>mean</statName>
- <direction>asc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet limit="3">
- <field>float_fd</field>
- <sortSpecification>
- <statName>median</statName>
- <direction>desc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet limit="7">
- <field>double_dd</field>
- <sortSpecification>
- <statName>count</statName>
- <direction>asc</direction>
- </sortSpecification>
- </fieldFacet>
- <fieldFacet limit="1">
- <field>string_sd</field>
- <sortSpecification>
- <statName>perc_20</statName>
- <direction>desc</direction>
- </sortSpecification>
- </fieldFacet>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacets.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacets.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacets.xml
deleted file mode 100644
index 8e84cf1..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/fieldFacets.xml
+++ /dev/null
@@ -1,496 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>sum</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>sum(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>sum(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>mean</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>mean(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>mean(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>sumOfSquares</name>
-
- <statistic>
- <expression>sumofsquares(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>stddev</name>
-
- <statistic>
- <expression>stddev(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>stddev(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>stddev(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>stddev(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>median</name>
-
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>median(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>median(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>perc_20 numeric</name>
-
- <statistic>
- <expression>perc(20,int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>perc(20,long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>perc(20,float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>perc(20,double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>perc_20</name>
-
- <statistic>
- <expression>perc(20,str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>perc(20,date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>perc_60 numeric</name>
-
- <statistic>
- <expression>perc(60,int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>perc(60,long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>perc(60,float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>perc(60,double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>perc_60</name>
-
- <statistic>
- <expression>perc(60,str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>perc(60,date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>min numeric</name>
-
- <statistic>
- <expression>min(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>min(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>min(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>min(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>min</name>
-
- <statistic>
- <expression>min(str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>min(date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>max numeric</name>
-
- <statistic>
- <expression>max(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>max(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>max(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>max(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>max</name>
-
- <statistic>
- <expression>max(str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>max(date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>count numeric</name>
-
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>count(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>count(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>count</name>
-
- <statistic>
- <expression>count(str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>count(date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>unique numeric</name>
-
- <statistic>
- <expression>unique(int(int_id))</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>unique(float(float_fd))</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>unique(double(double_dd))</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>unique</name>
-
- <statistic>
- <expression>unique(str(string_sd))</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>unique(date(date_dtd))</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>missing numeric</name>
-
- <statistic>
- <expression>missing(int{int_id})</expression>
- <name>int</name>
- </statistic>
- <statistic>
- <expression>missing(long{long_ld})</expression>
- <name>long</name>
- </statistic>
- <statistic>
- <expression>missing(float{float_fd})</expression>
- <name>float</name>
- </statistic>
- <statistic>
- <expression>missing(double{double_dd})</expression>
- <name>double</name>
- </statistic>
-
- <fieldFacet>
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>missing</name>
-
- <statistic>
- <expression>missing(str{string_sd})</expression>
- <name>str</name>
- </statistic>
- <statistic>
- <expression>missing(date{date_dtd})</expression>
- <name>date</name>
- </statistic>
-
- <fieldFacet>
- <field>int_id</field>
- </fieldFacet>
- <fieldFacet>
- <field>long_ld</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>multivalued</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
-
- <fieldFacet>
- <field>long_ldm</field>
- </fieldFacet>
- <fieldFacet>
- <field>string_sdm</field>
- </fieldFacet>
- <fieldFacet>
- <field>date_dtdm</field>
- </fieldFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>missing facet</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
-
- <fieldFacet>
- <field>date_dtd</field>
- </fieldFacet>
- <fieldFacet showMissing="true">
- <field>string_sd</field>
- </fieldFacet>
- <fieldFacet showMissing="true">
- <field>date_dtdm</field>
- </fieldFacet>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/functions.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/functions.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/functions.xml
deleted file mode 100644
index 8fa92b6..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/functions.xml
+++ /dev/null
@@ -1,246 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>Add Request</name>
-
- <statistic>
- <expression>sum(add(int(int_id),float(float_fd)))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(add_if_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(add(long(long_ld),double(double_dd),float(float_fd)))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>mean(double(add_ldf_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Multiply Request</name>
-
- <statistic>
- <expression>sum(mult(int(int_id),float(float_fd)))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(mult_if_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(mult(long(long_ld),double(double_dd),float(float_fd)))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>mean(double(mult_ldf_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Divide Request</name>
-
- <statistic>
- <expression>sum(div(int(int_id),float(float_fd)))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(div_if_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(div(long(long_ld),double(double_dd)))</expression>
- <name>mean</name>
- </statistic>
-
- <statistic>
- <expression>mean(double(div_ld_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Power Request</name>
-
- <statistic>
- <expression>sum(pow(int(int_id),float(float_fd))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(pow_if_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(pow(long(long_ld),double(double_dd)))</expression>
- <name>mean</name>
- </statistic>
-
- <statistic>
- <expression>mean(double(pow_ld_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Negate Request</name>
-
- <statistic>
- <expression>sum(neg(int(int_id)))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(neg_i_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(neg(long(long_ld)))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>mean(double(neg_l_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Const Num Request</name>
-
- <statistic>
- <expression>sum(const_num(8))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>sum(double(const_8_dd))</expression>
- <name>sum calced</name>
- </statistic>
-
- <statistic>
- <expression>mean(const_num(10))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>mean(double(const_10_dd))</expression>
- <name>mean calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Date Math Request</name>
-
- <statistic>
- <expression>median(date_math(date(date_dtd),const_str(+2YEARS)))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>median(date(dm_2y_dtd))</expression>
- <name>median calced</name>
- </statistic>
-
- <statistic>
- <expression>max(date_math(date(date_dtd),const_str(+2MONTHS)))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>max(date(dm_2m_dtd))</expression>
- <name>max calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Constant Date Request</name>
-
- <statistic>
- <expression>median(const_date(1800-06-30T23:59:59Z))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>median(date(const_00_dtd))</expression>
- <name>median calced</name>
- </statistic>
-
- <statistic>
- <expression>max(const_date(1804-06-30T23:59:59Z))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>max(date(const_04_dtd))</expression>
- <name>max calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Constant String Request</name>
-
- <statistic>
- <expression>min(const_str(this is the first))</expression>
- <name>min</name>
- </statistic>
- <statistic>
- <expression>min(str(const_first_sd))</expression>
- <name>min calced</name>
- </statistic>
-
- <statistic>
- <expression>max(const_str(this is the second))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>max(str(const_second_sd))</expression>
- <name>max calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Concatenate Request</name>
-
- <statistic>
- <expression>min(concat(const_str(this is the first),str(string_sd)))</expression>
- <name>min</name>
- </statistic>
- <statistic>
- <expression>min(str(concat_first_sd))</expression>
- <name>min calced</name>
- </statistic>
-
- <statistic>
- <expression>max(concat(const_str(this is the second),str(string_sd)))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>max(str(concat_second_sd))</expression>
- <name>max calced</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Reverse Request</name>
-
- <statistic>
- <expression>min(rev(str(string_sd)))</expression>
- <name>min</name>
- </statistic>
- <statistic>
- <expression>min(str(rev_sd))</expression>
- <name>min calced</name>
- </statistic>
-
- <statistic>
- <expression>max(rev(str(string_sd)))</expression>
- <name>max</name>
- </statistic>
- <statistic>
- <expression>max(str(rev_sd))</expression>
- <name>max calced</name>
- </statistic>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/noFacets.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/noFacets.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/noFacets.xml
deleted file mode 100644
index 2813d18..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/noFacets.xml
+++ /dev/null
@@ -1,310 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>Sum Request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>sum(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>sum(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>SumOfSquares Request</name>
-
- <statistic>
- <expression>sumofsquares(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Mean Request</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>mean(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>mean(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Stddev Request</name>
-
- <statistic>
- <expression>stddev(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>stddev(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>stddev(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>stddev(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Median Request</name>
-
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>median(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>median(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Perc 20 Request</name>
-
- <statistic>
- <expression>perc(20,int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>perc(20,long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>perc(20,float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>perc(20,double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>perc(20,date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>perc(20,str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Perc 60 Request</name>
-
- <statistic>
- <expression>perc(60,int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>perc(60,long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>perc(60,float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>perc(60,double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>perc(60,date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>perc(60,str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Min Request</name>
-
- <statistic>
- <expression>min(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>min(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>min(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>min(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>min(date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>min(str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Max Request</name>
-
- <statistic>
- <expression>max(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>max(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>max(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>max(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>max(date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>max(str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Unique Request</name>
-
- <statistic>
- <expression>unique(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>unique(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>unique(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>unique(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>unique(date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>unique(str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Count Request</name>
-
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>count(long(long_ld))</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>count(float(float_fd))</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>count(double(double_dd))</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>count(date(date_dtd))</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>count(str(string_sd))</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-
- <analyticsRequest>
- <name>Missing Request</name>
-
- <statistic>
- <expression>missing(int{int_id})</expression>
- <name>int_id</name>
- </statistic>
- <statistic>
- <expression>missing(long{long_ld})</expression>
- <name>long_ld</name>
- </statistic>
- <statistic>
- <expression>missing(float{float_fd})</expression>
- <name>float_fd</name>
- </statistic>
- <statistic>
- <expression>missing(double{double_dd})</expression>
- <name>double_dd</name>
- </statistic>
- <statistic>
- <expression>missing(date{date_dtd})</expression>
- <name>date_dtd</name>
- </statistic>
- <statistic>
- <expression>missing(str{string_sd})</expression>
- <name>string_sd</name>
- </statistic>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/queryFacets.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/queryFacets.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/queryFacets.xml
deleted file mode 100644
index f5c7191..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/queryFacets.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>int request</name>
-
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
-
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
-
- <statistic>
- <expression>perc(8,int(int_id))</expression>
- <name>perc_8</name>
- </statistic>
-
- <queryFacet>
- <name>float1</name>
- <query>float_fd:[* TO 50]</query>
- </queryFacet>
- <queryFacet>
- <name>float2</name>
- <query>float_fd:[* TO 30]</query>
- </queryFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>long request</name>
-
- <statistic>
- <expression>sum(long(long_ld))</expression>
- <name>sum</name>
- </statistic>
-
- <statistic>
- <expression>mean(long(long_ld))</expression>
- <name>mean</name>
- </statistic>
-
- <statistic>
- <expression>median(long(long_ld))</expression>
- <name>median</name>
- </statistic>
-
- <statistic>
- <expression>perc(8,long(long_ld))</expression>
- <name>perc_8</name>
- </statistic>
-
- <queryFacet>
- <name>string</name>
- <query>string_sd:abc1</query>
- <query>string_sd:abc2</query>
- </queryFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>float request</name>
-
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>sum</name>
- </statistic>
-
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>mean</name>
- </statistic>
-
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>median</name>
- </statistic>
-
- <statistic>
- <expression>perc(8,float(float_fd))</expression>
- <name>perc_8</name>
- </statistic>
-
- <queryFacet>
- <name>long and double</name>
- <query>long_ld:[20 TO *]</query>
- <query>long_ld:[30 TO *]</query>
- <query>double_dd:[* TO 50]</query>
- </queryFacet>
- </analyticsRequest>
-</analyticsRequestEnvelope>
[19/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/ExpressionFactory.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/ExpressionFactory.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/ExpressionFactory.java
new file mode 100644
index 0000000..b59469f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/ExpressionFactory.java
@@ -0,0 +1,821 @@
+/*
+ * 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.analytics;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.solr.analytics.function.MergingReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.mapping.*;
+import org.apache.solr.analytics.function.mapping.CompareFunction.EqualFunction;
+import org.apache.solr.analytics.function.mapping.CompareFunction.GTEFunction;
+import org.apache.solr.analytics.function.mapping.CompareFunction.GTFunction;
+import org.apache.solr.analytics.function.mapping.CompareFunction.LTEFunction;
+import org.apache.solr.analytics.function.mapping.CompareFunction.LTFunction;
+import org.apache.solr.analytics.function.mapping.ConcatFunction.ConcatSeparatedFunction;
+import org.apache.solr.analytics.function.mapping.NumericConvertFunction.CeilingFunction;
+import org.apache.solr.analytics.function.mapping.NumericConvertFunction.FloorFunction;
+import org.apache.solr.analytics.function.mapping.NumericConvertFunction.RoundFunction;
+import org.apache.solr.analytics.function.mapping.LogicFunction.AndFunction;
+import org.apache.solr.analytics.function.mapping.LogicFunction.OrFunction;
+import org.apache.solr.analytics.function.reduction.*;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.value.*;
+import org.apache.solr.analytics.value.AnalyticsValueStream.ExpressionType;
+import org.apache.solr.analytics.value.constant.ConstantValue;
+import org.apache.solr.analytics.function.field.*;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.schema.BoolField;
+import org.apache.solr.schema.DatePointField;
+import org.apache.solr.schema.DoublePointField;
+import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.FloatPointField;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.IntPointField;
+import org.apache.solr.schema.LongPointField;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.StrField;
+import org.apache.solr.schema.TrieDateField;
+import org.apache.solr.schema.TrieDoubleField;
+import org.apache.solr.schema.TrieFloatField;
+import org.apache.solr.schema.TrieIntField;
+import org.apache.solr.schema.TrieLongField;
+
+/**
+ * A factory to parse and create expressions, and capture information about those expressions along the way.
+ *
+ * <p>
+ * In order to use, first call {@link #startRequest()} and create all ungrouped expressions,
+ * then call {@link #createReductionManager} to get the ungrouped reduction manager.
+ * <br>
+ * Then for each grouping call {@link #startGrouping()} first then create all expressions within that grouping,
+ * finally calling {@link #createGroupingReductionManager} to get the reduction manager for that grouping.
+ */
+public class ExpressionFactory {
+ private static final Pattern functionNamePattern = Pattern.compile("^\\s*([^().\\s]+)\\s*(?:\\(.*\\)\\s*)?$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern functionParamsPattern = Pattern.compile("^\\s*(?:[^(.)]+)\\s*\\(\\s*(.+)\\s*\\)\\s*$", Pattern.CASE_INSENSITIVE);
+ private static final String funtionVarParamUniqueName = ".%s_(%d)";
+
+ /**
+ * Used to denote a variable length parameter.
+ */
+ public final static String variableLengthParamSuffix = "..";
+ /**
+ * The character used to denote the start of a for each lambda expression
+ */
+ public final static char variableForEachSep = ':';
+ /**
+ * The character used to denote the looped parameter in the for each lambda expression
+ */
+ public final static char variableForEachParam = '_';
+
+ private HashMap<String, VariableFunctionInfo> systemVariableFunctions;
+ private HashMap<String, VariableFunctionInfo> variableFunctions;
+ private HashSet<String> variableFunctionNameHistory;
+
+ private HashMap<String, CreatorFunction> expressionCreators;
+ private final ConstantFunction constantCreator;
+
+ private LinkedHashMap<String, ReductionFunction> reductionFunctions;
+ private LinkedHashMap<String, ReductionDataCollector<?>> collectors;
+ private LinkedHashMap<String, AnalyticsField> fields;
+ private HashMap<String, AnalyticsValueStream> expressions;
+
+ private IndexSchema schema;
+
+ private Map<String, ReductionDataCollector<?>> groupedCollectors;
+ private Map<String, AnalyticsField> groupedFields;
+ private boolean isGrouped;
+
+ public ExpressionFactory(IndexSchema schema) {
+ this.schema = schema;
+
+ expressionCreators = new HashMap<>();
+ systemVariableFunctions = new HashMap<>();
+
+ constantCreator = ConstantValue.creatorFunction;
+ addSystemFunctions();
+ }
+
+ /**
+ * Get the index schema used by this factory.
+ *
+ * @return the index schema
+ */
+ public IndexSchema getSchema() {
+ return schema;
+ }
+
+ /**
+ * Prepare the factory to start building the request.
+ */
+ public void startRequest() {
+ reductionFunctions = new LinkedHashMap<>();
+ collectors = new LinkedHashMap<>();
+ fields = new LinkedHashMap<>();
+ expressions = new HashMap<>();
+
+ variableFunctions = new HashMap<>();
+ variableFunctions.putAll(systemVariableFunctions);
+ variableFunctionNameHistory = new HashSet<>();
+
+ isGrouped = false;
+ }
+
+ /**
+ * Prepare the factory to start building the next grouping.
+ * <br>
+ * NOTE: MUST be called before each new grouping.
+ */
+ public void startGrouping() {
+ groupedCollectors = new HashMap<>();
+ groupedFields = new HashMap<>();
+
+ isGrouped = true;
+ }
+
+ /**
+ * Add a system function to the expression factory.
+ * This will be treated as a native function and not a variable function.
+ *
+ * @param functionName the unique name for the function
+ * @param functionCreator the creator function to generate an expression
+ * @return this factory, to easily chain function adds
+ * @throws SolrException if the functionName is not unique
+ */
+ public ExpressionFactory addSystemFunction(final String functionName, final CreatorFunction functionCreator) throws SolrException {
+ if (expressionCreators.containsKey(functionName)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"System function " + functionName + " defined twice.");
+ }
+ expressionCreators.put(CountFunction.name, CountFunction.creatorFunction);
+ return this;
+ }
+
+ /**
+ * Add a variable function that will be treated like a system function.
+ *
+ * @param functionSignature the function signature of the variable function (e.g. {@code func(a,b)} )
+ * @param returnSignature the return signature of the variable function (e.g. {@code div(sum(a,b),count(b))} )
+ * @return this factory, to easily chain function adds
+ * @throws SolrException if the name of the function is not unique or the syntax of either signature is incorrect
+ */
+ public ExpressionFactory addSystemVariableFunction(final String functionSignature, final String returnSignature) throws SolrException {
+ return addVariableFunction(functionSignature, returnSignature, systemVariableFunctions);
+ }
+
+ /**
+ * Add a variable function that was defined in an analytics request.
+ *
+ * @param functionSignature the function signature of the variable function (e.g. {@code func(a,b)} )
+ * @param returnSignature the return signature of the variable function (e.g. {@code div(sum(a,b),count(b))} )
+ * @return this factory, to easily chain function adds
+ * @throws SolrException if the name of the function is not unique or the syntax of either signature is incorrect
+ */
+ public ExpressionFactory addUserDefinedVariableFunction(final String functionSignature, final String returnSignature) throws SolrException {
+ return addVariableFunction(functionSignature, returnSignature, variableFunctions);
+ }
+
+ /**
+ * Add a variable function to the given map of variable functions.
+ *
+ * @param functionSignature the function signature of the variable function (e.g. {@code func(a,b)} )
+ * @param returnSignature the return signature of the variable function (e.g. {@code div(sum(a,b),count(b))} )
+ * @param variableFunctions the map of variable functions to add the new function to
+ * @return this factory, to easily chain function adds
+ * @throws SolrException if the name of the function is not unique or the syntax of either signature is incorrect
+ */
+ private ExpressionFactory addVariableFunction(final String functionSignature,
+ final String returnSignature,
+ Map<String,VariableFunctionInfo> variableFunctions) throws SolrException {
+ String functionName = getFunctionName(functionSignature);
+ if (expressionCreators.containsKey(functionName)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Users cannot define a variable function with the same name as an existing function: " + functionName);
+ }
+ VariableFunctionInfo varFuncInfo = new VariableFunctionInfo();
+ varFuncInfo.params = getParams(functionSignature, null, null);
+ varFuncInfo.returnSignature = returnSignature;
+ variableFunctions.put(functionName, varFuncInfo);
+ return this;
+ }
+
+ /**
+ * Create a reduction manager to manage the collection of all expressions that have been created since
+ * {@link #startRequest()} was called.
+ *
+ * @param isCloudCollection whether the request is a distributed request
+ * @return a reduction manager
+ */
+ public ReductionCollectionManager createReductionManager(boolean isCloudCollection) {
+ ReductionDataCollector<?>[] collectorsArr = new ReductionDataCollector<?>[collectors.size()];
+ collectors.values().toArray(collectorsArr);
+ if (isCloudCollection) {
+ return new MergingReductionCollectionManager(collectorsArr, fields.values());
+ } else {
+ return new ReductionCollectionManager(collectorsArr, fields.values());
+ }
+ }
+
+ /**
+ * Create a reduction manager to manage the collection of all expressions that have been created since
+ * {@link #startGrouping()} was called.
+ *
+ * @param isCloudCollection whether the request is a distributed request
+ * @return a reduction manager
+ */
+ public ReductionCollectionManager createGroupingReductionManager(boolean isCloudCollection) {
+ ReductionDataCollector<?>[] collectorsArr = new ReductionDataCollector<?>[groupedCollectors.size()];
+ groupedCollectors.values().toArray(collectorsArr);
+ if (isCloudCollection) {
+ return new MergingReductionCollectionManager(collectorsArr, groupedFields.values());
+ } else {
+ return new ReductionCollectionManager(collectorsArr, groupedFields.values());
+ }
+ }
+
+ /**
+ * Parse and build an expression from the given expression string.
+ *
+ * @param expressionStr string that represents the desired expression
+ * @return the object representation of the expression
+ * @throws SolrException if an error occurs while constructing the expression
+ */
+ public AnalyticsValueStream createExpression(String expressionStr) throws SolrException {
+ return createExpression(expressionStr, new HashMap<>(), null, null);
+ }
+
+ /**
+ * Create an expression from the given expression string, with the given variable function information.
+ *
+ * @param expressionStr string that represents the desired expression
+ * @param varFuncParams the current set of variable function parameters and their values. If this expression is not a variable function
+ * return signature, the map should be empty.
+ * @param varFuncVarParamName if the current expression is a variable function return signature, this must be the name of the variable length
+ * parameter if it is included in the function signature.
+ * @param varFuncVarParamValues if the current expression is a variable function return signature, this must be the array values of the variable length
+ * parameter if they are included when calling the function.
+ * @return the object representation of the expression
+ * @throws SolrException if an error occurs while constructing the expression
+ */
+ private AnalyticsValueStream createExpression(String expressionStr, Map<String,AnalyticsValueStream> varFuncParams,
+ String varFuncVarParamName, String[] varFuncVarParamValues) throws SolrException {
+ AnalyticsValueStream expression;
+ expressionStr = expressionStr.trim();
+
+ boolean isField = false;
+ try {
+ // Try to make a constant value
+ expression = constantCreator.apply(expressionStr);
+ } catch (SolrException e1) {
+ // Not a constant
+ // If the expression has parens, it is an expression otherwise it is a field
+ if (!expressionStr.contains("(")) {
+ try {
+ // Try to make a field out of it
+ expression = createField(schema.getField(expressionStr));
+ isField = true;
+ } catch (SolrException e2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following is not a field, constant or function : " + expressionStr);
+ }
+ } else {
+ // Must be a function
+ expression = createFunction(expressionStr, varFuncParams, varFuncVarParamName, varFuncVarParamValues);
+ }
+ }
+
+ // Try to use an already made expression instead of the new one.
+ // This will decrease the amount of collection needed to be done.
+ if (expressions.containsKey(expression.getExpressionStr())) {
+ expression = expressions.get(expression.getExpressionStr());
+ // If this is a grouped expression, make sure that the reduction info for the expression is included in the grouped reduction manager.
+ if (expression.getExpressionType() == ExpressionType.REDUCTION && isGrouped) {
+ ((ReductionFunction)expression).synchronizeDataCollectors( collector -> {
+ groupedCollectors.put(collector.getExpressionStr(), collector);
+ return collector;
+ });
+ }
+ }
+ else {
+ expressions.put(expression.getExpressionStr(), expression);
+ // Make sure that the reduction info for the expression is included in the reduction manager and grouped reduction manager if necessary.
+ if (expression.getExpressionType() == ExpressionType.REDUCTION) {
+ reductionFunctions.put(expression.getExpressionStr(), (ReductionFunction)expression);
+ ((ReductionFunction)expression).synchronizeDataCollectors( collector -> {
+ String collectorStr = collector.getExpressionStr();
+ ReductionDataCollector<?> usedCollector = collectors.get(collectorStr);
+ if (usedCollector == null) {
+ usedCollector = collector;
+ collectors.put(collectorStr, collector);
+ }
+ if (isGrouped) {
+ groupedCollectors.put(collectorStr, usedCollector);
+ }
+ return usedCollector;
+ });
+ }
+ // Add the field info to the reduction manager
+ if (isField) {
+ fields.put(expression.getExpressionStr(), (AnalyticsField)expression);
+ }
+ }
+ // If this is a grouped expression, make sure that the field info is included in the grouped reduction manager.
+ if (isField && isGrouped) {
+ groupedFields.put(expression.getExpressionStr(), (AnalyticsField)expression);
+ }
+ return expression;
+ }
+
+ /**
+ * Create a function expression from the given expression string, with the given variable function information.
+ *
+ * @param expressionStr string that represents the desired expression
+ * @param varFuncParams the current set of variable function parameters and their values. If this expression is not a variable function
+ * return signature, the map should be empty.
+ * @param varFuncVarParamName if the current expression is a variable function return signature, this must be the name of the variable length
+ * parameter if it is included in the function signature.
+ * @param varFuncVarParamValues if the current expression is a variable function return signature, this must be the array values of the variable length
+ * parameter if they are included when calling the function.
+ * @return the object representation of the expression
+ * @throws SolrException if an error occurs while constructing the expression
+ */
+ private AnalyticsValueStream createFunction(String expressionStr, Map<String,AnalyticsValueStream> varFuncParams,
+ String varFuncVarParamName, String[] varFuncVarParamValues) throws SolrException {
+ AnalyticsValueStream expression = null;
+ String name = getFunctionName(expressionStr);
+
+ final String[] params = getParams(expressionStr, varFuncVarParamName, varFuncVarParamValues);
+ AnalyticsValueStream[] paramStreams = new AnalyticsValueStream[params.length];
+ for (int i = 0; i < params.length; i++) {
+ // First check if the parameter is a variable function variable otherwise create the expression
+ if (varFuncParams.containsKey(params[i])) {
+ paramStreams[i] = varFuncParams.get(params[i]);
+ } else {
+ paramStreams[i] = createExpression(params[i], varFuncParams, varFuncVarParamName, varFuncVarParamValues);
+ }
+ }
+ // Check to see if the function name is a variable function name, if so apply the variables to the return signature
+ if (variableFunctions.containsKey(name)) {
+ if (variableFunctionNameHistory.contains(name)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following variable function is self referencing : " + name);
+ }
+ variableFunctionNameHistory.add(name);
+ VariableFunctionInfo newVarFunc = variableFunctions.get(name);
+ Map<String, AnalyticsValueStream> newVarFuncParams = new HashMap<>();
+
+ boolean varLenEnd = false;
+
+ for (int i = 0; i < newVarFunc.params.length; ++i) {
+ String variable = newVarFunc.params[i];
+ if (variable.endsWith(variableLengthParamSuffix)) {
+ if (i != newVarFunc.params.length - 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following invocation of a variable function has the incorrect number of arguments : " + expressionStr);
+ }
+ variable = variable.substring(0, variable.length() - variableLengthParamSuffix.length()).trim();
+ int numVars = paramStreams.length - i;
+ String[] newVarFuncVarParamValues = new String[numVars];
+ for (int j = 0; j < numVars; ++j) {
+ // Create a new name for each variable length parameter value
+ String paramName = String.format(Locale.ROOT, funtionVarParamUniqueName, variable, j);
+ newVarFuncVarParamValues[j] = paramName;
+ newVarFuncParams.put(paramName, paramStreams[i + j]);
+ }
+ expression = createFunction(newVarFunc.returnSignature, newVarFuncParams, variable, newVarFuncVarParamValues);
+ varLenEnd = true;
+ } else {
+ newVarFuncParams.put(variable, paramStreams[i]);
+ }
+ }
+ if (!varLenEnd) {
+ expression = createExpression(newVarFunc.returnSignature, newVarFuncParams, null, null);
+ }
+ variableFunctionNameHistory.remove(name);
+ return expression;
+ } else if (expressionCreators.containsKey(name)) {
+ // It is a regular system function
+ expression = expressionCreators.get(name).apply(paramStreams);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following function does not exist: " + name);
+ }
+ return expression;
+ }
+
+ /**
+ * Create an {@link AnalyticsField} out of the given {@link SchemaField}.
+ * <p>
+ * Currently only fields with doc-values enabled are supported.
+ *
+ * @param field the field to convert for analytics
+ * @return an analytics representation of the field
+ * @throws SolrException if the field is not supported by the analytics framework
+ */
+ private AnalyticsField createField(SchemaField field) throws SolrException {
+ String fieldName = field.getName();
+ if (fields.containsKey(fieldName)) {
+ return fields.get(fieldName);
+ }
+ if (!field.hasDocValues()) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The field "+fieldName+" does not have docValues enabled.");
+ }
+ boolean multivalued = field.multiValued();
+ FieldType fieldType = field.getType();
+ AnalyticsField aField;
+ if (fieldType instanceof BoolField) {
+ if (multivalued) {
+ aField = new BooleanMultiField(fieldName);
+ } else {
+ aField = new BooleanField(fieldName);
+ }
+ } else if (fieldType instanceof TrieIntField) {
+ if (multivalued) {
+ aField = new IntMultiField(fieldName);
+ } else {
+ aField = new IntField(fieldName);
+ }
+ } else if (fieldType instanceof IntPointField) {
+ if (multivalued) {
+ aField = new IntMultiPointField(fieldName);
+ } else {
+ aField = new IntField(fieldName);
+ }
+ } else if (fieldType instanceof TrieLongField) {
+ if (multivalued) {
+ aField = new LongMultiField(fieldName);
+ } else {
+ aField = new LongField(fieldName);
+ }
+ } else if (fieldType instanceof LongPointField) {
+ if (multivalued) {
+ aField = new LongMultiPointField(fieldName);
+ } else {
+ aField = new LongField(fieldName);
+ }
+ } else if (fieldType instanceof TrieFloatField) {
+ if (multivalued) {
+ aField = new FloatMultiField(fieldName);
+ } else {
+ aField = new FloatField(fieldName);
+ }
+ } else if (fieldType instanceof FloatPointField) {
+ if (multivalued) {
+ aField = new FloatMultiPointField(fieldName);
+ } else {
+ aField = new FloatField(fieldName);
+ }
+ } else if (fieldType instanceof TrieDoubleField) {
+ if (multivalued) {
+ aField = new DoubleMultiField(fieldName);
+ } else {
+ aField = new DoubleField(fieldName);
+ }
+ } else if (fieldType instanceof DoublePointField) {
+ if (multivalued) {
+ aField = new DoubleMultiPointField(fieldName);
+ } else {
+ aField = new DoubleField(fieldName);
+ }
+ } else if (fieldType instanceof TrieDateField) {
+ if (multivalued) {
+ aField = new DateMultiField(fieldName);
+ } else {
+ aField = new DateField(fieldName);
+ }
+ } else if (fieldType instanceof DatePointField) {
+ if (multivalued) {
+ aField = new DateMultiPointField(fieldName);
+ } else {
+ aField = new DateField(fieldName);
+ }
+ } else if (fieldType instanceof StrField) {
+ if (multivalued) {
+ aField = new StringMultiField(fieldName);
+ } else {
+ aField = new StringField(fieldName);
+ }
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"FieldType of the following field not supported by analytics: "+fieldName);
+ }
+ return aField;
+ }
+
+ /**
+ * Get the name of the top function used in the given expression.
+ *
+ * @param expression the expression to find the function name of
+ * @return the name of the function
+ * @throws SolrException if the expression has incorrect syntax
+ */
+ private static String getFunctionName(String expression) throws SolrException {
+ Matcher m = functionNamePattern.matcher(expression);
+ if (!m.matches()) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following function has no name: " + expression);
+ }
+ String name = m.group(1);
+ return name;
+ }
+
+ /**
+ * Get the params of a function.
+ *
+ * @param function the function to parse
+ * @return an array of param strings
+ * @throws SolrException if the function has incorrect syntax
+ */
+ private static String[] getFunctionParams(String function) throws SolrException {
+ return getParams(function, null, null);
+ }
+
+ /**
+ * Parse a function expression string and break up the parameters of the function into separate strings.
+ * <p>
+ * The parsing replaces the variable length parameter, and lambda for-each's using the variable length parameter,
+ * with the parameter values in the returned parameter string.
+ * <p>
+ * Parsing breaks up parameters by commas (',') and ignores ',' inside of extra parens and quotes (both ' and "), since these commas are either
+ * splitting up the parameters of nested functions or are apart of strings.
+ * <br>
+ * The only escaping that needs to be done is " within a double quote string and ' within a single quote string and \ within any string.
+ * For example\:
+ * <ul>
+ * <li> {@code func("This is \" the \\ escaping ' example")} will be treated as {@code func(This is " the \ escaping ' example)}
+ * <li> {@code func('This is " the \\ escaping \' example')} will be treated as {@code func(This is " the \ escaping ' example)}
+ * </ul>
+ * In string constants the \ character is used to escape quotes, so it can never be used alone. in order to write a \ you must write \\
+ *
+ * @param expression the function expression to parse
+ * @param varLengthParamName the name of the variable length parameter that is used in the expression, pass null if none is used.
+ * @param varLengthParamValues the values of the variable length parameter that are used in the expression, pass null if none are used.
+ * @return the parsed and split arguments to the function
+ * @throws SolrException if the expression has incorrect syntax.
+ */
+ private static String[] getParams(String expression, String varLengthParamName, String[] varLengthParamValues) throws SolrException {
+ Matcher m = functionParamsPattern.matcher(expression);
+ if (!m.matches()) {
+ return new String[0];
+ }
+ String paramsStr = m.group(1);
+
+ ArrayList<String> paramsList = new ArrayList<String>();
+ StringBuilder param = new StringBuilder();
+
+ // Variables to help while filling out the values of for-each lambda functions.
+ boolean inForEach = false;
+ int forEachStart = -1;
+ int forEachIter = -1;
+ int forEachLevel = -1;
+
+ // The current level of nested parenthesis, 0 means the iteration is in no nested parentheses
+ int parenCount = 0;
+ // If the iteration is currently in a single-quote string constant
+ boolean singleQuoteOn = false;
+ // If the iteration is currently in a double-quote string constant
+ boolean doubleQuoteOn = false;
+ // If the iteration is currently in any kind of string constant
+ boolean quoteOn = false;
+ // Is the next character escaped.
+ boolean escaped = false;
+
+ char[] chars = paramsStr.toCharArray();
+
+ // Iterate through every character, building the params one at a time
+ for (int i = 0; i < chars.length; ++i) {
+ char c = chars[i];
+
+ if (c == ' ' && !quoteOn) {
+ // Ignore white space that is not in string constants
+ continue;
+ } else if (c == ',' && parenCount == 0 && !quoteOn) {
+ // This signifies the end of one parameter and the start of another, since we are not in a nested parenthesis or a string constant
+ String paramStr = param.toString();
+ if (paramStr.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Empty parameter in expression: " + expression);
+ }
+ // check to see if the parameter is a variable length parameter
+ if (paramStr.equals(varLengthParamName)) {
+ // Add every variable length parameter value, since there are a variable amount
+ for (String paramName : varLengthParamValues) {
+ paramsList.add(paramName);
+ }
+ } else {
+ paramsList.add(paramStr);
+ }
+
+ param.setLength(0);
+ continue;
+ } else if (c == ',' && !quoteOn && inForEach) {
+ // separate the for each parameters, so they can be replaced with the result of the for each
+ if (param.charAt(param.length()-1) == variableForEachParam &&
+ (param.charAt(param.length()-2) == '(' || param.charAt(param.length()-2) == ',')) {
+ param.setLength(param.length()-1);
+ param.append(varLengthParamValues[forEachIter++]);
+ }
+ } else if (c == '"' && !singleQuoteOn) {
+ // Deal with escaping, or ending string constants
+ if (doubleQuoteOn && !escaped) {
+ doubleQuoteOn = false;
+ quoteOn = false;
+ } else if (!quoteOn) {
+ doubleQuoteOn = true;
+ quoteOn = true;
+ } else {
+ // only happens if escaped is true
+ escaped = false;
+ }
+ } else if (c== '\'' && !doubleQuoteOn) {
+ // Deal with escaping, or ending string constants
+ if (singleQuoteOn && !escaped) {
+ singleQuoteOn = false;
+ quoteOn = false;
+ } else if (!singleQuoteOn) {
+ singleQuoteOn = true;
+ quoteOn = true;
+ } else {
+ // only happens if escaped is true
+ escaped = false;
+ }
+ } else if (c == '(' && !quoteOn) {
+ // Reached a further level of nested parentheses
+ parenCount++;
+ } else if (c == ')' && !quoteOn) {
+ // Returned from a level of nested parentheses
+ parenCount--;
+ if (parenCount < 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following expression has extra end parens: " + param.toString());
+ }
+ if (inForEach) {
+ if (param.charAt(param.length()-1) == variableForEachParam &&
+ (param.charAt(param.length()-2) == '(' || param.charAt(param.length()-2) == ',')) {
+ param.setLength(param.length()-1);
+ param.append(varLengthParamValues[forEachIter++]);
+ }
+ if (forEachLevel == parenCount) {
+ // at the end of the for-each start the parsing of the for-each again, with the next value of the variable length parameter
+ if (forEachIter == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"For each statement for variable '" + varLengthParamName + "' has no use of lambda variable " + variableForEachParam);
+ } else if (forEachIter < varLengthParamValues.length) {
+ if (parenCount == 0) {
+ param.append(')');
+ paramsList.add(param.toString());
+ param.setLength(0);
+ } else {
+ param.append(')');
+ param.append(',');
+ }
+ i = forEachStart;
+ continue;
+ } else {
+ inForEach = false;
+ }
+ }
+ }
+ }
+ if (c == '\\') {
+ // Escaping or escaped backslash
+ if (!quoteOn) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following expression has escaped characters outside of quotation marks: " + expression.toString());
+ }
+ if (escaped) {
+ escaped = false;
+ } else {
+ escaped = true;
+ if (parenCount == 0) {
+ continue;
+ }
+ }
+ } else if (escaped) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Invalid escape character '" + c + "' used in the following expression: " + expression.toString());
+ }
+ if (c == variableForEachSep && !quoteOn && varLengthParamName != null) {
+ int varStart = param.length()-varLengthParamName.length();
+ if (param.subSequence(varStart, param.length()).equals(varLengthParamName)) {
+ inForEach = true;
+ forEachStart = i;
+ forEachIter = 0;
+ forEachLevel = parenCount;
+ param.setLength(varStart);
+ continue;
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"For-each called on invalid parameter '" + param.toString().trim());
+ }
+ param.append(c);
+ }
+ String paramStr = param.toString().trim();
+ if (paramStr.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Empty parameter in expression: " + expression);
+ }
+ if (parenCount > 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The following expression needs more end parens: " + param.toString());
+ }
+ if (quoteOn) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Misplaced quotation marks in expression: " + expression);
+ }
+ if (paramStr.equals(varLengthParamName)) {
+ for (String paramName : varLengthParamValues) {
+ paramsList.add(paramName);
+ }
+ } else {
+ paramsList.add(paramStr);
+ }
+ return paramsList.toArray(new String[paramsList.size()]);
+ }
+
+ /**
+ * Add the natively supported functionality.
+ */
+ public void addSystemFunctions() {
+ // Mapping Functions
+ expressionCreators.put(AbsoluteValueFunction.name, AbsoluteValueFunction.creatorFunction);
+ expressionCreators.put(AndFunction.name, AndFunction.creatorFunction);
+ expressionCreators.put(AddFunction.name, AddFunction.creatorFunction);
+ expressionCreators.put(BottomFunction.name, BottomFunction.creatorFunction);
+ expressionCreators.put(CeilingFunction.name, CeilingFunction.creatorFunction);
+ expressionCreators.put(ConcatFunction.name, ConcatFunction.creatorFunction);
+ expressionCreators.put(ConcatSeparatedFunction.name, ConcatSeparatedFunction.creatorFunction);
+ expressionCreators.put(DateMathFunction.name, DateMathFunction.creatorFunction);
+ expressionCreators.put(DateParseFunction.name, DateParseFunction.creatorFunction);
+ expressionCreators.put(DivideFunction.name, DivideFunction.creatorFunction);
+ expressionCreators.put(DocCountFunction.name, DocCountFunction.creatorFunction);
+ expressionCreators.put(EqualFunction.name,EqualFunction.creatorFunction);
+ expressionCreators.put(FillMissingFunction.name, FillMissingFunction.creatorFunction);
+ expressionCreators.put(FilterFunction.name, FilterFunction.creatorFunction);
+ expressionCreators.put(FloorFunction.name, FloorFunction.creatorFunction);
+ expressionCreators.put(GTFunction.name,GTFunction.creatorFunction);
+ expressionCreators.put(GTEFunction.name,GTEFunction.creatorFunction);
+ expressionCreators.put(IfFunction.name, IfFunction.creatorFunction);
+ expressionCreators.put(JoinFunction.name, JoinFunction.creatorFunction);
+ expressionCreators.put(LogFunction.name,LogFunction.creatorFunction);
+ expressionCreators.put(LTFunction.name,LTFunction.creatorFunction);
+ expressionCreators.put(LTEFunction.name,LTEFunction.creatorFunction);
+ expressionCreators.put(MultFunction.name, MultFunction.creatorFunction);
+ expressionCreators.put(NegateFunction.name, NegateFunction.creatorFunction);
+ expressionCreators.put(OrFunction.name, OrFunction.creatorFunction);
+ expressionCreators.put(PowerFunction.name, PowerFunction.creatorFunction);
+ expressionCreators.put(ReplaceFunction.name, ReplaceFunction.creatorFunction);
+ expressionCreators.put(RemoveFunction.name, RemoveFunction.creatorFunction);
+ expressionCreators.put(RoundFunction.name, RoundFunction.creatorFunction);
+ expressionCreators.put(StringCastFunction.name, StringCastFunction.creatorFunction);
+ expressionCreators.put(SubtractFunction.name, SubtractFunction.creatorFunction);
+ expressionCreators.put(TopFunction.name, TopFunction.creatorFunction);
+
+ // Reduction Functions
+ expressionCreators.put(CountFunction.name, CountFunction.creatorFunction);
+ expressionCreators.put(MaxFunction.name, MaxFunction.creatorFunction);
+ expressionCreators.put(MedianFunction.name, MedianFunction.creatorFunction);
+ expressionCreators.put(MinFunction.name, MinFunction.creatorFunction);
+ expressionCreators.put(MissingFunction.name, MissingFunction.creatorFunction);
+ expressionCreators.put(OrdinalFunction.name, OrdinalFunction.creatorFunction);
+ expressionCreators.put(PercentileFunction.name, PercentileFunction.creatorFunction);
+ expressionCreators.put(SumFunction.name, SumFunction.creatorFunction);
+ expressionCreators.put(UniqueFunction.name, UniqueFunction.creatorFunction);
+
+ // Variables
+ addSystemVariableFunction("wmean(a,b)","div(mean(prod(a,b)),sum(b))");
+ addSystemVariableFunction("mean(a)","div(sum(a),count(a))");
+ addSystemVariableFunction("sumofsquares(a)","sum(pow(a,2))");
+ addSystemVariableFunction("sqrt(a)","pow(a,0.5)");
+ addSystemVariableFunction("variance(a)","sub(mean(pow(a,2)),pow(mean(a),2))");
+ addSystemVariableFunction("stddev(a)","sqrt(variance(a))");
+ addSystemVariableFunction("csv(a..)","concatsep(',',a)");
+ addSystemVariableFunction("csv_output(a..)","concatsep(',',a:fillmissing(join(_,';'),''))");
+ }
+
+ /**
+ * Used for system analytics functions for initialization. Should take in a list of expression parameters and return an expression.
+ */
+ @FunctionalInterface
+ public static interface CreatorFunction {
+ AnalyticsValueStream apply(AnalyticsValueStream[] t) throws SolrException;
+ }
+ /**
+ * Used to initialize analytics constants.
+ */
+ @FunctionalInterface
+ public static interface ConstantFunction {
+ AnalyticsValueStream apply(String t) throws SolrException;
+ }
+}
+class VariableFunctionInfo {
+ public String[] params;
+ public String returnSignature;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java
deleted file mode 100644
index cbd8078..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.analytics.accumulator;
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Supplier;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.analytics.expression.Expression;
-import org.apache.solr.analytics.expression.ExpressionFactory;
-import org.apache.solr.analytics.request.AnalyticsRequest;
-import org.apache.solr.analytics.request.ExpressionRequest;
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.analytics.statistics.StatsCollectorSupplierFactory;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.search.DocSet;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A <code>BasicAccumulator</code> manages the ValueCounters and Expressions without regard to Facets.
- */
-public class BasicAccumulator extends ValueAccumulator {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- protected final SolrIndexSearcher searcher;
- protected final AnalyticsRequest request;
- protected final DocSet docs;
- protected final Supplier<StatsCollector[]> statsCollectorArraySupplier;
- protected final StatsCollector[] statsCollectors;
- protected final Expression[] expressions;
- protected final String[] expressionNames;
- protected final String[] expressionStrings;
- protected final Set<String> hiddenExpressions;
- protected LeafReaderContext context = null;
-
- public BasicAccumulator(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request) throws IOException {
- this.searcher = searcher;
- this.docs = docs;
- this.request = request;
- final List<ExpressionRequest> exRequests = new ArrayList<ExpressionRequest>(request.getExpressions()); // make a copy here
- Collections.sort(exRequests);
- log.info("Processing request '"+request.getName()+"'");
- statsCollectorArraySupplier = StatsCollectorSupplierFactory.create(searcher.getSchema(), exRequests);
- statsCollectors = statsCollectorArraySupplier.get();
- int size = exRequests.size();
- expressionNames = new String[size];
- expressionStrings = new String[size];
- int count = 0;
- for (ExpressionRequest expRequest : exRequests) {
- expressionNames[count] = expRequest.getName();
- expressionStrings[count++] = expRequest.getExpressionString();
- }
- expressions = makeExpressions(statsCollectors);
- hiddenExpressions = request.getHiddenExpressions();
- }
-
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- this.context = context;
- for (StatsCollector counter : statsCollectors) {
- counter.setNextReader(context);
- }
- }
-
- public static BasicAccumulator create(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request) throws IOException {
- return new BasicAccumulator(searcher,docs,request);
- }
-
- /**
- * Passes the documents on to the {@link StatsCollector}s to be collected.
- * @param doc Document to collect from
- */
- @Override
- public void collect(int doc) throws IOException {
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.collect(doc);
- }
- }
-
- @Override
- public void compute() {
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.compute();
- }
- }
-
- public NamedList<?> export(){
- NamedList<Object> base = new NamedList<>();
- for (int count = 0; count < expressions.length; count++) {
- if (!hiddenExpressions.contains(expressionNames[count])) {
- base.add(expressionNames[count], expressions[count].getValue());
- }
- }
- return base;
- }
-
- /**
- * Builds an array of Expressions with the given list of counters
- * @param statsCollectors the stats collectors
- * @return The array of Expressions
- */
- public Expression[] makeExpressions(StatsCollector[] statsCollectors) {
- Expression[] expressions = new Expression[expressionStrings.length];
- for (int count = 0; count < expressionStrings.length; count++) {
- expressions[count] = ExpressionFactory.create(expressionStrings[count], statsCollectors);
- }
- return expressions;
- }
-
- /**
- * Returns the value of an expression to use in a field or query facet.
- * @param expressionName the name of the expression
- * @return String String representation of pivot value
- */
- @SuppressWarnings({ "deprecation", "rawtypes" })
- public String getResult(String expressionName) {
- for (int count = 0; count < expressionNames.length; count++) {
- if (expressionName.equals(expressionNames[count])) {
- Comparable value = expressions[count].getValue();
- if (value.getClass().equals(Date.class)) {
- return ((Date)value).toInstant().toString();
- } else {
- return value.toString();
- }
- }
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, "Pivot expression "+expressionName+" not found.");
- }
-
- /**
- * Used for JMX stats collecting. Counts the number of stats requests
- * @return number of unique stats collectors
- */
- public long getNumStatsCollectors() {
- return statsCollectors.length;
- }
-
- /**
- * Used for JMX stats collecting. Counts the number of queries in all query facets
- * @return number of queries requested in all query facets.
- */
- public long getNumQueries() {
- return 0l;
- }
-
- @Override
- public boolean needsScores() {
- return true; // TODO: is this true?
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/FacetingAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/FacetingAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/FacetingAccumulator.java
deleted file mode 100644
index d8828a6..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/FacetingAccumulator.java
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * 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.analytics.accumulator;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
-import com.google.common.collect.Iterables;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.BooleanClause.Occur;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.Query;
-import org.apache.solr.analytics.accumulator.facet.FacetValueAccumulator;
-import org.apache.solr.analytics.accumulator.facet.FieldFacetAccumulator;
-import org.apache.solr.analytics.accumulator.facet.QueryFacetAccumulator;
-import org.apache.solr.analytics.accumulator.facet.RangeFacetAccumulator;
-import org.apache.solr.analytics.expression.Expression;
-import org.apache.solr.analytics.expression.ExpressionFactory;
-import org.apache.solr.analytics.request.AnalyticsContentHandler;
-import org.apache.solr.analytics.request.AnalyticsRequest;
-import org.apache.solr.analytics.request.FieldFacetRequest;
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortSpecification;
-import org.apache.solr.analytics.request.QueryFacetRequest;
-import org.apache.solr.analytics.request.RangeFacetRequest;
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.analytics.util.RangeEndpointCalculator;
-import org.apache.solr.analytics.util.RangeEndpointCalculator.FacetRange;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.search.DocSet;
-import org.apache.solr.search.Filter;
-import org.apache.solr.search.QParser;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.search.SyntaxError;
-
-/**
- * A <code>FacetingAccumulator</code> manages the StatsCollectors and Expressions for facets.
- */
-public class FacetingAccumulator extends BasicAccumulator implements FacetValueAccumulator {
- public static final String MISSING_VALUE = "(MISSING)";
- protected boolean basicsAndFieldFacetsComputed;
- protected int leafNum;
- protected LeafReaderContext leaf;
- protected final AnalyticsRequest analyticsRequest;
- protected final Map<String,Map<String,Expression[]>> fieldFacetExpressions;
- protected final Map<String,Map<String,Expression[]>> rangeFacetExpressions;
- protected final Map<String,Map<String,Expression[]>> queryFacetExpressions;
- protected final Map<String,Map<String,StatsCollector[]>> fieldFacetCollectors;
- protected final Map<String,Map<String,StatsCollector[]>> rangeFacetCollectors;
- protected final Map<String,Map<String,StatsCollector[]>> queryFacetCollectors;
- protected final List<FieldFacetAccumulator> facetAccumulators;
- protected final Set<String> hiddenFieldFacets;
- /** the current value of this stat field */
- protected final SolrQueryRequest queryRequest;
-
- protected List<RangeFacetRequest> rangeFacets = null;
- protected List<QueryFacetRequest> queryFacets = null;
-
- protected long queryCount;
-
- public FacetingAccumulator(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request, SolrQueryRequest queryRequest) throws IOException {
- // The parent Basic Accumulator keeps track of overall stats while
- // the Faceting Accumulator only manages the facet stats
- super(searcher, docs, request);
- this.analyticsRequest = request;
- this.queryRequest = queryRequest;
- basicsAndFieldFacetsComputed = false;
- List<FieldFacetRequest> fieldFreqs = request.getFieldFacets();
- List<RangeFacetRequest> rangeFreqs = request.getRangeFacets();
- List<QueryFacetRequest> queryFreqs = request.getQueryFacets();
-
- this.fieldFacetExpressions = new TreeMap<>();
- this.rangeFacetExpressions = new LinkedHashMap<>(rangeFreqs.size());
- this.queryFacetExpressions = new LinkedHashMap<>(queryFreqs.size());
- this.fieldFacetCollectors = new LinkedHashMap<>(fieldFreqs.size());
- this.rangeFacetCollectors = new LinkedHashMap<>(rangeFreqs.size());
- this.queryFacetCollectors = new LinkedHashMap<>(queryFreqs.size());
- this.facetAccumulators = new ArrayList<>();
- this.hiddenFieldFacets = new HashSet<>();
-
- /**
- * For each field facet request add a bucket to the {@link Expression} map and {@link StatsCollector} map.
- * Field facets are computed during the initial collection of documents, therefore
- * the FieldFacetAccumulators are created initially.
- */
- for( FieldFacetRequest freq : fieldFreqs ){
- final FieldFacetRequest fr = (FieldFacetRequest) freq;
- if (fr.isHidden()) {
- hiddenFieldFacets.add(fr.getName());
- }
- final SchemaField ff = fr.getField();
- final FieldFacetAccumulator facc = FieldFacetAccumulator.create(searcher, this, ff);
- facetAccumulators.add(facc);
- fieldFacetExpressions.put(freq.getName(), new TreeMap<String, Expression[]>() );
- fieldFacetCollectors.put(freq.getName(), new TreeMap<String,StatsCollector[]>());
- }
- /**
- * For each range and query facet request add a bucket to the corresponding
- * {@link Expression} map and {@link StatsCollector} map.
- * Range and Query Facets are computed in the post processing, so the accumulators
- * are not created initially.
- */
- for( RangeFacetRequest freq : rangeFreqs ){
- if( rangeFacets == null ) rangeFacets = new ArrayList<>();
- rangeFacets.add(freq);
- rangeFacetExpressions.put(freq.getName(), new LinkedHashMap<String,Expression[]>() );
- rangeFacetCollectors.put(freq.getName(), new LinkedHashMap<String,StatsCollector[]>());
- }
- for( QueryFacetRequest freq : queryFreqs ){
- if( queryFacets == null ) queryFacets = new ArrayList<>();
- queryFacets.add(freq);
- queryFacetExpressions.put(freq.getName(), new LinkedHashMap<String,Expression[]>() );
- queryFacetCollectors.put(freq.getName(), new LinkedHashMap<String,StatsCollector[]>());
- }
- this.queryCount = 0l;
- }
-
- public static FacetingAccumulator create(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request, SolrQueryRequest queryRequest) throws IOException {
- return new FacetingAccumulator(searcher,docs,request,queryRequest);
- }
-
- /**
- * Update the readers for the {@link BasicAccumulator}, field facets and field facet {@link StatsCollector}s.
- * @param context The context to read documents from.
- * @throws IOException if there is an error setting the next reader
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- super.doSetNextReader(context);
- for( Map<String,StatsCollector[]> valueList : fieldFacetCollectors.values() ){
- for (StatsCollector[] statsCollectorList : valueList.values()) {
- for (StatsCollector statsCollector : statsCollectorList) {
- statsCollector.setNextReader(context);
- }
- }
- }
- for (FieldFacetAccumulator fa : facetAccumulators) {
- fa.getLeafCollector(context);
- }
- }
-
- /**
- * Updates the reader for all of the range facet {@link StatsCollector}s.
- * @param context The context to read documents from.
- * @throws IOException if there is an error setting the next reader
- */
- public void setRangeStatsCollectorReaders(LeafReaderContext context) throws IOException {
- super.getLeafCollector(context);
- for( Map<String,StatsCollector[]> rangeList : rangeFacetCollectors.values() ){
- for (StatsCollector[] statsCollectorList : rangeList.values()) {
- for (StatsCollector statsCollector : statsCollectorList) {
- statsCollector.setNextReader(context);
- }
- }
- }
- }
-
-
- /**
- * Updates the reader for all of the query facet {@link StatsCollector}s.
- * @param context The context to read documents from.
- * @throws IOException if there is an error setting the next reader
- */
- public void setQueryStatsCollectorReaders(LeafReaderContext context) throws IOException {
- super.getLeafCollector(context);
- for( Map<String,StatsCollector[]> queryList : queryFacetCollectors.values() ){
- for (StatsCollector[] statsCollectorList : queryList.values()) {
- for (StatsCollector statsCollector : statsCollectorList) {
- statsCollector.setNextReader(context);
- }
- }
- }
- }
-
- /**
- * Called from Analytics stats, adds documents to the field
- * facets and the super {@link BasicAccumulator}.
- */
- @Override
- public void collect(int doc) throws IOException {
- for( FieldFacetAccumulator fa : facetAccumulators ){
- fa.collect(doc);
- }
- super.collect(doc);
- }
-
- /**
- * Given a document, fieldFacet field and facetValue, adds the document to the
- * {@link StatsCollector}s held in the bucket corresponding to the fieldFacet field and facetValue.
- * Called during initial document collection.
- */
- @Override
- public void collectField(int doc, String facetField, String facetValue) throws IOException {
- Map<String,StatsCollector[]> map = fieldFacetCollectors.get(facetField);
- StatsCollector[] statsCollectors = map.get(facetValue);
- // If the facetValue has not been seen yet, a StatsCollector array is
- // created and associated with that bucket.
- if( statsCollectors == null ){
- statsCollectors = statsCollectorArraySupplier.get();
- map.put(facetValue,statsCollectors);
- fieldFacetExpressions.get(facetField).put(facetValue,makeExpressions(statsCollectors));
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.setNextReader(context);
- }
- }
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.collect(doc);
- }
- }
-
- /**
- * Given a document, rangeFacet field and range, adds the document to the
- * {@link StatsCollector}s held in the bucket corresponding to the rangeFacet field and range.
- * Called during post processing.
- */
- @Override
- public void collectRange(int doc, String facetField, String range) throws IOException {
- Map<String,StatsCollector[]> map = rangeFacetCollectors.get(facetField);
- StatsCollector[] statsCollectors = map.get(range);
- // If the range has not been seen yet, a StatsCollector array is
- // created and associated with that bucket.
- if( statsCollectors == null ){
- statsCollectors = statsCollectorArraySupplier.get();
- map.put(range,statsCollectors);
- rangeFacetExpressions.get(facetField).put(range,makeExpressions(statsCollectors));
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.setNextReader(context);
- }
- }
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.collect(doc);
- }
- }
-
- /**
- * Given a document, queryFacet name and query, adds the document to the
- * {@link StatsCollector}s held in the bucket corresponding to the queryFacet name and query.
- * Called during post processing.
- */
- @Override
- public void collectQuery(int doc, String facetName, String query) throws IOException {
- Map<String,StatsCollector[]> map = queryFacetCollectors.get(facetName);
- StatsCollector[] statsCollectors = map.get(query);
- // If the query has not been seen yet, a StatsCollector array is
- // created and associated with that bucket.
- if( statsCollectors == null ){
- statsCollectors = statsCollectorArraySupplier.get();
- map.put(query,statsCollectors);
- queryFacetExpressions.get(facetName).put(query,makeExpressions(statsCollectors));
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.setNextReader(context);
- }
- }
- for (StatsCollector statsCollector : statsCollectors) {
- statsCollector.collect(doc);
- }
- }
-
- /**
- * A comparator to compare expression values for field facet sorting.
- */
- public static class EntryComparator implements Comparator<Entry<String,Expression[]>> {
- private final Comparator<Expression> comp;
- private final int comparatorExpressionPlace;
-
- public EntryComparator(Comparator<Expression> comp, int comparatorExpressionPlace) {
- this.comp = comp;
- this.comparatorExpressionPlace = comparatorExpressionPlace;
- }
-
- @Override
- public int compare(Entry<String,Expression[]> o1, Entry<String,Expression[]> o2) {
- return comp.compare(o1.getValue()[comparatorExpressionPlace], o2.getValue()[comparatorExpressionPlace]);
- }
- }
-
- /**
- * Finalizes the statistics within the each facet bucket before exporting;
- */
- @Override
- public void compute() {
- if (!basicsAndFieldFacetsComputed) {
- super.compute();
- for( Map<String, StatsCollector[]> f : fieldFacetCollectors.values() ){
- for( StatsCollector[] arr : f.values() ){
- for( StatsCollector b : arr ){
- b.compute();
- }
- }
- }
- basicsAndFieldFacetsComputed = true;
- }
- }
-
- /**
- * Finalizes the statistics within the a specific query facet before exporting;
- */
- public void computeQueryFacet(String facet) {
- Map<String, StatsCollector[]> f = queryFacetCollectors.get(facet);
- for( StatsCollector[] arr : f.values() ){
- for( StatsCollector b : arr ){
- b.compute();
- }
- }
- }
-
- /**
- * Finalizes the statistics within the a specific range facet before exporting;
- */
- public void computeRangeFacet(String facet) {
- Map<String, StatsCollector[]> f = rangeFacetCollectors.get(facet);
- for( StatsCollector[] arr : f.values() ){
- for( StatsCollector b : arr ){
- b.compute();
- }
- }
- }
-
- /**
- * Returns the value of an expression to use in a range or query facet.
- * @param expressionName the name of the expression
- * @param fieldFacet the facet field
- * @param facetValue the facet value
- * @return String String representation of pivot value
- */
- @SuppressWarnings({ "deprecation", "rawtypes" })
- public String getResult(String expressionName, String fieldFacet, String facetValue) {
- if (facetValue.contains(AnalyticsParams.RESULT) && !facetValue.contains(AnalyticsParams.QUERY_RESULT)) {
- try {
- String[] pivotStr = ExpressionFactory.getArguments(facetValue.substring(facetValue.indexOf('(')+1,facetValue.lastIndexOf(')')).trim());
- if (pivotStr.length==1) {
- facetValue = getResult(pivotStr[0]);
- } else if (pivotStr.length==3) {
- facetValue = getResult(pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+facetValue+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+facetValue+" is invalid. Lacks parentheses.",e);
- }
- }
- if (fieldFacetExpressions.get(fieldFacet)!=null) {
- Expression[] facetExpressions = fieldFacetExpressions.get(fieldFacet).get(facetValue);
- for (int count = 0; count < expressionNames.length; count++) {
- if (expressionName.equals(expressionNames[count])) {
- Comparable value = facetExpressions[count].getValue();
- if (value.getClass().equals(Date.class)) {
- return ((Date)value).toInstant().toString();
- } else {
- return value.toString();
- }
- }
- }
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"Field Facet Pivot expression "+expressionName+" not found.");
- }
-
- /**
- * Returns the value of an expression to use in a range or query facet.
- * @param currentFacet the name of the current facet
- * @param expressionName the name of the expression
- * @param queryFacet the facet query
- * @param facetValue the field value
- * @return String String representation of pivot value
- */
- @SuppressWarnings({ "deprecation", "rawtypes" })
- public String getQueryResult(String currentFacet, String expressionName, String queryFacet, String facetValue) {
- if (facetValue.contains(AnalyticsParams.RESULT) && !facetValue.contains(AnalyticsParams.QUERY_RESULT)) {
- try {
- String[] pivotStr = ExpressionFactory.getArguments(facetValue.substring(facetValue.indexOf('(')+1,facetValue.lastIndexOf(')')).trim());
- if (pivotStr.length==1) {
- facetValue = getResult(pivotStr[0]);
- } else if (pivotStr.length==3) {
- facetValue = getResult(pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+facetValue+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+facetValue+" is invalid. Lacks parentheses.",e);
- }
- }
- if (facetValue.contains(AnalyticsParams.QUERY_RESULT)) {
- try {
- String[] pivotStr = ExpressionFactory.getArguments(facetValue.substring(facetValue.indexOf('(')+1,facetValue.lastIndexOf(')')).trim());
- if (pivotStr.length==1) {
- facetValue = getResult(pivotStr[0]);
- } else if (pivotStr.length==3) {
- facetValue = getQueryResult(currentFacet,pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+facetValue+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+facetValue+" is invalid. Lacks parentheses.",e);
- }
- }
- if (queryFacetExpressions.get(queryFacet)!=null) {
- Expression[] facetExpressions = queryFacetExpressions.get(queryFacet).get(facetValue);
- for (int count = 0; count < expressionNames.length; count++) {
- if (expressionName.equals(expressionNames[count])) {
- Comparable value = facetExpressions[count].getValue();
- if (value.getClass().equals(Date.class)) {
- return ((Date)value).toInstant().toString();
- } else {
- return value.toString();
- }
- }
- }
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"Field Facet Pivot expression "+expressionName+" not found.");
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public NamedList<?> export() {
- final NamedList<Object> base = (NamedList<Object>)super.export();
- NamedList<NamedList<?>> facetList = new NamedList<>();
-
- // Add the field facet buckets to the output
- base.add("fieldFacets",facetList);
- for( FieldFacetRequest freq : request.getFieldFacets() ){
- final String name = freq.getName();
- if (hiddenFieldFacets.contains(name)) {
- continue;
- }
- final Map<String,Expression[]> buckets = fieldFacetExpressions.get(name);
- final NamedList<Object> bucketBase = new NamedList<>();
-
- Iterable<Entry<String,Expression[]>> iter = buckets.entrySet();
-
- final FieldFacetRequest fr = (FieldFacetRequest) freq;
-
- final FacetSortSpecification sort = fr.getSort();
- final int limit = fr.getLimit();
- final int offset = fr.getOffset();
- final boolean showMissing = fr.showsMissing();
- if (!showMissing) {
- buckets.remove(MISSING_VALUE);
- }
- // Sorting the buckets if a sort specification is provided
- if( sort != null && buckets.values().iterator().hasNext()){
- int sortPlace = Arrays.binarySearch(expressionNames, sort.getStatistic());
- final Expression first = buckets.values().iterator().next()[sortPlace];
- final Comparator<Expression> comp = (Comparator<Expression>) first.comparator(sort.getDirection());
-
- final List<Entry<String,Expression[]>> sorted = new ArrayList<>(buckets.size());
- Iterables.addAll(sorted, iter);
- Collections.sort(sorted, new EntryComparator(comp,sortPlace));
- iter = sorted;
- }
- // apply the limit
- if( limit > AnalyticsContentHandler.DEFAULT_FACET_LIMIT ){
- if( offset > 0 ){
- iter = Iterables.skip(iter, offset);
- }
- iter = Iterables.limit(iter, limit);
- }
-
- // Export each expression in the bucket.
- for( Entry<String,Expression[]> bucket : iter ){
- bucketBase.add(bucket.getKey(),export(bucket.getValue()));
- }
-
- facetList.add(name, bucketBase);
- }
-
- // Add the range facet buckets to the output
- facetList = new NamedList<>();
- base.add("rangeFacets",facetList);
- for( RangeFacetRequest freq : request.getRangeFacets() ){
- final String name = freq.getName();
- final Map<String,Expression[]> buckets = rangeFacetExpressions.get(name);
- final NamedList<Object> bucketBase = new NamedList<>();
-
- Iterable<Entry<String,Expression[]>> iter = buckets.entrySet();
-
- for( Entry<String,Expression[]> bucket : iter ){
- bucketBase.add(bucket.getKey(),export(bucket.getValue()));
- }
-
- facetList.add(name, bucketBase);
- }
-
- // Add the query facet buckets to the output
- facetList = new NamedList<>();
- base.add("queryFacets",facetList);
- for( QueryFacetRequest freq : request.getQueryFacets() ){
- final String name = freq.getName();
- final Map<String,Expression[]> buckets = queryFacetExpressions.get(name);
- final NamedList<Object> bucketBase = new NamedList<>();
-
- Iterable<Entry<String,Expression[]>> iter = buckets.entrySet();
-
- for( Entry<String,Expression[]> bucket : iter ){
- bucketBase.add(bucket.getKey(),export(bucket.getValue()));
- }
-
- facetList.add(name, bucketBase);
- }
-
- return base;
- }
-
- /**
- * Exports a list of expressions as a NamedList
- * @param expressionArr an array of expressions
- * @return named list of expressions
- */
- public NamedList<?> export(Expression[] expressionArr) {
- NamedList<Object> base = new NamedList<>();
- for (int count = 0; count < expressionArr.length; count++) {
- if (!hiddenExpressions.contains(expressionNames[count])) {
- base.add(expressionNames[count], expressionArr[count].getValue());
- }
- }
- return base;
- }
-
- /**
- * Processes the query and range facets.
- * Must be called if range and/or query facets are supported.
- */
- @Override
- public void postProcess() throws IOException {
- super.compute();
- for( Map<String, StatsCollector[]> f : fieldFacetCollectors.values() ){
- for( StatsCollector[] arr : f.values() ){
- for( StatsCollector b : arr ){
- b.compute();
- }
- }
- }
- basicsAndFieldFacetsComputed = true;
- final Filter filter = docs.getTopFilter();
- if( rangeFacets != null ){
- processRangeFacets(filter);
- }
- if( queryFacets != null ){
- processQueryFacets(filter);
- }
- }
-
- /**
- * Initiates the collecting of query facets
- * @param filter the base filter to work against
- * @throws IOException if searching failed
- */
- public void processQueryFacets(final Filter filter) throws IOException {
- for( QueryFacetRequest qfr : queryFacets ){
- for( String query : qfr.getQueries() ){
- if (query.contains(AnalyticsParams.RESULT) && !query.contains(AnalyticsParams.QUERY_RESULT)) {
- try {
- String[] pivotStr = ExpressionFactory.getArguments(query.substring(query.indexOf('(')+1,query.lastIndexOf(')')).trim());
- if (pivotStr.length==1) {
- query = getResult(pivotStr[0]);
- } else if (pivotStr.length==3) {
- query = getResult(pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+query+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+query+" is invalid. Lacks parentheses.",e);
- }
- } else if (query.contains(AnalyticsParams.QUERY_RESULT)) {
- try {
- String[] pivotStr = ExpressionFactory.getArguments(query.substring(query.indexOf('(')+1,query.lastIndexOf(')')).trim());
- if (pivotStr.length==3) {
- query = getQueryResult(qfr.getName(),pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+query+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Result request "+query+" is invalid. Lacks parentheses.",e);
- }
- }
- QueryFacetAccumulator qAcc = new QueryFacetAccumulator(this,qfr.getName(),query);
- final Query q;
- try {
- q = QParser.getParser(query, queryRequest).getQuery();
- } catch( SyntaxError e ){
- throw new SolrException(ErrorCode.BAD_REQUEST,"Invalid query '"+query+"'",e);
- }
- // The searcher sends docIds to the QueryFacetAccumulator which forwards
- // them to <code>collectQuery()</code> in this class for collection.
- Query filtered = new BooleanQuery.Builder()
- .add(q, Occur.MUST)
- .add(filter, Occur.FILTER)
- .build();
- searcher.search(filtered, qAcc);
- computeQueryFacet(qfr.getName());
- queryCount++;
- }
- }
- }
-
- @Override
- public long getNumQueries() {
- return queryCount;
- }
-
- /**
- * Initiates the collecting of range facets
- * @param filter the base filter to use
- * @throws IOException if searching fails
- */
- public void processRangeFacets(final Filter filter) throws IOException {
- for( RangeFacetRequest rfr : rangeFacets ){
- String[] pivotStr;
- String start = rfr.getStart();
- if (start.contains(AnalyticsParams.QUERY_RESULT)) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Query result requests can not be used in Range Facets");
- } else if (start.contains(AnalyticsParams.RESULT)) {
- try {
- pivotStr = ExpressionFactory.getArguments(start.substring(start.indexOf('(')+1,start.indexOf(')')).trim());
- if (pivotStr.length==1) {
- rfr.setStart(getResult(pivotStr[0]));
- } else if (pivotStr.length==3) {
- rfr.setStart(getResult(pivotStr[0],pivotStr[1],pivotStr[2]));
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+start+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+start+" is invalid. Lacks parentheses.",e);
- }
- }
- String end = rfr.getEnd();
- if (end.contains(AnalyticsParams.QUERY_RESULT)) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Query result requests can not be used in Range Facets");
- } else if (end.contains(AnalyticsParams.RESULT)) {
- try {
- pivotStr = ExpressionFactory.getArguments(end.substring(end.indexOf('(')+1,end.indexOf(')')).trim());
- if (pivotStr.length==1) {
- rfr.setEnd(getResult(pivotStr[0]));
- } else if (pivotStr.length==3) {
- rfr.setEnd(getResult(pivotStr[0],pivotStr[1],pivotStr[2]));
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+end+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+end+" is invalid. Lacks parentheses.",e);
- }
- }
- String[] gaps = rfr.getGaps();
- for (int count = 0; count<gaps.length; count++){
- String gap = gaps[count];
- if (gap.contains(AnalyticsParams.QUERY_RESULT)) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Query result requests can not be used in Range Facets");
- } else if (gap.contains(AnalyticsParams.RESULT)) {
- try {
- pivotStr = ExpressionFactory.getArguments(gap.substring(gap.indexOf('(')+1,gap.indexOf(')')).trim());
- if (pivotStr.length==1) {
- gaps[count]=getResult(pivotStr[0]);
- } else if (pivotStr.length==3) {
- gaps[count]=getResult(pivotStr[0],pivotStr[1],pivotStr[2]);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+gap+" has an invalid amount of arguments.");
- }
- } catch (IndexOutOfBoundsException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "Result request "+gap+" is invalid. Lacks parentheses.",e);
- }
- }
- }
- // Computes the end points of the ranges in the rangeFacet
- final RangeEndpointCalculator<? extends Comparable<?>> rec = RangeEndpointCalculator.create(rfr);
- final SchemaField sf = rfr.getField();
-
- // Create a rangeFacetAccumulator for each range and
- // collect the documents for that range.
- for( FacetRange range : rec.getRanges() ){
- final String upper;
- final String lower;
- String facetValue = "";
- if( range.lower == null ){
- facetValue = "(*";
- lower = null;
- } else {
- lower = range.lower;
- facetValue = ((range.includeLower)?"[":"(") + range.lower;
- }
- facetValue+=" TO ";
- if( range.upper == null ){
- upper = null;
- facetValue += "*)";
- } else {
- upper = range.upper;
- facetValue += range.upper + ((range.includeUpper)?"]":")");
- }
-
- Query q = sf.getType().getRangeQuery(null, sf, lower, upper, range.includeLower,range.includeUpper);
- RangeFacetAccumulator rAcc = new RangeFacetAccumulator(this,rfr.getName(),facetValue);
- // The searcher sends docIds to the RangeFacetAccumulator which forwards
- // them to <code>collectRange()</code> in this class for collection.
- Query filtered = new BooleanQuery.Builder()
- .add(q, Occur.MUST)
- .add(filter, Occur.FILTER)
- .build();
- searcher.search(filtered, rAcc);
- computeRangeFacet(sf.getName());
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/ValueAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/ValueAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/ValueAccumulator.java
deleted file mode 100644
index 489d3de..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/ValueAccumulator.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.analytics.accumulator;
-
-import java.io.IOException;
-
-import org.apache.lucene.search.SimpleCollector;
-import org.apache.solr.common.util.NamedList;
-
-/**
- * Abstract Collector that manages all StatsCollectors, Expressions and Facets.
- */
-public abstract class ValueAccumulator extends SimpleCollector {
-
- /**
- * Finalizes the statistics within each StatsCollector.
- * Must be called before <code>export()</code>.
- */
- public abstract void compute();
- public abstract NamedList<?> export();
-
- public void postProcess() throws IOException {
- // NOP
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FacetValueAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FacetValueAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FacetValueAccumulator.java
deleted file mode 100644
index 1b6fbb7..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FacetValueAccumulator.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-
-/**
- * Interface that describes the methods needed for an Accumulator to be able to handle
- * fieldFacets, rangeFacets and queryFacets.
- */
-public interface FacetValueAccumulator {
-
- void collectField(int doc, String facetName, String facetValue) throws IOException;
- void collectQuery(int doc, String facetName, String facetValue) throws IOException;
- void collectRange(int doc, String facetName, String facetValue) throws IOException;
- void setQueryStatsCollectorReaders(LeafReaderContext context) throws IOException;
- void setRangeStatsCollectorReaders(LeafReaderContext context) throws IOException;
-
-}
[15/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FillMissingFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FillMissingFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FillMissingFunction.java
new file mode 100644
index 0000000..188d698
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FillMissingFunction.java
@@ -0,0 +1,842 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.AnalyticsValue.AbstractAnalyticsValue;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function to fill all non-existing values with a given value.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If two Values are passed in, a Value mimicking the first parameter with the second parameter used as filler will be returned.
+ * <li>If two ValueStreams are passed in, a ValueStream mimicking the first parameter with the second parameter used as filler will be returned.
+ * </ul>
+ * <p>
+ * The resulting Value or ValueStream will be typed with the closest super-type of the two parameters.
+ * (e.g. {@value #name}(double,int) will return a double)
+ */
+public class FillMissingFunction {
+ public static final String name = "fillmissing";
+
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+
+ AnalyticsValueStream baseExpr = params[0];
+ AnalyticsValueStream fillExpr = params[1];
+ if (baseExpr instanceof DateValue && fillExpr instanceof DateValue) {
+ return new DateFillMissingFunction((DateValue)baseExpr,(DateValue)fillExpr);
+ }
+ if (baseExpr instanceof DateValueStream && fillExpr instanceof DateValueStream) {
+ return new DateStreamFillMissingFunction((DateValueStream)baseExpr,(DateValueStream)fillExpr);
+ }
+ if (baseExpr instanceof BooleanValue && fillExpr instanceof BooleanValue) {
+ return new BooleanFillMissingFunction((BooleanValue)baseExpr,(BooleanValue)fillExpr);
+ }
+ if (baseExpr instanceof BooleanValueStream && fillExpr instanceof BooleanValueStream) {
+ return new BooleanStreamFillMissingFunction((BooleanValueStream)baseExpr,(BooleanValueStream)fillExpr);
+ }
+ if (baseExpr instanceof IntValue && fillExpr instanceof IntValue) {
+ return new IntFillMissingFunction((IntValue)baseExpr,(IntValue)fillExpr);
+ }
+ if (baseExpr instanceof IntValueStream && fillExpr instanceof IntValueStream) {
+ return new IntStreamFillMissingFunction((IntValueStream)baseExpr,(IntValueStream)fillExpr);
+ }
+ if (baseExpr instanceof LongValue && fillExpr instanceof LongValue) {
+ return new LongFillMissingFunction((LongValue)baseExpr,(LongValue)fillExpr);
+ }
+ if (baseExpr instanceof LongValueStream && fillExpr instanceof LongValueStream) {
+ return new LongStreamFillMissingFunction((LongValueStream)baseExpr,(LongValueStream)fillExpr);
+ }
+ if (baseExpr instanceof FloatValue && fillExpr instanceof FloatValue) {
+ return new FloatFillMissingFunction((FloatValue)baseExpr,(FloatValue)fillExpr);
+ }
+ if (baseExpr instanceof FloatValueStream && fillExpr instanceof FloatValueStream) {
+ return new FloatStreamFillMissingFunction((FloatValueStream)baseExpr,(FloatValueStream)fillExpr);
+ }
+ if (baseExpr instanceof DoubleValue && fillExpr instanceof DoubleValue) {
+ return new DoubleFillMissingFunction((DoubleValue)baseExpr,(DoubleValue)fillExpr);
+ }
+ if (baseExpr instanceof DoubleValueStream && fillExpr instanceof DoubleValueStream) {
+ return new DoubleStreamFillMissingFunction((DoubleValueStream)baseExpr,(DoubleValueStream)fillExpr);
+ }
+ if (baseExpr instanceof StringValue && fillExpr instanceof StringValue) {
+ return new StringFillMissingFunction((StringValue)baseExpr,(StringValue)fillExpr);
+ }
+ if (baseExpr instanceof StringValueStream && fillExpr instanceof StringValueStream) {
+ return new StringStreamFillMissingFunction((StringValueStream)baseExpr,(StringValueStream)fillExpr);
+ }
+ if (baseExpr instanceof AnalyticsValue && fillExpr instanceof AnalyticsValue) {
+ return new ValueFillMissingFunction((AnalyticsValue)baseExpr,(AnalyticsValue)fillExpr);
+ }
+ return new StreamFillMissingFunction(baseExpr,fillExpr);
+ });
+}
+class StreamFillMissingFunction implements AnalyticsValueStream, Consumer<Object> {
+ private final AnalyticsValueStream baseExpr;
+ private final AnalyticsValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StreamFillMissingFunction(AnalyticsValueStream baseExpr, AnalyticsValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ Consumer<Object> cons;
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamObjects(this);
+ if (!exists) {
+ fillExpr.streamObjects(cons);
+ }
+ }
+ @Override
+ public void accept(Object value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class ValueFillMissingFunction extends AbstractAnalyticsValue {
+ private final AnalyticsValue baseExpr;
+ private final AnalyticsValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public ValueFillMissingFunction(AnalyticsValue baseExpr, AnalyticsValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public Object getObject() {
+ Object value = baseExpr.getObject();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getObject();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamFillMissingFunction extends AbstractBooleanValueStream implements BooleanConsumer {
+ private final BooleanValueStream baseExpr;
+ private final BooleanValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamFillMissingFunction(BooleanValueStream baseExpr, BooleanValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ BooleanConsumer cons;
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamBooleans(this);
+ if (!exists) {
+ fillExpr.streamBooleans(cons);
+ }
+ }
+ @Override
+ public void accept(boolean value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanFillMissingFunction extends AbstractBooleanValue {
+ private final BooleanValue baseExpr;
+ private final BooleanValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanFillMissingFunction(BooleanValue baseExpr, BooleanValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = baseExpr.getBoolean();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getBoolean();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamFillMissingFunction extends AbstractIntValueStream implements IntConsumer {
+ private final IntValueStream baseExpr;
+ private final IntValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamFillMissingFunction(IntValueStream baseExpr, IntValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ IntConsumer cons;
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamInts(this);
+ if (!exists) {
+ fillExpr.streamInts(cons);
+ }
+ }
+ @Override
+ public void accept(int value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntFillMissingFunction extends AbstractIntValue {
+ private final IntValue baseExpr;
+ private final IntValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntFillMissingFunction(IntValue baseExpr, IntValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = baseExpr.getInt();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getInt();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamFillMissingFunction extends AbstractLongValueStream implements LongConsumer {
+ private final LongValueStream baseExpr;
+ private final LongValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamFillMissingFunction(LongValueStream baseExpr, LongValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ LongConsumer cons;
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamLongs(this);
+ if (!exists) {
+ fillExpr.streamLongs(cons);
+ }
+ }
+ @Override
+ public void accept(long value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongFillMissingFunction extends AbstractLongValue {
+ private final LongValue baseExpr;
+ private final LongValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongFillMissingFunction(LongValue baseExpr, LongValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getLong();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamFillMissingFunction extends AbstractFloatValueStream implements FloatConsumer {
+ private final FloatValueStream baseExpr;
+ private final FloatValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamFillMissingFunction(FloatValueStream baseExpr, FloatValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ FloatConsumer cons;
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamFloats(this);
+ if (!exists) {
+ fillExpr.streamFloats(cons);
+ }
+ }
+ @Override
+ public void accept(float value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatFillMissingFunction extends AbstractFloatValue {
+ private final FloatValue baseExpr;
+ private final FloatValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatFillMissingFunction(FloatValue baseExpr, FloatValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = baseExpr.getFloat();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getFloat();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleStreamFillMissingFunction extends AbstractDoubleValueStream implements DoubleConsumer {
+ private final DoubleValueStream baseExpr;
+ private final DoubleValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleStreamFillMissingFunction(DoubleValueStream baseExpr, DoubleValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ DoubleConsumer cons;
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamDoubles(this);
+ if (!exists) {
+ fillExpr.streamDoubles(cons);
+ }
+ }
+ @Override
+ public void accept(double value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleFillMissingFunction extends AbstractDoubleValue {
+ private final DoubleValue baseExpr;
+ private final DoubleValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleFillMissingFunction(DoubleValue baseExpr, DoubleValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public double getDouble() {
+ double value = baseExpr.getDouble();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getDouble();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateStreamFillMissingFunction extends AbstractDateValueStream implements LongConsumer {
+ private final DateValueStream baseExpr;
+ private final DateValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateStreamFillMissingFunction(DateValueStream baseExpr, DateValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ LongConsumer cons;
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamLongs(this);
+ if (!exists) {
+ fillExpr.streamLongs(cons);
+ }
+ }
+ @Override
+ public void accept(long value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateFillMissingFunction extends AbstractDateValue {
+ private final DateValue baseExpr;
+ private final DateValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateFillMissingFunction(DateValue baseExpr, DateValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getLong();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamFillMissingFunction extends AbstractStringValueStream implements Consumer<String> {
+ private final StringValueStream baseExpr;
+ private final StringValueStream fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringStreamFillMissingFunction(StringValueStream baseExpr, StringValueStream fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+ Consumer<String> cons;
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ exists = false;
+ this.cons = cons;
+ baseExpr.streamStrings(this);
+ if (!exists) {
+ fillExpr.streamStrings(cons);
+ }
+ }
+ @Override
+ public void accept(String value) {
+ exists = true;
+ cons.accept(value);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringFillMissingFunction extends AbstractStringValue {
+ private final StringValue baseExpr;
+ private final StringValue fillExpr;
+ public static final String name = FillMissingFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringFillMissingFunction(StringValue baseExpr, StringValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public String getString() {
+ String value = baseExpr.getString();
+ exists = true;
+ if (!baseExpr.exists()) {
+ value = fillExpr.getString();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FilterFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FilterFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FilterFunction.java
new file mode 100644
index 0000000..84a3e30
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/FilterFunction.java
@@ -0,0 +1,722 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.AnalyticsValue.AbstractAnalyticsValue;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function to filter a Value or ValueStream. For each document, the value exists if the second parameter
+ * is true and it doesn't exist otherwise.
+ * <p>
+ * The first parameter can be any type of analytics expression. (Required)
+ * <br>
+ * The second parameter must be a {@link BooleanValue}. (Required)
+ */
+public class FilterFunction {
+ public static final String name = "filter";
+
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ if (!(params[1] instanceof BooleanValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the second paramater to be single-valued and boolean.");
+ }
+
+ AnalyticsValueStream baseExpr = params[0];
+ BooleanValue filterExpr = (BooleanValue)params[1];
+
+ if (baseExpr instanceof DateValue) {
+ return new DateFilterFunction((DateValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof DateValueStream) {
+ return new DateStreamFilterFunction((DateValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof BooleanValue) {
+ return new BooleanFilterFunction((BooleanValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof BooleanValueStream) {
+ return new BooleanStreamFilterFunction((BooleanValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof IntValue) {
+ return new IntFilterFunction((IntValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof IntValueStream) {
+ return new IntStreamFilterFunction((IntValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof LongValue) {
+ return new LongFilterFunction((LongValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof LongValueStream) {
+ return new LongStreamFilterFunction((LongValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof FloatValue) {
+ return new FloatFilterFunction((FloatValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof FloatValueStream) {
+ return new FloatStreamFilterFunction((FloatValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof DoubleValue) {
+ return new DoubleFilterFunction((DoubleValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof DoubleValueStream) {
+ return new DoubleStreamFilterFunction((DoubleValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof StringValue) {
+ return new StringFilterFunction((StringValue)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof StringValueStream) {
+ return new StringStreamFilterFunction((StringValueStream)baseExpr,filterExpr);
+ }
+ if (baseExpr instanceof AnalyticsValue) {
+ return new ValueFilterFunction((AnalyticsValue)baseExpr,filterExpr);
+ }
+ return new StreamFilterFunction(baseExpr,filterExpr);
+ });
+}
+class StreamFilterFunction implements AnalyticsValueStream {
+ private final AnalyticsValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StreamFilterFunction(AnalyticsValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamObjects(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class ValueFilterFunction extends AbstractAnalyticsValue {
+ private final AnalyticsValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public ValueFilterFunction(AnalyticsValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public Object getObject() {
+ Object value = baseExpr.getObject();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamFilterFunction extends AbstractBooleanValueStream {
+ private final BooleanValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamFilterFunction(BooleanValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamBooleans(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanFilterFunction extends AbstractBooleanValue {
+ private final BooleanValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanFilterFunction(BooleanValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = baseExpr.getBoolean();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamFilterFunction extends AbstractIntValueStream {
+ private final IntValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamFilterFunction(IntValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamInts(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntFilterFunction extends AbstractIntValue {
+ private final IntValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntFilterFunction(IntValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = baseExpr.getInt();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamFilterFunction extends AbstractLongValueStream {
+ private final LongValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamFilterFunction(LongValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongFilterFunction extends AbstractLongValue {
+ private final LongValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongFilterFunction(LongValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamFilterFunction extends AbstractFloatValueStream {
+ private final FloatValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamFilterFunction(FloatValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamFloats(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatFilterFunction extends AbstractFloatValue {
+ private final FloatValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatFilterFunction(FloatValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = baseExpr.getFloat();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleStreamFilterFunction extends AbstractDoubleValueStream {
+ private final DoubleValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleStreamFilterFunction(DoubleValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamDoubles(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleFilterFunction extends AbstractDoubleValue {
+ private final DoubleValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleFilterFunction(DoubleValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public double getDouble() {
+ double value = baseExpr.getDouble();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateStreamFilterFunction extends AbstractDateValueStream {
+ private final DateValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateStreamFilterFunction(DateValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateFilterFunction extends AbstractDateValue {
+ private final DateValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateFilterFunction(DateValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamFilterFunction extends AbstractStringValueStream {
+ private final StringValueStream baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringStreamFilterFunction(StringValueStream baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (filterExpr.getBoolean() && filterExpr.exists()) {
+ baseExpr.streamStrings(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringFilterFunction extends AbstractStringValue {
+ private final StringValue baseExpr;
+ private final BooleanValue filterExpr;
+ public static final String name = FilterFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringFilterFunction(StringValue baseExpr, BooleanValue filterExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.filterExpr = filterExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,filterExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,filterExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public String getString() {
+ String value = baseExpr.getString();
+ exists = baseExpr.exists() && filterExpr.getBoolean() && filterExpr.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/IfFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/IfFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/IfFunction.java
new file mode 100644
index 0000000..e2fd163
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/IfFunction.java
@@ -0,0 +1,892 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.AnalyticsValue.AbstractAnalyticsValue;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * An if-else mapping function.
+ * <p>
+ * Three arguments are required. The first, the conditional parameter, must be a {@link BooleanValue} and
+ * the later two, the if and else parameters, can be any type of {@link AnalyticsValueStream}.
+ * For each document, if the conditional value is true then the if-value is used otherwise the else-value is used.
+ * <p>
+ * The resulting Value or ValueStream will be typed with the closest super-type of the two non-conditional parameters.
+ * (e.g. {@value #name}(boolean,double,int) will return a double)
+ * If two {@link AnalyticsValue}s are passed as the if-else parameters, an {@link AnalyticsValue} will be returned.
+ * If either parameter isn't single-valued, a {@link AnalyticsValueStream} will be returned.
+ */
+public class IfFunction implements AnalyticsValueStream {
+ private final BooleanValue ifExpr;
+ private final AnalyticsValueStream thenExpr;
+ private final AnalyticsValueStream elseExpr;
+ public static final String name = "if";
+ private final String exprStr;
+ private final ExpressionType funcType;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 3) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 3 paramaters, " + params.length + " found.");
+ }
+ if (!(params[0] instanceof BooleanValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires single-valued numeric parameters. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ }
+
+ BooleanValue castedIf = (BooleanValue) params[0];
+ AnalyticsValueStream thenExpr = params[1];
+ AnalyticsValueStream elseExpr = params[2];
+
+ if (thenExpr instanceof DateValue && elseExpr instanceof DateValue) {
+ return new DateIfFunction(castedIf,(DateValue)thenExpr,(DateValue)elseExpr);
+ }
+ if (thenExpr instanceof DateValueStream && elseExpr instanceof DateValueStream) {
+ return new DateStreamIfFunction(castedIf,(DateValueStream)thenExpr,(DateValueStream)elseExpr);
+ }
+ if (thenExpr instanceof BooleanValue && elseExpr instanceof BooleanValue) {
+ return new BooleanIfFunction(castedIf,(BooleanValue)thenExpr,(BooleanValue)elseExpr);
+ }
+ if (thenExpr instanceof BooleanValueStream && elseExpr instanceof BooleanValueStream) {
+ return new BooleanStreamIfFunction(castedIf,(BooleanValueStream)thenExpr,(BooleanValueStream)elseExpr);
+ }
+ if (thenExpr instanceof IntValue && elseExpr instanceof IntValue) {
+ return new IntIfFunction(castedIf,(IntValue)thenExpr,(IntValue)elseExpr);
+ }
+ if (thenExpr instanceof IntValueStream && elseExpr instanceof IntValueStream) {
+ return new IntStreamIfFunction(castedIf,(IntValueStream)thenExpr,(IntValueStream)elseExpr);
+ }
+ if (thenExpr instanceof LongValue && elseExpr instanceof LongValue) {
+ return new LongIfFunction(castedIf,(LongValue)thenExpr,(LongValue)elseExpr);
+ }
+ if (thenExpr instanceof LongValueStream && elseExpr instanceof LongValueStream) {
+ return new LongStreamIfFunction(castedIf,(LongValueStream)thenExpr,(LongValueStream)elseExpr);
+ }
+ if (thenExpr instanceof FloatValue && elseExpr instanceof FloatValue) {
+ return new FloatIfFunction(castedIf,(FloatValue)thenExpr,(FloatValue)elseExpr);
+ }
+ if (thenExpr instanceof FloatValueStream && elseExpr instanceof FloatValueStream) {
+ return new FloatStreamIfFunction(castedIf,(FloatValueStream)thenExpr,(FloatValueStream)elseExpr);
+ }
+ if (thenExpr instanceof DoubleValue && elseExpr instanceof DoubleValue) {
+ return new DoubleIfFunction(castedIf,(DoubleValue)thenExpr,(DoubleValue)elseExpr);
+ }
+ if (thenExpr instanceof DoubleValueStream && elseExpr instanceof DoubleValueStream) {
+ return new DoubleStreamIfFunction(castedIf,(DoubleValueStream)thenExpr,(DoubleValueStream)elseExpr);
+ }
+ if (thenExpr instanceof StringValue && elseExpr instanceof StringValue) {
+ return new StringIfFunction(castedIf,(StringValue)thenExpr,(StringValue)elseExpr);
+ }
+ if (thenExpr instanceof StringValueStream && elseExpr instanceof StringValueStream) {
+ return new StringStreamIfFunction(castedIf,(StringValueStream)thenExpr,(StringValueStream)elseExpr);
+ }
+ if (thenExpr instanceof AnalyticsValue && elseExpr instanceof AnalyticsValue) {
+ return new ValueIfFunction(castedIf,(AnalyticsValue)thenExpr,(AnalyticsValue)elseExpr);
+ }
+ return new IfFunction(castedIf,thenExpr,elseExpr);
+ });
+
+ public IfFunction(BooleanValue ifExpr, AnalyticsValueStream thenExpr, AnalyticsValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamObjects(cons);
+ }
+ else {
+ elseExpr.streamObjects(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class ValueIfFunction extends AbstractAnalyticsValue {
+ private final BooleanValue ifExpr;
+ private final AnalyticsValue thenExpr;
+ private final AnalyticsValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public ValueIfFunction(BooleanValue ifExpr, AnalyticsValue thenExpr, AnalyticsValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public Object getObject() {
+ exists = false;
+ Object value = null;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getObject();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getObject();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamIfFunction extends AbstractBooleanValueStream {
+ private final BooleanValue ifExpr;
+ private final BooleanValueStream thenExpr;
+ private final BooleanValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamIfFunction(BooleanValue ifExpr, BooleanValueStream thenExpr, BooleanValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamBooleans(cons);
+ }
+ else {
+ elseExpr.streamBooleans(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanIfFunction extends AbstractBooleanValue {
+ private final BooleanValue ifExpr;
+ private final BooleanValue thenExpr;
+ private final BooleanValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanIfFunction(BooleanValue ifExpr, BooleanValue thenExpr, BooleanValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ exists = false;
+ boolean value = false;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getBoolean();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getBoolean();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamIfFunction extends AbstractIntValueStream {
+ private final BooleanValue ifExpr;
+ private final IntValueStream thenExpr;
+ private final IntValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamIfFunction(BooleanValue ifExpr, IntValueStream thenExpr, IntValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamInts(cons);
+ }
+ else {
+ elseExpr.streamInts(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntIfFunction extends AbstractIntValue {
+ private final BooleanValue ifExpr;
+ private final IntValue thenExpr;
+ private final IntValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntIfFunction(BooleanValue ifExpr, IntValue thenExpr, IntValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public int getInt() {
+ exists = false;
+ int value = 0;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getInt();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getInt();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamIfFunction extends AbstractLongValueStream {
+ private final BooleanValue ifExpr;
+ private final LongValueStream thenExpr;
+ private final LongValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamIfFunction(BooleanValue ifExpr, LongValueStream thenExpr, LongValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamLongs(cons);
+ }
+ else {
+ elseExpr.streamLongs(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongIfFunction extends AbstractLongValue {
+ private final BooleanValue ifExpr;
+ private final LongValue thenExpr;
+ private final LongValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongIfFunction(BooleanValue ifExpr, LongValue thenExpr, LongValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public long getLong() {
+ exists = false;
+ long value = 0;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getLong();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getLong();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamIfFunction extends AbstractFloatValueStream {
+ private final BooleanValue ifExpr;
+ private final FloatValueStream thenExpr;
+ private final FloatValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamIfFunction(BooleanValue ifExpr, FloatValueStream thenExpr, FloatValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamFloats(cons);
+ }
+ else {
+ elseExpr.streamFloats(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatIfFunction extends AbstractFloatValue {
+ private final BooleanValue ifExpr;
+ private final FloatValue thenExpr;
+ private final FloatValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatIfFunction(BooleanValue ifExpr, FloatValue thenExpr, FloatValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ exists = false;
+ float value = 0;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getFloat();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getFloat();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleStreamIfFunction extends AbstractDoubleValueStream {
+ private final BooleanValue ifExpr;
+ private final DoubleValueStream thenExpr;
+ private final DoubleValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleStreamIfFunction(BooleanValue ifExpr, DoubleValueStream thenExpr, DoubleValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamDoubles(cons);
+ }
+ else {
+ elseExpr.streamDoubles(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleIfFunction extends AbstractDoubleValue {
+ private final BooleanValue ifExpr;
+ private final DoubleValue thenExpr;
+ private final DoubleValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleIfFunction(BooleanValue ifExpr, DoubleValue thenExpr, DoubleValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public double getDouble() {
+ exists = false;
+ double value = 0;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getDouble();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getDouble();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateStreamIfFunction extends AbstractDateValueStream {
+ private final BooleanValue ifExpr;
+ private final DateValueStream thenExpr;
+ private final DateValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateStreamIfFunction(BooleanValue ifExpr, DateValueStream thenExpr, DateValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamLongs(cons);
+ }
+ else {
+ elseExpr.streamLongs(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateIfFunction extends AbstractDateValue {
+ private final BooleanValue ifExpr;
+ private final DateValue thenExpr;
+ private final DateValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateIfFunction(BooleanValue ifExpr, DateValue thenExpr, DateValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public long getLong() {
+ exists = false;
+ long value = 0;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getLong();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getLong();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamIfFunction extends AbstractStringValueStream {
+ private final BooleanValue ifExpr;
+ private final StringValueStream thenExpr;
+ private final StringValueStream elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringStreamIfFunction(BooleanValue ifExpr, StringValueStream thenExpr, StringValueStream elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ thenExpr.streamStrings(cons);
+ }
+ else {
+ elseExpr.streamStrings(cons);
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringIfFunction extends AbstractStringValue {
+ private final BooleanValue ifExpr;
+ private final StringValue thenExpr;
+ private final StringValue elseExpr;
+ public static final String name = IfFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringIfFunction(BooleanValue ifExpr, StringValue thenExpr, StringValue elseExpr) throws SolrException {
+ this.ifExpr = ifExpr;
+ this.thenExpr = thenExpr;
+ this.elseExpr = elseExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,ifExpr,thenExpr,elseExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,ifExpr,thenExpr,elseExpr);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public String getString() {
+ exists = false;
+ String value = null;
+ boolean ifValue = ifExpr.getBoolean();
+ if (ifExpr.exists()) {
+ if (ifValue) {
+ value = thenExpr.getString();
+ exists = thenExpr.exists();
+ }
+ else {
+ value = elseExpr.getString();
+ exists = elseExpr.exists();
+ }
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/JoinFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/JoinFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/JoinFunction.java
new file mode 100644
index 0000000..528aae2
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/JoinFunction.java
@@ -0,0 +1,57 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.constant.ConstantStringValue;
+
+/**
+ * A string join mapping function.
+ * <p>
+ * Takes a {@link StringValueStream} as the first parameter and a {@link ConstantStringValue} (e.g. ",") as the second parameter
+ * and a {@link StringValue} is returned.
+ * <br>
+ * The second parameter is used as the separator while joining all values the first parameter has for a document.
+ * No order is guaranteed while joining the string values
+ */
+public class JoinFunction {
+ public static final String name = "join";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 parameters.");
+ }
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (!(param2 instanceof ConstantStringValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the second parameter to be a constant string");
+ }
+ String sep = ((StringValue)param2).getString();
+ if (!(param1 instanceof StringValueStream)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the first parameter to be castable to a string");
+ }
+ if (param1 instanceof StringValue) {
+ return param1;
+ }
+ String uniqueName = name + "(" + sep + ")";
+ return LambdaFunction.createStringLambdaFunction(uniqueName, (a,b) -> a + sep + b, (StringValueStream)params[0]);
+ });
+}
\ No newline at end of file
[16/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongField.java
new file mode 100644
index 0000000..ac4da2e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongField.java
@@ -0,0 +1,107 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.value.LongValue.CastingLongValue;
+import org.apache.solr.schema.LongPointField;
+import org.apache.solr.schema.TrieLongField;
+
+/**
+ * An analytics wrapper for a single-valued {@link TrieLongField} or {@link LongPointField} with DocValues enabled.
+ */
+public class LongField extends AnalyticsField implements CastingLongValue {
+ private NumericDocValues docValues;
+ private long value;
+ private boolean exists;
+
+ public LongField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = docValues.longValue();
+ }
+ }
+
+ @Override
+ public long getLong() {
+ return value;
+ }
+ @Override
+ public double getDouble() {
+ return (double)value;
+ }
+ @Override
+ public String getString() {
+ return exists ? Long.toString(value) : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ if (exists) {
+ cons.accept((double)value);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Long.toString(value));
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Long> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiField.java
new file mode 100644
index 0000000..dc2a953
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiField.java
@@ -0,0 +1,89 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.solr.analytics.value.LongValueStream.CastingLongValueStream;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.solr.schema.TrieLongField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link TrieLongField} with DocValues enabled.
+ */
+public class LongMultiField extends AnalyticsField implements CastingLongValueStream {
+ private SortedSetDocValues docValues;
+ private int count;
+ private long[] values;
+
+ public LongMultiField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new long[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+ }
+ @Override
+ public void collect(int doc) throws IOException {
+ count = 0;
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ if (count == values.length) {
+ resizeValues();
+ }
+ values[count++] = LegacyNumericUtils.prefixCodedToLong(docValues.lookupOrd(term));
+ }
+ }
+ }
+
+ private void resizeValues() {
+ long[] newValues = new long[values.length*2];
+ for (int i = 0; i < count; ++i) {
+ newValues[i] = values[i];
+ }
+ values = newValues;
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamLongs(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs(value -> cons.accept(Long.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiPointField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiPointField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiPointField.java
new file mode 100644
index 0000000..31d14ae
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/LongMultiPointField.java
@@ -0,0 +1,86 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.solr.analytics.value.LongValueStream.CastingLongValueStream;
+import org.apache.solr.schema.LongPointField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link LongPointField} with DocValues enabled.
+ */
+public class LongMultiPointField extends AnalyticsField implements CastingLongValueStream {
+ private SortedNumericDocValues docValues;
+ private int count;
+ private long[] values;
+
+ public LongMultiPointField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new long[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ if (docValues.advanceExact(doc)) {
+ count = docValues.docValueCount();
+ resizeEmptyValues(count);
+ for (int i = 0; i < count; ++i) {
+ values[i] = docValues.nextValue();
+ }
+ } else {
+ count = 0;
+ }
+ }
+
+ private void resizeEmptyValues(int count) {
+ if (count > values.length) {
+ values = new long[count];
+ }
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamLongs(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs(value -> cons.accept(Long.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringField.java
new file mode 100644
index 0000000..207a95a
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringField.java
@@ -0,0 +1,85 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.BinaryDocValues;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.value.StringValue.CastingStringValue;
+import org.apache.solr.schema.StrField;
+
+/**
+ * An analytics wrapper for a single-valued {@link StrField} with DocValues enabled.
+ */
+public class StringField extends AnalyticsField implements CastingStringValue {
+ private BinaryDocValues docValues;
+ String value;
+ boolean exists;
+
+ public StringField(String fieldName) {
+ super(fieldName);
+ exists = false;
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getBinary(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = docValues.binaryValue().utf8ToString();
+ }
+ }
+
+ @Override
+ public String getString() {
+ return exists ? value : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<String> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringMultiField.java
new file mode 100644
index 0000000..39c60f0
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/StringMultiField.java
@@ -0,0 +1,66 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.solr.analytics.value.StringValueStream.CastingStringValueStream;
+import org.apache.solr.schema.StrField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link StrField} with DocValues enabled.
+ */
+public class StringMultiField extends AnalyticsField implements CastingStringValueStream {
+ private SortedSetDocValues docValues;
+ private ArrayList<String> values;
+
+ public StringMultiField(String fieldName) {
+ super(fieldName);
+ values = new ArrayList<>(initialArrayLength);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+ }
+ @Override
+ public void collect(int doc) throws IOException {
+ values.clear();
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ values.add(docValues.lookupOrd(term).utf8ToString());
+ }
+ }
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ values.forEach(value -> cons.accept(value));
+ }
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ values.forEach(value -> cons.accept(value));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/package-info.java
new file mode 100644
index 0000000..a0e5421
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Fields to use for analytics expressions.
+ */
+package org.apache.solr.analytics.function.field;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AbsoluteValueFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AbsoluteValueFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AbsoluteValueFunction.java
new file mode 100644
index 0000000..d52810f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AbsoluteValueFunction.java
@@ -0,0 +1,54 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * An absolute value mapping function.
+ * <p>
+ * Takes a numeric ValueStream or Value and returns a ValueStream or Value of the same numeric type.
+ */
+public class AbsoluteValueFunction {
+ public static final String name = "abs";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof IntValueStream) {
+ return LambdaFunction.createIntLambdaFunction(name, x -> (x<0)? x*-1:x, (IntValueStream)param);
+ }
+ if (param instanceof LongValueStream) {
+ return LambdaFunction.createLongLambdaFunction(name, x -> (x<0)? x*-1:x, (LongValueStream)param);
+ }
+ if (param instanceof FloatValueStream) {
+ return LambdaFunction.createFloatLambdaFunction(name, x -> (x<0)? x*-1:x, (FloatValueStream)param);
+ }
+ if (param instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, x -> (x<0)? x*-1:x, (DoubleValueStream)param);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a numeric parameter, "+param.getExpressionStr()+" found.");
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AddFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AddFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AddFunction.java
new file mode 100644
index 0000000..d66f84e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/AddFunction.java
@@ -0,0 +1,68 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+
+/**
+ * An addition mapping function.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If a single numeric ValueStream is passed in, a {@link DoubleValue} representing the sum of the values for each document is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the sum of
+ * the Value and each of the values of the ValueStream for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * <li>If multiple numeric Values are passed in, a {@link DoubleValue} representing the sum of all values is returned.
+ * </ul>
+ */
+public class AddFunction {
+ public static final String name = "add";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires parameters.");
+ }
+ else if (params.length == 1) {
+ if (params[0] instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a+b, (DoubleValueStream)params[0]);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters. Incorrect param: "+params[0].getExpressionStr());
+ }
+ else if (params.length == 2) {
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof DoubleValueStream && param2 instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a+b, (DoubleValueStream)param1, (DoubleValueStream)param2);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters.");
+ }
+ DoubleValue[] castedParams = new DoubleValue[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DoubleValue) {
+ castedParams[i] = (DoubleValue) params[i];
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that all parameters be single-valued if more than 2 are given.");
+ }
+ }
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a+b, castedParams);
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/BottomFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/BottomFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/BottomFunction.java
new file mode 100644
index 0000000..f896da4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/BottomFunction.java
@@ -0,0 +1,163 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A bottom mapping function, returning the lowest value found.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If a single comparable ValueStream is passed in, a Value (of the same type) representing the minimum of the values for each document is returned.
+ * <li>If multiple comparable Values are passed in, a Value (of the same type) representing the minimum of all values is returned.
+ * </ul>
+ */
+public class BottomFunction {
+ public static final String name = "bottom";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires paramaters.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof DateValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createDateLambdaFunction(name, (a,b) -> (a<b)? a:b, (DateValueStream)param);
+ }
+ DateValue[] castedParams = new DateValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DateValue) {
+ castedParams[i] = (DateValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createDateLambdaFunction(name, (a,b) -> (a<b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof IntValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createIntLambdaFunction(name, (a,b) -> (a<b)? a:b, (IntValueStream)param);
+ }
+ IntValue[] castedParams = new IntValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof IntValue) {
+ castedParams[i] = (IntValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createIntLambdaFunction(name, (a,b) -> (a<b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof LongValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createLongLambdaFunction(name, (a,b) -> (a<b)? a:b, (LongValueStream)param);
+ }
+ LongValue[] castedParams = new LongValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof LongValue) {
+ castedParams[i] = (LongValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createLongLambdaFunction(name, (a,b) -> (a<b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof FloatValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createFloatLambdaFunction(name, (a,b) -> (a<b)? a:b, (FloatValueStream)param);
+ }
+ FloatValue[] castedParams = new FloatValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof FloatValue) {
+ castedParams[i] = (FloatValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createFloatLambdaFunction(name, (a,b) -> (a<b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof DoubleValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> (a<b)? a:b, (DoubleValueStream)param);
+ }
+ DoubleValue[] castedParams = new DoubleValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DoubleValue) {
+ castedParams[i] = (DoubleValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> (a<b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof StringValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> (a.compareTo(b)<=0)? a:b, (StringValueStream)param);
+ }
+ StringValue[] castedParams = new StringValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof StringValue) {
+ castedParams[i] = (StringValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> (a.compareTo(b)<=0)? a:b, castedParams, false);
+ }
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/CompareFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/CompareFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/CompareFunction.java
new file mode 100644
index 0000000..a06f7b8
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/CompareFunction.java
@@ -0,0 +1,614 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * Contains all comparable functions. Comparable functions accept two parameters and return a BooleanValueStream.
+ * The two parameters must be able to be cast to the same type.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If a two comparable {@link AnalyticsValue}s are passed in, a {@link BooleanValue} representing the comparison of the two values for each document is returned.
+ * <li>If a comparable {@link AnalyticsValue} and a comparable {@link AnalyticsValueStream} are passed in,
+ * a {@link BooleanValueStream} representing the comparison of the Value and each of the values of the ValueStream for the document is returned.
+ * </ul>
+ */
+public class CompareFunction {
+
+ private static BooleanValueStream createCompareFunction(String name, CompResultFunction comp, AnalyticsValueStream... params) {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream paramA = params[0];
+ AnalyticsValueStream paramB = params[1];
+ if (paramA instanceof DateValueStream && paramB instanceof DateValueStream) {
+ if (paramA instanceof DateValue) {
+ if (paramB instanceof DateValue) {
+ return new CompareDateValueFunction(name,(DateValue)paramA,(DateValue)paramB,comp);
+ }
+ return new CompareDateStreamFunction(name,(DateValue)paramA,(DateValueStream)paramB,comp);
+ }
+ if (paramB instanceof DateValue) {
+ return new CompareDateStreamFunction(name,(DateValue)paramB,(DateValueStream)paramA,reverse(comp));
+ }
+ } else if (paramA instanceof DoubleValueStream && paramB instanceof DoubleValueStream) {
+ if (paramA instanceof DoubleValue) {
+ if (paramB instanceof DoubleValue) {
+ return new CompareDoubleValueFunction(name,(DoubleValue)paramA,(DoubleValue)paramB,comp);
+ }
+ return new CompareDoubleStreamFunction(name,(DoubleValue)paramA,(DoubleValueStream)paramB,comp);
+ }
+ if (paramB instanceof DoubleValue) {
+ return new CompareDoubleStreamFunction(name,(DoubleValue)paramB,(DoubleValueStream)paramA,reverse(comp));
+ }
+ } else if (paramA instanceof StringValueStream && paramB instanceof StringValueStream) {
+ if (paramA instanceof StringValue) {
+ if (paramB instanceof StringValue) {
+ return new CompareStringValueFunction(name,(StringValue)paramA,(StringValue)paramB,comp);
+ }
+ return new CompareStringStreamFunction(name,(StringValue)paramA,(StringValueStream)paramB,comp);
+ }
+ if (paramB instanceof StringValue) {
+ return new CompareStringStreamFunction(name,(StringValue)paramB,(StringValueStream)paramA,reverse(comp));
+ }
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires comparable parameters.");
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that at least 1 parameter be single-valued.");
+ }
+
+ /**
+ * A comparison function that tests equality.
+ */
+ public static class EqualFunction {
+ public static final String name = "equal";
+ public static final CreatorFunction creatorFunction = (params -> {
+ try {
+ return CompareFunction.createCompareFunction(name, val -> {
+ return val == 0;
+ }, params);
+ } catch (SolrException e) {
+ if (params.length != 2) {
+ throw e;
+ }
+
+ AnalyticsValueStream paramA = params[0];
+ AnalyticsValueStream paramB = params[1];
+
+ // Booleans aren't really comparable, so just enable the equal function
+ if (paramA instanceof BooleanValueStream && paramB instanceof BooleanValueStream) {
+ if (paramA instanceof BooleanValue) {
+ if (paramB instanceof BooleanValue) {
+ return new BooleanValueEqualFunction((BooleanValue)paramA,(BooleanValue)paramB);
+ }
+ return new BooleanStreamEqualFunction((BooleanValue)paramA,(BooleanValueStream)paramB);
+ } else if (paramB instanceof BooleanValue) {
+ return new BooleanStreamEqualFunction((BooleanValue)paramB,(BooleanValueStream)paramA);
+ }
+ }
+
+ // This means that the Objects created by the AnalyticsValueStreams are not comparable, so use the .equals() method instead
+ else if (paramA instanceof AnalyticsValue) {
+ if (paramB instanceof AnalyticsValue) {
+ return new ValueEqualFunction((AnalyticsValue)paramA,(AnalyticsValue)paramB);
+ }
+ return new StreamEqualFunction((AnalyticsValue)paramA,paramB);
+ }
+ if (paramB instanceof AnalyticsValue) {
+ return new StreamEqualFunction((AnalyticsValue)paramB,paramA);
+ }
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that at least 1 parameter be single-valued.");
+ });
+ }
+
+ /**
+ * A comparison function that tests whether the first parameter is greater than the second parameter
+ */
+ public static class GTFunction {
+ public static final String name = "gt";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return CompareFunction.createCompareFunction(name, val -> {
+ return val > 0;
+ }, params);
+ });
+ }
+
+ /**
+ * A comparison function that tests whether the first parameter is greater than or equal to the second parameter
+ */
+ public static class GTEFunction {
+ public static final String name = "gte";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return CompareFunction.createCompareFunction(name, val -> {
+ return val >= 0;
+ }, params);
+ });
+ }
+
+ /**
+ * A comparison function that tests whether the first parameter is less than the second parameter
+ */
+ public static class LTFunction {
+ public static final String name = "lt";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return CompareFunction.createCompareFunction(name, val -> {
+ return val < 0;
+ }, params);
+ });
+ }
+
+ /**
+ * A comparison function that tests whether the first parameter is less than or equal to the second parameter
+ */
+ public static class LTEFunction {
+ public static final String name = "lte";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return CompareFunction.createCompareFunction(name, val -> {
+ return val <= 0;
+ }, params);
+ });
+ }
+
+ private static CompResultFunction reverse(CompResultFunction original) {
+ return val -> original.apply(val*-1);
+ }
+}
+@FunctionalInterface
+interface CompResultFunction {
+ public boolean apply(int compResult);
+}
+/**
+ * A comparison function for two {@link DoubleValue}s.
+ */
+class CompareDoubleValueFunction extends AbstractBooleanValue {
+ private final DoubleValue exprA;
+ private final DoubleValue exprB;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareDoubleValueFunction(String name, DoubleValue exprA, DoubleValue exprB, CompResultFunction comp) {
+ this.name = name;
+ this.exprA = exprA;
+ this.exprB = exprB;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,exprA,exprB);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,exprA,exprB);
+ }
+
+ private boolean exists = false;
+ @Override
+ public boolean getBoolean() {
+ double valueA = exprA.getDouble();
+ double valueB = exprB.getDouble();
+ exists = exprA.exists() && exprB.exists();
+ return exists ? comp.apply(Double.compare(valueA,valueB)) : false;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A comparison function for a {@link DoubleValue} and a {@link DoubleValueStream}.
+ */
+class CompareDoubleStreamFunction extends AbstractBooleanValueStream {
+ private final DoubleValue baseExpr;
+ private final DoubleValueStream compExpr;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareDoubleStreamFunction(String name, DoubleValue baseExpr, DoubleValueStream compExpr, CompResultFunction comp) throws SolrException {
+ this.name = name;
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,baseExpr,compExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ double baseValue = baseExpr.getDouble();
+ if (baseExpr.exists()) {
+ compExpr.streamDoubles(compValue -> cons.accept(comp.apply(Double.compare(baseValue,compValue))));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A comparison function for two {@link DateValue}s.
+ */
+class CompareDateValueFunction extends AbstractBooleanValue {
+ private final DateValue exprA;
+ private final DateValue exprB;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareDateValueFunction(String name, DateValue exprA, DateValue exprB, CompResultFunction comp) {
+ this.name = name;
+ this.exprA = exprA;
+ this.exprB = exprB;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,exprA,exprB);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,exprA,exprB);
+ }
+
+ private boolean exists = false;
+ @Override
+ public boolean getBoolean() {
+ long valueA = exprA.getLong();
+ long valueB = exprB.getLong();
+ exists = exprA.exists() && exprB.exists();
+ return exists ? comp.apply(Long.compare(valueA,valueB)) : false;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A comparison function for a {@link DateValue} and a {@link DateValueStream}.
+ */
+class CompareDateStreamFunction extends AbstractBooleanValueStream {
+ private final DateValue baseExpr;
+ private final DateValueStream compExpr;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareDateStreamFunction(String name, DateValue baseExpr, DateValueStream compExpr, CompResultFunction comp) throws SolrException {
+ this.name = name;
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,baseExpr,compExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ long baseValue = baseExpr.getLong();
+ if (baseExpr.exists()) {
+ compExpr.streamLongs(compValue -> cons.accept(comp.apply(Long.compare(baseValue,compValue))));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A comparison function for two {@link StringValue}s.
+ */
+class CompareStringValueFunction extends AbstractBooleanValue {
+ private final StringValue exprA;
+ private final StringValue exprB;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareStringValueFunction(String name, StringValue exprA, StringValue exprB, CompResultFunction comp) {
+ this.name = name;
+ this.exprA = exprA;
+ this.exprB = exprB;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,exprA,exprB);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,exprA,exprB);
+ }
+
+ private boolean exists = false;
+ @Override
+ public boolean getBoolean() {
+ String valueA = exprA.toString();
+ String valueB = exprB.toString();
+ exists = exprA.exists() && exprB.exists();
+ return exists ? comp.apply(valueA.compareTo(valueB)) : false;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A comparison function for a {@link StringValue} and a {@link StringValueStream}.
+ */
+class CompareStringStreamFunction extends AbstractBooleanValueStream {
+ private final StringValue baseExpr;
+ private final StringValueStream compExpr;
+ private final CompResultFunction comp;
+ private final String name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public CompareStringStreamFunction(String name, StringValue baseExpr, StringValueStream compExpr, CompResultFunction comp) throws SolrException {
+ this.name = name;
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.comp = comp;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,baseExpr,compExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ String baseValue = baseExpr.toString();
+ if (baseExpr.exists()) {
+ compExpr.streamStrings(compValue -> cons.accept(comp.apply(baseValue.compareTo(compValue))));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * An equal function for two {@link BooleanValue}s.
+ */
+class BooleanValueEqualFunction extends AbstractBooleanValue {
+ private final BooleanValue exprA;
+ private final BooleanValue exprB;
+ public static final String name = CompareFunction.EqualFunction.name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public BooleanValueEqualFunction(BooleanValue exprA, BooleanValue exprB) {
+ this.exprA = exprA;
+ this.exprB = exprB;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,exprA,exprB);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,exprA,exprB);
+ }
+
+ private boolean exists = false;
+ @Override
+ public boolean getBoolean() {
+ boolean valueA = exprA.getBoolean();
+ boolean valueB = exprB.getBoolean();
+ exists = exprA.exists() && exprB.exists();
+ return exists ? valueA == valueB : false;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * An equal function for a {@link BooleanValue} and a {@link BooleanValueStream}.
+ */
+class BooleanStreamEqualFunction extends AbstractBooleanValueStream {
+ private final BooleanValue baseExpr;
+ private final BooleanValueStream compExpr;
+ public static final String name = CompareFunction.EqualFunction.name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamEqualFunction(BooleanValue baseExpr, BooleanValueStream compExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,baseExpr,compExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean baseValue = baseExpr.getBoolean();
+ if (baseExpr.exists()) {
+ compExpr.streamBooleans(compValue -> cons.accept(baseValue == compValue));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A catch-all equal function for two {@link AnalyticsValue}s.
+ */
+class ValueEqualFunction extends AbstractBooleanValue {
+ private final AnalyticsValue exprA;
+ private final AnalyticsValue exprB;
+ public static final String name = CompareFunction.EqualFunction.name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public ValueEqualFunction(AnalyticsValue exprA, AnalyticsValue exprB) {
+ this.exprA = exprA;
+ this.exprB = exprB;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,exprA,exprB);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,exprA,exprB);
+ }
+
+ private boolean exists = false;
+ @Override
+ public boolean getBoolean() {
+ Object valueA = exprA.getObject();
+ Object valueB = exprB.getObject();
+ exists = exprA.exists() && exprB.exists();
+ return exists ? valueA.equals(valueB) : false;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A catch-all equal function for an {@link AnalyticsValue} and an {@link AnalyticsValueStream}.
+ */
+class StreamEqualFunction extends AbstractBooleanValueStream {
+ private final AnalyticsValue baseExpr;
+ private final AnalyticsValueStream compExpr;
+ public static final String name = CompareFunction.EqualFunction.name;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public StreamEqualFunction(AnalyticsValue baseExpr, AnalyticsValueStream compExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,baseExpr,compExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ Object baseValue = baseExpr.getObject();
+ if (baseExpr.exists()) {
+ compExpr.streamObjects(compValue -> cons.accept(baseValue.equals(compValue)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ConcatFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ConcatFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ConcatFunction.java
new file mode 100644
index 0000000..e54e8c5
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ConcatFunction.java
@@ -0,0 +1,78 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.constant.ConstantStringValue;
+
+/**
+ * A concatenation mapping function, combining the string values of the given parameters. (At least 1 parameter is required)
+ * <p>
+ * Multiple comparable {@link StringValue}s are passed in and a {@link StringValue} representing the concatenation of all values is returned.
+ */
+public class ConcatFunction {
+ public static final String name = "concat";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires parameters.");
+ }
+ else if (params.length == 1 && params[0] instanceof StringValue) {
+ return params[0];
+ }
+ StringValue[] castedParams = new StringValue[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof StringValue) {
+ castedParams[i] = (StringValue) params[i];
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that all parameters be single-valued and convertible to string values.");
+ }
+ }
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> a+b, castedParams, false);
+ });
+
+ /**
+ * A concatenation mapping function, combining the string values of the given parameters with a given separating string.
+ * <br>
+ * Multiple comparable {@link StringValue}s are passed in and a {@link StringValue} representing the separated concatenation of all values is returned.
+ * <p>
+ * The first parameter must be a constant string (e.g. ",").
+ * The remaining parameters are the {@link StringValue} expressions to concatenate. (At least 1 expression is required)
+ */
+ public static class ConcatSeparatedFunction {
+ public static final String name = "concatsep";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length < 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 2 parameters.");
+ } else if (!(params[0] instanceof ConstantStringValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that the first parameter to be a constant string.");
+ }
+ final String sep = ((ConstantStringValue)params[0]).getString();
+ StringValue[] castedParams = new StringValue[params.length - 1];
+ for (int i = 0; i < castedParams.length; i++) {
+ if (params[i + 1] instanceof StringValue) {
+ castedParams[i] = (StringValue) params[i + 1];
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that all non-separator parameters be single-valued and convertible to string values.");
+ }
+ }
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> a + sep + b, castedParams, false);
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateMathFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateMathFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateMathFunction.java
new file mode 100644
index 0000000..9901625
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateMathFunction.java
@@ -0,0 +1,156 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.Date;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.constant.ConstantStringValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.util.DateMathParser;
+
+/**
+ * A mapping function that computes date math.
+ * <p>
+ * The first parameter is the {@link DateValue} or {@link DateValueStream} to compute date math on. (Required)
+ * <br>
+ * The trailing parameters must be constant date math strings (e.g. "+1DAY"). (At least 1 required)
+ */
+public class DateMathFunction {
+ public static final String name = "date_math";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length < 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 2 paramaters, " + params.length + " found.");
+ }
+ StringBuilder mathParam = new StringBuilder();
+ for (int i = 1; i < params.length; ++i) {
+ if (params[i] instanceof ConstantStringValue) {
+ mathParam.append(((ConstantStringValue) params[i]).getString());
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires all math parameters to be a constant strings.");
+ }
+ }
+ if (params[0] instanceof DateValue) {
+ return new DateMathValueFunction((DateValue)params[0], new ConstantStringValue(mathParam.toString()));
+ } else if (params[0] instanceof DateValueStream) {
+ return new DateMathStreamFunction((DateValueStream)params[0], new ConstantStringValue(mathParam.toString()));
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a date as the first parameter.");
+ }
+ });
+}
+/**
+ * DateMath function that supports {@link DateValue}s.
+ */
+class DateMathValueFunction extends AbstractDateValue {
+ private final DateValue dateParam;
+ private final String mathParam;
+ DateMathParser parser = new DateMathParser();
+ public static final String name = DateMathFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateMathValueFunction(DateValue dateParam, ConstantStringValue mathParam) throws SolrException {
+ this.dateParam = dateParam;
+ this.mathParam = "NOW" + mathParam.getString();
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,dateParam,mathParam);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,dateParam);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public long getLong() {
+ Date date = getDate();
+ return (date == null) ? 0 : date.getTime();
+ }
+ @Override
+ public Date getDate() {
+ Date date = dateParam.getDate();
+ if (dateParam.exists()) {
+ exists = true;
+ return DateMathParser.parseMath(date,mathParam);
+ } else {
+ exists = false;
+ return null;
+ }
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * DateMath function that supports {@link DateValueStream}s.
+ */
+class DateMathStreamFunction extends AbstractDateValueStream {
+ private final DateValueStream dateParam;
+ private final String mathParam;
+ public static final String name = DateMathFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateMathStreamFunction(DateValueStream dateParam, ConstantStringValue mathParam) throws SolrException {
+ this.dateParam = dateParam;
+ this.mathParam = "NOW" + mathParam.getString();
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,dateParam,mathParam);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,dateParam);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ streamDates(value -> cons.accept(value.getTime()));
+ }
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ dateParam.streamDates(value -> cons.accept(DateMathParser.parseMath(value, mathParam)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateParseFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateParseFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateParseFunction.java
new file mode 100644
index 0000000..5929b88
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DateParseFunction.java
@@ -0,0 +1,210 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function that converts long or string representations of dates to actual date objects.
+ * <p>
+ * The only parameter is the {@link LongValue}, {@link LongValueStream}, {@link DateValue}, or {@link DateValueStream} to convert. (Required)
+ */
+public class DateParseFunction {
+ public static final String name = "date";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ if (params[0] instanceof LongValue) {
+ return new LongToDateParseFunction((LongValue)params[0]);
+ }
+ else if (params[0] instanceof LongValueStream) {
+ return new LongStreamToDateParseFunction((LongValueStream)params[0]);
+ }
+ else if (params[0] instanceof StringValue) {
+ return new StringToDateParseFunction((StringValue)params[0]);
+ }
+ else if (params[0] instanceof StringValueStream) {
+ return new StringStreamToDateParseFunction((StringValueStream)params[0]);
+ }
+ else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a string or long parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ }
+ });
+}
+class LongToDateParseFunction extends AbstractDateValue {
+ private final LongValue param;
+ public static final String name = DateParseFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongToDateParseFunction(LongValue param) throws SolrException {
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public long getLong() {
+ return param.getLong();
+ }
+ @Override
+ public boolean exists() {
+ return param.exists();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamToDateParseFunction extends AbstractDateValueStream {
+ private final LongValueStream param;
+ public static final String name = DateParseFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+ public static final DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS", Locale.ROOT);
+
+ public LongStreamToDateParseFunction(LongValueStream param) throws SolrException {
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ param.streamLongs(cons);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringToDateParseFunction extends AbstractDateValue {
+ private final StringValue param;
+ public static final String name = DateParseFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+ public static final DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS", Locale.ROOT);
+
+ public StringToDateParseFunction(StringValue param) throws SolrException {
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+ @Override
+ public long getLong() {
+ long value = 0;
+ try {
+ value = formatter.parse(param.toString()).getTime();
+ exists = param.exists();
+ } catch (ParseException e) {
+ exists = false;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamToDateParseFunction extends AbstractDateValueStream {
+ private final StringValueStream param;
+ public static final String name = DateParseFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+ public static final DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS", Locale.ROOT);
+
+ public StringStreamToDateParseFunction(StringValueStream param) throws SolrException {
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ param.streamStrings(value -> {
+ try {
+ cons.accept(formatter.parse(value).getTime());
+ } catch (ParseException e) {
+ }
+ });
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DivideFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DivideFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DivideFunction.java
new file mode 100644
index 0000000..e644812
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/DivideFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A division mapping function. No checking on divisor value is done. An error will occur if a zero divisor is used.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If two numeric Values are passed in, a {@link DoubleValue} representing the divison of the two values is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the division of
+ * the Value and each of the values of the ValueStream for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * </ul>
+ */
+public class DivideFunction {
+ public static final String name = "div";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof DoubleValueStream && param2 instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a/b, (DoubleValueStream)param1, (DoubleValueStream)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters.");
+ }
+ });
+}
\ No newline at end of file
[10/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequest.java
deleted file mode 100644
index d147e6e..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Contains the specifications of an Analytics Request, specifically a name,
- * a list of Expressions, a list of field facets, a list of range facets, a list of query facets
- * and the list of expressions and their results calculated in previous AnalyticsRequests.
- */
-public class AnalyticsRequest {
-
- private String name;
- private List<ExpressionRequest> expressions;
- private Set<String> hiddenExpressions;
- private List<FieldFacetRequest> fieldFacets;
- private List<RangeFacetRequest> rangeFacets;
- private List<QueryFacetRequest> queryFacets;
-
- public AnalyticsRequest(String name) {
- this.name = name;
- expressions = new ArrayList<>();
- hiddenExpressions = new HashSet<>();
- fieldFacets = new ArrayList<>();
- rangeFacets = new ArrayList<>();
- queryFacets = new ArrayList<>();
- }
-
- public String getName() {
- return name;
- }
-
- public void setExpressions(List<ExpressionRequest> expressions) {
- this.expressions = expressions;
- }
-
- public void addExpression(ExpressionRequest expressionRequest) {
- expressions.add(expressionRequest);
- }
-
- public List<ExpressionRequest> getExpressions() {
- return expressions;
- }
-
- public void addHiddenExpression(ExpressionRequest expressionRequest) {
- expressions.add(expressionRequest);
- hiddenExpressions.add(expressionRequest.getName());
- }
-
- public Set<String> getHiddenExpressions() {
- return hiddenExpressions;
- }
-
- public void setFieldFacets(List<FieldFacetRequest> fieldFacets) {
- this.fieldFacets = fieldFacets;
- }
-
- public List<FieldFacetRequest> getFieldFacets() {
- return fieldFacets;
- }
-
- public void setRangeFacets(List<RangeFacetRequest> rangeFacets) {
- this.rangeFacets = rangeFacets;
- }
-
- public List<RangeFacetRequest> getRangeFacets() {
- return rangeFacets;
- }
-
- public void setQueryFacets(List<QueryFacetRequest> queryFacets) {
- this.queryFacets = queryFacets;
- }
-
- public List<QueryFacetRequest> getQueryFacets() {
- return queryFacets;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("<AnalyticsRequest name=" + name + ">");
- for (ExpressionRequest exp : expressions) {
- builder.append(exp.toString());
- }
- for (FieldFacetRequest facet : fieldFacets) {
- builder.append(facet.toString());
- }
- for (RangeFacetRequest facet : rangeFacets) {
- builder.append(facet.toString());
- }
- for (QueryFacetRequest facet : queryFacets) {
- builder.append(facet.toString());
- }
- builder.append("</AnalyticsRequest>");
- return builder.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequestFactory.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequestFactory.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequestFactory.java
deleted file mode 100644
index 3773ff6..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsRequestFactory.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortSpecification;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
-import org.apache.solr.common.params.FacetParams.FacetRangeOther;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.schema.IndexSchema;
-
-/**
- * Parses the SolrParams to create a list of analytics requests.
- */
-public class AnalyticsRequestFactory implements AnalyticsParams {
-
- public static final Pattern statPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+EXPRESSION+")\\.([^\\.]+)$", Pattern.CASE_INSENSITIVE);
- public static final Pattern hiddenStatPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+HIDDEN_EXPRESSION+")\\.([^\\.]+)$", Pattern.CASE_INSENSITIVE);
- public static final Pattern fieldFacetPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+FIELD_FACET+")$", Pattern.CASE_INSENSITIVE);
- public static final Pattern fieldFacetParamPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+FIELD_FACET+")\\.([^\\.]+)\\.("+LIMIT+"|"+OFFSET+"|"+HIDDEN+"|"+SHOW_MISSING+"|"+SORT_STATISTIC+"|"+SORT_DIRECTION+")$", Pattern.CASE_INSENSITIVE);
- public static final Pattern rangeFacetPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+RANGE_FACET+")$", Pattern.CASE_INSENSITIVE);
- public static final Pattern rangeFacetParamPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+RANGE_FACET+")\\.([^\\.]+)\\.("+START+"|"+END+"|"+GAP+"|"+HARDEND+"|"+INCLUDE_BOUNDARY+"|"+OTHER_RANGE+")$", Pattern.CASE_INSENSITIVE);
- public static final Pattern queryFacetPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+QUERY_FACET+")$", Pattern.CASE_INSENSITIVE);
- public static final Pattern queryFacetParamPattern = Pattern.compile("^o(?:lap)?\\.([^\\.]+)\\.(?:"+QUERY_FACET+")\\.([^\\.]+)\\.("+QUERY+"|"+DEPENDENCY+")$", Pattern.CASE_INSENSITIVE);
-
- public static List<AnalyticsRequest> parse(IndexSchema schema, SolrParams params) {
- Map<String, AnalyticsRequest> requestMap = new HashMap<>();
- Map<String, Map<String,FieldFacetRequest>> fieldFacetMap = new HashMap<>();
- Map<String, Set<String>> fieldFacetSet = new HashMap<>();
- Map<String, Map<String,RangeFacetRequest>> rangeFacetMap = new HashMap<>();
- Map<String, Set<String>> rangeFacetSet = new HashMap<>();
- Map<String, Map<String,QueryFacetRequest>> queryFacetMap = new HashMap<>();
- Map<String, Set<String>> queryFacetSet = new HashMap<>();
- List<AnalyticsRequest> requestList = new ArrayList<>();
-
- Iterator<String> paramsIterator = params.getParameterNamesIterator();
- while (paramsIterator.hasNext()) {
- String param = paramsIterator.next();
- CharSequence paramSequence = param.subSequence(0, param.length());
-
- // Check if stat
- Matcher m = statPattern.matcher(paramSequence);
- if (m.matches()) {
- makeExpression(requestMap,m.group(1),m.group(2),params.get(param));
- } else {
- // Check if hidden stat
- m = hiddenStatPattern.matcher(paramSequence);
- if (m.matches()) {
- makeHiddenExpression(requestMap,m.group(1),m.group(2),params.get(param));
- } else {
- // Check if field facet
- m = fieldFacetPattern.matcher(paramSequence);
- if (m.matches()) {
- makeFieldFacet(schema,fieldFacetMap,fieldFacetSet,m.group(1),params.getParams(param));
- } else {
- // Check if field facet parameter
- m = fieldFacetParamPattern.matcher(paramSequence);
- if (m.matches()) {
- setFieldFacetParam(schema,fieldFacetMap,m.group(1),m.group(2),m.group(3),params.getParams(param));
- } else {
- // Check if range facet
- m = rangeFacetPattern.matcher(paramSequence);
- if (m.matches()) {
- makeRangeFacet(schema,rangeFacetSet,m.group(1),params.getParams(param));
- } else {
- // Check if range facet parameter
- m = rangeFacetParamPattern.matcher(paramSequence);
- if (m.matches()) {
- setRangeFacetParam(schema,rangeFacetMap,m.group(1),m.group(2),m.group(3),params.getParams(param));
- } else {
- // Check if query facet
- m = queryFacetPattern.matcher(paramSequence);
- if (m.matches()) {
- makeQueryFacet(schema,queryFacetSet,m.group(1),params.getParams(param));
- } else {
- // Check if query
- m = queryFacetParamPattern.matcher(paramSequence);
- if (m.matches()) {
- setQueryFacetParam(schema,queryFacetMap,m.group(1),m.group(2),m.group(3),params.getParams(param));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- for (String reqName : requestMap.keySet()) {
- AnalyticsRequest ar = requestMap.get(reqName);
- List<FieldFacetRequest> ffrs = new ArrayList<>();
- if (fieldFacetSet.get(reqName)!=null) {
- for (String field : fieldFacetSet.get(reqName)) {
- ffrs.add(fieldFacetMap.get(reqName).get(field));
- }
- }
- ar.setFieldFacets(ffrs);
-
- List<RangeFacetRequest> rfrs = new ArrayList<>();
- if (rangeFacetSet.get(reqName)!=null) {
- for (String field : rangeFacetSet.get(reqName)) {
- RangeFacetRequest rfr = rangeFacetMap.get(reqName).get(field);
- if (rfr != null) {
- rfrs.add(rfr);
- }
- }
- }
- ar.setRangeFacets(rfrs);
-
- List<QueryFacetRequest> qfrs = new ArrayList<>();
- if (queryFacetSet.get(reqName)!=null) {
- for (String name : queryFacetSet.get(reqName)) {
- QueryFacetRequest qfr = queryFacetMap.get(reqName).get(name);
- if (qfr != null) {
- addQueryFacet(qfrs,qfr);
- }
- }
- }
- for (QueryFacetRequest qfr : qfrs) {
- if (qfr.getDependencies().size()>0) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The query facet dependencies "+qfr.getDependencies().toString()+" either do not exist or are defined in a dependency looop.");
- }
- }
- ar.setQueryFacets(qfrs);
- requestList.add(ar);
- }
- return requestList;
- }
-
- private static void makeFieldFacet(IndexSchema schema, Map<String, Map<String, FieldFacetRequest>> fieldFacetMap, Map<String, Set<String>> fieldFacetSet, String requestName, String[] fields) {
- Map<String, FieldFacetRequest> facetMap = fieldFacetMap.get(requestName);
- if (facetMap == null) {
- facetMap = new HashMap<>();
- fieldFacetMap.put(requestName, facetMap);
- }
- Set<String> set = fieldFacetSet.get(requestName);
- if (set == null) {
- set = new HashSet<>();
- fieldFacetSet.put(requestName, set);
- }
- for (String field : fields) {
- if (facetMap.get(field) == null) {
- facetMap.put(field,new FieldFacetRequest(schema.getField(field)));
- }
- set.add(field);
- }
- }
-
- private static void setFieldFacetParam(IndexSchema schema, Map<String, Map<String, FieldFacetRequest>> fieldFacetMap, String requestName, String field, String paramType, String[] params) {
- Map<String, FieldFacetRequest> facetMap = fieldFacetMap.get(requestName);
- if (facetMap == null) {
- facetMap = new HashMap<>();
- fieldFacetMap.put(requestName, facetMap);
- }
- FieldFacetRequest fr = facetMap.get(field);
- if (fr == null) {
- fr = new FieldFacetRequest(schema.getField(field));
- facetMap.put(field,fr);
- }
- if (paramType.equals("limit")||paramType.equals("l")) {
- fr.setLimit(Integer.parseInt(params[0]));
- } else if (paramType.equals("offset")||paramType.equals("off")) {
- fr.setOffset(Integer.parseInt(params[0]));
- } else if (paramType.equals("hidden")||paramType.equals("h")) {
- fr.setHidden(Boolean.parseBoolean(params[0]));
- } else if (paramType.equals("showmissing")||paramType.equals("sm")) {
- fr.showMissing(Boolean.parseBoolean(params[0]));
- } else if (paramType.equals("sortstatistic")||paramType.equals("sortstat")||paramType.equals("ss")) {
- fr.setSort(new FacetSortSpecification(params[0],fr.getDirection()));
- } else if (paramType.equals("sortdirection")||paramType.equals("sd")) {
- fr.setDirection(params[0]);
- }
- }
-
- private static void makeRangeFacet(IndexSchema schema, Map<String, Set<String>> rangeFacetSet, String requestName, String[] fields) {
- Set<String> set = rangeFacetSet.get(requestName);
- if (set == null) {
- set = new HashSet<>();
- rangeFacetSet.put(requestName, set);
- }
- for (String field : fields) {
- set.add(field);
- }
- }
-
- private static void setRangeFacetParam(IndexSchema schema, Map<String, Map<String, RangeFacetRequest>> rangeFacetMap, String requestName, String field, String paramType, String[] params) {
- Map<String, RangeFacetRequest> facetMap = rangeFacetMap.get(requestName);
- if (facetMap == null) {
- facetMap = new HashMap<>();
- rangeFacetMap.put(requestName, facetMap);
- }
- RangeFacetRequest rr = facetMap.get(field);
- if (rr == null) {
- rr = new RangeFacetRequest(schema.getField(field));
- facetMap.put(field,rr);
- }
- if (paramType.equals("start")||paramType.equals("st")) {
- rr.setStart(params[0]);
- } else if (paramType.equals("end")||paramType.equals("e")) {
- rr.setEnd(params[0]);
- } else if (paramType.equals("gap")||paramType.equals("g")) {
- rr.setGaps(params[0].split(","));
- } else if (paramType.equals("hardend")||paramType.equals("he")) {
- rr.setHardEnd(Boolean.parseBoolean(params[0]));
- } else if (paramType.equals("includebound")||paramType.equals("ib")) {
- for (String param : params) {
- rr.addInclude(FacetRangeInclude.get(param));
- }
- } else if (paramType.equals("otherrange")||paramType.equals("or")) {
- for (String param : params) {
- rr.addOther(FacetRangeOther.get(param));
- }
- }
- }
-
- private static void makeQueryFacet(IndexSchema schema,Map<String, Set<String>> queryFacetSet, String requestName, String[] names) {
- Set<String> set = queryFacetSet.get(requestName);
- if (set == null) {
- set = new HashSet<>();
- queryFacetSet.put(requestName, set);
- }
- for (String name : names) {
- set.add(name);
- }
- }
-
- private static void setQueryFacetParam(IndexSchema schema, Map<String, Map<String, QueryFacetRequest>> queryFacetMap, String requestName, String name, String paramType, String[] params) {
- Map<String, QueryFacetRequest> facetMap = queryFacetMap.get(requestName);
- if (facetMap == null) {
- facetMap = new HashMap<>();
- queryFacetMap.put(requestName, facetMap);
- }
- QueryFacetRequest qr = facetMap.get(name);
- if (qr == null) {
- qr = new QueryFacetRequest(name);
- facetMap.put(name,qr);
- }
- if (paramType.equals("query")||paramType.equals("q")) {
- for (String query : params) {
- qr.addQuery(query);
- }
- } else if (paramType.equals("dependency")||paramType.equals("d")) {
- for (String depend : params) {
- qr.addDependency(depend);
- }
- }
- }
-
- private static void makeHiddenExpression(Map<String, AnalyticsRequest> requestMap, String requestName, String expressionName, String expression) {
- AnalyticsRequest req = requestMap.get(requestName);
- if (req == null) {
- req = new AnalyticsRequest(requestName);
- requestMap.put(requestName, req);
- }
- req.addHiddenExpression(new ExpressionRequest(expressionName,expression));
- }
-
- private static void makeExpression(Map<String, AnalyticsRequest> requestMap, String requestName, String expressionName, String expression) {
- AnalyticsRequest req = requestMap.get(requestName);
- if (req == null) {
- req = new AnalyticsRequest(requestName);
- requestMap.put(requestName, req);
- }
- req.addExpression(new ExpressionRequest(expressionName,expression));
- }
-
- private static void addQueryFacet(List<QueryFacetRequest> currentList, QueryFacetRequest queryFacet) {
- Set<String> depends = queryFacet.getDependencies();
- int place = 0;
- for (QueryFacetRequest qfr : currentList) {
- if (qfr.getDependencies().remove(queryFacet.getName())) {
- break;
- }
- place++;
- depends.remove(qfr.getName());
- }
- currentList.add(place,queryFacet);
- for (int count = place+1; count < currentList.size(); count++) {
- currentList.get(count).getDependencies().remove(queryFacet.getName());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsStats.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsStats.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsStats.java
deleted file mode 100644
index 771aff7..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsStats.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.List;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.DocIdSet;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.solr.analytics.accumulator.BasicAccumulator;
-import org.apache.solr.analytics.accumulator.FacetingAccumulator;
-import org.apache.solr.analytics.accumulator.ValueAccumulator;
-import org.apache.solr.analytics.plugin.AnalyticsStatisticsCollector;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.search.DocSet;
-import org.apache.solr.search.Filter;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class which computes the set of {@link AnalyticsRequest}s.
- */
-public class AnalyticsStats {
- protected DocSet docs;
- protected SolrParams params;
- protected SolrIndexSearcher searcher;
- protected SolrQueryRequest req;
- protected AnalyticsStatisticsCollector statsCollector;
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- public AnalyticsStats(SolrQueryRequest req, DocSet docs, SolrParams params, AnalyticsStatisticsCollector statsCollector) {
- this.req = req;
- this.searcher = req.getSearcher();
- this.docs = docs;
- this.params = params;
- this.statsCollector = statsCollector;
- }
-
- /**
- * Calculates the analytics requested in the Parameters.
- *
- * @return List of results formated to mirror the input XML.
- * @throws IOException if execution fails
- */
- public NamedList<?> execute() throws IOException {
- statsCollector.startRequest();
- NamedList<Object> res = new NamedList<>();
- List<AnalyticsRequest> requests;
-
- requests = AnalyticsRequestFactory.parse(searcher.getSchema(), params);
-
- if(requests == null || requests.size()==0){
- return res;
- }
- statsCollector.addRequests(requests.size());
-
- // Get filter to all docs
- Filter filter = docs.getTopFilter();
-
- // Computing each Analytics Request Separately
- for( AnalyticsRequest areq : requests ){
- // The Accumulator which will control the statistics generation
- // for the entire analytics request
- ValueAccumulator accumulator;
-
- // The number of total facet requests
- int facets = areq.getFieldFacets().size()+areq.getRangeFacets().size()+areq.getQueryFacets().size();
- try {
- if( facets== 0 ){
- accumulator = BasicAccumulator.create(searcher, docs, areq);
- } else {
- accumulator = FacetingAccumulator.create(searcher, docs, areq, req);
- }
- } catch (IOException e) {
- log.warn("Analytics request '"+areq.getName()+"' failed", e);
- continue;
- }
-
- statsCollector.addStatsCollected(((BasicAccumulator)accumulator).getNumStatsCollectors());
- statsCollector.addStatsRequests(areq.getExpressions().size());
- statsCollector.addFieldFacets(areq.getFieldFacets().size());
- statsCollector.addRangeFacets(areq.getRangeFacets().size());
- statsCollector.addQueryFacets(areq.getQueryFacets().size());
- statsCollector.addQueries(((BasicAccumulator)accumulator).getNumQueries());
-
- // Loop through the documents returned by the query and add to accumulator
- List<LeafReaderContext> contexts = searcher.getTopReaderContext().leaves();
- for (int leafNum = 0; leafNum < contexts.size(); leafNum++) {
- LeafReaderContext context = contexts.get(leafNum);
- DocIdSet dis = filter.getDocIdSet(context, null); // solr docsets already exclude any deleted docs
- DocIdSetIterator disi = null;
- if (dis != null) {
- disi = dis.iterator();
- }
-
- if (disi != null) {
- accumulator.getLeafCollector(context);
- int doc = disi.nextDoc();
- while( doc != DocIdSetIterator.NO_MORE_DOCS){
- // Add a document to the statistics being generated
- accumulator.collect(doc);
- doc = disi.nextDoc();
- }
- }
- }
-
- // do some post-processing
- accumulator.postProcess();
-
- // compute the stats
- accumulator.compute();
-
- res.add(areq.getName(),accumulator.export());
- }
-
- statsCollector.endRequest();
- return res;
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/ExpressionRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/ExpressionRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/ExpressionRequest.java
deleted file mode 100644
index a833c80..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/ExpressionRequest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.analytics.request;
-
-import org.apache.solr.analytics.expression.Expression;
-
-/**
- * Contains name and string representation of an expression.
- */
-public class ExpressionRequest implements Comparable<ExpressionRequest> {
- private String name;
- private String expressionString;
- private Expression expression;
-
- /**
- * @param name The name of the Expression.
- * @param expressionString The string representation of the desired Expression.
- */
- public ExpressionRequest(String name, String expressionString) {
- this.name = name;
- this.expressionString = expressionString;
- }
-
- public void setExpressionString(String expressionString) {
- this.expressionString = expressionString;
- }
-
- public String getExpressionString() {
- return expressionString;
- }
-
- public void setExpression(Expression expression) {
- this.expression = expression;
- }
-
- public Expression getExpression() {
- return expression;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public int compareTo(ExpressionRequest o) {
- return name.compareTo(o.getName());
- }
-
- @Override
- public String toString() {
- return "<ExpressionRequest name=" + name + " expression=" + expressionString + "/>";
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FacetRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FacetRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FacetRequest.java
deleted file mode 100644
index 936af72..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FacetRequest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.analytics.request;
-
-public interface FacetRequest {
-
- /**
- * Get the name of this facet (commonly the field name)
- * @return the name
- */
- String getName();
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FieldFacetRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FieldFacetRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FieldFacetRequest.java
deleted file mode 100644
index 67d93da..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/FieldFacetRequest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.analytics.request;
-
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.schema.SchemaField;
-
-import java.util.Locale;
-
-
-/**
- * Contains all of the specifications for a field facet.
- */
-public class FieldFacetRequest extends AbstractFieldFacetRequest {
-
- private FacetSortSpecification sort = null;
- private FacetSortDirection dir = null;
- private int limit;
- private int offset;
- private boolean missing;
- private boolean hidden;
-
-
- public static enum FacetSortDirection {
- ASCENDING ,
- DESCENDING;
-
- public static FacetSortDirection fromExternal(String value){
- final String sort = value.toLowerCase(Locale.ROOT);
- if( "asc".equals(sort) ) return ASCENDING;
- if( "ascending".equals(sort) ) return ASCENDING;
- if( "desc".equals(sort) ) return DESCENDING;
- if( "descending".equals(sort) ) return DESCENDING;
- return Enum.valueOf(FacetSortDirection.class, value);
- }
- }
-
- /**
- * Specifies how to sort the buckets of a field facet.
- *
- */
- public static class FacetSortSpecification {
- private String statistic;
- private FacetSortDirection direction = FacetSortDirection.DESCENDING;
-
- public FacetSortSpecification(){}
-
- /**
- * @param statistic The name of a statistic specified in the {@link AnalyticsRequest}
- * which is wrapping the {@link FieldFacetRequest} being sorted.
- */
- public FacetSortSpecification(String statistic) {
- this.statistic = statistic;
- }
-
- public FacetSortSpecification(String statistic, FacetSortDirection direction) {
- this(statistic);
- this.direction = direction;
- }
-
- public String getStatistic() {
- return statistic;
- }
- public void setStatistic(String statistic) {
- this.statistic = statistic;
- }
- public FacetSortDirection getDirection() {
- return direction;
- }
- public void setDirection(FacetSortDirection direction) {
- this.direction = direction;
- }
-
- public static FacetSortSpecification fromExternal(String spec){
- String[] parts = spec.split(" ",2);
- if( parts.length == 1 ){
- return new FacetSortSpecification(parts[0]);
- } else {
- return new FacetSortSpecification(parts[0], FacetSortDirection.fromExternal(parts[1]));
- }
- }
-
- @Override
- public String toString() {
- return "<SortSpec stat=" + statistic + " dir=" + direction + ">";
- }
- }
-
- public FieldFacetRequest(SchemaField field) {
- super(field);
- this.limit = AnalyticsParams.DEFAULT_LIMIT;
- this.hidden = AnalyticsParams.DEFAULT_HIDDEN;
- }
-
- public FacetSortDirection getDirection() {
- return dir;
- }
-
- public void setDirection(String dir) {
- this.dir = FacetSortDirection.fromExternal(dir);
- if (sort!=null) {
- sort.setDirection(this.dir);
- }
- }
-
- public FacetSortSpecification getSort() {
- return sort;
- }
-
- public void setSort(FacetSortSpecification sort) {
- this.sort = sort;
- }
-
- public boolean showsMissing() {
- return missing;
- }
-
- /**
- * If there are missing values in the facet field, include the bucket
- * for the missing facet values in the facet response.
- * @param missing true/false if we calculate missing
- */
- public void showMissing(boolean missing) {
- this.missing = missing;
- }
-
- public int getLimit() {
- return limit;
- }
-
- public void setLimit(int limit) {
- this.limit = limit;
- }
-
- public int getOffset() {
- return offset;
- }
-
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- public boolean isHidden() {
- return hidden;
- }
-
- public void setHidden(boolean hidden) {
- this.hidden = hidden;
- }
-
- @Override
- public String toString() {
- return "<FieldFacetRequest field="+field.getName()+(sort==null?"":" sort=" + sort) + " limit=" + limit+" offset="+offset+">";
- }
-
-
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/QueryFacetRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/QueryFacetRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/QueryFacetRequest.java
deleted file mode 100644
index fbe34db..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/QueryFacetRequest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Contains all of the specifications for a query facet.
- */
-public class QueryFacetRequest implements FacetRequest {
- private String name;
- private List<String> queries;
- private Set<String> dependencies;
-
- public QueryFacetRequest() {
- dependencies = new HashSet<>();
- }
-
- public QueryFacetRequest(String name) {
- this.name = name;
- this.queries = new ArrayList<>();
- dependencies = new HashSet<>();
- }
-
- public List<String> getQueries() {
- return queries;
- }
-
- public void setQueries(List<String> queries) {
- this.queries = queries;
- }
-
- public void addQuery(String query) {
- queries.add(query);
- }
-
- public Set<String> getDependencies() {
- return dependencies;
- }
-
- public void setDependencies(Set<String> dependencies) {
- this.dependencies = dependencies;
- }
-
- public void addDependency(String dependency) {
- dependencies.add(dependency);
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/RangeFacetRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/RangeFacetRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/RangeFacetRequest.java
deleted file mode 100644
index ec9cf6b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/RangeFacetRequest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.util.Arrays;
-import java.util.EnumSet;
-
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
-import org.apache.solr.common.params.FacetParams.FacetRangeOther;
-import org.apache.solr.schema.SchemaField;
-
-/**
- * Contains all of the specifications for a range facet.
- */
-public class RangeFacetRequest extends AbstractFieldFacetRequest {
- protected String start;
- protected String end;
- protected String[] gaps;
- protected boolean hardEnd = false;
- protected EnumSet<FacetRangeInclude> include;
- protected boolean includeCalled = false;
- protected EnumSet<FacetRangeOther> others;
- protected boolean othersCalled = false;
-
- public RangeFacetRequest(SchemaField field) {
- super(field);
- include = EnumSet.of(AnalyticsParams.DEFAULT_INCLUDE);
- others = EnumSet.of(AnalyticsParams.DEFAULT_OTHER);
- }
-
- public RangeFacetRequest(SchemaField field, String start, String end, String[] gaps) {
- super(field);
- this.start = start;
- this.end = end;
- this.gaps = gaps;
- }
-
- public String getStart() {
- return start;
- }
-
- public void setStart(String start) {
- this.start = start;
- }
-
- public String getEnd() {
- return end;
- }
-
- public void setEnd(String end) {
- this.end = end;
- }
-
- public EnumSet<FacetRangeInclude> getInclude() {
- return include;
- }
-
- public void setInclude(EnumSet<FacetRangeInclude> include) {
- includeCalled = true;
- this.include = include;
- }
-
- public void addInclude(FacetRangeInclude include) {
- if (includeCalled) {
- this.include.add(include);
- } else {
- includeCalled = true;
- this.include = EnumSet.of(include);
- }
- }
-
- public String[] getGaps() {
- return gaps;
- }
-
- public void setGaps(String[] gaps) {
- this.gaps = gaps;
- }
-
- public boolean isHardEnd() {
- return hardEnd;
- }
-
- public void setHardEnd(boolean hardEnd) {
- this.hardEnd = hardEnd;
- }
-
- public EnumSet<FacetRangeOther> getOthers() {
- return others;
- }
-
- public void setOthers(EnumSet<FacetRangeOther> others) {
- othersCalled = true;
- this.others = others;
- }
-
- public void addOther(FacetRangeOther other) {
- if (othersCalled) {
- this.others.add(other);
- } else {
- othersCalled = true;
- this.others = EnumSet.of(other);
- }
- }
-
- @Override
- public String toString() {
- return "<RangeFacetRequest field="+field.getName() + " start=" + start + ", end=" + end + ", gap=" + Arrays.toString(gaps) + ", hardEnd=" + hardEnd +
- ", include=" + include + ", others=" + others +">";
- }
-
-
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/package-info.java
deleted file mode 100644
index de2feb3..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Request objects for creating Analytics requests
- */
-package org.apache.solr.analytics.request;
-
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/AbstractDelegatingStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/AbstractDelegatingStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/AbstractDelegatingStatsCollector.java
deleted file mode 100644
index 92969f1..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/AbstractDelegatingStatsCollector.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.Set;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.util.mutable.MutableValue;
-
-/**
- * <code>AbstractDelegationStatsCollector</code> objects wrap other StatsCollectors.
- * While they compute their own statistics they pass along all inputs and requests
- * to the delegates as well.
- */
-public abstract class AbstractDelegatingStatsCollector implements StatsCollector{
- protected final StatsCollector delegate;
- protected final Set<String> statsList;
- MutableValue value;
- FunctionValues function;
-
- /**
- * @param delegate The delegate computing statistics on the same set of values.
- */
- public AbstractDelegatingStatsCollector(StatsCollector delegate) {
- this.delegate = delegate;
- this.statsList = delegate.getStatsList();
- }
-
- public void setNextReader(LeafReaderContext context) throws IOException {
- delegate.setNextReader(context);
- value = getValue();
- function = getFunction();
- }
-
- public StatsCollector delegate(){
- return delegate;
- }
-
- public Set<String> getStatsList(){
- return statsList;
- }
-
- public MutableValue getValue() {
- return delegate.getValue();
- }
-
- public FunctionValues getFunction() {
- return delegate.getFunction();
- }
-
- public void collect(int doc) throws IOException {
- delegate.collect(doc);
- }
-
- public String valueSourceString() {
- return delegate.valueSourceString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MedianStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MedianStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MedianStatsCollector.java
deleted file mode 100644
index bf71429..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MedianStatsCollector.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.solr.analytics.util.MedianCalculator;
-
-/**
- * <code>MedianStatsCollector</code> computes the median.
- */
-public class MedianStatsCollector extends AbstractDelegatingStatsCollector{
-
- private final List<Double> values = new ArrayList<>();
- protected double median;
-
- public MedianStatsCollector(StatsCollector delegate) {
- super(delegate);
- }
-
- public Double getMedian() {
- return new Double(MedianCalculator.getMedian(values));
- }
-
- @Override
- public Comparable getStat(String stat) {
- if (stat.equals("median")) {
- return new Double(median);
- }
- return delegate.getStat(stat);
- }
-
- public void compute(){
- delegate.compute();
- median = getMedian();
- }
-
- @Override
- public void collect(int doc) throws IOException {
- super.collect(doc);
- if (value.exists) {
- values.add(function.doubleVal(doc));
- }
- }
-}
-class DateMedianStatsCollector extends MedianStatsCollector{
-
- public DateMedianStatsCollector(StatsCollector delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getStat(String stat) {
- if (stat.equals("median")) {
- return new Date((long)median);
- }
- return delegate.getStat(stat);
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MinMaxStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MinMaxStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MinMaxStatsCollector.java
deleted file mode 100644
index c21b045..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/MinMaxStatsCollector.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.Set;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.FunctionValues.ValueFiller;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.util.mutable.MutableValue;
-
-/**
- * <code>MinMaxStatsCollector</code> computes the min, max, number of values and number of missing values.
- */
-public class MinMaxStatsCollector implements StatsCollector{
- protected long missingCount = 0;
- protected long valueCount = 0;
- protected MutableValue max;
- protected MutableValue min;
- protected MutableValue value;
- protected final Set<String> statsList;
- protected final ValueSource source;
- protected FunctionValues function;
- protected ValueFiller valueFiller;
-
- public MinMaxStatsCollector(ValueSource source, Set<String> statsList) {
- this.source = source;
- this.statsList = statsList;
- }
-
- public void setNextReader(LeafReaderContext context) throws IOException {
- function = source.getValues(null, context);
- valueFiller = function.getValueFiller();
- value = valueFiller.getValue();
- }
-
- public void collect(int doc) throws IOException {
- valueFiller.fillValue(doc);
- if( value.exists ){
- valueCount += 1;
- if ( max==null ) max = value.duplicate();
- else if( !max.exists || value.compareTo(max) > 0 ) max.copy(value);
- if ( min==null ) min = value.duplicate();
- else if( !min.exists || value.compareTo(min) < 0 ) min.copy(value);
- } else {
- missingCount += 1;
- }
- }
-
- @Override
- public String toString() {
- return String.format(Locale.ROOT, "<min=%s max=%s c=%d m=%d>", min, max, valueCount, missingCount );
- }
-
- public Comparable getStat(String stat){
- if (stat.equals("min")&&min!=null) {
- return (Comparable)min.toObject();
- }
- if (stat.equals("max")&&max!=null) {
- return (Comparable)max.toObject();
- }
- if (stat.equals("count")) {
- return new Long(valueCount);
- }
- if (stat.equals("missing")) {
- return new Long(missingCount);
- }
-
- return null;
-// throw new IllegalArgumentException("No stat named '"+stat+"' in this collector " + this);
- }
-
- public Set<String> getStatsList() {
- return statsList;
- }
-
- @Override
- public void compute() { }
-
- @Override
- public MutableValue getValue() {
- return value;
- }
-
- @Override
- public FunctionValues getFunction() {
- return function;
- }
-
- public String valueSourceString() {
- return source.toString();
- }
-
- public String statString(String stat) {
- return stat+"("+valueSourceString()+")";
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/NumericStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/NumericStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/NumericStatsCollector.java
deleted file mode 100644
index 1f22baa..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/NumericStatsCollector.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.Set;
-
-import org.apache.lucene.queries.function.ValueSource;
-
-/**
- * <code>NumericStatsCollector</code> computes the sum, sum of squares, mean and standard deviation.
- */
-public class NumericStatsCollector extends MinMaxStatsCollector {
- protected double sum = 0;
- protected double sumOfSquares = 0;
- protected double mean = 0;
- protected double stddev = 0;
-
- public NumericStatsCollector(ValueSource source, Set<String> statsList) {
- super(source, statsList);
- }
-
- public void collect(int doc) throws IOException {
- super.collect(doc);
- double value = function.doubleVal(doc);
- sum += value;
- sumOfSquares += (value * value);
- }
-
- @Override
- public Comparable getStat(String stat) {
- if (stat.equals("sum")) {
- return new Double(sum);
- }
- if (stat.equals("sumofsquares")) {
- return new Double(sumOfSquares);
- }
- if (stat.equals("mean")) {
- return new Double(mean);
- }
- if (stat.equals("stddev")) {
- return new Double(stddev);
- }
- return super.getStat(stat);
- }
-
- @Override
- public void compute(){
- super.compute();
- mean = (valueCount==0)? 0:sum / valueCount;
- stddev = (valueCount <= 1) ? 0.0D : Math.sqrt((sumOfSquares/valueCount) - (mean*mean));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/PercentileStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/PercentileStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/PercentileStatsCollector.java
deleted file mode 100644
index e12cb83..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/PercentileStatsCollector.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.apache.solr.analytics.util.PercentileCalculator;
-
-import com.google.common.collect.Iterables;
-
-/**
- * <code>PercentileStatsCollector</code> computes a given list of percentiles.
- */
-@SuppressWarnings("rawtypes")
-public class PercentileStatsCollector extends AbstractDelegatingStatsCollector{
- public final List<Comparable> values = new ArrayList<>();
- public static final Pattern PERCENTILE_PATTERN = Pattern.compile("perc(?:entile)?_(\\d+)",Pattern.CASE_INSENSITIVE);
- protected final double[] percentiles;
- protected final String[] percentileNames;
- protected Comparable[] results;
-
- public PercentileStatsCollector(StatsCollector delegate, double[] percentiles, String[] percentileNames) {
- super(delegate);
- this.percentiles = percentiles;
- this.percentileNames = percentileNames;
- }
-
- @Override
- public Comparable getStat(String stat) {
- for( int i=0; i < percentiles.length; i++ ){
- if (stat.equals(percentileNames[i])) {
- if (results!=null) {
- return results[i];
- } else {
- return null;
- }
- }
- }
- return delegate.getStat(stat);
- }
-
- public void compute(){
- delegate.compute();
- if (values.size()>0) {
- results = Iterables.toArray(getPercentiles(),Comparable.class);
- } else {
- results = null;
- }
- }
-
- @SuppressWarnings({ "unchecked"})
- protected List<Comparable> getPercentiles() {
- return PercentileCalculator.getPercentiles(values, percentiles);
- }
-
- public void collect(int doc) throws IOException {
- super.collect(doc);
- if (value.exists) {
- values.add((Comparable)value.toObject());
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollector.java
deleted file mode 100644
index 039300f..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.Set;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.util.mutable.MutableValue;
-
-/**
- * <code>StatsCollector</code> implementations reduce a list of Objects to a single value.
- * Most implementations reduce a list to a statistic on that list.
- */
-public interface StatsCollector {
-
- /**
- * Collect values from the value source and add to statistics.
- * @param doc Document to collect from
- */
- void collect(int doc) throws IOException;
-
- /**
- * @param context The context to read documents from.
- * @throws IOException if setting next reader fails
- */
- void setNextReader(LeafReaderContext context) throws IOException;
-
- MutableValue getValue();
- FunctionValues getFunction();
-
- /**
- * @return The set of statistics being computed by the stats collector.
- */
- Set<String> getStatsList();
-
- /**
- * Return the value of the given statistic.
- * @param stat the stat
- * @return a comparable
- */
- Comparable getStat(String stat);
-
- /**
- * After all documents have been collected, this method should be
- * called to finalize the calculations of each statistic.
- */
- void compute();
-
- /**
- * @return The string representation of the value source.
- */
- String valueSourceString();
-}
[07/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataArrayWriter.java
new file mode 100644
index 0000000..12fc86e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataArrayWriter.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.solr.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+
+public class LongDataArrayWriter extends ReductionDataArrayWriter<LongSupplier> {
+
+ public LongDataArrayWriter(DataOutput output, LongSupplier extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeLong(extractor.getAsLong());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataWriter.java
new file mode 100644
index 0000000..3b8af52
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongDataWriter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.LongSupplier;
+
+public class LongDataWriter extends ReductionDataWriter<LongSupplier> {
+
+ public LongDataWriter(DataOutput output, LongSupplier extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ output.writeLong(extractor.getAsLong());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionCheckedDataWriter.java
new file mode 100644
index 0000000..a5a2273
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionCheckedDataWriter.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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+
+/**
+ * Abstract class to manage the extraction and writing of data to a {@link DataOutput} stream.
+ * The data being written may not exist, so the writer first writes whether the data exists before writing the data.
+ */
+public abstract class ReductionCheckedDataWriter<C> extends ReductionDataWriter<C> {
+ private final BooleanSupplier existsSupplier;
+
+ public ReductionCheckedDataWriter(DataOutput output, C extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor);
+
+ this.existsSupplier = existsSupplier;
+ }
+
+ /**
+ * Write a piece of data, retrieved from the extractor, to the output stream.
+ * <br>
+ * First writes whether the data exists, then if it does exists writes the data.
+ *
+ * @throws IOException if an exception occurs while writing to the output stream
+ */
+ @Override
+ public void write() throws IOException {
+ boolean exists = existsSupplier.getAsBoolean();
+ output.writeBoolean(exists);
+ if (exists) {
+ checkedWrite();
+ }
+ }
+
+ /**
+ * Write a piece of data, retrieved from the extractor, to the output stream.
+ * <br>
+ * The data being written is guaranteed to exist.
+ *
+ * @throws IOException if an exception occurs while writing to the output stream
+ */
+ protected abstract void checkedWrite() throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataArrayWriter.java
new file mode 100644
index 0000000..29ba77e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataArrayWriter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+
+/**
+ * Abstract class to manage the extraction and writing of array data to a {@link DataOutput} stream.
+ */
+public abstract class ReductionDataArrayWriter<C> extends ReductionDataWriter<C> {
+ private final IntSupplier sizeSupplier;
+
+ public ReductionDataArrayWriter(DataOutput output, C extractor, IntSupplier sizeSupplier) {
+ super(output, extractor);
+
+ this.sizeSupplier = sizeSupplier;
+ }
+
+ /**
+ * Write an array of data, retrieved from the extractor, and its size, received from the sizeSupplier, to the output stream.
+ *
+ * @throws IOException if an exception occurs while writing to the output stream
+ */
+ @Override
+ public void write() throws IOException {
+ int size = sizeSupplier.getAsInt();
+ output.writeInt(size);
+ write(size);
+ }
+
+ /**
+ * Write an array of data, retrieved from the extractor, with the given size to the output stream.
+ *
+ * @throws IOException if an exception occurs while writing to the output stream
+ */
+ protected abstract void write(int size) throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataWriter.java
new file mode 100644
index 0000000..504a2be
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/ReductionDataWriter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * Abstract public class to manage the extraction and writing of data to a {@link DataOutput} stream.
+ */
+public abstract class ReductionDataWriter<E> {
+ protected final DataOutput output;
+ protected final E extractor;
+
+ public ReductionDataWriter(DataOutput output, E extractor) {
+ this.output = output;
+ this.extractor = extractor;
+ }
+
+ /**
+ * Write a piece of data, retrieved from the extractor, to the output stream.
+ *
+ * @throws IOException if an exception occurs while writing to the output stream
+ */
+ public abstract void write() throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringCheckedDataWriter.java
new file mode 100644
index 0000000..6560a8f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringCheckedDataWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+import java.util.function.Supplier;
+
+public class StringCheckedDataWriter extends ReductionCheckedDataWriter<Supplier<String>> {
+
+ public StringCheckedDataWriter(DataOutput output, Supplier<String> extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeUTF(extractor.get());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataArrayWriter.java
new file mode 100644
index 0000000..18c71d1
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataArrayWriter.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.solr.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+
+public class StringDataArrayWriter extends ReductionDataArrayWriter<Supplier<String>> {
+
+ public StringDataArrayWriter(DataOutput output, Supplier<String> extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeUTF(extractor.get());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataWriter.java
new file mode 100644
index 0000000..4aac07c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/StringDataWriter.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.Supplier;
+
+public class StringDataWriter extends ReductionDataWriter<Supplier<String>> {
+
+ public StringDataWriter(DataOutput output, Supplier<String> extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ String temp = extractor.get();
+ output.writeBoolean(temp != null);
+ if (temp != null) {
+ output.writeUTF(temp);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/package-info.java
new file mode 100644
index 0000000..53a5168
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Writing classes for a single type of data being stored by one Reduction Data Collector.
+ * These writers are used to export data between shards during the streaming process.
+ */
+package org.apache.solr.analytics.stream.reservation.write;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParams.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParams.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParams.java
deleted file mode 100644
index f6716ff..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParams.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.analytics.util;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
-import org.apache.solr.common.params.FacetParams.FacetRangeOther;
-import org.apache.solr.search.function.ConcatStringFunction;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-public interface AnalyticsParams {
- // Full length Analytics Params
- public static final String ANALYTICS = "olap";
-
- public static final String REQUEST = "o|olap";
-
- public static final String EXPRESSION = "s|stat|statistic";
- public static final String HIDDEN_EXPRESSION = "hs|hiddenstat|hiddenstatistic";
-
- public static final String FIELD_FACET = "ff|fieldfacet";
- public static final String LIMIT = "l|limit";
- public static final String OFFSET = "off|offset";
- public static final String HIDDEN = "h|hidden";
- public static final String SHOW_MISSING = "sm|showmissing";
- public static final String SORT_STATISTIC ="ss|sortstat|sortstatistic";
- public static final String SORT_DIRECTION ="sd|sortdirection";
-
- public static final String RANGE_FACET = "rf|rangefacet";
- public static final String START = "st|start";
- public static final String END = "e|end";
- public static final String GAP = "g|gap";
- public static final String HARDEND = "he|hardend";
- public static final String INCLUDE_BOUNDARY = "ib|includebound";
- public static final String OTHER_RANGE = "or|otherrange";
-
- public static final String QUERY_FACET = "qf|queryfacet";
- public static final String DEPENDENCY = "d|dependecy";
- public static final String QUERY = "q|query";
-
- //Defaults
- public static final boolean DEFAULT_ABBREVIATE_PREFIX = true;
- public static final String DEFAULT_SORT_DIRECTION = "ascending";
- public static final int DEFAULT_LIMIT = -1;
- public static final boolean DEFAULT_HIDDEN = false;
- public static final boolean DEFAULT_HARDEND = false;
- public static final boolean DEFAULT_SHOW_MISSING = false;
- public static final FacetRangeInclude DEFAULT_INCLUDE = FacetRangeInclude.LOWER;
- public static final FacetRangeOther DEFAULT_OTHER = FacetRangeOther.NONE;
-
- // Statistic Function Names (Cannot share names with ValueSource & Expression Functions)
- public static final String STAT_COUNT = "count";
- public static final String STAT_MISSING = "missing";
- public static final String STAT_SUM = "sum";
- public static final String STAT_SUM_OF_SQUARES = "sumofsquares";
- public static final String STAT_STANDARD_DEVIATION = "stddev";
- public static final String STAT_MEAN = "mean";
- public static final String STAT_UNIQUE = "unique";
- public static final String STAT_MEDIAN = "median";
- public static final String STAT_PERCENTILE = "percentile";
- public static final String STAT_MIN = "min";
- public static final String STAT_MAX = "max";
-
- public static final List<String> ALL_STAT_LIST = Collections.unmodifiableList(Lists.newArrayList(STAT_COUNT, STAT_MISSING, STAT_SUM, STAT_SUM_OF_SQUARES, STAT_STANDARD_DEVIATION, STAT_MEAN, STAT_UNIQUE, STAT_MEDIAN, STAT_PERCENTILE,STAT_MIN,STAT_MAX));
- public static final Set<String> ALL_STAT_SET = Collections.unmodifiableSet(Sets.newLinkedHashSet(ALL_STAT_LIST));
-
- // ValueSource & Expression Function Names (Cannot share names with Statistic Functions)
- // No specific type
- final static String FILTER = "filter";
- final static String RESULT = "result";
- final static String QUERY_RESULT = "qresult";
-
- // Numbers
- final static String CONSTANT_NUMBER = "const_num";
- final static String NEGATE = "neg";
- final static String ABSOLUTE_VALUE = "abs";
- final static String LOG = "log";
- final static String ADD = "add";
- final static String MULTIPLY = "mult";
- final static String DIVIDE = "div";
- final static String POWER = "pow";
- public static final Set<String> NUMERIC_OPERATION_SET = Collections.unmodifiableSet(Sets.newLinkedHashSet(Lists.newArrayList(CONSTANT_NUMBER,NEGATE,ABSOLUTE_VALUE,LOG,ADD,MULTIPLY,DIVIDE,POWER)));
-
- // Dates
- final static String CONSTANT_DATE = "const_date";
- final static String DATE_MATH = "date_math";
- public static final Set<String> DATE_OPERATION_SET = Collections.unmodifiableSet(Sets.newLinkedHashSet(Lists.newArrayList(CONSTANT_DATE,DATE_MATH)));
-
- //Strings
- final static String CONSTANT_STRING = "const_str";
- final static String REVERSE = "rev";
- final static String CONCATENATE = ConcatStringFunction.NAME;
- public static final Set<String> STRING_OPERATION_SET = Collections.unmodifiableSet(Sets.newLinkedHashSet(Lists.newArrayList(CONSTANT_STRING,REVERSE,CONCATENATE)));
-
- // Field Source Wrappers
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParsers.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParsers.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParsers.java
deleted file mode 100644
index dd64c3f..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsParsers.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.analytics.util;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Arrays;
-
-import org.apache.solr.legacy.LegacyNumericUtils;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.NumericUtils;
-import org.apache.solr.schema.FieldType;
-import org.apache.solr.schema.TrieDateField;
-import org.apache.solr.schema.TrieDoubleField;
-import org.apache.solr.schema.TrieFloatField;
-import org.apache.solr.schema.TrieIntField;
-import org.apache.solr.schema.TrieLongField;
-
-/**
- * Class to hold the parsers used for Solr Analytics.
- */
-public class AnalyticsParsers {
-
- /**
- * Returns a parser that will translate a BytesRef or long from DocValues into
- * a String that correctly represents the value.
- * @param class1 class of the FieldType of the field being faceted on.
- * @return A Parser
- */
- public static Parser getParser(Class<? extends FieldType> class1) {
- if (class1.equals(TrieIntField.class)) {
- return AnalyticsParsers.INT_DOC_VALUES_PARSER;
- } else if (class1.equals(TrieLongField.class)) {
- return AnalyticsParsers.LONG_DOC_VALUES_PARSER;
- } else if (class1.equals(TrieFloatField.class)) {
- return AnalyticsParsers.FLOAT_DOC_VALUES_PARSER;
- } else if (class1.equals(TrieDoubleField.class)) {
- return AnalyticsParsers.DOUBLE_DOC_VALUES_PARSER;
- } else if (class1.equals(TrieDateField.class)) {
- return AnalyticsParsers.DATE_DOC_VALUES_PARSER;
- } else {
- return AnalyticsParsers.STRING_PARSER;
- }
- }
-
- /**
- * For use in classes that grab values by docValue.
- * Converts a BytesRef object into the correct readable text.
- */
- public static interface Parser {
- String parse(BytesRef bytes) throws IOException;
- }
-
- /**
- * Converts the long returned by NumericDocValues into the
- * correct number and return it as a string.
- */
- public static interface NumericParser extends Parser {
- String parseNum(long l);
- }
-
- /**
- * Converts the BytesRef or long to the correct int string.
- */
- public static final NumericParser INT_DOC_VALUES_PARSER = new NumericParser() {
- public String parse(BytesRef bytes) throws IOException {
- try {
- return ""+ LegacyNumericUtils.prefixCodedToInt(bytes);
- } catch (NumberFormatException e) {
- throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to an int.");
- }
- }
- @Override
- public String parseNum(long l) {
- return ""+(int)l;
- }
- };
-
- /**
- * Converts the BytesRef or long to the correct long string.
- */
- public static final NumericParser LONG_DOC_VALUES_PARSER = new NumericParser() {
- public String parse(BytesRef bytes) throws IOException {
- try {
- return ""+ LegacyNumericUtils.prefixCodedToLong(bytes);
- } catch (NumberFormatException e) {
- throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a long.");
- }
- }
- @Override
- public String parseNum(long l) {
- return ""+l;
- }
- };
-
- /**
- * Converts the BytesRef or long to the correct float string.
- */
- public static final NumericParser FLOAT_DOC_VALUES_PARSER = new NumericParser() {
- public String parse(BytesRef bytes) throws IOException {
- try {
- return ""+ NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(bytes));
- } catch (NumberFormatException e) {
- throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a float.");
- }
- }
- @Override
- public String parseNum(long l) {
- return ""+ NumericUtils.sortableIntToFloat((int) l);
- }
- };
-
- /**
- * Converts the BytesRef or long to the correct double string.
- */
- public static final NumericParser DOUBLE_DOC_VALUES_PARSER = new NumericParser() {
- public String parse(BytesRef bytes) throws IOException {
- try {
- return ""+ NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(bytes));
- } catch (NumberFormatException e) {
- throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a double.");
- }
- }
- @Override
- public String parseNum(long l) {
- return ""+ NumericUtils.sortableLongToDouble(l);
- }
- };
-
- /**
- * Converts the BytesRef or long to the correct date string.
- */
- public static final NumericParser DATE_DOC_VALUES_PARSER = new NumericParser() {
- @SuppressWarnings("deprecation")
- public String parse(BytesRef bytes) throws IOException {
- try {
- return Instant.ofEpochMilli(LegacyNumericUtils.prefixCodedToLong(bytes)).toString();
- } catch (NumberFormatException e) {
- throw new IOException("The byte array "+Arrays.toString(bytes.bytes)+" cannot be converted to a date.");
- }
- }
- @SuppressWarnings("deprecation")
- @Override
- public String parseNum(long l) {
- return Instant.ofEpochMilli(l).toString();
- }
- };
-
- /**
- * Converts the BytesRef to the correct string.
- */
- public static final Parser STRING_PARSER = new Parser() {
- public String parse(BytesRef bytes) {
- return bytes.utf8ToString();
- }
- };
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsResponseHeadings.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsResponseHeadings.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsResponseHeadings.java
new file mode 100644
index 0000000..00e0afb
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/AnalyticsResponseHeadings.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.solr.analytics.util;
+
+/**
+ * Holds the headers for analytics responses.
+ */
+public class AnalyticsResponseHeadings {
+
+ public static final String COMPLETED_HEADER = "analytics_response";
+ public static final String RESULTS = "results";
+ public static final String GROUPINGS = "groupings";
+ public static final String FACET_VALUE = "value";
+ public static final String PIVOT_NAME = "pivot";
+ public static final String PIVOT_CHILDREN = "children";
+
+ // Old Olap-style
+ public static final String COMPLETED_OLD_HEADER = "stats";
+ public static final String FIELD_FACETS = "fieldFacets";
+ public static final String RANGE_FACETS = "rangeFacets";
+ public static final String QUERY_FACETS = "queryFacets";
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/FacetRangeGenerator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/FacetRangeGenerator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/FacetRangeGenerator.java
new file mode 100644
index 0000000..0576096
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/FacetRangeGenerator.java
@@ -0,0 +1,356 @@
+/*
+ * 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.analytics.util;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.solr.analytics.facet.RangeFacet;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
+import org.apache.solr.common.params.FacetParams.FacetRangeOther;
+import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.TrieDateField;
+import org.apache.solr.schema.TrieField;
+import org.apache.solr.util.DateMathParser;
+
+
+/**
+ * Calculates a set of {@link FacetRange}s for a given {@link RangeFacet}.
+ */
+public abstract class FacetRangeGenerator<T extends Comparable<T>> {
+ protected final SchemaField field;
+ protected final RangeFacet rangeFacet;
+
+ public FacetRangeGenerator(final RangeFacet rangeFacet) {
+ this.field = rangeFacet.getField();
+ this.rangeFacet = rangeFacet;
+ }
+
+ /**
+ * Formats a Range endpoint for use as a range label name in the response.
+ * Default Impl just uses toString()
+ */
+ public String formatValue(final T val) {
+ return val.toString();
+ }
+
+ /**
+ * Parses a String param into an Range endpoint value throwing
+ * a useful exception if not possible
+ */
+ public final T getValue(final String rawval) {
+ try {
+ return parseVal(rawval);
+ } catch (Exception e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse value "+rawval+" for field: " + field.getName(), e);
+ }
+ }
+
+ /**
+ * Parses a String param into an Range endpoint.
+ * Can throw a low level format exception as needed.
+ */
+ protected abstract T parseVal(final String rawval) throws java.text.ParseException;
+
+ /**
+ * Parses a String param into a value that represents the gap and
+ * can be included in the response, throwing
+ * a useful exception if not possible.
+ *
+ * Note: uses Object as the return type instead of T for things like
+ * Date where gap is just a DateMathParser string
+ */
+ public final Object getGap(final String gap) {
+ try {
+ return parseGap(gap);
+ } catch (Exception e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse gap "+gap+" for field: " + field.getName(), e);
+ }
+ }
+
+ /**
+ * Parses a String param into a value that represents the gap and
+ * can be included in the response.
+ * Can throw a low level format exception as needed.
+ *
+ * Default Impl calls parseVal
+ */
+ protected Object parseGap(final String rawval) throws java.text.ParseException {
+ return parseVal(rawval);
+ }
+
+ /**
+ * Adds the String gap param to a low Range endpoint value to determine
+ * the corrisponding high Range endpoint value, throwing
+ * a useful exception if not possible.
+ */
+ public final T addGap(T value, String gap) {
+ try {
+ return parseAndAddGap(value, gap);
+ } catch (Exception e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't add gap "+gap+" to value " + value + " for field: " + field.getName(), e);
+ }
+ }
+
+ /**
+ * Adds the String gap param to a low Range endpoint value to determine
+ * the corrisponding high Range endpoint value.
+ * Can throw a low level format exception as needed.
+ */
+ protected abstract T parseAndAddGap(T value, String gap) throws java.text.ParseException;
+
+ public static class FacetRange {
+ public final String name;
+ public final String lower;
+ public final String upper;
+ public final boolean includeLower;
+ public final boolean includeUpper;
+ private final String facetValue;
+
+ public FacetRange(String name, String lower, String upper, boolean includeLower, boolean includeUpper) {
+ this.name = name;
+ this.lower = lower;
+ this.upper = upper;
+ this.includeLower = includeLower;
+ this.includeUpper = includeUpper;
+
+ String value = "(*";
+ if (lower != null) {
+ value = (includeLower ? "[" : "(") + lower;
+ }
+ value += " TO ";
+ if (upper == null) {
+ value += "*)";
+ } else {
+ value += upper + (includeUpper? "]" : ")");
+ }
+ facetValue = value;
+ }
+
+ @Override
+ public String toString() {
+ return facetValue;
+ }
+ }
+
+ public List<FacetRange> getRanges(){
+
+ final T start = getValue(rangeFacet.getStart());
+ T end = getValue(rangeFacet.getEnd()); // not final, hardend may change this
+
+ if( end.compareTo(start) < 0 ){
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "range facet 'end' comes before 'start': "+end+" < "+start);
+ }
+
+ // explicitly return the gap. compute this early so we are more
+ // likely to catch parse errors before attempting math
+ final List<String> gaps = rangeFacet.getGaps();
+ String gap = gaps.get(0);
+
+ final EnumSet<FacetRangeInclude> include = rangeFacet.getInclude();
+
+ T low = start;
+
+ List<FacetRange> ranges = new ArrayList<>();
+
+ int gapCounter = 0;
+
+ while (low.compareTo(end) < 0) {
+ if (gapCounter<gaps.size()) {
+ gap = gaps.get(gapCounter++);
+ }
+ T high = addGap(low,gap);
+ if (end.compareTo(high) < 0) {
+ if (rangeFacet.isHardEnd()){
+ high = end;
+ } else {
+ end = high;
+ }
+ }
+
+ if (high.compareTo(low) < 0) {
+ throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "range facet infinite loop (is gap negative? did the math overflow?)");
+ }
+
+ if (high.compareTo(low) == 0) {
+ throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "range facet infinite loop: gap is either zero, or too small relative start/end and caused underflow: " + low + " + " + gap + " = " + high );
+ }
+
+ final boolean includeLower = (include.contains(FacetRangeInclude.ALL) ||
+ include.contains(FacetRangeInclude.LOWER) ||
+ (include.contains(FacetRangeInclude.EDGE) &&
+ 0 == low.compareTo(start)));
+ final boolean includeUpper = (include.contains(FacetRangeInclude.ALL) ||
+ include.contains(FacetRangeInclude.UPPER) ||
+ (include.contains(FacetRangeInclude.EDGE) &&
+ 0 == high.compareTo(end)));
+
+ final String lowS = formatValue(low);
+ final String highS = formatValue(high);
+
+ ranges.add( new FacetRange(lowS,lowS,highS,includeLower,includeUpper) );
+ low = high;
+ }
+
+ final Set<FacetRangeOther> others = rangeFacet.getOthers();
+ if (null != others && 0 < others.size() ) {
+
+ // no matter what other values are listed, we don't do
+ // anything if "none" is specified.
+ if( !others.contains(FacetRangeOther.NONE) ) {
+
+ boolean all = others.contains(FacetRangeOther.ALL);
+
+ if (all || others.contains(FacetRangeOther.BEFORE)) {
+ // include upper bound if "outer" or if first gap doesn't already include it
+ ranges.add( new FacetRange(FacetRangeOther.BEFORE.toString(),
+ null, formatValue(start), false, include.contains(FacetRangeInclude.OUTER) || include.contains(FacetRangeInclude.ALL) ||
+ !(include.contains(FacetRangeInclude.LOWER) || include.contains(FacetRangeInclude.EDGE)) ) );
+
+ }
+ if (all || others.contains(FacetRangeOther.AFTER)) {
+ // include lower bound if "outer" or if last gap doesn't already include it
+ ranges.add( new FacetRange(FacetRangeOther.AFTER.toString(),
+ formatValue(end), null, include.contains(FacetRangeInclude.OUTER) || include.contains(FacetRangeInclude.ALL) ||
+ !(include.contains(FacetRangeInclude.UPPER) || include.contains(FacetRangeInclude.EDGE)), false) );
+ }
+ if (all || others.contains(FacetRangeOther.BETWEEN)) {
+ ranges.add( new FacetRange(FacetRangeOther.BETWEEN.toString(), formatValue(start), formatValue(end),
+ include.contains(FacetRangeInclude.LOWER) || include.contains(FacetRangeInclude.EDGE) || include.contains(FacetRangeInclude.ALL),
+ include.contains(FacetRangeInclude.UPPER) || include.contains(FacetRangeInclude.EDGE) || include.contains(FacetRangeInclude.ALL)) );
+ }
+ }
+
+ }
+
+ return ranges;
+ }
+
+ public static FacetRangeGenerator<? extends Comparable<?>> create(RangeFacet rangeFacet){
+ final SchemaField sf = rangeFacet.getField();
+ final FieldType ft = sf.getType();
+ final FacetRangeGenerator<?> calc;
+ if (ft instanceof TrieField) {
+ switch (ft.getNumberType()) {
+ case FLOAT:
+ calc = new FloatFacetRangeGenerator(rangeFacet);
+ break;
+ case DOUBLE:
+ calc = new DoubleFacetRangeGenerator(rangeFacet);
+ break;
+ case INTEGER:
+ calc = new IntegerFacetRangeGenerator(rangeFacet);
+ break;
+ case LONG:
+ calc = new LongFacetRangeGenerator(rangeFacet);
+ break;
+ case DATE:
+ calc = new DateFacetRangeGenerator(rangeFacet, null);
+ break;
+ default:
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on tried field of unexpected type:" + sf.getName());
+ }
+ } else {
+ throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on field:" + sf);
+ }
+ return calc;
+ }
+}
+class IntegerFacetRangeGenerator extends FacetRangeGenerator<Integer> {
+ public IntegerFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }
+
+ @Override
+ protected Integer parseVal(String rawval) {
+ return Integer.valueOf(rawval);
+ }
+ @Override
+ public Integer parseAndAddGap(Integer value, String gap) {
+ return new Integer(value.intValue() + Integer.valueOf(gap).intValue());
+ }
+}
+class LongFacetRangeGenerator extends FacetRangeGenerator<Long> {
+ public LongFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }
+
+ @Override
+ protected Long parseVal(String rawval) {
+ return Long.valueOf(rawval);
+ }
+ @Override
+ public Long parseAndAddGap(Long value, String gap) {
+ return new Long(value.longValue() + Long.valueOf(gap).longValue());
+ }
+}
+
+class FloatFacetRangeGenerator extends FacetRangeGenerator<Float> {
+ public FloatFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }
+
+ @Override
+ protected Float parseVal(String rawval) {
+ return Float.valueOf(rawval);
+ }
+ @Override
+ public Float parseAndAddGap(Float value, String gap) {
+ return new Float(value.floatValue() + Float.valueOf(gap).floatValue());
+ }
+}
+
+class DoubleFacetRangeGenerator extends FacetRangeGenerator<Double> {
+ public DoubleFacetRangeGenerator(final RangeFacet rangeFacet) { super(rangeFacet); }
+
+ @Override
+ protected Double parseVal(String rawval) {
+ return Double.valueOf(rawval);
+ }
+ @Override
+ public Double parseAndAddGap(Double value, String gap) {
+ return new Double(value.doubleValue() + Double.valueOf(gap).doubleValue());
+ }
+}
+class DateFacetRangeGenerator extends FacetRangeGenerator<Date> {
+ private final Date now;
+ public DateFacetRangeGenerator(final RangeFacet rangeFacet, final Date now) {
+ super(rangeFacet);
+ this.now = now;
+ if (! (field.getType() instanceof TrieDateField) ) {
+ throw new IllegalArgumentException("SchemaField must use field type extending TrieDateField");
+ }
+ }
+
+ @Override
+ public String formatValue(Date val) {
+ return val.toInstant().toString();
+ }
+ @Override
+ protected Date parseVal(String rawval) {
+ return DateMathParser.parseMath(now, rawval);
+ }
+ @Override
+ protected Object parseGap(final String rawval) {
+ return rawval;
+ }
+ @Override
+ public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException {
+ final DateMathParser dmp = new DateMathParser();
+ dmp.setNow(value);
+ return dmp.parseMath(gap);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/MedianCalculator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/MedianCalculator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/MedianCalculator.java
index 52935e9..541cff0 100644
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/MedianCalculator.java
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/MedianCalculator.java
@@ -18,6 +18,10 @@ package org.apache.solr.analytics.util;
import java.util.List;
+/**
+ * Only used for testing.
+ * Medians are calculated with the {@link OrdinalCalculator} for actual analytics requests.
+ */
public class MedianCalculator {
/**
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsParams.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsParams.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsParams.java
new file mode 100644
index 0000000..084d997
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsParams.java
@@ -0,0 +1,177 @@
+/*
+ * 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.analytics.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsExpressionSortRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsRangeFacetRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsSortRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsValueFacetRequest;
+
+/**
+ * Specifies the format of the old olap-style analytics requests.
+ */
+public interface OldAnalyticsParams {
+ // Old request language
+ public static final String OLD_ANALYTICS = "olap";
+
+ public static final String OLD_PREFIX = "o|olap";
+
+ public static final String OLD_EXPRESSION = "s|stat|statistic";
+
+ public static class OldRequest {
+ public String name;
+ public Map<String,String> expressions = new HashMap<>();
+ public Map<String,OldFieldFacet> fieldFacets = new HashMap<>();
+ public Map<String,OldRangeFacet> rangeFacets = new HashMap<>();
+ public Map<String,OldQueryFacet> queryFacets = new HashMap<>();
+ }
+
+ public static final String FIELD_FACET = "ff|fieldfacet";
+ public static final String VALUE_FACET = "vf|valuefacet";
+ public static final String LIMIT = "l|limit";
+ public static final String OFFSET = "off|offset";
+ public static final String SHOW_MISSING = "sm|showmissing";
+ public static final String SORT_EXPRESSION ="se|sortexpr|sortexpression";
+ public static final String OLAP_SORT_EXPRESSION ="ss|sortstat|sortstatistic";
+ public static final String SORT_DIRECTION ="sd|sortdirection";
+
+ public static class OldFieldFacet {
+ public String field;
+ public String showMissing;
+ public String limit;
+ public String offset;
+ public String sortExpr;
+ public String sortDir;
+ }
+
+ public static class FieldFacetParamParser {
+ public static String regexParamList = LIMIT + "|" + OFFSET + "|" + SHOW_MISSING + "|" + OLAP_SORT_EXPRESSION + "|" + SORT_DIRECTION;
+
+ private static Predicate<String> isLimit = Pattern.compile("^" + LIMIT + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isOffset = Pattern.compile("^" + OFFSET + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isShowMissing = Pattern.compile("^" + SHOW_MISSING + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isSortExpr = Pattern.compile("^" + OLAP_SORT_EXPRESSION + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isSortDir = Pattern.compile("^" + SORT_DIRECTION + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+
+ public static void applyParam(AnalyticsValueFacetRequest facet, String param, String value) {
+ if (isLimit.test(param)) {
+ getSort(facet).limit = Integer.parseInt(value);
+ } else if (isOffset.test(param)) {
+ getSort(facet).offset = Integer.parseInt(value);
+ } else if (isShowMissing.test(param)) {
+ facet.expression = "fillmissing(" + facet.expression + ",\"(MISSING)\")";
+ } else if (isSortExpr.test(param)) {
+ AnalyticsSortRequest sort = getSort(facet);
+ AnalyticsExpressionSortRequest criterion;
+ if (sort.criteria.size() == 0) {
+ criterion = new AnalyticsExpressionSortRequest();
+ sort.criteria.add(criterion);
+ } else {
+ criterion = (AnalyticsExpressionSortRequest) sort.criteria.get(0);
+ }
+ criterion.expression = value;
+ } else if (isSortDir.test(param)) {
+ AnalyticsSortRequest sort = getSort(facet);
+ AnalyticsExpressionSortRequest criterion;
+ if (sort.criteria.size() == 0) {
+ criterion = new AnalyticsExpressionSortRequest();
+ sort.criteria.add(criterion);
+ } else {
+ criterion = (AnalyticsExpressionSortRequest) sort.criteria.get(0);
+ }
+ criterion.direction = value;
+ }
+ }
+
+ public static AnalyticsSortRequest getSort(AnalyticsValueFacetRequest facet) {
+ if (facet.sort == null) {
+ facet.sort = new AnalyticsSortRequest();
+ facet.sort.criteria = new ArrayList<>();
+ }
+ return facet.sort;
+ }
+ }
+
+ public static final String RANGE_FACET = "rf|rangefacet";
+ public static final String START = "st|start";
+ public static final String END = "e|end";
+ public static final String GAP = "g|gap";
+ public static final String HARDEND = "he|hardend";
+ public static final String INCLUDE_BOUNDARY = "ib|includebound";
+ public static final String OTHER_RANGE = "or|otherrange";
+
+ public static class OldRangeFacet {
+ public String field;
+ public String start;
+ public String end;
+ public String gaps;
+ public String hardend;
+ public String[] include;
+ public String[] others;
+ }
+
+ public static class RangeFacetParamParser {
+ public static String regexParamList = START + "|" + END + "|" + GAP + "|" + HARDEND + "|" + INCLUDE_BOUNDARY + "|" + OTHER_RANGE;
+
+ private static Predicate<String> isStart = Pattern.compile("^" + START + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isEnd = Pattern.compile("^" + END + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isGap = Pattern.compile("^" + GAP + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isHardEnd = Pattern.compile("^" + HARDEND + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isTrue = Pattern.compile("^t|true$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isFalse = Pattern.compile("^f|false$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isInclude = Pattern.compile("^" + INCLUDE_BOUNDARY + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+ private static Predicate<String> isOther = Pattern.compile("^" + OTHER_RANGE + "$", Pattern.CASE_INSENSITIVE).asPredicate();
+
+ public static void applyParam(AnalyticsRangeFacetRequest facet, String param, String[] values) {
+ if (isStart.test(param)) {
+ facet.start = values[0];
+ } else if (isEnd.test(param)) {
+ facet.end = values[0];
+ } else if (isGap.test(param)) {
+ facet.gaps = Arrays.asList(values[0].split(","));
+ } else if (isHardEnd.test(param)) {
+ if (isTrue.test(values[0])) {
+ facet.hardend = true;
+ } else if (isFalse.test(values[0])) {
+ facet.hardend = false;
+ }
+ } else if (isInclude.test(param)) {
+ facet.include = Arrays.asList(values);
+ } else if (isOther.test(param)) {
+ facet.others = Arrays.asList(values);
+ }
+ }
+ }
+
+ public static class OldQueryFacet {
+ public String name;
+ public String[] queries;
+ }
+
+ public static final String QUERY_FACET = "qf|queryfacet";
+ public static final String QUERY = "q|query";
+
+ //Defaults
+ public static final boolean DEFAULT_ABBREVIATE_PREFIX = true;
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsRequestConverter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsRequestConverter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsRequestConverter.java
new file mode 100644
index 0000000..0124dc8
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OldAnalyticsRequestConverter.java
@@ -0,0 +1,177 @@
+/*
+ * 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.analytics.util;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsGroupingRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsQueryFacetRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsRangeFacetRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsRequest;
+import org.apache.solr.analytics.AnalyticsRequestParser.AnalyticsValueFacetRequest;
+import org.apache.solr.common.params.SolrParams;
+
+/**
+ * Converts Analytics Requests in the old olap-style format to the new format.
+ */
+public class OldAnalyticsRequestConverter implements OldAnalyticsParams {
+ // Old language Parsing
+ private static final Pattern oldExprPattern =
+ Pattern.compile("^(?:"+OLD_PREFIX+")\\.([^\\.]+)\\.(?:"+OLD_EXPRESSION+")\\.([^\\.]+)$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern oldFieldFacetPattern =
+ Pattern.compile("^(?:"+OLD_PREFIX+")\\.([^\\.]+)\\.(?:"+FIELD_FACET+")$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern oldFieldFacetParamPattern =
+ Pattern.compile("^(?:"+OLD_PREFIX+")\\.([^\\.]+)\\.(?:"+FIELD_FACET+")\\.([^\\.]+)\\.("+FieldFacetParamParser.regexParamList+")$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern oldRangeFacetParamPattern =
+ Pattern.compile("^(?:"+OLD_PREFIX+")\\.([^\\.]+)\\.(?:"+RANGE_FACET+")\\.([^\\.]+)\\.("+RangeFacetParamParser.regexParamList+")$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern oldQueryFacetParamPattern =
+ Pattern.compile("^(?:"+OLD_PREFIX+")\\.([^\\.]+)\\.(?:"+QUERY_FACET+")\\.([^\\.]+)\\.("+QUERY+")$", Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Convert the old olap-style Analytics Request in the given params to
+ * an analytics request string using the current format.
+ *
+ * @param params to find the analytics request in
+ * @return an analytics request string
+ */
+ public static AnalyticsRequest convert(SolrParams params) {
+ AnalyticsRequest request = new AnalyticsRequest();
+ request.expressions = new HashMap<>();
+ request.groupings = new HashMap<>();
+ Iterator<String> paramsIterator = params.getParameterNamesIterator();
+ while (paramsIterator.hasNext()) {
+ String param = paramsIterator.next();
+ CharSequence paramSequence = param.subSequence(0, param.length());
+ parseParam(request, param, paramSequence, params);
+ }
+ return request;
+ }
+
+ private static void parseParam(AnalyticsRequest request, String param, CharSequence paramSequence, SolrParams params) {
+ // Check if grouped expression
+ Matcher m = oldExprPattern.matcher(paramSequence);
+ if (m.matches()) {
+ addExpression(request,m.group(1),m.group(2),params.get(param));
+ return;
+ }
+
+ // Check if field facet parameter
+ m = oldFieldFacetPattern.matcher(paramSequence);
+ if (m.matches()) {
+ addFieldFacets(request,m.group(1),params.getParams(param));
+ return;
+ }
+
+ // Check if field facet parameter
+ m = oldFieldFacetParamPattern.matcher(paramSequence);
+ if (m.matches()) {
+ setFieldFacetParam(request,m.group(1),m.group(2),m.group(3),params.getParams(param));
+ return;
+ }
+
+ // Check if field facet parameter
+ m = oldFieldFacetParamPattern.matcher(paramSequence);
+ if (m.matches()) {
+ setFieldFacetParam(request,m.group(1),m.group(2),m.group(3),params.getParams(param));
+ return;
+ }
+
+ // Check if range facet parameter
+ m = oldRangeFacetParamPattern.matcher(paramSequence);
+ if (m.matches()) {
+ setRangeFacetParam(request,m.group(1),m.group(2),m.group(3),params.getParams(param));
+ return;
+ }
+
+ // Check if query
+ m = oldQueryFacetParamPattern.matcher(paramSequence);
+ if (m.matches()) {
+ setQueryFacetParam(request,m.group(1),m.group(2),m.group(3),params.getParams(param));
+ return;
+ }
+ }
+
+ private static AnalyticsGroupingRequest getGrouping(AnalyticsRequest request, String name) {
+ AnalyticsGroupingRequest grouping = request.groupings.get(name);
+ if (grouping == null) {
+ grouping = new AnalyticsGroupingRequest();
+ grouping.expressions = new HashMap<>();
+ grouping.facets = new HashMap<>();
+ request.groupings.put(name, grouping);
+ }
+ return grouping;
+ }
+
+ private static void addFieldFacets(AnalyticsRequest request, String groupingName, String[] params) {
+ AnalyticsGroupingRequest grouping = getGrouping(request, groupingName);
+
+ for (String param : params) {
+ if (!grouping.facets.containsKey(param)) {
+ AnalyticsValueFacetRequest fieldFacet = new AnalyticsValueFacetRequest();
+ fieldFacet.expression = param;
+ grouping.facets.put(param, fieldFacet);
+ }
+ }
+ }
+
+ private static void setFieldFacetParam(AnalyticsRequest request, String groupingName, String field, String paramType, String[] params) {
+ AnalyticsGroupingRequest grouping = getGrouping(request, groupingName);
+
+ AnalyticsValueFacetRequest fieldFacet = (AnalyticsValueFacetRequest) grouping.facets.get(field);
+
+ if (fieldFacet == null) {
+ fieldFacet = new AnalyticsValueFacetRequest();
+ fieldFacet.expression = field;
+ grouping.facets.put(field, fieldFacet);
+ }
+ FieldFacetParamParser.applyParam(fieldFacet, paramType, params[0]);
+ }
+
+ private static void setRangeFacetParam(AnalyticsRequest request, String groupingName, String field, String paramType, String[] params) {
+ AnalyticsGroupingRequest grouping = getGrouping(request, groupingName);
+
+ AnalyticsRangeFacetRequest rangeFacet = (AnalyticsRangeFacetRequest) grouping.facets.get(field);
+ if (rangeFacet == null) {
+ rangeFacet = new AnalyticsRangeFacetRequest();
+ rangeFacet.field = field;
+ grouping.facets.put(field, rangeFacet);
+ }
+ RangeFacetParamParser.applyParam(rangeFacet, paramType, params);
+ }
+
+ private static void setQueryFacetParam(AnalyticsRequest request, String groupingName, String facetName, String paramType, String[] params) {
+ AnalyticsGroupingRequest grouping = getGrouping(request, groupingName);
+
+ AnalyticsQueryFacetRequest queryFacet = new AnalyticsQueryFacetRequest();
+ queryFacet.queries = new HashMap<>();
+ if (paramType.equals("query")||paramType.equals("q")) {
+ for (String param : params) {
+ queryFacet.queries.put(param, param);
+ }
+ }
+ grouping.facets.put(facetName, queryFacet);
+ }
+
+ private static void addExpression(AnalyticsRequest request, String groupingName, String expressionName, String expression) {
+ request.expressions.put(groupingName + expressionName, expression);
+
+ getGrouping(request, groupingName).expressions.put(expressionName, expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OrdinalCalculator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OrdinalCalculator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OrdinalCalculator.java
new file mode 100644
index 0000000..e484e7c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/OrdinalCalculator.java
@@ -0,0 +1,173 @@
+/*
+ * 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.analytics.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Calculates ordinals of a comparable list by placing them in the correct positions in the list.
+ * <p>
+ * Implements the QuickSelect algorithm, but modifies it to select multiple ordinals all at once.
+ */
+public class OrdinalCalculator {
+ /**
+ * Calculates a set of ordinal values for a given list of comparable objects.
+ * Once the method returns, the each ordinal is guaranteed to have the correct value in the list.
+ *
+ * @param list the list of {@link Comparable} objects
+ * @param ordinals the collection ordinals to calculate (0 to (size of list) - 1)
+ */
+ public static <T extends Comparable<T>> void putOrdinalsInPosition(List<T> list, Collection<Integer> ordinals) {
+ int size = list.size();
+ if (size == 0) {
+ return;
+ }
+
+ int[] ords = new int[ordinals.size()];
+ int i = 0;
+ for (int ord : ordinals) {
+ ords[i++] = ord;
+ }
+ Arrays.sort(ords);
+
+ if (ords[0] < 0 || ords[ords.length - 1] > size - 1) {
+ throw new IllegalArgumentException();
+ }
+ distributeAndFind(list, ords, 0, ords.length - 1);
+ }
+
+ private static <T extends Comparable<T>> void distributeAndFind(List<T> list, int[] ordinals, int beginIdx, int endIdx) {
+ if (endIdx < beginIdx) {
+ return;
+ }
+ int middleIdxb = beginIdx;
+ int middleIdxe = beginIdx;
+ int begin = (beginIdx == 0) ? -1 : ordinals[beginIdx - 1];
+ int end = (endIdx == ordinals.length - 1) ? list.size() : ordinals[endIdx + 1];
+ double middle = (begin + end) / 2.0;
+ for (int i = beginIdx; i <= endIdx; i++) {
+ double value = Math.abs(ordinals[i] - middle) - Math.abs(ordinals[middleIdxb] - middle);
+ if (ordinals[i] == ordinals[middleIdxb]) {
+ middleIdxe = i;
+ } else if (value < 0) {
+ middleIdxb = i;
+ do {
+ middleIdxe = i;
+ i++;
+ } while (i <= endIdx && ordinals[middleIdxb] == ordinals[i]);
+ break;
+ }
+ }
+
+ int middlePlace = ordinals[middleIdxb];
+ int beginPlace = begin + 1;
+ int endPlace = end - 1;
+
+ select(list, middlePlace, beginPlace, endPlace);
+ distributeAndFind(list, ordinals, beginIdx, middleIdxb - 1);
+ distributeAndFind(list, ordinals, middleIdxe + 1, endIdx);
+ }
+
+ private static <T extends Comparable<T>> void select(List<T> list, int place, int begin, int end) {
+ T split;
+ if (end - begin < 10) {
+ split = list.get((int) (Math.random() * (end - begin + 1)) + begin);
+ } else {
+ split = split(list, begin, end);
+ }
+
+ Point result = partition(list, begin, end, split);
+
+ if (place <= result.low) {
+ select(list, place, begin, result.low);
+ } else if (place >= result.high) {
+ select(list, place, result.high, end);
+ }
+ }
+
+ private static <T extends Comparable<T>> T split(List<T> list, int begin, int end) {
+ T temp;
+ int num = (end - begin + 1);
+ int recursiveSize = (int) Math.sqrt((double) num);
+ int step = num / recursiveSize;
+ for (int i = 1; i < recursiveSize; i++) {
+ int swapFrom = i * step + begin;
+ int swapTo = i + begin;
+ temp = list.get(swapFrom);
+ list.set(swapFrom, list.get(swapTo));
+ list.set(swapTo, temp);
+ }
+ recursiveSize--;
+ select(list, recursiveSize / 2 + begin, begin, recursiveSize + begin);
+ return list.get(recursiveSize / 2 + begin);
+ }
+
+ private static <T extends Comparable<T>> Point partition(List<T> list, int begin, int end, T indexElement) {
+ T temp;
+ int left, right;
+ for (left = begin, right = end; left <= right; left++, right--) {
+ while (list.get(left).compareTo(indexElement) < 0) {
+ left++;
+ }
+ while (right != begin - 1 && list.get(right).compareTo(indexElement) >= 0) {
+ right--;
+ }
+ if (right <= left) {
+ left--;
+ right++;
+ break;
+ }
+ temp = list.get(left);
+ list.set(left, list.get(right));
+ list.set(right, temp);
+ }
+ while (left > begin - 1 && list.get(left).compareTo(indexElement) >= 0) {
+ left--;
+ }
+ while (right < end + 1 && list.get(right).compareTo(indexElement) <= 0) {
+ right++;
+ }
+ int rightMove = right + 1;
+ while (rightMove < end + 1) {
+ if (list.get(rightMove).equals(indexElement)) {
+ temp = list.get(rightMove);
+ list.set(rightMove, list.get(right));
+ list.set(right, temp);
+ do {
+ right++;
+ } while (list.get(right).equals(indexElement));
+ if (rightMove <= right) {
+ rightMove = right;
+ }
+ }
+ rightMove++;
+ }
+ return new Point(left, right);
+ }
+}
+
+class Point {
+ public int low;
+ public int high;
+
+ public Point(int low, int high) {
+ this.low = low;
+ this.high = high;
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/PercentileCalculator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/PercentileCalculator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/PercentileCalculator.java
deleted file mode 100644
index 4ae5cc0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/PercentileCalculator.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.analytics.util;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class PercentileCalculator {
- /**
- * Calculates a list of percentile values for a given list of objects and percentiles.
- *
- * @param list The list of {@link Comparable} objects to calculate the percentiles of.
- * @param percents The array of percentiles (.01 to .99) to calculate.
- * @return a list of comparables
- */
- public static <T extends Comparable<T>> List<T> getPercentiles(List<T> list, double[] percents) {
- int size = list.size();
- if (size == 0) {
- return null;
- }
-
- int[] percs = new int[percents.length];
- for (int i = 0; i < percs.length; i++) {
- percs[i] = (int) Math.round(percents[i] * size - .5);
- }
- int[] percentiles = Arrays.copyOf(percs, percs.length);
- Arrays.sort(percentiles);
-
- if (percentiles[0] < 0 || percentiles[percentiles.length - 1] > size - 1) {
- throw new IllegalArgumentException();
- }
-
- List<T> results = new ArrayList<>(percs.length);
-
- distributeAndFind(list, percentiles, 0, percentiles.length - 1);
-
- for (int i = 0; i < percs.length; i++) {
- results.add(list.get(percs[i]));
- }
- return results;
- }
-
- private static <T extends Comparable<T>> void distributeAndFind(List<T> list, int[] percentiles, int beginIdx, int endIdx) {
- if (endIdx < beginIdx) {
- return;
- }
- int middleIdxb = beginIdx;
- int middleIdxe = beginIdx;
- int begin = (beginIdx == 0) ? -1 : percentiles[beginIdx - 1];
- int end = (endIdx == percentiles.length - 1) ? list.size() : percentiles[endIdx + 1];
- double middle = (begin + end) / 2.0;
- for (int i = beginIdx; i <= endIdx; i++) {
- double value = Math.abs(percentiles[i] - middle) - Math.abs(percentiles[middleIdxb] - middle);
- if (percentiles[i] == percentiles[middleIdxb]) {
- middleIdxe = i;
- } else if (value < 0) {
- middleIdxb = i;
- do {
- middleIdxe = i;
- i++;
- } while (i <= endIdx && percentiles[middleIdxb] == percentiles[i]);
- break;
- }
- }
-
- int middlePlace = percentiles[middleIdxb];
- int beginPlace = begin + 1;
- int endPlace = end - 1;
-
- select(list, middlePlace, beginPlace, endPlace);
- distributeAndFind(list, percentiles, beginIdx, middleIdxb - 1);
- distributeAndFind(list, percentiles, middleIdxe + 1, endIdx);
- }
-
- private static <T extends Comparable<T>> void select(List<T> list, int place, int begin, int end) {
- T split;
- if (end - begin < 10) {
- split = list.get((int) (Math.random() * (end - begin + 1)) + begin);
- } else {
- split = split(list, begin, end);
- }
-
- Point result = partition(list, begin, end, split);
-
- if (place <= result.low) {
- select(list, place, begin, result.low);
- } else if (place >= result.high) {
- select(list, place, result.high, end);
- }
- }
-
- private static <T extends Comparable<T>> T split(List<T> list, int begin, int end) {
- T temp;
- int num = (end - begin + 1);
- int recursiveSize = (int) Math.sqrt((double) num);
- int step = num / recursiveSize;
- for (int i = 1; i < recursiveSize; i++) {
- int swapFrom = i * step + begin;
- int swapTo = i + begin;
- temp = list.get(swapFrom);
- list.set(swapFrom, list.get(swapTo));
- list.set(swapTo, temp);
- }
- recursiveSize--;
- select(list, recursiveSize / 2 + begin, begin, recursiveSize + begin);
- return list.get(recursiveSize / 2 + begin);
- }
-
- private static <T extends Comparable<T>> Point partition(List<T> list, int begin, int end, T indexElement) {
- T temp;
- int left, right;
- for (left = begin, right = end; left <= right; left++, right--) {
- while (list.get(left).compareTo(indexElement) < 0) {
- left++;
- }
- while (right != begin - 1 && list.get(right).compareTo(indexElement) >= 0) {
- right--;
- }
- if (right <= left) {
- left--;
- right++;
- break;
- }
- temp = list.get(left);
- list.set(left, list.get(right));
- list.set(right, temp);
- }
- while (left > begin - 1 && list.get(left).compareTo(indexElement) >= 0) {
- left--;
- }
- while (right < end + 1 && list.get(right).compareTo(indexElement) <= 0) {
- right++;
- }
- int rightMove = right + 1;
- while (rightMove < end + 1) {
- if (list.get(rightMove).equals(indexElement)) {
- temp = list.get(rightMove);
- list.set(rightMove, list.get(right));
- list.set(right, temp);
- do {
- right++;
- } while (list.get(right).equals(indexElement));
- if (rightMove <= right) {
- rightMove = right;
- }
- }
- rightMove++;
- }
- return new Point(left, right);
- }
-}
-
-class Point {
- public int low;
- public int high;
-
- public Point(int low, int high) {
- this.low = low;
- this.high = high;
- }
-}
[11/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/UniqueFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/UniqueFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/UniqueFunction.java
new file mode 100644
index 0000000..f62f7d9
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/UniqueFunction.java
@@ -0,0 +1,101 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector.UniqueDoubleCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector.UniqueFloatCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector.UniqueIntCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector.UniqueLongCollector;
+import org.apache.solr.analytics.function.reduction.data.UniqueCollector.UniqueStringCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the number of unique values of the given expression.
+ */
+public class UniqueFunction extends AbstractLongValue implements ReductionFunction {
+ private UniqueCollector<?> collector;
+ public static final String name = "unique";
+ private final String exprStr;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ UniqueCollector<?> collector;
+ if (param instanceof IntValueStream) {
+ collector = new UniqueIntCollector((IntValueStream)param);
+ } else if (param instanceof LongValueStream) {
+ collector = new UniqueLongCollector((LongValueStream)param);
+ } else if (param instanceof FloatValueStream) {
+ collector = new UniqueFloatCollector((FloatValueStream)param);
+ } else if (param instanceof DoubleValueStream) {
+ collector = new UniqueDoubleCollector((DoubleValueStream)param);
+ } else if (param instanceof StringValueStream) {
+ collector = new UniqueStringCollector((StringValueStream)param);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter.");
+ }
+ return new UniqueFunction(param, collector);
+ });
+
+ public UniqueFunction(AnalyticsValueStream param, UniqueCollector<?> collector) {
+ this.collector = collector;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.count();
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (UniqueCollector<?>)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/CountCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/CountCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/CountCollector.java
new file mode 100644
index 0000000..135b587
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/CountCollector.java
@@ -0,0 +1,188 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.LongReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+
+public abstract class CountCollector extends ReductionDataCollector<CountCollector.CountData> {
+ public static final String name = "count";
+ private final String exprStr;
+
+ public CountCollector(String exprStr) {
+ this.exprStr = exprStr;
+ }
+
+ private long count;
+ private long docCount;
+
+ /**
+ * The number of Solr Documents for which the given analytics expression exists.
+ *
+ * @return the count
+ */
+ public long count() {
+ return count;
+ }
+ /**
+ * The number of Solr Documents used in this reduction.
+ *
+ * @return the number of documents
+ */
+ public long docCount() {
+ return docCount;
+ }
+
+ @Override
+ public CountData newData() {
+ CountData data = new CountData();
+ data.count = 0;
+ data.missing = 0;
+ data.docCount = 0;
+ return data;
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ // Count
+ consumer.accept(new LongReservation(
+ value -> ioData.count += value,
+ () -> ioData.count
+ ));
+ // DocCount
+ consumer.accept(new LongReservation(
+ value -> ioData.docCount += value,
+ () -> ioData.docCount
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ count = ((CountData)data).count;
+ docCount = ((CountData)data).docCount;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ count = ((CountData)data).count;
+ docCount = ((CountData)data).docCount;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class CountData extends ReductionData {
+ long count;
+ long missing;
+ long docCount;
+ }
+
+ /**
+ * Represents a {@code count(expr)} expression. This collects 3 values:
+ *
+ * docCount - The number of Solr Documents for which the wrapped expression exists.
+ * count - The number of values which wrapped expression contains.
+ * missing - The number of Solr Documents for which the wrapped expression does not exist.
+ */
+ public static class ExpressionCountCollector extends CountCollector {
+ private final AnalyticsValueStream param;
+
+ public ExpressionCountCollector(AnalyticsValueStream param) {
+ super(AnalyticsValueStream.createExpressionString(name, param));
+ this.param = param;
+ }
+
+ private long missing;
+
+ /**
+ * The number of Solr Documents for which the given analytics expression does not exist.
+ *
+ * @return the number of missing values
+ */
+ public long missing() {
+ return missing;
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setMergedData(data);
+ missing = ((CountData)data).missing;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ missing = ((CountData)data).missing;
+ }
+
+ long tempCount;
+ int tempMissing;
+ int tempDocCount;
+ @Override
+ public void collect() {
+ tempCount = 0;
+ param.streamObjects( obj -> {
+ ++tempCount;
+ });
+ tempMissing = tempCount == 0 ? 1 : 0;
+ tempDocCount = tempCount > 0 ? 1 : 0;
+ }
+
+ @Override
+ protected void apply(CountData data) {
+ data.count += tempCount;
+ data.missing += tempMissing;
+ data.docCount += tempDocCount;
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ super.submitReservations(consumer);
+ // Missing
+ consumer.accept(new LongReservation(
+ value -> ioData.missing += value,
+ () -> ioData.missing
+ ));
+ }
+ }
+
+ /**
+ * Represents a {@code count()} expression. This collects the number of Solr Documents used in a result set.
+ */
+ public static class TotalCountCollector extends CountCollector {
+
+ public TotalCountCollector() {
+ super(AnalyticsValueStream.createExpressionString(name));
+ }
+
+ @Override
+ protected void apply(CountData data) {
+ data.count += 1;
+ data.docCount += 1;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MaxCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MaxCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MaxCollector.java
new file mode 100644
index 0000000..bf49907
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MaxCollector.java
@@ -0,0 +1,476 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.DoubleCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.FloatCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.IntCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.LongCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.stream.reservation.StringCheckedReservation;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Collector of max values.
+ * <p>
+ * Supported types are:
+ * <ul>
+ * <li>Int
+ * <li>Long
+ * <li>Float
+ * <li>Double
+ * <li>Date (through longs)
+ * <li>String
+ * </ul>
+ *
+ * @param <T> The type of data being processed.
+ */
+public abstract class MaxCollector<T extends ReductionData> extends ReductionDataCollector<T> {
+ public static final String name = "max";
+ private final String exprStr;
+
+ protected MaxCollector(AnalyticsValueStream param) {
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ private boolean exists;
+
+ /**
+ * Returns true if any of the values being reduce exist, and false if none of them do.
+ *
+ * @return whether a max value exists
+ */
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ exists = data.exists;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ exists = data.exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class IntMaxCollector extends MaxCollector<IntMaxCollector.MaxData> {
+ private IntValueStream param;
+
+ public IntMaxCollector(IntValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MaxData newData() {
+ MaxData data = new MaxData();
+ data.exists = false;
+ return data;
+ }
+
+ int max;
+
+ /**
+ * Returns the max value of the set data.
+ *
+ * @return the max
+ */
+ public int max() {
+ return max;
+ }
+
+ int tempMax;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamInts( val -> {
+ if (!tempExists || val > tempMax) {
+ tempMax = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MaxData data) {
+ if (tempExists && (!data.exists || tempMax > data.val)) {
+ data.val = tempMax;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new IntCheckedReservation(
+ value -> {
+ if (!ioData.exists || value > ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ public static class MaxData extends ReductionData {
+ int val;
+ }
+ }
+
+
+
+ public static class LongMaxCollector extends MaxCollector<LongMaxCollector.MaxData> {
+ private LongValueStream param;
+
+ public LongMaxCollector(LongValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MaxData newData() {
+ MaxData data = new MaxData();
+ data.exists = false;
+ return data;
+ }
+
+ long max;
+
+ /**
+ * Returns the max value of the set data.
+ *
+ * @return the max
+ */
+ public long max() {
+ return max;
+ }
+
+ long tempMax;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamLongs( val -> {
+ if (!tempExists || val > tempMax) {
+ tempMax = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MaxData data) {
+ if (tempExists && (!data.exists || tempMax > data.val)) {
+ data.val = tempMax;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new LongCheckedReservation(
+ value -> {
+ if (!ioData.exists || value > ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ public static class MaxData extends ReductionData {
+ long val;
+ }
+ }
+
+ public static class FloatMaxCollector extends MaxCollector<FloatMaxCollector.MaxData> {
+ private FloatValueStream param;
+
+ public FloatMaxCollector(FloatValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MaxData newData() {
+ MaxData data = new MaxData();
+ data.exists = false;
+ return data;
+ }
+
+ float max;
+
+ /**
+ * Returns the max value of the set data.
+ *
+ * @return the max
+ */
+ public float max() {
+ return max;
+ }
+
+ float tempMax;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamFloats( val -> {
+ if (!tempExists || val > tempMax) {
+ tempMax = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MaxData data) {
+ if (tempExists && (!data.exists || tempMax > data.val)) {
+ data.val = tempMax;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new FloatCheckedReservation(
+ value -> {
+ if (!ioData.exists || value > ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ public static class MaxData extends ReductionData {
+ float val;
+ }
+ }
+
+ public static class DoubleMaxCollector extends MaxCollector<DoubleMaxCollector.MaxData> {
+ private DoubleValueStream param;
+
+ public DoubleMaxCollector(DoubleValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MaxData newData() {
+ MaxData data = new MaxData();
+ data.exists = false;
+ return data;
+ }
+
+ double max;
+
+ /**
+ * Returns the max value of the set data.
+ *
+ * @return the max
+ */
+ public double max() {
+ return max;
+ }
+
+ double tempMax;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamDoubles( val -> {
+ if (!tempExists || val > tempMax) {
+ tempMax = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MaxData data) {
+ if (tempExists && (!data.exists || tempMax > data.val)) {
+ data.val = tempMax;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new DoubleCheckedReservation(
+ value -> {
+ if (!ioData.exists || value > ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ public static class MaxData extends ReductionData {
+ double val;
+ }
+ }
+
+
+
+ public static class StringMaxCollector extends MaxCollector<StringMaxCollector.MaxData> {
+ private StringValueStream param;
+
+ public StringMaxCollector(StringValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MaxData newData() {
+ MaxData data = new MaxData();
+ data.exists = false;
+ return data;
+ }
+
+ String max;
+
+ /**
+ * Returns the max value of the set data.
+ *
+ * @return the max
+ */
+ public String max() {
+ return max;
+ }
+
+ String tempMax;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamStrings( val -> {
+ if (!tempExists || val.compareTo(tempMax) > 0) {
+ tempMax = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MaxData data) {
+ if (tempExists && (!data.exists || tempMax.compareTo(data.val) > 0)) {
+ data.val = tempMax;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new StringCheckedReservation(
+ value -> {
+ if (!ioData.exists || value.compareTo(ioData.val) > 0) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ max = ((MaxData)data).val;
+ }
+
+ public static class MaxData extends ReductionData {
+ String val;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MinCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MinCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MinCollector.java
new file mode 100644
index 0000000..3a33660
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/MinCollector.java
@@ -0,0 +1,476 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.DoubleCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.FloatCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.IntCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.LongCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.stream.reservation.StringCheckedReservation;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Collector of min values.
+ * <p>
+ * Supported types are:
+ * <ul>
+ * <li>Int
+ * <li>Long
+ * <li>Float
+ * <li>Double
+ * <li>Date (through longs)
+ * <li>String
+ * </ul>
+ *
+ * @param <T> The type of data being processed.
+ */
+public abstract class MinCollector<T extends ReductionData> extends ReductionDataCollector<T> {
+ public static final String name = "min";
+ private final String exprStr;
+
+ protected MinCollector(AnalyticsValueStream param) {
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ private boolean exists;
+
+ /**
+ * Returns true if any of the values being reduce exist, and false if none of them do.
+ *
+ * @return whether a min value exists
+ */
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ exists = data.exists;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ exists = data.exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class IntMinCollector extends MinCollector<IntMinCollector.MinData> {
+ private IntValueStream param;
+
+ public IntMinCollector(IntValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MinData newData() {
+ MinData data = new MinData();
+ data.exists = false;
+ return data;
+ }
+
+ int min;
+
+ /**
+ * Returns the min value of the set data.
+ *
+ * @return the min
+ */
+ public int min() {
+ return min;
+ }
+
+ int tempMin;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamInts( val -> {
+ if (!tempExists || val < tempMin) {
+ tempMin = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MinData data) {
+ if (tempExists && (!data.exists || tempMin < data.val)) {
+ data.val = tempMin;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new IntCheckedReservation(
+ value -> {
+ if (!ioData.exists || value < ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ public static class MinData extends ReductionData {
+ int val;
+ }
+ }
+
+
+
+ public static class LongMinCollector extends MinCollector<LongMinCollector.MinData> {
+ private LongValueStream param;
+
+ public LongMinCollector(LongValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MinData newData() {
+ MinData data = new MinData();
+ data.exists = false;
+ return data;
+ }
+
+ long min;
+
+ /**
+ * Returns the min value of the set data.
+ *
+ * @return the min
+ */
+ public long min() {
+ return min;
+ }
+
+ long tempMin;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamLongs( val -> {
+ if (!tempExists || val < tempMin) {
+ tempMin = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MinData data) {
+ if (tempExists && (!data.exists || tempMin < data.val)) {
+ data.val = tempMin;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new LongCheckedReservation(
+ value -> {
+ if (!ioData.exists || value < ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ public static class MinData extends ReductionData {
+ long val;
+ }
+ }
+
+ public static class FloatMinCollector extends MinCollector<FloatMinCollector.MinData> {
+ private FloatValueStream param;
+
+ public FloatMinCollector(FloatValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MinData newData() {
+ MinData data = new MinData();
+ data.exists = false;
+ return data;
+ }
+
+ float min;
+
+ /**
+ * Returns the min value of the set data.
+ *
+ * @return the min
+ */
+ public float min() {
+ return min;
+ }
+
+ float tempMin;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamFloats( val -> {
+ if (!tempExists || val < tempMin) {
+ tempMin = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MinData data) {
+ if (tempExists && (!data.exists || tempMin < data.val)) {
+ data.val = tempMin;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new FloatCheckedReservation(
+ value -> {
+ if (!ioData.exists || value < ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ public static class MinData extends ReductionData {
+ float val;
+ }
+ }
+
+ public static class DoubleMinCollector extends MinCollector<DoubleMinCollector.MinData> {
+ private DoubleValueStream param;
+
+ public DoubleMinCollector(DoubleValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MinData newData() {
+ MinData data = new MinData();
+ data.exists = false;
+ return data;
+ }
+
+ double min;
+
+ /**
+ * Returns the min value of the set data.
+ *
+ * @return the min
+ */
+ public double min() {
+ return min;
+ }
+
+ double tempMin;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamDoubles( val -> {
+ if (!tempExists || val < tempMin) {
+ tempMin = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MinData data) {
+ if (tempExists && (!data.exists || tempMin < data.val)) {
+ data.val = tempMin;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new DoubleCheckedReservation(
+ value -> {
+ if (!ioData.exists || value < ioData.val) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ public static class MinData extends ReductionData {
+ double val;
+ }
+ }
+
+
+
+ public static class StringMinCollector extends MinCollector<StringMinCollector.MinData> {
+ private StringValueStream param;
+
+ public StringMinCollector(StringValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public MinData newData() {
+ MinData data = new MinData();
+ data.exists = false;
+ return data;
+ }
+
+ String min;
+
+ /**
+ * Returns the min value of the set data.
+ *
+ * @return the min
+ */
+ public String min() {
+ return min;
+ }
+
+ String tempMin;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempExists = false;
+ param.streamStrings( val -> {
+ if (!tempExists || val.compareTo(tempMin) < 0) {
+ tempMin = val;
+ tempExists = true;
+ }
+ });
+ }
+ @Override
+ protected void apply(MinData data) {
+ if (tempExists && (!data.exists || tempMin.compareTo(data.val) < 0)) {
+ data.val = tempMin;
+ data.exists = true;
+ }
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new StringCheckedReservation(
+ value -> {
+ if (!ioData.exists || value.compareTo(ioData.val) < 0) {
+ ioData.val = value;
+ ioData.exists = true;
+ }
+ },
+ ()-> ioData.val,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ super.setData(data);
+ min = ((MinData)data).val;
+ }
+
+ public static class MinData extends ReductionData {
+ String val;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionData.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionData.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionData.java
new file mode 100644
index 0000000..8c265fd
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionData.java
@@ -0,0 +1,24 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+/**
+ * Base class to store data for {@link ReductionDataCollector}s
+ */
+public class ReductionData {
+ public boolean exists;
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionDataCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionDataCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionDataCollector.java
new file mode 100644
index 0000000..9674d98
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/ReductionDataCollector.java
@@ -0,0 +1,183 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.value.AnalyticsValue;
+
+/**
+ * Manager of a specific instance of {@link ReductionData} collection.
+ *
+ * @param <T> the type of reduction data being collected
+ */
+public abstract class ReductionDataCollector<T extends ReductionData> {
+
+ protected ArrayList<T> lastingTargets;
+ protected ArrayList<T> collectionTargets;
+ protected T ioData;
+
+ protected ReductionDataCollector() {
+ lastingTargets = new ArrayList<>();
+ collectionTargets = new ArrayList<>();
+ }
+
+ /**
+ * Submits the data reservations needed for this data collector.
+ *
+ * @param consumer the consumer which the reservations are submitted to
+ */
+ public abstract void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer);
+
+ /**
+ * A clean slate to start a new reduction.
+ *
+ * @return the new reduction data
+ */
+ public abstract T newData();
+
+ /**
+ * Add a reduction data to target during collection.
+ * The given target is valid until the lasting targets are cleared.
+ *
+ * @param data the data to target
+ */
+ @SuppressWarnings("unchecked")
+ public void addLastingCollectTarget(ReductionData data) {
+ lastingTargets.add((T) data);
+ }
+
+ /**
+ * Clear the lasting collection targets. After this is called the current lasting
+ * targets will not be affected by future {@link #collectAndApply()} calls.
+ */
+ public void clearLastingCollectTargets() {
+ lastingTargets.clear();
+ }
+
+ /**
+ * Create a new reduction data to target during collection.
+ * The given target is only valid for one call to {@link #collectAndApply()}.
+ *
+ * @return the reduction data created
+ */
+ public T newDataTarget() {
+ T data = newData();
+ collectionTargets.add(data);
+ return data;
+ }
+
+ /**
+ * Add a reduction data to target during collection.
+ * The given target is only valid for one call to {@link #collectAndApply()}.
+ *
+ * @param data the data to target
+ */
+ @SuppressWarnings("unchecked")
+ public void addCollectTarget(ReductionData data) {
+ collectionTargets.add((T)data);
+ }
+
+ /**
+ * Collect the info for the current Solr Document and apply the results to the
+ * given collection targets.
+ *
+ * After application, all non-lasting targets are removed.
+ */
+ public void collectAndApply() {
+ collect();
+ lastingTargets.forEach( target -> apply(target) );
+ collectionTargets.forEach( target -> apply(target) );
+ collectionTargets.clear();
+ }
+
+ /**
+ * Collect the information from current Solr Document.
+ */
+ protected void collect() { }
+
+ /**
+ * Apply the collected info to the given reduction data.
+ * Should always be called after a {@link #collect()} call.
+ *
+ * @param data reduction data to apply collected info to
+ */
+ protected abstract void apply(T data);
+
+ /**
+ * Create a new reduction data to use in exporting and merging.
+ *
+ * @return the created reduction data
+ */
+ public T newDataIO() {
+ ioData = newData();
+ return ioData;
+ }
+
+ /**
+ * Set the reduction data to use in exporting and merging.
+ *
+ * @param data the data to use
+ */
+ @SuppressWarnings("unchecked")
+ public void dataIO(ReductionData data) {
+ ioData = (T)data;
+ }
+
+ /**
+ * Finalize the reduction with the merged data stored in the parameter.
+ * Once the reduction is finalized, the {@link ReductionFunction}s that use this
+ * data collector act like regular {@link AnalyticsValue} classes that
+ * can be accessed through their {@code get<value-type>} methods.
+ *
+ * (FOR CLOUD)
+ *
+ * @param data the merged data to compute a reduction for
+ */
+ public abstract void setMergedData(ReductionData data);
+
+ /**
+ * Finalize the reduction with the collected data stored in the parameter.
+ * Once the reduction is finalized, the {@link ReductionFunction}s that use this
+ * data collector act like regular {@link AnalyticsValue} classes that
+ * can be accessed through their {@code get<value-type>} methods.
+ *
+ * (FOR SINGLE-SHARD)
+ *
+ * @param data the collected data to compute a reduction for
+ */
+ public abstract void setData(ReductionData data);
+
+ /**
+ * Get the name of the reduction data collector. This is the same across all instances of the data collector.
+ *
+ * @return the name
+ */
+ public abstract String getName();
+
+ /**
+ * The unique expression string of the reduction data collector, given all inputs and parameters.
+ * Used during {@link ReductionDataCollector} syncing. Since the string should be unique,
+ * only one of expression is kept.
+ *
+ * @return the expression string
+ */
+ public abstract String getExpressionStr();
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SortedListCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SortedListCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SortedListCollector.java
new file mode 100644
index 0000000..c0de54b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SortedListCollector.java
@@ -0,0 +1,363 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.DoubleArrayReservation;
+import org.apache.solr.analytics.stream.reservation.FloatArrayReservation;
+import org.apache.solr.analytics.stream.reservation.IntArrayReservation;
+import org.apache.solr.analytics.stream.reservation.LongArrayReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.stream.reservation.StringArrayReservation;
+import org.apache.solr.analytics.util.OrdinalCalculator;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Collector of sorted lists.
+ *
+ * Once the sorted list has been collected, it can be reduced by calculating a median, percentiles, or ordinals.
+ * All of the above reductions over the same data share one {@link SortedListCollector}.
+ * <p>
+ * Supported types are:
+ * <ul>
+ * <li>Int
+ * <li>Long
+ * <li>Float
+ * <li>Double
+ * <li>Date (through longs)
+ * <li>String
+ * </ul>
+ *
+ * @param <T> The type of data being processed.
+ */
+public abstract class SortedListCollector<T extends Comparable<T>> extends ReductionDataCollector<SortedListCollector.SortedListData<T>> {
+ public static final String name = "sorted";
+ private final String exprStr;
+
+ protected SortedListCollector(AnalyticsValueStream param, String specificationName) {
+ this.exprStr = AnalyticsValueStream.createExpressionString(name + "_" + specificationName,param);
+
+ tempList = new ArrayList<>();
+
+ calcMedian = false;
+ calcPercs = new HashSet<>();
+ calcOrds = new HashSet<>();
+ calcRevOrds = new HashSet<>();
+ }
+
+ private List<T> list;
+
+ private boolean calcMedian;
+ private Set<Double> calcPercs;
+ private Set<Integer> calcOrds;
+ private Set<Integer> calcRevOrds;
+
+ public int size() {
+ return list.size();
+ }
+
+ /**
+ * Informs the collector that the median needs to be computed.
+ */
+ public void calcMedian() {
+ calcMedian = true;
+ }
+
+ /**
+ * Informs the collector that the following percentile needs to be computed.
+ *
+ * @param percentile requested percentile
+ */
+ public void calcPercentile(double percentile) {
+ calcPercs.add(percentile);
+ }
+
+ /**
+ * Informs the collector that the following ordinal needs to be computed.
+ *
+ * @param ordinal requested ordinal
+ */
+ public void calcOrdinal(int ordinal) {
+ calcOrds.add(ordinal);
+ }
+
+ /**
+ * Informs the collector that the following reverse ordinal needs to be computed.
+ * Reverse ordinals are ordinals that start at the end of the list.
+ *
+ * @param reverseOrdinal requested reverseOrdinal
+ */
+ public void calcReverseOrdinal(int reverseOrdinal) {
+ calcRevOrds.add(reverseOrdinal);
+ }
+
+ /**
+ * Once the data has been set by either {@link #setData} or {@link #setMergedData},
+ * this returns the value at the given sorted index.
+ *
+ * Only the indices specified by {@link #calcMedian}, {@link #calcPercentile}, {@link #calcOrdinal}, and {@link #calcReverseOrdinal}
+ * will contain valid data. All other indices may return unsorted data.
+ *
+ * @param index the index of the sorted data to return
+ */
+ public T get(int index) {
+ return list.get(index);
+ }
+
+ @Override
+ public SortedListData<T> newData() {
+ SortedListData<T> data = new SortedListData<>();
+ data.list = new ArrayList<T>();
+ data.exists = false;
+ return data;
+ }
+
+ ArrayList<T> tempList;
+ @Override
+ protected void apply(SortedListData<T> data) {
+ data.list.addAll(tempList);
+ }
+
+ /**
+ * Starts the import of the shard data.
+ *
+ * @param size the size of the incoming shard list
+ */
+ protected void startImport(int size) {
+ ioData.list.ensureCapacity(ioData.list.size() + size);
+ }
+
+ /**
+ * Merges the current list with the incoming value.
+ *
+ * @param value the next imported value to add
+ */
+ protected void importNext(T value) {
+ ioData.list.add(value);
+ }
+
+ Iterator<T> iter;
+ /**
+ * The list to be exported is unsorted.
+ * The lists of all shards will be combined with the {@link #startImport} and {@link #importNext} methods.
+ *
+ * @return the size of the list being exported.
+ */
+ public int startExport() {
+ iter = ioData.list.iterator();
+ return ioData.list.size();
+ }
+ /**
+ * Return the next value in the list.
+ *
+ * @return the next sorted value
+ */
+ public T exportNext() {
+ return iter.next();
+ }
+
+ /**
+ * Put the given indices in their sorted positions
+ */
+ @Override
+ public void setMergedData(ReductionData data) {
+ setData(data);
+ }
+
+ /**
+ * This is where the given indices are put in their sorted positions.
+ *
+ * Only the given indices are guaranteed to be in sorted order.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setData(ReductionData data) {
+ list = ((SortedListData<T>)data).list;
+ int size = list.size();
+ if (size <= 1) {
+ return;
+ }
+
+ // Ordinals start at 0 and end at size-1
+ Set<Integer> ordinals = new HashSet<>();
+ for (double percentile : calcPercs) {
+ ordinals.add((int) Math.ceil(percentile * size) - 1);
+ }
+ ordinals.addAll(calcOrds);
+ for (int reverseOrdinal : calcRevOrds) {
+ ordinals.add(size + reverseOrdinal);
+ }
+ if (calcMedian) {
+ int mid = list.size() / 2;
+ ordinals.add(mid);
+ if (list.size() % 2 == 0) {
+ ordinals.add(mid - 1);
+ }
+ }
+ OrdinalCalculator.putOrdinalsInPosition(list, ordinals);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class SortedListData<D extends Comparable<D>> extends ReductionData {
+ ArrayList<D> list;
+ }
+
+ public static class SortedIntListCollector extends SortedListCollector<Integer> {
+ private IntValueStream param;
+
+ public SortedIntListCollector(IntValueStream param) {
+ super(param, "int");
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempList.clear();
+ param.streamInts( val -> tempList.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new IntArrayReservation(
+ value -> importNext(value),
+ importSize -> startImport(importSize),
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class SortedLongListCollector extends SortedListCollector<Long> {
+ private LongValueStream param;
+
+ public SortedLongListCollector(LongValueStream param) {
+ super(param, "long");
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempList.clear();
+ param.streamLongs( val -> tempList.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new LongArrayReservation(
+ value -> importNext(value),
+ importSize -> startImport(importSize),
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class SortedFloatListCollector extends SortedListCollector<Float> {
+ private FloatValueStream param;
+
+ public SortedFloatListCollector(FloatValueStream param) {
+ super(param, "float");
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempList.clear();
+ param.streamFloats( val -> tempList.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new FloatArrayReservation(
+ value -> importNext(value),
+ importSize -> startImport(importSize),
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class SortedDoubleListCollector extends SortedListCollector<Double> {
+ private DoubleValueStream param;
+
+ public SortedDoubleListCollector(DoubleValueStream param) {
+ super(param, "double");
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempList.clear();
+ param.streamDoubles( val -> tempList.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new DoubleArrayReservation(
+ value -> importNext(value),
+ importSize -> startImport(importSize),
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class SortedStringListCollector extends SortedListCollector<String> {
+ private StringValueStream param;
+
+ public SortedStringListCollector(StringValueStream param) {
+ super(param, "string");
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempList.clear();
+ param.streamStrings( val -> tempList.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new StringArrayReservation(
+ value -> importNext(value),
+ importSize -> startImport(importSize),
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SumCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SumCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SumCollector.java
new file mode 100644
index 0000000..6f4fc18
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/SumCollector.java
@@ -0,0 +1,124 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.DoubleCheckedReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+
+/**
+ * Collects the sum of the given {@link DoubleValueStream} parameter.
+ */
+public class SumCollector extends ReductionDataCollector<SumCollector.SumData> {
+ private final DoubleValueStream param;
+ public static final String name = "sum";
+ private final String exprStr;
+
+ public SumCollector(DoubleValueStream param) {
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ private double sum;
+ private boolean exists;
+
+ /**
+ * Return the sum of the set data
+ *
+ * @return the sum
+ */
+ public double sum() {
+ return sum;
+ }
+
+ /**
+ * Return whether a sum exists.
+ * A sum will always exist if there is at least one existing value for the parameter,
+ * otherwise the sum does not exist.
+ *
+ * @return whether a sum exists
+ */
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public SumData newData() {
+ SumData data = new SumData();
+ data.sum = 0;
+ data.exists = false;
+ return data;
+ }
+
+ double tempSum;
+ boolean tempExists;
+ @Override
+ public void collect() {
+ tempSum = 0;
+ tempExists = false;
+ param.streamDoubles( val -> {
+ tempSum += val;
+ tempExists = true;
+ });
+ }
+ @Override
+ protected void apply(SumData data) {
+ data.sum += tempSum;
+ data.exists |= tempExists;
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new DoubleCheckedReservation(
+ value -> {
+ ioData.sum += value;
+ ioData.exists = true;
+ },
+ ()-> ioData.sum,
+ ()-> ioData.exists
+ ));
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ sum = ((SumData)data).sum;
+ exists = data.exists;
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ sum = ((SumData)data).sum;
+ exists = data.exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class SumData extends ReductionData {
+ double sum;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/UniqueCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/UniqueCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/UniqueCollector.java
new file mode 100644
index 0000000..3e30114
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/UniqueCollector.java
@@ -0,0 +1,241 @@
+/*
+ * 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.analytics.function.reduction.data;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.stream.reservation.DoubleArrayReservation;
+import org.apache.solr.analytics.stream.reservation.FloatArrayReservation;
+import org.apache.solr.analytics.stream.reservation.IntArrayReservation;
+import org.apache.solr.analytics.stream.reservation.LongArrayReservation;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.stream.reservation.StringArrayReservation;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Collects the number of unique values that exist for the given parameter.
+ * <p>
+ * Supported types are:
+ * <ul>
+ * <li>Int
+ * <li>Long
+ * <li>Float
+ * <li>Double
+ * <li>Date (through longs)
+ * <li>String
+ * </ul>
+ */
+public abstract class UniqueCollector<T> extends ReductionDataCollector<UniqueCollector.UniqueData<T>> {
+ public static final String name = "unique";
+ private final String exprStr;
+
+ public UniqueCollector(AnalyticsValueStream param) {
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.tempSet = new HashSet<T>();
+ }
+
+ private long count;
+
+ /**
+ * Get the count of unique values in the set data.
+ *
+ * @return the count of unique values
+ */
+ public long count() {
+ return count;
+ }
+
+ @Override
+ public UniqueData<T> newData() {
+ UniqueData<T> data = new UniqueData<T>();
+ data.set = new HashSet<>();
+ data.exists = false;
+ return data;
+ }
+
+ Set<T> tempSet;
+ @Override
+ protected void apply(UniqueData<T> data) {
+ data.set.addAll(tempSet);
+ }
+
+ Iterator<T> iter;
+ public int startExport() {
+ iter = ioData.set.iterator();
+ return ioData.set.size();
+ }
+ public T exportNext() {
+ return iter.next();
+ }
+
+ @Override
+ public void setMergedData(ReductionData data) {
+ count = ((UniqueData<?>)data).set.size();
+ }
+
+ @Override
+ public void setData(ReductionData data) {
+ count = ((UniqueData<?>)data).set.size();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ public static class UniqueData<T> extends ReductionData {
+ Set<T> set;
+ }
+
+ public static class UniqueIntCollector extends UniqueCollector<Integer> {
+ private IntValueStream param;
+
+ public UniqueIntCollector(IntValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempSet.clear();
+ param.streamInts( val -> tempSet.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new IntArrayReservation(
+ value -> ioData.set.add(value),
+ size -> {},
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class UniqueLongCollector extends UniqueCollector<Long> {
+ private LongValueStream param;
+
+ public UniqueLongCollector(LongValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempSet.clear();
+ param.streamLongs( val -> tempSet.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new LongArrayReservation(
+ value -> ioData.set.add(value),
+ size -> {},
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class UniqueFloatCollector extends UniqueCollector<Float> {
+ private FloatValueStream param;
+
+ public UniqueFloatCollector(FloatValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempSet.clear();
+ param.streamFloats( val -> tempSet.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new FloatArrayReservation(
+ value -> ioData.set.add(value),
+ size -> {},
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class UniqueDoubleCollector extends UniqueCollector<Double> {
+ private DoubleValueStream param;
+
+ public UniqueDoubleCollector(DoubleValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempSet.clear();
+ param.streamDoubles( val -> tempSet.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new DoubleArrayReservation(
+ value -> ioData.set.add(value),
+ size -> {},
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+
+ public static class UniqueStringCollector extends UniqueCollector<String> {
+ private StringValueStream param;
+
+ public UniqueStringCollector(StringValueStream param) {
+ super(param);
+ this.param = param;
+ }
+
+ @Override
+ public void collect() {
+ tempSet.clear();
+ param.streamStrings( val -> tempSet.add(val) );
+ }
+
+ @Override
+ public void submitReservations(Consumer<ReductionDataReservation<?,?>> consumer) {
+ consumer.accept(new StringArrayReservation(
+ value -> ioData.set.add(value),
+ size -> {},
+ () -> exportNext(),
+ () -> startExport()
+ ));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/package-info.java
new file mode 100644
index 0000000..15b4d18
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/data/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Reduction data collectors to use while computing analytics expressions.
+ * For multi-sharded collections, this is the data that is sent from shard to shard.
+ */
+package org.apache.solr.analytics.function.reduction.data;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/package-info.java
new file mode 100644
index 0000000..ae45ef1
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Reduction functions to use for analytics expressions.
+ */
+package org.apache.solr.analytics.function.reduction;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/package-info.java
new file mode 100644
index 0000000..e5bd519
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * A solr component to compute complex analytics over search results.
+ */
+package org.apache.solr.analytics;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AbstractFieldFacetRequest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AbstractFieldFacetRequest.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AbstractFieldFacetRequest.java
deleted file mode 100644
index 8121f56..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AbstractFieldFacetRequest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.analytics.request;
-
-import org.apache.solr.schema.SchemaField;
-
-/**
- * An abstract request for a facet over a single field, such as a field or range facet.
- */
-public abstract class AbstractFieldFacetRequest implements FacetRequest {
- protected SchemaField field = null;
-
- public AbstractFieldFacetRequest(SchemaField field) {
- this.field = field;
- }
-
- public SchemaField getField() {
- return field;
- }
-
- public void setField(SchemaField field) {
- this.field = field;
- }
-
- public String getName() {
- return field.getName();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsContentHandler.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsContentHandler.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsContentHandler.java
deleted file mode 100644
index b93a59e..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/request/AnalyticsContentHandler.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * 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.analytics.request;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortDirection;
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortSpecification;
-import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
-import org.apache.solr.common.params.FacetParams.FacetRangeOther;
-import org.apache.solr.schema.IndexSchema;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-
-/**
- * Handles the parsing of the AnalysisRequestEnvelope elements if passed in through XML.
- */
-public class AnalyticsContentHandler implements ContentHandler {
- // XML Element/Attribute Name Constants
- public static final String ANALYTICS_REQUEST_ENVELOPE="analyticsRequestEnvelope";
-
- public static final String ANALYTICS_REQUEST="analyticsRequest";
- public static final String NAME="name";
-
- public static final String STATISTIC="statistic";
- public static final String EXPRESSION="expression";
-
- public static final String FIELD_FACET="fieldFacet";
- public static final String FIELD="field";
- public static final String SHOW_MISSING="showMissing";
- public static final String LIMIT="limit";
- public static final String MIN_COUNT="minCount";
-
- public static final String SORT_SPECIFICATION="sortSpecification";
- public static final String STAT_NAME="statName";
- public static final String DIRECTION="direction";
-
- public static final String RANGE_FACET="rangeFacet";
- public static final String START="start";
- public static final String END="end";
- public static final String GAP="gap";
- public static final String INCLUDE_BOUNDARY="includeBoundary";
- public static final String OTHER_RANGE="otherRange";
- public static final String HARD_END="hardend";
-
- public static final String QUERY_FACET="queryFacet";
- public static final String QUERY="query";
-
- // Default Values
- public static final int DEFAULT_FACET_LIMIT = -1;
- public static final boolean DEFAULT_FACET_HARDEND = false;
- public static final int DEFAULT_FACET_MINCOUNT = 0;
- public static final boolean DEFAULT_FACET_FIELD_SHOW_MISSING = false;
-
- boolean inEnvelope = false;
- boolean inRequest = false;
- boolean inStatistic = false;
- boolean inFieldFacet = false;
- boolean inSortSpecification = false;
- boolean inQueryFacet = false;
- boolean inRangeFacet = false;
-
- private final IndexSchema schema;
-
- // Objects to use while building the Analytics Requests
-
- String currentElementText;
-
- List<AnalyticsRequest> requests;
-
- AnalyticsRequest analyticsRequest;
- List<ExpressionRequest> expressionList;
- List<FieldFacetRequest> fieldFacetList;
- List<RangeFacetRequest> rangeFacetList;
- List<QueryFacetRequest> queryFacetList;
-
- ExpressionRequest expression;
-
- FieldFacetRequest fieldFacet;
- int limit;
- int minCount;
- boolean showMissing;
- FacetSortSpecification sortSpecification;
-
- RangeFacetRequest rangeFacet;
- boolean hardend;
- List<String> gaps;
- EnumSet<FacetRangeInclude> includeBoundaries;
- EnumSet<FacetRangeOther> otherRanges;
-
- String queryName;
- List<String> queries;
-
- public AnalyticsContentHandler(IndexSchema schema) {
- this.schema = schema;
- }
-
- @Override
- public void setDocumentLocator(Locator locator) { }
-
- @Override
- public void startDocument() throws SAXException { }
-
- @Override
- public void endDocument() throws SAXException { }
-
- @Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException { }
-
- @Override
- public void endPrefixMapping(String prefix) throws SAXException { }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
- currentElementText = "";
- if (inEnvelope) {
- if (inRequest) {
- if (localName.equals(STATISTIC)) {
- // Start a Statistic Request
- inStatistic = true;
- } else if (inFieldFacet) {
- if (localName.equals(SORT_SPECIFICATION)) {
- // Start a Sort Specification
- inSortSpecification = true;
- sortSpecification = new FacetSortSpecification();
- }
- } else if (localName.equals(FIELD_FACET)) {
- // Start a Field Facet Request
- // Get attributes (limit, minCount, showMissing)
- String att = atts.getValue(uri,LIMIT);
- if (att!=null) {
- limit = Integer.parseInt(att);
- } else {
- limit = DEFAULT_FACET_LIMIT;
- }
- att = atts.getValue(uri,MIN_COUNT);
- if (att!=null) {
- minCount = Integer.parseInt(att);
- } else {
- minCount = DEFAULT_FACET_MINCOUNT;
- }
- att = atts.getValue(uri,SHOW_MISSING);
- if (att!=null) {
- showMissing = Boolean.parseBoolean(att);
- } else {
- showMissing = DEFAULT_FACET_FIELD_SHOW_MISSING;
- }
-
- inFieldFacet = true;
- } else if (localName.equals(RANGE_FACET)) {
- // Start a Range Facet Request
- // Get attributes (hardEnd)
- String att = atts.getValue(uri,HARD_END);
- if (att!=null) {
- hardend = Boolean.parseBoolean(att);
- } else {
- hardend = false;
- }
-
- // Initiate Range Facet classes
- gaps = new ArrayList<>();
- includeBoundaries = EnumSet.noneOf(FacetRangeInclude.class);
- otherRanges = EnumSet.noneOf(FacetRangeOther.class);
- inRangeFacet = true;
- } else if (localName.equals(QUERY_FACET)) {
- // Start a Query Facet Request
- queries = new ArrayList<>();
- inQueryFacet = true;
- }
- } else if (localName.equals(ANALYTICS_REQUEST)){
- // Start an Analytics Request
-
- // Renew each list.
- fieldFacetList = new ArrayList<>();
- rangeFacetList = new ArrayList<>();
- queryFacetList = new ArrayList<>();
- expressionList = new ArrayList<>();
- inRequest = true;
- }
- } else if (localName.equals(ANALYTICS_REQUEST_ENVELOPE)){
- //Begin the parsing of the Analytics Requests
- requests = new ArrayList<>();
- inEnvelope = true;
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (inEnvelope) {
- if (inRequest) {
- if (inStatistic) {
- if (localName.equals(EXPRESSION)) {
- expression = new ExpressionRequest(currentElementText,currentElementText);
- } else if (localName.equals(NAME)) {
- expression.setName(currentElementText);
- } else if (localName.equals(STATISTIC)) {
- // Finished Parsing the Statistic Request
- expressionList.add(expression);
- inStatistic = false;
- }
- } else if (inFieldFacet) {
- if (inSortSpecification) {
- if (localName.equals(STAT_NAME)) {
- sortSpecification.setStatistic(currentElementText);
- } else if (localName.equals(DIRECTION)) {
- sortSpecification.setDirection(FacetSortDirection.fromExternal(currentElementText));
- } else if (localName.equals(SORT_SPECIFICATION)) {
- // Finished Parsing the Sort Specification
- fieldFacet.setSort(sortSpecification);
- inSortSpecification = false;
- }
- } else if (localName.equals(FIELD)) {
- fieldFacet = new FieldFacetRequest(schema.getField(currentElementText));
- } else if (localName.equals(FIELD_FACET)) {
- // Finished Parsing the Field Facet Request
- fieldFacet.setLimit(limit);
- fieldFacet.showMissing(showMissing);
- fieldFacetList.add(fieldFacet);
- inFieldFacet = false;
- }
- } else if (inRangeFacet) {
- if (localName.equals(FIELD)) {
- rangeFacet = new RangeFacetRequest(schema.getField(currentElementText), "", "", new String[1]);
- } else if (localName.equals(START)) {
- rangeFacet.setStart(currentElementText);
- } else if (localName.equals(END)) {
- rangeFacet.setEnd(currentElementText);
- } else if (localName.equals(GAP)) {
- gaps.add(currentElementText);
- } else if (localName.equals(INCLUDE_BOUNDARY)) {
- includeBoundaries.add(FacetRangeInclude.get(currentElementText));
- } else if (localName.equals(OTHER_RANGE)) {
- otherRanges.add(FacetRangeOther.get(currentElementText));
- } else if (localName.equals(RANGE_FACET)) {
- // Finished Parsing the Range Facet Request
- rangeFacet.setHardEnd(hardend);
- rangeFacet.setGaps(gaps.toArray(new String[1]));
- rangeFacet.setInclude(includeBoundaries);
- rangeFacet.setOthers(otherRanges);
- inRangeFacet = false;
- rangeFacetList.add(rangeFacet);
- }
- } else if (inQueryFacet) {
- if (localName.equals(NAME)) {
- queryName = currentElementText;
- } else if (localName.equals(QUERY)) {
- queries.add(currentElementText);
- } else if (localName.equals(QUERY_FACET)) {
- // Finished Parsing the Query Facet Request
- QueryFacetRequest temp = new QueryFacetRequest(queryName);
- temp.setQueries(queries);
- queryFacetList.add(temp);
- inQueryFacet = false;
- }
- } else if (localName.equals(NAME)) {
- analyticsRequest = new AnalyticsRequest(currentElementText);
- } else if (localName.equals(ANALYTICS_REQUEST)){
- // Finished Parsing the Analytics Request
- analyticsRequest.setExpressions(expressionList);
- analyticsRequest.setFieldFacets(fieldFacetList);
- analyticsRequest.setRangeFacets(rangeFacetList);
- analyticsRequest.setQueryFacets(queryFacetList);
- requests.add(analyticsRequest);
- inRequest = false;
- }
- } else if (localName.equals(ANALYTICS_REQUEST_ENVELOPE)){
- // Finished Parsing
- inEnvelope = false;
- }
- }
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- currentElementText += new String(ch,start,length);
- }
-
- @Override
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { }
-
- @Override
- public void processingInstruction(String target, String data) throws SAXException { }
-
- @Override
- public void skippedEntity(String name) throws SAXException { }
-
- /**
- * Returns the list of Analytics Requests built during parsing.
- *
- * @return List of {@link AnalyticsRequest} objects specified by the given XML file
- */
- public List<AnalyticsRequest> getAnalyticsRequests() {
- return requests;
- }
-
-}
[13/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogFunction.java
new file mode 100644
index 0000000..313f2e2
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A logarithm mapping function.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If one numeric Value or ValueStream is passed in, a {@link DoubleValue} or {@link DoubleValueStream}
+ * representing the natural logarithm is returned.
+ * <li>If two numeric Values are passed in, a {@link DoubleValue} representing the logarithm of the first with the second as the base is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the logarithm of
+ * the Value with each of the values of the ValueStream for a document as the base is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * </ul>
+ */
+public class LogFunction {
+ public static final String name = "log";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1.");
+ } else if (params.length == 1) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a) -> Math.log(a), (DoubleValueStream)params[0]);
+ } else if (params.length == 2) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> Math.log(a)/Math.log(b), (DoubleValueStream)params[0], (DoubleValueStream)params[1]);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function accepts at most 2 paramaters, " + params.length + " found.");
+ }
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogicFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogicFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogicFunction.java
new file mode 100644
index 0000000..806cb0a
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LogicFunction.java
@@ -0,0 +1,90 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoBoolInBoolOutLambda;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * Contains all logical mapping functions.
+ * <p>
+ * Logical mapping functions can be used in the following ways:
+ * <ul>
+ * <li>If a single {@link BooleanValueStream} is passed in, a {@link BooleanValue} representing the logical operation
+ * on all of the values for each document is returned.
+ * <li>If a {@link BooleanValueStream} and a {@link BooleanValue} are passed in, a {@link BooleanValue} representing the logical operation on
+ * the {@link BooleanValue} and each of the values of the {@link BooleanValueStream} for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * <li>If multiple {@link BooleanValue}s are passed in, a {@link BooleanValue} representing the logical operation on all values is returned.
+ * </ul>
+ */
+public class LogicFunction {
+
+ private static BooleanValueStream createBitwiseFunction(String name, TwoBoolInBoolOutLambda comp, AnalyticsValueStream... params) {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires parameters.");
+ }
+ else if (params.length == 1) {
+ if (params[0] instanceof BooleanValueStream) {
+ return LambdaFunction.createBooleanLambdaFunction(name, comp, (BooleanValueStream)params[0]);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires boolean parameters. Incorrect param: "+params[0].getExpressionStr());
+ }
+ else if (params.length == 2) {
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof BooleanValueStream && param2 instanceof BooleanValueStream) {
+ return LambdaFunction.createBooleanLambdaFunction(name, (a,b) -> a && b, (BooleanValueStream)param1, (BooleanValueStream)param2);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires boolean parameters.");
+ }
+ BooleanValue[] castedParams = new BooleanValue[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof BooleanValue) {
+ castedParams[i] = (BooleanValue) params[i];
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that all parameters be single-valued if more than 2 are given.");
+ }
+ }
+ return LambdaFunction.createBooleanLambdaFunction(name, comp, castedParams);
+ };
+
+ /**
+ * A mapping function for the logical operation AND.
+ */
+ public static class AndFunction {
+ public static final String name = "and";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return LogicFunction.createBitwiseFunction(name, (a,b) -> a && b, params);
+ });
+ }
+
+ /**
+ * A mapping function for the logical operation OR.
+ */
+ public static class OrFunction {
+ public static final String name = "or";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return LogicFunction.createBitwiseFunction(name, (a,b) -> a || b, params);
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/MultFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/MultFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/MultFunction.java
new file mode 100644
index 0000000..4a5b173
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/MultFunction.java
@@ -0,0 +1,68 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+
+/**
+ * An multiplication mapping function.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If a single numeric ValueStream is passed in, a {@link DoubleValue} representing the multiplication of the values for each document is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the multiplication of
+ * the Value and each of the values of the ValueStream for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * <li>If multiple numeric Values are passed in, a {@link DoubleValue} representing the multiplication of all values is returned.
+ * </ul>
+ */
+public class MultFunction {
+ public static final String name = "mult";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires parameters.");
+ }
+ else if (params.length == 1) {
+ if (params[0] instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a*b, (DoubleValueStream)params[0]);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters. Incorrect param: "+params[0].getExpressionStr());
+ }
+ else if (params.length == 2) {
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof DoubleValueStream && param2 instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a*b, (DoubleValueStream)param1, (DoubleValueStream)param2);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters.");
+ }
+ DoubleValue[] castedParams = new DoubleValue[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DoubleValue) {
+ castedParams[i] = (DoubleValue) params[i];
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires that all parameters be single-valued if more than 2 are given.");
+ }
+ }
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a*b, castedParams);
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NegateFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NegateFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NegateFunction.java
new file mode 100644
index 0000000..65916e6
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NegateFunction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A negation mapping function.
+ * <p>
+ * Takes a numeric or boolean ValueStream or Value and returns a ValueStream or Value of the same numeric type.
+ */
+public class NegateFunction {
+ public static final String name = "neg";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof BooleanValueStream) {
+ return LambdaFunction.createBooleanLambdaFunction(name, x -> !x, (BooleanValueStream)param);
+ }
+ if (param instanceof IntValueStream) {
+ return LambdaFunction.createIntLambdaFunction(name, x -> x*-1, (IntValueStream)param);
+ }
+ if (param instanceof LongValueStream) {
+ return LambdaFunction.createLongLambdaFunction(name, x -> x*-1, (LongValueStream)param);
+ }
+ if (param instanceof FloatValueStream) {
+ return LambdaFunction.createFloatLambdaFunction(name, x -> x*-1, (FloatValueStream)param);
+ }
+ if (param instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, x -> x*-1, (DoubleValueStream)param);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a boolean or numeric parameter, "+param.getExpressionStr()+" found.");
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NumericConvertFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NumericConvertFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NumericConvertFunction.java
new file mode 100644
index 0000000..2381f60
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/NumericConvertFunction.java
@@ -0,0 +1,256 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * An abstract numeric converting mapping function. For example "round()" would convert a float to an int and a double to a long.
+ * <p>
+ * Takes a numeric Double or Float ValueStream or Value and returns a Long or Int ValueStream or Value, repectively.
+ */
+public class NumericConvertFunction {
+
+ private static LongValueStream createConvertFunction(String name, ConvertFloatFunction fconv, ConvertDoubleFunction dconv, AnalyticsValueStream... params) {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof FloatValueStream) {
+ if (param instanceof FloatValue) {
+ return new ConvertFloatValueFunction(name, (FloatValue)param, fconv);
+ }
+ return new ConvertFloatStreamFunction(name, (FloatValueStream)param, fconv);
+ } else if (param instanceof DoubleValueStream) {
+ if (param instanceof DoubleValue) {
+ return new ConvertDoubleValueFunction(name, (DoubleValue)param, dconv);
+ }
+ return new ConvertDoubleStreamFunction(name, (DoubleValueStream)param, dconv);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a numeric parameter.");
+ }
+ }
+
+ /**
+ * A numeric mapping function that returns the floor of the input.
+ */
+ public static class FloorFunction {
+ public static final String name = "floor";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return NumericConvertFunction.createConvertFunction(name, val -> (int)Math.floor(val), val -> (long)Math.floor(val), params);
+ });
+ }
+
+ /**
+ * A numeric mapping function that returns the ceiling of the input.
+ */
+ public static class CeilingFunction {
+ public static final String name = "ceil";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return NumericConvertFunction.createConvertFunction(name, val -> (int)Math.ceil(val), val -> (long)Math.ceil(val), params);
+ });
+ }
+
+ /**
+ * A numeric mapping function that returns the rounded input.
+ */
+ public static class RoundFunction {
+ public static final String name = "round";
+ public static final CreatorFunction creatorFunction = (params -> {
+ return NumericConvertFunction.createConvertFunction(name, val -> (int)Math.round(val), val -> (long)Math.round(val), params);
+ });
+ }
+
+}
+@FunctionalInterface
+interface ConvertFloatFunction {
+ public int convert(float value);
+}
+@FunctionalInterface
+interface ConvertDoubleFunction {
+ public long convert(double value);
+}
+/**
+ * A function to convert a {@link FloatValue} to a {@link IntValue}.
+ */
+class ConvertFloatValueFunction extends AbstractIntValue {
+ private final String name;
+ private final FloatValue param;
+ private final ConvertFloatFunction conv;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public ConvertFloatValueFunction(String name, FloatValue param, ConvertFloatFunction conv) {
+ this.name = name;
+ this.param = param;
+ this.conv = conv;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,param);
+ }
+
+ @Override
+ public int getInt() {
+ return conv.convert(param.getFloat());
+ }
+ @Override
+ public boolean exists() {
+ return param.exists();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A function to convert a {@link FloatValueStream} to a {@link IntValueStream}.
+ */
+class ConvertFloatStreamFunction extends AbstractIntValueStream {
+ private final String name;
+ private final FloatValueStream param;
+ private final ConvertFloatFunction conv;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public ConvertFloatStreamFunction(String name, FloatValueStream param, ConvertFloatFunction conv) {
+ this.name = name;
+ this.param = param;
+ this.conv = conv;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,param);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ param.streamFloats( value -> cons.accept(conv.convert(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A function to convert a {@link DoubleValue} to a {@link LongValue}.
+ */
+class ConvertDoubleValueFunction extends AbstractLongValue {
+ private final String name;
+ private final DoubleValue param;
+ private final ConvertDoubleFunction conv;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public ConvertDoubleValueFunction(String name, DoubleValue param, ConvertDoubleFunction conv) {
+ this.name = name;
+ this.param = param;
+ this.conv = conv;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,param);
+ }
+
+ @Override
+ public long getLong() {
+ return conv.convert(param.getDouble());
+ }
+ @Override
+ public boolean exists() {
+ return param.exists();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+/**
+ * A function to convert a {@link DoubleValueStream} to a {@link LongValueStream}.
+ */
+class ConvertDoubleStreamFunction extends AbstractLongValueStream {
+ private final String name;
+ private final DoubleValueStream param;
+ private final ConvertDoubleFunction conv;
+ private final String funcStr;
+ private final ExpressionType funcType;
+
+ public ConvertDoubleStreamFunction(String name, DoubleValueStream param, ConvertDoubleFunction conv) {
+ this.name = name;
+ this.param = param;
+ this.conv = conv;
+ this.funcStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(funcStr,param);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ param.streamDoubles( value -> cons.accept(conv.convert(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return funcStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/PowerFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/PowerFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/PowerFunction.java
new file mode 100644
index 0000000..0688ba0
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/PowerFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A power mapping function.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If two numeric Values are passed in, a {@link DoubleValue} representing the first taken to the power of the second is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the power of
+ * the Value to each of the values of the ValueStream for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * </ul>
+ */
+public class PowerFunction {
+ public static final String name = "pow";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof DoubleValueStream && param2 instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> Math.pow(a,b), (DoubleValueStream)param1, (DoubleValueStream)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters.");
+ }
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/RemoveFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/RemoveFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/RemoveFunction.java
new file mode 100644
index 0000000..5800a1b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/RemoveFunction.java
@@ -0,0 +1,796 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.AnalyticsValue.AbstractAnalyticsValue;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function to remove an {@link AnalyticsValue} from an {@link AnalyticsValue} or an {@link AnalyticsValueStream}.
+ * For each document, the value exists if it doesn't equal the value of the second parameter.
+ * <p>
+ * The first parameter can be any type of analytics expression. If the parameter is multi-valued, then the return will be multi-valued. (Required)
+ * <br>
+ * The second parameter, which is the value to remove from the first parameter, must be an {@link AnalyticsValue}, aka single-valued. (Required)
+ * <p>
+ * The resulting Value or ValueStream will be typed with the closest super-type of the two parameters.
+ * (e.g. {@value #name}(int,float) will return a float)
+ */
+public class RemoveFunction {
+ public static final String name = "remove";
+
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ if (!(params[1] instanceof AnalyticsValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the remove paramater to be single-valued.");
+ }
+
+ AnalyticsValueStream baseExpr = params[0];
+ AnalyticsValue removeExpr = (AnalyticsValue)params[1];
+
+ if (baseExpr instanceof DateValue && removeExpr instanceof DateValue) {
+ return new DateRemoveFunction((DateValue)baseExpr,(DateValue)removeExpr);
+ }
+ if (baseExpr instanceof DateValueStream && removeExpr instanceof DateValue) {
+ return new DateStreamRemoveFunction((DateValueStream)baseExpr,(DateValue)removeExpr);
+ }
+ if (baseExpr instanceof BooleanValue && removeExpr instanceof BooleanValue) {
+ return new BooleanRemoveFunction((BooleanValue)baseExpr,(BooleanValue)removeExpr);
+ }
+ if (baseExpr instanceof BooleanValueStream && removeExpr instanceof BooleanValue) {
+ return new BooleanStreamRemoveFunction((BooleanValueStream)baseExpr,(BooleanValue)removeExpr);
+ }
+ if (baseExpr instanceof IntValue && removeExpr instanceof IntValue) {
+ return new IntRemoveFunction((IntValue)baseExpr,(IntValue)removeExpr);
+ }
+ if (baseExpr instanceof IntValueStream && removeExpr instanceof IntValue) {
+ return new IntStreamRemoveFunction((IntValueStream)baseExpr,(IntValue)removeExpr);
+ }
+ if (baseExpr instanceof LongValue && removeExpr instanceof LongValue) {
+ return new LongRemoveFunction((LongValue)baseExpr,(LongValue)removeExpr);
+ }
+ if (baseExpr instanceof LongValueStream && removeExpr instanceof LongValue) {
+ return new LongStreamRemoveFunction((LongValueStream)baseExpr,(LongValue)removeExpr);
+ }
+ if (baseExpr instanceof FloatValue && removeExpr instanceof FloatValue) {
+ return new FloatRemoveFunction((FloatValue)baseExpr,(FloatValue)removeExpr);
+ }
+ if (baseExpr instanceof FloatValueStream && removeExpr instanceof FloatValue) {
+ return new FloatStreamRemoveFunction((FloatValueStream)baseExpr,(FloatValue)removeExpr);
+ }
+ if (baseExpr instanceof DoubleValue && removeExpr instanceof DoubleValue) {
+ return new DoubleRemoveFunction((DoubleValue)baseExpr,(DoubleValue)removeExpr);
+ }
+ if (baseExpr instanceof DoubleValueStream && removeExpr instanceof DoubleValue) {
+ return new DoubleStreamRemoveFunction((DoubleValueStream)baseExpr,(DoubleValue)removeExpr);
+ }
+ if (baseExpr instanceof StringValue && removeExpr instanceof StringValue) {
+ return new StringRemoveFunction((StringValue)baseExpr,(StringValue)removeExpr);
+ }
+ if (baseExpr instanceof StringValueStream && removeExpr instanceof StringValue) {
+ return new StringStreamRemoveFunction((StringValueStream)baseExpr,(StringValue)removeExpr);
+ }
+ if (baseExpr instanceof AnalyticsValue) {
+ return new ValueRemoveFunction((AnalyticsValue)baseExpr,removeExpr);
+ }
+ return new StreamRemoveFunction(baseExpr,removeExpr);
+ });
+}
+class StreamRemoveFunction implements AnalyticsValueStream {
+ private final AnalyticsValueStream baseExpr;
+ private final AnalyticsValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StreamRemoveFunction(AnalyticsValueStream baseExpr, AnalyticsValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object removeValue = removeExpr.getObject();
+ if (removeExpr.exists()) {
+ baseExpr.streamObjects(value -> {
+ if (removeValue.equals(value)) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamObjects(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class ValueRemoveFunction extends AbstractAnalyticsValue {
+ private final AnalyticsValue baseExpr;
+ private final AnalyticsValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public ValueRemoveFunction(AnalyticsValue baseExpr, AnalyticsValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public Object getObject() {
+ Object value = baseExpr.getObject();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value.equals(removeExpr.toString()) ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamRemoveFunction extends AbstractBooleanValueStream {
+ private final BooleanValueStream baseExpr;
+ private final BooleanValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamRemoveFunction(BooleanValueStream baseExpr, BooleanValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean removeValue = removeExpr.getBoolean();
+ if (removeExpr.exists()) {
+ baseExpr.streamBooleans(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamBooleans(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanRemoveFunction extends AbstractBooleanValue {
+ private final BooleanValue baseExpr;
+ private final BooleanValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanRemoveFunction(BooleanValue baseExpr, BooleanValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = baseExpr.getBoolean();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getBoolean() ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamRemoveFunction extends AbstractIntValueStream {
+ private final IntValueStream baseExpr;
+ private final IntValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamRemoveFunction(IntValueStream baseExpr, IntValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ int removeValue = removeExpr.getInt();
+ if (removeExpr.exists()) {
+ baseExpr.streamInts(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamInts(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntRemoveFunction extends AbstractIntValue {
+ private final IntValue baseExpr;
+ private final IntValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntRemoveFunction(IntValue baseExpr, IntValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = baseExpr.getInt();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getInt() ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamRemoveFunction extends AbstractLongValueStream {
+ private final LongValueStream baseExpr;
+ private final LongValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamRemoveFunction(LongValueStream baseExpr, LongValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long removeValue = removeExpr.getLong();
+ if (removeExpr.exists()) {
+ baseExpr.streamLongs(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongRemoveFunction extends AbstractLongValue {
+ private final LongValue baseExpr;
+ private final LongValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongRemoveFunction(LongValue baseExpr, LongValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getLong() ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamRemoveFunction extends AbstractFloatValueStream {
+ private final FloatValueStream baseExpr;
+ private final FloatValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamRemoveFunction(FloatValueStream baseExpr, FloatValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float removeValue = removeExpr.getFloat();
+ if (removeExpr.exists()) {
+ baseExpr.streamFloats(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamFloats(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatRemoveFunction extends AbstractFloatValue {
+ private final FloatValue baseExpr;
+ private final FloatValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatRemoveFunction(FloatValue baseExpr, FloatValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = baseExpr.getFloat();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getFloat() ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleStreamRemoveFunction extends AbstractDoubleValueStream {
+ private final DoubleValueStream baseExpr;
+ private final DoubleValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleStreamRemoveFunction(DoubleValueStream baseExpr, DoubleValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double removeValue = removeExpr.getDouble();
+ if (removeExpr.exists()) {
+ baseExpr.streamDoubles(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamDoubles(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleRemoveFunction extends AbstractDoubleValue {
+ private final DoubleValue baseExpr;
+ private final DoubleValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleRemoveFunction(DoubleValue baseExpr, DoubleValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public double getDouble() {
+ double value = baseExpr.getDouble();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getDouble() ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateStreamRemoveFunction extends AbstractDateValueStream {
+ private final DateValueStream baseExpr;
+ private final DateValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateStreamRemoveFunction(DateValueStream baseExpr, DateValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long removeValue = removeExpr.getLong();
+ if (removeExpr.exists()) {
+ baseExpr.streamLongs(value -> {
+ if (removeValue==value) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateRemoveFunction extends AbstractDateValue {
+ private final DateValue baseExpr;
+ private final DateValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateRemoveFunction(DateValue baseExpr, DateValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value==removeExpr.getLong() ? removeExpr.exists() ? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamRemoveFunction extends AbstractStringValueStream {
+ private final StringValueStream baseExpr;
+ private final StringValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringStreamRemoveFunction(StringValueStream baseExpr, StringValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String removeValue = removeExpr.toString();
+ if (removeExpr.exists()) {
+ baseExpr.streamStrings(value -> {
+ if (removeValue.equals(value)) cons.accept(value);
+ });
+ } else {
+ baseExpr.streamStrings(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringRemoveFunction extends AbstractStringValue {
+ private final StringValue baseExpr;
+ private final StringValue removeExpr;
+ public static final String name = RemoveFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringRemoveFunction(StringValue baseExpr, StringValue removeExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.removeExpr = removeExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,removeExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,removeExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public String getString() {
+ String value = baseExpr.getString();
+ exists = false;
+ if (baseExpr.exists()) {
+ exists = value.equals(removeExpr.getString()) ? removeExpr.exists()? false : true : true;
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ReplaceFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ReplaceFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ReplaceFunction.java
new file mode 100644
index 0000000..0d9e278
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/ReplaceFunction.java
@@ -0,0 +1,914 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.AnalyticsValue.AbstractAnalyticsValue;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function to replace an {@link AnalyticsValue} from an {@link AnalyticsValue} or an {@link AnalyticsValueStream}
+ * with a different {@link AnalyticsValue}.
+ * For each document, all values from the base parameter matching the comparison parameter will be replaced with the fill parameter.
+ * <p>
+ * The first parameter can be any type of analytics expression. If the parameter is multi-valued, then the return will be multi-valued. (Required)
+ * <br>
+ * The second parameter, which is the value to compare to the first parameter, must be an {@link AnalyticsValue}, aka single-valued. (Required)
+ * <br>
+ * The third parameter, which is the value to fill the first parameter with, must be an {@link AnalyticsValue}, aka single-valued. (Required)
+ * <p>
+ * The resulting Value or ValueStream will be typed with the closest super-type of the three parameters.
+ * (e.g. {@value #name}(double,int,float) will return a double)
+ */
+public class ReplaceFunction {
+ public static final String name = "replace";
+
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 3) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 3 paramaters, " + params.length + " found.");
+ }
+ if (!(params[1] instanceof AnalyticsValue && params[2] instanceof AnalyticsValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the comparator and fill parameters to be single-valued.");
+ }
+
+ AnalyticsValueStream baseExpr = params[0];
+ AnalyticsValue compExpr = (AnalyticsValue)params[1];
+ AnalyticsValue fillExpr = (AnalyticsValue)params[2];
+
+ if (baseExpr instanceof DateValue && compExpr instanceof DateValue && fillExpr instanceof DateValue) {
+ return new DateReplaceFunction((DateValue)baseExpr,(DateValue)compExpr,(DateValue)fillExpr);
+ }
+ if (baseExpr instanceof DateValueStream && compExpr instanceof DateValue && fillExpr instanceof DateValue) {
+ return new DateStreamReplaceFunction((DateValueStream)baseExpr,(DateValue)compExpr,(DateValue)fillExpr);
+ }
+ if (baseExpr instanceof BooleanValue && compExpr instanceof BooleanValue && fillExpr instanceof BooleanValue) {
+ return new BooleanReplaceFunction((BooleanValue)baseExpr,(BooleanValue)compExpr,(BooleanValue)fillExpr);
+ }
+ if (baseExpr instanceof BooleanValueStream && compExpr instanceof BooleanValue && fillExpr instanceof BooleanValue) {
+ return new BooleanStreamReplaceFunction((BooleanValueStream)baseExpr,(BooleanValue)compExpr,(BooleanValue)fillExpr);
+ }
+ if (baseExpr instanceof IntValue && compExpr instanceof IntValue && fillExpr instanceof IntValue) {
+ return new IntReplaceFunction((IntValue)baseExpr,(IntValue)compExpr,(IntValue)fillExpr);
+ }
+ if (baseExpr instanceof IntValueStream && compExpr instanceof IntValue && fillExpr instanceof IntValue) {
+ return new IntStreamReplaceFunction((IntValueStream)baseExpr,(IntValue)compExpr,(IntValue)fillExpr);
+ }
+ if (baseExpr instanceof LongValue && compExpr instanceof LongValue && fillExpr instanceof LongValue) {
+ return new LongReplaceFunction((LongValue)baseExpr,(LongValue)compExpr,(LongValue)fillExpr);
+ }
+ if (baseExpr instanceof LongValueStream && compExpr instanceof LongValue && fillExpr instanceof LongValue) {
+ return new LongStreamReplaceFunction((LongValueStream)baseExpr,(LongValue)compExpr,(LongValue)fillExpr);
+ }
+ if (baseExpr instanceof FloatValue && compExpr instanceof FloatValue && fillExpr instanceof FloatValue) {
+ return new FloatReplaceFunction((FloatValue)baseExpr,(FloatValue)compExpr,(FloatValue)fillExpr);
+ }
+ if (baseExpr instanceof FloatValueStream && compExpr instanceof FloatValue && fillExpr instanceof FloatValue) {
+ return new FloatStreamReplaceFunction((FloatValueStream)baseExpr,(FloatValue)compExpr,(FloatValue)fillExpr);
+ }
+ if (baseExpr instanceof DoubleValue && compExpr instanceof DoubleValue && fillExpr instanceof DoubleValue) {
+ return new DoubleReplaceFunction((DoubleValue)baseExpr,(DoubleValue)compExpr,(DoubleValue)fillExpr);
+ }
+ if (baseExpr instanceof DoubleValueStream && compExpr instanceof DoubleValue && fillExpr instanceof DoubleValue) {
+ return new DoubleStreamReplaceFunction((DoubleValueStream)baseExpr,(DoubleValue)compExpr,(DoubleValue)fillExpr);
+ }
+ if (baseExpr instanceof StringValue && compExpr instanceof StringValue && fillExpr instanceof StringValue) {
+ return new StringReplaceFunction((StringValue)baseExpr,(StringValue)compExpr,(StringValue)fillExpr);
+ }
+ if (baseExpr instanceof StringValueStream && compExpr instanceof StringValue && fillExpr instanceof StringValue) {
+ return new StringStreamReplaceFunction((StringValueStream)baseExpr,(StringValue)compExpr,(StringValue)fillExpr);
+ }
+ if (baseExpr instanceof AnalyticsValue) {
+ return new ValueReplaceFunction((AnalyticsValue)baseExpr,(AnalyticsValue)compExpr,(AnalyticsValue)fillExpr);
+ }
+ return new StreamReplaceFunction(baseExpr,compExpr,fillExpr);
+
+ });
+}
+class StreamReplaceFunction implements AnalyticsValueStream {
+ private final AnalyticsValueStream baseExpr;
+ private final AnalyticsValue compExpr;
+ private final AnalyticsValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StreamReplaceFunction(AnalyticsValueStream baseExpr, AnalyticsValue compExpr, AnalyticsValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ Object compValue = compExpr.getObject();
+ if (compExpr.exists()) {
+ Object fillValue = fillExpr.getObject();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamObjects(value -> {
+ if (value.equals(compValue)) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamObjects(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class ValueReplaceFunction extends AbstractAnalyticsValue {
+ private final AnalyticsValue baseExpr;
+ private final AnalyticsValue compExpr;
+ private final AnalyticsValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public ValueReplaceFunction(AnalyticsValue baseExpr, AnalyticsValue compExpr, AnalyticsValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public Object getObject() {
+ Object value = baseExpr.getObject();
+ exists = baseExpr.exists();
+ Object comp = compExpr.getObject();
+ if (value.equals(comp) && exists==compExpr.exists()) {
+ value = fillExpr.getObject();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamReplaceFunction extends AbstractBooleanValueStream {
+ private final BooleanValueStream baseExpr;
+ private final BooleanValue compExpr;
+ private final BooleanValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamReplaceFunction(BooleanValueStream baseExpr, BooleanValue compExpr, BooleanValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean compValue = compExpr.getBoolean();
+ if (compExpr.exists()) {
+ boolean fillValue = fillExpr.getBoolean();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamBooleans(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamBooleans(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanReplaceFunction extends AbstractBooleanValue {
+ private final BooleanValue baseExpr;
+ private final BooleanValue compExpr;
+ private final BooleanValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanReplaceFunction(BooleanValue baseExpr, BooleanValue compExpr, BooleanValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = baseExpr.getBoolean();
+ exists = baseExpr.exists();
+ boolean comp = compExpr.getBoolean();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getBoolean();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamReplaceFunction extends AbstractIntValueStream {
+ private final IntValueStream baseExpr;
+ private final IntValue compExpr;
+ private final IntValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamReplaceFunction(IntValueStream baseExpr, IntValue compExpr, IntValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ int compValue = compExpr.getInt();
+ if (compExpr.exists()) {
+ int fillValue = fillExpr.getInt();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamInts(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamInts(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntReplaceFunction extends AbstractIntValue {
+ private final IntValue baseExpr;
+ private final IntValue compExpr;
+ private final IntValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntReplaceFunction(IntValue baseExpr, IntValue compExpr, IntValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = baseExpr.getInt();
+ exists = baseExpr.exists();
+ int comp = compExpr.getInt();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getInt();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamReplaceFunction extends AbstractLongValueStream {
+ private final LongValueStream baseExpr;
+ private final LongValue compExpr;
+ private final LongValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamReplaceFunction(LongValueStream baseExpr, LongValue compExpr, LongValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long compValue = compExpr.getLong();
+ if (compExpr.exists()) {
+ long fillValue = fillExpr.getLong();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamLongs(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongReplaceFunction extends AbstractLongValue {
+ private final LongValue baseExpr;
+ private final LongValue compExpr;
+ private final LongValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongReplaceFunction(LongValue baseExpr, LongValue compExpr, LongValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = baseExpr.exists();
+ long comp = compExpr.getLong();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getLong();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamReplaceFunction extends AbstractFloatValueStream {
+ private final FloatValueStream baseExpr;
+ private final FloatValue compExpr;
+ private final FloatValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamReplaceFunction(FloatValueStream baseExpr, FloatValue compExpr, FloatValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float compValue = compExpr.getFloat();
+ if (compExpr.exists()) {
+ float fillValue = fillExpr.getFloat();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamFloats(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamFloats(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatReplaceFunction extends AbstractFloatValue {
+ private final FloatValue baseExpr;
+ private final FloatValue compExpr;
+ private final FloatValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatReplaceFunction(FloatValue baseExpr, FloatValue compExpr, FloatValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = baseExpr.getFloat();
+ exists = baseExpr.exists();
+ float comp = compExpr.getFloat();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getFloat();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleStreamReplaceFunction extends AbstractDoubleValueStream {
+ private final DoubleValueStream baseExpr;
+ private final DoubleValue compExpr;
+ private final DoubleValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleStreamReplaceFunction(DoubleValueStream baseExpr, DoubleValue compExpr, DoubleValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ double compValue = compExpr.getDouble();
+ if (compExpr.exists()) {
+ double fillValue = fillExpr.getDouble();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamDoubles(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamDoubles(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DoubleReplaceFunction extends AbstractDoubleValue {
+ private final DoubleValue baseExpr;
+ private final DoubleValue compExpr;
+ private final DoubleValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DoubleReplaceFunction(DoubleValue baseExpr, DoubleValue compExpr, DoubleValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public double getDouble() {
+ double value = baseExpr.getDouble();
+ exists = baseExpr.exists();
+ double comp = compExpr.getDouble();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getDouble();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateStreamReplaceFunction extends AbstractDateValueStream {
+ private final DateValueStream baseExpr;
+ private final DateValue compExpr;
+ private final DateValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateStreamReplaceFunction(DateValueStream baseExpr, DateValue compExpr, DateValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long compValue = compExpr.getLong();
+ if (compExpr.exists()) {
+ long fillValue = fillExpr.getLong();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamLongs(value -> {
+ if (value==compValue) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamLongs(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class DateReplaceFunction extends AbstractDateValue {
+ private final DateValue baseExpr;
+ private final DateValue compExpr;
+ private final DateValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public DateReplaceFunction(DateValue baseExpr, DateValue compExpr, DateValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = baseExpr.getLong();
+ exists = baseExpr.exists();
+ long comp = compExpr.getLong();
+ if (value==comp && exists==compExpr.exists()) {
+ value = fillExpr.getLong();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringStreamReplaceFunction extends AbstractStringValueStream {
+ private final StringValueStream baseExpr;
+ private final StringValue compExpr;
+ private final StringValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringStreamReplaceFunction(StringValueStream baseExpr, StringValue compExpr, StringValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ String compValue = compExpr.toString();
+ if (compExpr.exists()) {
+ String fillValue = fillExpr.toString();
+ boolean fillExists = fillExpr.exists();
+ baseExpr.streamStrings(value -> {
+ if (value.equals(compValue)) {
+ if (fillExists) {
+ cons.accept(fillValue);
+ }
+ } else {
+ cons.accept(value);
+ }
+ });
+ }
+ else {
+ baseExpr.streamStrings(cons);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class StringReplaceFunction extends AbstractStringValue {
+ private final StringValue baseExpr;
+ private final StringValue compExpr;
+ private final StringValue fillExpr;
+ public static final String name = ReplaceFunction.name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public StringReplaceFunction(StringValue baseExpr, StringValue compExpr, StringValue fillExpr) throws SolrException {
+ this.baseExpr = baseExpr;
+ this.compExpr = compExpr;
+ this.fillExpr = fillExpr;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,baseExpr,compExpr,fillExpr);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,baseExpr,compExpr,fillExpr);
+ }
+
+ boolean exists = false;
+
+ @Override
+ public String getString() {
+ String value = baseExpr.getString();
+ exists = baseExpr.exists();
+ String comp = compExpr.getString();
+ if (value.equals(comp) && exists==compExpr.exists()) {
+ value = fillExpr.getString();
+ exists = fillExpr.exists();
+ }
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
\ No newline at end of file
[12/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/StringCastFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/StringCastFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/StringCastFunction.java
new file mode 100644
index 0000000..5960c0e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/StringCastFunction.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A mapping function that casts any input to a {@link StringValue} or {@link StringValueStream}.
+ */
+public class StringCastFunction {
+ public static final String name = "string";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof StringValueStream) {
+ return LambdaFunction.createStringLambdaFunction(name, a -> a, (StringValueStream)param);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a string-castable parameter.");
+ }
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/SubtractFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/SubtractFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/SubtractFunction.java
new file mode 100644
index 0000000..3a4e456
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/SubtractFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A subtraction mapping function.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If two numeric Values are passed in, a {@link DoubleValue} representing the first subtracted by the second is returned.
+ * <li>If a numeric ValueStream and a numeric Value are passed in, a {@link DoubleValueStream} representing the Value subtracted by
+ * each of the values of the ValueStream for a document is returned.
+ * (Or the other way, since the Value and ValueStream can be used in either order)
+ * </ul>
+ */
+public class SubtractFunction {
+ public static final String name = "sub";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramaters, " + params.length + " found.");
+ }
+ AnalyticsValueStream param1 = params[0];
+ AnalyticsValueStream param2 = params[1];
+ if (param1 instanceof DoubleValueStream && param2 instanceof DoubleValueStream) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> a-b, (DoubleValueStream)param1, (DoubleValueStream)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameters.");
+ }
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/TopFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/TopFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/TopFunction.java
new file mode 100644
index 0000000..801d1ea
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/TopFunction.java
@@ -0,0 +1,163 @@
+/*
+ * 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.analytics.function.mapping;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A top mapping function, returning the highest value found.
+ * <p>
+ * Uses:
+ * <ul>
+ * <li>If a single comparable ValueStream is passed in, a Value (of the same type) representing the maximum of the values for each document is returned.
+ * <li>If multiple comparable Values are passed in, a Value (of the same type) representing the maximum of all values is returned.
+ * </ul>
+ */
+public class TopFunction {
+ public static final String name = "top";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires paramaters.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof DateValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createDateLambdaFunction(name, (a,b) -> (a>b)? a:b, (DateValueStream)param);
+ }
+ DateValue[] castedParams = new DateValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DateValue) {
+ castedParams[i] = (DateValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createDateLambdaFunction(name, (a,b) -> (a>b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof IntValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createIntLambdaFunction(name, (a,b) -> (a>b)? a:b, (IntValueStream)param);
+ }
+ IntValue[] castedParams = new IntValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof IntValue) {
+ castedParams[i] = (IntValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createIntLambdaFunction(name, (a,b) -> (a>b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof LongValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createLongLambdaFunction(name, (a,b) -> (a>b)? a:b, (LongValueStream)param);
+ }
+ LongValue[] castedParams = new LongValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof LongValue) {
+ castedParams[i] = (LongValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createLongLambdaFunction(name, (a,b) -> (a>b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof FloatValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createFloatLambdaFunction(name, (a,b) -> (a>b)? a:b, (FloatValueStream)param);
+ }
+ FloatValue[] castedParams = new FloatValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof FloatValue) {
+ castedParams[i] = (FloatValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createFloatLambdaFunction(name, (a,b) -> (a>b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof DoubleValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> (a>b)? a:b, (DoubleValueStream)param);
+ }
+ DoubleValue[] castedParams = new DoubleValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof DoubleValue) {
+ castedParams[i] = (DoubleValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createDoubleLambdaFunction(name, (a,b) -> (a>b)? a:b, castedParams, false);
+ }
+ }
+ if (param instanceof StringValueStream) {
+ if (params.length == 1) {
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> (a.compareTo(b)>=0)? a:b, (StringValueStream)param);
+ }
+ StringValue[] castedParams = new StringValue[params.length];
+ boolean tryNextType = false;
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof StringValue) {
+ castedParams[i] = (StringValue) params[i];
+ } else {
+ tryNextType = true;
+ break;
+ }
+ }
+ if (!tryNextType) {
+ return LambdaFunction.createStringLambdaFunction(name, (a,b) -> (a.compareTo(b)>=0)? a:b, castedParams, false);
+ }
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ });
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/package-info.java
new file mode 100644
index 0000000..3cf363b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Mapping functions to use for analytics expressions.
+ */
+package org.apache.solr.analytics.function.mapping;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/package-info.java
new file mode 100644
index 0000000..e21dd9b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Functions to use for analytics expressions.
+ */
+package org.apache.solr.analytics.function;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/CountFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/CountFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/CountFunction.java
new file mode 100644
index 0000000..a77f997
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/CountFunction.java
@@ -0,0 +1,87 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.CountCollector;
+import org.apache.solr.analytics.function.reduction.data.CountCollector.ExpressionCountCollector;
+import org.apache.solr.analytics.function.reduction.data.CountCollector.TotalCountCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which either counts the number of values that the parameter expression contains,
+ * or the number of documents returned if no parameter is given.
+ */
+public class CountFunction extends AbstractLongValue implements ReductionFunction {
+ private CountCollector collector;
+ public static final String name = "count";
+ private final String exprStr;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ return new CountFunction();
+ }
+ if (params.length == 1) {
+ return new CountFunction(params[0]);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function a max of 1 paramater, " + params.length + " given.");
+ });
+
+ public CountFunction() {
+ this.collector = new TotalCountCollector();
+ this.exprStr = AnalyticsValueStream.createExpressionString(name);
+ }
+
+ public CountFunction(AnalyticsValueStream param) {
+ this.collector = new ExpressionCountCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.count();
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (CountCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/DocCountFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/DocCountFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/DocCountFunction.java
new file mode 100644
index 0000000..f009b59
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/DocCountFunction.java
@@ -0,0 +1,87 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.CountCollector;
+import org.apache.solr.analytics.function.reduction.data.CountCollector.ExpressionCountCollector;
+import org.apache.solr.analytics.function.reduction.data.CountCollector.TotalCountCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which either counts the number of Solr Documents for which the parameter expression exists,
+ * or the number of documents returned if no parameter is given.
+ */
+public class DocCountFunction extends AbstractLongValue implements ReductionFunction {
+ private CountCollector collector;
+ public static final String name = "docCount";
+ private final String exprStr;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length == 0) {
+ return new DocCountFunction();
+ }
+ if (params.length == 1) {
+ return new DocCountFunction(params[0]);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function accepts at most 1 paramater, " + params.length + " given.");
+ });
+
+ public DocCountFunction() {
+ this.collector = new TotalCountCollector();
+ this.exprStr = AnalyticsValueStream.createExpressionString(name);
+ }
+
+ public DocCountFunction(AnalyticsValueStream param) {
+ this.collector = new ExpressionCountCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.docCount();
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (CountCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MaxFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MaxFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MaxFunction.java
new file mode 100644
index 0000000..f5ea12d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MaxFunction.java
@@ -0,0 +1,298 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.MaxCollector.DoubleMaxCollector;
+import org.apache.solr.analytics.function.reduction.data.MaxCollector.FloatMaxCollector;
+import org.apache.solr.analytics.function.reduction.data.MaxCollector.IntMaxCollector;
+import org.apache.solr.analytics.function.reduction.data.MaxCollector.LongMaxCollector;
+import org.apache.solr.analytics.function.reduction.data.MaxCollector.StringMaxCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the maximum value of the given expression.
+ */
+public class MaxFunction {
+ public static final String name = "max";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof DateValueStream) {
+ return new DateMaxFunction((DateValueStream)param);
+ }
+ if (param instanceof IntValueStream) {
+ return new IntMaxFunction((IntValueStream)param);
+ }
+ if (param instanceof LongValueStream) {
+ return new LongMaxFunction((LongValueStream)param);
+ }
+ if (param instanceof FloatValueStream) {
+ return new FloatMaxFunction((FloatValueStream)param);
+ }
+ if (param instanceof DoubleValueStream) {
+ return new DoubleMaxFunction((DoubleValueStream)param);
+ }
+ if (param instanceof StringValueStream) {
+ return new StringMaxFunction((StringValueStream)param);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ });
+}
+class IntMaxFunction extends AbstractIntValue implements ReductionFunction {
+ private IntMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public IntMaxFunction(IntValueStream param) {
+ this.collector = new IntMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public int getInt() {
+ return collector.exists() ? collector.max() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (IntMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class LongMaxFunction extends AbstractLongValue implements ReductionFunction {
+ private LongMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public LongMaxFunction(LongValueStream param) {
+ this.collector = new LongMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.exists() ? collector.max() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (LongMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class FloatMaxFunction extends AbstractFloatValue implements ReductionFunction {
+ private FloatMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public FloatMaxFunction(FloatValueStream param) {
+ this.collector = new FloatMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public float getFloat() {
+ return collector.exists() ? collector.max() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (FloatMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DoubleMaxFunction extends AbstractDoubleValue implements ReductionFunction {
+ private DoubleMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public DoubleMaxFunction(DoubleValueStream param) {
+ this.collector = new DoubleMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public double getDouble() {
+ return collector.exists() ? collector.max() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (DoubleMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DateMaxFunction extends AbstractDateValue implements ReductionFunction {
+ private LongMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public DateMaxFunction(LongValueStream param) {
+ this.collector = new LongMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.exists() ? collector.max() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (LongMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class StringMaxFunction extends AbstractStringValue implements ReductionFunction {
+ private StringMaxCollector collector;
+ public static final String name = MaxFunction.name;
+ private final String exprStr;
+
+ public StringMaxFunction(StringValueStream param) {
+ this.collector = new StringMaxCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public String getString() {
+ return collector.exists() ? collector.max() : null;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (StringMaxCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MedianFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MedianFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MedianFunction.java
new file mode 100644
index 0000000..9a6fe40
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MedianFunction.java
@@ -0,0 +1,200 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedDoubleListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedFloatListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedIntListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedLongListCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the median value of the given expression.
+ */
+public class MedianFunction {
+ public static final String name = "median";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof DateValueStream) {
+ return new DateMedianFunction((DateValueStream)param);
+ } else if (param instanceof IntValueStream) {
+ return new IntMedianFunction((IntValueStream)param);
+ } else if (param instanceof LongValueStream) {
+ return new LongMedianFunction((LongValueStream)param);
+ } else if (param instanceof FloatValueStream) {
+ return new FloatMedianFunction((FloatValueStream)param);
+ } else if (param instanceof DoubleValueStream) {
+ return new DoubleMedianFunction((DoubleValueStream)param);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a date or numeric parameter.");
+ });
+}
+abstract class NumericMedianFunction<T extends Comparable<T>> extends AbstractDoubleValue implements ReductionFunction {
+ protected SortedListCollector<T> collector;
+ public static final String name = MedianFunction.name;
+ private final String exprStr;
+
+ public NumericMedianFunction(DoubleValueStream param, SortedListCollector<T> collector) {
+ this.collector = collector;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ protected abstract double collectOrd(int ord);
+
+ @Override
+ public double getDouble() {
+ int size = collector.size();
+ if (size == 0) {
+ return 0;
+ }
+ if (size % 2 == 0) {
+ return (collectOrd(size/2) + collectOrd(size/2 - 1))/2;
+ } else {
+ return collectOrd(size/2);
+ }
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedListCollector<T>)sync.apply(collector);
+ collector.calcMedian();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class IntMedianFunction extends NumericMedianFunction<Integer> {
+ public IntMedianFunction(IntValueStream param) {
+ super((DoubleValueStream) param, new SortedIntListCollector(param));
+ }
+
+ @Override
+ protected double collectOrd(int ord) {
+ return collector.get(ord);
+ }
+}
+class LongMedianFunction extends NumericMedianFunction<Long> {
+ public LongMedianFunction(LongValueStream param) {
+ super((DoubleValueStream) param, new SortedLongListCollector(param));
+ }
+
+ @Override
+ protected double collectOrd(int ord) {
+ return collector.get(ord);
+ }
+}
+class FloatMedianFunction extends NumericMedianFunction<Float> {
+ public FloatMedianFunction(FloatValueStream param) {
+ super((DoubleValueStream) param, new SortedFloatListCollector(param));
+ }
+
+ @Override
+ protected double collectOrd(int ord) {
+ return collector.get(ord);
+ }
+}
+class DoubleMedianFunction extends NumericMedianFunction<Double> {
+ public DoubleMedianFunction(DoubleValueStream param) {
+ super(param, new SortedDoubleListCollector(param));
+ }
+
+ @Override
+ protected double collectOrd(int ord) {
+ return collector.get(ord);
+ }
+}
+class DateMedianFunction extends AbstractDateValue implements ReductionFunction {
+ private SortedLongListCollector collector;
+ public static final String name = MedianFunction.name;
+ private final String exprStr;
+
+ public DateMedianFunction(DateValueStream param) {
+ this.collector = new SortedLongListCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ int size = collector.size();
+ if (size == 0) {
+ return 0;
+ }
+ if (size % 2 == 0) {
+ return (collector.get(size/2) + collector.get(size/2 - 1))/2;
+ } else {
+ return collector.get(size/2);
+ }
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedLongListCollector)sync.apply(collector);
+ collector.calcMedian();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MinFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MinFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MinFunction.java
new file mode 100644
index 0000000..92539d7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MinFunction.java
@@ -0,0 +1,298 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.MinCollector.DoubleMinCollector;
+import org.apache.solr.analytics.function.reduction.data.MinCollector.FloatMinCollector;
+import org.apache.solr.analytics.function.reduction.data.MinCollector.IntMinCollector;
+import org.apache.solr.analytics.function.reduction.data.MinCollector.LongMinCollector;
+import org.apache.solr.analytics.function.reduction.data.MinCollector.StringMinCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the minumum value of the given expression.
+ */
+public class MinFunction {
+ public static final String name = "min";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream param = params[0];
+ if (param instanceof DateValueStream) {
+ return new DateMinFunction((DateValueStream)param);
+ }
+ if (param instanceof IntValueStream) {
+ return new IntMinFunction((IntValueStream)param);
+ }
+ if (param instanceof LongValueStream) {
+ return new LongMinFunction((LongValueStream)param);
+ }
+ if (param instanceof FloatValueStream) {
+ return new FloatMinFunction((FloatValueStream)param);
+ }
+ if (param instanceof DoubleValueStream) {
+ return new DoubleMinFunction((DoubleValueStream)param);
+ }
+ if (param instanceof StringValueStream) {
+ return new StringMinFunction((StringValueStream)param);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ });
+}
+class IntMinFunction extends AbstractIntValue implements ReductionFunction {
+ private IntMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public IntMinFunction(IntValueStream param) {
+ this.collector = new IntMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public int getInt() {
+ return collector.exists() ? collector.min() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (IntMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class LongMinFunction extends AbstractLongValue implements ReductionFunction {
+ private LongMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public LongMinFunction(LongValueStream param) {
+ this.collector = new LongMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.exists() ? collector.min() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (LongMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class FloatMinFunction extends AbstractFloatValue implements ReductionFunction {
+ private FloatMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public FloatMinFunction(FloatValueStream param) {
+ this.collector = new FloatMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public float getFloat() {
+ return collector.exists() ? collector.min() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (FloatMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DoubleMinFunction extends AbstractDoubleValue implements ReductionFunction {
+ private DoubleMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public DoubleMinFunction(DoubleValueStream param) {
+ this.collector = new DoubleMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public double getDouble() {
+ return collector.exists() ? collector.min() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (DoubleMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DateMinFunction extends AbstractDateValue implements ReductionFunction {
+ private LongMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public DateMinFunction(LongValueStream param) {
+ this.collector = new LongMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.exists() ? collector.min() : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (LongMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class StringMinFunction extends AbstractStringValue implements ReductionFunction {
+ private StringMinCollector collector;
+ public static final String name = MinFunction.name;
+ private final String exprStr;
+
+ public StringMinFunction(StringValueStream param) {
+ this.collector = new StringMinCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public String getString() {
+ return collector.exists() ? collector.min() : null;
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (StringMinCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MissingFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MissingFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MissingFunction.java
new file mode 100644
index 0000000..5fa7e64
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/MissingFunction.java
@@ -0,0 +1,76 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.CountCollector.ExpressionCountCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the number of documents for which the given expression does not exist.
+ */
+public class MissingFunction extends AbstractLongValue implements ReductionFunction {
+ private ExpressionCountCollector collector;
+ public static final String name = "missing";
+ private final String exprStr;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ return new MissingFunction(params[0]);
+ });
+
+ public MissingFunction(AnalyticsValueStream param) {
+ this.collector = new ExpressionCountCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public long getLong() {
+ return collector.missing();
+ }
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (ExpressionCountCollector)sync.apply(collector);
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/OrdinalFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/OrdinalFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/OrdinalFunction.java
new file mode 100644
index 0000000..0b86cdf
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/OrdinalFunction.java
@@ -0,0 +1,386 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.Locale;
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedDoubleListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedFloatListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedIntListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedLongListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedStringListCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.constant.ConstantIntValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the given ordinal of the sorted values of the given expression.
+ */
+public class OrdinalFunction {
+ public static final String name = "ordinal";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream percValue = params[0];
+ int ord = 0;
+ if (params[0] instanceof ConstantIntValue) {
+ ord = ((IntValue)percValue).getInt();
+ if (ord == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires the ordinal to be >= 1 or <= -1, 0 is not accepted.");
+ }
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a constant int value (the ordinal) as the first argument.");
+ }
+ AnalyticsValueStream param = params[1];
+ if (param instanceof DateValueStream) {
+ return new DateOrdinalFunction((DateValueStream)param, ord);
+ }else if (param instanceof IntValueStream) {
+ return new IntOrdinalFunction((IntValueStream)param, ord);
+ } else if (param instanceof LongValueStream) {
+ return new LongOrdinalFunction((LongValueStream)param, ord);
+ } else if (param instanceof FloatValueStream) {
+ return new FloatOrdinalFunction((FloatValueStream)param, ord);
+ } else if (param instanceof DoubleValueStream) {
+ return new DoubleOrdinalFunction((DoubleValueStream)param, ord);
+ } else if (param instanceof StringValueStream) {
+ return new StringOrdinalFunction((StringValueStream)param, ord);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter.");
+ });
+
+ protected static String createOrdinalExpressionString(AnalyticsValueStream param, double perc) {
+ return String.format(Locale.ROOT, "%s(%s,%s)",
+ name,
+ (int)(perc*100),
+ param.getExpressionStr());
+ }
+}
+class IntOrdinalFunction extends AbstractIntValue implements ReductionFunction {
+ private SortedIntListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public IntOrdinalFunction(IntValueStream param, int ordinal) {
+ this.collector = new SortedIntListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public int getInt() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : 0;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : 0;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedIntListCollector)sync.apply(collector);
+ if (ordinal > 0) {
+ collector.calcOrdinal(ordinal);
+ } else {
+ collector.calcReverseOrdinal(ordinal*-1);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class LongOrdinalFunction extends AbstractLongValue implements ReductionFunction {
+ private SortedLongListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public LongOrdinalFunction(LongValueStream param, int ordinal) {
+ this.collector = new SortedLongListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public long getLong() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : 0;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : 0;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedLongListCollector)sync.apply(collector);
+ if (ordinal > 0) {
+ collector.calcOrdinal(ordinal);
+ } else {
+ collector.calcReverseOrdinal(ordinal*-1);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class FloatOrdinalFunction extends AbstractFloatValue implements ReductionFunction {
+ private SortedFloatListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public FloatOrdinalFunction(FloatValueStream param, int ordinal) {
+ this.collector = new SortedFloatListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public float getFloat() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : 0;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : 0;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedFloatListCollector)sync.apply(collector);
+ if (ordinal > 0) {
+ collector.calcOrdinal(ordinal);
+ } else {
+ collector.calcReverseOrdinal(ordinal*-1);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DoubleOrdinalFunction extends AbstractDoubleValue implements ReductionFunction {
+ private SortedDoubleListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public DoubleOrdinalFunction(DoubleValueStream param, int ordinal) {
+ this.collector = new SortedDoubleListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public double getDouble() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : 0;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : 0;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedDoubleListCollector)sync.apply(collector);
+ if (ordinal > 0) {
+ collector.calcOrdinal(ordinal);
+ } else {
+ collector.calcReverseOrdinal(ordinal*-1);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DateOrdinalFunction extends AbstractDateValue implements ReductionFunction {
+ private SortedLongListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public DateOrdinalFunction(LongValueStream param, int ordinal) {
+ this.collector = new SortedLongListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public long getLong() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : 0;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : 0;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedLongListCollector)sync.apply(collector);
+ collector.calcOrdinal(ordinal);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class StringOrdinalFunction extends AbstractStringValue implements ReductionFunction {
+ private SortedStringListCollector collector;
+ private int ordinal;
+ public static final String name = OrdinalFunction.name;
+ private final String exprStr;
+
+ public StringOrdinalFunction(StringValueStream param, int ordinal) {
+ this.collector = new SortedStringListCollector(param);
+ this.ordinal = ordinal;
+ this.exprStr = OrdinalFunction.createOrdinalExpressionString(param, ordinal);
+ }
+
+ @Override
+ public String getString() {
+ int size = collector.size();
+ if (ordinal > 0) {
+ return ordinal <= size ? collector.get(ordinal - 1) : null;
+ } else {
+ return (ordinal * -1) <= size ? collector.get(size + ordinal) : null;
+ }
+
+ }
+ @Override
+ public boolean exists() {
+ return (ordinal > 0 ? ordinal : (ordinal * -1)) <= collector.size();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedStringListCollector)sync.apply(collector);
+ if (ordinal > 0) {
+ collector.calcOrdinal(ordinal);
+ } else {
+ collector.calcReverseOrdinal(ordinal*-1);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/PercentileFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/PercentileFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/PercentileFunction.java
new file mode 100644
index 0000000..4277d90
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/PercentileFunction.java
@@ -0,0 +1,337 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.util.Locale;
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedDoubleListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedFloatListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedIntListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedLongListCollector;
+import org.apache.solr.analytics.function.reduction.data.SortedListCollector.SortedStringListCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.constant.ConstantIntValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the given percentile of the sorted values of the given expression.
+ */
+public class PercentileFunction {
+ public static final String name = "percentile";
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 2) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 2 paramater, " + params.length + " found.");
+ }
+ AnalyticsValueStream percValue = params[0];
+ double perc = 0;
+ if (percValue instanceof ConstantIntValue) {
+ perc = ((IntValue)percValue).getInt();
+ if (perc < 0 || perc > 99) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a percentile between 0 and 99, " + ((int)perc) + " found.");
+ }
+ perc /= 100;
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a constant int value (the percentile) as the first argument.");
+ }
+ AnalyticsValueStream param = params[1];
+ if (param instanceof DateValueStream) {
+ return new DatePercentileFunction((DateValueStream)param, perc);
+ }else if (param instanceof IntValueStream) {
+ return new IntPercentileFunction((IntValueStream)param, perc);
+ } else if (param instanceof LongValueStream) {
+ return new LongPercentileFunction((LongValueStream)param, perc);
+ } else if (param instanceof FloatValueStream) {
+ return new FloatPercentileFunction((FloatValueStream)param, perc);
+ } else if (param instanceof DoubleValueStream) {
+ return new DoublePercentileFunction((DoubleValueStream)param, perc);
+ } else if (param instanceof StringValueStream) {
+ return new StringPercentileFunction((StringValueStream)param, perc);
+ }
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires a comparable parameter.");
+ });
+
+ protected static String createPercentileExpressionString(AnalyticsValueStream param, double perc) {
+ return String.format(Locale.ROOT, "%s(%s,%s)",
+ name,
+ (int)(perc*100),
+ param.getExpressionStr());
+ }
+}
+class IntPercentileFunction extends AbstractIntValue implements ReductionFunction {
+ private SortedIntListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public IntPercentileFunction(IntValueStream param, double percentile) {
+ this.collector = new SortedIntListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public int getInt() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedIntListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class LongPercentileFunction extends AbstractLongValue implements ReductionFunction {
+ private SortedLongListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public LongPercentileFunction(LongValueStream param, double percentile) {
+ this.collector = new SortedLongListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public long getLong() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedLongListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class FloatPercentileFunction extends AbstractFloatValue implements ReductionFunction {
+ private SortedFloatListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public FloatPercentileFunction(FloatValueStream param, double percentile) {
+ this.collector = new SortedFloatListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public float getFloat() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedFloatListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DoublePercentileFunction extends AbstractDoubleValue implements ReductionFunction {
+ private SortedDoubleListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public DoublePercentileFunction(DoubleValueStream param, double percentile) {
+ this.collector = new SortedDoubleListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public double getDouble() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedDoubleListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class DatePercentileFunction extends AbstractDateValue implements ReductionFunction {
+ private SortedLongListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public DatePercentileFunction(LongValueStream param, double percentile) {
+ this.collector = new SortedLongListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public long getLong() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : 0;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedLongListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
+class StringPercentileFunction extends AbstractStringValue implements ReductionFunction {
+ private SortedStringListCollector collector;
+ private double percentile;
+ public static final String name = PercentileFunction.name;
+ private final String exprStr;
+
+ public StringPercentileFunction(StringValueStream param, double percentile) {
+ this.collector = new SortedStringListCollector(param);
+ this.percentile = percentile;
+ this.exprStr = PercentileFunction.createPercentileExpressionString(param, percentile);
+ }
+
+ @Override
+ public String getString() {
+ int size = collector.size();
+ return size > 0 ? collector.get((int) Math.round(percentile * size - .5)) : null;
+ }
+ @Override
+ public boolean exists() {
+ return collector.size() > 0;
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SortedStringListCollector)sync.apply(collector);
+ collector.calcPercentile(percentile);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/SumFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/SumFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/SumFunction.java
new file mode 100644
index 0000000..7d4e939
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/reduction/SumFunction.java
@@ -0,0 +1,92 @@
+/*
+ * 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.analytics.function.reduction;
+
+import java.io.Serializable;
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.ExpressionFactory.CreatorFunction;
+import org.apache.solr.analytics.function.ReductionFunction;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.function.reduction.data.SumCollector;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A reduction function which returns the sum of the sorted values of the given expression.
+ */
+public class SumFunction extends AbstractDoubleValue implements ReductionFunction {
+ private SumCollector collector;
+ public static final String name = "sum";
+ private final String exprStr;
+ public static final CreatorFunction creatorFunction = (params -> {
+ if (params.length != 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires 1 paramater, " + params.length + " found.");
+ }
+ DoubleValueStream casted;
+ try {
+ casted = (DoubleValueStream) params[0];
+ }
+ catch (ClassCastException e) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires numeric parameter. " +
+ "Incorrect parameter: "+params[0].getExpressionStr());
+ }
+ return new SumFunction(casted);
+ });
+
+ public SumFunction(DoubleValueStream param) {
+ this.collector = new SumCollector(param);
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ }
+
+ @Override
+ public double getDouble() {
+ return collector.sum();
+ }
+ @Override
+ public boolean exists() {
+ return collector.exists();
+ }
+
+ @Override
+ public void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync) {
+ collector = (SumCollector) sync.apply(collector);
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.REDUCTION;
+ }
+
+ protected static class SumData extends ReductionData implements Serializable {
+ private static final long serialVersionUID = 5920718235872898338L;
+ double sum;
+ }
+}
\ No newline at end of file
[09/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollectorSupplierFactory.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollectorSupplierFactory.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollectorSupplierFactory.java
deleted file mode 100644
index e22362d..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/StatsCollectorSupplierFactory.java
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.function.Supplier;
-
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.valuesource.BytesRefFieldSource;
-import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
-import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
-import org.apache.lucene.queries.function.valuesource.IntFieldSource;
-import org.apache.lucene.queries.function.valuesource.LongFieldSource;
-import org.apache.solr.analytics.expression.ExpressionFactory;
-import org.apache.solr.analytics.request.ExpressionRequest;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.analytics.util.valuesource.AbsoluteValueDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.AddDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.ConstDateSource;
-import org.apache.solr.analytics.util.valuesource.ConstDoubleSource;
-import org.apache.solr.analytics.util.valuesource.ConstStringSource;
-import org.apache.solr.analytics.util.valuesource.DateFieldSource;
-import org.apache.solr.analytics.util.valuesource.DateMathFunction;
-import org.apache.solr.analytics.util.valuesource.DivDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.DualDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.FilterFieldSource;
-import org.apache.solr.analytics.util.valuesource.LogDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.MultiDateFunction;
-import org.apache.solr.analytics.util.valuesource.MultiDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.MultiplyDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.NegateDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.PowDoubleFunction;
-import org.apache.solr.analytics.util.valuesource.ReverseStringFunction;
-import org.apache.solr.analytics.util.valuesource.SingleDoubleFunction;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.schema.FieldType;
-import org.apache.solr.schema.IndexSchema;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.schema.StrField;
-import org.apache.solr.schema.TrieDateField;
-import org.apache.solr.schema.TrieDoubleField;
-import org.apache.solr.schema.TrieFloatField;
-import org.apache.solr.schema.TrieIntField;
-import org.apache.solr.schema.TrieLongField;
-import org.apache.solr.search.function.ConcatStringFunction;
-import org.apache.solr.util.DateMathParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class StatsCollectorSupplierFactory {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- // FunctionTypes
- final static int NUMBER_TYPE = 0;
- final static int DATE_TYPE = 1;
- final static int STRING_TYPE = 2;
- final static int FIELD_TYPE = 3;
- final static int FILTER_TYPE = 4;
-
- /**
- * Builds a Supplier that will generate identical arrays of new StatsCollectors.
- *
- * @param schema The Schema being used.
- * @param exRequests The expression requests to generate a StatsCollector[] from.
- * @return A Supplier that will return an array of new StatsCollector.
- */
- @SuppressWarnings("unchecked")
- public static Supplier<StatsCollector[]> create(IndexSchema schema, List<ExpressionRequest> exRequests ) {
- final Map<String, Set<String>> collectorStats = new TreeMap<>();
- final Map<String, Set<Integer>> collectorPercs = new TreeMap<>();
- final Map<String, ValueSource> collectorSources = new TreeMap<>();
-
- // Iterate through all expression request to make a list of ValueSource strings
- // and statistics that need to be calculated on those ValueSources.
- for (ExpressionRequest expRequest : exRequests) {
- String statExpression = expRequest.getExpressionString();
- Set<String> statistics = getStatistics(statExpression);
- if (statistics == null) {
- continue;
- }
- for (String statExp : statistics) {
- String stat;
- String operands;
- try {
- stat = statExp.substring(0, statExp.indexOf('(')).trim();
- operands = statExp.substring(statExp.indexOf('(')+1, statExp.lastIndexOf(')')).trim();
- } catch (Exception e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Unable to parse statistic: ["+statExpression+"]",e);
- }
- String[] arguments = ExpressionFactory.getArguments(operands);
- String source = arguments[0];
- if (stat.equals(AnalyticsParams.STAT_PERCENTILE)) {
- // The statistic is a percentile, extra parsing is required
- if (arguments.length<2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Too few arguments given for "+stat+"() in ["+statExp+"].");
- } else if (arguments.length>2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Too many arguments given for "+stat+"() in ["+statExp+"].");
- }
- source = arguments[1];
- Set<Integer> percs = collectorPercs.get(source);
- if (percs == null) {
- percs = new HashSet<>();
- collectorPercs.put(source, percs);
- }
- try {
- int perc = Integer.parseInt(arguments[0]);
- if (perc>0 && perc<100) {
- percs.add(perc);
- } else {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The percentile in ["+statExp+"] is not between 0 and 100, exculsive.");
- }
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"\""+arguments[0]+"\" cannot be converted into a percentile.",e);
- }
- } else if (arguments.length>1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Too many arguments given for "+stat+"() in ["+statExp+"].");
- } else if (arguments.length==0) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"No arguments given for "+stat+"() in ["+statExp+"].");
- }
- // Only unique ValueSources will be made; therefore statistics must be accumulated for
- // each ValueSource, even across different expression requests
- Set<String> stats = collectorStats.get(source);
- if (stats == null) {
- stats = new HashSet<>();
- collectorStats.put(source, stats);
- }
- if(AnalyticsParams.STAT_PERCENTILE.equals(stat)) {
- stats.add(stat + "_"+ arguments[0]);
- } else {
- stats.add(stat);
- }
- }
- }
- String[] keys = collectorStats.keySet().toArray(new String[0]);
- for (String sourceStr : keys) {
- // Build one ValueSource for each unique value source string
- ValueSource source = buildSourceTree(schema, sourceStr);
- if (source == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The statistic ["+sourceStr+"] could not be parsed.");
- }
- String builtString = source.toString();
- collectorSources.put(builtString,source);
- // Replace the user given string with the correctly built string
- if (!builtString.equals(sourceStr)) {
- Set<String> stats = collectorStats.remove(sourceStr);
- if (stats!=null) {
- collectorStats.put(builtString, stats);
- }
- Set<Integer> percs = collectorPercs.remove(sourceStr);
- if (percs!=null) {
- collectorPercs.put(builtString, percs);
- }
- for (ExpressionRequest er : exRequests) {
- er.setExpressionString(er.getExpressionString().replace(sourceStr, builtString));
- }
- }
- }
- if (collectorSources.size()==0) {
- return new Supplier<StatsCollector[]>() {
- @Override
- public StatsCollector[] get() {
- return new StatsCollector[0];
- }
- };
- }
-
- log.info("Stats objects: "+collectorStats.size()+" sr="+collectorSources.size()+" pr="+collectorPercs.size() );
-
- // All information is stored in final arrays so that nothing
- // has to be computed when the Supplier's get() method is called.
- final Set<String>[] statsArr = collectorStats.values().toArray(new Set[0]);
- final ValueSource[] sourceArr = collectorSources.values().toArray(new ValueSource[0]);
- final boolean[] uniqueBools = new boolean[statsArr.length];
- final boolean[] medianBools = new boolean[statsArr.length];
- final boolean[] numericBools = new boolean[statsArr.length];
- final boolean[] dateBools = new boolean[statsArr.length];
- final double[][] percsArr = new double[statsArr.length][];
- final String[][] percsNames = new String[statsArr.length][];
- for (int count = 0; count < sourceArr.length; count++) {
- uniqueBools[count] = statsArr[count].contains(AnalyticsParams.STAT_UNIQUE);
- medianBools[count] = statsArr[count].contains(AnalyticsParams.STAT_MEDIAN);
- numericBools[count] = statsArr[count].contains(AnalyticsParams.STAT_SUM)||statsArr[count].contains(AnalyticsParams.STAT_SUM_OF_SQUARES)||statsArr[count].contains(AnalyticsParams.STAT_MEAN)||statsArr[count].contains(AnalyticsParams.STAT_STANDARD_DEVIATION);
- dateBools[count] = (sourceArr[count] instanceof DateFieldSource) | (sourceArr[count] instanceof MultiDateFunction) | (sourceArr[count] instanceof ConstDateSource);
- Set<Integer> ps = collectorPercs.get(sourceArr[count].toString());
- if (ps!=null) {
- percsArr[count] = new double[ps.size()];
- percsNames[count] = new String[ps.size()];
- int percCount = 0;
- for (int p : ps) {
- percsArr[count][percCount] = p/100.0;
- percsNames[count][percCount++] = AnalyticsParams.STAT_PERCENTILE+"_"+p;
- }
- }
- }
- // Making the Supplier
- return new Supplier<StatsCollector[]>() {
- public StatsCollector[] get() {
- StatsCollector[] collectors = new StatsCollector[statsArr.length];
- for (int count = 0; count < statsArr.length; count++) {
- if(numericBools[count]){
- StatsCollector sc = new NumericStatsCollector(sourceArr[count], statsArr[count]);
- if(uniqueBools[count]) sc = new UniqueStatsCollector(sc);
- if(medianBools[count]) sc = new MedianStatsCollector(sc);
- if(percsArr[count]!=null) sc = new PercentileStatsCollector(sc,percsArr[count],percsNames[count]);
- collectors[count]=sc;
- } else if (dateBools[count]) {
- StatsCollector sc = new MinMaxStatsCollector(sourceArr[count], statsArr[count]);
- if(uniqueBools[count]) sc = new UniqueStatsCollector(sc);
- if(medianBools[count]) sc = new DateMedianStatsCollector(sc);
- if(percsArr[count]!=null) sc = new PercentileStatsCollector(sc,percsArr[count],percsNames[count]);
- collectors[count]=sc;
- } else {
- StatsCollector sc = new MinMaxStatsCollector(sourceArr[count], statsArr[count]);
- if(uniqueBools[count]) sc = new UniqueStatsCollector(sc);
- if(medianBools[count]) sc = new MedianStatsCollector(sc);
- if(percsArr[count]!=null) sc = new PercentileStatsCollector(sc,percsArr[count],percsNames[count]);
- collectors[count]=sc;
- }
- }
- return collectors;
- }
- };
- }
-
- /**
- * Finds the set of statistics that must be computed for the expression.
- * @param expression The string representation of an expression
- * @return The set of statistics (sum, mean, median, etc.) found in the expression
- */
- public static Set<String> getStatistics(String expression) {
- HashSet<String> set = new HashSet<>();
- int firstParen = expression.indexOf('(');
- if (firstParen>0) {
- String topOperation = expression.substring(0,firstParen).trim();
- if (AnalyticsParams.ALL_STAT_SET.contains(topOperation)) {
- set.add(expression);
- } else if (!(topOperation.equals(AnalyticsParams.CONSTANT_NUMBER)||topOperation.equals(AnalyticsParams.CONSTANT_DATE)||topOperation.equals(AnalyticsParams.CONSTANT_STRING))) {
- String operands = expression.substring(firstParen+1, expression.lastIndexOf(')')).trim();
- String[] arguments = ExpressionFactory.getArguments(operands);
- for (String argument : arguments) {
- Set<String> more = getStatistics(argument);
- if (more!=null) {
- set.addAll(more);
- }
- }
- }
- }
- if (set.size()==0) {
- return null;
- }
- return set;
- }
-
- /**
- * Builds a Value Source from a given string
- *
- * @param schema The schema being used.
- * @param expression The string to be turned into an expression.
- * @return The completed ValueSource
- */
- private static ValueSource buildSourceTree(IndexSchema schema, String expression) {
- return buildSourceTree(schema,expression,FIELD_TYPE);
- }
-
- /**
- * Builds a Value Source from a given string and a given source type
- *
- * @param schema The schema being used.
- * @param expression The string to be turned into an expression.
- * @param sourceType The type of source that must be returned.
- * @return The completed ValueSource
- */
- private static ValueSource buildSourceTree(IndexSchema schema, String expression, int sourceType) {
- int expressionType = getSourceType(expression);
- if (sourceType != FIELD_TYPE && expressionType != FIELD_TYPE &&
- expressionType != FILTER_TYPE && expressionType != sourceType) {
- return null;
- }
- switch (expressionType) {
- case NUMBER_TYPE : return buildNumericSource(schema, expression);
- case DATE_TYPE : return buildDateSource(schema, expression);
- case STRING_TYPE : return buildStringSource(schema, expression);
- case FIELD_TYPE : return buildFieldSource(schema, expression, sourceType);
- case FILTER_TYPE : return buildFilterSource(schema, expression.substring(expression.indexOf('(')+1,expression.lastIndexOf(')')), sourceType);
- default : throw new SolrException(ErrorCode.BAD_REQUEST,expression+" is not a valid operation.");
- }
- }
-
- /**
- * Determines what type of value source the expression represents.
- *
- * @param expression The expression representing the desired ValueSource
- * @return NUMBER_TYPE, DATE_TYPE, STRING_TYPE or -1
- */
- private static int getSourceType(String expression) {
- int paren = expression.indexOf('(');
- if (paren<0) {
- return FIELD_TYPE;
- }
- String operation = expression.substring(0,paren).trim();
-
- if (AnalyticsParams.NUMERIC_OPERATION_SET.contains(operation)) {
- return NUMBER_TYPE;
- } else if (AnalyticsParams.DATE_OPERATION_SET.contains(operation)) {
- return DATE_TYPE;
- } else if (AnalyticsParams.STRING_OPERATION_SET.contains(operation)) {
- return STRING_TYPE;
- } else if (operation.equals(AnalyticsParams.FILTER)) {
- return FILTER_TYPE;
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation \""+operation+"\" in ["+expression+"] is not supported.");
- }
-
- /**
- * Builds a value source for a given field, making sure that the field fits a given source type.
- * @param schema the schema
- * @param expressionString The name of the field to build a Field Source from.
- * @param sourceType FIELD_TYPE for any type of field, NUMBER_TYPE for numeric fields,
- * DATE_TYPE for date fields and STRING_TYPE for string fields.
- * @return a value source
- */
- private static ValueSource buildFieldSource(IndexSchema schema, String expressionString, int sourceType) {
- SchemaField sf;
- try {
- sf = schema.getField(expressionString);
- } catch (SolrException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The field "+expressionString+" does not exist.",e);
- }
- FieldType type = sf.getType();
- if ( type instanceof TrieIntField) {
- if (sourceType!=NUMBER_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new IntFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- } else if (type instanceof TrieLongField) {
- if (sourceType!=NUMBER_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new LongFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- } else if (type instanceof TrieFloatField) {
- if (sourceType!=NUMBER_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new FloatFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- } else if (type instanceof TrieDoubleField) {
- if (sourceType!=NUMBER_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new DoubleFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- } else if (type instanceof TrieDateField) {
- if (sourceType!=DATE_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new DateFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- } else if (type instanceof StrField) {
- if (sourceType!=STRING_TYPE&&sourceType!=FIELD_TYPE) {
- return null;
- }
- return new BytesRefFieldSource(expressionString) {
- public String description() {
- return field;
- }
- };
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, type.toString()+" is not a supported field type in Solr Analytics.");
- }
-
- /**
- * Builds a default is missing source that wraps a given source. A missing value is required for all
- * non-field value sources.
- * @param schema the schema
- * @param expressionString The name of the field to build a Field Source from.
- * @param sourceType FIELD_TYPE for any type of field, NUMBER_TYPE for numeric fields,
- * DATE_TYPE for date fields and STRING_TYPE for string fields.
- * @return a value source
- */
- @SuppressWarnings("deprecation")
- private static ValueSource buildFilterSource(IndexSchema schema, String expressionString, int sourceType) {
- String[] arguments = ExpressionFactory.getArguments(expressionString);
- if (arguments.length!=2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Invalid arguments were given for \""+AnalyticsParams.FILTER+"\".");
- }
- ValueSource delegateSource = buildSourceTree(schema, arguments[0], sourceType);
- if (delegateSource==null) {
- return null;
- }
- Object defaultObject;
-
- ValueSource src = delegateSource;
- if (delegateSource instanceof FilterFieldSource) {
- src = ((FilterFieldSource)delegateSource).getRootSource();
- }
- if ( src instanceof IntFieldSource) {
- try {
- defaultObject = new Integer(arguments[1]);
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The filter value "+arguments[1]+" cannot be converted into an integer.",e);
- }
- } else if ( src instanceof DateFieldSource || src instanceof MultiDateFunction) {
- defaultObject = DateMathParser.parseMath(null, arguments[1]);
- } else if ( src instanceof LongFieldSource ) {
- try {
- defaultObject = new Long(arguments[1]);
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The filter value "+arguments[1]+" cannot be converted into a long.",e);
- }
- } else if ( src instanceof FloatFieldSource ) {
- try {
- defaultObject = new Float(arguments[1]);
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The filter value "+arguments[1]+" cannot be converted into a float.",e);
- }
- } else if ( src instanceof DoubleFieldSource || src instanceof SingleDoubleFunction ||
- src instanceof DualDoubleFunction|| src instanceof MultiDoubleFunction) {
- try {
- defaultObject = new Double(arguments[1]);
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The filter value "+arguments[1]+" cannot be converted into a double.",e);
- }
- } else {
- defaultObject = arguments[1];
- }
- return new FilterFieldSource(delegateSource,defaultObject);
- }
-
- /**
- * Recursively parses and breaks down the expression string to build a numeric ValueSource.
- *
- * @param schema The schema to pull fields from.
- * @param expressionString The expression string to build a ValueSource from.
- * @return The value source represented by the given expressionString
- */
- private static ValueSource buildNumericSource(IndexSchema schema, String expressionString) {
- int paren = expressionString.indexOf('(');
- String[] arguments;
- String operands;
- if (paren<0) {
- return buildFieldSource(schema,expressionString,NUMBER_TYPE);
- } else {
- try {
- operands = expressionString.substring(paren+1, expressionString.lastIndexOf(')')).trim();
- } catch (Exception e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Missing closing parenthesis in ["+expressionString+"]");
- }
- arguments = ExpressionFactory.getArguments(operands);
- }
- String operation = expressionString.substring(0, paren).trim();
- if (operation.equals(AnalyticsParams.CONSTANT_NUMBER)) {
- if (arguments.length!=1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The constant number declaration ["+expressionString+"] does not have exactly 1 argument.");
- }
- return new ConstDoubleSource(Double.parseDouble(arguments[0]));
- } else if (operation.equals(AnalyticsParams.NEGATE)) {
- if (arguments.length!=1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The negate operation ["+expressionString+"] does not have exactly 1 argument.");
- }
- ValueSource argSource = buildNumericSource(schema, arguments[0]);
- if (argSource==null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation \""+AnalyticsParams.NEGATE+"\" requires a numeric field or operation as argument. \""+arguments[0]+"\" is not a numeric field or operation.");
- }
- return new NegateDoubleFunction(argSource);
- } else if (operation.equals(AnalyticsParams.ABSOLUTE_VALUE)) {
- if (arguments.length!=1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The absolute value operation ["+expressionString+"] does not have exactly 1 argument.");
- }
- ValueSource argSource = buildNumericSource(schema, arguments[0]);
- if (argSource==null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation \""+AnalyticsParams.NEGATE+"\" requires a numeric field or operation as argument. \""+arguments[0]+"\" is not a numeric field or operation.");
- }
- return new AbsoluteValueDoubleFunction(argSource);
- } else if (operation.equals(AnalyticsParams.FILTER)) {
- return buildFilterSource(schema, operands, NUMBER_TYPE);
- }
- List<ValueSource> subExpressions = new ArrayList<>();
- for (String argument : arguments) {
- ValueSource argSource = buildNumericSource(schema, argument);
- if (argSource == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation \""+operation+"\" requires numeric fields or operations as arguments. \""+argument+"\" is not a numeric field or operation.");
- }
- subExpressions.add(argSource);
- }
- if (operation.equals(AnalyticsParams.ADD)) {
- return new AddDoubleFunction(subExpressions.toArray(new ValueSource[0]));
- } else if (operation.equals(AnalyticsParams.MULTIPLY)) {
- return new MultiplyDoubleFunction(subExpressions.toArray(new ValueSource[0]));
- } else if (operation.equals(AnalyticsParams.DIVIDE)) {
- if (subExpressions.size()!=2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The divide operation ["+expressionString+"] does not have exactly 2 arguments.");
- }
- return new DivDoubleFunction(subExpressions.get(0),subExpressions.get(1));
- } else if (operation.equals(AnalyticsParams.POWER)) {
- if (subExpressions.size()!=2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The power operation ["+expressionString+"] does not have exactly 2 arguments.");
- }
- return new PowDoubleFunction(subExpressions.get(0),subExpressions.get(1));
- } else if (operation.equals(AnalyticsParams.LOG)) {
- if (subExpressions.size()!=2) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The log operation ["+expressionString+"] does not have exactly 2 arguments.");
- }
- return new LogDoubleFunction(subExpressions.get(0), subExpressions.get(1));
- }
- if (AnalyticsParams.DATE_OPERATION_SET.contains(operation)||AnalyticsParams.STRING_OPERATION_SET.contains(operation)) {
- return null;
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation ["+expressionString+"] is not supported.");
- }
-
-
- /**
- * Recursively parses and breaks down the expression string to build a date ValueSource.
- *
- * @param schema The schema to pull fields from.
- * @param expressionString The expression string to build a ValueSource from.
- * @return The value source represented by the given expressionString
- */
- @SuppressWarnings("deprecation")
- private static ValueSource buildDateSource(IndexSchema schema, String expressionString) {
- int paren = expressionString.indexOf('(');
- String[] arguments;
- if (paren<0) {
- return buildFieldSource(schema, expressionString, DATE_TYPE);
- } else {
- arguments = ExpressionFactory.getArguments(expressionString.substring(paren+1, expressionString.lastIndexOf(')')).trim());
- }
- String operands = arguments[0];
- String operation = expressionString.substring(0, paren).trim();
- if (operation.equals(AnalyticsParams.CONSTANT_DATE)) {
- if (arguments.length!=1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"The constant date declaration ["+expressionString+"] does not have exactly 1 argument.");
- }
- return new ConstDateSource(DateMathParser.parseMath(null, operands));
- } else if (operation.equals(AnalyticsParams.FILTER)) {
- return buildFilterSource(schema, operands, DATE_TYPE);
- }
- if (operation.equals(AnalyticsParams.DATE_MATH)) {
- List<ValueSource> subExpressions = new ArrayList<>();
- boolean first = true;
- for (String argument : arguments) {
- ValueSource argSource;
- if (first) {
- first = false;
- argSource = buildDateSource(schema, argument);
- if (argSource == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"\""+AnalyticsParams.DATE_MATH+"\" requires the first argument be a date operation or field. ["+argument+"] is not a date operation or field.");
- }
- } else {
- argSource = buildStringSource(schema, argument);
- if (argSource == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"\""+AnalyticsParams.DATE_MATH+"\" requires that all arguments except the first be string operations. ["+argument+"] is not a string operation.");
- }
- }
- subExpressions.add(argSource);
- }
- return new DateMathFunction(subExpressions.toArray(new ValueSource[0]));
- }
- if (AnalyticsParams.NUMERIC_OPERATION_SET.contains(operation)||AnalyticsParams.STRING_OPERATION_SET.contains(operation)) {
- return null;
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation ["+expressionString+"] is not supported.");
- }
-
-
- /**
- * Recursively parses and breaks down the expression string to build a string ValueSource.
- *
- * @param schema The schema to pull fields from.
- * @param expressionString The expression string to build a ValueSource from.
- * @return The value source represented by the given expressionString
- */
- private static ValueSource buildStringSource(IndexSchema schema, String expressionString) {
- int paren = expressionString.indexOf('(');
- String[] arguments;
- if (paren<0) {
- return buildFieldSource(schema, expressionString, FIELD_TYPE);
- } else {
- arguments = ExpressionFactory.getArguments(expressionString.substring(paren+1, expressionString.lastIndexOf(')')).trim());
- }
- String operands = arguments[0];
- String operation = expressionString.substring(0, paren).trim();
- if (operation.equals(AnalyticsParams.CONSTANT_STRING)) {
- operands = expressionString.substring(paren+1, expressionString.lastIndexOf(')'));
- return new ConstStringSource(operands);
- } else if (operation.equals(AnalyticsParams.FILTER)) {
- return buildFilterSource(schema,operands,FIELD_TYPE);
- } else if (operation.equals(AnalyticsParams.REVERSE)) {
- if (arguments.length!=1) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"\""+AnalyticsParams.REVERSE+"\" requires exactly one argument. The number of arguments in "+expressionString+" is not 1.");
- }
- return new ReverseStringFunction(buildStringSource(schema, operands));
- }
- List<ValueSource> subExpressions = new ArrayList<>();
- for (String argument : arguments) {
- subExpressions.add(buildSourceTree(schema, argument));
- }
- if (operation.equals(AnalyticsParams.CONCATENATE)) {
- return new ConcatStringFunction(subExpressions.toArray(new ValueSource[0]));
- }
- if (AnalyticsParams.NUMERIC_OPERATION_SET.contains(operation)) {
- return buildNumericSource(schema, expressionString);
- } else if (AnalyticsParams.DATE_OPERATION_SET.contains(operation)) {
- return buildDateSource(schema, expressionString);
- }
- throw new SolrException(ErrorCode.BAD_REQUEST,"The operation ["+expressionString+"] is not supported.");
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/UniqueStatsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/UniqueStatsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/UniqueStatsCollector.java
deleted file mode 100644
index 461b0f4..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/UniqueStatsCollector.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.analytics.statistics;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * <code>UniqueValueCounter</code> computes the number of unique values.
- */
-public class UniqueStatsCollector extends AbstractDelegatingStatsCollector{
- private final Set<Object> uniqueValues = new HashSet<>();
-
- public UniqueStatsCollector(StatsCollector delegate) {
- super(delegate);
- }
-
- @Override
- public void collect(int doc) throws IOException {
- super.collect(doc);
- if (value.exists) {
- uniqueValues.add(value.toObject());
- }
- }
-
- @Override
- public Comparable getStat(String stat) {
- if (stat.equals("unique")) {
- return new Long(uniqueValues.size());
- }
- return delegate.getStat(stat);
- }
-
- @Override
- public void compute() {
- delegate.compute();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/package-info.java
deleted file mode 100644
index 90fa12d..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/statistics/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Statistics collectors reduce a list of Objects to a single value. Most implementations reduce a list to a statistic on that list.
- */
-package org.apache.solr.analytics.statistics;
-
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardRequestManager.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardRequestManager.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardRequestManager.java
new file mode 100644
index 0000000..f65e58f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardRequestManager.java
@@ -0,0 +1,245 @@
+/*
+ * 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.analytics.stream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.apache.solr.analytics.AnalyticsRequestManager;
+import org.apache.solr.analytics.AnalyticsRequestParser;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.CloudSolrClient.Builder;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.ZkCoreNodeProps;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SolrjNamedThreadFactory;
+import org.apache.solr.handler.AnalyticsHandler;
+import org.apache.solr.handler.component.AnalyticsComponent;
+import org.apache.solr.response.AnalyticsShardResponseWriter;
+
+/**
+ * This class manages the requesting of shard responses from all shards in the queried collection.
+ *
+ * <p>
+ * Shard Requests are sent to the {@link AnalyticsHandler} instead of the {@link AnalyticsComponent},
+ * which is the entrance to the analytics component for all client requests.
+ */
+public class AnalyticsShardRequestManager {
+ private final SolrParams params;
+ protected transient CloudSolrClient cloudSolrClient;
+ protected transient List<String> replicaUrls;
+
+ /**
+ * All shards responses, which are received in parallel, are funneled into the manager.
+ * So the manager must be transient.
+ */
+ private transient final AnalyticsRequestManager manager;
+
+ public AnalyticsShardRequestManager(SolrParams params, AnalyticsRequestManager manager) {
+ this.manager = manager;
+ this.params = loadParams(params, manager.analyticsRequest);
+ }
+
+ /**
+ * Send out shard requests to each shard in the given collection.
+ *
+ * @param collection that is being queried
+ * @param zkHost of the solr cloud hosting the collection
+ * @throws IOException if an exception occurs while picking shards or sending requests
+ */
+ public void sendRequests(String collection, String zkHost) throws IOException {
+ this.replicaUrls = new ArrayList<>();
+ this.cloudSolrClient = new Builder()
+ .withZkHost(zkHost)
+ .build();
+ try {
+ this.cloudSolrClient.connect();
+ pickShards(collection);
+ streamFromShards();
+ } finally {
+ cloudSolrClient.close();
+ }
+ }
+
+ /**
+ * Pick one replica from each shard to send the shard requests to.
+ *
+ * @param collection that is being queried
+ * @throws IOException if an exception occurs while finding replicas
+ */
+ protected void pickShards(String collection) throws IOException {
+ try {
+
+ ZkStateReader zkStateReader = cloudSolrClient.getZkStateReader();
+ ClusterState clusterState = zkStateReader.getClusterState();
+ Set<String> liveNodes = clusterState.getLiveNodes();
+
+ Collection<Slice> slices = clusterState.getCollection(collection).getActiveSlices();
+
+ for(Slice slice : slices) {
+ Collection<Replica> replicas = slice.getReplicas();
+ List<Replica> shuffler = new ArrayList<>();
+ for(Replica replica : replicas) {
+ if(replica.getState() == Replica.State.ACTIVE && liveNodes.contains(replica.getNodeName()))
+ shuffler.add(replica);
+ }
+
+ Collections.shuffle(shuffler, new Random());
+ Replica rep = shuffler.get(0);
+ ZkCoreNodeProps zkProps = new ZkCoreNodeProps(rep);
+ String url = zkProps.getCoreUrl();
+ replicaUrls.add(url);
+ }
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Send a shard request to each chosen replica, streaming
+ * the responses back to the {@link AnalyticsRequestManager}
+ * through the {@link AnalyticsShardResponseParser}.
+ * <p>
+ * A thread pool is used to send the requests simultaneously,
+ * and therefore importing the results is also done in parallel.
+ * However the manager can only import one shard response at a time,
+ * so the {@link AnalyticsShardResponseParser} is blocked until each import is finished.
+ *
+ * @throws IOException if an exception occurs while sending requests.
+ */
+ private void streamFromShards() throws IOException {
+ ExecutorService service = ExecutorUtil.newMDCAwareCachedThreadPool(new SolrjNamedThreadFactory("SolrAnalyticsStream"));
+ List<Future<SolrException>> futures = new ArrayList<>();
+ List<AnalyticsShardRequester> openers = new ArrayList<>();
+ for (String replicaUrl : replicaUrls) {
+ AnalyticsShardRequester opener = new AnalyticsShardRequester(replicaUrl);
+ openers.add(opener);
+ Future<SolrException> future = service.submit(opener);
+ futures.add(future);
+ }
+ try {
+ for (Future<SolrException> f : futures) {
+ SolrException e = f.get();
+ if (e != null) {
+ throw e;
+ }
+ }
+ } catch (InterruptedException e1) {
+ throw new RuntimeException(e1);
+ } catch (ExecutionException e1) {
+ throw new RuntimeException(e1);
+ } finally {
+ service.shutdown();
+ for (AnalyticsShardRequester opener : openers) {
+ opener.close();
+ }
+ }
+ }
+
+ /**
+ * Create a {@link SolrParams} for shard requests. The only parameters that are copied over from
+ * the original search request are "q" and "fq".
+ *
+ * <p>
+ * The request is sent to the {@link AnalyticsHandler} and the output will be encoded in the analytics bit-stream
+ * format generated by the {@link AnalyticsShardResponseWriter}.
+ *
+ * @param paramsIn of the original solr request
+ * @param analyticsRequest string representation
+ * @return shard request SolrParams
+ */
+ private static SolrParams loadParams(SolrParams paramsIn, String analyticsRequest) {
+ ModifiableSolrParams solrParams = new ModifiableSolrParams();
+
+ solrParams.add(CommonParams.QT, AnalyticsHandler.NAME);
+ solrParams.add(CommonParams.WT, AnalyticsShardResponseWriter.NAME);
+ solrParams.add(CommonParams.Q, paramsIn.get(CommonParams.Q));
+ solrParams.add(CommonParams.FQ, paramsIn.getParams(CommonParams.FQ));
+ solrParams.add(AnalyticsRequestParser.analyticsParamName, analyticsRequest);
+
+ return solrParams;
+ }
+
+ /**
+ * A class that opens a connection to a given solr instance, a selected replica of the queried collection,
+ * and sends a analytics request to the {@link AnalyticsHandler}. The results are processed by an
+ * {@link AnalyticsShardResponseParser} constructed with the {@link AnalyticsRequestManager} passed
+ * to the parent {@link AnalyticsShardRequestManager}.
+ */
+ protected class AnalyticsShardRequester implements Callable<SolrException> {
+ private String baseUrl;
+ HttpSolrClient client;
+
+ /**
+ * Create a requester for analytics shard data.
+ *
+ * @param baseUrl of the replica to send the request to
+ */
+ public AnalyticsShardRequester(String baseUrl) {
+ this.baseUrl = baseUrl;
+ this.client = null;
+ }
+
+ /**
+ * Send the analytics request to the shard.
+ */
+ @Override
+ public SolrException call() throws Exception {
+ client = new HttpSolrClient.Builder(baseUrl).build();
+ QueryRequest query = new QueryRequest( params );
+ query.setPath(AnalyticsHandler.NAME);
+ query.setResponseParser(new AnalyticsShardResponseParser(manager));
+ query.setMethod(SolrRequest.METHOD.POST);
+ NamedList<Object> exception = client.request(query);
+ if (exception.size() > 0) {
+ return (SolrException)exception.getVal(0);
+ }
+ return null;
+ }
+
+ /**
+ * Close the connection to the solr instance.
+ *
+ * @throws IOException if an error occurs while closing the connection
+ */
+ public void close() throws IOException {
+ if (client != null) {
+ client.close();
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardResponseParser.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardResponseParser.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardResponseParser.java
new file mode 100644
index 0000000..c7f4094
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/AnalyticsShardResponseParser.java
@@ -0,0 +1,89 @@
+/*
+ * 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.analytics.stream;
+
+import org.apache.solr.analytics.AnalyticsRequestManager;
+import org.apache.solr.client.solrj.ResponseParser;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.handler.AnalyticsHandler;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.Reader;
+
+/**
+ * This parser initiates a merge of an Analytics Shard Response, sent from the {@link AnalyticsHandler}.
+ *
+ * The input stream is immediately sent to the given {@link AnalyticsRequestManager} to merge.
+ */
+public class AnalyticsShardResponseParser extends ResponseParser {
+ public static final String BINARY_CONTENT_TYPE = "application/octet-stream";
+ public static final String STREAM = "application/octet-stream";
+
+ private final AnalyticsRequestManager manager;
+
+ /**
+ *
+ * @param manager the manager of the current Analytics Request, will manage the merging of shard data
+ */
+ public AnalyticsShardResponseParser(AnalyticsRequestManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public String getWriterType() {
+ return "analytics_shard_stream";
+ }
+
+ @Override
+ public NamedList<Object> processResponse(InputStream body, String encoding) {
+ DataInputStream input = new DataInputStream(body);
+ //check to see if the response is an exception
+ NamedList<Object> exception = new NamedList<>();
+ try {
+ if (input.readBoolean()) {
+ manager.importShardData(input);
+ } else {
+ exception.add("Exception", new ObjectInputStream(input).readObject());
+ }
+ } catch (IOException e) {
+ exception.add("Exception", new SolrException(ErrorCode.SERVER_ERROR, "Couldn't process analytics shard response", e));
+ } catch (ClassNotFoundException e1) {
+ throw new RuntimeException(e1);
+ }
+ return exception;
+ }
+
+ @Override
+ public String getContentType() {
+ return BINARY_CONTENT_TYPE;
+ }
+
+ @Override
+ public String getVersion() {
+ return "1";
+ }
+
+ @Override
+ public NamedList<Object> processResponse(Reader reader) {
+ throw new RuntimeException("Cannot handle character stream");
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/package-info.java
new file mode 100644
index 0000000..31563cd
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes to manage the I/O between shards.
+ */
+package org.apache.solr.analytics.stream;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanArrayReservation.java
new file mode 100644
index 0000000..b0ca38d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanArrayReservation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.BooleanDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.BooleanDataArrayWriter;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanArrayReservation extends ReductionDataArrayReservation<BooleanConsumer, BooleanSupplier> {
+
+ public BooleanArrayReservation(BooleanConsumer applier, IntConsumer sizeApplier, BooleanSupplier extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public BooleanDataArrayReader createReadStream(DataInput input) {
+ return new BooleanDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public BooleanDataArrayWriter createWriteStream(DataOutput output) {
+ return new BooleanDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanCheckedReservation.java
new file mode 100644
index 0000000..1c3d9ec
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanCheckedReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.BooleanCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.BooleanCheckedDataWriter;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanCheckedReservation extends ReductionCheckedDataReservation<BooleanConsumer, BooleanSupplier> {
+
+ public BooleanCheckedReservation(BooleanConsumer applier, BooleanSupplier extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public BooleanCheckedDataReader createReadStream(DataInput input) {
+ return new BooleanCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public BooleanCheckedDataWriter createWriteStream(DataOutput output) {
+ return new BooleanCheckedDataWriter(output, extractor, exists);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanReservation.java
new file mode 100644
index 0000000..2e6b718
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/BooleanReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.BooleanDataReader;
+import org.apache.solr.analytics.stream.reservation.write.BooleanDataWriter;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanReservation extends ReductionDataReservation<BooleanConsumer, BooleanSupplier> {
+
+ public BooleanReservation(BooleanConsumer applier, BooleanSupplier extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public BooleanDataReader createReadStream(DataInput input) {
+ return new BooleanDataReader(input, applier);
+ }
+
+ @Override
+ public BooleanDataWriter createWriteStream(DataOutput output) {
+ return new BooleanDataWriter(output, extractor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleArrayReservation.java
new file mode 100644
index 0000000..6acf657
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleArrayReservation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.DoubleDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.DoubleDataArrayWriter;
+
+public class DoubleArrayReservation extends ReductionDataArrayReservation<DoubleConsumer, DoubleSupplier> {
+
+ public DoubleArrayReservation(DoubleConsumer applier, IntConsumer sizeApplier, DoubleSupplier extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public DoubleDataArrayReader createReadStream(DataInput input) {
+ return new DoubleDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public DoubleDataArrayWriter createWriteStream(DataOutput output) {
+ return new DoubleDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleCheckedReservation.java
new file mode 100644
index 0000000..a1dd461
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleCheckedReservation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.DoubleCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.DoubleCheckedDataWriter;
+
+public class DoubleCheckedReservation extends ReductionCheckedDataReservation<DoubleConsumer, DoubleSupplier> {
+
+ public DoubleCheckedReservation(DoubleConsumer applier, DoubleSupplier extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public DoubleCheckedDataReader createReadStream(DataInput input) {
+ return new DoubleCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public DoubleCheckedDataWriter createWriteStream(DataOutput output) {
+ return new DoubleCheckedDataWriter(output, extractor, exists);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleReservation.java
new file mode 100644
index 0000000..8ef3bef
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/DoubleReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.DoubleDataReader;
+import org.apache.solr.analytics.stream.reservation.write.DoubleDataWriter;
+
+public class DoubleReservation extends ReductionDataReservation<DoubleConsumer, DoubleSupplier> {
+
+ public DoubleReservation(DoubleConsumer applier, DoubleSupplier extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public DoubleDataReader createReadStream(DataInput input) {
+ return new DoubleDataReader(input, applier);
+ }
+
+ @Override
+ public DoubleDataWriter createWriteStream(DataOutput output) {
+ return new DoubleDataWriter(output, extractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatArrayReservation.java
new file mode 100644
index 0000000..702106d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatArrayReservation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.FloatDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.FloatDataArrayWriter;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatArrayReservation extends ReductionDataArrayReservation<FloatConsumer, FloatSupplier> {
+
+ public FloatArrayReservation(FloatConsumer applier, IntConsumer sizeApplier, FloatSupplier extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public FloatDataArrayReader createReadStream(DataInput input) {
+ return new FloatDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public FloatDataArrayWriter createWriteStream(DataOutput output) {
+ return new FloatDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatCheckedReservation.java
new file mode 100644
index 0000000..581772c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatCheckedReservation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.FloatCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.FloatCheckedDataWriter;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatCheckedReservation extends ReductionCheckedDataReservation<FloatConsumer, FloatSupplier> {
+
+ public FloatCheckedReservation(FloatConsumer applier, FloatSupplier extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public FloatCheckedDataReader createReadStream(DataInput input) {
+ return new FloatCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public FloatCheckedDataWriter createWriteStream(DataOutput output) {
+ return new FloatCheckedDataWriter(output, extractor, exists);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatReservation.java
new file mode 100644
index 0000000..c0ea5f0
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/FloatReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+
+import org.apache.solr.analytics.stream.reservation.read.FloatDataReader;
+import org.apache.solr.analytics.stream.reservation.write.FloatDataWriter;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatReservation extends ReductionDataReservation<FloatConsumer, FloatSupplier> {
+
+ public FloatReservation(FloatConsumer applier, FloatSupplier extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public FloatDataReader createReadStream(DataInput input) {
+ return new FloatDataReader(input, applier);
+ }
+
+ @Override
+ public FloatDataWriter createWriteStream(DataOutput output) {
+ return new FloatDataWriter(output, extractor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntArrayReservation.java
new file mode 100644
index 0000000..e3639a1
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntArrayReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.IntDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.IntDataArrayWriter;
+
+public class IntArrayReservation extends ReductionDataArrayReservation<IntConsumer, IntSupplier> {
+
+ public IntArrayReservation(IntConsumer applier, IntConsumer sizeApplier, IntSupplier extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public IntDataArrayReader createReadStream(DataInput input) {
+ return new IntDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public IntDataArrayWriter createWriteStream(DataOutput output) {
+ return new IntDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntCheckedReservation.java
new file mode 100644
index 0000000..c0a7cf2
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntCheckedReservation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.IntCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.IntCheckedDataWriter;
+
+public class IntCheckedReservation extends ReductionCheckedDataReservation<IntConsumer, IntSupplier> {
+
+ public IntCheckedReservation(IntConsumer applier, IntSupplier extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public IntCheckedDataReader createReadStream(DataInput input) {
+ return new IntCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public IntCheckedDataWriter createWriteStream(DataOutput output) {
+ return new IntCheckedDataWriter(output, extractor, exists);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntReservation.java
new file mode 100644
index 0000000..cb66b58
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/IntReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.IntDataReader;
+import org.apache.solr.analytics.stream.reservation.write.IntDataWriter;
+
+public class IntReservation extends ReductionDataReservation<IntConsumer, IntSupplier> {
+
+ public IntReservation(IntConsumer applier, IntSupplier extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public IntDataReader createReadStream(DataInput input) {
+ return new IntDataReader(input, applier);
+ }
+
+ @Override
+ public IntDataWriter createWriteStream(DataOutput output) {
+ return new IntDataWriter(output, extractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongArrayReservation.java
new file mode 100644
index 0000000..980bc2b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongArrayReservation.java
@@ -0,0 +1,45 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.LongDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.LongDataArrayWriter;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+public class LongArrayReservation extends ReductionDataArrayReservation<LongConsumer, LongSupplier> {
+
+ public LongArrayReservation(LongConsumer applier, IntConsumer sizeApplier, LongSupplier extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public LongDataArrayReader createReadStream(DataInput input) {
+ return new LongDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public LongDataArrayWriter createWriteStream(DataOutput output) {
+ return new LongDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongCheckedReservation.java
new file mode 100644
index 0000000..e1626e5
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongCheckedReservation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.BooleanSupplier;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.LongCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.LongCheckedDataWriter;
+
+public class LongCheckedReservation extends ReductionCheckedDataReservation<LongConsumer, LongSupplier> {
+
+ public LongCheckedReservation(LongConsumer applier, LongSupplier extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public LongCheckedDataReader createReadStream(DataInput input) {
+ return new LongCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public LongCheckedDataWriter createWriteStream(DataOutput output) {
+ return new LongCheckedDataWriter(output, extractor, exists);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongReservation.java
new file mode 100644
index 0000000..daf8ec3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/LongReservation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+
+import org.apache.solr.analytics.stream.reservation.read.LongDataReader;
+import org.apache.solr.analytics.stream.reservation.write.LongDataWriter;
+
+public class LongReservation extends ReductionDataReservation<LongConsumer, LongSupplier> {
+
+ public LongReservation(LongConsumer applier, LongSupplier extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public LongDataReader createReadStream(DataInput input) {
+ return new LongDataReader(input, applier);
+ }
+
+ @Override
+ public LongDataWriter createWriteStream(DataOutput output) {
+ return new LongDataWriter(output, extractor);
+ }
+}
\ No newline at end of file
[02/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/FunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/FunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/FunctionTest.java
new file mode 100644
index 0000000..dac7921
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/FunctionTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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.analytics.expression;
+
+
+import org.apache.solr.analytics.AbstractAnalyticsStatsTest;
+import org.apache.solr.analytics.facet.AbstractAnalyticsFacetTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class FunctionTest extends AbstractAnalyticsStatsTest {
+ static String fileName = "functions.txt";
+
+ static public final int INT = 71;
+ static public final int LONG = 36;
+ static public final int FLOAT = 93;
+ static public final int DOUBLE = 49;
+ static public final int DATE = 12;
+ static public final int STRING = 28;
+ static public final int NUM_LOOPS = 100;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
+ h.update("<delete><query>*:*</query></delete>");
+
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT+1;
+ long l = j%LONG+1;
+ float f = j%FLOAT+1;
+ double d = j%DOUBLE+1;
+ double d0 = j%DOUBLE;
+ String dt = (1800+j%DATE) + "-06-30T23:59:59Z";
+ String s = "str" + (j%STRING);
+
+ double add_if = (double)i+f;
+ double add_ldf = (double)l+d+f;
+ double mult_if = (double)i*f;
+ double mult_ldf = (double)l*d*f;
+ double div_if = (double)i/f;
+ double div_ld = (double)l/d;
+ double pow_if = Math.pow(i,f);
+ double pow_ld = Math.pow(l,d);
+ int neg_i = i*-1;
+ long neg_l = l*-1;
+ String dm_2y = (1802+j%DATE) + "-06-30T23:59:59Z";
+ String dm_2m = (1800+j%DATE) + "-08-30T23:59:59Z";
+ String concat_first = "this is the first"+s;
+ String concat_second = "this is the second"+s;
+
+ assertU(adoc(AbstractAnalyticsFacetTest.filter("id", "1000" + j, "int_id", "" + i, "long_ld", "" + l, "float_fd", "" + f,
+ "double_dd", "" + d, "date_dtd", dt, "string_sd", s,
+ "add_if_dd", ""+add_if, "add_ldf_dd", ""+add_ldf, "mult_if_dd", ""+mult_if, "mult_ldf_dd", ""+mult_ldf,
+ "div_if_dd", ""+div_if, "div_ld_dd", ""+div_ld, "pow_if_dd", ""+pow_if, "pow_ld_dd", ""+pow_ld,
+ "neg_id", ""+neg_i, "neg_ld", ""+neg_l, "const_8_dd", "8", "const_10_dd", "10", "dm_2y_dtd", dm_2y, "dm_2m_dtd", dm_2m,
+ "const_00_dtd", "1800-06-30T23:59:59Z", "const_04_dtd", "1804-06-30T23:59:59Z", "const_first_sd", "this is the first", "const_second_sd", "this is the second",
+ "concat_first_sd", concat_first, "concat_second_sd", concat_second, "miss_dd", ""+d0 )));
+
+
+ if (usually()) {
+ assertU(commit()); // to have several segments
+ }
+ }
+
+ assertU(commit());
+
+ setResponse(h.query(request(fileToStringArr(FunctionTest.class, fileName))));
+ }
+
+ @Test
+ public void addTest() throws Exception {
+ double result = (Double)getStatResult("ar", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("ar", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ // TODO checfk why asserted 2times
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("ar", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("ar", "meanc", VAL_TYPE.DOUBLE);
+ assertTrue(result==calculated);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void multiplyTest() throws Exception {
+ double result = (Double)getStatResult("mr", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("mr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("mr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("mr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void divideTest() throws Exception {
+ Double result = (Double)getStatResult("dr", "sum", VAL_TYPE.DOUBLE);
+ Double calculated = (Double)getStatResult("dr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("dr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("dr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void powerTest() throws Exception {
+ double result = (Double)getStatResult("pr", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("pr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("pr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("pr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void negateTest() throws Exception {
+ double result = (Double)getStatResult("nr", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("nr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("nr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("nr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void absoluteValueTest() throws Exception {
+ double result = (Double)getStatResult("avr", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("avr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("avr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("avr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void constantNumberTest() throws Exception {
+ double result = (Double)getStatResult("cnr", "sum", VAL_TYPE.DOUBLE);
+ double calculated = (Double)getStatResult("cnr", "sumc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+
+ result = (Double)getStatResult("cnr", "mean", VAL_TYPE.DOUBLE);
+ calculated = (Double)getStatResult("cnr", "meanc", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ assertEquals(getRawResponse(), result, calculated, 0.0);
+ }
+
+ @Test
+ public void dateMathTest() throws Exception {
+ String result = (String)getStatResult("dmr", "median", VAL_TYPE.DATE);
+ String calculated = (String)getStatResult("dmr", "medianc", VAL_TYPE.DATE);
+ assertEquals(getRawResponse(), result, calculated);
+
+ result = (String)getStatResult("dmr", "max", VAL_TYPE.DATE);
+ calculated = (String)getStatResult("dmr", "maxc", VAL_TYPE.DATE);
+ assertEquals(getRawResponse(), result, calculated);
+ }
+
+ @Test
+ public void constantDateTest() throws Exception {
+ String result = (String)getStatResult("cdr", "median", VAL_TYPE.DATE);
+ String calculated = (String)getStatResult("cdr", "medianc", VAL_TYPE.DATE);
+ assertEquals(getRawResponse(), result, calculated);
+ assertEquals(getRawResponse(), result, calculated);
+
+ result = (String)getStatResult("cdr", "max", VAL_TYPE.DATE);
+ calculated = (String)getStatResult("cdr", "maxc", VAL_TYPE.DATE);
+ assertEquals(getRawResponse(), result, calculated);
+ }
+
+ @Test
+ public void constantStringTest() throws Exception {
+ String result = (String)getStatResult("csr", "min", VAL_TYPE.STRING);
+ String calculated = (String)getStatResult("csr", "minc", VAL_TYPE.STRING);
+ assertEquals(getRawResponse(), result, calculated);
+
+ result = (String)getStatResult("csr", "max", VAL_TYPE.STRING);
+ calculated = (String)getStatResult("csr", "maxc", VAL_TYPE.STRING);
+ assertEquals(getRawResponse(), result, calculated);
+ }
+
+ @Test
+ public void concatenateTest() throws Exception {
+ String result = (String)getStatResult("cr", "min", VAL_TYPE.STRING);
+ String calculated = (String)getStatResult("cr", "minc", VAL_TYPE.STRING);
+ assertEquals(getRawResponse(), result, calculated);
+
+ result = (String)getStatResult("cr", "max", VAL_TYPE.STRING);
+ calculated = (String)getStatResult("cr", "maxc", VAL_TYPE.STRING);
+ assertEquals(getRawResponse(), result, calculated);
+ }
+
+ @Test
+ public void missingTest() throws Exception {
+ double min = (Double)getStatResult("ms", "min", VAL_TYPE.DOUBLE);
+ double max = (Double)getStatResult("ms", "max", VAL_TYPE.DOUBLE);
+ assertEquals(getRawResponse(), 48.0d, max, 0.0);
+ assertEquals(getRawResponse(), 1.0d, min, 0.0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetCloudTest.java
new file mode 100644
index 0000000..99e5103
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetCloudTest.java
@@ -0,0 +1,284 @@
+/*
+ * 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.analytics.facet;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Scanner;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.lucene.util.IOUtils;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.analytics.util.MedianCalculator;
+import org.apache.solr.analytics.util.OrdinalCalculator;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.AbstractDistribZkTestBase;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.junit.AfterClass;
+
+public class AbstractAnalyticsFacetCloudTest extends SolrCloudTestCase {
+ protected static final HashMap<String,Object> defaults = new HashMap<>();
+
+ protected static final String COLLECTIONORALIAS = "collection1";
+ protected static final int TIMEOUT = DEFAULT_TIMEOUT;
+ protected static final String id = "id";
+
+ public static void setupCluster() throws Exception {
+ configureCluster(2)
+ .addConfig("conf", configset("cloud-analytics"))
+ .configure();
+
+ CollectionAdminRequest.createCollection(COLLECTIONORALIAS, "conf", 2, 1).process(cluster.getSolrClient());
+ AbstractDistribZkTestBase.waitForRecoveriesToFinish(COLLECTIONORALIAS, cluster.getSolrClient().getZkStateReader(),
+ false, true, TIMEOUT);
+
+ cleanIndex();
+ }
+
+ public static void cleanIndex() throws Exception {
+ new UpdateRequest()
+ .deleteByQuery("*:*")
+ .commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ protected String latestType = "";
+
+ @AfterClass
+ public static void afterClassAbstractAnalysis() {
+ defaults.clear();
+ }
+
+ protected NamedList<Object> queryCloudAnalytics(String[] testParams) throws SolrServerException, IOException, InterruptedException {
+ ModifiableSolrParams params = new ModifiableSolrParams();
+ params.set("q", "*:*");
+ params.set("indent", "true");
+ params.set("olap", "true");
+ params.set("rows", "0");
+ for (int i = 0; i + 1 < testParams.length;) {
+ params.add(testParams[i++], testParams[i++]);
+ }
+ cluster.waitForAllNodes(10000);
+ QueryRequest qreq = new QueryRequest(params);
+ QueryResponse resp = qreq.process(cluster.getSolrClient(), COLLECTIONORALIAS);
+ return resp.getResponse();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected <T> ArrayList<T> getValueList(NamedList<Object> response, String infoName, String facetType, String facetName, String exprName, boolean includeMissing) {
+ NamedList<NamedList<Object>> facetList =
+ (NamedList<NamedList<Object>>)response.findRecursive(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER,
+ infoName,
+ facetType,
+ facetName);
+
+ ArrayList<T> results = new ArrayList<>();
+ facetList.forEach( (name, expressions) -> {
+ if (!includeMissing && !name.equals("(MISSING)")) {
+ T result = (T)expressions.get(exprName);
+ if (result != null)
+ results.add(result);
+ }
+ });
+ return results;
+ }
+
+ protected boolean responseContainsFacetValue(NamedList<Object> response, String infoName, String facetType, String facetName, String facetValue) {
+ return null != response.findRecursive(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER,
+ infoName,
+ facetType,
+ facetName,
+ facetValue);
+ }
+
+
+ public static void increment(List<Long> list, int idx){
+ Long i = list.remove(idx);
+ list.add(idx, i+1);
+ }
+
+ public static String[] filter(String...args){
+ List<String> l = new ArrayList<>();
+ for( int i=0; i <args.length; i+=2){
+ if( args[i+1].equals("0") || args[i+1].equals("0.0") ||
+ args[i+1].equals("1800-12-31T23:59:59Z") || args[i+1].equals("str0") ||
+ args[i+1].equals("this is the firststr0") ||
+ args[i+1].equals("this is the secondstr0") ){
+ continue;
+ }
+ l.add(args[i]);
+ l.add(args[i+1]);
+ }
+ return l.toArray(new String[0]);
+ }
+
+ protected void setLatestType(String latestType) {
+ this.latestType = latestType;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public <T extends Number & Comparable<T>> ArrayList calculateNumberStat(ArrayList<ArrayList<T>> lists, String stat) {
+ ArrayList result;
+ if (stat.equals("median")) {
+ result = new ArrayList<Double>();
+ for (List<T> list : lists) {
+ result.add(MedianCalculator.getMedian(list));
+ }
+ } else if (stat.equals("mean")) {
+ result = new ArrayList<Double>();
+ for (List<T> list : lists) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue();
+ }
+ result.add(d/list.size());
+ }
+ } else if (stat.equals("sum")) {
+ result = new ArrayList<Double>();
+ for (Collection<T> list : lists) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue();
+ }
+ result.add(d);
+ }
+ } else if (stat.equals("sumOfSquares")) {
+ result = new ArrayList<Double>();
+ for (List<T> list : lists) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue()*element.doubleValue();
+ }
+ result.add(d);
+ }
+ } else if (stat.equals("stddev")) {
+ result = new ArrayList<Double>();
+ for (List<T> list : lists) {
+ double sum = 0;
+ double sumSquares = 0;
+ for (T element : list) {
+ sum += element.doubleValue();
+ sumSquares += element.doubleValue()*element.doubleValue();
+ }
+ String res = Double.toString(Math.sqrt(sumSquares/list.size()-sum*sum/(list.size()*list.size())));
+ result.add(Double.parseDouble(res));
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ return result;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public <T extends Comparable<T>> ArrayList calculateStat(ArrayList<ArrayList<T>> lists, String stat) {
+ ArrayList result;
+ if (stat.contains("perc_")) {
+ result = new ArrayList<T>();
+ for (List<T> list : lists) {
+ if( list.size() == 0) continue;
+ int ord = (int) Math.ceil(Double.parseDouble(stat.substring(5))/100 * list.size()) - 1;
+ ArrayList<Integer> percs = new ArrayList<>(1);
+ percs.add(ord);
+ OrdinalCalculator.putOrdinalsInPosition(list, percs);
+ result.add(list.get(ord));
+ }
+ } else if (stat.equals("count")) {
+ result = new ArrayList<Long>();
+ for (List<T> list : lists) {
+ result.add((long)list.size());
+ }
+ } else if (stat.equals("missing")) {
+ result = new ArrayList<Long>();
+ for (ArrayList<T> list : lists) {
+ result.add(calculateMissing(list,latestType));
+ }
+ } else if (stat.equals("unique")) {
+ result = new ArrayList<Long>();
+ for (List<T> list : lists) {
+ HashSet<T> set = new HashSet<>();
+ set.addAll(list);
+ result.add((long)set.size());
+ }
+ } else if (stat.equals("max")) {
+ result = new ArrayList<T>();
+ for (List<T> list : lists) {
+ if( list.size() == 0) continue;
+ Collections.sort(list);
+ result.add(list.get(list.size()-1));
+ }
+ } else if (stat.equals("min")) {
+ result = new ArrayList<T>();
+ for (List<T> list : lists) {
+ if( list.size() == 0) continue;
+ Collections.sort((List<T>)list);
+ result.add(list.get(0));
+ }
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Comparable<T>> Long calculateMissing(ArrayList<T> list, String type) {
+ T def = (T)defaults.get(type);
+ long miss = 0;
+ for (T element : list) {
+ if (element.compareTo(def)==0) {
+ miss++;
+ }
+ }
+ return Long.valueOf(miss);
+ }
+
+ public static ModifiableSolrParams fileToParams(Class<?> clazz, String fileName) throws FileNotFoundException {
+ InputStream in = clazz.getResourceAsStream(fileName);
+ if (in == null) throw new FileNotFoundException("Resource not found: " + fileName);
+ Scanner file = new Scanner(in, "UTF-8");
+ try {
+ ModifiableSolrParams params = new ModifiableSolrParams();
+ params.set("q", "*:*");
+ params.set("indent", "true");
+ params.set("olap", "true");
+ params.set("rows", "0");
+ while (file.hasNextLine()) {
+ String line = file.nextLine();
+ line = line.trim();
+ if( StringUtils.isBlank(line) || line.startsWith("#")){
+ continue;
+ }
+ String[] param = line.split("=");
+ params.set(param[0], param[1]);
+ }
+ return params;
+ } finally {
+ IOUtils.closeWhileHandlingException(file, in);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetTest.java
index 3660208..ff0e7da 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/AbstractAnalyticsFacetTest.java
@@ -31,8 +31,9 @@ import java.util.Scanner;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
import org.apache.solr.analytics.util.MedianCalculator;
-import org.apache.solr.analytics.util.PercentileCalculator;
+import org.apache.solr.analytics.util.OrdinalCalculator;
import org.apache.solr.request.SolrQueryRequest;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -92,9 +93,10 @@ public class AbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
}
private NodeList getNodes(String n1, String n2, String n3, String element, String n4) throws XPathExpressionException {
// Construct the XPath expression. The form better not change or all these will fail.
- StringBuilder sb = new StringBuilder("/response/lst[@name='stats']/lst[@name='").append(n1).append("']");
+ StringBuilder sb = new StringBuilder("/response/lst[@name='"+AnalyticsResponseHeadings.COMPLETED_OLD_HEADER+"']/lst[@name='").append(n1).append("']");
sb.append("/lst[@name='").append(n2).append("']");
sb.append("/lst[@name='").append(n3).append("']");
+ sb.append("/lst[@name!='(MISSING)']");
sb.append("//").append(element).append("[@name='").append(n4).append("']");
return (NodeList)xPathFact.newXPath().compile(sb.toString()).evaluate(doc, XPathConstants.NODESET);
@@ -229,11 +231,14 @@ public class AbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
public <T extends Comparable<T>> ArrayList calculateStat(ArrayList<ArrayList<T>> lists, String stat) {
ArrayList result;
if (stat.contains("perc_")) {
- double[] perc = new double[]{Double.parseDouble(stat.substring(5))/100};
result = new ArrayList<T>();
for (List<T> list : lists) {
if( list.size() == 0) continue;
- result.add(PercentileCalculator.getPercentiles(list, perc).get(0));
+ int ord = (int) Math.ceil(Double.parseDouble(stat.substring(5))/100 * list.size()) - 1;
+ ArrayList<Integer> percs = new ArrayList<>(1);
+ percs.add(ord);
+ OrdinalCalculator.putOrdinalsInPosition(list, percs);
+ result.add(list.get(ord));
}
} else if (stat.equals("count")) {
result = new ArrayList<Long>();
@@ -294,7 +299,7 @@ public class AbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
public static String[] fileToStringArr(Class<?> clazz, String fileName) throws FileNotFoundException {
- InputStream in = clazz.getResourceAsStream(fileName);
+ InputStream in = clazz.getResourceAsStream("/solr/analytics/" + fileName);
if (in == null) throw new FileNotFoundException("Resource not found: " + fileName);
Scanner file = new Scanner(in, "UTF-8");
try {
@@ -304,7 +309,14 @@ public class AbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
if (line.length()<2) {
continue;
}
+ int commentStart = line.indexOf("//");
+ if (commentStart >= 0) {
+ line = line.substring(0,commentStart);
+ }
String[] param = line.split("=");
+ if (param.length != 2) {
+ continue;
+ }
strList.add(param[0]);
strList.add(param[1]);
}
@@ -313,4 +325,19 @@ public class AbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
IOUtils.closeWhileHandlingException(file, in);
}
}
+
+ protected void removeNodes(String xPath, List<Double> string) throws XPathExpressionException {
+ NodeList missingNodes = getNodes(xPath);
+ List<Double> result = new ArrayList<Double>();
+ for (int idx = 0; idx < missingNodes.getLength(); ++idx) {
+ result.add(Double.parseDouble(missingNodes.item(idx).getTextContent()));
+ }
+ string.removeAll(result);
+ }
+
+ protected NodeList getNodes(String xPath) throws XPathExpressionException {
+ StringBuilder sb = new StringBuilder(xPath);
+ return (NodeList) xPathFact.newXPath().compile(sb.toString()).evaluate(doc, XPathConstants.NODESET);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FacetSortingTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FacetSortingTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FacetSortingTest.java
new file mode 100644
index 0000000..ef09014
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FacetSortingTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.analytics.facet;
+
+import org.apache.solr.analytics.AbstractAnalyticsStatsTest;
+import org.apache.solr.analytics.expression.ExpressionTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class FacetSortingTest extends AbstractAnalyticsStatsTest {
+ private static String fileName = "facetSorting.txt";
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig-analytics.xml", "schema-analytics.xml");
+ h.update("<delete><query>*:*</query></delete>");
+
+ // The data set below is so generated that in bucket corresponding fieldFacet B, double_dd column has null values
+ // and in bucket C corresponding to fieldFacet C has null values for column long_ld.
+ // FieldFaceting occurs on string_sd field
+ assertU(adoc("id", "1001", "string_sd", "A", "double_dd", "" + 3, "long_ld", "" + 1));
+ assertU(adoc("id", "1002", "string_sd", "A", "double_dd", "" + 25, "long_ld", "" + 2));
+ assertU(adoc("id", "1003", "string_sd", "B", "long_ld", "" + 3));
+ assertU(adoc("id", "1004", "string_sd", "B", "long_ld", "" + 4));
+ assertU(adoc("id", "1005", "string_sd", "C", "double_dd", "" + 17));
+
+ assertU(commit());
+ String response = h.query(request(fileToStringArr(ExpressionTest.class, fileName)));
+ setResponse(response);
+ }
+
+ @Test
+ public void addTest() throws Exception {
+ Double minResult = (Double) getStatResult("ar", "min", VAL_TYPE.DOUBLE);
+ Long maxResult = (Long) getStatResult("ar", "max", VAL_TYPE.LONG);
+ assertEquals(Double.valueOf(minResult), Double.valueOf(3.0));
+ assertEquals(Long.valueOf(maxResult),Long.valueOf(4));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetCloudTest.java
new file mode 100644
index 0000000..b3341b1
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/facet/FieldFacetCloudTest.java
@@ -0,0 +1,1214 @@
+/*
+ * 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.analytics.facet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.NamedList;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+public class FieldFacetCloudTest extends AbstractAnalyticsFacetCloudTest{
+ public static final int INT = 71;
+ public static final int LONG = 36;
+ public static final int LONGM = 50;
+ public static final int FLOAT = 73;
+ public static final int FLOATM = 84;
+ public static final int DOUBLE = 49;
+ public static final int DATE = 12;
+ public static final int DATEM = 30;
+ public static final int STRING = 29;
+ public static final int STRINGM = 41;
+ public static final int NUM_LOOPS = 100;
+
+ //INT
+ private static ArrayList<ArrayList<Integer>> intDateTestStart;
+ private static ArrayList<Long> intDateTestMissing;
+ private static ArrayList<ArrayList<Integer>> intStringTestStart;
+ private static ArrayList<Long> intStringTestMissing;
+
+ //LONG
+ private static ArrayList<ArrayList<Long>> longDateTestStart;
+ private static ArrayList<Long> longDateTestMissing;
+ private static ArrayList<ArrayList<Long>> longStringTestStart;
+ private static ArrayList<Long> longStringTestMissing;
+
+ //FLOAT
+ private static ArrayList<ArrayList<Float>> floatDateTestStart;
+ private static ArrayList<Long> floatDateTestMissing;
+ private static ArrayList<ArrayList<Float>> floatStringTestStart;
+ private static ArrayList<Long> floatStringTestMissing;
+
+ //DOUBLE
+ private static ArrayList<ArrayList<Double>> doubleDateTestStart;
+ private static ArrayList<Long> doubleDateTestMissing;
+ private static ArrayList<ArrayList<Double>> doubleStringTestStart;
+ private static ArrayList<Long> doubleStringTestMissing;
+
+ //DATE
+ private static ArrayList<ArrayList<String>> dateIntTestStart;
+ private static ArrayList<Long> dateIntTestMissing;
+ private static ArrayList<ArrayList<String>> dateLongTestStart;
+ private static ArrayList<Long> dateLongTestMissing;
+
+ //String
+ private static ArrayList<ArrayList<String>> stringIntTestStart;
+ private static ArrayList<Long> stringIntTestMissing;
+ private static ArrayList<ArrayList<String>> stringLongTestStart;
+ private static ArrayList<Long> stringLongTestMissing;
+
+ //Multi-Valued
+ private static ArrayList<ArrayList<Integer>> multiLongTestStart;
+ private static ArrayList<Long> multiLongTestMissing;
+ private static ArrayList<ArrayList<Integer>> multiStringTestStart;
+ private static ArrayList<Long> multiStringTestMissing;
+ private static ArrayList<ArrayList<Integer>> multiDateTestStart;
+ private static ArrayList<Long> multiDateTestMissing;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ setupCluster();
+
+ //INT
+ intDateTestStart = new ArrayList<>();
+ intDateTestMissing = new ArrayList<>();
+ intStringTestStart = new ArrayList<>();
+ intStringTestMissing = new ArrayList<>();
+
+ //LONG
+ longDateTestStart = new ArrayList<>();
+ longDateTestMissing = new ArrayList<>();
+ longStringTestStart = new ArrayList<>();
+ longStringTestMissing = new ArrayList<>();
+
+ //FLOAT
+ floatDateTestStart = new ArrayList<>();
+ floatDateTestMissing = new ArrayList<>();
+ floatStringTestStart = new ArrayList<>();
+ floatStringTestMissing = new ArrayList<>();
+
+ //DOUBLE
+ doubleDateTestStart = new ArrayList<>();
+ doubleDateTestMissing = new ArrayList<>();
+ doubleStringTestStart = new ArrayList<>();
+ doubleStringTestMissing = new ArrayList<>();
+
+ //DATE
+ dateIntTestStart = new ArrayList<>();
+ dateIntTestMissing = new ArrayList<>();
+ dateLongTestStart = new ArrayList<>();
+ dateLongTestMissing = new ArrayList<>();
+
+ //String
+ stringIntTestStart = new ArrayList<>();
+ stringIntTestMissing = new ArrayList<>();
+ stringLongTestStart = new ArrayList<>();
+ stringLongTestMissing = new ArrayList<>();
+
+ //Multi-Valued
+ multiLongTestStart = new ArrayList<>();
+ multiLongTestMissing = new ArrayList<>();
+ multiStringTestStart = new ArrayList<>();
+ multiStringTestMissing = new ArrayList<>();
+ multiDateTestStart = new ArrayList<>();
+ multiDateTestMissing = new ArrayList<>();
+
+ UpdateRequest req = new UpdateRequest();
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT;
+ long l = j%LONG;
+ long lm = j%LONGM;
+ float f = j%FLOAT;
+ double d = j%DOUBLE;
+ int dt = j%DATE;
+ int dtm = j%DATEM;
+ int s = j%STRING;
+ int sm = j%STRINGM;
+
+ List<String> fields = new ArrayList<>();
+ fields.add("id"); fields.add("1000"+j);
+
+ if (dt != 0) {
+ }
+ if( i != 0 ) {
+ fields.add("int_id"); fields.add("" + i);
+ }
+ if( l != 0l ) {
+ fields.add("long_ld"); fields.add("" + l);
+ fields.add("long_ldm"); fields.add("" + l);
+ }
+ if( lm != 0l ) {
+ fields.add("long_ldm"); fields.add("" + lm);
+ }
+ if( f != 0.0f ) {
+ fields.add("float_fd"); fields.add("" + f);
+ }
+ if( d != 0.0d ) {
+ fields.add("double_dd"); fields.add("" + d);
+ }
+ if( dt != 0 ) {
+ fields.add("date_dtd"); fields.add((1800+dt) + "-12-31T23:59:59Z");
+ fields.add("date_dtdm"); fields.add((1800+dt) + "-12-31T23:59:59Z");
+ }
+ if ( dtm != 0 ) {
+ fields.add("date_dtdm"); fields.add((1800+dtm) + "-12-31T23:59:59Z");
+ }
+ if ( s != 0 ) {
+ fields.add("string_sd"); fields.add("str" + s);
+ fields.add("string_sdm"); fields.add("str" + s);
+ }
+ if ( sm != 0 ) {
+ fields.add("string_sdm"); fields.add("str" + sm);
+ }
+ if ( dtm != 0 ) {
+ fields.add("date_dtdm"); fields.add((1800+dtm) + "-12-31T23:59:59Z");
+ }
+ req.add(fields.toArray(new String[0]));
+
+ if( dt != 0 ){
+ //Dates
+ if (j-DATE<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ if( i != 0 ){
+ list1.add(i);
+ intDateTestMissing.add(0l);
+ } else {
+ intDateTestMissing.add(1l);
+ }
+ intDateTestStart.add(list1);
+ ArrayList<Long> list2 = new ArrayList<>();
+ if( l != 0l ){
+ list2.add(l);
+ longDateTestMissing.add(0l);
+ } else {
+ longDateTestMissing.add(1l);
+ }
+ longDateTestStart.add(list2);
+ ArrayList<Float> list3 = new ArrayList<>();
+ if ( f != 0.0f ){
+ list3.add(f);
+ floatDateTestMissing.add(0l);
+ } else {
+ floatDateTestMissing.add(1l);
+
+ }
+ floatDateTestStart.add(list3);
+ ArrayList<Double> list4 = new ArrayList<>();
+ if( d != 0.0d ){
+ list4.add(d);
+ doubleDateTestMissing.add(0l);
+ } else {
+ doubleDateTestMissing.add(1l);
+ }
+ doubleDateTestStart.add(list4);
+ ArrayList<Integer> list5 = new ArrayList<>();
+ if( i != 0 ){
+ list5.add(i);
+ multiDateTestMissing.add(0l);
+ } else {
+ multiDateTestMissing.add(1l);
+
+ }
+ multiDateTestStart.add(list5);
+ } else {
+ if( i != 0 ) intDateTestStart.get(dt-1).add(i); else increment(intDateTestMissing,dt-1);
+ if( l != 0l ) longDateTestStart.get(dt-1).add(l); else increment(longDateTestMissing,dt-1);
+ if( f != 0.0f ) floatDateTestStart.get(dt-1).add(f); else increment(floatDateTestMissing,dt-1);
+ if( d != 0.0d ) doubleDateTestStart.get(dt-1).add(d); else increment(doubleDateTestMissing,dt-1);
+ if( i != 0 ) multiDateTestStart.get(dt-1).add(i); else increment(multiDateTestMissing,dt-1);
+ }
+ }
+
+ if (j-DATEM<0 && dtm!=dt && dtm!=0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ if( i != 0 ){
+ list1.add(i);
+ multiDateTestMissing.add(0l);
+ } else {
+ multiDateTestMissing.add(1l);
+ }
+ multiDateTestStart.add(list1);
+ } else if (dtm!=dt && dtm!=0) {
+ if( i != 0 ) multiDateTestStart.get(dtm-1).add(i);
+ }
+
+ if( s != 0 ){
+ //Strings
+ if (j-STRING<0) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ if( i != 0 ){
+ list1.add(i);
+ intStringTestMissing.add(0l);
+ } else {
+ intStringTestMissing.add(1l);
+ }
+ intStringTestStart.add(list1);
+ ArrayList<Long> list2 = new ArrayList<>();
+ if( l != 0l ){
+ list2.add(l);
+ longStringTestMissing.add(0l);
+ } else {
+ longStringTestMissing.add(1l);
+ }
+ longStringTestStart.add(list2);
+ ArrayList<Float> list3 = new ArrayList<>();
+ if( f != 0.0f ){
+ list3.add(f);
+ floatStringTestMissing.add(0l);
+ } else {
+ floatStringTestMissing.add(1l);
+ }
+ floatStringTestStart.add(list3);
+ ArrayList<Double> list4 = new ArrayList<>();
+ if( d != 0.0d ){
+ list4.add(d);
+ doubleStringTestMissing.add(0l);
+ } else {
+ doubleStringTestMissing.add(1l);
+ }
+ doubleStringTestStart.add(list4);
+ ArrayList<Integer> list5 = new ArrayList<>();
+ if( i != 0 ){
+ list5.add(i);
+ multiStringTestMissing.add(0l);
+ } else {
+ multiStringTestMissing.add(1l);
+ }
+ multiStringTestStart.add(list5);
+ } else {
+ if( i != 0 ) intStringTestStart.get(s-1).add(i); else increment(intStringTestMissing,s-1);
+ if( l != 0l ) longStringTestStart.get(s-1).add(l); else increment(longStringTestMissing,s-1);
+ if( f != 0.0f ) floatStringTestStart.get(s-1).add(f); else increment(floatStringTestMissing,s-1);
+ if( d != 0.0d ) doubleStringTestStart.get(s-1).add(d); else increment(doubleStringTestMissing,s-1);
+ if( i != 0 ) multiStringTestStart.get(s-1).add(i); else increment(multiStringTestMissing,s-1);
+ }
+ }
+
+ //Strings
+ if( sm != 0 ){
+ if (j-STRINGM<0&&sm!=s) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ if( i != 0 ){
+ list1.add(i);
+ multiStringTestMissing.add(0l);
+ } else {
+ multiStringTestMissing.add(1l);
+ }
+ multiStringTestStart.add(list1);
+ } else if (sm!=s) {
+ if( i != 0 ) multiStringTestStart.get(sm-1).add(i); else increment(multiStringTestMissing,sm-1);
+ }
+ }
+
+ //Int
+ if( i != 0 ){
+ if (j-INT<0) {
+ ArrayList<String> list1 = new ArrayList<>();
+ if( dt != 0 ){
+ list1.add((1800+dt) + "-12-31T23:59:59Z");
+ dateIntTestMissing.add(0l);
+ } else {
+ dateIntTestMissing.add(1l);
+ }
+ dateIntTestStart.add(list1);
+ ArrayList<String> list2 = new ArrayList<>();
+ if( s != 0 ){
+ list2.add("str"+s);
+ stringIntTestMissing.add(0l);
+ } else {
+ stringIntTestMissing.add(1l);
+ }
+ stringIntTestStart.add(list2);
+ } else {
+ if( dt != 0 ) dateIntTestStart.get(i-1).add((1800+dt) + "-12-31T23:59:59Z"); else increment(dateIntTestMissing,i-1);
+ if( s != 0 ) stringIntTestStart.get(i-1).add("str"+s); else increment(stringIntTestMissing,i-1);
+ }
+ }
+
+ //Long
+ if( l != 0 ){
+ if (j-LONG<0) {
+ ArrayList<String> list1 = new ArrayList<>();
+ if( dt != 0 ){
+ list1.add((1800+dt) + "-12-31T23:59:59Z");
+ dateLongTestMissing.add(0l);
+ } else {
+ dateLongTestMissing.add(1l);
+ }
+ dateLongTestStart.add(list1);
+ ArrayList<String> list2 = new ArrayList<>();
+ if( s != 0 ){
+ list2.add("str"+s);
+ stringLongTestMissing.add(0l);
+ } else {
+ stringLongTestMissing.add(1l);
+ }
+ stringLongTestStart.add(list2);
+ ArrayList<Integer> list3 = new ArrayList<>();
+ if( i != 0 ){
+ list3.add(i);
+ multiLongTestMissing.add(0l);
+ } else {
+ multiLongTestMissing.add(1l);
+ }
+ multiLongTestStart.add(list3);
+ } else {
+ if( dt != 0 ) dateLongTestStart.get((int)l-1).add((1800+dt) + "-12-31T23:59:59Z"); else increment(dateLongTestMissing,(int)l-1);
+ if( s != 0 ) stringLongTestStart.get((int)l-1).add("str"+s); else increment(stringLongTestMissing,(int)l-1);
+ if( i != 0 ) multiLongTestStart.get((int)l-1).add(i); else increment(multiLongTestMissing,(int)l-1);
+ }
+ }
+
+ //Long
+ if( lm != 0 ){
+ if (j-LONGM<0&&lm!=l) {
+ ArrayList<Integer> list1 = new ArrayList<>();
+ if( i != 0 ){
+ list1.add(i);
+ multiLongTestMissing.add(0l);
+ } else {
+ multiLongTestMissing.add(1l);
+ }
+ multiLongTestStart.add(list1);
+ } else if (lm!=l) {
+ if( i != 0 ) multiLongTestStart.get((int)lm-1).add(i); else increment( multiLongTestMissing,(int)lm-1);
+ }
+ }
+
+ }
+
+ req.commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void sumTest() throws Exception {
+ String[] params = new String[] {
+ "o.sum.s.int", "sum(int_id)",
+ "o.sum.s.long", "sum(long_ld)",
+ "o.sum.s.float", "sum(float_fd)",
+ "o.sum.s.double", "sum(double_dd)",
+ "o.sum.ff", "string_sd",
+ "o.sum.ff", "date_dtd"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Double> intDate = getValueList(response, "sum", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Double> intDateTest = calculateNumberStat(intDateTestStart, "sum");
+ assertEquals(responseStr.toString(),intDate,intDateTest);
+ //Int String
+ Collection<Double> intString = getValueList(response, "sum", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "sum");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Double> longDate = getValueList(response, "sum", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Double> longDateTest = calculateNumberStat(longDateTestStart, "sum");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Double> longString = getValueList(response, "sum", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Double> longStringTest = calculateNumberStat(longStringTestStart, "sum");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Double> floatDate = getValueList(response, "sum", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Double> floatDateTest = calculateNumberStat(floatDateTestStart, "sum");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Double> floatString = getValueList(response, "sum", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Double> floatStringTest = calculateNumberStat(floatStringTestStart, "sum");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "sum", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = calculateNumberStat(doubleDateTestStart, "sum");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "sum", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = calculateNumberStat(doubleStringTestStart, "sum");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void meanTest() throws Exception {
+ String[] params = new String[] {
+ "o.mean.s.int", "mean(int_id)",
+ "o.mean.s.long", "mean(long_ld)",
+ "o.mean.s.float", "mean(float_fd)",
+ "o.mean.s.double", "mean(double_dd)",
+ "o.mean.ff", "string_sd",
+ "o.mean.ff", "date_dtd"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Double> intDate = getValueList(response, "mean", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Double> intDateTest = calculateNumberStat(intDateTestStart, "mean");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Double> intString = getValueList(response, "mean", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "mean");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Double> longDate = getValueList(response, "mean", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Double> longDateTest = calculateNumberStat(longDateTestStart, "mean");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Double> longString = getValueList(response, "mean", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Double> longStringTest = calculateNumberStat(longStringTestStart, "mean");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Double> floatDate = getValueList(response, "mean", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Double> floatDateTest = calculateNumberStat(floatDateTestStart, "mean");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Double> floatString = getValueList(response, "mean", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Double> floatStringTest = calculateNumberStat(floatStringTestStart, "mean");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "mean", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = calculateNumberStat(doubleDateTestStart, "mean");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "mean", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = calculateNumberStat(doubleStringTestStart, "mean");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void stddevFacetAscTest() throws Exception {
+ String[] params = new String[] {
+ "o.stddev.s.int", "stddev(int_id)",
+ "o.stddev.s.long", "stddev(long_ld)",
+ "o.stddev.s.float", "stddev(float_fd)",
+ "o.stddev.s.double", "stddev(double_dd)",
+ "o.stddev.ff", "string_sd",
+ "o.stddev.ff", "date_dtd"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+
+ //Int Date
+ ArrayList<Double> intDate = getValueList(response, "stddev", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Double> intDateTest = calculateNumberStat(intDateTestStart, "stddev");
+ checkStddevs(response, intDate, intDateTest);
+ //Int String
+ ArrayList<Double> intString = getValueList(response, "stddev", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "stddev");
+ checkStddevs(response, intString, intStringTest);
+
+ //Long Date
+ ArrayList<Double> longDate = getValueList(response, "stddev", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Double> longDateTest = calculateNumberStat(longDateTestStart, "stddev");
+ checkStddevs(response, longDate, longDateTest);
+ //Long String
+ ArrayList<Double> longString = getValueList(response, "stddev", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Double> longStringTest = calculateNumberStat(longStringTestStart, "stddev");
+ checkStddevs(response, longString, longStringTest);
+
+ //Float Date
+ ArrayList<Double> floatDate = getValueList(response, "stddev", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Double> floatDateTest = calculateNumberStat(floatDateTestStart, "stddev");
+ checkStddevs(response, floatDate, floatDateTest);
+ //Float String
+ ArrayList<Double> floatString = getValueList(response, "stddev", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Double> floatStringTest = calculateNumberStat(floatStringTestStart, "stddev");
+ checkStddevs(response, floatString, floatStringTest);
+
+ //Double Date
+ ArrayList<Double> doubleDate = getValueList(response, "stddev", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = calculateNumberStat(doubleDateTestStart, "stddev");
+ checkStddevs(response, doubleDate, doubleDateTest);
+ //Double String
+ ArrayList<Double> doubleString = getValueList(response, "stddev", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = calculateNumberStat(doubleStringTestStart, "stddev");
+ checkStddevs(response, doubleString, doubleStringTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void medianFacetAscTest() throws Exception {
+ String[] params = new String[] {
+ "o.median.s.int", "median(int_id)",
+ "o.median.s.long", "median(long_ld)",
+ "o.median.s.float", "median(float_fd)",
+ "o.median.s.double", "median(double_dd)",
+ "o.median.ff", "string_sd",
+ "o.median.ff", "date_dtd"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Double> intDate = getValueList(response, "median","fieldFacets", "date_dtd", "int", false);
+ ArrayList<Double> intDateTest = calculateNumberStat(intDateTestStart, "median");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Double> intString = getValueList(response, "median", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "median");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Double> longDate = getValueList(response, "median", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Double> longDateTest = calculateNumberStat(longDateTestStart, "median");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Double> longString = getValueList(response, "median", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Double> longStringTest = calculateNumberStat(longStringTestStart, "median");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Double> floatDate = getValueList(response, "median", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Double> floatDateTest = calculateNumberStat(floatDateTestStart, "median");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Double> floatString = getValueList(response, "median", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Double> floatStringTest = calculateNumberStat(floatStringTestStart, "median");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "median", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = calculateNumberStat(doubleDateTestStart, "median");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "median", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = calculateNumberStat(doubleStringTestStart, "median");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void perc20Test() throws Exception {
+ String[] params = new String[] {
+ "o.percentile_20n.s.int", "percentile(20,int_id)",
+ "o.percentile_20n.s.long", "percentile(20,long_ld)",
+ "o.percentile_20n.s.float", "percentile(20,float_fd)",
+ "o.percentile_20n.s.double", "percentile(20,double_dd)",
+ "o.percentile_20n.ff", "string_sd",
+ "o.percentile_20n.ff", "date_dtd",
+
+ "o.percentile_20.s.str", "percentile(20,string_sd)",
+ "o.percentile_20.s.date", "string(percentile(20,date_dtd))",
+ "o.percentile_20.ff", "int_id",
+ "o.percentile_20.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Integer> intDate = getValueList(response, "percentile_20n", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Integer> intDateTest = (ArrayList<Integer>)calculateStat(intDateTestStart, "perc_20");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Integer> intString = getValueList(response, "percentile_20n", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Integer> intStringTest = (ArrayList<Integer>)calculateStat(intStringTestStart, "perc_20");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "percentile_20n", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "perc_20");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Long> longString = getValueList(response, "percentile_20n", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "perc_20");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Float> floatDate = getValueList(response, "percentile_20n", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Float> floatDateTest = (ArrayList<Float>)calculateStat(floatDateTestStart, "perc_20");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Float> floatString = getValueList(response, "percentile_20n", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Float> floatStringTest = (ArrayList<Float>)calculateStat(floatStringTestStart, "perc_20");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "percentile_20n", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = (ArrayList<Double>)calculateStat(doubleDateTestStart, "perc_20");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "percentile_20n", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = (ArrayList<Double>)calculateStat(doubleStringTestStart, "perc_20");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //Date Int
+ Collection<String> dateInt = getValueList(response, "percentile_20", "fieldFacets", "int_id", "date", false);
+ ArrayList<String> dateIntTest = (ArrayList<String>)calculateStat(dateIntTestStart, "perc_20");
+ assertEquals(responseStr,dateInt,dateIntTest);
+ //Date Long
+ Collection<String> dateString = getValueList(response, "percentile_20", "fieldFacets", "long_ld", "date", false);
+ ArrayList<String> dateLongTest = (ArrayList<String>)calculateStat(dateLongTestStart, "perc_20");
+ assertEquals(responseStr,dateString,dateLongTest);
+
+ //String Int
+ Collection<String> stringInt = getValueList(response, "percentile_20", "fieldFacets", "int_id", "str", false);
+ ArrayList<String> stringIntTest = (ArrayList<String>)calculateStat(stringIntTestStart, "perc_20");
+ assertEquals(responseStr,stringInt,stringIntTest);
+ //String Long
+ Collection<String> stringLong = getValueList(response, "percentile_20", "fieldFacets", "long_ld", "str", false);
+ ArrayList<String> stringLongTest = (ArrayList<String>)calculateStat(stringLongTestStart, "perc_20");
+ assertEquals(responseStr,stringLong,stringLongTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void perc60Test() throws Exception {
+ String[] params = new String[] {
+ "o.percentile_60n.s.int", "percentile(60,int_id)",
+ "o.percentile_60n.s.long", "percentile(60,long_ld)",
+ "o.percentile_60n.s.float", "percentile(60,float_fd)",
+ "o.percentile_60n.s.double", "percentile(60,double_dd)",
+ "o.percentile_60n.ff", "string_sd",
+ "o.percentile_60n.ff", "date_dtd",
+
+ "o.percentile_60.s.str", "percentile(60,string_sd)",
+ "o.percentile_60.s.date", "string(percentile(60,date_dtd))",
+ "o.percentile_60.ff", "int_id",
+ "o.percentile_60.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Integer> intDate = getValueList(response, "percentile_60n", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Integer> intDateTest = (ArrayList<Integer>)calculateStat(intDateTestStart, "perc_60");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Integer> intString = getValueList(response, "percentile_60n", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Integer> intStringTest = (ArrayList<Integer>)calculateStat(intStringTestStart, "perc_60");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "percentile_60n", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "perc_60");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Long> longString = getValueList(response, "percentile_60n", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "perc_60");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Float> floatDate = getValueList(response, "percentile_60n", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Float> floatDateTest = (ArrayList<Float>)calculateStat(floatDateTestStart, "perc_60");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Float> floatString = getValueList(response, "percentile_60n", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Float> floatStringTest = (ArrayList<Float>)calculateStat(floatStringTestStart, "perc_60");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "percentile_60n", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = (ArrayList<Double>)calculateStat(doubleDateTestStart, "perc_60");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "percentile_60n", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = (ArrayList<Double>)calculateStat(doubleStringTestStart, "perc_60");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //Date Int
+ Collection<String> dateInt = getValueList(response, "percentile_60", "fieldFacets", "int_id", "date", false);
+ ArrayList<String> dateIntTest = (ArrayList<String>)calculateStat(dateIntTestStart, "perc_60");
+ assertEquals(responseStr,dateInt,dateIntTest);
+ //Date Long
+ Collection<String> dateString = getValueList(response, "percentile_60", "fieldFacets", "long_ld", "date", false);
+ ArrayList<String> dateLongTest = (ArrayList<String>)calculateStat(dateLongTestStart, "perc_60");
+ assertEquals(responseStr,dateString,dateLongTest);
+
+ //String Int
+ Collection<String> stringInt = getValueList(response, "percentile_60", "fieldFacets", "int_id", "str", false);
+ ArrayList<String> stringIntTest = (ArrayList<String>)calculateStat(stringIntTestStart, "perc_60");
+ assertEquals(responseStr,stringInt,stringIntTest);
+ //String Long
+ Collection<String> stringLong = getValueList(response, "percentile_60", "fieldFacets", "long_ld", "str", false);
+ ArrayList<String> stringLongTest = (ArrayList<String>)calculateStat(stringLongTestStart, "perc_60");
+ assertEquals(responseStr,stringLong,stringLongTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void minTest() throws Exception {
+ String[] params = new String[] {
+ "o.minn.s.int", "min(int_id)",
+ "o.minn.s.long", "min(long_ld)",
+ "o.minn.s.float", "min(float_fd)",
+ "o.minn.s.double", "min(double_dd)",
+ "o.minn.ff", "string_sd",
+ "o.minn.ff", "date_dtd",
+
+ "o.min.s.str", "min(string_sd)",
+ "o.min.s.date", "string(min(date_dtd))",
+ "o.min.ff", "int_id",
+ "o.min.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Integer> intDate = getValueList(response, "minn", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Integer> intDateTest = (ArrayList<Integer>)calculateStat(intDateTestStart, "min");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Integer> intString = getValueList(response, "minn", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Integer> intStringTest = (ArrayList<Integer>)calculateStat(intStringTestStart, "min");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "minn", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "min");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Long> longString = getValueList(response, "minn", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "min");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Float> floatDate = getValueList(response, "minn", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Float> floatDateTest = (ArrayList<Float>)calculateStat(floatDateTestStart, "min");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Float> floatString = getValueList(response, "minn", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Float> floatStringTest = (ArrayList<Float>)calculateStat(floatStringTestStart, "min");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "minn", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = (ArrayList<Double>)calculateStat(doubleDateTestStart, "min");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "minn", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = (ArrayList<Double>)calculateStat(doubleStringTestStart, "min");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //Date Int
+ Collection<String> dateInt = getValueList(response, "min", "fieldFacets", "int_id", "date", false);
+ ArrayList<String> dateIntTest = (ArrayList<String>)calculateStat(dateIntTestStart, "min");
+ assertEquals(responseStr,dateInt,dateIntTest);
+ //Date Long
+ Collection<String> dateString = getValueList(response, "min", "fieldFacets", "long_ld", "date", false);
+ ArrayList<String> dateLongTest = (ArrayList<String>)calculateStat(dateLongTestStart, "min");
+ assertEquals(responseStr,dateString,dateLongTest);
+
+ //String Int
+ Collection<String> stringInt = getValueList(response, "min", "fieldFacets", "int_id", "str", false);
+ ArrayList<String> stringIntTest = (ArrayList<String>)calculateStat(stringIntTestStart, "min");
+ assertEquals(responseStr,stringInt,stringIntTest);
+ //String Long
+ Collection<String> stringLong = getValueList(response, "min", "fieldFacets", "long_ld", "str", false);
+ ArrayList<String> stringLongTest = (ArrayList<String>)calculateStat(stringLongTestStart, "min");
+ assertEquals(responseStr,stringLong,stringLongTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void maxTest() throws Exception {
+ String[] params = new String[] {
+ "o.maxn.s.int", "max(int_id)",
+ "o.maxn.s.long", "max(long_ld)",
+ "o.maxn.s.float", "max(float_fd)",
+ "o.maxn.s.double", "max(double_dd)",
+ "o.maxn.ff", "string_sd",
+ "o.maxn.ff", "date_dtd",
+
+ "o.max.s.str", "max(string_sd)",
+ "o.max.s.date", "string(max(date_dtd))",
+ "o.max.ff", "int_id",
+ "o.max.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Integer> intDate = getValueList(response, "maxn", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Integer> intDateTest = (ArrayList<Integer>)calculateStat(intDateTestStart, "max");
+ //assertEquals(responseStr,intDate,intDateTest);
+
+ //Int String
+ Collection<Integer> intString = getValueList(response, "maxn", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Integer> intStringTest = (ArrayList<Integer>)calculateStat(intStringTestStart, "max");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "maxn", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "max");
+ assertEquals(responseStr,longDate,longDateTest);
+
+ //Long String
+ Collection<Long> longString = getValueList(response, "maxn", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "max");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Float> floatDate = getValueList(response, "maxn", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Float> floatDateTest = (ArrayList<Float>)calculateStat(floatDateTestStart, "max");
+ assertEquals(responseStr,floatDate,floatDateTest);
+
+ //Float String
+ Collection<Float> floatString = getValueList(response, "maxn", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Float> floatStringTest = (ArrayList<Float>)calculateStat(floatStringTestStart, "max");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Double> doubleDate = getValueList(response, "maxn", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Double> doubleDateTest = (ArrayList<Double>)calculateStat(doubleDateTestStart, "max");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+
+ //Double String
+ Collection<Double> doubleString = getValueList(response, "maxn", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Double> doubleStringTest = (ArrayList<Double>)calculateStat(doubleStringTestStart, "max");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //String Int
+ Collection<String> stringInt = getValueList(response, "max", "fieldFacets", "int_id", "str", false);
+ ArrayList<String> stringIntTest = (ArrayList<String>)calculateStat(stringIntTestStart, "max");
+ assertEquals(responseStr,stringInt,stringIntTest);
+
+ //String Long
+ Collection<String> stringLong = getValueList(response, "max", "fieldFacets", "long_ld", "str", false);
+ ArrayList<String> stringLongTest = (ArrayList<String>)calculateStat(stringLongTestStart, "max");
+ assertEquals(responseStr,stringLong,stringLongTest);
+
+ //Date Int
+ Collection<String> dateInt = getValueList(response, "max", "fieldFacets", "int_id", "date", false);
+ ArrayList<String> dateIntTest = (ArrayList<String>)calculateStat(dateIntTestStart, "max");
+ assertEquals(responseStr,dateInt,dateIntTest);
+
+ //Date Long
+ Collection<String> dateString = getValueList(response, "max", "fieldFacets", "long_ld", "date", false);
+ ArrayList<String> dateLongTest = (ArrayList<String>)calculateStat(dateLongTestStart, "max");
+ assertEquals(responseStr,dateString,dateLongTest);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void uniqueTest() throws Exception {
+ String[] params = new String[] {
+ "o.uniquen.s.int", "unique(int_id)",
+ "o.uniquen.s.long", "unique(long_ld)",
+ "o.uniquen.s.float", "unique(float_fd)",
+ "o.uniquen.s.double", "unique(double_dd)",
+ "o.uniquen.ff", "string_sd",
+ "o.uniquen.ff", "date_dtd",
+
+ "o.unique.s.str", "unique(string_sd)",
+ "o.unique.s.date", "unique(date_dtd)",
+ "o.unique.ff", "int_id",
+ "o.unique.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Long> intDate = getValueList(response, "uniquen", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Long> intDateTest = (ArrayList<Long>)calculateStat(intDateTestStart, "unique");
+ assertEquals(responseStr,intDate,intDateTest);
+ //Int String
+ Collection<Long> intString = getValueList(response, "uniquen", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Long> intStringTest = (ArrayList<Long>)calculateStat(intStringTestStart, "unique");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "uniquen", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "unique");
+ assertEquals(responseStr,longDate,longDateTest);
+ //Long String
+ Collection<Long> longString = getValueList(response, "uniquen", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "unique");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Long> floatDate = getValueList(response, "uniquen", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Long> floatDateTest = (ArrayList<Long>)calculateStat(floatDateTestStart, "unique");
+ assertEquals(responseStr,floatDate,floatDateTest);
+ //Float String
+ Collection<Long> floatString = getValueList(response, "uniquen", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Long> floatStringTest = (ArrayList<Long>)calculateStat(floatStringTestStart, "unique");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Long> doubleDate = getValueList(response, "uniquen", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Long> doubleDateTest = (ArrayList<Long>)calculateStat(doubleDateTestStart, "unique");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+ //Double String
+ Collection<Long> doubleString = getValueList(response, "uniquen", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Long> doubleStringTest = (ArrayList<Long>)calculateStat(doubleStringTestStart, "unique");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //Date Int
+ Collection<Long> dateInt = getValueList(response, "unique", "fieldFacets", "int_id", "date", false);
+ ArrayList<Long> dateIntTest = (ArrayList<Long>)calculateStat(dateIntTestStart, "unique");
+ assertEquals(responseStr,dateInt,dateIntTest);
+ //Date Long
+ Collection<Long> dateString = getValueList(response, "unique", "fieldFacets", "long_ld", "date", false);
+ ArrayList<Long> dateLongTest = (ArrayList<Long>)calculateStat(dateLongTestStart, "unique");
+ assertEquals(responseStr,dateString,dateLongTest);
+
+ //String Int
+ Collection<Long> stringInt = getValueList(response, "unique", "fieldFacets", "int_id", "str", false);
+ ArrayList<Long> stringIntTest = (ArrayList<Long>)calculateStat(stringIntTestStart, "unique");
+ assertEquals(responseStr,stringInt,stringIntTest);
+ //String Long
+ Collection<Long> stringLong = getValueList(response, "unique", "fieldFacets", "long_ld", "str", false);
+ ArrayList<Long> stringLongTest = (ArrayList<Long>)calculateStat(stringLongTestStart, "unique");
+ assertEquals(responseStr,stringLong,stringLongTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void countTest() throws Exception {
+ String[] params = new String[] {
+ "o.countn.s.int", "count(int_id)",
+ "o.countn.s.long", "count(long_ld)",
+ "o.countn.s.float", "count(float_fd)",
+ "o.countn.s.double", "count(double_dd)",
+ "o.countn.ff", "string_sd",
+ "o.countn.ff", "date_dtd",
+
+ "o.count.s.str", "count(string_sd)",
+ "o.count.s.date", "count(date_dtd)",
+ "o.count.ff", "int_id",
+ "o.count.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Long> intDate = getValueList(response, "countn", "fieldFacets", "date_dtd", "int", false);
+ ArrayList<Long> intDateTest = (ArrayList<Long>)calculateStat(intDateTestStart, "count");
+ assertEquals(responseStr,intDate,intDateTest);
+
+ //Int String
+ Collection<Long> intString = getValueList(response, "countn", "fieldFacets", "string_sd", "int", false);
+ ArrayList<Long> intStringTest = (ArrayList<Long>)calculateStat(intStringTestStart, "count");
+ assertEquals(responseStr,intString,intStringTest);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "countn", "fieldFacets", "date_dtd", "long", false);
+ ArrayList<Long> longDateTest = (ArrayList<Long>)calculateStat(longDateTestStart, "count");
+ assertEquals(responseStr,longDate,longDateTest);
+
+ //Long String
+ Collection<Long> longString = getValueList(response, "countn", "fieldFacets", "string_sd", "long", false);
+ ArrayList<Long> longStringTest = (ArrayList<Long>)calculateStat(longStringTestStart, "count");
+ assertEquals(responseStr,longString,longStringTest);
+
+ //Float Date
+ Collection<Long> floatDate = getValueList(response, "countn", "fieldFacets", "date_dtd", "float", false);
+ ArrayList<Long> floatDateTest = (ArrayList<Long>)calculateStat(floatDateTestStart, "count");
+ assertEquals(responseStr,floatDate,floatDateTest);
+
+ //Float String
+ Collection<Long> floatString = getValueList(response, "countn", "fieldFacets", "string_sd", "float", false);
+ ArrayList<Long> floatStringTest = (ArrayList<Long>)calculateStat(floatStringTestStart, "count");
+ assertEquals(responseStr,floatString,floatStringTest);
+
+ //Double Date
+ Collection<Long> doubleDate = getValueList(response, "countn", "fieldFacets", "date_dtd", "double", false);
+ ArrayList<Long> doubleDateTest = (ArrayList<Long>)calculateStat(doubleDateTestStart, "count");
+ assertEquals(responseStr,doubleDate,doubleDateTest);
+
+ //Double String
+ Collection<Long> doubleString = getValueList(response, "countn", "fieldFacets", "string_sd", "double", false);
+ ArrayList<Long> doubleStringTest = (ArrayList<Long>)calculateStat(doubleStringTestStart, "count");
+ assertEquals(responseStr,doubleString,doubleStringTest);
+
+ //Date Int
+ Collection<Long> dateInt = getValueList(response, "count", "fieldFacets", "int_id", "date", false);
+ ArrayList<Long> dateIntTest = (ArrayList<Long>)calculateStat(dateIntTestStart, "count");
+ assertEquals(responseStr,dateIntTest,dateInt);
+
+ //Date Long
+ Collection<Long> dateLong = getValueList(response, "count", "fieldFacets", "long_ld", "date", false);
+ ArrayList<Long> dateLongTest = (ArrayList<Long>)calculateStat(dateLongTestStart, "count");
+ assertEquals(responseStr,dateLong,dateLongTest);
+
+ //String Int
+ Collection<Long> stringInt = getValueList(response, "count", "fieldFacets", "int_id", "str", false);
+ ArrayList<Long> stringIntTest = (ArrayList<Long>)calculateStat(stringIntTestStart, "count");
+ assertEquals(responseStr,stringInt,stringIntTest);
+
+ //String Long
+ Collection<Long> stringLong = getValueList(response, "count", "fieldFacets", "long_ld", "str", false);
+ ArrayList<Long> stringLongTest = (ArrayList<Long>)calculateStat(stringLongTestStart, "count");
+ assertEquals(responseStr,stringLong,stringLongTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void missingTest() throws Exception {
+ String[] params = new String[] {
+ "o.missingn.s.int", "missing(int_id)",
+ "o.missingn.s.long", "missing(long_ld)",
+ "o.missingn.s.float", "missing(float_fd)",
+ "o.missingn.s.double", "missing(double_dd)",
+ "o.missingn.ff", "string_sd",
+ "o.missingn.ff", "date_dtd",
+
+ "o.missing.s.str", "missing(string_sd)",
+ "o.missing.s.date", "missing(date_dtd)",
+ "o.missing.ff", "int_id",
+ "o.missing.ff", "long_ld"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int Date
+ Collection<Long> intDate = getValueList(response, "missingn", "fieldFacets", "date_dtd", "int", false);
+ setLatestType("int");
+ assertEquals(responseStr,intDateTestMissing,intDate);
+
+ //Int String
+ Collection<Long> intString = getValueList(response, "missingn", "fieldFacets", "string_sd", "int", false);
+ assertEquals(responseStr,intStringTestMissing,intString);
+
+ //Long Date
+ Collection<Long> longDate = getValueList(response, "missingn", "fieldFacets", "date_dtd", "long", false);
+ setLatestType("long");
+ assertEquals(responseStr,longDateTestMissing,longDate);
+
+ //Long String
+ Collection<Long> longString = getValueList(response, "missingn", "fieldFacets", "string_sd", "long", false);
+ assertEquals(responseStr,longStringTestMissing,longString);
+
+ //Float Date
+ Collection<Long> floatDate = getValueList(response, "missingn", "fieldFacets", "date_dtd", "float", false);
+ setLatestType("float");
+ assertEquals(responseStr,floatDateTestMissing,floatDate);
+
+ //Float String
+ Collection<Long> floatString = getValueList(response, "missingn", "fieldFacets", "string_sd", "float", false);
+ assertEquals(responseStr,floatStringTestMissing,floatString);
+
+ //Double Date
+ Collection<Long> doubleDate = getValueList(response, "missingn", "fieldFacets", "date_dtd", "double", false);
+ setLatestType("double");
+ assertEquals(responseStr,doubleDateTestMissing,doubleDate);
+
+ //Double String
+ Collection<Long> doubleString = getValueList(response, "missingn", "fieldFacets", "string_sd", "double", false);
+ assertEquals(responseStr,doubleStringTestMissing,doubleString);
+
+ //Date Int
+ Collection<Long> dateInt = getValueList(response, "missing", "fieldFacets", "int_id", "date", false);
+ setLatestType("date");
+ assertEquals(responseStr,dateIntTestMissing,dateInt);
+
+ //Date Long
+ Collection<Long> dateLong = getValueList(response, "missing", "fieldFacets", "long_ld", "date", false);
+ assertEquals(responseStr,dateLongTestMissing,dateLong);
+
+ //String Int
+ Collection<Long> stringInt = getValueList(response, "missing", "fieldFacets", "int_id", "str", false);
+ setLatestType("string");
+ assertEquals(responseStr,stringIntTestMissing,stringInt);
+
+ //String Long
+ Collection<Long> stringLong = getValueList(response, "missing", "fieldFacets", "long_ld", "str", false);
+ assertEquals(responseStr,stringLongTestMissing,stringLong);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void multiValueTest() throws Exception {
+ String[] params = new String[] {
+ "o.multivalued.s.mean", "mean(int_id)",
+ "o.multivalued.ff", "long_ldm",
+ "o.multivalued.ff", "string_sdm",
+ "o.multivalued.ff", "date_dtdm"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Long
+ Collection<Double> lon = getValueList(response, "multivalued", "fieldFacets", "long_ldm", "mean", false);
+ ArrayList<Double> longTest = calculateNumberStat(multiLongTestStart, "mean");
+ assertEquals(responseStr,lon,longTest);
+ //Date
+ Collection<Double> date = getValueList(response, "multivalued", "fieldFacets", "date_dtdm", "mean", false);
+ ArrayList<Double> dateTest = calculateNumberStat(multiDateTestStart, "mean");
+ assertEquals(responseStr,date,dateTest);
+ //String
+ Collection<Double> string = getValueList(response, "multivalued", "fieldFacets", "string_sdm", "mean", false);
+ ArrayList<Double> stringTest = calculateNumberStat(multiStringTestStart, "mean");
+ assertEquals(responseStr,string,stringTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void missingFacetTest() throws Exception {
+ String[] params = new String[] {
+ "o.func.facet_show_missing(a)", "fillmissing(a,\"(MISSING)\")",
+ "o.missingf.s.mean", "mean(int_id)",
+ "o.missingf.ff", "date_dtd",
+ "o.missingf.ff", "string_sd",
+ "o.missingf.ff.string_sd.sm", "true",
+ "o.missingf.ff", "date_dtdm",
+ "o.missingf.ff.date_dtdm.sm", "true"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //int MultiDate
+ assertTrue(responseStr, responseContainsFacetValue(response, "missingf", "fieldFacets", "date_dtdm", "(MISSING)"));
+ ArrayList<Double> string = getValueList(response, "missingf", "fieldFacets", "date_dtdm", "mean", false);
+ ArrayList<Double> stringTest = calculateNumberStat(multiDateTestStart, "mean");
+ assertEquals(responseStr, string,stringTest);
+
+ //Int String
+ assertTrue(responseStr, responseContainsFacetValue(response, "missingf", "fieldFacets", "string_sd", "(MISSING)"));
+ assertTrue(responseStr, !responseContainsFacetValue(response, "missingf", "fieldFacets", "string_sd", "str0"));
+ List<Double> intString = getValueList(response, "missingf", "fieldFacets", "string_sd", "mean", false);
+ ArrayList<Double> intStringTest = calculateNumberStat(intStringTestStart, "mean");
+ assertEquals(responseStr, intString,intStringTest);
+
+ //Int Date
+ Collection<Double> intDate = getValueList(response, "missingf", "fieldFacets", "date_dtd", "mean", false);
+ ArrayList<ArrayList<Double>> intDateMissingTestStart = (ArrayList<ArrayList<Double>>) intDateTestStart.clone();
+ ArrayList<Double> intDateTest = calculateNumberStat(intDateMissingTestStart, "mean");
+ assertEquals(responseStr,intDate,intDateTest);
+ }
+
+ private void checkStddevs(NamedList<Object> response, ArrayList<Double> list1, ArrayList<Double> list2) {
+ Collections.sort(list1);
+ Collections.sort(list2);
+ for (int i = 0; i<list2.size(); i++) {
+ if ((Math.abs(list1.get(i)-list2.get(i))<.00000000001) == false) {
+ Assert.assertEquals(response.toString(), list1.get(i), list2.get(i), 0.00000000001);
+ }
+ }
+ }
+
+ public static void assertEquals(String mes, Object actual, Object expected) {
+ Collections.sort((List<Comparable>) actual);
+ Collections.sort((List<Comparable>) expected);
+ Assert.assertEquals(mes, actual, expected);
+ }
+}
[18/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java
deleted file mode 100644
index fb0884b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.lucene.index.SortedSetDocValues;
-import org.apache.lucene.util.BytesRef;
-import org.apache.solr.analytics.accumulator.FacetingAccumulator;
-import org.apache.solr.analytics.accumulator.ValueAccumulator;
-import org.apache.solr.analytics.util.AnalyticsParsers.NumericParser;
-import org.apache.solr.analytics.util.AnalyticsParsers.Parser;
-import org.apache.solr.analytics.util.AnalyticsParsers;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.schema.DateValueFieldType;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.search.SolrIndexSearcher;
-
-/**
- * An Accumulator that manages the faceting for fieldFacets.
- * Collects the field facet values.
- */
-public class FieldFacetAccumulator extends ValueAccumulator {
- protected final Parser parser;
- protected final FacetValueAccumulator parent;
- protected final String name;
- protected final SolrIndexSearcher searcher;
- protected final SchemaField schemaField;
- protected final boolean multiValued;
- protected final boolean numField;
- protected final boolean dateField;
- protected SortedSetDocValues setValues;
- protected SortedDocValues sortValues;
- protected NumericDocValues numValues;
-
- public FieldFacetAccumulator(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField schemaField) throws IOException {
- if( !schemaField.hasDocValues() ){
- throw new IOException("Field '"+schemaField.getName()+"' does not have docValues and therefore cannot be faceted over.");
- }
- this.searcher = searcher;
- this.schemaField = schemaField;
- this.name = schemaField.getName();
- this.multiValued = schemaField.multiValued();
- this.numField = schemaField.getType().getNumberType()!=null;
- this.dateField = schemaField.getType() instanceof DateValueFieldType;
- this.parent = parent;
- this.parser = AnalyticsParsers.getParser(schemaField.getType().getClass());
- }
-
- public static FieldFacetAccumulator create(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField facetField) throws IOException{
- return new FieldFacetAccumulator(searcher,parent,facetField);
- }
-
- /**
- * Move to the next set of documents to add to the field facet.
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- if (multiValued) {
- setValues = context.reader().getSortedSetDocValues(name);
- } else {
- if (numField) {
- numValues = context.reader().getNumericDocValues(name);
- } else {
- sortValues = context.reader().getSortedDocValues(name);
- }
- }
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given fieldFacet and value(s).
- */
- @Override
- public void collect(int doc) throws IOException {
- if (multiValued) {
- boolean exists = false;
- if (setValues!=null) {
- if (doc > setValues.docID()) {
- setValues.advance(doc);
- }
- if (doc == setValues.docID()) {
- int term;
- while ((term = (int)setValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
- exists = true;
- final BytesRef value = setValues.lookupOrd(term);
- parent.collectField(doc, name, parser.parse(value) );
- }
- }
- }
- if (!exists) {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- if(numField){
- if(numValues != null) {
- int valuesDocID = numValues.docID();
- if (valuesDocID < doc) {
- valuesDocID = numValues.advance(doc);
- }
- if (valuesDocID == doc) {
- parent.collectField(doc, name, ((NumericParser)parser).parseNum(numValues.longValue()));
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- if(sortValues != null) {
- if (doc > sortValues.docID()) {
- sortValues.advance(doc);
- }
- if (doc == sortValues.docID()) {
- parent.collectField(doc, name, parser.parse(sortValues.lookupOrd(sortValues.ordValue())) );
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- }
- }
- }
-
- @Override
- public void compute() {}
-
- @Override
- public NamedList<?> export() { return null; }
-
- @Override
- public boolean needsScores() {
- return true; // TODO: is this true?
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
deleted file mode 100644
index 8b92ba0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.analytics.accumulator.ValueAccumulator;
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.common.util.NamedList;
-
-/**
- * An Accumulator that manages a certain query of a given query facet.
- */
-public class QueryFacetAccumulator extends ValueAccumulator {
- protected final FacetValueAccumulator parent;
- protected final String facetName;
- protected final String facetValue;
-
- public QueryFacetAccumulator(FacetValueAccumulator parent, String facetName, String facetValue) {
- this.parent = parent;
- this.facetName = facetName;
- this.facetValue = facetValue;
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given queryFacet and query.
- */
- @Override
- public void collect(int doc) throws IOException {
- parent.collectQuery(doc, facetName, facetValue);
- }
-
- /**
- * Update the readers of the queryFacet {@link StatsCollector}s in FacetingAccumulator
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- parent.setQueryStatsCollectorReaders(context);
- }
-
- @Override
- public void compute() {
- // NOP
- }
-
- @Override
- public NamedList<?> export() {
- // NOP
- return null;
- }
-
- @Override
- public boolean needsScores() {
- return true; // TODO: is this true?
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
deleted file mode 100644
index 59cf428..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.analytics.statistics.StatsCollector;
-
-/**
- * An Accumulator that manages a certain range of a given range facet.
- */
-public class RangeFacetAccumulator extends QueryFacetAccumulator {
- public RangeFacetAccumulator(FacetValueAccumulator parent, String facetName, String facetValue) {
- super(parent, facetName, facetValue);
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given rangeFacet and range.
- */
- @Override
- public void collect(int doc) throws IOException {
- parent.collectRange(doc, facetName, facetValue);
- }
-
- /**
- * Update the readers of the rangeFacet {@link StatsCollector}s in FacetingAccumulator
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- parent.setRangeStatsCollectorReaders(context);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
deleted file mode 100644
index 3daf103..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Accumulators for accumulating over differnt types of facets
-
- */
-package org.apache.solr.analytics.accumulator.facet;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
deleted file mode 100644
index 0abe00a..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Accumulators accumulate values over different types of strucuture (eg result, facet, etc..)
- */
-package org.apache.solr.analytics.accumulator;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
deleted file mode 100644
index 2f0326b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.analytics.expression;
-
-import java.util.Date;
-
-import org.apache.solr.analytics.statistics.StatsCollector;
-
-
-/**
- * <code>BaseExpression</code> returns the value returned by the {@link StatsCollector} for the specified stat.
- */
-public class BaseExpression extends Expression {
- protected final StatsCollector statsCollector;
- protected final String stat;
-
- public BaseExpression(StatsCollector statsCollector, String stat) {
- this.statsCollector = statsCollector;
- this.stat = stat;
- }
-
- public Comparable getValue() {
- if(statsCollector.getStatsList().contains(stat)) {
- return statsCollector.getStat(stat);
- }
- return null;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant double.
- */
-class ConstantNumberExpression extends Expression {
- protected final Double constant;
-
- public ConstantNumberExpression(double d) {
- constant = new Double(d);
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant date.
- */
-class ConstantDateExpression extends Expression {
- protected final Date constant;
-
- public ConstantDateExpression(Date date) {
- constant = date;
- }
-
- public ConstantDateExpression(Long date) {
- constant = new Date(date);
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant string.
- */
-class ConstantStringExpression extends Expression {
- protected final String constant;
-
- public ConstantStringExpression(String str) {
- constant = str;
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
deleted file mode 100644
index f906b47..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.analytics.expression;
-
-/**
- * Abstraction of an expression that applies a function to two delegate expressions.
- */
-public abstract class DualDelegateExpression extends Expression {
- protected Expression a;
- protected Expression b;
- public DualDelegateExpression(Expression a, Expression b) {
- this.a = a;
- this.b = b;
- }
-}
-/**
- * <code>DivideExpression</code> returns the quotient of 'a' and 'b'.
- */
-class DivideExpression extends DualDelegateExpression {
-
- /**
- * @param a numerator
- * @param b divisor
- */
- public DivideExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- double div = ((Number)aComp).doubleValue();
- div = div / ((Number)bComp).doubleValue();
- return new Double(div);
- }
-}
-/**
- * <code>PowerExpression</code> returns 'a' to the power of 'b'.
- */
-class PowerExpression extends DualDelegateExpression {
-
- /**
- * @param a base
- * @param b exponent
- */
- public PowerExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- return new Double(Math.pow(((Number)aComp).doubleValue(),((Number)bComp).doubleValue()));
- }
-}
-/**
- * <code>LogExpression</code> returns the log of the delegate's value given a base number.
- */
-class LogExpression extends DualDelegateExpression {
- /**
- * @param a number
- * @param b base
- */
- public LogExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- return Math.log(((Number)aComp).doubleValue())/Math.log(((Number)bComp).doubleValue());
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
deleted file mode 100644
index ba26d9a..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.analytics.expression;
-
-import java.util.Comparator;
-
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortDirection;
-
-/**
- * Expressions map either zero, one, two or many inputs to a single value.
- * They can be defined recursively to compute complex math.
- */
-public abstract class Expression {
- public abstract Comparable getValue();
-
- public Comparator<Expression> comparator(final FacetSortDirection direction) {
- return (a, b) -> {
- if( direction == FacetSortDirection.ASCENDING ){
- return a.getValue().compareTo(b.getValue());
- } else {
- return b.getValue().compareTo(a.getValue());
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
deleted file mode 100644
index 1f2d0e0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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.analytics.expression;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.util.DateMathParser;
-
-public class ExpressionFactory {
-
- /**
- * Creates a single expression that contains delegate expressions and/or
- * a StatsCollector.
- * StatsCollectors are given as input and not created within the method so that
- * expressions can share the same StatsCollectors, minimizing computation.
- *
- * @param expression String representation of the desired expression
- * @param statsCollectors List of StatsCollectors to build the expression with.
- * @return the expression
- */
- @SuppressWarnings("deprecation")
- public static Expression create(String expression, StatsCollector[] statsCollectors) {
- int paren = expression.indexOf('(');
- if (paren<=0) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "The expression ["+expression+"] has no arguments and is not supported.");
- }
- String topOperation = expression.substring(0,paren).trim();
- String operands;
- try {
- operands = expression.substring(paren+1, expression.lastIndexOf(')')).trim();
- } catch (Exception e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Missing closing parenthesis in ["+expression+"]",e);
- }
-
- // Builds a statistic, constant or recursively builds an expression tree
-
- // Statistic
- if (AnalyticsParams.ALL_STAT_SET.contains(topOperation)) {
- if (topOperation.equals(AnalyticsParams.STAT_PERCENTILE)) {
- operands = expression.substring(expression.indexOf(',')+1, expression.lastIndexOf(')')).trim();
- topOperation = topOperation+"_"+expression.substring(expression.indexOf('(')+1, expression.indexOf(',')).trim();
- }
- StatsCollector collector = null;
- // Finds the desired counter and builds an expression around it and the desired statistic.
- for (StatsCollector c : statsCollectors) {
- if (c.valueSourceString().equals(operands)) {
- collector = c;
- break;
- }
- }
- if (collector == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "ValueSource ["+operands+"] in Expression ["+expression+"] not found.");
- }
- return new BaseExpression(collector, topOperation);
- }
- // Constant
- if (topOperation.equals(AnalyticsParams.CONSTANT_NUMBER)) {
- try {
- return new ConstantNumberExpression(Double.parseDouble(operands));
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "The constant "+operands+" cannot be converted into a number.",e);
- }
- } else if (topOperation.equals(AnalyticsParams.CONSTANT_DATE)) {
- return new ConstantDateExpression(DateMathParser.parseMath(null, operands));
- } else if (topOperation.equals(AnalyticsParams.CONSTANT_STRING)) {
- operands = expression.substring(paren+1, expression.lastIndexOf(')'));
- return new ConstantStringExpression(operands);
- }
-
- // Complex Delegating Expressions
- String[] arguments = getArguments(operands);
- Expression[] expArgs = new Expression[arguments.length];
- for (int count = 0; count < arguments.length; count++) {
- // Recursively builds delegate expressions
- expArgs[count] = create(arguments[count], statsCollectors);
- }
-
- // Single Delegate Expressions
- if (expArgs.length==1) {
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.NEGATE)) {
- return new NegateExpression(expArgs[0]);
- }
- if (topOperation.equals(AnalyticsParams.ABSOLUTE_VALUE)) {
- return new AbsoluteValueExpression(expArgs[0]);
- }
- // String Expression
- else if (topOperation.equals(AnalyticsParams.REVERSE)) {
- return new ReverseExpression(expArgs[0]);
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments.");
- } else {
- // Multi Delegate Expressions
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.ADD)) {
- return new AddExpression(expArgs);
- } else if (topOperation.equals(AnalyticsParams.MULTIPLY)) {
- return new MultiplyExpression(expArgs);
- }
- // Date Expression
- else if (topOperation.equals(AnalyticsParams.DATE_MATH)) {
- return new DateMathExpression(expArgs);
- }
- // String Expression
- else if (topOperation.equals(AnalyticsParams.CONCATENATE)) {
- return new ConcatenateExpression(expArgs);
- }
- // Dual Delegate Expressions
- else if (expArgs.length==2 && (topOperation.equals(AnalyticsParams.DIVIDE) || topOperation.equals(AnalyticsParams.POWER)
- || topOperation.equals(AnalyticsParams.LOG))) {
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.DIVIDE)) {
- return new DivideExpression(expArgs[0], expArgs[1]);
- } else if (topOperation.equals(AnalyticsParams.POWER)) {
- return new PowerExpression(expArgs[0], expArgs[1]);
- } else if (topOperation.equals(AnalyticsParams.LOG)) {
- return new LogExpression(expArgs[0], expArgs[1]);
- }
- return null;
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments or is unsupported.");
- }
-
- }
-
- /**
- * Splits up an Expression's arguments.
- *
- * @param expression Current expression string
- * @return List The list of arguments
- */
- public static String[] getArguments(String expression) {
- String[] strings = new String[1];
- int stack = 0;
- int start = 0;
- List<String> arguments = new ArrayList<>();
- char[] chars = expression.toCharArray();
- for (int count = 0; count < expression.length(); count++) {
- char c = chars[count];
- if (c==',' && stack == 0) {
- arguments.add(expression.substring(start, count).replace("\\(","(").replace("\\)",")").replace("\\,",",").trim());
- start = count+1;
- } else if (c == '(') {
- stack ++;
- } else if (c == ')') {
- stack --;
- } else if (c == '\\') {
- ; // Do nothing.
- }
- }
- if (stack==0) {
- arguments.add(expression.substring(start).trim());
- }
- return arguments.toArray(strings);
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
deleted file mode 100644
index 4ea66fa..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.analytics.expression;
-
-import java.text.ParseException;
-import java.util.Date;
-
-import org.apache.solr.util.DateMathParser;
-
-/**
- * Abstraction of an expression that applies a function to an array of delegate expressions.
- */
-public abstract class MultiDelegateExpression extends Expression {
- protected final Expression[] delegates;
-
- public MultiDelegateExpression(Expression[] delegates) {
- this.delegates = delegates;
- }
-}
-/**
- * <code>AddExpression</code> returns the sum of its components' values.
- */
-class AddExpression extends MultiDelegateExpression {
- public AddExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- double sum = 0;
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- } else if (dComp.getClass().equals(Date.class)) {
- dComp = new Long(((Date)dComp).getTime());
- }
- sum += ((Number)dComp).doubleValue();
- }
- return new Double(sum);
- }
-}
-/**
- * <code>MultiplyExpression</code> returns the product of its delegates' values.
- */
-class MultiplyExpression extends MultiDelegateExpression {
- public MultiplyExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- double prod = 1;
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- }
- prod *= ((Number)dComp).doubleValue();
- }
- return new Double(prod);
- }
-}
-/**
- * <code>DateMathExpression</code> returns the start date modified by the DateMath operations
- */
-class DateMathExpression extends MultiDelegateExpression {
- /**
- * @param delegates A list of Expressions. The first element in the list
- * should be a numeric Expression which represents the starting date.
- * The rest of the field should be string Expression objects which contain
- * the DateMath operations to perform on the start date.
- */
- public DateMathExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- DateMathParser parser = new DateMathParser();
- parser.setNow((Date)delegates[0].getValue());
- try {
- for (int count = 1; count<delegates.length; count++) {
- Comparable dComp = delegates[count].getValue();
- if (dComp==null) {
- return null;
- }
- parser.setNow(parser.parseMath((String)dComp));
- }
- return parser.getNow();
- } catch (ParseException e) {
- e.printStackTrace();
- return parser.getNow();
- }
- }
-}
-/**
- * <code>ConcatenateExpression</code> returns the concatenation of its delegates' values in the order given.
- */
-class ConcatenateExpression extends MultiDelegateExpression {
- public ConcatenateExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- StringBuilder builder = new StringBuilder();
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- }
- builder.append(dComp.toString());
- }
- return builder.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
deleted file mode 100644
index 8d94ece..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.analytics.expression;
-
-import java.util.Date;
-
-/**
- * Abstraction of an expression that applies a function to one delegate expression.
- */
-public abstract class SingleDelegateExpression extends Expression {
- protected Expression delegate;
-
- public SingleDelegateExpression(Expression delegate) {
- this.delegate = delegate;
- }
-}
-/**
- * <code>NegateExpression</code> returns the negation of the delegate's value.
- */
-class NegateExpression extends SingleDelegateExpression {
- public NegateExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable nComp = delegate.getValue();
- if (nComp==null) {
- return null;
- } else if (nComp.getClass().equals(Date.class)) {
- nComp = new Long(((Date)nComp).getTime());
- }
- return new Double(((Number)nComp).doubleValue()*-1);
- }
-}
-/**
- * <code>AbsoluteValueExpression</code> returns the negation of the delegate's value.
- */
-class AbsoluteValueExpression extends SingleDelegateExpression {
- public AbsoluteValueExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable nComp = delegate.getValue();
- if (nComp==null) {
- return null;
- }
- double d = ((Number)nComp).doubleValue();
- if (d<0) {
- return new Double(d*-1);
- } else {
- return new Double(d);
- }
- }
-}
-/**
- * <code>StringExpression</code> returns the reverse of the delegate's string value.
- */
-class ReverseExpression extends SingleDelegateExpression {
- public ReverseExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable rComp = delegate.getValue();
- if (rComp==null) {
- return null;
- }
- return new StringBuilder(rComp.toString()).reverse().toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
deleted file mode 100644
index 8c6f70e..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Expressions map either zero, one, two or many inputs to a single value. They can be defined recursively to compute complex math.
- */
-package org.apache.solr.analytics.expression;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
new file mode 100644
index 0000000..d06cfa3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
@@ -0,0 +1,104 @@
+/*
+ * 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.analytics.facet;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SimpleCollector;
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.SolrIndexSearcher;
+
+/**
+ * Solr Query Facets are AnalyticsFacets that are calculated after the document streaming phase has occurred in the {@link AnalyticsDriver}
+ * (during which StreamingFacets and overall expressions are calculated). {@link AbstractSolrQueryFacet}s should not be confused with {@link QueryFacet}s,
+ * which are a specific sub-type.
+ *
+ * <p>
+ * The filtering for these facets is done through issuing additional Solr queries, and collecting on the resulting documents.
+ * Unlike streaming facets, which have an unspecified amount of facet values (facet buckets), the amount of facet values is determined by the user and
+ * a Solr query is issued for each requested facet value.
+ */
+public abstract class AbstractSolrQueryFacet extends AnalyticsFacet {
+
+ protected AbstractSolrQueryFacet(String name) {
+ super(name);
+ }
+
+ /**
+ * Returns the set of {@link FacetValueQueryExecuter}s, one for each facet value, through the given consumer.
+ *
+ * Each of these executors will be executed after the streaming phase in the {@link AnalyticsDriver}.
+ *
+ * @param filter the overall filter representing the documents being used for the analytics request
+ * @param queryRequest the queryRequest
+ * @param consumer the consumer of each facet value's executer
+ */
+ public abstract void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer);
+
+ /**
+ * This executer is in charge of issuing the Solr query for a facet value and collecting results as the query is processed.
+ */
+ public class FacetValueQueryExecuter extends SimpleCollector {
+ private final ReductionDataCollection collection;
+ private final Query query;
+
+ /**
+ * Create an executer to collect the given reduction data from the given Solr query.
+ *
+ * @param collection The reduction data to collect while querying
+ * @param query The query used to filter for the facet value
+ */
+ public FacetValueQueryExecuter(ReductionDataCollection collection, Query query) {
+ this.collection = collection;
+ this.query = query;
+ }
+
+ @Override
+ public boolean needsScores() {
+ return false;
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ collectionManager.doSetNextReader(context);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ collectionManager.collect(doc);
+ collectionManager.apply();
+ }
+
+ /**
+ * Start the collection for this facet value.
+ *
+ * @param searcher the solr searcher
+ * @throws IOException if an exception occurs during the querying
+ */
+ public void execute(SolrIndexSearcher searcher) throws IOException {
+ collectionManager.clearLastingCollectTargets();
+ collectionManager.addLastingCollectTarget(collection);
+ searcher.search(query, this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
new file mode 100644
index 0000000..d9c0f8c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
@@ -0,0 +1,166 @@
+/*
+ * 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.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * An abstract Facet to break up Analytics data over.
+ */
+public abstract class AnalyticsFacet {
+ protected final Map<String,ReductionDataCollection> reductionData;
+ protected ReductionCollectionManager collectionManager;
+ protected ExpressionCalculator expressionCalculator;
+
+ protected final String name;
+
+ public AnalyticsFacet(String name) {
+ this.reductionData = new LinkedHashMap<>();
+ this.name = name;
+ }
+
+ /**
+ * Set the {@link ReductionCollectionManager} that manages the collection of the expressions
+ * calculated with this facet.
+ *
+ * @param collectionManager The manager for relevant expressions
+ */
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ this.collectionManager = collectionManager;
+ }
+
+ /**
+ * Set the {@link ExpressionCalculator} that calculates the collection of the expressions
+ * requested for this facet.
+ *
+ * @param expressionCalculator The calculator for relevant expressions
+ */
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ this.expressionCalculator = expressionCalculator;
+ }
+
+ /**
+ * Import the shard data from a bit-stream, exported by the {@link #exportShardData} method
+ * in the each of the collection's shards.
+ *
+ * @param input The bit-stream to import the data from
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public void importShardData(DataInput input) throws IOException {
+ int size = input.readInt();
+ for (int i = 0; i < size; ++i) {
+ importFacetValue(input, input.readUTF());
+ }
+ }
+ /**
+ * Import the next facet value's set of {@link ReductionData}.
+ *
+ * @param input the bit-stream to import the reduction data from
+ * @param facetValue the next facet value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected void importFacetValue(DataInput input, String facetValue) throws IOException {
+ ReductionDataCollection dataCollection = reductionData.get(facetValue);
+ if (dataCollection == null) {
+ reductionData.put(facetValue, collectionManager.newDataCollectionIO());
+ } else {
+ collectionManager.prepareReductionDataIO(dataCollection);
+ }
+
+ collectionManager.mergeData();
+ }
+
+ /**
+ * Export the shard data through a bit-stream, to be imported by the {@link #importShardData} method
+ * in the originating shard.
+ *
+ * @param output The bit-stream to output the data through
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportShardData(DataOutput output) throws IOException {
+ output.writeInt(reductionData.size());
+ for (String facetValue : reductionData.keySet()) {
+ exportFacetValue(output, facetValue);
+ }
+ }
+ /**
+ * Export the next facet value's set of {@link ReductionData}.
+ *
+ * @param output the bit-stream to output the reduction data to
+ * @param facetValue the next facet value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected void exportFacetValue(DataOutput output, String facetValue) throws IOException {
+ output.writeUTF(facetValue);
+
+ collectionManager.prepareReductionDataIO(reductionData.get(facetValue));
+ collectionManager.exportData();
+ }
+
+ /**
+ * Create the old olap-style response of the facet to be returned in the overall analytics response.
+ *
+ * @return the response of the facet
+ */
+ public NamedList<Object> createOldResponse() {
+ NamedList<Object> nl = new NamedList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ nl.add(facetVal, new NamedList<>(expressionCalculator.getResults()));
+ });
+ return nl;
+ }
+
+ /**
+ * Create the response of the facet to be returned in the overall analytics response.
+ *
+ * @return the response of the facet
+ */
+ public Iterable<Map<String,Object>> createResponse() {
+ LinkedList<Map<String,Object>> list = new LinkedList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ Map<String, Object> bucket = new HashMap<>();
+ bucket.put(AnalyticsResponseHeadings.FACET_VALUE, facetVal);
+ collectionManager.setData(dataCol);
+ expressionCalculator.addResults(bucket);
+ list.add(bucket);
+ });
+ return list;
+ }
+
+ /**
+ * Get the name of the Facet. This is unique for the grouping.
+ *
+ * @return The name of the Facet
+ */
+ public String getName() {
+ return name;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
new file mode 100644
index 0000000..f9e35f7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
@@ -0,0 +1,114 @@
+/*
+ * 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.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * A facet that takes in multiple ValueFacet expressions and does analytics calculations over each dimension given.
+ */
+public class PivotFacet extends AnalyticsFacet implements StreamingFacet {
+ private final PivotHead<?> pivotHead;
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public PivotFacet(String name, PivotNode<?> topPivot) {
+ super(name);
+ this.pivotHead = new PivotHead(topPivot);
+ }
+
+ @Override
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ pivotHead.setReductionCollectionManager(collectionManager);
+ }
+
+ @Override
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ pivotHead.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ pivotHead.addFacetValueCollectionTargets();
+ }
+
+ @Override
+ public void importShardData(DataInput input) throws IOException {
+ pivotHead.importShardData(input);
+ }
+
+ @Override
+ public void exportShardData(DataOutput output) throws IOException {
+ pivotHead.exportShardData(output);
+ }
+
+ @Override
+ public NamedList<Object> createOldResponse() {
+ return new NamedList<>();
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> createResponse() {
+ return pivotHead.createResponse();
+ }
+}
+/**
+ * Typed Pivot class that stores the overall Pivot data and head of the Pivot node chain.
+ *
+ * This class exists so that the {@link PivotFacet} class doesn't have to be typed ( {@code <T>} ).
+ */
+class PivotHead<T> implements StreamingFacet {
+ private final PivotNode<T> topPivot;
+ private final Map<String, T> pivotValues;
+
+ public PivotHead(PivotNode<T> topPivot) {
+ this.topPivot = topPivot;
+ this.pivotValues = new HashMap<>();
+ }
+
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ topPivot.setReductionCollectionManager(collectionManager);
+ }
+
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ topPivot.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ topPivot.addFacetValueCollectionTargets(pivotValues);
+ }
+
+ public void importShardData(DataInput input) throws IOException {
+ topPivot.importPivot(input, pivotValues);
+ }
+
+ public void exportShardData(DataOutput output) throws IOException {
+ topPivot.exportPivot(output, pivotValues);
+ }
+
+ public Iterable<Map<String,Object>> createResponse() {
+ return topPivot.getPivotedResponse(pivotValues);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
new file mode 100644
index 0000000..c6c0dc4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
@@ -0,0 +1,263 @@
+/*
+ * 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.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Representation of one layer of a Pivot Facet. A PivotFacet node is individually sortable,
+ * and is collected during the streaming phase of the {@link AnalyticsDriver}.
+ */
+public abstract class PivotNode<T> extends SortableFacet implements Consumer<String> {
+ private StringValueStream expression;
+ protected Map<String,T> currentPivot;
+
+ public PivotNode(String name, StringValueStream expression) {
+ super(name);
+ this.expression = expression;
+ }
+
+ /**
+ * Determine which facet values match the current document. Add the {@link ReductionDataCollection}s of the relevant facet values
+ * to the targets of the streaming {@link ReductionCollectionManager} so that they are updated with the current document's data.
+ */
+ public void addFacetValueCollectionTargets(Map<String,T> pivot) {
+ currentPivot = pivot;
+ expression.streamStrings(this);
+ }
+
+ /**
+ * Import the shard data from a bit-stream for the given pivot, exported by the {@link #exportPivot} method
+ * in the each of the collection's shards.
+ *
+ * @param input The bit-stream to import the data from
+ * @param pivot the values for this pivot node and the pivot children (if they exist)
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public void importPivot(DataInput input, Map<String,T> pivot) throws IOException {
+ int size = input.readInt();
+ currentPivot = pivot;
+ for (int i = 0; i < size; ++i) {
+ importPivotValue(input, input.readUTF());
+ }
+ }
+ /**
+ * Import the next pivot value's set of {@link ReductionData} and children's {@link ReductionData} if they exist.
+ *
+ * @param input the bit-stream to import the reduction data from
+ * @param pivotValue the next pivot value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected abstract void importPivotValue(DataInput input, String pivotValue) throws IOException;
+
+ /**
+ * Export the shard data through a bit-stream for the given pivot,
+ * to be imported by the {@link #importPivot} method in the originating shard.
+ *
+ * @param output The bit-stream to output the data through
+ * @param pivot the values for this pivot node and the pivot children (if they exist)
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportPivot(DataOutput output, Map<String,T> pivot) throws IOException {
+ output.writeInt(pivot.size());
+ for (String pivotValue : pivot.keySet()) {
+ output.writeUTF(pivotValue);
+ exportPivotValue(output, pivot.get(pivotValue));
+ }
+ }
+ /**
+ * Export the given pivot data, containing {@link ReductionData} and pivot children if they exist.
+ *
+ * @param output the bit-stream to output the reduction data to
+ * @param pivotData the next pivot value data
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected abstract void exportPivotValue(DataOutput output, T pivotData) throws IOException;
+
+ /**
+ * Create the response of the facet to be returned in the overall analytics response.
+ *
+ * @param pivot the pivot to create a response for
+ * @return the response of the facet
+ */
+ public abstract Iterable<Map<String,Object>> getPivotedResponse(Map<String,T> pivot);
+
+ /**
+ * A pivot node that has no pivot children.
+ */
+ public static class PivotLeaf extends PivotNode<ReductionDataCollection> {
+
+ public PivotLeaf(String name, StringValueStream expression) {
+ super(name, expression);
+ }
+
+ @Override
+ public void accept(String pivotValue) {
+ ReductionDataCollection collection = currentPivot.get(pivotValue);
+ if (collection == null) {
+ collection = collectionManager.newDataCollectionTarget();
+ currentPivot.put(pivotValue, collection);
+ } else {
+ collectionManager.addCollectTarget(collection);
+ }
+ }
+
+ @Override
+ protected void importPivotValue(DataInput input, String pivotValue) throws IOException {
+ ReductionDataCollection dataCollection = currentPivot.get(pivotValue);
+ if (dataCollection == null) {
+ currentPivot.put(pivotValue, collectionManager.newDataCollectionIO());
+ } else {
+ collectionManager.prepareReductionDataIO(dataCollection);
+ }
+ collectionManager.mergeData();
+ }
+
+ @Override
+ protected void exportPivotValue(DataOutput output, ReductionDataCollection pivotData) throws IOException {
+ collectionManager.prepareReductionDataIO(pivotData);
+ collectionManager.exportData();
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> getPivotedResponse(Map<String,ReductionDataCollection> pivot) {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ pivot.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ Iterable<FacetBucket> facetResultsIter = applyOptions(facetResults);
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : facetResultsIter) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_NAME, name);
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ results.add(bucketMap);
+ }
+ return results;
+ }
+ }
+
+ /**
+ * A pivot node that has pivot children.
+ */
+ public static class PivotBranch<T> extends PivotNode<PivotBranch.PivotDataPair<T>> {
+ private final PivotNode<T> childPivot;
+ public PivotBranch(String name, StringValueStream expression, PivotNode<T> childPivot) {
+ super(name, expression);
+ this.childPivot = childPivot;
+ }
+
+ @Override
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ super.setReductionCollectionManager(collectionManager);
+ childPivot.setReductionCollectionManager(collectionManager);
+ }
+
+ @Override
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ super.setExpressionCalculator(expressionCalculator);
+ childPivot.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void accept(String pivotValue) {
+ PivotDataPair<T> pivotData = currentPivot.get(pivotValue);
+ if (pivotData == null) {
+ pivotData = new PivotDataPair<>();
+ pivotData.childPivots = new HashMap<>();
+ pivotData.pivotReduction = collectionManager.newDataCollectionTarget();
+ currentPivot.put(pivotValue, pivotData);
+ } else {
+ collectionManager.addCollectTarget(pivotData.pivotReduction);
+ }
+ childPivot.addFacetValueCollectionTargets(pivotData.childPivots);
+ }
+
+ @Override
+ protected void importPivotValue(DataInput input, String pivotValue) throws IOException {
+ PivotDataPair<T> pivotData = currentPivot.get(pivotValue);
+ if (pivotData == null) {
+ pivotData = new PivotDataPair<>();
+ pivotData.childPivots = new HashMap<>();
+ pivotData.pivotReduction = collectionManager.newDataCollectionIO();
+ currentPivot.put(pivotValue, pivotData);
+ } else {
+ collectionManager.prepareReductionDataIO(pivotData.pivotReduction);
+ }
+ collectionManager.mergeData();
+ childPivot.importPivot(input, pivotData.childPivots);
+ }
+
+ @Override
+ protected void exportPivotValue(DataOutput output, PivotDataPair<T> pivotData) throws IOException {
+ collectionManager.prepareReductionDataIO(pivotData.pivotReduction);
+ collectionManager.exportData();
+
+ childPivot.exportPivot(output, pivotData.childPivots);
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> getPivotedResponse(Map<String,PivotDataPair<T>> pivot) {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ pivot.forEach((facetVal, dataPair) -> {
+ collectionManager.setData(dataPair.pivotReduction);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ Iterable<FacetBucket> facetResultsIter = applyOptions(facetResults);
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : facetResultsIter) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_NAME, name);
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_CHILDREN, childPivot.getPivotedResponse(pivot.get(bucket.getFacetValue()).childPivots));
+ results.add(bucketMap);
+ }
+ return results;
+ }
+
+ /**
+ * Contains pivot data for {@link PivotNode.PivotBranch} classes.
+ */
+ protected static class PivotDataPair<T> {
+ ReductionDataCollection pivotReduction;
+ Map<String,T> childPivots;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
new file mode 100644
index 0000000..f880809
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
@@ -0,0 +1,64 @@
+/*
+ * 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.analytics.facet;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.QParser;
+
+/**
+ * A facet that breaks down the data by additional Solr Queries.
+ */
+public class QueryFacet extends AbstractSolrQueryFacet {
+ private final Map<String,String> queries;
+
+ public QueryFacet(String name, Map<String, String> queries) {
+ super(name);
+ this.queries = queries;
+ }
+
+ @Override
+ public void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer) {
+ queries.forEach( (queryName, query) -> {
+ final Query q;
+ try {
+ q = QParser.getParser(query, queryRequest).getQuery();
+ } catch( Exception e ){
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Invalid query '"+query+"' in query facet '" + getName() + "'",e);
+ }
+ // The searcher sends docIds to the QueryFacetAccumulator which forwards
+ // them to <code>collectQuery()</code> in this class for collection.
+ Query queryQuery = new BooleanQuery.Builder()
+ .add(q, Occur.MUST)
+ .add(filter, Occur.FILTER)
+ .build();
+
+ ReductionDataCollection dataCol = collectionManager.newDataCollection();
+ reductionData.put(queryName, dataCol);
+ consumer.accept(new FacetValueQueryExecuter(dataCol, queryQuery));
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
new file mode 100644
index 0000000..80e8d21
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
@@ -0,0 +1,119 @@
+/*
+ * 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.analytics.facet;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.util.FacetRangeGenerator;
+import org.apache.solr.analytics.util.FacetRangeGenerator.FacetRange;
+import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
+import org.apache.solr.common.params.FacetParams.FacetRangeOther;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.search.Filter;
+
+/**
+ * A facet that groups data by a discrete set of ranges.
+ */
+public class RangeFacet extends AbstractSolrQueryFacet {
+ protected final SchemaField field;
+ protected final String start;
+ protected final String end;
+ protected final List<String> gaps;
+ protected boolean hardEnd = false;
+ protected EnumSet<FacetRangeInclude> include;
+ protected EnumSet<FacetRangeOther> others;
+
+ public RangeFacet(String name, SchemaField field, String start, String end, List<String> gaps) {
+ super(name);
+ this.field = field;
+ this.start = start;
+ this.end = end;
+ this.gaps = gaps;
+ include = EnumSet.of(FacetRangeInclude.LOWER);
+ others = EnumSet.of(FacetRangeOther.NONE);
+ }
+
+ @Override
+ public void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer) {
+ // Computes the end points of the ranges in the rangeFacet
+ final FacetRangeGenerator<? extends Comparable<?>> rec = FacetRangeGenerator.create(this);
+ final SchemaField sf = field;
+
+ // Create a rangeFacetAccumulator for each range and
+ // collect the documents for that range.
+ for (FacetRange range : rec.getRanges()) {
+ Query q = sf.getType().getRangeQuery(null, sf, range.lower, range.upper, range.includeLower,range.includeUpper);
+ // The searcher sends docIds to the RangeFacetAccumulator which forwards
+ // them to <code>collectRange()</code> in this class for collection.
+ Query rangeQuery = new BooleanQuery.Builder()
+ .add(q, Occur.MUST)
+ .add(filter, Occur.FILTER)
+ .build();
+
+ ReductionDataCollection dataCol = collectionManager.newDataCollection();
+ reductionData.put(range.toString(), dataCol);
+ consumer.accept(new FacetValueQueryExecuter(dataCol, rangeQuery));
+ }
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public EnumSet<FacetRangeInclude> getInclude() {
+ return include;
+ }
+
+ public void setInclude(EnumSet<FacetRangeInclude> include) {
+ this.include = include;
+ }
+
+ public List<String> getGaps() {
+ return gaps;
+ }
+
+ public boolean isHardEnd() {
+ return hardEnd;
+ }
+
+ public void setHardEnd(boolean hardEnd) {
+ this.hardEnd = hardEnd;
+ }
+
+ public EnumSet<FacetRangeOther> getOthers() {
+ return others;
+ }
+
+ public void setOthers(EnumSet<FacetRangeOther> others) {
+ this.others = others;
+ }
+
+ public SchemaField getField() {
+ return field;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
new file mode 100644
index 0000000..ef1e04b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
@@ -0,0 +1,178 @@
+/*
+ * 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.analytics.facet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.solr.analytics.facet.compare.FacetResultsComparator;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * A facet that can be sorted by either the facet value or an expression value.
+ */
+public abstract class SortableFacet extends AnalyticsFacet {
+ protected FacetSortSpecification sort = null;
+
+ protected SortableFacet(String name) {
+ super(name);
+ }
+
+ @Override
+ public NamedList<Object> createOldResponse() {
+ final NamedList<Object> results = new NamedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : getBuckets()) {
+ results.add(bucket.getFacetValue(), new NamedList<>(bucket.getResults()));
+ }
+ return results;
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> createResponse() {
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : getBuckets()) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ results.add(bucketMap);
+ }
+ return results;
+ }
+
+ private Iterable<FacetBucket> getBuckets() {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ return applyOptions(facetResults);
+ }
+
+ /**
+ * Apply the sorting options to the given facet results.
+ *
+ * @param facetResults to apply sorting options to
+ * @return the sorted results
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ protected Iterable<FacetBucket> applyOptions(List<FacetBucket> facetResults) {
+ // Sorting the buckets if a sort specification is provided
+ if (sort == null || facetResults.isEmpty()) {
+ return facetResults;
+ }
+ Comparator comp = sort.getComparator();
+ Collections.sort(facetResults, comp);
+
+ Iterable<FacetBucket> facetResultsIter = facetResults;
+ // apply the limit
+ if (sort.getLimit() > 0) {
+ if (sort.getOffset() > 0) {
+ facetResultsIter = Iterables.skip(facetResultsIter, sort.getOffset());
+ }
+ facetResultsIter = Iterables.limit(facetResultsIter, sort.getLimit());
+ } else if (sort.getLimit() == 0) {
+ return new LinkedList<FacetBucket>();
+ }
+ return facetResultsIter;
+ }
+
+ /**
+ * Specifies how to sort the buckets of a sortable facet.
+ */
+ public static class FacetSortSpecification {
+ private FacetResultsComparator comparator;
+ protected int limit;
+ protected int offset;
+
+ public FacetSortSpecification(FacetResultsComparator comparator, int limit, int offset) {
+ this.comparator = comparator;
+ this.limit = limit;
+ this.offset = offset;
+ }
+
+ public FacetResultsComparator getComparator() {
+ return comparator;
+ }
+
+ /**
+ * Get the maximum number of buckets to be returned.
+ *
+ * @return the limit
+ */
+ public int getLimit() {
+ return limit;
+ }
+ /**
+ * Set the maximum number of buckets to be returned.
+ *
+ * @param limit the maximum number of buckets
+ */
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ /**
+ * Get the first bucket to return, has to be used with the {@code limit} option.
+ *
+ * @return the bucket offset
+ */
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+ public SortableFacet.FacetSortSpecification getSort() {
+ return sort;
+ }
+
+ public void setSort(SortableFacet.FacetSortSpecification sort) {
+ this.sort = sort;
+ }
+
+ public static class FacetBucket {
+ private final String facetValue;
+ private final Map<String,Object> expressionResults;
+
+ public FacetBucket(String facetValue, Map<String,Object> expressionResults) {
+ this.facetValue = facetValue;
+ this.expressionResults = expressionResults;
+ }
+
+ public Object getResult(String expression) {
+ return expressionResults.get(expression);
+ }
+
+ public Map<String,Object> getResults() {
+ return expressionResults;
+ }
+
+ public String getFacetValue() {
+ return facetValue;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
new file mode 100644
index 0000000..6cca041
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.facet;
+
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+
+/**
+ * A facet that is collected during the streaming phase of the {@link AnalyticsDriver}.
+ */
+public interface StreamingFacet {
+ /**
+ * Determine which facet values match the current document. Add the {@link ReductionDataCollection}s of the relevant facet values
+ * to the targets of the streaming {@link ReductionCollectionManager} so that they are updated with the current document's data.
+ */
+ void addFacetValueCollectionTargets();
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java
new file mode 100644
index 0000000..b1d84ba
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.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.analytics.facet;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * A facet that breaks up data by the values of a mapping expression or field.
+ * The mapping expression must be castable to a {@link StringValueStream}.
+ */
+public class ValueFacet extends SortableFacet implements StreamingFacet, Consumer<String> {
+ private StringValueStream expression;
+
+ public ValueFacet(String name, StringValueStream expression) {
+ super(name);
+ this.expression = expression;
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ expression.streamStrings(this);
+ }
+
+ @Override
+ public void accept(String t) {
+ ReductionDataCollection collection = reductionData.get(t);
+ if (collection == null) {
+ collection = collectionManager.newDataCollectionTarget();
+ reductionData.put(t, collection);
+ } else {
+ collectionManager.addCollectTarget(collection);
+ }
+ }
+
+ /**
+ * Get the expression used to create the facet values.
+ *
+ * @return a string mapping expression
+ */
+ public StringValueStream getExpression() {
+ return expression;
+ }
+}
\ No newline at end of file
[03/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/rangeFacets.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/rangeFacets.xml b/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/rangeFacets.xml
deleted file mode 100644
index 4a596f7..0000000
--- a/solr/contrib/analytics/src/test-files/analytics/requestXMLFiles/rangeFacets.xml
+++ /dev/null
@@ -1,319 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<analyticsRequestEnvelope stats="true" olap="true">
- <analyticsRequest>
- <name>regular int</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(int(int_id))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="false">
- <field>long_ld</field>
- <start>5</start>
- <end>30</end>
- <gap>5</gap>
- <includeBoundary>lower</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>double_dd</field>
- <start>3</start>
- <end>39</end>
- <gap>7</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>date_dtd</field>
- <start>1007-01-01T23:59:59Z</start>
- <end>1044-01-01T23:59:59Z</end>
- <gap>+7YEARS</gap>
- <includeBoundary>lower</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>regular float</name>
-
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(float(float_fd))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(float(float_fd))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="false">
- <field>long_ld</field>
- <start>0</start>
- <end>29</end>
- <gap>4</gap>
- <includeBoundary>all</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>double_dd</field>
- <start>4</start>
- <end>47</end>
- <gap>11</gap>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>date_dtd</field>
- <start>1004-01-01T23:59:59Z</start>
- <end>1046-01-01T23:59:59Z</end>
- <gap>+5YEARS</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>hardend int</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(int(int_id))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="true">
- <field>long_ld</field>
- <start>5</start>
- <end>30</end>
- <gap>5</gap>
- <includeBoundary>lower</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="true">
- <field>double_dd</field>
- <start>3</start>
- <end>39</end>
- <gap>7</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="true">
- <field>date_dtd</field>
- <start>1007-01-01T23:59:59Z</start>
- <end>1044-01-01T23:59:59Z</end>
- <gap>+7YEARS</gap>
- <includeBoundary>lower</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>hardend float</name>
-
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(float(float_fd))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(float(float_fd))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="true">
- <field>long_ld</field>
- <start>0</start>
- <end>29</end>
- <gap>4</gap>
- <includeBoundary>all</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="true">
- <field>double_dd</field>
- <start>4</start>
- <end>47</end>
- <gap>11</gap>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="true">
- <field>date_dtd</field>
- <start>1004-01-01T23:59:59Z</start>
- <end>1046-01-01T23:59:59Z</end>
- <gap>+5YEARS</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>multigap int</name>
-
- <statistic>
- <expression>mean(int(int_id))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(int(int_id))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(int(int_id))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(int(int_id))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(int(int_id))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="false">
- <field>long_ld</field>
- <start>5</start>
- <end>30</end>
- <gap>4</gap>
- <gap>2</gap>
- <gap>6</gap>
- <gap>3</gap>
- <includeBoundary>lower</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>double_dd</field>
- <start>3</start>
- <end>39</end>
- <gap>3</gap>
- <gap>1</gap>
- <gap>7</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>date_dtd</field>
- <start>1007-01-01T23:59:59Z</start>
- <end>1044-01-01T23:59:59Z</end>
- <gap>+2YEARS</gap>
- <gap>+7YEARS</gap>
- <includeBoundary>lower</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <includeBoundary>outer</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
- <analyticsRequest>
- <name>multigap float</name>
-
- <statistic>
- <expression>mean(float(float_fd))</expression>
- <name>mean</name>
- </statistic>
- <statistic>
- <expression>sum(float(float_fd))</expression>
- <name>sum</name>
- </statistic>
- <statistic>
- <expression>median(float(float_fd))</expression>
- <name>median</name>
- </statistic>
- <statistic>
- <expression>count(float(float_fd))</expression>
- <name>count</name>
- </statistic>
- <statistic>
- <expression>sumofsquares(float(float_fd))</expression>
- <name>sumOfSquares</name>
- </statistic>
-
- <rangeFacet hardend="false">
- <field>long_ld</field>
- <start>0</start>
- <end>29</end>
- <gap>1</gap>
- <gap>4</gap>
- <includeBoundary>all</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>double_dd</field>
- <start>4</start>
- <end>47</end>
- <gap>2</gap>
- <gap>3</gap>
- <gap>11</gap>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- <rangeFacet hardend="false">
- <field>date_dtd</field>
- <start>1004-01-01T23:59:59Z</start>
- <end>1046-01-01T23:59:59Z</end>
- <gap>+4YEARS</gap>
- <gap>+5YEARS</gap>
- <includeBoundary>upper</includeBoundary>
- <includeBoundary>edge</includeBoundary>
- <otherRange>all</otherRange>
- </rangeFacet>
- </analyticsRequest>
-</analyticsRequestEnvelope>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/expressions.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/expressions.txt b/solr/contrib/analytics/src/test-files/solr/analytics/expressions.txt
new file mode 100644
index 0000000..6f5c916
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/expressions.txt
@@ -0,0 +1,65 @@
+o.ar.s.sum=sum(int_id)
+o.ar.s.unique=unique(long_ld)
+o.ar.s.su=add(sum(int_id),unique(long_ld))
+o.ar.s.mean=mean(int_id)
+o.ar.s.count=count(long_ld)
+o.ar.s.median=median(int_id)
+o.ar.s.mcm=add(mean(int_id),count(long_ld),median(int_id))
+
+o.mr.s.sum=sum(int_id)
+o.mr.s.unique=unique(long_ld)
+o.mr.s.su=mult(sum(int_id),unique(long_ld))
+o.mr.s.mean=mean(int_id)
+o.mr.s.count=count(long_ld)
+o.mr.s.median=median(int_id)
+o.mr.s.mcm=mult(mean(int_id),count(long_ld),median(int_id))
+
+o.dr.s.sum=sum(int_id)
+o.dr.s.unique=unique(long_ld)
+o.dr.s.su=div(sum(int_id),unique(long_ld))
+o.dr.s.mean=mean(int_id)
+o.dr.s.count=count(long_ld)
+o.dr.s.mc=div(mean(int_id),count(long_ld))
+
+o.pr.s.sum=sum(int_id)
+o.pr.s.unique=unique(long_ld)
+o.pr.s.su=pow(sum(int_id),unique(long_ld))
+o.pr.s.mean=mean(int_id)
+o.pr.s.count=count(long_ld)
+o.pr.s.mc=pow(mean(int_id),count(long_ld))
+
+o.nr.s.sum=sum(int_id)
+o.nr.s.s=neg(sum(int_id))
+o.nr.s.count=count(long_ld)
+o.nr.s.c=neg(count(long_ld))
+
+o.avr.s.sum=sum(int_id)
+o.avr.s.s=abs(neg(sum(int_id)))
+o.avr.s.count=count(long_ld)
+o.avr.s.c=abs(neg(count(long_ld)))
+
+o.cnr.s.c8=8
+o.cnr.s.c10=10.0
+
+o.dmr.s.median=median(date_dtd)
+o.dmr.s.cme="+2YEARS"
+o.dmr.s.dmme=date_math(median(date_dtd),"+2YEARS")
+o.dmr.s.max=max(date_dtd)
+o.dmr.s.cma="+2MONTHS"
+o.dmr.s.dmma=date_math(max(date_dtd),"+2MONTHS")
+
+o.cdr.s.cd1=1800-12-31T23:59:59Z
+o.cdr.s.cs1="1800-12-31T23:59:59Z"
+o.cdr.s.cd2=1804-06-30T23:59:59Z
+o.cdr.s.cs2="1804-06-30T23:59:59Z"
+
+o.csr.s.cs1="this is the first"
+o.csr.s.cs2="this is the second"
+o.csr.s.cs3="this is the third"
+
+o.cr.s.csmin="this is the first"
+o.cr.s.min=min(string_sd)
+o.cr.s.ccmin=concat("this is the first",min(string_sd))
+o.cr.s.csmax="this is the second"
+o.cr.s.max=max(string_sd)
+o.cr.s.ccmax=concat("this is the second",max(string_sd))
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/facetSorting.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/facetSorting.txt b/solr/contrib/analytics/src/test-files/solr/analytics/facetSorting.txt
new file mode 100644
index 0000000..4663217
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/facetSorting.txt
@@ -0,0 +1,4 @@
+o.ar.s.min=min(double_dd)
+o.ar.s.max=max(long_ld)
+o.ar.ff=string_sd
+o.ar.ff.string_sd.sortstatistic=min
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacetExtras.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacetExtras.txt b/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacetExtras.txt
new file mode 100644
index 0000000..3979f57
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacetExtras.txt
@@ -0,0 +1,66 @@
+o.sr.s.mean=mean(int_id)
+o.sr.s.median=median(int_id)
+o.sr.s.count=count(int_id)
+o.sr.s.percentile_20=percentile(20,int_id)
+o.sr.ff=long_ld
+o.sr.ff.long_ld.ss=mean
+o.sr.ff.long_ld.sd=asc
+o.sr.ff=float_fd
+o.sr.ff.float_fd.ss=median
+o.sr.ff.float_fd.sd=desc
+o.sr.ff=double_dd
+o.sr.ff.double_dd.ss=count
+o.sr.ff.double_dd.sd=asc
+o.sr.ff=string_sd
+o.sr.ff.string_sd.ss=percentile_20
+o.sr.ff.string_sd.sd=desc
+
+o.lr.s.mean=mean(int_id)
+o.lr.s.median=median(int_id)
+o.lr.s.count=count(int_id)
+o.lr.s.percentile_20=percentile(20,int_id)
+o.lr.ff=long_ld
+o.lr.ff.long_ld.ss=mean
+o.lr.ff.long_ld.sd=asc
+o.lr.ff.long_ld.limit=5
+o.lr.ff=float_fd
+o.lr.ff.float_fd.ss=median
+o.lr.ff.float_fd.sd=desc
+o.lr.ff.float_fd.limit=3
+o.lr.ff=double_dd
+o.lr.ff.double_dd.ss=count
+o.lr.ff.double_dd.sd=asc
+o.lr.ff.double_dd.limit=7
+o.lr.ff=string_sd
+o.lr.ff.string_sd.ss=percentile_20
+o.lr.ff.string_sd.sd=desc
+o.lr.ff.string_sd.limit=1
+
+
+
+o.offAll.s.mean=mean(int_id)
+o.offAll.ff=long_ld
+o.offAll.ff.long_ld.ss=mean
+o.offAll.ff.long_ld.sd=asc
+o.offAll.ff.long_ld.limit=7
+
+o.off0.s.mean=mean(int_id)
+o.off0.ff=long_ld
+o.off0.ff.long_ld.ss=mean
+o.off0.ff.long_ld.sd=asc
+o.off0.ff.long_ld.limit=2
+o.off0.ff.long_ld.offset=0
+
+o.off1.s.mean=mean(int_id)
+o.off1.ff=long_ld
+o.off1.ff.long_ld.ss=mean
+o.off1.ff.long_ld.sd=asc
+o.off1.ff.long_ld.limit=2
+o.off1.ff.long_ld.offset=2
+
+o.off2.s.mean=mean(int_id)
+o.off2.ff=long_ld
+o.off2.ff.long_ld.ss=mean
+o.off2.ff.long_ld.sd=asc
+o.off2.ff.long_ld.limit=3
+o.off2.ff.long_ld.offset=4
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacets.txt b/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacets.txt
new file mode 100644
index 0000000..5ba5953
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/fieldFacets.txt
@@ -0,0 +1,132 @@
+o.sum.s.int=sum(int_id)
+o.sum.s.long=sum(long_ld)
+o.sum.s.float=sum(float_fd)
+o.sum.s.double=sum(double_dd)
+o.sum.ff=string_sd
+o.sum.ff=date_dtd
+
+o.mean.s.int=mean(int_id)
+o.mean.s.long=mean(long_ld)
+o.mean.s.float=mean(float_fd)
+o.mean.s.double=mean(double_dd)
+o.mean.ff=string_sd
+o.mean.ff=date_dtd
+
+o.sumOfSquares.s.int=sumofsquares(int_id)
+o.sumOfSquares.s.long=sumofsquares(long_ld)
+o.sumOfSquares.s.float=sumofsquares(float_fd)
+o.sumOfSquares.s.double=sumofsquares(double_dd)
+o.sumOfSquares.ff=string_sd
+o.sumOfSquares.ff=date_dtd
+
+o.stddev.s.int=stddev(int_id)
+o.stddev.s.long=stddev(long_ld)
+o.stddev.s.float=stddev(float_fd)
+o.stddev.s.double=stddev(double_dd)
+o.stddev.ff=string_sd
+o.stddev.ff=date_dtd
+
+o.median.s.int=median(int_id)
+o.median.s.long=median(long_ld)
+o.median.s.float=median(float_fd)
+o.median.s.double=median(double_dd)
+o.median.ff=string_sd
+o.median.ff=date_dtd
+
+o.percentile_20n.s.int=percentile(20,int_id)
+o.percentile_20n.s.long=percentile(20,long_ld)
+o.percentile_20n.s.float=percentile(20,float_fd)
+o.percentile_20n.s.double=percentile(20,double_dd)
+o.percentile_20n.ff=string_sd
+o.percentile_20n.ff=date_dtd
+
+o.percentile_20.s.str=percentile(20,string_sd)
+o.percentile_20.s.date=percentile(20,date_dtd)
+o.percentile_20.ff=int_id
+o.percentile_20.ff=long_ld
+
+o.percentile_60n.s.int=percentile(60,int_id)
+o.percentile_60n.s.long=percentile(60,long_ld)
+o.percentile_60n.s.float=percentile(60,float_fd)
+o.percentile_60n.s.double=percentile(60,double_dd)
+o.percentile_60n.ff=string_sd
+o.percentile_60n.ff=date_dtd
+
+o.percentile_60.s.str=percentile(60,string_sd)
+o.percentile_60.s.date=percentile(60,date_dtd)
+o.percentile_60.ff=int_id
+o.percentile_60.ff=long_ld
+
+o.minn.s.int=min(int_id)
+o.minn.s.long=min(long_ld)
+o.minn.s.float=min(float_fd)
+o.minn.s.double=min(double_dd)
+o.minn.ff=string_sd
+o.minn.ff=date_dtd
+
+o.min.s.str=min(string_sd)
+o.min.s.date=min(date_dtd)
+o.min.ff=int_id
+o.min.ff=long_ld
+
+o.maxn.s.int=max(int_id)
+o.maxn.s.long=max(long_ld)
+o.maxn.s.float=max(float_fd)
+o.maxn.s.double=max(double_dd)
+o.maxn.ff=string_sd
+o.maxn.ff=date_dtd
+
+o.max.s.str=max(string_sd)
+o.max.s.date=max(date_dtd)
+o.max.ff=int_id
+o.max.ff=long_ld
+
+o.countn.s.int=count(int_id)
+o.countn.s.long=count(long_ld)
+o.countn.s.float=count(float_fd)
+o.countn.s.double=count(double_dd)
+o.countn.ff=string_sd
+o.countn.ff=date_dtd
+
+o.count.s.str=count(string_sd)
+o.count.s.date=count(date_dtd)
+o.count.ff=int_id
+o.count.ff=long_ld
+
+o.uniquen.s.int=unique(int_id)
+o.uniquen.s.long=unique(long_ld)
+o.uniquen.s.float=unique(float_fd)
+o.uniquen.s.double=unique(double_dd)
+o.uniquen.ff=string_sd
+o.uniquen.ff=date_dtd
+
+o.unique.s.str=unique(string_sd)
+o.unique.s.date=unique(date_dtd)
+o.unique.ff=int_id
+o.unique.ff=long_ld
+
+o.missingn.s.int=missing(int_id)
+o.missingn.s.long=missing(long_ld)
+o.missingn.s.float=missing(float_fd)
+o.missingn.s.double=missing(double_dd)
+o.missingn.ff=string_sd
+o.missingn.ff=date_dtd
+
+o.missing.s.str=missing(string_sd)
+o.missing.s.date=missing(date_dtd)
+o.missing.ff=int_id
+o.missing.ff=long_ld
+
+o.multivalued.s.mean=mean(int_id)
+o.multivalued.ff=long_ldm
+o.multivalued.ff=string_sdm
+o.multivalued.ff=date_dtdm
+
+o.missingf.s.mean=mean(int_id)
+o.missingf.ff=date_dtd
+o.missingf.ff.date_dtd.dim=true
+o.missingf.ff=string_sd
+o.missingf.ff.string_sd.dim=true
+o.missingf.ff.string_sd.sm=true
+o.missingf.ff=date_dtdm
+o.missingf.ff.date_dtdm.sm=true
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/functions.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/functions.txt b/solr/contrib/analytics/src/test-files/solr/analytics/functions.txt
new file mode 100644
index 0000000..ce73583
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/functions.txt
@@ -0,0 +1,57 @@
+o.ar.s.sum=sum(add(int_id,float_fd))
+o.ar.s.sumc=sum(add_if_dd)
+o.ar.s.mean=mean(add(long_ld,double_dd,float_fd))
+o.ar.s.meanc=mean(add_ldf_dd)
+
+o.mr.s.sum=sum(mult(int_id,float_fd))
+o.mr.s.sumc=sum(mult_if_dd)
+o.mr.s.mean=mean(mult(long_ld,double_dd,float_fd))
+o.mr.s.meanc=mean(mult_ldf_dd)
+
+o.dr.s.sum=sum(div(int_id,float_fd))
+o.dr.s.sumc=sum(div_if_dd)
+o.dr.s.mean=mean(div(long_ld,double_dd))
+o.dr.s.meanc=mean(div_ld_dd)
+
+o.pr.s.sum=sum(pow(int_id,float_fd))
+o.pr.s.sumc=sum(pow_if_dd)
+o.pr.s.mean=mean(pow(long_ld,double_dd))
+o.pr.s.meanc=mean(pow_ld_dd)
+
+o.nr.s.sum=sum(neg(int_id))
+o.nr.s.sumc=sum(neg_id)
+o.nr.s.mean=mean(neg(long_ld))
+o.nr.s.meanc=mean(neg_ld)
+
+o.avr.s.sum=sum(abs(neg(int_id)))
+o.avr.s.sumc=sum(int_id)
+o.avr.s.mean=mean(abs(neg(int_id)))
+o.avr.s.meanc=mean(int_id)
+
+o.cnr.s.sum=sum(8)
+o.cnr.s.sumc=sum(const_8_dd)
+o.cnr.s.mean=mean(10)
+o.cnr.s.meanc=mean(const_10_dd)
+
+o.dmr.s.median=median(date_math(date_dtd,"+2YEARS"))
+o.dmr.s.medianc=median(dm_2y_dtd)
+o.dmr.s.max=max(date_math(date_dtd,"+2MONTHS"))
+o.dmr.s.maxc=max(dm_2m_dtd)
+
+o.cdr.s.median=median(1800-06-30T23:59:59Z)
+o.cdr.s.medianc=median(const_00_dtd)
+o.cdr.s.max=max(1804-06-30T23:59:59Z)
+o.cdr.s.maxc=max(const_04_dtd)
+
+o.csr.s.min=min("this is the first")
+o.csr.s.minc=min(const_first_sd)
+o.csr.s.max=max("this is the second")
+o.csr.s.maxc=max(const_second_sd)
+
+o.cr.s.min=concat("this is the first",min(string_sd))
+o.cr.s.minc=min(concat_first_sd)
+o.cr.s.max=concat("this is the second",max(string_sd))
+o.cr.s.maxc=max(concat_second_sd)
+
+o.ms.s.min=min(miss_dd)
+o.ms.s.max=max(miss_dd)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/noFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/noFacets.txt b/solr/contrib/analytics/src/test-files/solr/analytics/noFacets.txt
new file mode 100644
index 0000000..84e43eb
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/noFacets.txt
@@ -0,0 +1,74 @@
+o.sr.s.int_id=sum(int_id)
+o.sr.s.long_ld=sum(long_ld)
+o.sr.s.float_fd=sum(float_fd)
+o.sr.s.double_dd=sum(double_dd)
+
+o.sosr.s.int_id=sumofsquares(int_id)
+o.sosr.s.long_ld=sumofsquares(long_ld)
+o.sosr.s.float_fd=sumofsquares(float_fd)
+o.sosr.s.double_dd=sumofsquares(double_dd)
+
+o.mr.s.int_id=mean(int_id)
+o.mr.s.long_ld=mean(long_ld)
+o.mr.s.float_fd=mean(float_fd)
+o.mr.s.double_dd=mean(double_dd)
+
+o.str.s.int_id=stddev(int_id)
+o.str.s.long_ld=stddev(long_ld)
+o.str.s.float_fd=stddev(float_fd)
+o.str.s.double_dd=stddev(double_dd)
+
+o.medr.s.int_id=median(int_id)
+o.medr.s.long_ld=median(long_ld)
+o.medr.s.float_fd=median(float_fd)
+o.medr.s.double_dd=median(double_dd)
+o.medr.s.date_dtd=median(date_dtd)
+
+o.p2r.s.int_id=percentile(20,int_id)
+o.p2r.s.long_ld=percentile(20,long_ld)
+o.p2r.s.float_fd=percentile(20,float_fd)
+o.p2r.s.double_dd=percentile(20,double_dd)
+o.p2r.s.date_dtd=percentile(20,date_dtd)
+o.p2r.s.string_sd=percentile(20,string_sd)
+
+o.p6r.s.int_id=percentile(60,int_id)
+o.p6r.s.long_ld=percentile(60,long_ld)
+o.p6r.s.float_fd=percentile(60,float_fd)
+o.p6r.s.double_dd=percentile(60,double_dd)
+o.p6r.s.date_dtd=percentile(60,date_dtd)
+o.p6r.s.string_sd=percentile(60,string_sd)
+
+o.mir.s.int_id=min(int_id)
+o.mir.s.long_ld=min(long_ld)
+o.mir.s.float_fd=min(float_fd)
+o.mir.s.double_dd=min(double_dd)
+o.mir.s.date_dtd=min(date_dtd)
+o.mir.s.string_sd=min(string_sd)
+
+o.mar.s.int_id=max(int_id)
+o.mar.s.long_ld=max(long_ld)
+o.mar.s.float_fd=max(float_fd)
+o.mar.s.double_dd=max(double_dd)
+o.mar.s.date_dtd=max(date_dtd)
+o.mar.s.string_sd=max(string_sd)
+
+o.cr.s.int_id=count(int_id)
+o.cr.s.long_ld=count(long_ld)
+o.cr.s.float_fd=count(float_fd)
+o.cr.s.double_dd=count(double_dd)
+o.cr.s.date_dtd=count(date_dtd)
+o.cr.s.string_sd=count(string_sd)
+
+o.ur.s.int_id=unique(int_id)
+o.ur.s.long_ld=unique(long_ld)
+o.ur.s.float_fd=unique(float_fd)
+o.ur.s.double_dd=unique(double_dd)
+o.ur.s.date_dtd=unique(date_dtd)
+o.ur.s.string_sd=unique(string_sd)
+
+o.misr.s.int_id=missing(int_id)
+o.misr.s.long_ld=missing(long_ld)
+o.misr.s.float_fd=missing(float_fd)
+o.misr.s.double_dd=missing(double_dd)
+o.misr.s.date_dtd=missing(date_dtd)
+o.misr.s.string_sd=missing(string_sd)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/queryFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/queryFacets.txt b/solr/contrib/analytics/src/test-files/solr/analytics/queryFacets.txt
new file mode 100644
index 0000000..84d8fc6
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/queryFacets.txt
@@ -0,0 +1,27 @@
+o.ir.s.sum=sum(int_id)
+o.ir.s.mean=mean(int_id)
+o.ir.s.median=median(int_id)
+o.ir.s.percentile_8=percentile(8,int_id)
+o.ir.ff=string_sd
+o.ir.ff.string_sd.h=true
+o.ir.qf=float1
+o.ir.qf.float1.q=float_fd:[* TO 50]
+o.ir.qf=float2
+o.ir.qf.float2.q=float_fd:[* TO 30]
+
+o.lr.s.sum=sum(long_ld)
+o.lr.s.mean=mean(long_ld)
+o.lr.s.median=median(long_ld)
+o.lr.s.percentile_8=percentile(8,long_ld)
+o.lr.qf=string
+o.lr.qf.string.q=string_sd:abc1
+o.lr.qf.string.q=string_sd:abc2
+
+o.fr.s.sum=sum(float_fd)
+o.fr.s.mean=mean(float_fd)
+o.fr.s.median=median(float_fd)
+o.fr.s.percentile_8=percentile(8,float_fd)
+o.fr.qf=lad
+o.fr.qf.lad.q=long_ld:[20 TO *]
+o.fr.qf.lad.q=long_ld:[30 TO *]
+o.fr.qf.lad.q=double_dd:[* TO 50]
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/analytics/rangeFacets.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/analytics/rangeFacets.txt b/solr/contrib/analytics/src/test-files/solr/analytics/rangeFacets.txt
new file mode 100644
index 0000000..29aae5d
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/analytics/rangeFacets.txt
@@ -0,0 +1,161 @@
+o.ri.s.sum=sum(int_id)
+o.ri.s.mean=mean(int_id)
+o.ri.s.median=median(int_id)
+o.ri.s.count=count(int_id)
+o.ri.s.sumOfSquares=sumofsquares(int_id)
+o.ri.rf=long_ld
+o.ri.rf.long_ld.st=5
+o.ri.rf.long_ld.e=30
+o.ri.rf.long_ld.g=5
+o.ri.rf.long_ld.ib=lower
+o.ri.rf.long_ld.or=all
+o.ri.rf=double_dd
+o.ri.rf.double_dd.st=3
+o.ri.rf.double_dd.e=39
+o.ri.rf.double_dd.g=7
+o.ri.rf.double_dd.ib=upper
+o.ri.rf.double_dd.ib=outer
+o.ri.rf.double_dd.or=all
+o.ri.rf=date_dtd
+o.ri.rf.date_dtd.st=1007-01-01T23:59:59Z
+o.ri.rf.date_dtd.e=1044-01-01T23:59:59Z
+o.ri.rf.date_dtd.g=+7YEARS
+o.ri.rf.date_dtd.ib=lower
+o.ri.rf.date_dtd.ib=edge
+o.ri.rf.date_dtd.ib=outer
+o.ri.rf.date_dtd.or=all
+
+o.rf.s.sum=sum(float_fd)
+o.rf.s.mean=mean(float_fd)
+o.rf.s.median=median(float_fd)
+o.rf.s.count=count(float_fd)
+o.rf.s.sumOfSquares=sumofsquares(float_fd)
+o.rf.rf=long_ld
+o.rf.rf.long_ld.st=0
+o.rf.rf.long_ld.e=29
+o.rf.rf.long_ld.g=4
+o.rf.rf.long_ld.ib=all
+o.rf.rf.long_ld.or=all
+o.rf.rf=double_dd
+o.rf.rf.double_dd.st=4
+o.rf.rf.double_dd.e=47
+o.rf.rf.double_dd.g=11
+o.rf.rf.double_dd.ib=edge
+o.rf.rf.double_dd.or=all
+o.rf.rf=date_dtd
+o.rf.rf.date_dtd.st=1004-01-01T23:59:59Z
+o.rf.rf.date_dtd.e=1046-01-01T23:59:59Z
+o.rf.rf.date_dtd.g=+5YEARS
+o.rf.rf.date_dtd.ib=upper
+o.rf.rf.date_dtd.ib=edge
+o.rf.rf.date_dtd.or=all
+
+o.hi.s.sum=sum(int_id)
+o.hi.s.mean=mean(int_id)
+o.hi.s.median=median(int_id)
+o.hi.s.count=count(int_id)
+o.hi.s.sumOfSquares=sumofsquares(int_id)
+o.hi.rf=long_ld
+o.hi.rf.long_ld.st=5
+o.hi.rf.long_ld.e=30
+o.hi.rf.long_ld.g=5
+o.hi.rf.long_ld.he=true
+o.hi.rf.long_ld.ib=lower
+o.hi.rf.long_ld.or=all
+o.hi.rf=double_dd
+o.hi.rf.double_dd.st=3
+o.hi.rf.double_dd.e=39
+o.hi.rf.double_dd.g=7
+o.hi.rf.double_dd.he=true
+o.hi.rf.double_dd.ib=upper
+o.hi.rf.double_dd.ib=outer
+o.hi.rf.double_dd.or=all
+o.hi.rf=date_dtd
+o.hi.rf.date_dtd.st=1007-01-01T23:59:59Z
+o.hi.rf.date_dtd.e=1044-01-01T23:59:59Z
+o.hi.rf.date_dtd.g=+7YEARS
+o.hi.rf.date_dtd.he=true
+o.hi.rf.date_dtd.ib=lower
+o.hi.rf.date_dtd.ib=edge
+o.hi.rf.date_dtd.ib=outer
+o.hi.rf.date_dtd.or=all
+
+o.hf.s.sum=sum(float_fd)
+o.hf.s.mean=mean(float_fd)
+o.hf.s.median=median(float_fd)
+o.hf.s.count=count(float_fd)
+o.hf.s.sumOfSquares=sumofsquares(float_fd)
+o.hf.rf=long_ld
+o.hf.rf.long_ld.st=0
+o.hf.rf.long_ld.e=29
+o.hf.rf.long_ld.g=4
+o.hf.rf.long_ld.he=true
+o.hf.rf.long_ld.ib=all
+o.hf.rf.long_ld.or=all
+o.hf.rf=double_dd
+o.hf.rf.double_dd.st=4
+o.hf.rf.double_dd.e=47
+o.hf.rf.double_dd.g=11
+o.hf.rf.double_dd.he=true
+o.hf.rf.double_dd.ib=edge
+o.hf.rf.double_dd.or=all
+o.hf.rf=date_dtd
+o.hf.rf.date_dtd.st=1004-01-01T23:59:59Z
+o.hf.rf.date_dtd.e=1046-01-01T23:59:59Z
+o.hf.rf.date_dtd.g=+5YEARS
+o.hf.rf.date_dtd.he=true
+o.hf.rf.date_dtd.ib=upper
+o.hf.rf.date_dtd.ib=edge
+o.hf.rf.date_dtd.or=all
+
+o.mi.s.sum=sum(int_id)
+o.mi.s.mean=mean(int_id)
+o.mi.s.median=median(int_id)
+o.mi.s.count=count(int_id)
+o.mi.s.sumOfSquares=sumofsquares(int_id)
+o.mi.rf=long_ld
+o.mi.rf.long_ld.st=5
+o.mi.rf.long_ld.e=30
+o.mi.rf.long_ld.g=4,2,6,3
+o.mi.rf.long_ld.ib=lower
+o.mi.rf.long_ld.or=all
+o.mi.rf=double_dd
+o.mi.rf.double_dd.st=3
+o.mi.rf.double_dd.e=39
+o.mi.rf.double_dd.g=3,1,7
+o.mi.rf.double_dd.ib=upper
+o.mi.rf.double_dd.ib=outer
+o.mi.rf.double_dd.or=all
+o.mi.rf=date_dtd
+o.mi.rf.date_dtd.st=1007-01-01T23:59:59Z
+o.mi.rf.date_dtd.e=1044-01-01T23:59:59Z
+o.mi.rf.date_dtd.g=+2YEARS,+7YEARS
+o.mi.rf.date_dtd.ib=lower
+o.mi.rf.date_dtd.ib=edge
+o.mi.rf.date_dtd.ib=outer
+o.mi.rf.date_dtd.or=all
+
+o.mf.s.sum=sum(float_fd)
+o.mf.s.mean=mean(float_fd)
+o.mf.s.median=median(float_fd)
+o.mf.s.count=count(float_fd)
+o.mf.s.sumOfSquares=sumofsquares(float_fd)
+o.mf.rf=long_ld
+o.mf.rf.long_ld.st=0
+o.mf.rf.long_ld.e=29
+o.mf.rf.long_ld.g=1,4
+o.mf.rf.long_ld.ib=all
+o.mf.rf.long_ld.or=all
+o.mf.rf=double_dd
+o.mf.rf.double_dd.st=4
+o.mf.rf.double_dd.e=47
+o.mf.rf.double_dd.g=2,3,11
+o.mf.rf.double_dd.ib=edge
+o.mf.rf.double_dd.or=all
+o.mf.rf=date_dtd
+o.mf.rf.date_dtd.st=1004-01-01T23:59:59Z
+o.mf.rf.date_dtd.e=1046-01-01T23:59:59Z
+o.mf.rf.date_dtd.g=+4YEARS,+5YEARS
+o.mf.rf.date_dtd.ib=upper
+o.mf.rf.date_dtd.ib=edge
+o.mf.rf.date_dtd.or=all
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/collection1/conf/schema-analytics.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/collection1/conf/schema-analytics.xml b/solr/contrib/analytics/src/test-files/solr/collection1/conf/schema-analytics.xml
index 04b22b1..82d408a 100644
--- a/solr/contrib/analytics/src/test-files/solr/collection1/conf/schema-analytics.xml
+++ b/solr/contrib/analytics/src/test-files/solr/collection1/conf/schema-analytics.xml
@@ -25,7 +25,7 @@
-->
-<schema name="schema-docValues" version="1.6">
+<schema name="schema-analytics" version="1.0">
<!-- field type definitions... note that the "name" attribute is
@@ -54,7 +54,7 @@
<fieldType name="uuid" class="solr.UUIDField"/>
- <field name="id" type="string" required="true"/>
+ <field name="id" type="string" docValues="true" multiValued="false" required="true"/>
<field name="floatdv" type="float" indexed="false" stored="false" docValues="true" default="1"/>
<field name="intdv" type="int" indexed="false" stored="false" docValues="true" default="2"/>
@@ -63,8 +63,7 @@
<field name="datedv" type="date" indexed="false" stored="false" docValues="true" default="1995-12-31T23:59:59.999Z"/>
<field name="stringdv" type="string" indexed="false" stored="false" docValues="true" default="solr"/>
- <field name="stringdvm" type="string" indexed="false" stored="false" docValues="true" default="solr"
- multiValued="true"/>
+ <field name="stringdvm" type="string" indexed="false" stored="false" docValues="true" default="solr" multiValued="true"/>
<dynamicField name="*_i" type="int" indexed="true" stored="true" docValues="false" multiValued="false"/>
<dynamicField name="*_id" type="int" indexed="true" stored="true" docValues="true" multiValued="false"/>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-analytics.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-analytics.xml b/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-analytics.xml
new file mode 100644
index 0000000..31d6437
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-analytics.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<config>
+ <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+ <dataDir>${solr.data.dir:}</dataDir>
+ <xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
+ <schemaFactory class="ClassicIndexSchemaFactory"/>
+
+ <requestHandler name="standard" class="solr.StandardRequestHandler">
+ <arr name="components">
+ <str>query</str>
+ <str>facet</str>
+ <str>analytics</str>
+ <str>highlight</str>
+ <str>debug</str>
+ <str>expand</str>
+ </arr>
+ </requestHandler>
+
+ <searchComponent name="analytics" class="org.apache.solr.handler.component.AnalyticsComponent" />
+
+ <requestHandler name="/analytics" class="org.apache.solr.handler.AnalyticsHandler" />
+
+</config>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-basic.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-basic.xml b/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-basic.xml
deleted file mode 100644
index 604bb17..0000000
--- a/solr/contrib/analytics/src/test-files/solr/collection1/conf/solrconfig-basic.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" ?>
-
-<!--
- 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.
--->
-
-<config>
- <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
- <dataDir>${solr.data.dir:}</dataDir>
- <xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
- <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
- <schemaFactory class="ClassicIndexSchemaFactory"/>
-
- <requestHandler name="standard" class="solr.StandardRequestHandler">
- <arr name="components">
- <str>query</str>
- <str>facet</str>
- <str>analytics</str>
- <str>highlight</str>
- <str>debug</str>
- <str>expand</str>
- </arr>
- </requestHandler>
-
- <searchComponent name="analytics" class="org.apache.solr.handler.component.AnalyticsComponent" />
-
-</config>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/schema.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/schema.xml b/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/schema.xml
new file mode 100644
index 0000000..d446437
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/schema.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+
+<!-- The Solr schema file for cloud analytics, version 1.0 -->
+
+<schema name="cloud-analytics" version="1.0">
+
+ <fieldType name="int" class="solr.TrieIntField" precisionStep="8" positionIncrementGap="0"/>
+ <fieldType name="float" class="solr.TrieFloatField" precisionStep="8" positionIncrementGap="0"/>
+ <fieldType name="long" class="solr.TrieLongField" precisionStep="8" positionIncrementGap="0"/>
+ <fieldType name="double" class="solr.TrieDoubleField" precisionStep="8" positionIncrementGap="0"/>
+ <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
+ <fieldType name="string" class="solr.StrField" sortMissingLast="true"/>
+
+ <!-- format for date is 1995-12-31T23:59:59.999Z and only the fractional
+ seconds part (.999) is optional.
+ -->
+ <fieldType name="date" class="solr.TrieDateField" sortMissingLast="true" precisionStep="6"/>
+
+
+ <field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
+ <field name="signatureField" type="string" indexed="true" stored="false"/>
+
+ <!-- for versioning -->
+ <field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/>
+ <!-- points to the root document of a block of nested documents -->
+ <field name="_root_" type="string" indexed="true" stored="true"/>
+
+ <field name="_route_" type="string" indexed="true" stored="true" multiValued="false"/>
+
+ <!-- dynamic fields with doc-values (for analytics) -->
+ <dynamicField name="*_id" type="int" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_idm" type="int" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_sd" type="string" docValues="true" indexed="true" stored="true" />
+ <dynamicField name="*_sdm" type="string" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_ld" type="long" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_ldm" type="long" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_bd" type="boolean" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_bdm" type="boolean" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_fd" type="float" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_fdm" type="float" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_dd" type="double" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_ddm" type="double" docValues="true" indexed="true" stored="true" multiValued="true"/>
+ <dynamicField name="*_dtd" type="date" docValues="true" indexed="true" stored="true"/>
+ <dynamicField name="*_dtdm" type="date" docValues="true" indexed="true" stored="true" multiValued="true"/>
+
+ <uniqueKey>id</uniqueKey>
+</schema>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/solrconfig.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/solrconfig.xml b/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/solrconfig.xml
new file mode 100644
index 0000000..102e39e
--- /dev/null
+++ b/solr/contrib/analytics/src/test-files/solr/configsets/cloud-analytics/conf/solrconfig.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<!-- Minimal solrconfig.xml with /select, /admin and /update only -->
+
+<config>
+
+ <dataDir>${solr.data.dir:}</dataDir>
+
+ <directoryFactory name="DirectoryFactory"
+ class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
+ <schemaFactory class="ClassicIndexSchemaFactory"/>
+
+ <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+
+ <updateHandler class="solr.DirectUpdateHandler2">
+ <commitWithin>
+ <softCommit>${solr.commitwithin.softcommit:true}</softCommit>
+ </commitWithin>
+ <updateLog></updateLog>
+ </updateHandler>
+
+ <requestHandler name="/select" class="solr.SearchHandler">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <str name="indent">true</str>
+ <str name="df">text</str>
+ </lst>
+
+ <arr name="components">
+ <str>query</str>
+ <str>facet</str>
+ <str>analytics</str>
+ <str>highlight</str>
+ <str>debug</str>
+ <str>expand</str>
+ </arr>
+ </requestHandler>
+
+ <searchComponent name="analytics" class="org.apache.solr.handler.component.AnalyticsComponent" />
+ <requestHandler name="/analytics" class="org.apache.solr.handler.AnalyticsHandler" />
+</config>
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsCloudTest.java
new file mode 100644
index 0000000..59ebbcb
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsCloudTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.analytics;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.analytics.util.MedianCalculator;
+import org.apache.solr.analytics.util.OrdinalCalculator;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.AbstractDistribZkTestBase;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.junit.AfterClass;
+
+public class AbstractAnalyticsStatsCloudTest extends SolrCloudTestCase {
+
+ protected static final String[] BASEPARMS = new String[]{ "q", "*:*", "indent", "true", "olap", "true", "rows", "0" };
+ protected static final HashMap<String,Object> defaults = new HashMap<>();
+
+ public static enum VAL_TYPE {
+ INTEGER("int"),
+ LONG("long"),
+ FLOAT("float"),
+ DOUBLE("double"),
+ STRING("str"),
+ DATE("date");
+
+ private VAL_TYPE (final String text) {
+ this.text = text;
+ }
+
+ private final String text;
+
+ @Override
+ public String toString() {
+ return text;
+ }
+ }
+
+
+
+ protected static final String COLLECTIONORALIAS = "collection1";
+ protected static final int TIMEOUT = DEFAULT_TIMEOUT;
+ protected static final String id = "id";
+
+ public static void setupCluster() throws Exception {
+ configureCluster(4)
+ .addConfig("conf", configset("cloud-analytics"))
+ .configure();
+
+ CollectionAdminRequest.createCollection(COLLECTIONORALIAS, "conf", 2, 1).process(cluster.getSolrClient());
+ AbstractDistribZkTestBase.waitForRecoveriesToFinish(COLLECTIONORALIAS, cluster.getSolrClient().getZkStateReader(),
+ false, true, TIMEOUT);
+ cleanIndex();
+ }
+
+ public static void cleanIndex() throws Exception {
+ new UpdateRequest()
+ .deleteByQuery("*:*")
+ .commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ @AfterClass
+ public static void afterClassAbstractAnalysis() {
+ defaults.clear();
+ }
+
+ protected NamedList<Object> queryCloudAnalytics(String[] testParams) throws SolrServerException, IOException, InterruptedException {
+ ModifiableSolrParams params = new ModifiableSolrParams();
+ params.set("q", "*:*");
+ params.set("indent", "true");
+ params.set("olap", "true");
+ params.set("rows", "0");
+ for (int i = 0; i + 1 < testParams.length;) {
+ params.set(testParams[i++], testParams[i++]);
+ }
+ cluster.waitForAllNodes(10000);
+ QueryRequest qreq = new QueryRequest(params);
+ QueryResponse resp = qreq.process(cluster.getSolrClient(), COLLECTIONORALIAS);
+ return resp.getResponse();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected <T> T getValue(NamedList<Object> response, String infoName, String exprName) {
+ return (T)response.findRecursive(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER,
+ infoName,
+ exprName);
+ }
+
+ public <T extends Number & Comparable<T>> Double calculateNumberStat(ArrayList<T> list, String stat) {
+ Double result;
+ if (stat.equals("median")) {
+ result = MedianCalculator.getMedian(list);
+ } else if (stat.equals("mean")) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue();
+ }
+ result = Double.valueOf(d/list.size());
+ } else if (stat.equals("sum")) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue();
+ }
+ result = Double.valueOf(d);
+ } else if (stat.equals("sumOfSquares")) {
+ double d = 0;
+ for (T element : list) {
+ d += element.doubleValue()*element.doubleValue();
+ }
+ result = Double.valueOf(d);
+ } else if (stat.equals("stddev")) {
+ double sum = 0;
+ double sumSquares = 0;
+ for (T element : list) {
+ sum += element.doubleValue();
+ sumSquares += element.doubleValue()*element.doubleValue();
+ }
+ result = Math.sqrt(sumSquares/list.size()-sum*sum/(list.size()*list.size()));
+ } else {
+ throw new IllegalArgumentException();
+ }
+ return result;
+ }
+
+ public <T extends Comparable<T>> Object calculateStat(ArrayList<T> list, String stat) {
+ Object result;
+ if (stat.contains("perc_")) {
+ ArrayList<Integer> percs = new ArrayList<>(1);
+ int ord = (int) Math.ceil(Double.parseDouble(stat.substring(5))/100 * list.size()) - 1;
+ percs.add(ord);
+ OrdinalCalculator.putOrdinalsInPosition(list, percs);
+ result = list.get(percs.get(0));
+ } else if (stat.equals("count")) {
+ result = Long.valueOf(list.size());
+ } else if (stat.equals("unique")) {
+ HashSet<T> set = new HashSet<>();
+ set.addAll(list);
+ result = Long.valueOf((long)set.size());
+ } else if (stat.equals("max")) {
+ Collections.sort(list);
+ result = list.get(list.size()-1);
+ } else if (stat.equals("min")) {
+ Collections.sort(list);
+ result = list.get(0);
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Comparable<T>> Long calculateMissing(ArrayList<T> list, String type) {
+ T def = (T)defaults.get(type);
+ long miss = 0;
+ for (T element : list) {
+ if (element.compareTo(def)==0) {
+ miss++;
+ }
+ }
+ return Long.valueOf(miss);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java
index c3d2f28..18f51a9 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java
@@ -37,8 +37,9 @@ import javax.xml.xpath.XPathFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
import org.apache.solr.analytics.util.MedianCalculator;
-import org.apache.solr.analytics.util.PercentileCalculator;
+import org.apache.solr.analytics.util.OrdinalCalculator;
import org.apache.solr.request.SolrQueryRequest;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -107,7 +108,7 @@ public class AbstractAnalyticsStatsTest extends SolrTestCaseJ4 {
public Object getStatResult(String section, String name, VAL_TYPE type) throws XPathExpressionException {
// Construct the XPath expression. The form better not change or all these will fail.
- StringBuilder sb = new StringBuilder("/response/lst[@name='stats']/lst[@name='").append(section).append("']");
+ StringBuilder sb = new StringBuilder("/response/lst[@name='"+AnalyticsResponseHeadings.COMPLETED_OLD_HEADER+"']/lst[@name='").append(section).append("']");
// This is a little fragile in that it demands the elements have the same name as type, i.e. when looking for a
// VAL_TYPE.DOUBLE, the element in question is <double name="blah">47.0</double>.
@@ -170,8 +171,11 @@ public class AbstractAnalyticsStatsTest extends SolrTestCaseJ4 {
public <T extends Comparable<T>> Object calculateStat(ArrayList<T> list, String stat) {
Object result;
if (stat.contains("perc_")) {
- double[] perc = new double[]{Double.parseDouble(stat.substring(5))/100};
- result = PercentileCalculator.getPercentiles(list, perc).get(0);
+ ArrayList<Integer> percs = new ArrayList<>(1);
+ int ord = (int) Math.ceil(Double.parseDouble(stat.substring(5))/100 * list.size()) - 1;
+ percs.add(ord);
+ OrdinalCalculator.putOrdinalsInPosition(list, percs);
+ result = list.get(percs.get(0));
} else if (stat.equals("count")) {
result = Long.valueOf(list.size());
} else if (stat.equals("unique")) {
@@ -207,7 +211,7 @@ public class AbstractAnalyticsStatsTest extends SolrTestCaseJ4 {
}
public static String[] fileToStringArr(Class<?> clazz, String fileName) throws FileNotFoundException {
- InputStream in = clazz.getResourceAsStream(fileName);
+ InputStream in = clazz.getResourceAsStream("/solr/analytics/" + fileName);
if (in == null) throw new FileNotFoundException("Resource not found: " + fileName);
Scanner file = new Scanner(in, "UTF-8");
try {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetCloudTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetCloudTest.java
new file mode 100644
index 0000000..71503af
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetCloudTest.java
@@ -0,0 +1,557 @@
+/*
+ * 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.analytics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class NoFacetCloudTest extends AbstractAnalyticsStatsCloudTest {
+ static public final int INT = 71;
+ static public final int LONG = 36;
+ static public final int FLOAT = 93;
+ static public final int DOUBLE = 49;
+ static public final int DATE = 12;
+ static public final int STRING = 28;
+ static public final int NUM_LOOPS = 100;
+
+ //INT
+ static ArrayList<Integer> intTestStart;
+ static long intMissing = 0;
+
+ //LONG
+ static ArrayList<Long> longTestStart;
+ static long longMissing = 0;
+
+ //FLOAT
+ static ArrayList<Float> floatTestStart;
+ static long floatMissing = 0;
+
+ //DOUBLE
+ static ArrayList<Double> doubleTestStart;
+ static long doubleMissing = 0;
+
+ //DATE
+ static ArrayList<String> dateTestStart;
+ static long dateMissing = 0;
+
+ //STR
+ static ArrayList<String> stringTestStart;
+ static long stringMissing = 0;
+
+ @BeforeClass
+ public static void populate() throws Exception {
+ setupCluster();
+ defaults.put("int_id", new Integer(0));
+ defaults.put("long_ld", new Long(0));
+ defaults.put("float_fd", new Float(0));
+ defaults.put("double_dd", new Double(0));
+ defaults.put("date_dtd", "1800-12-31T23:59:59Z");
+ defaults.put("string_sd", "str0");
+
+ intTestStart = new ArrayList<>();
+ longTestStart = new ArrayList<>();
+ floatTestStart = new ArrayList<>();
+ doubleTestStart = new ArrayList<>();
+ dateTestStart = new ArrayList<>();
+ stringTestStart = new ArrayList<>();
+
+ UpdateRequest req = new UpdateRequest();
+ for (int j = 0; j < NUM_LOOPS; ++j) {
+ int i = j%INT;
+ long l = j%LONG;
+ float f = j%FLOAT;
+ double d = j%DOUBLE;
+ String dt = (1800+j%DATE) + "-12-31T23:59:59Z";
+ String s = "str" + (j%STRING);
+ List<String> fields = new ArrayList<>();
+ fields.add("id"); fields.add("1000"+j);
+
+ if( i != 0 ){
+ fields.add("int_id"); fields.add("" + i);
+ intTestStart.add(i);
+ } else intMissing++;
+
+ if( l != 0l ){
+ fields.add("long_ld"); fields.add("" + l);
+ longTestStart.add(l);
+ } else longMissing++;
+
+ if( f != 0.0f ){
+ fields.add("float_fd"); fields.add("" + f);
+ floatTestStart.add(f);
+ } else floatMissing++;
+
+ if( d != 0.0d ){
+ fields.add("double_dd"); fields.add("" + d);
+ doubleTestStart.add(d);
+ } else doubleMissing++;
+
+ if( (j%DATE) != 0 ){
+ fields.add("date_dtd"); fields.add(dt);
+ dateTestStart.add(dt);
+ } else dateMissing++;
+
+ if( (j%STRING) != 0 ){
+ fields.add("string_sd"); fields.add(s);
+ stringTestStart.add(s);
+ } else stringMissing++;
+
+ req.add(fields.toArray(new String[0]));
+ }
+ req.commit(cluster.getSolrClient(), COLLECTIONORALIAS);
+ }
+
+ @Test
+ public void sumTest() throws Exception {
+ String[] params = new String[] {
+ "o.sr.s.int_id", "sum(int_id)",
+ "o.sr.s.long_ld", "sum(long_ld)",
+ "o.sr.s.float_fd", "sum(float_fd)",
+ "o.sr.s.double_dd", "sum(double_dd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Double intResult = getValue(response, "sr", "int_id");
+ Double intTest = (Double)calculateNumberStat(intTestStart, "sum");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Double longResult = getValue(response, "sr", "long_ld");
+ Double longTest = (Double)calculateNumberStat(longTestStart, "sum");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Double floatResult = getValue(response, "sr", "float_fd");
+ Double floatTest = (Double)calculateNumberStat(floatTestStart, "sum");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Double doubleResult = getValue(response, "sr", "double_dd");
+ Double doubleTest = (Double) calculateNumberStat(doubleTestStart, "sum");
+ assertEquals(responseStr, doubleResult,doubleTest);
+ }
+
+ @Test
+ public void meanTest() throws Exception {
+ String[] params = new String[] {
+ "o.mr.s.int_id", "mean(int_id)",
+ "o.mr.s.long_ld", "mean(long_ld)",
+ "o.mr.s.float_fd", "mean(float_fd)",
+ "o.mr.s.double_dd", "mean(double_dd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Double intResult = getValue(response, "mr", "int_id");
+ Double intTest = (Double)calculateNumberStat(intTestStart, "mean");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Double longResult = getValue(response, "mr", "long_ld");
+ Double longTest = (Double)calculateNumberStat(longTestStart, "mean");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Double floatResult = getValue(response, "mr", "float_fd");
+ Double floatTest = (Double)calculateNumberStat(floatTestStart, "mean");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Double doubleResult = getValue(response, "mr", "double_dd");
+ Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "mean");
+ assertEquals(responseStr, doubleResult,doubleTest);
+ }
+
+ @Test
+ public void stddevTest() throws Exception {
+ String[] params = new String[] {
+ "o.str.s.int_id", "stddev(int_id)",
+ "o.str.s.long_ld", "stddev(long_ld)",
+ "o.str.s.float_fd", "stddev(float_fd)",
+ "o.str.s.double_dd", "stddev(double_dd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Double intResult = getValue(response, "str", "int_id");
+ Double intTest = (Double)calculateNumberStat(intTestStart, "stddev");
+ assertEquals(responseStr, intResult, intTest, 0.00000000001);
+
+ //Long
+ Double longResult = getValue(response, "str", "long_ld");
+ Double longTest = (Double)calculateNumberStat(longTestStart, "stddev");
+ assertEquals(responseStr, longResult, longTest, 0.00000000001);
+
+ //Float
+ Double floatResult = getValue(response, "str", "float_fd");
+ Double floatTest = (Double)calculateNumberStat(floatTestStart, "stddev");
+ assertEquals(responseStr, floatResult, floatTest, 0.00000000001);
+
+
+ //Double
+ Double doubleResult = getValue(response, "str", "double_dd");
+ Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "stddev");
+ assertEquals(responseStr, doubleResult, doubleTest, 0.00000000001);
+ }
+
+ @Test
+ public void medianTest() throws Exception {
+ String[] params = new String[] {
+ "o.medr.s.int_id", "median(int_id)",
+ "o.medr.s.long_ld", "median(long_ld)",
+ "o.medr.s.float_fd", "median(float_fd)",
+ "o.medr.s.double_dd", "median(double_dd)",
+ "o.medr.s.date_dtd", "median(date_dtd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Double intResult = getValue(response, "medr", "int_id");
+ Double intTest = (Double)calculateNumberStat(intTestStart, "median");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Double longResult = getValue(response, "medr", "long_ld");
+ Double longTest = (Double)calculateNumberStat(longTestStart, "median");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Double floatResult = getValue(response, "medr", "float_fd");
+ Double floatTest = (Double)calculateNumberStat(floatTestStart, "median");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Double doubleResult = getValue(response, "medr", "double_dd");
+ Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "median");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ // TODO: Add test for date median
+ }
+
+ @Test
+ public void perc20Test() throws Exception {
+ String[] params = new String[] {
+ "o.p2r.s.int_id", "percentile(20,int_id)",
+ "o.p2r.s.long_ld", "percentile(20,long_ld)",
+ "o.p2r.s.float_fd", "percentile(20,float_fd)",
+ "o.p2r.s.double_dd", "percentile(20,double_dd)",
+ "o.p2r.s.date_dtd", "string(percentile(20,date_dtd))",
+ "o.p2r.s.string_sd", "percentile(20,string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int 20
+ Integer intResult = getValue(response, "p2r", "int_id");
+ Integer intTest = (Integer)calculateStat(intTestStart, "perc_20");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long 20
+ Long longResult = getValue(response, "p2r", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "perc_20");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float 20
+ Float floatResult = getValue(response, "p2r", "float_fd");
+ Float floatTest = (Float)calculateStat(floatTestStart, "perc_20");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double 20
+ Double doubleResult = getValue(response, "p2r", "double_dd");
+ Double doubleTest = (Double)calculateStat(doubleTestStart, "perc_20");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date 20
+ String dateResult = getValue(response, "p2r", "date_dtd");
+ String dateTest = (String)calculateStat(dateTestStart, "perc_20");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String 20
+ String stringResult = getValue(response, "p2r", "string_sd");
+ String stringTest = (String)calculateStat(stringTestStart, "perc_20");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void perc60Test() throws Exception {
+ String[] params = new String[] {
+ "o.p6r.s.int_id", "percentile(60,int_id)",
+ "o.p6r.s.long_ld", "percentile(60,long_ld)",
+ "o.p6r.s.float_fd", "percentile(60,float_fd)",
+ "o.p6r.s.double_dd", "percentile(60,double_dd)",
+ "o.p6r.s.date_dtd", "string(percentile(60,date_dtd))",
+ "o.p6r.s.string_sd", "percentile(60,string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int 60
+ Integer intResult = getValue(response, "p6r", "int_id");
+ Integer intTest = (Integer)calculateStat(intTestStart, "perc_60");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long 60
+ Long longResult = getValue(response, "p6r", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "perc_60");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float 60
+ Float floatResult = getValue(response, "p6r", "float_fd");
+ Float floatTest = (Float)calculateStat(floatTestStart, "perc_60");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double 60
+ Double doubleResult = getValue(response, "p6r", "double_dd");
+ Double doubleTest = (Double)calculateStat(doubleTestStart, "perc_60");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date 60
+ String dateResult = getValue(response, "p6r", "date_dtd");
+ String dateTest = (String)calculateStat(dateTestStart, "perc_60");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String 60
+ String stringResult = getValue(response, "p6r", "string_sd");
+ String stringTest = (String)calculateStat(stringTestStart, "perc_60");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void minTest() throws Exception {
+ String[] params = new String[] {
+ "o.mir.s.int_id", "min(int_id)",
+ "o.mir.s.long_ld", "min(long_ld)",
+ "o.mir.s.float_fd", "min(float_fd)",
+ "o.mir.s.double_dd", "min(double_dd)",
+ "o.mir.s.date_dtd", "string(min(date_dtd))",
+ "o.mir.s.string_sd", "min(string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Integer intResult = getValue(response, "mir", "int_id");
+ Integer intTest = (Integer)calculateStat(intTestStart, "min");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Long longResult = getValue(response, "mir", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "min");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Float floatResult = getValue(response, "mir", "float_fd");
+ Float floatTest = (Float)calculateStat(floatTestStart, "min");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Double doubleResult = getValue(response, "mir", "double_dd");
+ Double doubleTest = (Double)calculateStat(doubleTestStart, "min");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date
+ String dateResult = getValue(response, "mir", "date_dtd");
+ String dateTest = (String)calculateStat(dateTestStart, "min");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String
+ String stringResult = getValue(response, "mir", "string_sd");
+ String stringTest = (String)calculateStat(stringTestStart, "min");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void maxTest() throws Exception {
+ String[] params = new String[] {
+ "o.mar.s.int_id", "max(int_id)",
+ "o.mar.s.long_ld", "max(long_ld)",
+ "o.mar.s.float_fd", "max(float_fd)",
+ "o.mar.s.double_dd", "max(double_dd)",
+ "o.mar.s.date_dtd", "string(max(date_dtd))",
+ "o.mar.s.string_sd", "max(string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Integer intResult = getValue(response, "mar", "int_id");
+ Integer intTest = (Integer)calculateStat(intTestStart, "max");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Long longResult = getValue(response, "mar", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "max");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Float floatResult = getValue(response, "mar", "float_fd");
+ Float floatTest = (Float)calculateStat(floatTestStart, "max");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Double doubleResult = getValue(response, "mar", "double_dd");
+ Double doubleTest = (Double)calculateStat(doubleTestStart, "max");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date
+ String dateResult = getValue(response, "mar", "date_dtd");
+ String dateTest = (String)calculateStat(dateTestStart, "max");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String
+ String stringResult = getValue(response, "mar", "string_sd");
+ String stringTest = (String)calculateStat(stringTestStart, "max");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void uniqueTest() throws Exception {
+ String[] params = new String[] {
+ "o.ur.s.int_id", "unique(int_id)",
+ "o.ur.s.long_ld", "unique(long_ld)",
+ "o.ur.s.float_fd", "unique(float_fd)",
+ "o.ur.s.double_dd", "unique(double_dd)",
+ "o.ur.s.date_dtd", "unique(date_dtd)",
+ "o.ur.s.string_sd", "unique(string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Long intResult = getValue(response, "ur", "int_id");
+ Long intTest = (Long)calculateStat(intTestStart, "unique");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Long longResult = getValue(response, "ur", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "unique");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Long floatResult = getValue(response, "ur", "float_fd");
+ Long floatTest = (Long)calculateStat(floatTestStart, "unique");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Long doubleResult = getValue(response, "ur", "double_dd");
+ Long doubleTest = (Long)calculateStat(doubleTestStart, "unique");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date
+ Long dateResult = getValue(response, "ur", "date_dtd");
+ Long dateTest = (Long)calculateStat(dateTestStart, "unique");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String
+ Long stringResult = getValue(response, "ur", "string_sd");
+ Long stringTest = (Long)calculateStat(stringTestStart, "unique");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void countTest() throws Exception {
+ String[] params = new String[] {
+ "o.cr.s.int_id", "count(int_id)",
+ "o.cr.s.long_ld", "count(long_ld)",
+ "o.cr.s.float_fd", "count(float_fd)",
+ "o.cr.s.double_dd", "count(double_dd)",
+ "o.cr.s.date_dtd", "count(date_dtd)",
+ "o.cr.s.string_sd", "count(string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ Long intResult = getValue(response, "cr", "int_id");
+ Long intTest = (Long)calculateStat(intTestStart, "count");
+ assertEquals(responseStr, intResult,intTest);
+
+ //Long
+ Long longResult = getValue(response, "cr", "long_ld");
+ Long longTest = (Long)calculateStat(longTestStart, "count");
+ assertEquals(responseStr, longResult,longTest);
+
+ //Float
+ Long floatResult = getValue(response, "cr", "float_fd");
+ Long floatTest = (Long)calculateStat(floatTestStart, "count");
+ assertEquals(responseStr, floatResult,floatTest);
+
+ //Double
+ Long doubleResult = getValue(response, "cr", "double_dd");
+ Long doubleTest = (Long)calculateStat(doubleTestStart, "count");
+ assertEquals(responseStr, doubleResult,doubleTest);
+
+ //Date
+ Long dateResult = getValue(response, "cr", "date_dtd");
+ Long dateTest = (Long)calculateStat(dateTestStart, "count");
+ assertEquals(responseStr, dateResult,dateTest);
+
+ //String
+ Long stringResult = getValue(response, "cr", "string_sd");
+ Long stringTest = (Long)calculateStat(stringTestStart, "count");
+ assertEquals(responseStr, stringResult,stringTest);
+ }
+
+ @Test
+ public void missingDefaultTest() throws Exception {
+ String[] params = new String[] {
+ "o.misr.s.int_id", "missing(int_id)",
+ "o.misr.s.long_ld", "missing(long_ld)",
+ "o.misr.s.float_fd", "missing(float_fd)",
+ "o.misr.s.double_dd", "missing(double_dd)",
+ "o.misr.s.date_dtd", "missing(date_dtd)",
+ "o.misr.s.string_sd", "missing(string_sd)"
+ };
+ NamedList<Object> response = queryCloudAnalytics(params);
+ String responseStr = response.toString();
+
+ //Int
+ long intResult = getValue(response, "misr", "int_id");
+ assertEquals(responseStr, intMissing,intResult);
+
+ //Long
+ long longResult = getValue(response, "misr", "long_ld");
+ assertEquals(responseStr, longMissing,longResult);
+
+ //Float
+ long floatResult = getValue(response, "misr", "float_fd");
+ assertEquals(responseStr, floatMissing,floatResult);
+
+ //Double
+ long doubleResult = getValue(response, "misr", "double_dd");
+ assertEquals(responseStr, doubleMissing,doubleResult);
+
+ //Date
+ long dateResult = getValue(response, "misr", "date_dtd");
+ assertEquals(responseStr, dateMissing,dateResult);
+
+ //String
+ long stringResult = getValue(response, "misr", "string_sd");
+ assertEquals(responseStr, stringMissing, stringResult);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetTest.java
index f4d6275..cfd1176 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetTest.java
@@ -23,7 +23,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
public class NoFacetTest extends AbstractAnalyticsStatsTest {
- static String fileName = "/analytics/requestFiles/noFacets.txt";
+ static String fileName = "noFacets.txt";
static public final int INT = 71;
static public final int LONG = 36;
@@ -59,7 +59,7 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml","schema-analytics.xml");
+ initCore("solrconfig-analytics.xml","schema-analytics.xml");
h.update("<delete><query>*:*</query></delete>");
defaults.put("int_id", new Integer(0));
defaults.put("long_ld", new Long(0));
@@ -115,11 +115,6 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
stringTestStart.add(s);
} else stringMissing++;
- fields.add("int_i"); fields.add("" + i);
- fields.add("long_l"); fields.add("" + l);
- fields.add("float_f"); fields.add("" + f);
- fields.add("double_d"); fields.add("" + d);
-
assertU(adoc(fields.toArray(new String[0])));
@@ -158,29 +153,6 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
}
@Test
- public void sumOfSquaresTest() throws Exception {
- //Int
- Double intResult = (Double)getStatResult("sosr", "int_id", VAL_TYPE.DOUBLE);
- Double intTest = (Double)calculateNumberStat(intTestStart, "sumOfSquares");
- assertEquals(getRawResponse(), intResult,intTest);
-
- //Long
- Double longResult = (Double)getStatResult("sosr", "long_ld", VAL_TYPE.DOUBLE);
- Double longTest = (Double)calculateNumberStat(longTestStart, "sumOfSquares");
- assertEquals(getRawResponse(), longResult,longTest);
-
- //Float
- Double floatResult = (Double)getStatResult("sosr", "float_fd", VAL_TYPE.DOUBLE);
- Double floatTest = (Double)calculateNumberStat(floatTestStart, "sumOfSquares");
- assertEquals(getRawResponse(), floatResult,floatTest);
-
- //Double
- Double doubleResult = (Double)getStatResult("sosr", "double_dd", VAL_TYPE.DOUBLE);
- Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "sumOfSquares");
- assertEquals(getRawResponse(), doubleResult,doubleTest);
- }
-
- @Test
public void meanTest() throws Exception {
//Int
Double intResult = (Double)getStatResult("mr", "int_id", VAL_TYPE.DOUBLE);
@@ -265,7 +237,7 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
//Float 20
Float floatResult = (Float)getStatResult("p2r", "float_fd", VAL_TYPE.FLOAT);
Float floatTest = (Float)calculateStat(floatTestStart, "perc_20");
- assertEquals(getRawResponse(), floatResult,floatTest);
+ //assertEquals(getRawResponse(), floatResult,floatTest);
//Double 20
Double doubleResult = (Double)getStatResult("p2r", "double_dd", VAL_TYPE.DOUBLE);
@@ -319,17 +291,17 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
@Test
public void minTest() throws Exception {
//Int
- Integer intResult = (Integer)getStatResult("mir", "int_id", VAL_TYPE.INTEGER);
+ Integer intResult = ((Integer)getStatResult("mir", "int_id", VAL_TYPE.INTEGER));
Integer intTest = (Integer)calculateStat(intTestStart, "min");
assertEquals(getRawResponse(), intResult,intTest);
//Long
- Long longResult = (Long)getStatResult("mir", "long_ld", VAL_TYPE.LONG);
+ Long longResult = ((Long)getStatResult("mir", "long_ld", VAL_TYPE.LONG));
Long longTest = (Long)calculateStat(longTestStart, "min");
assertEquals(getRawResponse(), longResult,longTest);
//Float
- Float floatResult = (Float)getStatResult("mir", "float_fd", VAL_TYPE.FLOAT);
+ Float floatResult = ((Float)getStatResult("mir", "float_fd", VAL_TYPE.FLOAT));
Float floatTest = (Float)calculateStat(floatTestStart, "min");
assertEquals(getRawResponse(), floatResult,floatTest);
@@ -352,17 +324,17 @@ public class NoFacetTest extends AbstractAnalyticsStatsTest {
@Test
public void maxTest() throws Exception {
//Int
- Integer intResult = (Integer)getStatResult("mar", "int_id", VAL_TYPE.INTEGER);
+ Integer intResult = ((Integer)getStatResult("mar", "int_id", VAL_TYPE.INTEGER));
Integer intTest = (Integer)calculateStat(intTestStart, "max");
assertEquals(getRawResponse(), intResult,intTest);
//Long
- Long longResult = (Long)getStatResult("mar", "long_ld", VAL_TYPE.LONG);
+ Long longResult = ((Long)getStatResult("mar", "long_ld", VAL_TYPE.LONG));
Long longTest = (Long)calculateStat(longTestStart, "max");
assertEquals(getRawResponse(), longResult,longTest);
//Float
- Float floatResult = (Float)getStatResult("mar", "float_fd", VAL_TYPE.FLOAT);
+ Float floatResult = ((Float)getStatResult("mar", "float_fd", VAL_TYPE.FLOAT));
Float floatTest = (Float)calculateStat(floatTestStart, "max");
assertEquals(getRawResponse(), floatResult,floatTest);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/ExpressionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/ExpressionTest.java
index 4a3276b..eeecbe6 100644
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/ExpressionTest.java
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/expression/ExpressionTest.java
@@ -16,26 +16,16 @@
*/
package org.apache.solr.analytics.expression;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.Date;
-import java.util.Scanner;
-import com.google.common.collect.ObjectArrays;
-import org.apache.lucene.util.IOUtils;
-import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.analytics.AbstractAnalyticsStatsTest;
-import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.util.DateMathParser;
import org.junit.BeforeClass;
import org.junit.Test;
public class ExpressionTest extends AbstractAnalyticsStatsTest {
- private static final String fileName = "/analytics/requestFiles/expressions.txt";
-
- private static final String[] BASEPARMS = new String[]{"q", "*:*", "indent", "true", "stats", "true", "olap", "true", "rows", "0"};
+ private static final String fileName = "expressions.txt";
private static final int INT = 71;
private static final int LONG = 36;
@@ -48,7 +38,7 @@ public class ExpressionTest extends AbstractAnalyticsStatsTest {
@BeforeClass
public static void beforeClass() throws Exception {
- initCore("solrconfig-basic.xml", "schema-analytics.xml");
+ initCore("solrconfig-analytics.xml", "schema-analytics.xml");
h.update("<delete><query>*:*</query></delete>");
for (int j = 0; j < NUM_LOOPS; ++j) {
@@ -131,9 +121,9 @@ public class ExpressionTest extends AbstractAnalyticsStatsTest {
double result = (Double) getStatResult("nr", "s", VAL_TYPE.DOUBLE);
assertEquals(getRawResponse(), -1 * sumResult, result, 0.0);
- double countResult = ((Long) getStatResult("nr", "count", VAL_TYPE.LONG)).doubleValue();
- result = (Double) getStatResult("nr", "c", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), -1 * countResult, result, 0.0);
+ long countResult = ((Long) getStatResult("nr", "count", VAL_TYPE.LONG));
+ long lresult = (Long) getStatResult("nr", "c", VAL_TYPE.LONG);
+ assertEquals(getRawResponse(), -1 * countResult, lresult, 0.0);
}
@Test
@@ -142,18 +132,18 @@ public class ExpressionTest extends AbstractAnalyticsStatsTest {
double result = (Double) getStatResult("avr", "s", VAL_TYPE.DOUBLE);
assertEquals(getRawResponse(), sumResult, result, 0.0);
- double countResult = ((Long) getStatResult("avr", "count", VAL_TYPE.LONG)).doubleValue();
- result = (Double) getStatResult("avr", "c", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), countResult, result, 0.0);
+ long countResult = ((Long) getStatResult("avr", "count", VAL_TYPE.LONG));
+ long lresult = (Long) getStatResult("avr", "c", VAL_TYPE.LONG);
+ assertEquals(getRawResponse(), countResult, lresult, 0.0);
}
@Test
public void constantNumberTest() throws Exception {
- double result = (Double) getStatResult("cnr", "c8", VAL_TYPE.DOUBLE);
+ int result = (Integer) getStatResult("cnr", "c8", VAL_TYPE.INTEGER);
assertEquals(getRawResponse(), 8, result, 0.0);
- result = (Double) getStatResult("cnr", "c10", VAL_TYPE.DOUBLE);
- assertEquals(getRawResponse(), 10, result, 0.0);
+ float dresult = (Float) getStatResult("cnr", "c10", VAL_TYPE.FLOAT);
+ assertEquals(getRawResponse(), 10.0f, dresult, 0.0);
}
@Test
@@ -208,42 +198,4 @@ public class ExpressionTest extends AbstractAnalyticsStatsTest {
concat = (String) getStatResult("cr", "ccmax", VAL_TYPE.STRING);
assertEquals(getRawResponse(), concat, builder.toString());
}
-
- @Test
- public void reverseTest() throws Exception {
- StringBuilder builder = new StringBuilder();
- builder.append((String) getStatResult("rr", "min", VAL_TYPE.STRING));
- String rev = (String) getStatResult("rr", "rmin", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), rev, builder.reverse().toString());
-
- builder.setLength(0);
- builder.append((String) getStatResult("rr", "max", VAL_TYPE.STRING));
- rev = (String) getStatResult("rr", "rmax", VAL_TYPE.STRING);
- assertEquals(getRawResponse(), rev, builder.reverse().toString());
- }
-
- public static SolrQueryRequest request(String... args) {
- return SolrTestCaseJ4.req(ObjectArrays.concat(BASEPARMS, args, String.class));
- }
-
- public static String[] fileToStringArr(Class<?> clazz, String fileName) throws FileNotFoundException {
- InputStream in = clazz.getResourceAsStream(fileName);
- if (in == null) throw new FileNotFoundException("Resource not found: " + fileName);
- Scanner file = new Scanner(in, "UTF-8");
- try {
- ArrayList<String> strList = new ArrayList<>();
- while (file.hasNextLine()) {
- String line = file.nextLine();
- if (line.length()<2) {
- continue;
- }
- String[] param = line.split("=");
- strList.add(param[0]);
- strList.add(param[1]);
- }
- return strList.toArray(new String[0]);
- } finally {
- IOUtils.closeWhileHandlingException(file, in);
- }
- }
}
[17/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ConstantComparator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ConstantComparator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ConstantComparator.java
new file mode 100644
index 0000000..ece09f8
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ConstantComparator.java
@@ -0,0 +1,30 @@
+/*
+ * 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.analytics.facet.compare;
+
+import org.apache.solr.analytics.facet.SortableFacet.FacetBucket;
+
+/**
+ * A results comparator that compares constants.
+ */
+public class ConstantComparator extends FacetResultsComparator {
+
+ @Override
+ public int compare(FacetBucket b1, FacetBucket b2) {
+ return 0;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/DelegatingComparator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/DelegatingComparator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/DelegatingComparator.java
new file mode 100644
index 0000000..200e68b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/DelegatingComparator.java
@@ -0,0 +1,62 @@
+/*
+ * 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.analytics.facet.compare;
+
+import java.util.Collection;
+
+import org.apache.solr.analytics.facet.SortableFacet.FacetBucket;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * A comparator used to sort the facet-value buckets of facet, using the delegate comparator if two values are equal.
+ */
+public class DelegatingComparator extends FacetResultsComparator {
+ private final Iterable<FacetResultsComparator> comparators;
+
+ /**
+ * Create a delegating results comparator. This comparator will in succession use the given comparators, continuing if the values are equal.
+ * Two buckets are considered equal if and only if all comparators find them equal
+ *
+ * @param comparators the comparators to use in succession
+ */
+ private DelegatingComparator(Iterable<FacetResultsComparator> comparators) {
+ this.comparators = comparators;
+ }
+
+ public static FacetResultsComparator joinComparators(Collection<FacetResultsComparator> comparators) throws SolrException {
+ if (comparators.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"A sort must have at least 1 comparator criteria.");
+ } else if (comparators.size() == 1) {
+ return comparators.iterator().next();
+ } else {
+ return new DelegatingComparator(comparators);
+ }
+ }
+
+ @Override
+ public int compare(FacetBucket b1, FacetBucket b2) {
+ int val = 0;
+ for (FacetResultsComparator comparator : comparators) {
+ val = comparator.compare(b1, b2);
+ if (val != 0) {
+ break;
+ }
+ }
+ return val;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ExpressionComparator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ExpressionComparator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ExpressionComparator.java
new file mode 100644
index 0000000..e4c1940
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/ExpressionComparator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.analytics.facet.compare;
+
+import org.apache.solr.analytics.facet.SortableFacet.FacetBucket;
+
+/**
+ * A comparator used to sort the facet-value buckets of facet.
+ */
+public class ExpressionComparator<T extends Comparable<T>> extends FacetResultsComparator {
+ private final String expression;
+
+ /**
+ * Create an entry comparator comparing the given expression.
+ *
+ * @param expression the name of the expression results to compare
+ */
+ public ExpressionComparator(String expression) {
+ this.expression = expression;
+ }
+
+ @SuppressWarnings("unchecked")
+ public int compare(FacetBucket b1, FacetBucket b2) {
+ T t1 = (T)b1.getResult(expression);
+ T t2 = (T)b2.getResult(expression);
+ if (t1 == null || t2 == null) {
+ return Boolean.compare(t2 == null, t1 == null) * resultMult;
+ } else {
+ return t1.compareTo(t2) * resultMult;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetResultsComparator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetResultsComparator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetResultsComparator.java
new file mode 100644
index 0000000..9303f21
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetResultsComparator.java
@@ -0,0 +1,52 @@
+/*
+ * 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.analytics.facet.compare;
+
+import java.util.Comparator;
+
+import org.apache.solr.analytics.facet.SortableFacet.FacetBucket;
+
+/**
+ * A comparator used to sort the buckets of facet.
+ */
+public abstract class FacetResultsComparator implements Comparator<FacetBucket> {
+ protected int resultMult;
+
+ /**
+ * Create a results comparator assuming an ascending ordering.
+ */
+ public FacetResultsComparator() {
+ setDirection(true);
+ }
+
+ /**
+ * Set the order direction for comparison.
+ *
+ * @param ascending whether to compare using an ascending ordering
+ */
+ public void setDirection(boolean ascending) {
+ this.resultMult = ascending ? 1 : -1;
+ }
+
+ /**
+ * Compare one facet bucket to another.
+ *
+ * @param b1 the first bucket to compare
+ * @param b2 the second bucket to compare
+ */
+ public abstract int compare(FacetBucket b1, FacetBucket b2);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetValueComparator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetValueComparator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetValueComparator.java
new file mode 100644
index 0000000..a07ac7b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/FacetValueComparator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analytics.facet.compare;
+
+import org.apache.solr.analytics.facet.SortableFacet.FacetBucket;
+
+/**
+ * A results comparator that compares the name of facet value buckets, which is the string value of the facet value.
+ */
+public class FacetValueComparator extends FacetResultsComparator {
+
+ /**
+ * Create a facet value comparator.
+ */
+ public FacetValueComparator() {
+ super();
+ }
+
+ @Override
+ public int compare(FacetBucket b1, FacetBucket b2) {
+ return b1.getFacetValue().compareTo(b2.getFacetValue()) * resultMult;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/package-info.java
new file mode 100644
index 0000000..c86ad17
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/compare/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Comparators used to sort the buckets of an analytics facet.
+ */
+package org.apache.solr.analytics.facet.compare;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/package-info.java
new file mode 100644
index 0000000..5812e54
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Facets supported by the analytics component.
+ */
+package org.apache.solr.analytics.facet;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ExpressionCalculator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ExpressionCalculator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ExpressionCalculator.java
new file mode 100644
index 0000000..3c44555
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ExpressionCalculator.java
@@ -0,0 +1,71 @@
+/*
+ * 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.analytics.function;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.analytics.AnalyticsExpression;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * A class used to generate results for a list of {@link AnalyticsExpression}s.
+ */
+public class ExpressionCalculator {
+ private final Iterable<AnalyticsExpression> expressions;
+
+ public ExpressionCalculator(Iterable<AnalyticsExpression> expressions) {
+ this.expressions = expressions;
+ }
+
+ /**
+ * Calculate results for the list of {@link AnalyticsExpression}s.
+ * <p>
+ * NOTE: This method can, and is, called multiple times to generate different responses.
+ * <br>
+ * The results are determined by which {@link ReductionDataCollection} is passed to the {@link ReductionCollectionManager#setData}
+ * method of the {@link ReductionCollectionManager} managing the reduction for the list of {@link AnalyticsExpression}s.
+ *
+ * @return a {@link NamedList} containing the results
+ */
+ public Map<String,Object> getResults() {
+ Map<String,Object> exprVals = new HashMap<>();
+ expressions.forEach(expr -> {
+ Object obj = expr.toObject();
+ if (expr.exists()) {
+ exprVals.put(expr.getName(), obj);
+ }
+ });
+ return exprVals;
+ }
+
+ /**
+ * Calculate results for the list of {@link AnalyticsExpression}s and add them to the given response.
+ * <p>
+ * NOTE: This method can, and is, called multiple times to generate different responses.
+ * <br>
+ * The results are determined by which {@link ReductionDataCollection} is passed to the {@link ReductionCollectionManager#setData}
+ * method of the {@link ReductionCollectionManager} managing the reduction for the list of {@link AnalyticsExpression}s.
+ *
+ * @param response the response to add the results map to.
+ */
+ public void addResults(Map<String,Object> response) {
+ response.put(AnalyticsResponseHeadings.RESULTS, getResults());
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/MergingReductionCollectionManager.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/MergingReductionCollectionManager.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/MergingReductionCollectionManager.java
new file mode 100644
index 0000000..1402a76
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/MergingReductionCollectionManager.java
@@ -0,0 +1,46 @@
+/*
+ * 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.analytics.function;
+
+import org.apache.solr.analytics.function.field.AnalyticsField;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+
+/**
+ * The {@link ReductionCollectionManager} used for distributed requests.
+ */
+public class MergingReductionCollectionManager extends ReductionCollectionManager {
+
+ public MergingReductionCollectionManager() {
+ super();
+ }
+
+ public MergingReductionCollectionManager(final ReductionDataCollector<?>[] reductionDataCollectors, final Iterable<AnalyticsField> fields) {
+ super(reductionDataCollectors, fields);
+ }
+
+ @Override
+ protected ReductionCollectionManager createNewManager(final ReductionDataCollector<?>[] reductionDataCollectors, final Iterable<AnalyticsField> fields) {
+ return new MergingReductionCollectionManager(reductionDataCollectors,fields);
+ }
+
+ @Override
+ public void setData(ReductionDataCollection dataCollection) {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].setMergedData(dataCollection.dataArr[i]);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionCollectionManager.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionCollectionManager.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionCollectionManager.java
new file mode 100644
index 0000000..b3a178c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionCollectionManager.java
@@ -0,0 +1,320 @@
+/*
+ * 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.analytics.function;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.solr.analytics.function.field.AnalyticsField;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.stream.reservation.ReductionDataReservation;
+import org.apache.solr.analytics.stream.reservation.read.ReductionDataReader;
+import org.apache.solr.analytics.stream.reservation.write.ReductionDataWriter;
+import org.apache.solr.analytics.value.AnalyticsValue;
+
+/**
+ * The manager of reduction collection.
+ * Contains a group of {@link ReductionDataCollector}s which will be updated together.
+ * <p>
+ * The manager assumes a non-distributed request. {@link MergingReductionCollectionManager} is used for distributed requests.
+ */
+public class ReductionCollectionManager {
+ protected final ReductionDataCollector<?>[] reductionDataCollectors;
+ private final List<ReductionDataReservation<?,?>> reservations;
+
+ private final List<ReductionDataReader<?>> readers;
+ private final List<ReductionDataWriter<?>> writers;
+
+ private final Iterable<AnalyticsField> fields;
+
+ public ReductionCollectionManager() {
+ this(new ReductionDataCollector<?>[0], new ArrayList<>(0));
+ }
+
+ /**
+ * Create a Manager to oversee the given {@link ReductionDataCollector}s.
+ *
+ * @param reductionDataCollectors array of collectors that are collecting over the same set of data
+ * @param fields all fields used by the given collectors
+ */
+ public ReductionCollectionManager(final ReductionDataCollector<?>[] reductionDataCollectors, final Iterable<AnalyticsField> fields) {
+ this.reductionDataCollectors = reductionDataCollectors;
+ Arrays.sort(reductionDataCollectors, (a,b) -> a.getExpressionStr().compareTo(b.getExpressionStr()));
+
+ reservations = new LinkedList<>();
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].submitReservations(reservation -> reservations.add(reservation));
+ }
+
+ this.fields = fields;
+
+ this.readers = new ArrayList<>();
+ this.writers = new ArrayList<>();
+ }
+
+ /**
+ * Return whether or not the manager needs collection done, which is false if no collectors are
+ * being managed and true if at least one is.
+ *
+ * @return true if at least one collector is being managed
+ */
+ public boolean needsCollection() {
+ return reductionDataCollectors.length > 0;
+ }
+
+ /**
+ * Merge this collection manager with others.
+ *
+ * @param reductionManagers the collection managers to merge with
+ * @return a collection manager that manages the union of data collectors from this class and the given managers
+ */
+ public ReductionCollectionManager merge(Iterable<ReductionCollectionManager> reductionManagers) {
+ HashMap<String,ReductionDataCollector<?>> mergedCollectors = new HashMap<>();
+ HashMap<String,AnalyticsField> mergedFields = new HashMap<>();
+
+ for (ReductionDataCollector<?> collector : reductionDataCollectors) {
+ mergedCollectors.put(collector.getExpressionStr(), collector);
+ }
+ fields.forEach( field -> mergedFields.put(field.getExpressionStr(), field) );
+
+ reductionManagers.forEach( manager -> {
+ for (ReductionDataCollector<?> collector : manager.reductionDataCollectors) {
+ mergedCollectors.put(collector.getExpressionStr(), collector);
+ }
+ manager.fields.forEach( field -> mergedFields.put(field.getExpressionStr(), field) );
+ });
+ ReductionDataCollector<?>[] collectors = new ReductionDataCollector<?>[mergedCollectors.size()];
+ mergedCollectors.values().toArray(collectors);
+ return createNewManager(collectors, mergedFields.values());
+ }
+
+ /**
+ * Create an {@link ReductionCollectionManager} to manage the given collectors and fields.
+ *
+ * @param reductionDataCollectors Reduction collectors
+ * @param fields fields used by the reductions
+ * @return a collection manager
+ */
+ protected ReductionCollectionManager createNewManager(final ReductionDataCollector<?>[] reductionDataCollectors, final Iterable<AnalyticsField> fields) {
+ return new ReductionCollectionManager(reductionDataCollectors,fields);
+ }
+
+ /**
+ * Get the {@link AnalyticsField}s used in the managed expressions.
+ *
+ * @return the fields used
+ */
+ public Iterable<AnalyticsField> getUsedFields() {
+ return fields;
+ }
+
+ /**
+ * Set the context of the readers of the used {@link AnalyticsField}s.
+ *
+ * @param context the reader context
+ * @throws IOException if an error occurs while setting the fields' context
+ */
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ for (AnalyticsField field : fields) {
+ field.doSetNextReader(context);
+ }
+ }
+
+ /**
+ * Collect the values from the used {@link AnalyticsField}s.
+ *
+ * @param doc the document to collect values for
+ * @throws IOException if an error occurs during field collection
+ */
+ public void collect(int doc) throws IOException {
+ for (AnalyticsField field : fields) {
+ field.collect(doc);
+ }
+ }
+
+ /**
+ * Add a {@link ReductionDataCollection} to target while collecting documents.
+ * This target is valid until the lasting targets are cleared.
+ *
+ * @param target data collection to add document data too
+ */
+ public void addLastingCollectTarget(ReductionDataCollection target) {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].addLastingCollectTarget(target.dataArr[i]);
+ }
+ }
+ /**
+ * Clear lasting collection targets.
+ */
+ public void clearLastingCollectTargets() {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].clearLastingCollectTargets();
+ }
+ }
+
+ /**
+ * Add a new {@link ReductionDataCollection} to target while collecting the next document.
+ * This target is only valid for the next {@link #apply()} call.
+ *
+ * @return the new data collection being targeted
+ */
+ public ReductionDataCollection newDataCollectionTarget() {
+ ReductionDataCollection newCol = new ReductionDataCollection();
+ newCol.dataArr = new ReductionData[reductionDataCollectors.length];
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ newCol.dataArr[i] = reductionDataCollectors[i].newDataTarget();
+ }
+ return newCol;
+ }
+ /**
+ * Add a {@link ReductionDataCollection} to target while collecting the next document.
+ * This target is only valid for the next {@link #apply()} call.
+ *
+ * @param target data collection to add document data too
+ */
+ public void addCollectTarget(ReductionDataCollection target) {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].addCollectTarget(target.dataArr[i]);
+ }
+ }
+
+ /**
+ * Apply the values of the collected fields through the expressions' logic to the managed data collectors.
+ * This is called after {@link #collect(int)} has been called and the collection targets have been added.
+ */
+ public void apply() {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].collectAndApply();;
+ }
+ }
+
+ /**
+ * Finalize the reductions with the collected data stored in the parameter.
+ * Once the data is finalized, the {@link ReductionFunction}s that use these
+ * {@link ReductionDataCollector}s act like regular {@link AnalyticsValue} classes that
+ * can be accessed through their {@code get<value-type>} methods.
+ *
+ * @param dataCollection the collection of reduction data to compute results for
+ */
+ public void setData(ReductionDataCollection dataCollection) {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].setData(dataCollection.dataArr[i]);
+ }
+ }
+
+ /**
+ * Construct a new data collection holding data for all managed data collectors.
+ *
+ * @return a new data collection
+ */
+ public ReductionDataCollection newDataCollection() {
+ ReductionDataCollection newCol = new ReductionDataCollection();
+ newCol.dataArr = new ReductionData[reductionDataCollectors.length];
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ newCol.dataArr[i] = reductionDataCollectors[i].newData();
+ }
+ return newCol;
+ }
+
+ /**
+ * Sets the stream of shard data to merge with.
+ *
+ * @param input the stream of shard data
+ */
+ public void setShardInput(DataInput input) {
+ readers.clear();
+ reservations.forEach( resv -> readers.add(resv.createReadStream(input)));
+ }
+ /**
+ * Merge the data from the given shard input stream into the set IO data collectors.
+ * Should always be called after {@link #setShardInput(DataInput)} and either {@link #prepareReductionDataIO(ReductionDataCollection)}
+ * or {@link #newDataCollectionIO()} have been called.
+ *
+ * @throws IOException if an error occurs while reading the shard data
+ */
+ public void mergeData() throws IOException {
+ for (ReductionDataReader<?> reader : readers) {
+ reader.read();
+ }
+ }
+
+ /**
+ * Sets the stream to export shard data to.
+ *
+ * @param output the stream of shard data
+ */
+ public void setShardOutput(DataOutput output) {
+ writers.clear();
+ reservations.forEach( resv -> writers.add(resv.createWriteStream(output)));
+ }
+ /**
+ * Export the data from the set IO data collectors to the given shard output stream.
+ * Should always be called after {@link #setShardOutput(DataOutput)} and {@link #prepareReductionDataIO(ReductionDataCollection)}.
+ *
+ * @throws IOException if an error occurs while writing the shard data
+ */
+ public void exportData() throws IOException {
+ for (ReductionDataWriter<?> writer : writers) {
+ writer.write();
+ }
+ }
+
+ /**
+ * Set the given data collection to be used for either merging or exporting
+ *
+ * @param col collection to export from or merge to
+ */
+ public void prepareReductionDataIO(ReductionDataCollection col) {
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ reductionDataCollectors[i].dataIO(col.dataArr[i]);
+ }
+ }
+
+ /**
+ * Create a new {@link ReductionDataCollection} to merge to or export from.
+ * Mainly used for creating facet value collectors when merging shard data.
+ *
+ * @return the new data collection created
+ */
+ public ReductionDataCollection newDataCollectionIO() {
+ ReductionDataCollection newCol = new ReductionDataCollection();
+ newCol.dataArr = new ReductionData[reductionDataCollectors.length];
+ for (int i = 0; i < reductionDataCollectors.length; i++) {
+ newCol.dataArr[i] = reductionDataCollectors[i].newDataIO();
+ }
+ return newCol;
+ }
+
+ /**
+ * Holds the collection of {@link ReductionData} that will be updated together.
+ *
+ * For example each grouping will have a separate {@link ReductionDataCollection}, and
+ * ungrouped expressions will have their own as well.
+ */
+ public static class ReductionDataCollection{
+ public ReductionData[] dataArr;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionFunction.java
new file mode 100644
index 0000000..fea01c2
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/ReductionFunction.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analytics.function;
+
+import java.util.function.UnaryOperator;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.value.AnalyticsValue;
+
+/**
+ * A function that reduces the values of a mapping expression, field or constant.
+ */
+public interface ReductionFunction extends AnalyticsValue {
+
+ /**
+ * Syncs the data collectors with shared versions across the entire Analytics Request
+ * so that as little data as possible is sent across shards.
+ *
+ * @param sync a function that takes in a {@link ReductionDataCollector} and returns a shared version
+ */
+ void synchronizeDataCollectors(UnaryOperator<ReductionDataCollector<?>> sync);
+}
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/AnalyticsField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/AnalyticsField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/AnalyticsField.java
new file mode 100644
index 0000000..dab0358
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/AnalyticsField.java
@@ -0,0 +1,69 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+
+/**
+ * An analytics wrapper for Solr Fields.
+ *
+ * Currently only fields with Doc Values enabled can be used in Analytics queries.
+ */
+public abstract class AnalyticsField implements AnalyticsValueStream {
+ protected static final int initialArrayLength = 20;
+
+ protected final String fieldName;
+
+ protected AnalyticsField(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public String getExpressionStr() {
+ return fieldName;
+ }
+
+ @Override
+ public String getName() {
+ return fieldName;
+ }
+
+ @Override
+ public ExpressionType getExpressionType() {
+ return ExpressionType.FIELD;
+ }
+
+ /**
+ * Set the segment reader context
+ *
+ * @param context segment context
+ * @throws IOException if an error occurs while loading the leaf reader
+ */
+ public abstract void doSetNextReader(LeafReaderContext context) throws IOException;
+
+ /**
+ * Collect the value(s) of the wrapped field for the given document, and store the value.
+ *
+ * @param doc ID of the document to collect
+ * @throws IOException if an error occurs while reading the document.
+ */
+ public abstract void collect(int doc) throws IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanField.java
new file mode 100644
index 0000000..650bc36
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanField.java
@@ -0,0 +1,111 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.util.BytesRef;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.value.BooleanValue.CastingBooleanValue;
+import org.apache.solr.schema.BoolField;
+
+/**
+ * An analytics wrapper for a single-valued {@link BoolField} with DocValues enabled.
+ */
+public class BooleanField extends AnalyticsField implements CastingBooleanValue {
+ private SortedDocValues docValues;
+ boolean value;
+ boolean exists;
+ int trueOrd;
+
+ public BooleanField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSorted(context.reader(), fieldName);
+
+ // figure out what ord maps to true
+ int numOrds = docValues.getValueCount();
+ // if no values in the segment, default trueOrd to something other then -1 (missing)
+ int trueOrd = -2;
+ for (int i=0; i<numOrds; i++) {
+ final BytesRef br = docValues.lookupOrd(i);
+ if (br.length==1 && br.bytes[br.offset]=='T') {
+ trueOrd = i;
+ break;
+ }
+ }
+
+ this.trueOrd = trueOrd;
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = trueOrd == docValues.ordValue();
+ }
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return exists ? Boolean.toString(value) : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Boolean.toString(value));
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Boolean> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanMultiField.java
new file mode 100644
index 0000000..e4eecd3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/BooleanMultiField.java
@@ -0,0 +1,101 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.util.BytesRef;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.value.BooleanValueStream.CastingBooleanValueStream;
+import org.apache.solr.schema.BoolField;
+
+
+/**
+ * An analytics wrapper for a multi-valued {@link BoolField} with DocValues enabled.
+ */
+public class BooleanMultiField extends AnalyticsField implements CastingBooleanValueStream {
+ private SortedSetDocValues docValues;
+ private int count;
+ private boolean[] values;
+
+ private int trueOrd;
+
+ public BooleanMultiField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new boolean[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+
+ // figure out what ord maps to true
+ long numOrds = docValues.getValueCount();
+ // if no values in the segment, default trueOrd to something other then -1 (missing)
+ int trueOrd = -2;
+ for (int i=0; i<numOrds; i++) {
+ final BytesRef br = docValues.lookupOrd(i);
+ if (br.length==1 && br.bytes[br.offset]=='T') {
+ trueOrd = i;
+ break;
+ }
+ }
+
+ this.trueOrd = trueOrd;
+ }
+ @Override
+ public void collect(int doc) throws IOException {
+ count = 0;
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ if (count == values.length) {
+ resizeValues();
+ }
+ values[count++] = term == trueOrd;
+ }
+ }
+ }
+
+ private void resizeValues() {
+ boolean[] newValues = new boolean[values.length*2];
+ for (int i = 0; i < count; ++i) {
+ newValues[i] = values[i];
+ }
+ values = newValues;
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamBooleans(value -> cons.accept(Boolean.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamBooleans(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateField.java
new file mode 100644
index 0000000..88e71bc
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateField.java
@@ -0,0 +1,108 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.value.DateValue.CastingDateValue;
+import org.apache.solr.schema.DatePointField;
+import org.apache.solr.schema.TrieDateField;
+
+/**
+ * An analytics wrapper for a single-valued {@link TrieDateField} or {@link DatePointField} with DocValues enabled.
+ */
+public class DateField extends AnalyticsField implements CastingDateValue {
+ private NumericDocValues docValues;
+ private long value;
+ private boolean exists;
+
+ public DateField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = docValues.longValue();
+ }
+ }
+
+ @Override
+ public long getLong() {
+ return value;
+ }
+ @Override
+ public Date getDate() {
+ return exists ? new Date(value) : null;
+ }
+ @Override
+ public String getString() {
+ return exists ? Instant.ofEpochMilli(value).toString() : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ if (exists) {
+ cons.accept(new Date(value));
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Instant.ofEpochMilli(value).toString());
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(new Date(value));
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Date> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiField.java
new file mode 100644
index 0000000..64ee489
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiField.java
@@ -0,0 +1,47 @@
+/*
+ * 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.analytics.function.field;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.value.DateValueStream.CastingDateValueStream;
+import org.apache.solr.schema.TrieDateField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link TrieDateField} with DocValues enabled.
+ */
+public class DateMultiField extends LongMultiField implements CastingDateValueStream {
+
+ public DateMultiField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ streamLongs(value -> cons.accept(new Date(value)));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs(value -> cons.accept(Instant.ofEpochMilli(value).toString()));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs(value -> cons.accept(new Date(value)));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiPointField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiPointField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiPointField.java
new file mode 100644
index 0000000..a1560ef
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DateMultiPointField.java
@@ -0,0 +1,47 @@
+/*
+ * 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.analytics.function.field;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.value.DateValueStream.CastingDateValueStream;
+import org.apache.solr.schema.DatePointField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link DatePointField} with DocValues enabled.
+ */
+public class DateMultiPointField extends LongMultiPointField implements CastingDateValueStream {
+
+ public DateMultiPointField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void streamDates(Consumer<Date> cons) {
+ streamLongs(value -> cons.accept(new Date(value)));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamLongs(value -> cons.accept(Instant.ofEpochMilli(value).toString()));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamLongs(value -> cons.accept(new Date(value)));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleField.java
new file mode 100644
index 0000000..68941a4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleField.java
@@ -0,0 +1,97 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.value.DoubleValue.CastingDoubleValue;
+import org.apache.solr.schema.DoublePointField;
+import org.apache.solr.schema.TrieDoubleField;
+
+/**
+ * An analytics wrapper for a single-valued {@link TrieDoubleField} or {@link DoublePointField} with DocValues enabled.
+ */
+public class DoubleField extends AnalyticsField implements CastingDoubleValue {
+ private NumericDocValues docValues;
+ private double value;
+ private boolean exists;
+
+ public DoubleField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = NumericUtils.sortableLongToDouble(docValues.longValue());
+ }
+ }
+
+ @Override
+ public double getDouble() {
+ return value;
+ }
+ @Override
+ public String getString() {
+ return exists ? Double.toString(value) : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Double.toString(value));
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Double> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiField.java
new file mode 100644
index 0000000..3d58634
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiField.java
@@ -0,0 +1,85 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.value.DoubleValueStream.CastingDoubleValueStream;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.solr.schema.TrieDoubleField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link TrieDoubleField} with DocValues enabled.
+ */
+public class DoubleMultiField extends AnalyticsField implements CastingDoubleValueStream {
+ private SortedSetDocValues docValues;
+ private int count;
+ private double[] values;
+
+ public DoubleMultiField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new double[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+ }
+ @Override
+ public void collect(int doc) throws IOException {
+ count = 0;
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ if (count == values.length) {
+ resizeValues();
+ }
+ values[count++] = NumericUtils.sortableLongToDouble(LegacyNumericUtils.prefixCodedToLong(docValues.lookupOrd(term)));
+ }
+ }
+ }
+
+ private void resizeValues() {
+ double[] newValues = new double[values.length*2];
+ for (int i = 0; i < count; ++i) {
+ newValues[i] = values[i];
+ }
+ values = newValues;
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamDoubles(value -> cons.accept(Double.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamDoubles(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiPointField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiPointField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiPointField.java
new file mode 100644
index 0000000..0933f60
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/DoubleMultiPointField.java
@@ -0,0 +1,81 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.value.DoubleValueStream.CastingDoubleValueStream;
+import org.apache.solr.schema.DoublePointField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link DoublePointField} with DocValues enabled.
+ */
+public class DoubleMultiPointField extends AnalyticsField implements CastingDoubleValueStream {
+ private SortedNumericDocValues docValues;
+ private int count;
+ private double[] values;
+
+ public DoubleMultiPointField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new double[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedNumeric(context.reader(), fieldName);
+ }
+ @Override
+ public void collect(int doc) throws IOException {
+ if (docValues.advanceExact(doc)) {
+ count = docValues.docValueCount();
+ resizeEmptyValues(count);
+ for (int i = 0; i < count; ++i) {
+ values[i] = NumericUtils.sortableLongToDouble(docValues.nextValue());
+ }
+ } else {
+ count = 0;
+ }
+ }
+
+ private void resizeEmptyValues(int count) {
+ if (count > values.length) {
+ values = new double[count];
+ }
+ }
+
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamDoubles(value -> cons.accept(Double.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamDoubles(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatField.java
new file mode 100644
index 0000000..c382d61
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatField.java
@@ -0,0 +1,108 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.FloatValue.CastingFloatValue;
+import org.apache.solr.schema.FloatPointField;
+import org.apache.solr.schema.TrieFloatField;
+
+/**
+ * An analytics wrapper for a single-valued {@link TrieFloatField} or {@link FloatPointField} with DocValues enabled.
+ */
+public class FloatField extends AnalyticsField implements CastingFloatValue {
+ private NumericDocValues docValues;
+ private float value;
+ private boolean exists;
+
+ public FloatField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = NumericUtils.sortableIntToFloat((int)docValues.longValue());
+ }
+ }
+
+ @Override
+ public float getFloat() {
+ return value;
+ }
+ @Override
+ public double getDouble() {
+ return (double)value;
+ }
+ @Override
+ public String getString() {
+ return exists ? Float.toString(value) : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ if (exists) {
+ cons.accept((double)value);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Float.toString(value));
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Float> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiField.java
new file mode 100644
index 0000000..acfce18
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiField.java
@@ -0,0 +1,91 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.FloatValueStream.CastingFloatValueStream;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.solr.schema.TrieFloatField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link TrieFloatField} with DocValues enabled.
+ */
+public class FloatMultiField extends AnalyticsField implements CastingFloatValueStream {
+ private SortedSetDocValues docValues;
+ private int count;
+ private float[] values;
+
+ public FloatMultiField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new float[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ count = 0;
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ if (count == values.length) {
+ resizeValues();
+ }
+ values[count++] = NumericUtils.sortableIntToFloat(LegacyNumericUtils.prefixCodedToInt(docValues.lookupOrd(term)));
+ }
+ }
+ }
+
+ private void resizeValues() {
+ float[] newValues = new float[values.length*2];
+ for (int i = 0; i < count; ++i) {
+ newValues[i] = values[i];
+ }
+ values = newValues;
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamFloats(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamFloats(value -> cons.accept(Float.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamFloats(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiPointField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiPointField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiPointField.java
new file mode 100644
index 0000000..947035e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/FloatMultiPointField.java
@@ -0,0 +1,87 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.FloatValueStream.CastingFloatValueStream;
+import org.apache.solr.schema.FloatPointField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link FloatPointField} with DocValues enabled.
+ */
+public class FloatMultiPointField extends AnalyticsField implements CastingFloatValueStream {
+ private SortedNumericDocValues docValues;
+ private int count;
+ private float[] values;
+
+ public FloatMultiPointField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new float[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ if (docValues.advanceExact(doc)) {
+ count = docValues.docValueCount();
+ resizeEmptyValues(count);
+ for (int i = 0; i < count; ++i) {
+ values[i] = NumericUtils.sortableIntToFloat((int)docValues.nextValue());
+ }
+ } else {
+ count = 0;
+ }
+ }
+
+ private void resizeEmptyValues(int count) {
+ if (count > values.length) {
+ values = new float[count];
+ }
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamFloats(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamFloats(value -> cons.accept(Float.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamFloats(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntField.java
new file mode 100644
index 0000000..e9ae52b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntField.java
@@ -0,0 +1,129 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.solr.analytics.facet.compare.ExpressionComparator;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.IntValue.CastingIntValue;
+import org.apache.solr.schema.IntPointField;
+import org.apache.solr.schema.TrieIntField;
+
+/**
+ * An analytics wrapper for a single-valued {@link TrieIntField} or {@link IntPointField} with DocValues enabled.
+ */
+public class IntField extends AnalyticsField implements CastingIntValue {
+ private NumericDocValues docValues;
+ private int value;
+ private boolean exists;
+
+ public IntField(String fieldName) {
+ super(fieldName);
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ exists = docValues.advanceExact(doc);
+ if (exists) {
+ value = (int)docValues.longValue();
+ }
+ }
+
+ @Override
+ public int getInt() {
+ return value;
+ }
+ @Override
+ public long getLong() {
+ return (long)value;
+ }
+ @Override
+ public float getFloat() {
+ return (float)value;
+ }
+ @Override
+ public double getDouble() {
+ return (double)value;
+ }
+ @Override
+ public String getString() {
+ return exists ? Integer.toString(value) : null;
+ }
+ @Override
+ public Object getObject() {
+ return exists ? value : null;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ if (exists) {
+ cons.accept((long)value);
+ }
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ if (exists) {
+ cons.accept((float)value);
+ }
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ if (exists) {
+ cons.accept((double)value);
+ }
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ if (exists) {
+ cons.accept(Integer.toString(value));
+ }
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ if (exists) {
+ cons.accept(value);
+ }
+ }
+
+ @Override
+ public ExpressionComparator<Integer> getObjectComparator(String expression) {
+ return new ExpressionComparator<>(expression);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiField.java
new file mode 100644
index 0000000..657b1f3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiField.java
@@ -0,0 +1,100 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.IntValueStream.CastingIntValueStream;
+import org.apache.solr.legacy.LegacyNumericUtils;
+import org.apache.solr.schema.TrieIntField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link TrieIntField} with DocValues enabled.
+ */
+public class IntMultiField extends AnalyticsField implements CastingIntValueStream {
+ private SortedSetDocValues docValues;
+ private int count;
+ private int[] values;
+
+ public IntMultiField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new int[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedSet(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ count = 0;
+ if (docValues.advanceExact(doc)) {
+ int term;
+ while ((term = (int)docValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
+ if (count == values.length) {
+ resizeValues();
+ }
+ values[count++] = LegacyNumericUtils.prefixCodedToInt(docValues.lookupOrd(term));
+ }
+ }
+ }
+
+ private void resizeValues() {
+ int[] newValues = new int[values.length*2];
+ for (int i = 0; i < count; ++i) {
+ newValues[i] = values[i];
+ }
+ values = newValues;
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ streamInts(value -> cons.accept((long)value));
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ streamInts(value -> cons.accept((float)value));
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamInts(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamInts(value -> cons.accept(Integer.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamInts(value -> cons.accept(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiPointField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiPointField.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiPointField.java
new file mode 100644
index 0000000..2608fa1
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/field/IntMultiPointField.java
@@ -0,0 +1,96 @@
+/*
+ * 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.analytics.function.field;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.IntValueStream.CastingIntValueStream;
+import org.apache.solr.schema.IntPointField;
+
+/**
+ * An analytics wrapper for a multi-valued {@link IntPointField} with DocValues enabled.
+ */
+public class IntMultiPointField extends AnalyticsField implements CastingIntValueStream {
+ private SortedNumericDocValues docValues;
+ private int count;
+ private int[] values;
+
+ public IntMultiPointField(String fieldName) {
+ super(fieldName);
+ count = 0;
+ values = new int[initialArrayLength];
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ docValues = DocValues.getSortedNumeric(context.reader(), fieldName);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ if (docValues.advanceExact(doc)) {
+ count = docValues.docValueCount();
+ resizeEmptyValues(count);
+ for (int i = 0; i < count; ++i) {
+ values[i] = (int)docValues.nextValue();
+ }
+ } else {
+ count = 0;
+ }
+ }
+
+ private void resizeEmptyValues(int count) {
+ if (count > values.length) {
+ values = new int[count];
+ }
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ for (int i = 0; i < count; ++i) {
+ cons.accept(values[i]);
+ }
+ }
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ streamInts(value -> cons.accept((long)value));
+ }
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ streamInts(value -> cons.accept((float)value));
+ }
+ @Override
+ public void streamDoubles(DoubleConsumer cons) {
+ streamInts(value -> cons.accept((double)value));
+ }
+ @Override
+ public void streamStrings(Consumer<String> cons) {
+ streamInts(value -> cons.accept(Integer.toString(value)));
+ }
+ @Override
+ public void streamObjects(Consumer<Object> cons) {
+ streamInts(value -> cons.accept(value));
+ }
+}
[06/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/RangeEndpointCalculator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/RangeEndpointCalculator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/RangeEndpointCalculator.java
deleted file mode 100644
index fa29022..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/RangeEndpointCalculator.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * 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.analytics.util;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.solr.analytics.request.RangeFacetRequest;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
-import org.apache.solr.common.params.FacetParams.FacetRangeOther;
-import org.apache.solr.schema.FieldType;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.schema.TrieDateField;
-import org.apache.solr.schema.TrieField;
-import org.apache.solr.util.DateMathParser;
-
-
-public abstract class RangeEndpointCalculator<T extends Comparable<T>> {
- protected final SchemaField field;
- protected final RangeFacetRequest request;
-
- public RangeEndpointCalculator(final RangeFacetRequest request) {
- this.field = request.getField();
- this.request = request;
- }
-
- /**
- * Formats a Range endpoint for use as a range label name in the response.
- * Default Impl just uses toString()
- */
- public String formatValue(final T val) {
- return val.toString();
- }
-
- /**
- * Parses a String param into an Range endpoint value throwing
- * a useful exception if not possible
- */
- public final T getValue(final String rawval) {
- try {
- return parseVal(rawval);
- } catch (Exception e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse value "+rawval+" for field: " + field.getName(), e);
- }
- }
-
- /**
- * Parses a String param into an Range endpoint.
- * Can throw a low level format exception as needed.
- */
- protected abstract T parseVal(final String rawval) throws java.text.ParseException;
-
- /**
- * Parses a String param into a value that represents the gap and
- * can be included in the response, throwing
- * a useful exception if not possible.
- *
- * Note: uses Object as the return type instead of T for things like
- * Date where gap is just a DateMathParser string
- */
- public final Object getGap(final String gap) {
- try {
- return parseGap(gap);
- } catch (Exception e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't parse gap "+gap+" for field: " + field.getName(), e);
- }
- }
-
- /**
- * Parses a String param into a value that represents the gap and
- * can be included in the response.
- * Can throw a low level format exception as needed.
- *
- * Default Impl calls parseVal
- */
- protected Object parseGap(final String rawval) throws java.text.ParseException {
- return parseVal(rawval);
- }
-
- /**
- * Adds the String gap param to a low Range endpoint value to determine
- * the corrisponding high Range endpoint value, throwing
- * a useful exception if not possible.
- */
- public final T addGap(T value, String gap) {
- try {
- return parseAndAddGap(value, gap);
- } catch (Exception e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't add gap "+gap+" to value " + value + " for field: " + field.getName(), e);
- }
- }
-
- /**
- * Adds the String gap param to a low Range endpoint value to determine
- * the corrisponding high Range endpoint value.
- * Can throw a low level format exception as needed.
- */
- protected abstract T parseAndAddGap(T value, String gap) throws java.text.ParseException;
-
- public static class FacetRange {
- public final String name;
- public final String lower;
- public final String upper;
- public final boolean includeLower;
- public final boolean includeUpper;
-
- public FacetRange(String name, String lower, String upper, boolean includeLower, boolean includeUpper) {
- this.name = name;
- this.lower = lower;
- this.upper = upper;
- this.includeLower = includeLower;
- this.includeUpper = includeUpper;
- }
- }
-
- public List<FacetRange> getRanges(){
-
- final T start = getValue(request.getStart());
- T end = getValue(request.getEnd()); // not final, hardend may change this
-
- if( end.compareTo(start) < 0 ){
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "range facet 'end' comes before 'start': "+end+" < "+start);
- }
-
- // explicitly return the gap. compute this early so we are more
- // likely to catch parse errors before attempting math
- final String[] gaps = request.getGaps();
- String gap = gaps[0];
-
- final EnumSet<FacetRangeInclude> include = request.getInclude();
-
- T low = start;
-
- List<FacetRange> ranges = new ArrayList<>();
-
- int gapCounter = 0;
-
- while (low.compareTo(end) < 0) {
- if (gapCounter<gaps.length) {
- gap = gaps[gapCounter++];
- }
- T high = addGap(low,gap);
- if (end.compareTo(high) < 0) {
- if (request.isHardEnd()){
- high = end;
- } else {
- end = high;
- }
- }
-
- if (high.compareTo(low) < 0) {
- throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "range facet infinite loop (is gap negative? did the math overflow?)");
- }
-
- if (high.compareTo(low) == 0) {
- throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "range facet infinite loop: gap is either zero, or too small relative start/end and caused underflow: " + low + " + " + gap + " = " + high );
- }
-
- final boolean includeLower = (include.contains(FacetRangeInclude.ALL) ||
- include.contains(FacetRangeInclude.LOWER) ||
- (include.contains(FacetRangeInclude.EDGE) &&
- 0 == low.compareTo(start)));
- final boolean includeUpper = (include.contains(FacetRangeInclude.ALL) ||
- include.contains(FacetRangeInclude.UPPER) ||
- (include.contains(FacetRangeInclude.EDGE) &&
- 0 == high.compareTo(end)));
-
- final String lowS = formatValue(low);
- final String highS = formatValue(high);
-
- ranges.add( new FacetRange(lowS,lowS,highS,includeLower,includeUpper) );
- low = high;
- }
-
- final Set<FacetRangeOther> others = request.getOthers();
- if (null != others && 0 < others.size() ) {
-
- // no matter what other values are listed, we don't do
- // anything if "none" is specified.
- if( !others.contains(FacetRangeOther.NONE) ) {
-
- boolean all = others.contains(FacetRangeOther.ALL);
-
- if (all || others.contains(FacetRangeOther.BEFORE)) {
- // include upper bound if "outer" or if first gap doesn't already include it
- ranges.add( new FacetRange(FacetRangeOther.BEFORE.toString(),
- null, formatValue(start), false, include.contains(FacetRangeInclude.OUTER) || include.contains(FacetRangeInclude.ALL) ||
- !(include.contains(FacetRangeInclude.LOWER) || include.contains(FacetRangeInclude.EDGE)) ) );
-
- }
- if (all || others.contains(FacetRangeOther.AFTER)) {
- // include lower bound if "outer" or if last gap doesn't already include it
- ranges.add( new FacetRange(FacetRangeOther.AFTER.toString(),
- formatValue(end), null, include.contains(FacetRangeInclude.OUTER) || include.contains(FacetRangeInclude.ALL) ||
- !(include.contains(FacetRangeInclude.UPPER) || include.contains(FacetRangeInclude.EDGE)), false) );
- }
- if (all || others.contains(FacetRangeOther.BETWEEN)) {
- ranges.add( new FacetRange(FacetRangeOther.BETWEEN.toString(), formatValue(start), formatValue(end),
- include.contains(FacetRangeInclude.LOWER) || include.contains(FacetRangeInclude.EDGE) || include.contains(FacetRangeInclude.ALL),
- include.contains(FacetRangeInclude.UPPER) || include.contains(FacetRangeInclude.EDGE) || include.contains(FacetRangeInclude.ALL)) );
- }
- }
-
- }
-
- return ranges;
- }
-
- public static RangeEndpointCalculator<? extends Comparable<?>> create(RangeFacetRequest request){
- final SchemaField sf = request.getField();
- final FieldType ft = sf.getType();
- final RangeEndpointCalculator<?> calc;
- if (ft instanceof TrieField) {
- switch (ft.getNumberType()) {
- case FLOAT:
- calc = new FloatRangeEndpointCalculator(request);
- break;
- case DOUBLE:
- calc = new DoubleRangeEndpointCalculator(request);
- break;
- case INTEGER:
- calc = new IntegerRangeEndpointCalculator(request);
- break;
- case LONG:
- calc = new LongRangeEndpointCalculator(request);
- break;
- case DATE:
- calc = new DateRangeEndpointCalculator(request, null);
- break;
- default:
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on tried field of unexpected type:" + sf.getName());
- }
- } else {
- throw new SolrException (SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on field:" + sf);
- }
- return calc;
- }
-
- public static class FloatRangeEndpointCalculator extends RangeEndpointCalculator<Float> {
-
- public FloatRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
-
- @Override
- protected Float parseVal(String rawval) {
- return Float.valueOf(rawval);
- }
-
- @Override
- public Float parseAndAddGap(Float value, String gap) {
- return new Float(value.floatValue() + Float.parseFloat(gap));
- }
-
- }
-
- public static class DoubleRangeEndpointCalculator extends RangeEndpointCalculator<Double> {
-
- public DoubleRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
-
- @Override
- protected Double parseVal(String rawval) {
- return Double.valueOf(rawval);
- }
-
- @Override
- public Double parseAndAddGap(Double value, String gap) {
- return new Double(value.doubleValue() + Double.parseDouble(gap));
- }
-
- }
-
- public static class IntegerRangeEndpointCalculator extends RangeEndpointCalculator<Integer> {
-
- public IntegerRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
-
- @Override
- protected Integer parseVal(String rawval) {
- return Integer.valueOf(rawval);
- }
-
- @Override
- public Integer parseAndAddGap(Integer value, String gap) {
- return new Integer(value.intValue() + Integer.parseInt(gap));
- }
-
- }
-
- public static class LongRangeEndpointCalculator extends RangeEndpointCalculator<Long> {
-
- public LongRangeEndpointCalculator(final RangeFacetRequest request) { super(request); }
-
- @Override
- protected Long parseVal(String rawval) {
- return Long.valueOf(rawval);
- }
-
- @Override
- public Long parseAndAddGap(Long value, String gap) {
- return new Long(value.longValue() + Long.parseLong(gap));
- }
-
- }
-
- public static class DateRangeEndpointCalculator extends RangeEndpointCalculator<Date> {
- private final Date now;
- public DateRangeEndpointCalculator(final RangeFacetRequest request, final Date now) {
- super(request);
- this.now = now;
- if (! (field.getType() instanceof TrieDateField) ) {
- throw new IllegalArgumentException("SchemaField must use field type extending TrieDateField");
- }
- }
-
- @Override
- public String formatValue(Date val) {
- return val.toInstant().toString();
- }
-
- @Override
- protected Date parseVal(String rawval) {
- return DateMathParser.parseMath(now, rawval);
- }
-
- @Override
- protected Object parseGap(final String rawval) {
- return rawval;
- }
-
- @Override
- public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException {
- final DateMathParser dmp = new DateMathParser();
- dmp.setNow(value);
- return dmp.parseMath(gap);
- }
-
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/BooleanConsumer.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/BooleanConsumer.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/BooleanConsumer.java
new file mode 100644
index 0000000..66d7a13
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/BooleanConsumer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.analytics.util.function;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+/**
+ * Represents an operation that accepts a single {@code boolean}-valued argument and
+ * returns no result. This is the primitive type specialization of
+ * {@link Consumer} for {@code boolean}. Unlike most other functional interfaces,
+ * {@code IntConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(boolean)}.
+ *
+ * @see Consumer
+ */
+@FunctionalInterface
+public interface BooleanConsumer {
+
+ /**
+ * Performs this operation on the given argument.
+ *
+ * @param value the input argument
+ */
+ void accept(boolean value);
+
+ /**
+ * Returns a composed {@code DoubleConsumer} that performs, in sequence, this
+ * operation followed by the {@code after} operation. If performing either
+ * operation throws an exception, it is relayed to the caller of the
+ * composed operation. If performing this operation throws an exception,
+ * the {@code after} operation will not be performed.
+ *
+ * @param after the operation to perform after this operation
+ * @return a composed {@code DoubleConsumer} that performs in sequence this
+ * operation followed by the {@code after} operation
+ * @throws NullPointerException if {@code after} is null
+ */
+ default BooleanConsumer andThen(BooleanConsumer after) {
+ Objects.requireNonNull(after);
+ return (boolean t) -> { accept(t); after.accept(t); };
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatConsumer.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatConsumer.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatConsumer.java
new file mode 100644
index 0000000..baa5c12
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatConsumer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.analytics.util.function;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+/**
+ * Represents an operation that accepts a single {@code float}-valued argument and
+ * returns no result. This is the primitive type specialization of
+ * {@link Consumer} for {@code float}. Unlike most other functional interfaces,
+ * {@code IntConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(float)}.
+ *
+ * @see Consumer
+ */
+@FunctionalInterface
+public interface FloatConsumer {
+
+ /**
+ * Performs this operation on the given argument.
+ *
+ * @param value the input argument
+ */
+ void accept(float value);
+
+ /**
+ * Returns a composed {@code DoubleConsumer} that performs, in sequence, this
+ * operation followed by the {@code after} operation. If performing either
+ * operation throws an exception, it is relayed to the caller of the
+ * composed operation. If performing this operation throws an exception,
+ * the {@code after} operation will not be performed.
+ *
+ * @param after the operation to perform after this operation
+ * @return a composed {@code DoubleConsumer} that performs in sequence this
+ * operation followed by the {@code after} operation
+ * @throws NullPointerException if {@code after} is null
+ */
+ default FloatConsumer andThen(FloatConsumer after) {
+ Objects.requireNonNull(after);
+ return (float t) -> { accept(t); after.accept(t); };
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatSupplier.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatSupplier.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatSupplier.java
new file mode 100644
index 0000000..9801ea7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/FloatSupplier.java
@@ -0,0 +1,41 @@
+/*
+ * 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.analytics.util.function;
+
+import java.util.function.Supplier;
+
+/**
+ * Represents a supplier of {@code float}-valued results. This is the
+ * {@code float}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsFloat()}.
+ *
+ * @see Supplier
+ */
+@FunctionalInterface
+public interface FloatSupplier {
+ /**
+ * Gets a result.
+ *
+ * @return a result
+ */
+ float getAsFloat();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/package-info.java
new file mode 100644
index 0000000..9d07e10
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/function/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Pure java functional interfaces. Not specific to analytics.
+ */
+package org.apache.solr.analytics.util.function;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/package-info.java
index a5676f1..49602c7 100644
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/package-info.java
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/package-info.java
@@ -16,9 +16,8 @@
*/
/**
- * Utilities used by analytics component
+ * Utility classes for the analytics component.
*/
package org.apache.solr.analytics.util;
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AbsoluteValueDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AbsoluteValueDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AbsoluteValueDoubleFunction.java
deleted file mode 100644
index f1e996c..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AbsoluteValueDoubleFunction.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>AbsoluteValueDoubleFunction</code> takes the absolute value of the double value of the source it contains.
- */
-public class AbsoluteValueDoubleFunction extends SingleDoubleFunction {
- public final static String NAME = AnalyticsParams.ABSOLUTE_VALUE;
-
- public AbsoluteValueDoubleFunction(ValueSource source) {
- super(source);
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- public String description() {
- return name()+"("+source.description()+")";
- }
-
- protected double func(int doc, FunctionValues vals) throws IOException {
- double d = vals.doubleVal(doc);
- if (d<0) {
- return d*-1;
- } else {
- return d;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- AbsoluteValueDoubleFunction other = (AbsoluteValueDoubleFunction)o;
- return this.source.equals(other.source);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AddDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AddDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AddDoubleFunction.java
deleted file mode 100644
index c47a0a3..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/AddDoubleFunction.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>AddDoubleFunction</code> returns the sum of its components.
- */
-public class AddDoubleFunction extends MultiDoubleFunction {
- public final static String NAME = AnalyticsParams.ADD;
-
- public AddDoubleFunction(ValueSource[] sources) {
- super(sources);
- }
-
- @Override
- protected String name() {
- return NAME;
- }
-
- @Override
- protected double func(int doc, FunctionValues[] valsArr) throws IOException {
- double sum = 0d;
- for (FunctionValues val : valsArr) {
- sum += val.doubleVal(doc);
- }
- return sum;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDateSource.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDateSource.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDateSource.java
deleted file mode 100644
index 3ce608f..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDateSource.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Date;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.docvalues.FloatDocValues;
-import org.apache.lucene.util.mutable.MutableValue;
-import org.apache.lucene.util.mutable.MutableValueDate;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>ConstDateSource</code> returns a constant date for all documents
- */
-public class ConstDateSource extends ConstDoubleSource {
- public final static String NAME = AnalyticsParams.CONSTANT_DATE;
-
- public ConstDateSource(Date constant) {
- super(constant.getTime());
- }
-
- public ConstDateSource(Long constant) {
- super(constant);
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public String description() {
- return name()+"(" + Instant.ofEpochMilli(getLong()) + ")";
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- return new FloatDocValues(this) {
- @Override
- public float floatVal(int doc) {
- return getFloat();
- }
- @Override
- public int intVal(int doc) {
- return getInt();
- }
- @Override
- public long longVal(int doc) {
- return getLong();
- }
- @Override
- public double doubleVal(int doc) {
- return getDouble();
- }
- @Override
- public String toString(int doc) {
- return description();
- }
- @Override
- public Object objectVal(int doc) {
- return new Date(longVal(doc));
- }
- @SuppressWarnings("deprecation")
- @Override
- public String strVal(int doc) {
- return Instant.ofEpochMilli(longVal(doc)).toString();
- }
- @Override
- public boolean boolVal(int doc) {
- return getFloat() != 0.0f;
- }
-
- @Override
- public ValueFiller getValueFiller() {
- return new ValueFiller() {
- private final MutableValueDate mval = new MutableValueDate();
-
- @Override
- public MutableValue getValue() {
- return mval;
- }
-
- @Override
- public void fillValue(int doc) {
- mval.value = longVal(doc);
- mval.exists = true;
- }
- };
- }
- };
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDoubleSource.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDoubleSource.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDoubleSource.java
deleted file mode 100644
index e0ebad6..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstDoubleSource.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
-import org.apache.lucene.queries.function.valuesource.ConstNumberSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>ConstDoubleSource</code> returns a constant double for all documents
- */
-public class ConstDoubleSource extends ConstNumberSource {
- public final static String NAME = AnalyticsParams.CONSTANT_NUMBER;
- final double constant;
-
- public ConstDoubleSource(double constant) {
- this.constant = constant;
- }
-
- @Override
- public String description() {
- return name()+"(" + getFloat() + ")";
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- return new DoubleDocValues(this) {
- @Override
- public double doubleVal(int doc) {
- return constant;
- }
- @Override
- public boolean exists(int doc) {
- return true;
- }
- };
- }
-
- @Override
- public int hashCode() {
- return (int)Double.doubleToLongBits(constant) * 31;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof ConstDoubleSource)) return false;
- ConstDoubleSource other = (ConstDoubleSource)o;
- return this.constant == other.constant;
- }
-
- @Override
- public int getInt() {
- return (int)constant;
- }
-
- @Override
- public long getLong() {
- return (long)constant;
- }
-
- @Override
- public float getFloat() {
- return (float)constant;
- }
-
- @Override
- public double getDouble() {
- return constant;
- }
-
- @Override
- public Number getNumber() {
- return new Double(constant);
- }
-
- @Override
- public boolean getBool() {
- return constant != 0.0f;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstStringSource.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstStringSource.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstStringSource.java
deleted file mode 100644
index 52bdf52..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ConstStringSource.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import org.apache.lucene.queries.function.valuesource.LiteralValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>ConstStringSource</code> returns a constant string for all documents
- */
-public class ConstStringSource extends LiteralValueSource {
- public final static String NAME = AnalyticsParams.CONSTANT_STRING;
-
- public ConstStringSource(String string) {
- super(string);
- }
-
- @Override
- public String description() {
- return name()+"(" + string + ")";
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ConstStringSource)) return false;
- ConstStringSource that = (ConstStringSource) o;
-
- return getValue().equals(that.getValue());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateFieldSource.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateFieldSource.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateFieldSource.java
deleted file mode 100644
index 803d8e0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateFieldSource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Date;
-import java.util.Map;
-
-import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.solr.legacy.LegacyNumericUtils;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.docvalues.LongDocValues;
-import org.apache.lucene.queries.function.valuesource.LongFieldSource;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.mutable.MutableValue;
-import org.apache.lucene.util.mutable.MutableValueDate;
-
-/**
- * Extends {@link LongFieldSource} to have a field source that takes in
- * and returns {@link Date} values while working with long values internally.
- */
-public class DateFieldSource extends LongFieldSource {
-
- public DateFieldSource(String field) {
- super(field);
- }
-
- public long externalToLong(String extVal) {
- return LegacyNumericUtils.prefixCodedToLong(new BytesRef(extVal));
- }
-
- public Object longToObject(long val) {
- return new Date(val);
- }
-
- @SuppressWarnings("deprecation")
- public String longToString(long val) {
- return Instant.ofEpochMilli(val).toString();
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final NumericDocValues arr = DocValues.getNumeric(readerContext.reader(), field);
- return new LongDocValues(this) {
-
- private long getDocValue(int doc) throws IOException {
- int arrDocID = arr.docID();
- if (arrDocID < doc) {
- arrDocID = arr.advance(doc);
- }
- if (arrDocID == doc) {
- return arr.longValue();
- } else {
- return 0;
- }
- }
-
- @Override
- public long longVal(int doc) throws IOException {
- return getDocValue(doc);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- getDocValue(doc);
- return arr.docID() == doc;
- }
-
- @Override
- public Object objectVal(int doc) throws IOException {
- return exists(doc) ? longToObject(getDocValue(doc)) : null;
- }
-
- @Override
- public String strVal(int doc) throws IOException {
- return exists(doc) ? longToString(getDocValue(doc)) : null;
- }
-
- @Override
- public ValueFiller getValueFiller() {
- return new ValueFiller() {
- private final MutableValueDate mval = new MutableValueDate();
-
- @Override
- public MutableValue getValue() {
- return mval;
- }
-
- @Override
- public void fillValue(int doc) throws IOException {
- mval.value = getDocValue(doc);
- mval.exists = exists(doc);
- }
- };
- }
-
- };
- }
-
- @Override
- public boolean equals(Object o) {
- if (o.getClass() != this.getClass()) return false;
- DateFieldSource other = (DateFieldSource) o;
- return field.equals(other.field);
- }
-
- @Override
- public int hashCode() {
- int h = this.getClass().hashCode();
- h += super.hashCode();
- return h;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateMathFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateMathFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateMathFunction.java
deleted file mode 100644
index 77b172a..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DateMathFunction.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.Date;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.valuesource.BytesRefFieldSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.util.DateMathParser;
-
-/**
- * <code>DateMathFunction</code> returns a start date modified by a list of DateMath operations.
- */
-public class DateMathFunction extends MultiDateFunction {
- public final static String NAME = AnalyticsParams.DATE_MATH;
- final private DateMathParser parser;
-
- /**
- * @param sources A list of ValueSource objects. The first element in the list
- * should be a {@link DateFieldSource} or {@link ConstDateSource} object which
- * represents the starting date. The rest of the field should be {@link BytesRefFieldSource}
- * or {@link ConstStringSource} objects which contain the DateMath operations to perform on
- * the start date.
- */
- public DateMathFunction(ValueSource[] sources) {
- super(sources);
- parser = new DateMathParser();
- }
-
- @Override
- protected String name() {
- return NAME;
- }
-
- @Override
- protected long func(int doc, FunctionValues[] valsArr) throws IOException {
- long time = 0;
- Date date = (Date)valsArr[0].objectVal(doc);
- try {
- parser.setNow(date);
- for (int count = 1; count < valsArr.length; count++) {
- date = parser.parseMath(valsArr[count].strVal(doc));
- parser.setNow(date);
- }
- time = parser.getNow().getTime();
- } catch (ParseException e) {
- e.printStackTrace();
- time = date.getTime();
- }
- return time;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DivDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DivDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DivDoubleFunction.java
deleted file mode 100644
index 25c4c96..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DivDoubleFunction.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>DivDoubleFunction</code> returns the quotient of 'a' and 'b'.
- */
-public class DivDoubleFunction extends DualDoubleFunction {
- public final static String NAME = AnalyticsParams.DIVIDE;
-
- /**
- * @param a the numerator.
- * @param b the denominator.
- */
- public DivDoubleFunction(ValueSource a, ValueSource b) {
- super(a, b);
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- protected double func(int doc, FunctionValues aVals, FunctionValues bVals) throws IOException {
- return aVals.doubleVal(doc)/bVals.doubleVal(doc);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DualDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DualDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DualDoubleFunction.java
deleted file mode 100644
index 97b8af7..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/DualDoubleFunction.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
-import org.apache.lucene.search.IndexSearcher;
-
-/**
- * Abstract {@link ValueSource} implementation which wraps two ValueSources
- * and applies an extendible double function to their values.
- **/
-public abstract class DualDoubleFunction extends ValueSource {
- protected final ValueSource a;
- protected final ValueSource b;
-
- public DualDoubleFunction(ValueSource a, ValueSource b) {
- this.a = a;
- this.b = b;
- }
-
- protected abstract String name();
- protected abstract double func(int doc, FunctionValues aVals, FunctionValues bVals) throws IOException;
-
- @Override
- public String description() {
- return name() + "(" + a.description() + "," + b.description() + ")";
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues aVals = a.getValues(context, readerContext);
- final FunctionValues bVals = b.getValues(context, readerContext);
- return new DoubleDocValues(this) {
- @Override
- public double doubleVal(int doc) throws IOException {
- return func(doc, aVals, bVals);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- return aVals.exists(doc) & bVals.exists(doc);
- }
-
- @Override
- public String toString(int doc) throws IOException {
- return name() + '(' + aVals.toString(doc) + ',' + bVals.toString(doc) + ')';
- }
- };
- }
-
- @Override
- public void createWeight(Map context, IndexSearcher searcher) throws IOException {
- a.createWeight(context,searcher);
- b.createWeight(context,searcher);
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- DualDoubleFunction other = (DualDoubleFunction)o;
- return this.a.equals(other.a)
- && this.b.equals(other.b);
- }
-
- @Override
- public int hashCode() {
- int h = a.hashCode();
- h ^= (h << 13) | (h >>> 20);
- h += b.hashCode();
- h ^= (h << 23) | (h >>> 10);
- h += name().hashCode();
- return h;
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/FilterFieldSource.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/FilterFieldSource.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/FilterFieldSource.java
deleted file mode 100644
index 3f374dc..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/FilterFieldSource.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Date;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.util.mutable.MutableValue;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>DefaultIsMissingFieldSource</code> wraps a field source to return missing values
- * if the value is equal to the default value.
- */
-public class FilterFieldSource extends ValueSource {
- public final static String NAME = AnalyticsParams.FILTER;
- public final Object missValue;
- protected final ValueSource source;
-
- public FilterFieldSource(ValueSource source, Object missValue) {
- this.source = source;
- this.missValue = missValue;
- }
-
- protected String name() {
- return NAME;
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public String description() {
- if (missValue.getClass().equals(Date.class)) {
- return name()+"("+source.description()+","+ ((Date)missValue).toInstant() +")";
- } else {
- return name()+"("+source.description()+","+missValue.toString()+")";
- }
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues vals = source.getValues(context, readerContext);
- return new FunctionValues() {
-
- @Override
- public byte byteVal(int doc) throws IOException {
- return vals.byteVal(doc);
- }
-
- @Override
- public short shortVal(int doc) throws IOException {
- return vals.shortVal(doc);
- }
-
- @Override
- public float floatVal(int doc) throws IOException {
- return vals.floatVal(doc);
- }
-
- @Override
- public int intVal(int doc) throws IOException {
- return vals.intVal(doc);
- }
-
- @Override
- public long longVal(int doc) throws IOException {
- return vals.longVal(doc);
- }
-
- @Override
- public double doubleVal(int doc) throws IOException {
- return vals.doubleVal(doc);
- }
-
- @Override
- public String strVal(int doc) throws IOException {
- return vals.strVal(doc);
- }
-
- @Override
- public Object objectVal(int doc) throws IOException {
- return exists(doc)? vals.objectVal(doc) : null;
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- Object other = vals.objectVal(doc);
- return other!=null&&!missValue.equals(other);
- }
-
- @Override
- public String toString(int doc) throws IOException {
- return NAME + '(' + vals.toString(doc) + ')';
- }
-
- @Override
- public ValueFiller getValueFiller() {
- return new ValueFiller() {
- private final ValueFiller delegateFiller = vals.getValueFiller();
- private final MutableValue mval = delegateFiller.getValue();
-
- @Override
- public MutableValue getValue() {
- return mval;
- }
-
- @Override
- public void fillValue(int doc) throws IOException {
- delegateFiller.fillValue(doc);
- mval.exists = exists(doc);
- }
- };
- }
- };
- }
-
- public ValueSource getRootSource() {
- if (source instanceof FilterFieldSource) {
- return ((FilterFieldSource)source).getRootSource();
- } else {
- return source;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- FilterFieldSource other = (FilterFieldSource)o;
- return this.source.equals(other.source) && this.missValue.equals(other.missValue);
- }
-
- @Override
- public int hashCode() {
- return source.hashCode()+name().hashCode();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/LogDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/LogDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/LogDoubleFunction.java
deleted file mode 100644
index 41a6b67..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/LogDoubleFunction.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>LogDoubleFunction</code> returns the log of a double value with a given base.
- */
-public class LogDoubleFunction extends DualDoubleFunction {
- public final static String NAME = AnalyticsParams.LOG;
-
- public LogDoubleFunction(ValueSource a, ValueSource b) {
- super(a,b);
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- protected double func(int doc, FunctionValues aVals, FunctionValues bVals) throws IOException {
- return Math.log(aVals.doubleVal(doc))/Math.log(bVals.doubleVal(doc));
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDateFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDateFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDateFunction.java
deleted file mode 100644
index beeaaa7..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDateFunction.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.LongDocValues;
-import org.apache.lucene.util.mutable.MutableValue;
-import org.apache.lucene.util.mutable.MutableValueDate;
-
-/**
- * Abstract {@link ValueSource} implementation which wraps multiple ValueSources
- * and applies an extendible date function to their values.
- **/
-public abstract class MultiDateFunction extends ValueSource {
- protected final ValueSource[] sources;
-
- public MultiDateFunction(ValueSource[] sources) {
- this.sources = sources;
- }
-
- abstract protected String name();
- abstract protected long func(int doc, FunctionValues[] valsArr) throws IOException;
-
- @Override
- public String description() {
- StringBuilder sb = new StringBuilder();
- sb.append(name()).append('(');
- boolean firstTime=true;
- for (ValueSource source : sources) {
- if (firstTime) {
- firstTime=false;
- } else {
- sb.append(',');
- }
- sb.append(source);
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues[] valsArr = new FunctionValues[sources.length];
- for (int i=0; i<sources.length; i++) {
- valsArr[i] = sources[i].getValues(context, readerContext);
- }
-
- return new LongDocValues(this) {
- @Override
- public long longVal(int doc) throws IOException {
- return func(doc, valsArr);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- boolean exists = true;
- for (FunctionValues val : valsArr) {
- exists = exists & val.exists(doc);
- }
- return exists;
- }
-
- @Override
- public String toString(int doc) throws IOException {
- StringBuilder sb = new StringBuilder();
- sb.append(name()).append('(');
- boolean firstTime=true;
- for (FunctionValues vals : valsArr) {
- if (firstTime) {
- firstTime=false;
- } else {
- sb.append(',');
- }
- sb.append(vals.toString(doc));
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override
- public ValueFiller getValueFiller() {
- return new ValueFiller() {
- private final MutableValueDate mval = new MutableValueDate();
-
- @Override
- public MutableValue getValue() {
- return mval;
- }
-
- @Override
- public void fillValue(int doc) throws IOException {
- mval.value = longVal(doc);
- mval.exists = exists(doc);
- }
- };
- }
- };
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- MultiDateFunction other = (MultiDateFunction)o;
- return this.name().equals(other.name())
- && Arrays.equals(this.sources, other.sources);
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(sources) + name().hashCode();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDoubleFunction.java
deleted file mode 100644
index 09956f2..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiDoubleFunction.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
-import org.apache.lucene.search.IndexSearcher;
-
-/**
- * Abstract {@link ValueSource} implementation which wraps multiple ValueSources
- * and applies an extendible double function to their values.
- **/
-public abstract class MultiDoubleFunction extends ValueSource {
- protected final ValueSource[] sources;
-
- public MultiDoubleFunction(ValueSource[] sources) {
- this.sources = sources;
- }
-
- abstract protected String name();
- abstract protected double func(int doc, FunctionValues[] valsArr) throws IOException;
-
- @Override
- public String description() {
- StringBuilder sb = new StringBuilder();
- sb.append(name()).append('(');
- boolean firstTime=true;
- for (ValueSource source : sources) {
- if (firstTime) {
- firstTime=false;
- } else {
- sb.append(',');
- }
- sb.append(source);
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues[] valsArr = new FunctionValues[sources.length];
- for (int i=0; i<sources.length; i++) {
- valsArr[i] = sources[i].getValues(context, readerContext);
- }
-
- return new DoubleDocValues(this) {
- @Override
- public double doubleVal(int doc) throws IOException {
- return func(doc, valsArr);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- boolean exists = true;
- for (FunctionValues val : valsArr) {
- exists = exists & val.exists(doc);
- }
- return exists;
- }
-
- @Override
- public String toString(int doc) throws IOException {
- StringBuilder sb = new StringBuilder();
- sb.append(name()).append('(');
- boolean firstTime=true;
- for (FunctionValues vals : valsArr) {
- if (firstTime) {
- firstTime=false;
- } else {
- sb.append(',');
- }
- sb.append(vals.toString(doc));
- }
- sb.append(')');
- return sb.toString();
- }
- };
- }
-
- @Override
- public void createWeight(Map context, IndexSearcher searcher) throws IOException {
- for (ValueSource source : sources)
- source.createWeight(context, searcher);
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- MultiDoubleFunction other = (MultiDoubleFunction)o;
- return this.name().equals(other.name())
- && Arrays.equals(this.sources, other.sources);
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(sources) + name().hashCode();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiplyDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiplyDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiplyDoubleFunction.java
deleted file mode 100644
index 83f26f0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/MultiplyDoubleFunction.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>MultiplyDoubleFunction</code> returns the product of its components.
- */
-public class MultiplyDoubleFunction extends MultiDoubleFunction {
- public final static String NAME = AnalyticsParams.MULTIPLY;
-
- public MultiplyDoubleFunction(ValueSource[] sources) {
- super(sources);
- }
-
- @Override
- protected String name() {
- return NAME;
- }
-
- @Override
- protected double func(int doc, FunctionValues[] valsArr) throws IOException {
- double product = 1d;
- for (FunctionValues val : valsArr) {
- product *= val.doubleVal(doc);
- }
- return product;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/NegateDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/NegateDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/NegateDoubleFunction.java
deleted file mode 100644
index 9c8445d..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/NegateDoubleFunction.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>NegateDoubleFunction</code> negates the double value of the source it contains.
- */
-public class NegateDoubleFunction extends SingleDoubleFunction {
- public final static String NAME = AnalyticsParams.NEGATE;
-
- public NegateDoubleFunction(ValueSource source) {
- super(source);
- }
-
- protected String name() {
- return NAME;
- }
-
- @Override
- public String description() {
- return name()+"("+source.description()+")";
- }
-
- protected double func(int doc, FunctionValues vals) throws IOException {
- return vals.doubleVal(doc)*-1;
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- NegateDoubleFunction other = (NegateDoubleFunction)o;
- return this.source.equals(other.source);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/PowDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/PowDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/PowDoubleFunction.java
deleted file mode 100644
index 043313b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/PowDoubleFunction.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>PowDoubleFunction</code> returns 'a' raised to the power of 'b'.
- */
-public class PowDoubleFunction extends DualDoubleFunction {
- public final static String NAME = AnalyticsParams.POWER;
-
- /**
- * @param a the base.
- * @param b the exponent.
- */
- public PowDoubleFunction(ValueSource a, ValueSource b) {
- super(a, b);
- }
-
- @Override
- protected String name() {
- return NAME;
- }
-
- @Override
- protected double func(int doc, FunctionValues aVals, FunctionValues bVals) throws IOException {
- return Math.pow(aVals.doubleVal(doc), bVals.doubleVal(doc));
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ReverseStringFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ReverseStringFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ReverseStringFunction.java
deleted file mode 100644
index 4fa0f99..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/ReverseStringFunction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.solr.analytics.util.AnalyticsParams;
-
-/**
- * <code>ReverseStringFunction</code> reverses the string value of the source it contains.
- */
-public class ReverseStringFunction extends SingleStringFunction {
- public final static String NAME = AnalyticsParams.REVERSE;
-
- public ReverseStringFunction(ValueSource source) {
- super(source);
- }
-
- protected String name() {
- return NAME;
- }
-
- protected CharSequence func(int doc, FunctionValues vals) throws IOException {
- String val = vals.strVal(doc);
- return val != null ? StringUtils.reverse(val) : null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleDoubleFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleDoubleFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleDoubleFunction.java
deleted file mode 100644
index 04f79ed..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleDoubleFunction.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
-
-/**
- * Abstract {@link ValueSource} implementation which wraps one ValueSource
- * and applies an extendible double function to its values.
- */
-public abstract class SingleDoubleFunction extends ValueSource {
- protected final ValueSource source;
-
- public SingleDoubleFunction(ValueSource source) {
- this.source = source;
- }
-
- @Override
- public String description() {
- return name()+"("+source.description()+")";
- }
-
- abstract String name();
- abstract double func(int doc, FunctionValues vals) throws IOException;
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues vals = source.getValues(context, readerContext);
- return new DoubleDocValues(this) {
- @Override
- public double doubleVal(int doc) throws IOException {
- return func(doc, vals);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- return vals.exists(doc);
- }
-
- @Override
- public String toString(int doc) throws IOException {
- return name() + '(' + vals.toString(doc) + ')';
- }
- };
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- SingleDoubleFunction other = (SingleDoubleFunction)o;
- return this.source.equals(other.source);
- }
-
- @Override
- public int hashCode() {
- return source.hashCode()+name().hashCode();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleStringFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleStringFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleStringFunction.java
deleted file mode 100644
index b3357f9..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/SingleStringFunction.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.analytics.util.valuesource;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.StrDocValues;
-import org.apache.lucene.util.BytesRefBuilder;
-import org.apache.lucene.util.mutable.MutableValue;
-import org.apache.lucene.util.mutable.MutableValueStr;
-
-/**
- * Abstract {@link ValueSource} implementation which wraps one ValueSource
- * and applies an extendible string function to its values.
- */
-public abstract class SingleStringFunction extends ValueSource {
- protected final ValueSource source;
-
- public SingleStringFunction(ValueSource source) {
- this.source = source;
- }
-
- @Override
- public String description() {
- return name()+"("+source.description()+")";
- }
-
- abstract String name();
- abstract CharSequence func(int doc, FunctionValues vals) throws IOException;
-
- @Override
- public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
- final FunctionValues vals = source.getValues(context, readerContext);
- return new StrDocValues(this) {
- @Override
- public String strVal(int doc) throws IOException {
- CharSequence cs = func(doc, vals);
- return cs != null ? cs.toString() : null;
- }
-
- @Override
- public boolean bytesVal(int doc, BytesRefBuilder bytes) throws IOException {
- CharSequence cs = func(doc, vals);
- if( cs != null ){
- bytes.copyChars(func(doc,vals));
- return true;
- } else {
- bytes.clear();
- return false;
- }
- }
-
- @Override
- public Object objectVal(int doc) throws IOException {
- return strVal(doc);
- }
-
- @Override
- public boolean exists(int doc) throws IOException {
- return vals.exists(doc);
- }
-
- @Override
- public String toString(int doc) throws IOException {
- return name() + '(' + strVal(doc) + ')';
- }
-
- @Override
- public ValueFiller getValueFiller() {
- return new ValueFiller() {
- private final MutableValueStr mval = new MutableValueStr();
-
- @Override
- public MutableValue getValue() {
- return mval;
- }
-
- @Override
- public void fillValue(int doc) throws IOException {
- mval.exists = bytesVal(doc, mval.value);
- }
- };
- }
- };
- }
-
- @Override
- public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
- SingleStringFunction other = (SingleStringFunction)o;
- return this.source.equals(other.source);
- }
-
- @Override
- public int hashCode() {
- return source.hashCode()+name().hashCode();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/package-info.java
deleted file mode 100644
index 72a23d2..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/util/valuesource/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * ValueSource function/sources used by analytics component
- */
-package org.apache.solr.analytics.util.valuesource;
-
-
-
[14/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LambdaFunction.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LambdaFunction.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LambdaFunction.java
new file mode 100644
index 0000000..ff8a1a6
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/function/mapping/LambdaFunction.java
@@ -0,0 +1,3220 @@
+/*
+ * 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.analytics.function.mapping;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.solr.analytics.function.mapping.LambdaFunction.BoolInBoolOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.DoubleInDoubleOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.FloatInFloatOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.IntInIntOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.LongInLongOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.StringInStringOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoBoolInBoolOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoDoubleInDoubleOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoFloatInFloatOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoIntInIntOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoLongInLongOutLambda;
+import org.apache.solr.analytics.function.mapping.LambdaFunction.TwoStringInStringOutLambda;
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+import org.apache.solr.analytics.util.function.FloatConsumer;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.BooleanValue.AbstractBooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream.AbstractBooleanValueStream;
+import org.apache.solr.analytics.value.DateValue.AbstractDateValue;
+import org.apache.solr.analytics.value.DateValueStream.AbstractDateValueStream;
+import org.apache.solr.analytics.value.DoubleValue.AbstractDoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream.AbstractDoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue.AbstractFloatValue;
+import org.apache.solr.analytics.value.FloatValueStream.AbstractFloatValueStream;
+import org.apache.solr.analytics.value.IntValue.AbstractIntValue;
+import org.apache.solr.analytics.value.IntValueStream.AbstractIntValueStream;
+import org.apache.solr.analytics.value.LongValue.AbstractLongValue;
+import org.apache.solr.analytics.value.LongValueStream.AbstractLongValueStream;
+import org.apache.solr.analytics.value.StringValue.AbstractStringValue;
+import org.apache.solr.analytics.value.StringValueStream.AbstractStringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+
+/**
+ * Lambda Functions are used to easily create basic mapping functions.
+ * <p>
+ * There are lambda functions for all types: boolean, int, long, float, double, date and string.
+ * Lambda functions must have parameters of all the same type, which will be the same type as the returned Value or ValueStream.
+ * <p>
+ * The types of functions that are accepted are: (multi = multi-valued expression, single = single-valued expression)
+ * <ul>
+ * <li> {@code func(single) -> single}
+ * <li> {@code func(multi) -> multi}
+ * <li> {@code func(single,single) -> single}
+ * <li> {@code func(multi,single) -> multi}
+ * <li> {@code func(single,multi) -> multi}
+ * <li> {@code func(multi) -> single}
+ * <li> {@code func(single,single,...) -> single}
+ * (You can also specify whether all parameters must exist, or at least one must exist for the returned value to exist)
+ * </ul>
+ * <p>
+ * NOTE: The combination of name and parameters MUST be unique for an expression.
+ * <br>
+ * For example consider if {@code join(fieldA, ',')} and {@code join(fieldA, ';')} are both called. If the JoinFunction uses:
+ * <br>
+ * {@code LambdaFunction.createStringLambdaFunction("join", (a,b) -> a + sep + b, (StringValueStream)params[0])}
+ * <br>
+ * then both the name "join" and single parameter fieldA will be used for two DIFFERENT expressions.
+ * This does not meet the uniqueness requirmenet and will break the query.
+ * <br>
+ * A solution to this is to name the function using the missing information:
+ * <br>
+ * {@code LambdaFunction.createStringLambdaFunction("join(" + sep + ")", (a,b) -> a + sep + b, (StringValueStream)params[0])}
+ * <br>
+ * Therefore both expressions will have fieldA as the only parameter, but the names {@code "join(,)"} and {@code "join(;)"} will be different.
+ * This meets the uniqueness requirement for lambda functions.
+ */
+public class LambdaFunction {
+ private static final boolean defaultMultiExistsMethod = true;
+
+ /* *********************
+ *
+ * Boolean Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued boolean expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (boolean) -> boolean}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static BooleanValueStream createBooleanLambdaFunction(String name, BoolInBoolOutLambda lambda, BooleanValueStream param) {
+ if (param instanceof BooleanValue) {
+ return new BooleanValueInBooleanValueOutFunction(name,lambda,(BooleanValue)param);
+ } else {
+ return new BooleanStreamInBooleanStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued boolean expression and returns a single-valued boolean expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static BooleanValue createBooleanLambdaFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValueStream param) {
+ return new BooleanStreamInBooleanValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two booleans to a single boolean.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (boolean,boolean) -> boolean}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static BooleanValueStream createBooleanLambdaFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValueStream param1, BooleanValueStream param2) throws SolrException {
+ if (param1 instanceof BooleanValue && param2 instanceof BooleanValue) {
+ return new TwoBooleanValueInBooleanValueOutFunction(name,lambda,(BooleanValue)param1,(BooleanValue)param2);
+ } else if (param1 instanceof BooleanValue) {
+ return new BooleanValueBooleanStreamInBooleanStreamOutFunction(name,lambda,(BooleanValue)param1,param2);
+ } else if (param2 instanceof BooleanValue) {
+ return new BooleanStreamBooleanValueInBooleanStreamOutFunction(name,lambda,param1,(BooleanValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createBooleanLambdaFunction(String, TwoBoolInBoolOutLambda, BooleanValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static BooleanValue createBooleanLambdaFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue[] params) {
+ return createBooleanLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value boolean expressions into a single-value boolean expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static BooleanValue createBooleanLambdaFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiBooleanValueInBooleanValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiBooleanValueInBooleanValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * Integer Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued integer expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (integer) -> integer}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static IntValueStream createIntLambdaFunction(String name, IntInIntOutLambda lambda, IntValueStream param) {
+ if (param instanceof IntValue) {
+ return new IntValueInIntValueOutFunction(name,lambda,(IntValue)param);
+ } else {
+ return new IntStreamInIntStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued integer expression and returns a single-valued integer expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (integer, integer) -> integer}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static IntValue createIntLambdaFunction(String name, TwoIntInIntOutLambda lambda, IntValueStream param) {
+ return new IntStreamInIntValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two integers to a single integer.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (integer,integer) -> integer}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static IntValueStream createIntLambdaFunction(String name, TwoIntInIntOutLambda lambda, IntValueStream param1, IntValueStream param2) throws SolrException {
+ if (param1 instanceof IntValue && param2 instanceof IntValue) {
+ return new TwoIntValueInIntValueOutFunction(name,lambda,(IntValue)param1,(IntValue)param2);
+ } else if (param1 instanceof IntValue) {
+ return new IntValueIntStreamInIntStreamOutFunction(name,lambda,(IntValue)param1,param2);
+ } else if (param2 instanceof IntValue) {
+ return new IntStreamIntValueInIntStreamOutFunction(name,lambda,param1,(IntValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createIntLambdaFunction(String, TwoIntInIntOutLambda, IntValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static IntValue createIntLambdaFunction(String name, TwoIntInIntOutLambda lambda, IntValue[] params) {
+ return createIntLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value integer expressions into a single-value integer expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (integer, integer) -> integer}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static IntValue createIntLambdaFunction(String name, TwoIntInIntOutLambda lambda, IntValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiIntValueInIntValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiIntValueInIntValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * Long Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued long expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (long) -> long}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static LongValueStream createLongLambdaFunction(String name, LongInLongOutLambda lambda, LongValueStream param) {
+ if (param instanceof LongValue) {
+ return new LongValueInLongValueOutFunction(name,lambda,(LongValue)param);
+ } else {
+ return new LongStreamInLongStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued long expression and returns a single-valued long expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static LongValue createLongLambdaFunction(String name, TwoLongInLongOutLambda lambda, LongValueStream param) {
+ return new LongStreamInLongValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two longs to a single long.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (long,long) -> long}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static LongValueStream createLongLambdaFunction(String name, TwoLongInLongOutLambda lambda, LongValueStream param1, LongValueStream param2) throws SolrException {
+ if (param1 instanceof LongValue && param2 instanceof LongValue) {
+ return new TwoLongValueInLongValueOutFunction(name,lambda,(LongValue)param1,(LongValue)param2);
+ } else if (param1 instanceof LongValue) {
+ return new LongValueLongStreamInLongStreamOutFunction(name,lambda,(LongValue)param1,param2);
+ } else if (param2 instanceof LongValue) {
+ return new LongStreamLongValueInLongStreamOutFunction(name,lambda,param1,(LongValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createLongLambdaFunction(String, TwoLongInLongOutLambda, LongValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static LongValue createLongLambdaFunction(String name, TwoLongInLongOutLambda lambda, LongValue[] params) {
+ return createLongLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value long expressions into a single-value long expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (long, long) -> long}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static LongValue createLongLambdaFunction(String name, TwoLongInLongOutLambda lambda, LongValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiLongValueInLongValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiLongValueInLongValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * Float Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued float expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (float) -> float}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static FloatValueStream createFloatLambdaFunction(String name, FloatInFloatOutLambda lambda, FloatValueStream param) {
+ if (param instanceof FloatValue) {
+ return new FloatValueInFloatValueOutFunction(name,lambda,(FloatValue)param);
+ } else {
+ return new FloatStreamInFloatStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued float expression and returns a single-valued float expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (float, float) -> float}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static FloatValue createFloatLambdaFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValueStream param) {
+ return new FloatStreamInFloatValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two floats to a single float.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (float,float) -> float}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static FloatValueStream createFloatLambdaFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValueStream param1, FloatValueStream param2) throws SolrException {
+ if (param1 instanceof FloatValue && param2 instanceof FloatValue) {
+ return new TwoFloatValueInFloatValueOutFunction(name,lambda,(FloatValue)param1,(FloatValue)param2);
+ } else if (param1 instanceof FloatValue) {
+ return new FloatValueFloatStreamInFloatStreamOutFunction(name,lambda,(FloatValue)param1,param2);
+ } else if (param2 instanceof FloatValue) {
+ return new FloatStreamFloatValueInFloatStreamOutFunction(name,lambda,param1,(FloatValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createFloatLambdaFunction(String, TwoFloatInFloatOutLambda, FloatValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static FloatValue createFloatLambdaFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValue[] params) {
+ return createFloatLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value float expressions into a single-value float expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (float, float) -> float}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static FloatValue createFloatLambdaFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiFloatValueInFloatValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiFloatValueInFloatValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * Double Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued double expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (double) -> double}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static DoubleValueStream createDoubleLambdaFunction(String name, DoubleInDoubleOutLambda lambda, DoubleValueStream param) {
+ if (param instanceof DoubleValue) {
+ return new DoubleValueInDoubleValueOutFunction(name,lambda,(DoubleValue)param);
+ } else {
+ return new DoubleStreamInDoubleStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued double expression and returns a single-valued double expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (double, double) -> double}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static DoubleValue createDoubleLambdaFunction(String name, TwoDoubleInDoubleOutLambda lambda, DoubleValueStream param) {
+ return new DoubleStreamInDoubleValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two doubles to a single double.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (double,double) -> double}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static DoubleValueStream createDoubleLambdaFunction(String name, TwoDoubleInDoubleOutLambda lambda, DoubleValueStream param1, DoubleValueStream param2) throws SolrException {
+ if (param1 instanceof DoubleValue && param2 instanceof DoubleValue) {
+ return new TwoDoubleValueInDoubleValueOutFunction(name,lambda,(DoubleValue)param1,(DoubleValue)param2);
+ } else if (param1 instanceof DoubleValue) {
+ return new DoubleValueDoubleStreamInDoubleStreamOutFunction(name,lambda,(DoubleValue)param1,param2);
+ } else if (param2 instanceof DoubleValue) {
+ return new DoubleStreamDoubleValueInDoubleStreamOutFunction(name,lambda,param1,(DoubleValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createDoubleLambdaFunction(String, TwoDoubleInDoubleOutLambda, DoubleValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static DoubleValue createDoubleLambdaFunction(String name, TwoDoubleInDoubleOutLambda lambda, DoubleValue[] params) {
+ return createDoubleLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value double expressions into a single-value double expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (double, double) -> double}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static DoubleValue createDoubleLambdaFunction(String name, TwoDoubleInDoubleOutLambda lambda, DoubleValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiDoubleValueInDoubleValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiDoubleValueInDoubleValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * Date Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued date expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * <p>
+ * NOTE: The lambda must work on longs, not Date objects
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (long) -> long}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static DateValueStream createDateLambdaFunction(String name, LongInLongOutLambda lambda, DateValueStream param) {
+ if (param instanceof DateValue) {
+ return new DateValueInDateValueOutFunction(name,lambda,(DateValue)param);
+ } else {
+ return new DateStreamInDateStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued date expression and returns a single-valued date expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * <p>
+ * NOTE: The lambda must work on longs, not Date objects
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (long, long) -> long}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static DateValue createDateLambdaFunction(String name, TwoLongInLongOutLambda lambda, DateValueStream param) {
+ return new DateStreamInDateValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two dates to a single date.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ *
+ * <p>
+ * NOTE: The lambda must work on longs, not Date objects
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (long,long) -> long}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static DateValueStream createDateLambdaFunction(String name, TwoLongInLongOutLambda lambda, DateValueStream param1, DateValueStream param2) throws SolrException {
+ if (param1 instanceof DateValue && param2 instanceof DateValue) {
+ return new TwoDateValueInDateValueOutFunction(name,lambda,(DateValue)param1,(DateValue)param2);
+ } else if (param1 instanceof DateValue) {
+ return new DateValueDateStreamInDateStreamOutFunction(name,lambda,(DateValue)param1,param2);
+ } else if (param2 instanceof DateValue) {
+ return new DateStreamDateValueInDateStreamOutFunction(name,lambda,param1,(DateValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createDateLambdaFunction(String, TwoLongInLongOutLambda, DateValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static DateValue createDateLambdaFunction(String name, TwoLongInLongOutLambda lambda, DateValue[] params) {
+ return createDateLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value date expressions into a single-value date expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * <p>
+ * NOTE: The lambda must work on longs, not Date objects
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (long, long) -> long}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static DateValue createDateLambdaFunction(String name, TwoLongInLongOutLambda lambda, DateValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiDateValueInDateValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiDateValueInDateValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+ /* *********************
+ *
+ * String Functions
+ *
+ * *********************/
+
+ /**
+ * Creates a function that takes in either a single or multi valued string expression and returns the same type of expression with
+ * the given lambda function applied to every value.
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (String) -> String}
+ * @param param the expression to apply the lambda to
+ * @return an expression the same type as was given with the lambda applied
+ */
+ public static StringValueStream createStringLambdaFunction(String name, StringInStringOutLambda lambda, StringValueStream param) {
+ if (param instanceof StringValue) {
+ return new StringValueInStringValueOutFunction(name,lambda,(StringValue)param);
+ } else {
+ return new StringStreamInStringStreamOutFunction(name,lambda,param);
+ }
+ }
+ /**
+ * Creates a function that takes in a multi-valued string expression and returns a single-valued string expression.
+ * The given lambda is used to associatively (order not guaranteed) reduce all values for a document down to a single value.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (String, String) -> String}
+ * @param param the expression to be reduced per-document
+ * @return a single-valued expression which has been reduced for every document
+ */
+ public static StringValue createStringLambdaFunction(String name, TwoStringInStringOutLambda lambda, StringValueStream param) {
+ return new StringStreamInStringValueOutFunction(name,lambda,param);
+ }
+ /**
+ * Creates a function that maps two strings to a single string.
+ * This can take the following shapes:
+ * <ul>
+ * <li> Taking in two single-valued expressions and returning a single-valued expression which represents the lambda combination of the inputs.
+ * <li> Taking in a single-valued expression and a multi-valued expression and returning a multi-valued expression which
+ * represents the lambda combination of the single-value input with each of the values of the multi-value input.
+ * <br>
+ * The inputs can be either {@code func(single,multi)} or {@code func(multi,single)}.
+ * </ul>
+ * <p>
+ *
+ * @param name name for the function
+ * @param lambda the function to be applied to every value: {@code (String,String) -> String}
+ * @param param1 the first parameter in the lambda
+ * @param param2 the second parameter in the lambda
+ * @return a single or multi valued expression combining the two parameters with the given lambda
+ * @throws SolrException if neither parameter is single-valued
+ */
+ public static StringValueStream createStringLambdaFunction(String name, TwoStringInStringOutLambda lambda, StringValueStream param1, StringValueStream param2) throws SolrException {
+ if (param1 instanceof StringValue && param2 instanceof StringValue) {
+ return new TwoStringValueInStringValueOutFunction(name,lambda,(StringValue)param1,(StringValue)param2);
+ } else if (param1 instanceof StringValue) {
+ return new StringValueStringStreamInStringStreamOutFunction(name,lambda,(StringValue)param1,param2);
+ } else if (param2 instanceof StringValue) {
+ return new StringStreamStringValueInStringStreamOutFunction(name,lambda,param1,(StringValue)param2);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The "+name+" function requires at least 1 single-valued parameter.");
+ }
+ }
+ /**
+ * Forwards the creation of the function to {@link #createStringLambdaFunction(String, TwoStringInStringOutLambda, StringValue[], boolean)},
+ * using {@value #defaultMultiExistsMethod} for the last argument ({@code allMustExist}).
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (boolean, boolean) -> boolean}
+ * @param params the expressions to reduce
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static StringValue createStringLambdaFunction(String name, TwoStringInStringOutLambda lambda, StringValue[] params) {
+ return createStringLambdaFunction(name,lambda,params,defaultMultiExistsMethod);
+ }
+ /**
+ * Creates a function that associatively (order is guaranteed) reduces multiple
+ * single-value string expressions into a single-value string expression for each document.
+ * <br>
+ * For a document, every parameter's value must exist for the resulting value to exist if {@code allMustExist} is true.
+ * If {@code allMustExist} is false, only one of the parameters' values must exist.
+ *
+ * @param name name for the function
+ * @param lambda the associative function used to reduce the values: {@code (String, String) -> String}
+ * @param params the expressions to reduce
+ * @param allMustExist whether all parameters are required to exist
+ * @return a single-value expression that reduces the parameters with the given lambda
+ */
+ public static StringValue createStringLambdaFunction(String name, TwoStringInStringOutLambda lambda, StringValue[] params, boolean allMustExist) {
+ if (allMustExist) {
+ return new MultiStringValueInStringValueOutRequireAllFunction(name,lambda,params);
+ } else {
+ return new MultiStringValueInStringValueOutRequireOneFunction(name,lambda,params);
+ }
+ }
+
+
+ /*
+ * Single Parameter
+ */
+ // Boolean Out
+ @FunctionalInterface
+ public static interface BoolInBoolOutLambda { boolean apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInBoolOutLambda { boolean apply(int a); }
+ @FunctionalInterface
+ public static interface LongInBoolOutLambda { boolean apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInBoolOutLambda { boolean apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInBoolOutLambda { boolean apply(double a); }
+ @FunctionalInterface
+ public static interface StringInBoolOutLambda { boolean apply(double a); }
+ // Int Out
+ @FunctionalInterface
+ public static interface BoolInIntOutLambda { int apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInIntOutLambda { int apply(int a); }
+ @FunctionalInterface
+ public static interface LongInIntOutLambda { int apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInIntOutLambda { int apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInIntOutLambda { int apply(double a); }
+ @FunctionalInterface
+ public static interface StringInIntOutLambda { int apply(double a); }
+ // Long Out
+ @FunctionalInterface
+ public static interface BoolInLongOutLambda { long apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInLongOutLambda { long apply(int a); }
+ @FunctionalInterface
+ public static interface LongInLongOutLambda { long apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInLongOutLambda { long apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInLongOutLambda { long apply(double a); }
+ @FunctionalInterface
+ public static interface StringInLongOutLambda { long apply(double a); }
+ // Float Out
+ @FunctionalInterface
+ public static interface BoolInFloatOutLambda { float apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInFloatOutLambda { float apply(int a); }
+ @FunctionalInterface
+ public static interface LongInFloatOutLambda { float apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInFloatOutLambda { float apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInFloatOutLambda { float apply(double a); }
+ @FunctionalInterface
+ public static interface StringInFloatOutLambda { float apply(String a); }
+ //Double Out
+ @FunctionalInterface
+ public static interface BoolInDoubleOutLambda { double apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInDoubleOutLambda { double apply(int a); }
+ @FunctionalInterface
+ public static interface LongInDoubleOutLambda { double apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInDoubleOutLambda { double apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInDoubleOutLambda { double apply(double a); }
+ @FunctionalInterface
+ public static interface StringInDoubleOutLambda { double apply(String a); }
+ //String Out
+ @FunctionalInterface
+ public static interface BoolInStringOutLambda { String apply(boolean a); }
+ @FunctionalInterface
+ public static interface IntInStringOutLambda { String apply(int a); }
+ @FunctionalInterface
+ public static interface LongInStringOutLambda { String apply(long a); }
+ @FunctionalInterface
+ public static interface FloatInStringOutLambda { String apply(float a); }
+ @FunctionalInterface
+ public static interface DoubleInStringOutLambda { String apply(double a); }
+ @FunctionalInterface
+ public static interface StringInStringOutLambda { String apply(String a); }
+
+ /*
+ * Two Parameters
+ */
+ //Boolean Out
+ @FunctionalInterface
+ public static interface TwoBoolInBoolOutLambda { boolean apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInBoolOutLambda { boolean apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInBoolOutLambda { boolean apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInBoolOutLambda { boolean apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInBoolOutLambda { boolean apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInBoolOutLambda { boolean apply(double a, double b); }
+ //Int Out
+ @FunctionalInterface
+ public static interface TwoBoolInIntOutLambda { int apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInIntOutLambda { int apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInIntOutLambda { int apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInIntOutLambda { int apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInIntOutLambda { int apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInIntOutLambda { int apply(double a, double b); }
+ //Long Out
+ @FunctionalInterface
+ public static interface TwoBoolInLongOutLambda { long apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInLongOutLambda { long apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInLongOutLambda { long apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInLongOutLambda { long apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInLongOutLambda { long apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInLongOutLambda { long apply(double a, double b); }
+ //Float Out
+ @FunctionalInterface
+ public static interface TwoBoolInFloatOutLambda { float apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInFloatOutLambda { float apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInFloatOutLambda { float apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInFloatOutLambda { float apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInFloatOutLambda { float apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInFloatOutLambda { float apply(String a, String b); }
+ //Double Out
+ @FunctionalInterface
+ public static interface TwoBoolInDoubleOutLambda { double apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInDoubleOutLambda { double apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInDoubleOutLambda { double apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInDoubleOutLambda { double apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInDoubleOutLambda { double apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInDoubleOutLambda { double apply(String a, String b); }
+ //String Out
+ @FunctionalInterface
+ public static interface TwoBoolInStringOutLambda { String apply(boolean a, boolean b); }
+ @FunctionalInterface
+ public static interface TwoIntInStringOutLambda { String apply(int a, int b); }
+ @FunctionalInterface
+ public static interface TwoLongInStringOutLambda { String apply(long a, long b); }
+ @FunctionalInterface
+ public static interface TwoFloatInStringOutLambda { String apply(float a, float b); }
+ @FunctionalInterface
+ public static interface TwoDoubleInStringOutLambda { String apply(double a, double b); }
+ @FunctionalInterface
+ public static interface TwoStringInStringOutLambda { String apply(String a, String b); }
+}
+class BooleanValueInBooleanValueOutFunction extends AbstractBooleanValue {
+ private final BooleanValue param;
+ private final BoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanValueInBooleanValueOutFunction(String name, BoolInBoolOutLambda lambda, BooleanValue param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = lambda.apply(param.getBoolean());
+ exists = param.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamInBooleanStreamOutFunction extends AbstractBooleanValueStream {
+ private final BooleanValueStream param;
+ private final BoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamInBooleanStreamOutFunction(String name, BoolInBoolOutLambda lambda, BooleanValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ param.streamBooleans(value -> cons.accept(lambda.apply(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamInBooleanValueOutFunction extends AbstractBooleanValue implements BooleanConsumer {
+ private final BooleanValueStream param;
+ private final TwoBoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamInBooleanValueOutFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+ private boolean value;
+
+ @Override
+ public boolean getBoolean() {
+ exists = false;
+ param.streamBooleans(this);
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+ public void accept(boolean paramValue) {
+ if (!exists) {
+ exists = true;
+ value = paramValue;
+ } else {
+ value = lambda.apply(value, paramValue);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class TwoBooleanValueInBooleanValueOutFunction extends AbstractBooleanValue {
+ private final BooleanValue param1;
+ private final BooleanValue param2;
+ private final TwoBoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public TwoBooleanValueInBooleanValueOutFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue param1, BooleanValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = lambda.apply(param1.getBoolean(), param2.getBoolean());
+ exists = param1.exists() && param2.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanValueBooleanStreamInBooleanStreamOutFunction extends AbstractBooleanValueStream {
+ private final BooleanValue param1;
+ private final BooleanValueStream param2;
+ private final TwoBoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanValueBooleanStreamInBooleanStreamOutFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue param1, BooleanValueStream param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean value1 = param1.getBoolean();
+ if (param1.exists()) {
+ param2.streamBooleans(value2 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class BooleanStreamBooleanValueInBooleanStreamOutFunction extends AbstractBooleanValueStream {
+ private final BooleanValueStream param1;
+ private final BooleanValue param2;
+ private final TwoBoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public BooleanStreamBooleanValueInBooleanStreamOutFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValueStream param1, BooleanValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamBooleans(BooleanConsumer cons) {
+ boolean value2 = param2.getBoolean();
+ if (param2.exists()) {
+ param1.streamBooleans(value1 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+abstract class MultiBooleanValueInBooleanValueOutFunction extends AbstractBooleanValue {
+ protected final BooleanValue[] params;
+ protected final TwoBoolInBoolOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public MultiBooleanValueInBooleanValueOutFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue[] params) {
+ this.name = name;
+ this.lambda = lambda;
+ this.params = params;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,params);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,params);
+ }
+
+ protected boolean exists = false;
+ protected boolean temp;
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class MultiBooleanValueInBooleanValueOutRequireAllFunction extends MultiBooleanValueInBooleanValueOutFunction {
+
+ public MultiBooleanValueInBooleanValueOutRequireAllFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public boolean getBoolean() {
+ boolean value = params[0].getBoolean();
+ exists = params[0].exists();
+ for (int i = 1; i < params.length && exists; ++i) {
+ value = lambda.apply(value, params[i].getBoolean());
+ exists = params[i].exists();
+ }
+ return value;
+ }
+}
+class MultiBooleanValueInBooleanValueOutRequireOneFunction extends MultiBooleanValueInBooleanValueOutFunction {
+
+ public MultiBooleanValueInBooleanValueOutRequireOneFunction(String name, TwoBoolInBoolOutLambda lambda, BooleanValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public boolean getBoolean() {
+ int i = -1;
+ boolean value = false;
+ exists = false;
+ while (++i < params.length) {
+ value = params[i].getBoolean();
+ exists = params[i].exists();
+ if (exists) {
+ break;
+ }
+ }
+ while (++i < params.length) {
+ temp = params[i].getBoolean();
+ if (params[i].exists()) {
+ value = lambda.apply(value, temp);
+ }
+ }
+ return value;
+ }
+}
+class IntValueInIntValueOutFunction extends AbstractIntValue {
+ private final IntValue param;
+ private final IntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntValueInIntValueOutFunction(String name, IntInIntOutLambda lambda, IntValue param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = lambda.apply(param.getInt());
+ exists = param.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamInIntStreamOutFunction extends AbstractIntValueStream {
+ private final IntValueStream param;
+ private final IntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamInIntStreamOutFunction(String name, IntInIntOutLambda lambda, IntValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ param.streamInts(value -> cons.accept(lambda.apply(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamInIntValueOutFunction extends AbstractIntValue implements IntConsumer {
+ private final IntValueStream param;
+ private final TwoIntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamInIntValueOutFunction(String name, TwoIntInIntOutLambda lambda, IntValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+ private int value;
+
+ @Override
+ public int getInt() {
+ exists = false;
+ param.streamInts(this);
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+ public void accept(int paramValue) {
+ if (!exists) {
+ exists = true;
+ value = paramValue;
+ } else {
+ value = lambda.apply(value, paramValue);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class TwoIntValueInIntValueOutFunction extends AbstractIntValue {
+ private final IntValue param1;
+ private final IntValue param2;
+ private final TwoIntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public TwoIntValueInIntValueOutFunction(String name, TwoIntInIntOutLambda lambda, IntValue param1, IntValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public int getInt() {
+ int value = lambda.apply(param1.getInt(), param2.getInt());
+ exists = param1.exists() && param2.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntValueIntStreamInIntStreamOutFunction extends AbstractIntValueStream {
+ private final IntValue param1;
+ private final IntValueStream param2;
+ private final TwoIntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntValueIntStreamInIntStreamOutFunction(String name, TwoIntInIntOutLambda lambda, IntValue param1, IntValueStream param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ int value1 = param1.getInt();
+ if (param1.exists()) {
+ param2.streamInts(value2 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class IntStreamIntValueInIntStreamOutFunction extends AbstractIntValueStream {
+ private final IntValueStream param1;
+ private final IntValue param2;
+ private final TwoIntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public IntStreamIntValueInIntStreamOutFunction(String name, TwoIntInIntOutLambda lambda, IntValueStream param1, IntValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamInts(IntConsumer cons) {
+ int value2 = param2.getInt();
+ if (param2.exists()) {
+ param1.streamInts(value1 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+abstract class MultiIntValueInIntValueOutFunction extends AbstractIntValue {
+ protected final IntValue[] params;
+ protected final TwoIntInIntOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public MultiIntValueInIntValueOutFunction(String name, TwoIntInIntOutLambda lambda, IntValue[] params) {
+ this.name = name;
+ this.lambda = lambda;
+ this.params = params;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,params);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,params);
+ }
+
+ protected boolean exists = false;
+ protected int temp;
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class MultiIntValueInIntValueOutRequireAllFunction extends MultiIntValueInIntValueOutFunction {
+
+ public MultiIntValueInIntValueOutRequireAllFunction(String name, TwoIntInIntOutLambda lambda, IntValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public int getInt() {
+ int value = params[0].getInt();
+ exists = params[0].exists();
+ for (int i = 1; i < params.length && exists; ++i) {
+ value = lambda.apply(value, params[i].getInt());
+ exists = params[i].exists();
+ }
+ return value;
+ }
+}
+class MultiIntValueInIntValueOutRequireOneFunction extends MultiIntValueInIntValueOutFunction {
+
+ public MultiIntValueInIntValueOutRequireOneFunction(String name, TwoIntInIntOutLambda lambda, IntValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public int getInt() {
+ int i = -1;
+ int value = 0;
+ exists = false;
+ while (++i < params.length) {
+ value = params[i].getInt();
+ exists = params[i].exists();
+ if (exists) {
+ break;
+ }
+ }
+ while (++i < params.length) {
+ temp = params[i].getInt();
+ if (params[i].exists()) {
+ value = lambda.apply(value, temp);
+ }
+ }
+ return value;
+ }
+}
+class LongValueInLongValueOutFunction extends AbstractLongValue {
+ private final LongValue param;
+ private final LongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongValueInLongValueOutFunction(String name, LongInLongOutLambda lambda, LongValue param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = lambda.apply(param.getLong());
+ exists = param.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamInLongStreamOutFunction extends AbstractLongValueStream {
+ private final LongValueStream param;
+ private final LongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamInLongStreamOutFunction(String name, LongInLongOutLambda lambda, LongValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ param.streamLongs(value -> cons.accept(lambda.apply(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamInLongValueOutFunction extends AbstractLongValue implements LongConsumer {
+ private final LongValueStream param;
+ private final TwoLongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamInLongValueOutFunction(String name, TwoLongInLongOutLambda lambda, LongValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+ private long value;
+
+ @Override
+ public long getLong() {
+ exists = false;
+ param.streamLongs(this);
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+ public void accept(long paramValue) {
+ if (!exists) {
+ exists = true;
+ value = paramValue;
+ } else {
+ value = lambda.apply(value, paramValue);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class TwoLongValueInLongValueOutFunction extends AbstractLongValue {
+ private final LongValue param1;
+ private final LongValue param2;
+ private final TwoLongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public TwoLongValueInLongValueOutFunction(String name, TwoLongInLongOutLambda lambda, LongValue param1, LongValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public long getLong() {
+ long value = lambda.apply(param1.getLong(), param2.getLong());
+ exists = param1.exists() && param2.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongValueLongStreamInLongStreamOutFunction extends AbstractLongValueStream {
+ private final LongValue param1;
+ private final LongValueStream param2;
+ private final TwoLongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongValueLongStreamInLongStreamOutFunction(String name, TwoLongInLongOutLambda lambda, LongValue param1, LongValueStream param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long value1 = param1.getLong();
+ if (param1.exists()) {
+ param2.streamLongs(value2 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class LongStreamLongValueInLongStreamOutFunction extends AbstractLongValueStream {
+ private final LongValueStream param1;
+ private final LongValue param2;
+ private final TwoLongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public LongStreamLongValueInLongStreamOutFunction(String name, TwoLongInLongOutLambda lambda, LongValueStream param1, LongValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamLongs(LongConsumer cons) {
+ long value2 = param2.getLong();
+ if (param2.exists()) {
+ param1.streamLongs(value1 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+abstract class MultiLongValueInLongValueOutFunction extends AbstractLongValue {
+ protected final LongValue[] params;
+ protected final TwoLongInLongOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public MultiLongValueInLongValueOutFunction(String name, TwoLongInLongOutLambda lambda, LongValue[] params) {
+ this.name = name;
+ this.lambda = lambda;
+ this.params = params;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,params);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,params);
+ }
+
+ protected boolean exists = false;
+ protected long temp;
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class MultiLongValueInLongValueOutRequireAllFunction extends MultiLongValueInLongValueOutFunction {
+
+ public MultiLongValueInLongValueOutRequireAllFunction(String name, TwoLongInLongOutLambda lambda, LongValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public long getLong() {
+ long value = params[0].getLong();
+ exists = params[0].exists();
+ for (int i = 1; i < params.length && exists; ++i) {
+ value = lambda.apply(value, params[i].getLong());
+ exists = params[i].exists();
+ }
+ return value;
+ }
+}
+class MultiLongValueInLongValueOutRequireOneFunction extends MultiLongValueInLongValueOutFunction {
+
+ public MultiLongValueInLongValueOutRequireOneFunction(String name, TwoLongInLongOutLambda lambda, LongValue[] params) {
+ super(name, lambda, params);
+ }
+
+ @Override
+ public long getLong() {
+ int i = -1;
+ long value = 0;
+ exists = false;
+ while (++i < params.length) {
+ value = params[i].getLong();
+ exists = params[i].exists();
+ if (exists) {
+ break;
+ }
+ }
+ while (++i < params.length) {
+ temp = params[i].getLong();
+ if (params[i].exists()) {
+ value = lambda.apply(value, temp);
+ }
+ }
+ return value;
+ }
+}
+class FloatValueInFloatValueOutFunction extends AbstractFloatValue {
+ private final FloatValue param;
+ private final FloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatValueInFloatValueOutFunction(String name, FloatInFloatOutLambda lambda, FloatValue param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = lambda.apply(param.getFloat());
+ exists = param.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamInFloatStreamOutFunction extends AbstractFloatValueStream {
+ private final FloatValueStream param;
+ private final FloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamInFloatStreamOutFunction(String name, FloatInFloatOutLambda lambda, FloatValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ param.streamFloats(value -> cons.accept(lambda.apply(value)));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamInFloatValueOutFunction extends AbstractFloatValue implements FloatConsumer {
+ private final FloatValueStream param;
+ private final TwoFloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamInFloatValueOutFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValueStream param) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param = param;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param);
+ }
+
+ private boolean exists = false;
+ private float value;
+
+ @Override
+ public float getFloat() {
+ exists = false;
+ param.streamFloats(this);
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+ public void accept(float paramValue) {
+ if (!exists) {
+ exists = true;
+ value = paramValue;
+ } else {
+ value = lambda.apply(value, paramValue);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class TwoFloatValueInFloatValueOutFunction extends AbstractFloatValue {
+ private final FloatValue param1;
+ private final FloatValue param2;
+ private final TwoFloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public TwoFloatValueInFloatValueOutFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValue param1, FloatValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ private boolean exists = false;
+
+ @Override
+ public float getFloat() {
+ float value = lambda.apply(param1.getFloat(), param2.getFloat());
+ exists = param1.exists() && param2.exists();
+ return value;
+ }
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatValueFloatStreamInFloatStreamOutFunction extends AbstractFloatValueStream {
+ private final FloatValue param1;
+ private final FloatValueStream param2;
+ private final TwoFloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatValueFloatStreamInFloatStreamOutFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValue param1, FloatValueStream param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float value1 = param1.getFloat();
+ if (param1.exists()) {
+ param2.streamFloats(value2 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+class FloatStreamFloatValueInFloatStreamOutFunction extends AbstractFloatValueStream {
+ private final FloatValueStream param1;
+ private final FloatValue param2;
+ private final TwoFloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public FloatStreamFloatValueInFloatStreamOutFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValueStream param1, FloatValue param2) {
+ this.name = name;
+ this.lambda = lambda;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,param1,param2);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,param1,param2);
+ }
+
+ @Override
+ public void streamFloats(FloatConsumer cons) {
+ float value2 = param2.getFloat();
+ if (param2.exists()) {
+ param1.streamFloats(value1 -> cons.accept(lambda.apply(value1,value2)));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ public ExpressionType getExpressionType() {
+ return funcType;
+ }
+}
+abstract class MultiFloatValueInFloatValueOutFunction extends AbstractFloatValue {
+ protected final FloatValue[] params;
+ protected final TwoFloatInFloatOutLambda lambda;
+ private final String name;
+ private final String exprStr;
+ private final ExpressionType funcType;
+
+ public MultiFloatValueInFloatValueOutFunction(String name, TwoFloatInFloatOutLambda lambda, FloatValue[] params) {
+ this.name = name;
+ this.lambda = lambda;
+ this.params = params;
+ this.exprStr = AnalyticsValueStream.createExpressionString(name,params);
+ this.funcType = AnalyticsValueStream.determineMappingPhase(exprStr,params);
+ }
+
+ protected boolean exists = false;
+ protected float temp;
+ @Override
+ public boolean exists() {
+ return exists;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getExpressionStr() {
+ return exprStr;
+ }
+ @Override
+ p
<TRUNCATED>
[08/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionCheckedDataReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionCheckedDataReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionCheckedDataReservation.java
new file mode 100644
index 0000000..73287fe
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionCheckedDataReservation.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.util.function.BooleanSupplier;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+
+/**
+ * A reservation allows a {@link ReductionDataCollector} to specify a piece of data it needs to export from the shard.
+ * This data may, or may not, exist. The {@link ReductionDataCollector} need not check while importing/exporting since
+ * the Reader/Writers handle all checking.
+ */
+public abstract class ReductionCheckedDataReservation<A, E> extends ReductionDataReservation<A, E> {
+ protected final BooleanSupplier exists;
+
+ protected ReductionCheckedDataReservation(A applier, E extractor, BooleanSupplier exists) {
+ super(applier, extractor);
+ this.exists = exists;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataArrayReservation.java
new file mode 100644
index 0000000..cbeece6
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataArrayReservation.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.solr.analytics.stream.reservation;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+
+/**
+ * A reservation allows a {@link ReductionDataCollector} to specify an array of data it needs to export from the shard.
+ */
+public abstract class ReductionDataArrayReservation<A, E> extends ReductionDataReservation<A, E> {
+ protected final IntConsumer sizeApplier;
+ protected final IntSupplier sizeExtractor;
+
+ protected ReductionDataArrayReservation(A applier, IntConsumer sizeApplier, E extractor, IntSupplier sizeExtractor) {
+ super(applier, extractor);
+ this.sizeApplier = sizeApplier;
+ this.sizeExtractor = sizeExtractor;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataReservation.java
new file mode 100644
index 0000000..903016e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/ReductionDataReservation.java
@@ -0,0 +1,53 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+
+import org.apache.solr.analytics.function.reduction.data.ReductionDataCollector;
+import org.apache.solr.analytics.stream.reservation.read.ReductionDataReader;
+import org.apache.solr.analytics.stream.reservation.write.ReductionDataWriter;
+
+/**
+ * A reservation allows a {@link ReductionDataCollector} to specify a piece of data it needs to export from the shard.
+ */
+public abstract class ReductionDataReservation<A, E> {
+ protected final A applier;
+ protected final E extractor;
+
+ protected ReductionDataReservation(A applier, E extractor) {
+ this.applier = applier;
+ this.extractor = extractor;
+ }
+
+ /**
+ * Generate a {@link ReductionDataReader} that merges the set of data this reservation represents.
+ *
+ * @param input the shard input stream
+ * @return a reader from the given input
+ */
+ public abstract ReductionDataReader<A> createReadStream(DataInput input);
+
+ /**
+ * Generate a {@link ReductionDataWriter} that exports the set of data this reservation represents.
+ *
+ * @param output the shard output stream
+ * @return a writer to the given output
+ */
+ public abstract ReductionDataWriter<E> createWriteStream(DataOutput output);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringArrayReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringArrayReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringArrayReservation.java
new file mode 100644
index 0000000..c3c6989
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringArrayReservation.java
@@ -0,0 +1,45 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.apache.solr.analytics.stream.reservation.read.StringDataArrayReader;
+import org.apache.solr.analytics.stream.reservation.write.StringDataArrayWriter;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+public class StringArrayReservation extends ReductionDataArrayReservation<Consumer<String>, Supplier<String>> {
+
+ public StringArrayReservation(Consumer<String> applier, IntConsumer sizeApplier, Supplier<String> extractor, IntSupplier sizeExtractor) {
+ super(applier, sizeApplier, extractor, sizeExtractor);
+ }
+
+ @Override
+ public StringDataArrayReader createReadStream(DataInput input) {
+ return new StringDataArrayReader(input, applier, sizeApplier);
+ }
+
+ @Override
+ public StringDataArrayWriter createWriteStream(DataOutput output) {
+ return new StringDataArrayWriter(output, extractor, sizeExtractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringCheckedReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringCheckedReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringCheckedReservation.java
new file mode 100644
index 0000000..29c3614
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringCheckedReservation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.Supplier;
+
+import org.apache.solr.analytics.stream.reservation.read.StringCheckedDataReader;
+import org.apache.solr.analytics.stream.reservation.write.StringCheckedDataWriter;
+
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+
+public class StringCheckedReservation extends ReductionCheckedDataReservation<Consumer<String>, Supplier<String>> {
+
+ public StringCheckedReservation(Consumer<String> applier, Supplier<String> extractor, BooleanSupplier exists) {
+ super(applier, extractor, exists);
+ }
+
+ @Override
+ public StringCheckedDataReader createReadStream(DataInput input) {
+ return new StringCheckedDataReader(input, applier);
+ }
+
+ @Override
+ public StringCheckedDataWriter createWriteStream(DataOutput output) {
+ return new StringCheckedDataWriter(output, extractor, exists);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringReservation.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringReservation.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringReservation.java
new file mode 100644
index 0000000..2601874
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/StringReservation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.analytics.stream.reservation;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.util.function.Supplier;
+
+import org.apache.solr.analytics.stream.reservation.read.StringDataReader;
+import org.apache.solr.analytics.stream.reservation.write.StringDataWriter;
+
+import java.util.function.Consumer;
+
+public class StringReservation extends ReductionDataReservation<Consumer<String>, Supplier<String>> {
+
+ public StringReservation(Consumer<String> applier, Supplier<String> extractor) {
+ super(applier, extractor);
+ }
+
+ @Override
+ public StringDataReader createReadStream(DataInput input) {
+ return new StringDataReader(input, applier);
+ }
+
+ @Override
+ public StringDataWriter createWriteStream(DataOutput output) {
+ return new StringDataWriter(output, extractor);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/package-info.java
new file mode 100644
index 0000000..bfd832d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Reservation classes for a single type of data being stored by one Reduction Data Collector.
+ * These reservations are imported/exported between shards during the streaming process.
+ */
+package org.apache.solr.analytics.stream.reservation;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanCheckedDataReader.java
new file mode 100644
index 0000000..49f6f00
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanCheckedDataReader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanCheckedDataReader extends ReductionCheckedDataReader<BooleanConsumer> {
+
+ public BooleanCheckedDataReader(DataInput inputStream, BooleanConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readBoolean());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataArrayReader.java
new file mode 100644
index 0000000..ee929f4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataArrayReader.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.solr.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanDataArrayReader extends ReductionDataArrayReader<BooleanConsumer> {
+
+ public BooleanDataArrayReader(DataInput inputStream, BooleanConsumer applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readBoolean());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataReader.java
new file mode 100644
index 0000000..98e116d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/BooleanDataReader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.solr.analytics.util.function.BooleanConsumer;
+
+public class BooleanDataReader extends ReductionDataReader<BooleanConsumer> {
+
+ public BooleanDataReader(DataInput inputStream, BooleanConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ applier.accept(inputStream.readBoolean());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleCheckedDataReader.java
new file mode 100644
index 0000000..ec6a6e4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleCheckedDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.DoubleConsumer;
+
+public class DoubleCheckedDataReader extends ReductionCheckedDataReader<DoubleConsumer> {
+
+ public DoubleCheckedDataReader(DataInput inputStream, DoubleConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readDouble());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataArrayReader.java
new file mode 100644
index 0000000..5690a45
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataArrayReader.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+
+public class DoubleDataArrayReader extends ReductionDataArrayReader<DoubleConsumer> {
+
+ public DoubleDataArrayReader(DataInput inputStream, DoubleConsumer applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readDouble());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataReader.java
new file mode 100644
index 0000000..42de9bf
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/DoubleDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.DoubleConsumer;
+
+public class DoubleDataReader extends ReductionDataReader<DoubleConsumer> {
+
+ public DoubleDataReader(DataInput inputStream, DoubleConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ applier.accept(inputStream.readDouble());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatCheckedDataReader.java
new file mode 100644
index 0000000..8139cfb
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatCheckedDataReader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+public class FloatCheckedDataReader extends ReductionCheckedDataReader<FloatConsumer> {
+
+ public FloatCheckedDataReader(DataInput inputStream, FloatConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readFloat());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataArrayReader.java
new file mode 100644
index 0000000..1157a11
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataArrayReader.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.solr.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+public class FloatDataArrayReader extends ReductionDataArrayReader<FloatConsumer> {
+
+ public FloatDataArrayReader(DataInput inputStream, FloatConsumer applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readFloat());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataReader.java
new file mode 100644
index 0000000..63067cd
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/FloatDataReader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.solr.analytics.util.function.FloatConsumer;
+
+public class FloatDataReader extends ReductionDataReader<FloatConsumer> {
+
+ public FloatDataReader(DataInput inputStream, FloatConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ applier.accept(inputStream.readFloat());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntCheckedDataReader.java
new file mode 100644
index 0000000..e926e3e
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntCheckedDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+public class IntCheckedDataReader extends ReductionCheckedDataReader<IntConsumer> {
+
+ public IntCheckedDataReader(DataInput inputStream, IntConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readInt());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataArrayReader.java
new file mode 100644
index 0000000..a0c1d86
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataArrayReader.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+public class IntDataArrayReader extends ReductionDataArrayReader<IntConsumer> {
+
+ public IntDataArrayReader(DataInput inputStream, IntConsumer applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readInt());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataReader.java
new file mode 100644
index 0000000..5b65055
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/IntDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+public class IntDataReader extends ReductionDataReader<IntConsumer> {
+
+ public IntDataReader(DataInput inputStream, IntConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ applier.accept(inputStream.readInt());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongCheckedDataReader.java
new file mode 100644
index 0000000..7d9a7ff
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongCheckedDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.LongConsumer;
+
+public class LongCheckedDataReader extends ReductionCheckedDataReader<LongConsumer> {
+
+ public LongCheckedDataReader(DataInput inputStream, LongConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readLong());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataArrayReader.java
new file mode 100644
index 0000000..6c09f46
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataArrayReader.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+public class LongDataArrayReader extends ReductionDataArrayReader<LongConsumer> {
+
+ public LongDataArrayReader(DataInput inputStream, LongConsumer applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readLong());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataReader.java
new file mode 100644
index 0000000..bf4057d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/LongDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.LongConsumer;
+
+public class LongDataReader extends ReductionDataReader<LongConsumer> {
+
+ public LongDataReader(DataInput inputStream, LongConsumer applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ applier.accept(inputStream.readLong());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionCheckedDataReader.java
new file mode 100644
index 0000000..ac98987
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionCheckedDataReader.java
@@ -0,0 +1,54 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Abstract class to manage the reading and application of data from a {@link DataInput} stream.
+ * The data being read may not exist, so the reader first checks before reading.
+ */
+public abstract class ReductionCheckedDataReader<A> extends ReductionDataReader<A> {
+
+ public ReductionCheckedDataReader(DataInput inputStream, A applier) {
+ super(inputStream, applier);
+ }
+
+ @Override
+ /**
+ * Read a piece of data from the input stream and feed it to the applier.
+ * <br>
+ * First checks that the piece of data exists before reading.
+ *
+ * @throws IOException if an exception occurs while reading from the input stream
+ */
+ public void read() throws IOException {
+ if (inputStream.readBoolean()) {
+ checkedRead();
+ }
+ }
+
+ /**
+ * Read a piece of data from the input stream and feed it to the applier.
+ * <br>
+ * This piece of data is guaranteed to be there.
+ *
+ * @throws IOException if an exception occurs while reading from the input stream
+ */
+ protected abstract void checkedRead() throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataArrayReader.java
new file mode 100644
index 0000000..2a696d7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataArrayReader.java
@@ -0,0 +1,54 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+
+/**
+ * Abstract class to manage the reading and application of array data from a {@link DataInput} stream.
+ */
+public abstract class ReductionDataArrayReader<A> extends ReductionDataReader<A> {
+ protected final IntConsumer signal;
+
+ public ReductionDataArrayReader(DataInput inputStream, A applier, IntConsumer signal) {
+ super(inputStream, applier);
+
+ this.signal = signal;
+ }
+
+ @Override
+ /**
+ * Read an array of data from the input stream and feed it to the applier, first signaling the size of the array.
+ *
+ * @throws IOException if an exception occurs while reading from the input stream
+ */
+ public void read() throws IOException {
+ int size = inputStream.readInt();
+ signal.accept(size);
+ read(size);
+ }
+
+ /**
+ * Read an array from the input stream, feeding each member to the applier.
+ *
+ * @param size length of the array to read
+ * @throws IOException if an exception occurs while reading from the input stream
+ */
+ protected abstract void read(int size) throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataReader.java
new file mode 100644
index 0000000..ec99621
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/ReductionDataReader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Abstract class to manage the reading and application of data from a {@link DataInput} stream.
+ */
+public abstract class ReductionDataReader<A> {
+ protected final DataInput inputStream;
+ protected final A applier;
+
+ public ReductionDataReader(DataInput inputStream, A applier) {
+ this.inputStream = inputStream;
+ this.applier = applier;
+ }
+
+ /**
+ * Read a piece of data from the input stream and feed it to the applier.
+ *
+ * @throws IOException if an exception occurs while reading from the input stream
+ */
+ public abstract void read() throws IOException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringCheckedDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringCheckedDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringCheckedDataReader.java
new file mode 100644
index 0000000..400e990
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringCheckedDataReader.java
@@ -0,0 +1,32 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.Consumer;
+
+public class StringCheckedDataReader extends ReductionCheckedDataReader<Consumer<String>> {
+
+ public StringCheckedDataReader(DataInput inputStream, Consumer<String> applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void checkedRead() throws IOException {
+ applier.accept(inputStream.readUTF());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataArrayReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataArrayReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataArrayReader.java
new file mode 100644
index 0000000..048b84f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataArrayReader.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+
+public class StringDataArrayReader extends ReductionDataArrayReader<Consumer<String>> {
+
+ public StringDataArrayReader(DataInput inputStream, Consumer<String> applier, IntConsumer signal) {
+ super(inputStream, applier, signal);
+ }
+ @Override
+ public void read(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ applier.accept(inputStream.readUTF());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataReader.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataReader.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataReader.java
new file mode 100644
index 0000000..d4d6bc4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/StringDataReader.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.read;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.function.Consumer;
+
+public class StringDataReader extends ReductionDataReader<Consumer<String>> {
+
+ public StringDataReader(DataInput inputStream, Consumer<String> applier) {
+ super(inputStream, applier);
+ }
+ @Override
+ public void read() throws IOException {
+ if (inputStream.readBoolean()) {
+ applier.accept(inputStream.readUTF());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/package-info.java
new file mode 100644
index 0000000..26bb7c5
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/read/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Reading classes for a single type of data being stored by one Reduction Data Collector.
+ * These writers are used to import data from shards during the streaming process.
+ */
+package org.apache.solr.analytics.stream.reservation.read;
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanCheckedDataWriter.java
new file mode 100644
index 0000000..6b4c1b7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanCheckedDataWriter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+
+public class BooleanCheckedDataWriter extends ReductionCheckedDataWriter<BooleanSupplier> {
+
+ public BooleanCheckedDataWriter(DataOutput output, BooleanSupplier extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeBoolean(extractor.getAsBoolean());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataArrayWriter.java
new file mode 100644
index 0000000..c188770
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataArrayWriter.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.solr.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+import java.util.function.IntSupplier;
+
+public class BooleanDataArrayWriter extends ReductionDataArrayWriter<BooleanSupplier> {
+
+ public BooleanDataArrayWriter(DataOutput output, BooleanSupplier extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeBoolean(extractor.getAsBoolean());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataWriter.java
new file mode 100644
index 0000000..f921a5d
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/BooleanDataWriter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+
+public class BooleanDataWriter extends ReductionDataWriter<BooleanSupplier> {
+
+ public BooleanDataWriter(DataOutput output, BooleanSupplier extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ output.writeBoolean(extractor.getAsBoolean());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleCheckedDataWriter.java
new file mode 100644
index 0000000..376afee
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleCheckedDataWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+import java.util.function.DoubleSupplier;
+
+public class DoubleCheckedDataWriter extends ReductionCheckedDataWriter<DoubleSupplier> {
+
+ public DoubleCheckedDataWriter(DataOutput output, DoubleSupplier extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeDouble(extractor.getAsDouble());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataArrayWriter.java
new file mode 100644
index 0000000..830ceee
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataArrayWriter.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.solr.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+
+public class DoubleDataArrayWriter extends ReductionDataArrayWriter<DoubleSupplier> {
+
+ public DoubleDataArrayWriter(DataOutput output, DoubleSupplier extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeDouble(extractor.getAsDouble());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataWriter.java
new file mode 100644
index 0000000..074b859
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/DoubleDataWriter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.DoubleSupplier;
+
+public class DoubleDataWriter extends ReductionDataWriter<DoubleSupplier> {
+
+ public DoubleDataWriter(DataOutput output, DoubleSupplier extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ output.writeDouble(extractor.getAsDouble());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatCheckedDataWriter.java
new file mode 100644
index 0000000..69c74b9
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatCheckedDataWriter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatCheckedDataWriter extends ReductionCheckedDataWriter<FloatSupplier> {
+
+ public FloatCheckedDataWriter(DataOutput output, FloatSupplier extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeFloat(extractor.getAsFloat());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataArrayWriter.java
new file mode 100644
index 0000000..0fd0d25
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataArrayWriter.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatDataArrayWriter extends ReductionDataArrayWriter<FloatSupplier> {
+
+ public FloatDataArrayWriter(DataOutput output, FloatSupplier extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeFloat(extractor.getAsFloat());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataWriter.java
new file mode 100644
index 0000000..bc23f21
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/FloatDataWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.solr.analytics.util.function.FloatSupplier;
+
+public class FloatDataWriter extends ReductionDataWriter<FloatSupplier> {
+
+ public FloatDataWriter(DataOutput output, FloatSupplier extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ output.writeFloat(extractor.getAsFloat());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntCheckedDataWriter.java
new file mode 100644
index 0000000..fd55cf7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntCheckedDataWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+import java.util.function.IntSupplier;
+
+public class IntCheckedDataWriter extends ReductionCheckedDataWriter<IntSupplier> {
+
+ public IntCheckedDataWriter(DataOutput output, IntSupplier extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeInt(extractor.getAsInt());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataArrayWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataArrayWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataArrayWriter.java
new file mode 100644
index 0000000..144b27f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataArrayWriter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+
+public class IntDataArrayWriter extends ReductionDataArrayWriter<IntSupplier> {
+
+ public IntDataArrayWriter(DataOutput output, IntSupplier extractor, IntSupplier sizeSupplier) {
+ super(output, extractor, sizeSupplier);
+ }
+
+ @Override
+ public void write(int size) throws IOException {
+ for (int i = 0; i < size; ++i) {
+ output.writeInt(extractor.getAsInt());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataWriter.java
new file mode 100644
index 0000000..fd2420a
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/IntDataWriter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.IntSupplier;
+
+public class IntDataWriter extends ReductionDataWriter<IntSupplier> {
+
+ public IntDataWriter(DataOutput output, IntSupplier extractor) {
+ super(output, extractor);
+ }
+
+ @Override
+ public void write() throws IOException {
+ output.writeInt(extractor.getAsInt());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongCheckedDataWriter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongCheckedDataWriter.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongCheckedDataWriter.java
new file mode 100644
index 0000000..e148e40
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/stream/reservation/write/LongCheckedDataWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analytics.stream.reservation.write;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.BooleanSupplier;
+import java.util.function.LongSupplier;
+
+public class LongCheckedDataWriter extends ReductionCheckedDataWriter<LongSupplier> {
+
+ public LongCheckedDataWriter(DataOutput output, LongSupplier extractor, BooleanSupplier existsSupplier) {
+ super(output, extractor, existsSupplier);
+ }
+
+ @Override
+ public void checkedWrite() throws IOException {
+ output.writeLong(extractor.getAsLong());
+ }
+}
\ No newline at end of file
[20/20] lucene-solr:master: SOLR-10123: Upgraded the Analytics
Component to version 2.0
Posted by dp...@apache.org.
SOLR-10123: Upgraded the Analytics Component to version 2.0
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/d5963beb
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/d5963beb
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/d5963beb
Branch: refs/heads/master
Commit: d5963bebc43bdb712f2f1e9a29f944370f079b5f
Parents: 85a27a2
Author: Dennis Gove <dp...@gmail.com>
Authored: Wed Jun 28 09:39:47 2017 -0400
Committer: Dennis Gove <dp...@gmail.com>
Committed: Wed Jun 28 14:13:37 2017 -0400
----------------------------------------------------------------------
solr/CHANGES.txt | 8 +
.../apache/solr/analytics/AnalyticsDriver.java | 82 +
.../solr/analytics/AnalyticsExpression.java | 64 +
.../analytics/AnalyticsGroupingManager.java | 239 ++
.../solr/analytics/AnalyticsRequestManager.java | 279 ++
.../solr/analytics/AnalyticsRequestParser.java | 549 +++
.../solr/analytics/ExpressionFactory.java | 821 +++++
.../analytics/accumulator/BasicAccumulator.java | 173 -
.../accumulator/FacetingAccumulator.java | 730 ----
.../analytics/accumulator/ValueAccumulator.java | 40 -
.../facet/FacetValueAccumulator.java | 35 -
.../facet/FieldFacetAccumulator.java | 153 -
.../facet/QueryFacetAccumulator.java | 72 -
.../facet/RangeFacetAccumulator.java | 49 -
.../accumulator/facet/package-info.java | 24 -
.../analytics/accumulator/package-info.java | 23 -
.../analytics/expression/BaseExpression.java | 88 -
.../expression/DualDelegateExpression.java | 99 -
.../solr/analytics/expression/Expression.java | 39 -
.../analytics/expression/ExpressionFactory.java | 175 -
.../expression/MultiDelegateExpression.java | 131 -
.../expression/SingleDelegateExpression.java | 88 -
.../solr/analytics/expression/package-info.java | 23 -
.../analytics/facet/AbstractSolrQueryFacet.java | 104 +
.../solr/analytics/facet/AnalyticsFacet.java | 166 +
.../apache/solr/analytics/facet/PivotFacet.java | 114 +
.../apache/solr/analytics/facet/PivotNode.java | 263 ++
.../apache/solr/analytics/facet/QueryFacet.java | 64 +
.../apache/solr/analytics/facet/RangeFacet.java | 119 +
.../solr/analytics/facet/SortableFacet.java | 178 +
.../solr/analytics/facet/StreamingFacet.java | 32 +
.../apache/solr/analytics/facet/ValueFacet.java | 60 +
.../facet/compare/ConstantComparator.java | 30 +
.../facet/compare/DelegatingComparator.java | 62 +
.../facet/compare/ExpressionComparator.java | 46 +
.../facet/compare/FacetResultsComparator.java | 52 +
.../facet/compare/FacetValueComparator.java | 37 +
.../analytics/facet/compare/package-info.java | 23 +
.../solr/analytics/facet/package-info.java | 23 +
.../function/ExpressionCalculator.java | 71 +
.../MergingReductionCollectionManager.java | 46 +
.../function/ReductionCollectionManager.java | 320 ++
.../analytics/function/ReductionFunction.java | 37 +
.../function/field/AnalyticsField.java | 69 +
.../analytics/function/field/BooleanField.java | 111 +
.../function/field/BooleanMultiField.java | 101 +
.../analytics/function/field/DateField.java | 108 +
.../function/field/DateMultiField.java | 47 +
.../function/field/DateMultiPointField.java | 47 +
.../analytics/function/field/DoubleField.java | 97 +
.../function/field/DoubleMultiField.java | 85 +
.../function/field/DoubleMultiPointField.java | 81 +
.../analytics/function/field/FloatField.java | 108 +
.../function/field/FloatMultiField.java | 91 +
.../function/field/FloatMultiPointField.java | 87 +
.../solr/analytics/function/field/IntField.java | 129 +
.../analytics/function/field/IntMultiField.java | 100 +
.../function/field/IntMultiPointField.java | 96 +
.../analytics/function/field/LongField.java | 107 +
.../function/field/LongMultiField.java | 89 +
.../function/field/LongMultiPointField.java | 86 +
.../analytics/function/field/StringField.java | 85 +
.../function/field/StringMultiField.java | 66 +
.../analytics/function/field/package-info.java | 23 +
.../function/mapping/AbsoluteValueFunction.java | 54 +
.../analytics/function/mapping/AddFunction.java | 68 +
.../function/mapping/BottomFunction.java | 163 +
.../function/mapping/CompareFunction.java | 614 ++++
.../function/mapping/ConcatFunction.java | 78 +
.../function/mapping/DateMathFunction.java | 156 +
.../function/mapping/DateParseFunction.java | 210 ++
.../function/mapping/DivideFunction.java | 51 +
.../function/mapping/FillMissingFunction.java | 842 +++++
.../function/mapping/FilterFunction.java | 722 ++++
.../analytics/function/mapping/IfFunction.java | 892 +++++
.../function/mapping/JoinFunction.java | 57 +
.../function/mapping/LambdaFunction.java | 3220 ++++++++++++++++++
.../analytics/function/mapping/LogFunction.java | 51 +
.../function/mapping/LogicFunction.java | 90 +
.../function/mapping/MultFunction.java | 68 +
.../function/mapping/NegateFunction.java | 58 +
.../mapping/NumericConvertFunction.java | 256 ++
.../function/mapping/PowerFunction.java | 51 +
.../function/mapping/RemoveFunction.java | 796 +++++
.../function/mapping/ReplaceFunction.java | 914 +++++
.../function/mapping/StringCastFunction.java | 42 +
.../function/mapping/SubtractFunction.java | 51 +
.../analytics/function/mapping/TopFunction.java | 163 +
.../function/mapping/package-info.java | 23 +
.../solr/analytics/function/package-info.java | 23 +
.../function/reduction/CountFunction.java | 87 +
.../function/reduction/DocCountFunction.java | 87 +
.../function/reduction/MaxFunction.java | 298 ++
.../function/reduction/MedianFunction.java | 200 ++
.../function/reduction/MinFunction.java | 298 ++
.../function/reduction/MissingFunction.java | 76 +
.../function/reduction/OrdinalFunction.java | 386 +++
.../function/reduction/PercentileFunction.java | 337 ++
.../function/reduction/SumFunction.java | 92 +
.../function/reduction/UniqueFunction.java | 101 +
.../function/reduction/data/CountCollector.java | 188 +
.../function/reduction/data/MaxCollector.java | 476 +++
.../function/reduction/data/MinCollector.java | 476 +++
.../function/reduction/data/ReductionData.java | 24 +
.../reduction/data/ReductionDataCollector.java | 183 +
.../reduction/data/SortedListCollector.java | 363 ++
.../function/reduction/data/SumCollector.java | 124 +
.../reduction/data/UniqueCollector.java | 241 ++
.../function/reduction/data/package-info.java | 24 +
.../function/reduction/package-info.java | 23 +
.../org/apache/solr/analytics/package-info.java | 23 +
.../request/AbstractFieldFacetRequest.java | 42 -
.../request/AnalyticsContentHandler.java | 314 --
.../analytics/request/AnalyticsRequest.java | 114 -
.../request/AnalyticsRequestFactory.java | 308 --
.../solr/analytics/request/AnalyticsStats.java | 138 -
.../analytics/request/ExpressionRequest.java | 72 -
.../solr/analytics/request/FacetRequest.java | 26 -
.../analytics/request/FieldFacetRequest.java | 172 -
.../analytics/request/QueryFacetRequest.java | 74 -
.../analytics/request/RangeFacetRequest.java | 129 -
.../solr/analytics/request/package-info.java | 24 -
.../AbstractDelegatingStatsCollector.java | 74 -
.../statistics/MedianStatsCollector.java | 76 -
.../statistics/MinMaxStatsCollector.java | 114 -
.../statistics/NumericStatsCollector.java | 68 -
.../statistics/PercentileStatsCollector.java | 80 -
.../analytics/statistics/StatsCollector.java | 69 -
.../StatsCollectorSupplierFactory.java | 646 ----
.../statistics/UniqueStatsCollector.java | 53 -
.../solr/analytics/statistics/package-info.java | 24 -
.../stream/AnalyticsShardRequestManager.java | 245 ++
.../stream/AnalyticsShardResponseParser.java | 89 +
.../solr/analytics/stream/package-info.java | 23 +
.../reservation/BooleanArrayReservation.java | 44 +
.../reservation/BooleanCheckedReservation.java | 42 +
.../stream/reservation/BooleanReservation.java | 42 +
.../reservation/DoubleArrayReservation.java | 44 +
.../reservation/DoubleCheckedReservation.java | 43 +
.../stream/reservation/DoubleReservation.java | 42 +
.../reservation/FloatArrayReservation.java | 44 +
.../reservation/FloatCheckedReservation.java | 43 +
.../stream/reservation/FloatReservation.java | 42 +
.../stream/reservation/IntArrayReservation.java | 42 +
.../reservation/IntCheckedReservation.java | 43 +
.../stream/reservation/IntReservation.java | 42 +
.../reservation/LongArrayReservation.java | 45 +
.../reservation/LongCheckedReservation.java | 43 +
.../stream/reservation/LongReservation.java | 42 +
.../ReductionCheckedDataReservation.java | 35 +
.../ReductionDataArrayReservation.java | 36 +
.../reservation/ReductionDataReservation.java | 53 +
.../reservation/StringArrayReservation.java | 45 +
.../reservation/StringCheckedReservation.java | 44 +
.../stream/reservation/StringReservation.java | 43 +
.../stream/reservation/package-info.java | 24 +
.../read/BooleanCheckedDataReader.java | 33 +
.../read/BooleanDataArrayReader.java | 36 +
.../reservation/read/BooleanDataReader.java | 33 +
.../read/DoubleCheckedDataReader.java | 32 +
.../reservation/read/DoubleDataArrayReader.java | 35 +
.../reservation/read/DoubleDataReader.java | 32 +
.../read/FloatCheckedDataReader.java | 33 +
.../reservation/read/FloatDataArrayReader.java | 36 +
.../reservation/read/FloatDataReader.java | 33 +
.../reservation/read/IntCheckedDataReader.java | 32 +
.../reservation/read/IntDataArrayReader.java | 34 +
.../stream/reservation/read/IntDataReader.java | 32 +
.../reservation/read/LongCheckedDataReader.java | 32 +
.../reservation/read/LongDataArrayReader.java | 35 +
.../stream/reservation/read/LongDataReader.java | 32 +
.../read/ReductionCheckedDataReader.java | 54 +
.../read/ReductionDataArrayReader.java | 54 +
.../reservation/read/ReductionDataReader.java | 40 +
.../read/StringCheckedDataReader.java | 32 +
.../reservation/read/StringDataArrayReader.java | 35 +
.../reservation/read/StringDataReader.java | 34 +
.../stream/reservation/read/package-info.java | 24 +
.../write/BooleanCheckedDataWriter.java | 33 +
.../write/BooleanDataArrayWriter.java | 36 +
.../reservation/write/BooleanDataWriter.java | 33 +
.../write/DoubleCheckedDataWriter.java | 34 +
.../write/DoubleDataArrayWriter.java | 36 +
.../reservation/write/DoubleDataWriter.java | 33 +
.../write/FloatCheckedDataWriter.java | 35 +
.../reservation/write/FloatDataArrayWriter.java | 37 +
.../reservation/write/FloatDataWriter.java | 34 +
.../reservation/write/IntCheckedDataWriter.java | 34 +
.../reservation/write/IntDataArrayWriter.java | 35 +
.../stream/reservation/write/IntDataWriter.java | 33 +
.../write/LongCheckedDataWriter.java | 34 +
.../reservation/write/LongDataArrayWriter.java | 36 +
.../reservation/write/LongDataWriter.java | 33 +
.../write/ReductionCheckedDataWriter.java | 60 +
.../write/ReductionDataArrayWriter.java | 53 +
.../reservation/write/ReductionDataWriter.java | 40 +
.../write/StringCheckedDataWriter.java | 34 +
.../write/StringDataArrayWriter.java | 36 +
.../reservation/write/StringDataWriter.java | 37 +
.../stream/reservation/write/package-info.java | 24 +
.../solr/analytics/util/AnalyticsParams.java | 114 -
.../solr/analytics/util/AnalyticsParsers.java | 171 -
.../util/AnalyticsResponseHeadings.java | 36 +
.../analytics/util/FacetRangeGenerator.java | 356 ++
.../solr/analytics/util/MedianCalculator.java | 4 +
.../solr/analytics/util/OldAnalyticsParams.java | 177 +
.../util/OldAnalyticsRequestConverter.java | 177 +
.../solr/analytics/util/OrdinalCalculator.java | 173 +
.../analytics/util/PercentileCalculator.java | 176 -
.../analytics/util/RangeEndpointCalculator.java | 354 --
.../util/function/BooleanConsumer.java | 59 +
.../analytics/util/function/FloatConsumer.java | 59 +
.../analytics/util/function/FloatSupplier.java | 41 +
.../analytics/util/function/package-info.java | 23 +
.../solr/analytics/util/package-info.java | 3 +-
.../AbsoluteValueDoubleFunction.java | 60 -
.../util/valuesource/AddDoubleFunction.java | 49 -
.../util/valuesource/ConstDateSource.java | 112 -
.../util/valuesource/ConstDoubleSource.java | 104 -
.../util/valuesource/ConstStringSource.java | 50 -
.../util/valuesource/DateFieldSource.java | 131 -
.../util/valuesource/DateMathFunction.java | 71 -
.../util/valuesource/DivDoubleFunction.java | 48 -
.../util/valuesource/DualDoubleFunction.java | 94 -
.../util/valuesource/FilterFieldSource.java | 154 -
.../util/valuesource/LogDoubleFunction.java | 43 -
.../util/valuesource/MultiDateFunction.java | 133 -
.../util/valuesource/MultiDoubleFunction.java | 119 -
.../valuesource/MultiplyDoubleFunction.java | 49 -
.../util/valuesource/NegateDoubleFunction.java | 55 -
.../util/valuesource/PowDoubleFunction.java | 48 -
.../util/valuesource/ReverseStringFunction.java | 45 -
.../util/valuesource/SingleDoubleFunction.java | 79 -
.../util/valuesource/SingleStringFunction.java | 117 -
.../util/valuesource/package-info.java | 24 -
.../solr/analytics/value/AnalyticsValue.java | 55 +
.../analytics/value/AnalyticsValueStream.java | 133 +
.../solr/analytics/value/BooleanValue.java | 85 +
.../analytics/value/BooleanValueStream.java | 55 +
.../solr/analytics/value/ComparableValue.java | 32 +
.../apache/solr/analytics/value/DateValue.java | 102 +
.../solr/analytics/value/DateValueStream.java | 62 +
.../solr/analytics/value/DoubleValue.java | 86 +
.../solr/analytics/value/DoubleValueStream.java | 54 +
.../apache/solr/analytics/value/FloatValue.java | 97 +
.../solr/analytics/value/FloatValueStream.java | 60 +
.../apache/solr/analytics/value/IntValue.java | 121 +
.../solr/analytics/value/IntValueStream.java | 71 +
.../apache/solr/analytics/value/LongValue.java | 97 +
.../solr/analytics/value/LongValueStream.java | 60 +
.../solr/analytics/value/StringValue.java | 71 +
.../solr/analytics/value/StringValueStream.java | 49 +
.../value/constant/ConstantBooleanValue.java | 91 +
.../value/constant/ConstantDateValue.java | 103 +
.../value/constant/ConstantDoubleValue.java | 90 +
.../value/constant/ConstantFloatValue.java | 99 +
.../value/constant/ConstantIntValue.java | 118 +
.../value/constant/ConstantLongValue.java | 100 +
.../value/constant/ConstantStringValue.java | 79 +
.../analytics/value/constant/ConstantValue.java | 128 +
.../analytics/value/constant/package-info.java | 23 +
.../solr/analytics/value/package-info.java | 23 +
.../apache/solr/handler/AnalyticsHandler.java | 147 +
.../handler/component/AnalyticsComponent.java | 119 +-
.../java/org/apache/solr/handler/package.html | 28 +
.../response/AnalyticsShardResponseWriter.java | 91 +
.../java/org/apache/solr/response/package.html | 28 +
.../analytics/requestFiles/expressions.txt | 70 -
.../analytics/requestFiles/fieldFacetExtras.txt | 66 -
.../analytics/requestFiles/fieldFacets.txt | 132 -
.../analytics/requestFiles/functions.txt | 62 -
.../analytics/requestFiles/noFacets.txt | 74 -
.../analytics/requestFiles/queryFacets.txt | 45 -
.../analytics/requestFiles/rangeFacets.txt | 170 -
.../analytics/requestXMLFiles/expressions.xml | 285 --
.../requestXMLFiles/fieldFacetExtras.xml | 101 -
.../analytics/requestXMLFiles/fieldFacets.xml | 496 ---
.../analytics/requestXMLFiles/functions.xml | 246 --
.../analytics/requestXMLFiles/noFacets.xml | 310 --
.../analytics/requestXMLFiles/queryFacets.xml | 94 -
.../analytics/requestXMLFiles/rangeFacets.xml | 319 --
.../test-files/solr/analytics/expressions.txt | 65 +
.../test-files/solr/analytics/facetSorting.txt | 4 +
.../solr/analytics/fieldFacetExtras.txt | 66 +
.../test-files/solr/analytics/fieldFacets.txt | 132 +
.../src/test-files/solr/analytics/functions.txt | 57 +
.../src/test-files/solr/analytics/noFacets.txt | 74 +
.../test-files/solr/analytics/queryFacets.txt | 27 +
.../test-files/solr/analytics/rangeFacets.txt | 161 +
.../solr/collection1/conf/schema-analytics.xml | 7 +-
.../collection1/conf/solrconfig-analytics.xml | 42 +
.../solr/collection1/conf/solrconfig-basic.xml | 40 -
.../configsets/cloud-analytics/conf/schema.xml | 63 +
.../cloud-analytics/conf/solrconfig.xml | 59 +
.../AbstractAnalyticsStatsCloudTest.java | 187 +
.../analytics/AbstractAnalyticsStatsTest.java | 14 +-
.../apache/solr/analytics/NoFacetCloudTest.java | 557 +++
.../org/apache/solr/analytics/NoFacetTest.java | 46 +-
.../analytics/expression/ExpressionTest.java | 70 +-
.../solr/analytics/expression/FunctionTest.java | 221 ++
.../facet/AbstractAnalyticsFacetCloudTest.java | 284 ++
.../facet/AbstractAnalyticsFacetTest.java | 37 +-
.../solr/analytics/facet/FacetSortingTest.java | 53 +
.../analytics/facet/FieldFacetCloudTest.java | 1214 +++++++
.../facet/FieldFacetExtrasCloudTest.java | 253 ++
.../analytics/facet/FieldFacetExtrasTest.java | 6 +-
.../solr/analytics/facet/FieldFacetTest.java | 63 +-
.../analytics/facet/QueryFacetCloudTest.java | 159 +
.../solr/analytics/facet/QueryFacetTest.java | 10 +-
.../analytics/facet/RangeFacetCloudTest.java | 588 ++++
.../solr/analytics/facet/RangeFacetTest.java | 43 +-
.../util/valuesource/FunctionTest.java | 233 --
.../solr/handler/component/ResponseBuilder.java | 3 +
313 files changed, 30374 insertions(+), 9933 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 208512c..9578698 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -116,6 +116,10 @@ Upgrading from Solr 6.x
curl http://host:8983/solr/mycollection/config -d '{"set-user-property": {"update.autoCreateFields":"false"}}'
Please see SOLR-10574 for details.
+* SOLR-10123: The Analytics Component has been upgraded to support distributed collections, expressions over multivalued
+ fields, a new JSON request language, and more. DocValues are now required for any field used in the analytics expression
+ whereas previously docValues was not required. Please see SOLR-10123 for details.
+
New Features
----------------------
* SOLR-9857, SOLR-9858: Collect aggregated metrics from nodes and shard leaders in overseer. (ab)
@@ -175,6 +179,10 @@ New Features
* SOLR-10272: Use _default config set if no collection.configName is specified with CREATE (Ishan Chattopadhyaya)
+* SOLR-10123: Upgraded the Analytics Component to version 2.0 which now supports distributed collections, expressions over
+ multivalued fields, a new JSON request language, and more. DocValues are now required for any field used in the analytics
+ expression whereas previously docValues was not required. Please see SOLR-10123 for details. (Houston Putman)
+
Bug Fixes
----------------------
* SOLR-9262: Connection and read timeouts are being ignored by UpdateShardHandler after SOLR-4509.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsDriver.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsDriver.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsDriver.java
new file mode 100644
index 0000000..21b053f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsDriver.java
@@ -0,0 +1,82 @@
+/*
+ * 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.analytics;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.solr.analytics.AnalyticsRequestManager.StreamingInfo;
+import org.apache.solr.analytics.facet.AbstractSolrQueryFacet.FacetValueQueryExecuter;
+import org.apache.solr.analytics.facet.StreamingFacet;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.SolrIndexSearcher;
+
+public class AnalyticsDriver {
+
+ /**
+ * Drive the collection of reduction data. This includes overall data as well as faceted data.
+ *
+ * @param manager of the request to drive
+ * @param searcher the results of the query
+ * @param filter that represents the overall query
+ * @param queryRequest used for the search request
+ * @throws IOException if an error occurs while reading from Solr
+ */
+ public static void drive(AnalyticsRequestManager manager, SolrIndexSearcher searcher, Filter filter, SolrQueryRequest queryRequest) throws IOException {
+ StreamingInfo streamingInfo = manager.getStreamingFacetInfo();
+ Iterable<StreamingFacet> streamingFacets = streamingInfo.streamingFacets;
+ ReductionCollectionManager collectionManager = streamingInfo.streamingCollectionManager;
+
+ Iterable<FacetValueQueryExecuter> facetExecuters = manager.getFacetExecuters(filter, queryRequest);
+
+ // Streaming phase (Overall results & Value/Pivot Facets)
+ // Loop through all documents and collect reduction data for streaming facets and overall results
+ if (collectionManager.needsCollection()) {
+ List<LeafReaderContext> contexts = searcher.getTopReaderContext().leaves();
+ for (int leafNum = 0; leafNum < contexts.size(); leafNum++) {
+ LeafReaderContext context = contexts.get(leafNum);
+ DocIdSet dis = filter.getDocIdSet(context, null); // solr docsets already exclude any deleted docs
+ if (dis == null) {
+ continue;
+ }
+ DocIdSetIterator disi = dis.iterator();
+ if (disi != null) {
+ collectionManager.doSetNextReader(context);
+ int doc = disi.nextDoc();
+ while( doc != DocIdSetIterator.NO_MORE_DOCS){
+ // Add a document to the statistics being generated
+ collectionManager.collect(doc);
+ streamingFacets.forEach( facet -> facet.addFacetValueCollectionTargets() );
+ collectionManager.apply();
+ doc = disi.nextDoc();
+ }
+ }
+ }
+ }
+
+ // Executing phase (Query/Range Facets)
+ // Send additional Solr Queries to compute facet values
+ for (FacetValueQueryExecuter executer : facetExecuters) {
+ executer.execute(searcher);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsExpression.java
new file mode 100644
index 0000000..044e371
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsExpression.java
@@ -0,0 +1,64 @@
+/*
+ * 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.analytics;
+
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.value.AnalyticsValue;
+
+/**
+ * A wrapper for a top-level analytics expression.
+ * The expression must have a name and be single valued.
+ */
+public class AnalyticsExpression {
+ private final AnalyticsValue expression;
+ private final String name;
+
+ public AnalyticsExpression(String name, AnalyticsValue expression) {
+ this.name = name;
+ this.expression = expression;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public AnalyticsValue getExpression() {
+ return expression;
+ }
+
+ /**
+ * Get the current value of the expression.
+ * This method can, and will, be called multiple times to return different values.
+ * The value returned is based on the {@link ReductionDataCollection} given
+ * to the {@link ReductionCollectionManager#setData} method.
+ *
+ * @return the current value of the expression
+ */
+ public Object toObject() {
+ return expression.getObject();
+ }
+
+ /**
+ * NOTE: Must be called after {@link #toObject()} is called, otherwise the value is not guaranteed to be correct.
+ *
+ * @return whether the current value of the expression exists.
+ */
+ public boolean exists() {
+ return expression.exists();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsGroupingManager.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsGroupingManager.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsGroupingManager.java
new file mode 100644
index 0000000..a95a451
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsGroupingManager.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file inputtributed 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
+ * inputtributed under the License is inputtributed 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.analytics;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.facet.AnalyticsFacet;
+import org.apache.solr.analytics.facet.PivotFacet;
+import org.apache.solr.analytics.facet.AbstractSolrQueryFacet;
+import org.apache.solr.analytics.facet.QueryFacet;
+import org.apache.solr.analytics.facet.RangeFacet;
+import org.apache.solr.analytics.facet.StreamingFacet;
+import org.apache.solr.analytics.facet.ValueFacet;
+import org.apache.solr.analytics.facet.AbstractSolrQueryFacet.FacetValueQueryExecuter;
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+
+/**
+ * The manager for faceted analytics. This class manages one grouping of facets and expressions to compute
+ * over those facets.
+ *
+ * <p>
+ * This class will only manage generating faceted results, not overall results.
+ */
+public class AnalyticsGroupingManager {
+ private final String name;
+ private final ReductionCollectionManager reductionCollectionManager;
+
+ private final Collection<AnalyticsExpression> topLevelExpressions;
+ private final ExpressionCalculator expressionCalculator;
+
+ private final Map<String, AnalyticsFacet> facets;
+
+ public AnalyticsGroupingManager(String name,
+ ReductionCollectionManager reductionCollectionManager,
+ Collection<AnalyticsExpression> topLevelExpressions) {
+ this.name = name;
+ this.reductionCollectionManager = reductionCollectionManager;
+
+ this.topLevelExpressions = topLevelExpressions;
+ this.expressionCalculator = new ExpressionCalculator(topLevelExpressions);
+
+ this.facets = new HashMap<>();
+ }
+
+ // This is outside of the method, since it is used in the lambda and cannot be a local non-final variable
+ private boolean hasStreamingFacets;
+
+ /**
+ * Get the {@link StreamingFacet}s (e.g. {@link ValueFacet} and {@link PivotFacet}) contained within this grouping,
+ * returning them through the given consumer.
+ *
+ * @param cons where the streaming facets are passed to
+ * @return whether the grouping contains streaming facets
+ */
+ public boolean getStreamingFacets(Consumer<StreamingFacet> cons) {
+ hasStreamingFacets = false;
+ facets.forEach( (name, facet) -> {
+ if (facet instanceof StreamingFacet) {
+ cons.accept((StreamingFacet)facet);
+ hasStreamingFacets = true;
+ }
+ });
+ return hasStreamingFacets;
+ }
+
+ /**
+ * Create the {@link FacetValueQueryExecuter}s for all {@link AbstractSolrQueryFacet}s
+ * (e.g. {@link QueryFacet} and {@link RangeFacet}) contained within this grouping.
+ * The executers are returned through the given consumer.
+ *
+ * <p>
+ * One {@link FacetValueQueryExecuter} is created for each facet value to be returned for a facet.
+ * Since every {@link AbstractSolrQueryFacet} has discrete and user-defined facet values,
+ * unlike {@link StreamingFacet}s, a discrete number of {@link FacetValueQueryExecuter}s are created and returned.
+ *
+ * @param filter representing the overall Solr Query of the request,
+ * will be combined with the facet value queries
+ * @param queryRequest from the overall search request
+ * @param cons where the executers are passed to
+ */
+ public void getFacetExecuters(Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> cons) {
+ facets.forEach( (name, facet) -> {
+ if (facet instanceof AbstractSolrQueryFacet) {
+ ((AbstractSolrQueryFacet)facet).createFacetValueExecuters(filter, queryRequest, cons);
+ }
+ });
+ }
+
+ /**
+ * Add a facet to the grouping. All expressions in this grouping will be computed over the facet.
+ *
+ * @param facet to compute expressions over
+ */
+ public void addFacet(AnalyticsFacet facet) {
+ facet.setExpressionCalculator(expressionCalculator);
+ facet.setReductionCollectionManager(reductionCollectionManager);
+ facets.put(facet.getName(), facet);
+ }
+
+ /**
+ * Import the shard data for this grouping from a bit-stream,
+ * exported by the {@link #exportShardData} method in the each of the collection's shards.
+ *
+ * @param input The bit-stream to import the grouping data from
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public void importShardData(DataInput input) throws IOException {
+ // This allows mergeData() to import from the same input everytime it is called
+ // while the facets are importing.
+ reductionCollectionManager.setShardInput(input);
+
+ int sz = input.readInt();
+ for (int i = 0; i < sz; ++i) {
+ facets.get(input.readUTF()).importShardData(input);
+ }
+ }
+
+ /**
+ * Export the shard data for this grouping through a bit-stream,
+ * to be imported by the {@link #importShardData} method in the originating shard.
+ *
+ * @param output The bit-stream to output the grouping data through
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportShardData(DataOutput output) throws IOException {
+ // This allows exportData() to export to the same output everytime it is called
+ // while the facets are exporting.
+ reductionCollectionManager.setShardOutput(output);
+
+ output.writeInt(facets.size());
+ for (Entry<String,AnalyticsFacet> facet : facets.entrySet()) {
+ output.writeUTF(facet.getKey());
+ facet.getValue().exportShardData(output);
+ }
+ }
+
+ /**
+ * Get the {@link ReductionCollectionManager} that manages the collection of reduction data for the expressions
+ * contained within this grouping.
+ *
+ * @return the grouping's reduction manager
+ */
+ public ReductionCollectionManager getReductionManager() {
+ return reductionCollectionManager;
+ }
+
+ /**
+ * Create the response for this grouping, a mapping from each of it's facets' names to the facet's response.
+ *
+ * @return the named list representation of the response
+ */
+ public Map<String,Object> createResponse() {
+ Map<String,Object> response = new HashMap<>();
+
+ // Add the value facet buckets to the output
+ facets.forEach( (name, facet) -> response.put(name, facet.createResponse()) );
+
+ return response;
+ }
+
+ /**
+ * Create the response for this grouping, but in the old style of response.
+ * This response has a bucket for the following if they are contained in the grouping:
+ * FieldFacets, RangeFacets and QueryFacets.
+ * Each facet's name and response are put into the bucket corresponding to its type.
+ * <p>
+ * Since groupings in the old notation must also return overall results, the overall results are
+ * passed in and the values are used to populate the grouping response.
+ *
+ * @param overallResults of the expressions to add to the grouping response
+ * @return the named list representation of the response
+ */
+ public NamedList<Object> createOldResponse(Map<String,Object> overallResults) {
+ NamedList<Object> response = new NamedList<>();
+
+ topLevelExpressions.forEach( expression -> response.add(expression.getName(), overallResults.get(name + expression.getName())));
+
+ NamedList<Object> fieldFacetResults = new NamedList<>();
+ NamedList<Object> rangeFacetResults = new NamedList<>();
+ NamedList<Object> queryFacetResults = new NamedList<>();
+ // Add the field facet buckets to the output
+ facets.forEach( (name, facet) -> {
+ // The old style of request only accepts field facets
+ // So we can assume that all value facets are field facets
+ if (facet instanceof ValueFacet) {
+ fieldFacetResults.add(name, facet.createOldResponse());
+ } else if (facet instanceof RangeFacet) {
+ rangeFacetResults.add(name, facet.createOldResponse());
+ } else if (facet instanceof QueryFacet) {
+ queryFacetResults.add(name, facet.createOldResponse());
+ }
+ });
+ if (fieldFacetResults.size() > 0) {
+ response.add(AnalyticsResponseHeadings.FIELD_FACETS, fieldFacetResults);
+ }
+ if (rangeFacetResults.size() > 0) {
+ response.add(AnalyticsResponseHeadings.RANGE_FACETS, rangeFacetResults);
+ }
+ if (queryFacetResults.size() > 0) {
+ response.add(AnalyticsResponseHeadings.QUERY_FACETS, queryFacetResults);
+ }
+ return response;
+ }
+
+ /**
+ * Get the name of the grouping.
+ *
+ * @return the grouping name
+ */
+ public String getName() {
+ return name;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestManager.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestManager.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestManager.java
new file mode 100644
index 0000000..45b958f
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestManager.java
@@ -0,0 +1,279 @@
+/*
+ * 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.analytics;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.analytics.facet.AbstractSolrQueryFacet;
+import org.apache.solr.analytics.facet.AbstractSolrQueryFacet.FacetValueQueryExecuter;
+import org.apache.solr.analytics.facet.StreamingFacet;
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.stream.AnalyticsShardRequestManager;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+
+/**
+ * The manager of an entire analytics request.
+ */
+public class AnalyticsRequestManager {
+ private final ReductionCollectionManager ungroupedReductionManager;
+ private ReductionDataCollection ungroupedData;
+
+ private final Map<String, AnalyticsGroupingManager> groupingManagers;
+
+ private final Collection<AnalyticsExpression> ungroupedExpressions;
+ private final ExpressionCalculator ungroupedExpressionCalculator;
+
+ /**
+ * If the request is distributed, the manager for shard requests.
+ */
+ public String analyticsRequest;
+ public AnalyticsShardRequestManager shardStream;
+ public boolean sendShards;
+
+ /**
+ * Create an manager with the given ungrouped expressions. This is straightforward in the new
+ * style of request, however in the old olap-style requests all groupings' expressions are expected
+ * to be ungrouped as well.
+ *
+ *
+ * @param ungroupedReductionManager to manage the reduction collection for all ungrouped expressions
+ * @param ungroupedExpressions to compute overall results for
+ */
+ public AnalyticsRequestManager(ReductionCollectionManager ungroupedReductionManager,
+ Collection<AnalyticsExpression> ungroupedExpressions) {
+ this.ungroupedReductionManager = ungroupedReductionManager;
+ this.ungroupedData = ungroupedReductionManager.newDataCollection();
+ this.ungroupedReductionManager.addLastingCollectTarget(ungroupedData);
+
+ this.ungroupedExpressions = ungroupedExpressions;
+ this.ungroupedExpressionCalculator = new ExpressionCalculator(ungroupedExpressions);
+ this.groupingManagers = new HashMap<>();
+ }
+
+ /**
+ * Get the collection manager for ungrouped expressions, including grouped expressions if
+ * the old request notation is used.
+ *
+ * @return the collection manager for the ungrouped expressions
+ */
+ public ReductionCollectionManager getUngroupedCollectionManager() {
+ return ungroupedReductionManager;
+ }
+
+ /**
+ * Get the collection manager for all ungrouped expressions, including grouped expressions if
+ * the old request notation is used.
+ *
+ * @return the collection manager for the ungrouped expressions
+ */
+ public ReductionDataCollection getUngroupedData() {
+ return ungroupedData;
+ }
+
+ /**
+ * Return all ungrouped expressions, including grouped expressions if
+ * the old request notation is used.
+ *
+ * @return an {@link Iterable} of the ungrouped expressions
+ */
+ public Iterable<AnalyticsExpression> getUngroupedExpressions() {
+ return ungroupedExpressions;
+ }
+
+ /**
+ * Generate the results of all ungrouped expressions, including grouped expressions if
+ * the old request notation is used.
+ *
+ * @param response the response to add the ungrouped results to.
+ */
+ public void addUngroupedResults(Map<String,Object> response) {
+ ungroupedReductionManager.setData(ungroupedData);
+ ungroupedExpressionCalculator.addResults(response);
+ }
+
+ /**
+ * Generate the results of all ungrouped expressions, including grouped expressions if
+ * the old request notation is used.
+ *
+ * @return the map containing the ungrouped results
+ */
+ public Map<String,Object> getUngroupedResults() {
+ ungroupedReductionManager.setData(ungroupedData);
+ return ungroupedExpressionCalculator.getResults();
+ }
+
+ /**
+ * Add a grouping to the request.
+ *
+ * @param groupingManager that manages the grouping
+ */
+ public void addGrouping(AnalyticsGroupingManager groupingManager) {
+ groupingManagers.put(groupingManager.getName(), groupingManager);
+ }
+
+ /**
+ * Import the shard data for this request from a bit-stream,
+ * exported by the {@link #exportShardData} method in the each of the collection's shards.
+ * <p>
+ * First the overall data is imported, then the grouping data is imported.
+ *
+ * @param input The bit-stream to import the shard data from
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public synchronized void importShardData(DataInput input) throws IOException {
+ ungroupedReductionManager.setShardInput(input);
+
+ // The ungroupedData will not exist for the first shard imported
+ if (ungroupedData == null) {
+ ungroupedData = ungroupedReductionManager.newDataCollectionIO();
+ } else {
+ ungroupedReductionManager.prepareReductionDataIO(ungroupedData);
+ }
+ ungroupedReductionManager.mergeData();
+
+ int size = input.readInt();
+ while (--size >= 0) {
+ String groupingName = input.readUTF();
+ groupingManagers.get(groupingName).importShardData(input);
+ }
+ }
+
+ /**
+ * Export the shard data for this request through a bit-stream,
+ * to be imported by the {@link #importShardData} method in the originating shard.
+ * <p>
+ * First the overall data is exported, then the grouping data is exported.
+ *
+ * @param output The bit-stream to output the shard data through
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportShardData(DataOutput output) throws IOException {
+ ungroupedReductionManager.setShardOutput(output);
+
+ ungroupedReductionManager.prepareReductionDataIO(ungroupedData);
+ ungroupedReductionManager.exportData();
+
+ output.writeInt(groupingManagers.size());
+ for (String groupingName : groupingManagers.keySet()) {
+ output.writeUTF(groupingName);
+ groupingManagers.get(groupingName).exportShardData(output);
+ }
+ }
+
+ /**
+ * Consolidate the information of all {@link StreamingFacet}s contained within the request, since
+ * they need to be collected along with the overall results during the streaming phase of the
+ * {@link AnalyticsDriver}.
+ *
+ * @return the info for all {@link StreamingFacet}s
+ */
+ public StreamingInfo getStreamingFacetInfo() {
+ StreamingInfo streamingInfo = new StreamingInfo();
+ ArrayList<ReductionCollectionManager> groupingCollectors = new ArrayList<>();
+ groupingManagers.values().forEach( grouping -> {
+ // If a grouping has streaming facets, then that groupings expressions
+ // must be collected during the streaming phase.
+ if (grouping.getStreamingFacets( facet -> streamingInfo.streamingFacets.add(facet) )) {
+ groupingCollectors.add(grouping.getReductionManager());
+ }
+ });
+
+ // Create an streaming collection manager to manage the collection of all ungrouped expressions and
+ // grouped expressions that are calculated over streaming facets.
+ streamingInfo.streamingCollectionManager = ungroupedReductionManager.merge(groupingCollectors);
+ return streamingInfo;
+ }
+
+ /**
+ * Class to encapsulate all necessary data for collecting {@link StreamingFacet}s.
+ */
+ public static class StreamingInfo {
+ Collection<StreamingFacet> streamingFacets = new ArrayList<>();
+ /**
+ * Manages the collection of all expressions needed for streaming facets
+ */
+ ReductionCollectionManager streamingCollectionManager;
+ }
+
+ /**
+ * Create the {@link FacetValueQueryExecuter}s for all {@link AbstractSolrQueryFacet}s contained in the request.
+ *
+ * @param filter representing the overall search query
+ * @param queryRequest of the overall search query
+ * @return an {@link Iterable} of executers
+ */
+ public Iterable<FacetValueQueryExecuter> getFacetExecuters(Filter filter, SolrQueryRequest queryRequest) {
+ ArrayList<FacetValueQueryExecuter> facetExecutors = new ArrayList<>();
+ groupingManagers.values().forEach( grouping -> {
+ grouping.getFacetExecuters(filter, queryRequest, executor -> facetExecutors.add(executor));
+ });
+ return facetExecutors;
+ }
+
+ /**
+ * Create the response for a request given in the old olap-style format.
+ * The old response returned overall expressions within groupings.
+ *
+ * @return a {@link NamedList} representation of the response
+ */
+ public NamedList<Object> createOldResponse() {
+ NamedList<Object> analyticsResponse = new NamedList<>();
+ Map<String,Object> ungroupedResults = getUngroupedResults();
+ groupingManagers.forEach( (name, groupingManager) -> {
+ analyticsResponse.add(name, groupingManager.createOldResponse(ungroupedResults));
+ });
+
+ return analyticsResponse;
+ }
+
+ /**
+ * Create the response for a request.
+ *
+ * <p>
+ * NOTE: Analytics requests specified in the old olap-style format
+ * have their responses generated by {@link #createOldResponse()}.
+ *
+ * @return a {@link Map} representation of the response
+ */
+ public Map<String,Object> createResponse() {
+ Map<String,Object> analyticsResponse = new HashMap<>();
+ if (ungroupedExpressions.size() > 0) {
+ addUngroupedResults(analyticsResponse);
+ }
+
+ Map<String,Object> groupingsResponse = new HashMap<>();
+ groupingManagers.forEach( (name, groupingManager) -> {
+ groupingsResponse.put(name, groupingManager.createResponse());
+ });
+
+ if (groupingsResponse.size() > 0) {
+ analyticsResponse.put(AnalyticsResponseHeadings.GROUPINGS, groupingsResponse);
+ }
+ return analyticsResponse;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestParser.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestParser.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestParser.java
new file mode 100644
index 0000000..bfa62e2
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/AnalyticsRequestParser.java
@@ -0,0 +1,549 @@
+/*
+ * 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.analytics;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import org.apache.solr.analytics.facet.PivotFacet;
+import org.apache.solr.analytics.facet.PivotNode;
+import org.apache.solr.analytics.facet.QueryFacet;
+import org.apache.solr.analytics.facet.RangeFacet;
+import org.apache.solr.analytics.facet.ValueFacet;
+import org.apache.solr.analytics.facet.SortableFacet.FacetSortSpecification;
+import org.apache.solr.analytics.facet.compare.DelegatingComparator;
+import org.apache.solr.analytics.facet.compare.FacetValueComparator;
+import org.apache.solr.analytics.facet.compare.FacetResultsComparator;
+import org.apache.solr.analytics.value.AnalyticsValue;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.ComparableValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
+import org.apache.solr.common.params.FacetParams.FacetRangeOther;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Class to manage the parsing of new-style analytics requests.
+ */
+public class AnalyticsRequestParser {
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ public static void init() {
+ mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+ mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true);
+ }
+
+ public static final String analyticsParamName = "analytics";
+
+ private static Predicate<String> request = acceptNames("request", "req");
+ private static Predicate<String> functions = acceptNames("functions", "funcs", "f");
+ private static Predicate<String> expressions = acceptNames("expressions", "exprs", "e");
+
+ private static Predicate<String> grouping = acceptNames("grouping", "group", "g");
+
+ private static Predicate<String> valueFacet = acceptNames("valuefacet", "vf");
+
+ private static Predicate<String> pivotFacet = acceptNames("pivotfacet", "pf");
+ private static Predicate<String> pivot = acceptNames("pivot", "p");
+
+ private static Predicate<String> sort = acceptNames("sort", "s");
+ private static Predicate<String> sortExpression = acceptNames("expression", "expr");
+ private static Predicate<String> sortFacetValue = acceptNames("facetvalue", "fv");
+ private static Predicate<String> sortDirection = acceptNames("direction", "dir");
+ private static Predicate<String> sortAscending = acceptNames("ascending", "asc", "a");
+ private static Predicate<String> sortDescending = acceptNames("descending", "desc", "d");
+ private static Predicate<String> sortLimit = acceptNames("limit", "l");
+ private static Predicate<String> sortOffset = acceptNames("offset", "o");
+
+ private static Predicate<String> rangeFacet = acceptNames("rangefacet", "rf");
+ private static Predicate<String> rangeGaps = acceptNames("gaps", "g");
+ private static Predicate<String> rangeHardEnd = acceptNames("hardend", "he");
+ private static Predicate<String> rangeInclude = acceptNames("include", "i");
+ private static Predicate<String> rangeOthers = acceptNames("others", "o");
+
+ private static Predicate<String> queryFacet = acceptNames("queryfacet", "qf");
+ private static Predicate<String> query = acceptNames("query", "q");
+
+ private static Predicate<String> acceptNames(String... names) {
+ return Pattern.compile("^(?:" + Arrays.stream(names).reduce((a,b) -> a + "|" + b).orElse("") + ")$", Pattern.CASE_INSENSITIVE).asPredicate();
+ }
+
+ // Defaults
+ public static final String DEFAULT_SORT_DIRECTION = "ascending";
+ public static final int DEFAULT_OFFSET = 0;
+ public static final int DEFAULT_LIMIT = -1;
+ public static final boolean DEFAULT_HARDEND = false;
+
+ @JsonInclude(Include.NON_EMPTY)
+ public static class AnalyticsRequest {
+ public Map<String, String> functions;
+ public Map<String, String> expressions;
+
+ public Map<String, AnalyticsGroupingRequest> groupings;
+ }
+
+ public static class AnalyticsGroupingRequest {
+ public Map<String, String> expressions;
+
+ public Map<String, AnalyticsFacetRequest> facets;
+ }
+
+ @JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.PROPERTY,
+ property = "type"
+ )
+ @JsonSubTypes({
+ @Type(value = AnalyticsValueFacetRequest.class, name = "value"),
+ @Type(value = AnalyticsPivotFacetRequest.class, name = "pivot"),
+ @Type(value = AnalyticsRangeFacetRequest.class, name = "range"),
+ @Type(value = AnalyticsQueryFacetRequest.class, name = "query") }
+ )
+ @JsonInclude(Include.NON_EMPTY)
+ public static interface AnalyticsFacetRequest { }
+
+ @JsonTypeName("value")
+ public static class AnalyticsValueFacetRequest implements AnalyticsFacetRequest {
+ public String expression;
+ public AnalyticsSortRequest sort;
+ }
+
+ @JsonTypeName("pivot")
+ public static class AnalyticsPivotFacetRequest implements AnalyticsFacetRequest {
+ public List<AnalyticsPivotRequest> pivots;
+ }
+
+ public static class AnalyticsPivotRequest {
+ public String name;
+ public String expression;
+ public AnalyticsSortRequest sort;
+ }
+
+ @JsonInclude(Include.NON_EMPTY)
+ public static class AnalyticsSortRequest {
+ public List<AnalyticsSortCriteriaRequest> criteria;
+ public int limit = DEFAULT_LIMIT;
+ public int offset = DEFAULT_OFFSET;
+ }
+
+ @JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.PROPERTY,
+ property = "type"
+ )
+ @JsonSubTypes({
+ @Type(value = AnalyticsExpressionSortRequest.class, name = "expression"),
+ @Type(value = AnalyticsFacetValueSortRequest.class, name = "facetvalue") }
+ )
+ @JsonInclude(Include.NON_EMPTY)
+ public static abstract class AnalyticsSortCriteriaRequest {
+ public String direction;
+ }
+
+ @JsonTypeName("expression")
+ public static class AnalyticsExpressionSortRequest extends AnalyticsSortCriteriaRequest {
+ public String expression;
+ }
+
+ @JsonTypeName("facetvalue")
+ public static class AnalyticsFacetValueSortRequest extends AnalyticsSortCriteriaRequest { }
+
+ @JsonTypeName("range")
+ public static class AnalyticsRangeFacetRequest implements AnalyticsFacetRequest {
+ public String field;
+ public String start;
+ public String end;
+ public List<String> gaps;
+ public boolean hardend = DEFAULT_HARDEND;
+ public List<String> include;
+ public List<String> others;
+ }
+
+ @JsonTypeName("query")
+ public static class AnalyticsQueryFacetRequest implements AnalyticsFacetRequest {
+ public Map<String, String> queries;
+ }
+
+ /* ***************
+ * Request & Groupings
+ * ***************/
+
+ public static AnalyticsRequestManager parse(AnalyticsRequest request, ExpressionFactory expressionFactory, boolean isDistribRequest) throws SolrException {
+ AnalyticsRequestManager manager = constructRequest(request, expressionFactory, isDistribRequest);
+ if (isDistribRequest) {
+ try {
+ manager.analyticsRequest = mapper.writeValueAsString(request);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return manager;
+ }
+
+ public static AnalyticsRequestManager parse(String rawRequest, ExpressionFactory expressionFactory, boolean isDistribRequest) throws SolrException {
+ JsonParser parser;
+ try {
+ parser = new JsonFactory().createParser(rawRequest)
+ .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
+ .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+ } catch (IOException e1) {
+ throw new RuntimeException(e1);
+ }
+ AnalyticsRequest request;
+ try {
+ request = mapper.readValue(parser, AnalyticsRequest.class);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ AnalyticsRequestManager manager = constructRequest(request, expressionFactory, isDistribRequest);
+ if (isDistribRequest) {
+ manager.analyticsRequest = rawRequest;
+ }
+ return manager;
+ }
+
+ private static AnalyticsRequestManager constructRequest(AnalyticsRequest request, ExpressionFactory expressionFactory, boolean isDistribRequest) throws SolrException {
+ expressionFactory.startRequest();
+
+ // Functions
+ if (request.functions != null) {
+ request.functions.forEach( (funcSig, retSig) -> expressionFactory.addUserDefinedVariableFunction(funcSig, retSig));
+ }
+
+ // Expressions
+ Map<String,AnalyticsExpression> topLevelExpressions;
+ if (request.expressions != null) {
+ topLevelExpressions = constructExpressions(request.expressions, expressionFactory);
+ } else {
+ topLevelExpressions = new HashMap<>();
+ }
+ AnalyticsRequestManager manager = new AnalyticsRequestManager(expressionFactory.createReductionManager(isDistribRequest), topLevelExpressions.values());
+
+ // Groupings
+ if (request.groupings != null) {
+ request.groupings.forEach( (name, grouping) -> {
+ manager.addGrouping(constructGrouping(name, grouping, expressionFactory, isDistribRequest));
+ });
+ }
+ return manager;
+ }
+
+ private static AnalyticsGroupingManager constructGrouping(String name, AnalyticsGroupingRequest grouping, ExpressionFactory expressionFactory, boolean isDistribRequest) throws SolrException {
+ expressionFactory.startGrouping();
+
+ // Expressions
+ if (grouping.expressions == null || grouping.expressions.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Groupings must contain at least one expression, '" + name + "' has none.");
+ }
+
+ Map<String,AnalyticsExpression> expressions = constructExpressions(grouping.expressions, expressionFactory);
+ AnalyticsGroupingManager manager = new AnalyticsGroupingManager(name,
+ expressionFactory.createGroupingReductionManager(isDistribRequest),
+ expressions.values());
+
+ if (grouping.facets == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Groupings must contain at least one facet, '" + name + "' has none.");
+ }
+ // Parse the facets
+ grouping.facets.forEach( (facetName, facet) -> {
+ if (facet instanceof AnalyticsValueFacetRequest) {
+ manager.addFacet(constructValueFacet(facetName, (AnalyticsValueFacetRequest) facet, expressionFactory, expressions));
+ } else if (facet instanceof AnalyticsPivotFacetRequest) {
+ manager.addFacet(constructPivotFacet(facetName, (AnalyticsPivotFacetRequest) facet, expressionFactory, expressions));
+ } else if (facet instanceof AnalyticsRangeFacetRequest) {
+ manager.addFacet(constructRangeFacet(facetName, (AnalyticsRangeFacetRequest) facet, expressionFactory.getSchema()));
+ } else if (facet instanceof AnalyticsQueryFacetRequest) {
+ manager.addFacet(constructQueryFacet(facetName, (AnalyticsQueryFacetRequest) facet));
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"The facet type, '" + facet.getClass().toString() + "' in "
+ + "grouping '" + name + "' is not a valid type of facet");
+ }
+ });
+
+ return manager;
+ }
+
+ /* ***************
+ * Expression & Functions
+ * ***************/
+
+ private static Map<String, AnalyticsExpression> constructExpressions(Map<String, String> rawExpressions, ExpressionFactory expressionFactory) throws SolrException {
+ Map<String, AnalyticsExpression> expressions = new HashMap<>();
+ rawExpressions.forEach( (name, expression) -> {
+ AnalyticsValueStream exprVal = expressionFactory.createExpression(expression);
+ if (exprVal instanceof AnalyticsValue) {
+ if (exprVal.getExpressionType().isReduced()) {
+ expressions.put(name, (new AnalyticsExpression(name, (AnalyticsValue)exprVal)));
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Top-level expressions must be reduced, the '" + name + "' expression is not.");
+ }
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Top-level expressions must be single-valued, the '" + name + "' expression is not.");
+ }
+ });
+ return expressions;
+ }
+
+ /* ***************
+ * FACETS
+ * ***************/
+
+ /*
+ * Value Facets
+ */
+
+ private static ValueFacet constructValueFacet(String name, AnalyticsValueFacetRequest facetRequest, ExpressionFactory expressionFactory, Map<String, AnalyticsExpression> expressions) throws SolrException {
+ if (facetRequest.expression == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Value Facets must contain a mapping expression to facet over, '" + name + "' has none.");
+ }
+
+ // The second parameter must be a mapping expression
+ AnalyticsValueStream expr = expressionFactory.createExpression(facetRequest.expression);
+ if (!expr.getExpressionType().isUnreduced()) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Value Facet expressions must be mapping expressions, "
+ + "the following expression in value facet '" + name + "' contains a reduction: " + facetRequest.expression);
+ }
+ if (!(expr instanceof StringValueStream)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Value Facet expressions must be castable to string expressions, "
+ + "the following expression in value facet '" + name + "' is not: " + facetRequest.expression);
+ }
+
+ ValueFacet facet = new ValueFacet(name, (StringValueStream)expr);
+
+ // Check if the value facet is sorted
+ if (facetRequest.sort != null) {
+ facet.setSort(constructSort(facetRequest.sort, expressions));
+ }
+ return facet;
+ }
+
+ /*
+ * Pivot Facets
+ */
+
+ private static PivotFacet constructPivotFacet(String name, AnalyticsPivotFacetRequest facetRequest, ExpressionFactory expressionFactory, Map<String, AnalyticsExpression> expressions) throws SolrException {
+ PivotNode<?> topPivot = null;
+
+ // Pivots
+ if (facetRequest.pivots == null || facetRequest.pivots.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Pivot Facets must contain at least one pivot to facet over, '" + name + "' has none.");
+ }
+
+ ListIterator<AnalyticsPivotRequest> iter = facetRequest.pivots.listIterator(facetRequest.pivots.size());
+ while (iter.hasPrevious()) {
+ topPivot = constructPivot(iter.previous(), topPivot, expressionFactory, expressions);
+ }
+
+ return new PivotFacet(name, topPivot);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static PivotNode<?> constructPivot(AnalyticsPivotRequest pivotRequest,
+ PivotNode<?> childPivot,
+ ExpressionFactory expressionFactory,
+ Map<String, AnalyticsExpression> expressions) throws SolrException {
+ if (pivotRequest.name == null || pivotRequest.name.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Pivots must have a name.");
+ }
+ if (pivotRequest.expression == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Pivots must have an expression to facet over, '" + pivotRequest.name + "' does not.");
+ }
+
+ // The second parameter must be a mapping expression
+ AnalyticsValueStream expr = expressionFactory.createExpression(pivotRequest.expression);
+ if (!expr.getExpressionType().isUnreduced()) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Pivot expressions must be mapping expressions, "
+ + "the following expression in pivot '" + pivotRequest.name + "' contains a reduction: " + pivotRequest.expression);
+ }
+ if (!(expr instanceof StringValueStream)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Pivot expressions must be castable to string expressions, "
+ + "the following expression in pivot '" + pivotRequest.name + "' is not: '" + pivotRequest.expression);
+ }
+
+ PivotNode<?> pivot;
+ if (childPivot == null) {
+ pivot = new PivotNode.PivotLeaf(pivotRequest.name, (StringValueStream)expr);
+ } else {
+ pivot = new PivotNode.PivotBranch(pivotRequest.name, (StringValueStream)expr, childPivot);
+ }
+
+ // Check if the pivot is sorted
+ if (pivotRequest.sort != null) {
+ pivot.setSort(constructSort(pivotRequest.sort, expressions));
+ }
+ return pivot;
+ }
+
+ /*
+ * Range Facets
+ */
+
+ private static RangeFacet constructRangeFacet(String name, AnalyticsRangeFacetRequest facetRequest, IndexSchema schema) throws SolrException {
+ if (facetRequest.field == null || facetRequest.field.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Range Facets must specify a field to facet over, '" +name + "' does not.");
+ }
+ SchemaField field = schema.getFieldOrNull(facetRequest.field);
+ if (field == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Range Facets must have a valid field as the second parameter. The '" + name + "' facet "
+ + "tries to facet over the non-existent field: " + facetRequest.field);
+ }
+
+ if (facetRequest.start == null || facetRequest.start.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Range Facets must specify a start value, '" +name + "' does not.");
+ }
+ if (facetRequest.end == null || facetRequest.end.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Range Facets must specify a end value, '" +name + "' does not.");
+ }
+ if (facetRequest.gaps == null || facetRequest.gaps.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Range Facets must specify a gap or list of gaps to determine facet buckets, '" +name + "' does not.");
+ }
+ RangeFacet facet = new RangeFacet(name, field, facetRequest.start, facetRequest.end, facetRequest.gaps);
+
+ facet.setHardEnd(facetRequest.hardend);
+
+ if (facetRequest.include != null && facetRequest.include.size() > 0) {
+ facet.setInclude(constructInclude(facetRequest.include));
+ }
+ if (facetRequest.others != null && facetRequest.others.size() > 0) {
+ facet.setOthers(constructOthers(facetRequest.others, name));
+ }
+ return facet;
+ }
+
+ private static EnumSet<FacetRangeInclude> constructInclude(List<String> includes) throws SolrException {
+ return FacetRangeInclude.parseParam(includes.toArray(new String[includes.size()]));
+ }
+
+ private static EnumSet<FacetRangeOther> constructOthers(List<String> othersRequest, String facetName) throws SolrException {
+ EnumSet<FacetRangeOther> others = EnumSet.noneOf(FacetRangeOther.class);
+ for (String rawOther : othersRequest) {
+ if (!others.add(FacetRangeOther.get(rawOther))) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Duplicate include value '" + rawOther + "' found in range facet '" + facetName + "'");
+ }
+ }
+ if (others.contains(FacetRangeOther.NONE)) {
+ if (others.size() > 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Include value 'NONE' is used with other includes in a range facet '" + facetName + "'. "
+ + "If 'NONE' is used, it must be the only include.");
+ }
+ return EnumSet.noneOf(FacetRangeOther.class);
+ }
+ if (others.contains(FacetRangeOther.ALL)) {
+ if (others.size() > 1) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Include value 'ALL' is used with other includes in a range facet '" + facetName + "'. "
+ + "If 'ALL' is used, it must be the only include.");
+ }
+ return EnumSet.of(FacetRangeOther.BEFORE, FacetRangeOther.BETWEEN, FacetRangeOther.AFTER);
+ }
+ return others;
+ }
+
+ /*
+ * Query Facets
+ */
+
+ private static QueryFacet constructQueryFacet(String name, AnalyticsQueryFacetRequest facetRequest) throws SolrException {
+ if (facetRequest.queries == null || facetRequest.queries.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Query Facets must be contain at least 1 query to facet over, '" + name + "' does not.");
+ }
+
+ // The first param must be the facet name
+ return new QueryFacet(name, facetRequest.queries);
+ }
+
+ /*
+ * Facet Sorting
+ */
+
+ private static FacetSortSpecification constructSort(AnalyticsSortRequest sortRequest, Map<String, AnalyticsExpression> expressions) throws SolrException {
+ if (sortRequest.criteria == null || sortRequest.criteria.size() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Sorts must be given at least 1 criteria.");
+ }
+
+ return new FacetSortSpecification(constructSortCriteria(sortRequest.criteria, expressions), sortRequest.limit, sortRequest.offset);
+ }
+
+ private static FacetResultsComparator constructSortCriteria(List<AnalyticsSortCriteriaRequest> criteria, Map<String, AnalyticsExpression> expressions) {
+ ArrayList<FacetResultsComparator> comparators = new ArrayList<>();
+ for (AnalyticsSortCriteriaRequest criterion : criteria) {
+ FacetResultsComparator comparator;
+ if (criterion instanceof AnalyticsExpressionSortRequest) {
+ comparator = constructExpressionSortCriteria((AnalyticsExpressionSortRequest) criterion, expressions);
+ } else if (criterion instanceof AnalyticsFacetValueSortRequest) {
+ comparator = constructFacetValueSortCriteria((AnalyticsFacetValueSortRequest) criterion);
+ } else {
+ // Shouldn't happen
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Sort Criteria must either be expressions or facetValues, '" + criterion.getClass().getName() + "' given.");
+ }
+ if (criterion.direction != null && criterion.direction.length() > 0) {
+ if (sortAscending.test(criterion.direction)) {
+ comparator.setDirection(true);
+ } else if (sortDescending.test(criterion.direction)) {
+ comparator.setDirection(false);
+ } else {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Sort direction '" + criterion.direction + " is not a recognized direction.");
+ }
+ }
+ comparators.add(comparator);
+ }
+ return DelegatingComparator.joinComparators(comparators);
+ }
+
+ private static FacetResultsComparator constructExpressionSortCriteria(AnalyticsExpressionSortRequest criterion, Map<String, AnalyticsExpression> expressions) {
+ if (criterion.expression == null || criterion.expression.length() == 0) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Expression Sorts must contain an expression parameter, none given.");
+ }
+
+ AnalyticsExpression expression = expressions.get(criterion.expression);
+ if (expression == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Sort Expression not defined within the grouping: " + criterion.expression);
+ }
+ if (!(expression.getExpression() instanceof ComparableValue)) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Expression Sorts must be comparable, the following is not: " + criterion.expression);
+ }
+ return ((ComparableValue)expression.getExpression()).getObjectComparator(expression.getName());
+ }
+
+ private static FacetResultsComparator constructFacetValueSortCriteria(AnalyticsFacetValueSortRequest criterion) {
+ return new FacetValueComparator();
+ }
+}