You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2017/10/19 08:31:18 UTC

[30/50] [abbrv] lucene-solr:jira/solr-11072: SOLR-11145, SOLR-11146: Added comprehensive unit tests for Analytics Component 2.0 as well as analytics bug fixes.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/86d84bff/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
deleted file mode 100644
index 59ebbcb..0000000
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsCloudTest.java
+++ /dev/null
@@ -1,187 +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;
-
-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/86d84bff/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
deleted file mode 100644
index 18f51a9..0000000
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/AbstractAnalyticsStatsTest.java
+++ /dev/null
@@ -1,235 +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;
-
-import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Scanner;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-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.OrdinalCalculator;
-import org.apache.solr.request.SolrQueryRequest;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import com.google.common.collect.ObjectArrays;
-
-@SolrTestCaseJ4.SuppressPointFields(bugUrl="https://issues.apache.org/jira/browse/SOLR-10949")
-public class AbstractAnalyticsStatsTest extends SolrTestCaseJ4 {
-  
-  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;
-    }
-  }
-
-  static private Document doc;
-  static private XPathFactory xPathFact;
-
-  static private String rawResponse;
-  
-  @BeforeClass
-  public static void beforeClassAbstractAnalysis() {
-    xPathFact = XPathFactory.newInstance();
-  }
-  
-  @AfterClass
-  public static void afterClassAbstractAnalysis() {
-    xPathFact = null;
-    doc = null;
-    rawResponse = null;
-    defaults.clear();
-  }
-
-  public static void setResponse(String response) throws ParserConfigurationException, IOException, SAXException {
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    factory.setNamespaceAware(true); // never forget this!
-    DocumentBuilder builder = factory.newDocumentBuilder();
-    doc = builder.parse(new InputSource(new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8))));
-    rawResponse = response;
-  }
-
-  protected String getRawResponse() {
-    return rawResponse;
-  }
-
-  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='"+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>.
-    sb.append("/").append(type.toString()).append("[@name='").append(name).append("']");
-    String val = xPathFact.newXPath().compile(sb.toString()).evaluate(doc, XPathConstants.STRING).toString();
-    try {
-      switch (type) {
-        case INTEGER: return Integer.parseInt(val);
-        case DOUBLE:  return Double.parseDouble(val);
-        case FLOAT:   return Float.parseFloat(val);
-        case LONG:    return Long.parseLong(val);
-        case STRING:  assertTrue(rawResponse, val != null && val.length() > 0 ); return val;
-        case DATE:    assertTrue(rawResponse, val != null && val.length() > 0 ); return val;
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail("Caught exception in getStatResult, xPath = " + sb.toString() + " \nraw data: " + rawResponse);
-    }
-    fail("Unknown type used in getStatResult");
-    return null; // Really can't get here, but the compiler thinks we can!
-  }
-
-
-  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);
-  }
-  
-  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("/solr/analytics/" + 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();
-        line = line.trim();
-        if( StringUtils.isBlank(line) || line.startsWith("#")){
-          continue;
-        }
-        String[] param = line.split("=");
-        strList.add(param[0]);
-        strList.add(param[1]);
-      }
-      return strList.toArray(new String[0]);
-    } finally {
-      IOUtils.closeWhileHandlingException(file, in);
-    }
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/86d84bff/solr/contrib/analytics/src/test/org/apache/solr/analytics/ExpressionFactoryTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/ExpressionFactoryTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/ExpressionFactoryTest.java
new file mode 100644
index 0000000..b4f5b95
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/ExpressionFactoryTest.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.value.constant.ConstantValue;
+import org.apache.solr.schema.IndexSchema;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ExpressionFactoryTest extends SolrTestCaseJ4 {
+
+  private static IndexSchema indexSchema;
+  
+  @BeforeClass
+  public static void createSchemaAndFields() throws Exception {
+    initCore("solrconfig-analytics.xml","schema-analytics.xml");
+    assertU(adoc("id", "1", 
+        "int_i", "1",
+        "int_im", "1",
+        "long_l", "1",
+        "long_lm", "1",
+        "float_f", "1",
+        "float_fm", "1",
+        "double_d", "1",
+        "double_dm", "1",
+        "date_dt", "1800-12-31T23:59:59Z",
+        "date_dtm", "1800-12-31T23:59:59Z",
+        "string_s", "1",
+        "string_sm", "1",
+        "boolean_b", "true",
+        "boolean_bm", "false"
+    ));
+    assertU(commit());
+    
+    indexSchema = h.getCore().getLatestSchema();
+  }
+  
+  private ExpressionFactory getExpressionFactory() {
+    ExpressionFactory fact = new ExpressionFactory(indexSchema);
+    fact.startRequest();
+    return fact;
+  }
+  
+  @Test
+  public void userDefinedVariableFunctionTest() {
+    ExpressionFactory fact = getExpressionFactory();
+    
+    // Single parameter function
+    fact.startRequest();
+    fact.addUserDefinedVariableFunction("single_func(a)", "sum(add(a,double_d,float_f))");
+    assertEquals("div(sum(add(int_i,double_d,float_f)),count(string_s))", fact.createExpression("div(single_func(int_i),count(string_s))").getExpressionStr());
+    
+    // Multi parameter function
+    fact.startRequest();
+    fact.addUserDefinedVariableFunction("multi_func(a,b,c)", "median(if(boolean_b,add(a,b),c))");
+    assertEquals("div(median(if(boolean_b,add(int_i,double_d),float_f)),count(string_s))", fact.createExpression("div(multi_func(int_i,double_d,float_f),count(string_s))").getExpressionStr());
+    
+    // Function within function
+    fact.startRequest();
+    fact.addUserDefinedVariableFunction("inner_func(a,b)", "div(add(a,b),b)");
+    fact.addUserDefinedVariableFunction("outer_func(a,b,c)", "pow(inner_func(a,b),c)");
+    assertEquals("div(median(pow(div(add(int_i,double_d),double_d),float_f)),count(string_s))", fact.createExpression("div(median(outer_func(int_i,double_d,float_f)),count(string_s))").getExpressionStr());
+    
+    // Variable parameter function
+    fact.startRequest();
+    fact.addUserDefinedVariableFunction("var_func(a,b..)", "div(add(b),a)");
+    assertEquals("unique(div(add(double_d,float_f),int_i))", fact.createExpression("unique(var_func(int_i,double_d,float_f))").getExpressionStr());
+    assertEquals("unique(div(add(double_d,float_f,long_l),int_i))", fact.createExpression("unique(var_func(int_i,double_d,float_f,long_l))").getExpressionStr());
+    
+    // Variable parameter function with for-each
+    fact.startRequest();
+    fact.addUserDefinedVariableFunction("var_func_fe(a,b..)", "div(add(b:abs(_)),a)");
+    assertEquals("unique(div(add(abs(double_d),abs(float_f)),int_i))", fact.createExpression("unique(var_func_fe(int_i,double_d,float_f))").getExpressionStr());
+    assertEquals("unique(div(add(abs(double_d),abs(float_f),abs(long_l)),int_i))", fact.createExpression("unique(var_func_fe(int_i,double_d,float_f,long_l))").getExpressionStr());
+  }
+  
+  @Test
+  public void reuseFunctionsTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    // Two ungrouped exactly the same expression
+    fact.startRequest();
+    assertTrue("The objects of the two mapping expressions are not the same.", 
+        fact.createExpression("pow(int_i,double_d)") == fact.createExpression("pow(int_i,double_d)"));
+    assertTrue("The objects of the two reduced expressions are not the same.", 
+        fact.createExpression("unique(add(int_i,double_d))") == fact.createExpression("unique(add(int_i,double_d))"));
+    
+    // Two ungrouped different expressions
+    fact.startRequest();
+    assertFalse("The objects of the two mapping expressions are not the same.", 
+        fact.createExpression("pow(int_i,double_d)") == fact.createExpression("pow(int_i,float_f)"));
+    assertFalse("The objects of the two reduced expressions are not the same.", 
+        fact.createExpression("unique(add(int_i,double_d))") == fact.createExpression("unique(add(int_i,float_f))"));
+    
+    // Grouped and ungrouped mapping expression
+    fact.startRequest();
+    Object ungrouped = fact.createExpression("pow(int_i,double_d)");
+    fact.startGrouping();
+    Object grouped = fact.createExpression("pow(int_i,double_d)");
+    assertTrue("The objects of the two mapping expressions are not the same.", ungrouped == grouped);
+    
+    // Grouped and ungrouped diferent mapping expressions
+    fact.startRequest();
+    ungrouped = fact.createExpression("pow(int_i,double_d)");
+    fact.startGrouping();
+    grouped = fact.createExpression("pow(int_i,float_f)");
+    assertFalse("The objects of the two mapping expressions are not the same.", ungrouped == grouped);
+    
+    // Grouped and ungrouped reduced expression.
+    fact.startRequest();
+    ungrouped = fact.createExpression("unique(add(int_i,double_d))");
+    fact.startGrouping();
+    grouped = fact.createExpression("unique(add(int_i,double_d))");
+    assertTrue("The objects of the two mapping expressions are not the same.", ungrouped == grouped);
+    
+    // Grouped and ungrouped different reduced expressions.
+    fact.startRequest();
+    ungrouped = fact.createExpression("unique(add(int_i,double_d))");
+    fact.startGrouping();
+    grouped = fact.createExpression("unique(add(int_i,float_f))");
+    assertFalse("The objects of the two mapping expressions are the same.", ungrouped == grouped);
+  }
+  
+  @Test
+  public void constantFunctionConversionTest() {
+    ExpressionFactory fact = getExpressionFactory();
+    fact.startRequest();
+
+    assertTrue(fact.createExpression("add(1,2)") instanceof ConstantValue);
+    assertTrue(fact.createExpression("add(1,2,2,3,4)") instanceof ConstantValue);
+    assertTrue(fact.createExpression("add(1)") instanceof ConstantValue);
+    assertTrue(fact.createExpression("concat(add(1,2), ' is a number')") instanceof ConstantValue);
+
+    assertFalse(fact.createExpression("sum(add(1,2))") instanceof ConstantValue);
+    assertFalse(fact.createExpression("sum(int_i)") instanceof ConstantValue);
+    assertFalse(fact.createExpression("sub(1,long_l)") instanceof ConstantValue);
+  }
+  
+  public void testReductionManager(ReductionCollectionManager manager, boolean hasExpressions, String... fields) {
+    Set<String> usedFields = new HashSet<>(Arrays.asList(fields));
+    manager.getUsedFields().forEach( field -> {
+      assertTrue("Field '" + field.getName() + "' is either not unique or should not exist in the reductionManager.", usedFields.remove(field.getName()));
+    });
+    assertEquals(hasExpressions, manager.needsCollection());
+  }
+  
+  @Test
+  public void reductionManagerCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    // No expressions
+    fact.startRequest();
+    testReductionManager(fact.createReductionManager(false), false);
+
+    // No fields
+    fact.startRequest();
+    fact.createExpression("sum(add(1,2))");
+    testReductionManager(fact.createReductionManager(false), true);
+    
+    // Multiple expressions
+    fact.startRequest();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    testReductionManager(fact.createReductionManager(false), true, "int_i", "float_f", "double_d");
+  }
+  
+  @Test
+  public void groupingReductionManagerCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+    
+    // No grouped expressions
+    fact.startRequest();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    fact.startGrouping();
+    testReductionManager(fact.createGroupingReductionManager(false), false);
+    
+    // No grouped fields
+    fact.startRequest();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    fact.startGrouping();
+    fact.createExpression("sum(add(1,2))");
+    testReductionManager(fact.createGroupingReductionManager(false), true);
+
+    // Single grouping, no ungrouped
+    fact.startRequest();
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "double_d");
+
+    // Single grouping, with ungrouped
+    fact.startRequest();
+    fact.createExpression("count(string_s)");
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "double_d");
+    
+    // Multiple groupings, no ungrouped
+    fact.startRequest();
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "double_d");
+    fact.startGrouping();
+    testReductionManager(fact.createGroupingReductionManager(false), false);
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("ordinal(1,concat(string_s,'-extra'))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "string_s");
+    
+    // Multiple groupings, with grouped
+    fact.startRequest();
+    fact.createExpression("count(string_s)");
+    fact.createExpression("median(date_math(date_dt,'+1DAY'))");
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("sum(add(int_i,double_d))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "double_d");
+    fact.startGrouping();
+    testReductionManager(fact.createGroupingReductionManager(false), false);
+    fact.startGrouping();
+    fact.createExpression("unique(add(int_i,float_f))");
+    fact.createExpression("ordinal(1,concat(string_s,'-extra'))");
+    testReductionManager(fact.createGroupingReductionManager(false), true, "int_i", "float_f", "string_s");
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/86d84bff/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
deleted file mode 100644
index 71503af..0000000
--- a/solr/contrib/analytics/src/test/org/apache/solr/analytics/NoFacetCloudTest.java
+++ /dev/null
@@ -1,557 +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;
-
-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/86d84bff/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 cfd1176..6a5f8c5 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
@@ -17,434 +17,232 @@
 package org.apache.solr.analytics;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-public class NoFacetTest extends AbstractAnalyticsStatsTest {
-  static String fileName = "noFacets.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;
-  
-  //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;
+public class NoFacetTest extends SolrAnalyticsTestCase {
   
   @BeforeClass
-  public static void beforeClass() throws Exception {
-    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));
-    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<>();
-    
+  public static void populate() throws Exception {
     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 dtm = (1800+j%DATE + 10) + "-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 ( i != 0 ) {
+        fields.add("int_i"); fields.add("" + i);
+        fields.add("int_im"); fields.add("" + i);
+        fields.add("int_im"); fields.add("" + (i+10));
+      }
       
-      if( (j%DATE) != 0 ){
-        fields.add("date_dtd"); fields.add(dt);
-        dateTestStart.add(dt);
-      } else dateMissing++;
+      if ( l != 0l ) {
+        fields.add("long_l"); fields.add("" + l);
+        fields.add("long_lm"); fields.add("" + l);
+        fields.add("long_lm"); fields.add("" + (l+10));
+      }
       
-      if( (j%STRING) != 0 ){
-        fields.add("string_sd"); fields.add(s);
-        stringTestStart.add(s);
-      } else stringMissing++;
+      if ( f != 0.0f ) {
+        fields.add("float_f"); fields.add("" + f);
+        fields.add("float_fm"); fields.add("" + f);
+        fields.add("float_fm"); fields.add("" + (f+10));
+      }
       
-      assertU(adoc(fields.toArray(new String[0])));
+      if ( d != 0.0d ) {
+        fields.add("double_d"); fields.add("" + d);
+        fields.add("double_dm"); fields.add("" + d);
+        fields.add("double_dm"); fields.add("" + (d+10));
+      }
       
+      if ( (j%DATE) != 0 ) {
+        fields.add("date_dt"); fields.add(dt);
+        fields.add("date_dtm"); fields.add(dt);
+        fields.add("date_dtm"); fields.add(dtm);
+      }
       
-      if (usually()) {
-        assertU(commit());  // to have several segments
+      if ( (j%STRING) != 0 ) {
+        fields.add("string_s"); fields.add(s);
+        fields.add("string_sm"); fields.add(s);
+        fields.add("string_sm"); fields.add(s + "_second");
       }
+
+      addDoc(fields);
     }
+    commitDocs();
+  }
+  
+  static public final int INT = 7;
+  static public final int LONG = 2;
+  static public final int FLOAT = 6;
+  static public final int DOUBLE = 5;
+  static public final int DATE = 3;
+  static public final int STRING = 4;
+  static public final int NUM_LOOPS = 20;
+
+  @Test
+  public void countTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("count(long_l)", 10L));
+    expressions.put("multi", new ETP("count(string_sm)", 30L));
     
-    assertU(commit()); 
+    testExpressions(expressions);
+  }
+  
+  @Test
+  public void docCountTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("doc_count(date_dt)", 13L));
+    expressions.put("multi", new ETP("doc_count(float_fm)", 16L));
     
-    //Sort ascending tests
-    setResponse(h.query(request(fileToStringArr(NoFacetTest.class, fileName))));
+    testExpressions(expressions);
   }
       
   @Test
-  public void sumTest() throws Exception {
-    //Int
-    Double intResult = (Double)getStatResult("sr", "int_id", VAL_TYPE.DOUBLE);
-    Double intTest = (Double)calculateNumberStat(intTestStart, "sum");
-    assertEquals(getRawResponse(), intResult,intTest);
-    
-    //Long
-    Double longResult = (Double)getStatResult("sr", "long_ld", VAL_TYPE.DOUBLE);
-    Double longTest = (Double)calculateNumberStat(longTestStart, "sum");
-    assertEquals(getRawResponse(), longResult,longTest);
-    
-    //Float
-    Double floatResult = (Double)getStatResult("sr", "float_fd", VAL_TYPE.DOUBLE);
-    Double floatTest = (Double)calculateNumberStat(floatTestStart, "sum");
-    assertEquals(getRawResponse(), floatResult,floatTest);
+  public void missingTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("missing(string_s)", 5L));
+    expressions.put("multi", new ETP("missing(date_dtm)", 7L));
     
-    //Double
-    Double doubleResult = (Double)getStatResult("sr", "double_dd", VAL_TYPE.DOUBLE);
-        Double doubleTest = (Double) calculateNumberStat(doubleTestStart, "sum");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
+    testExpressions(expressions);
   }
   
   @Test
-  public void meanTest() throws Exception { 
-    //Int
-    Double intResult = (Double)getStatResult("mr", "int_id", VAL_TYPE.DOUBLE);
-    Double intTest = (Double)calculateNumberStat(intTestStart, "mean");
-    assertEquals(getRawResponse(), intResult,intTest);
-    
-    //Long
-    Double longResult = (Double)getStatResult("mr", "long_ld", VAL_TYPE.DOUBLE);
-    Double longTest = (Double)calculateNumberStat(longTestStart, "mean");
-    assertEquals(getRawResponse(), longResult,longTest);
-    
-    //Float
-    Double floatResult = (Double)getStatResult("mr", "float_fd", VAL_TYPE.DOUBLE);
-    Double floatTest = (Double)calculateNumberStat(floatTestStart, "mean");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-    
-    //Double
-    Double doubleResult = (Double)getStatResult("mr", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "mean");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
+  public void uniqueTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("unique(int_i)", 6L));
+    expressions.put("longs", new ETP("unique(long_lm)", 2L));
+    expressions.put("float", new ETP("unique(float_f)", 5L));
+    expressions.put("doubles", new ETP("unique(double_dm)", 8L));
+    expressions.put("dates", new ETP("unique(date_dt)", 2L));
+    expressions.put("strings", new ETP("unique(string_sm)", 6L));
+
+    testExpressions(expressions);
   }
   
   @Test
-  public void stddevTest() throws Exception { 
-    //Int
-    Double intResult = (Double)getStatResult("str", "int_id", VAL_TYPE.DOUBLE);
-    Double intTest = (Double)calculateNumberStat(intTestStart, "stddev");
-    assertEquals(getRawResponse(), intResult, intTest, 0.00000000001);
-    
-    //Long
-    Double longResult = (Double)getStatResult("str", "long_ld", VAL_TYPE.DOUBLE);
-    Double longTest = (Double)calculateNumberStat(longTestStart, "stddev");
-    assertEquals(getRawResponse(), longResult, longTest, 0.00000000001);
-    
-    //Float
-    Double floatResult = (Double)getStatResult("str", "float_fd", VAL_TYPE.DOUBLE);
-    Double floatTest = (Double)calculateNumberStat(floatTestStart, "stddev");
-    assertEquals(getRawResponse(), floatResult, floatTest, 0.00000000001);
-
-
-    //Double
-    Double doubleResult = (Double)getStatResult("str", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "stddev");
-    assertEquals(getRawResponse(), doubleResult, doubleTest, 0.00000000001);
+  public void minTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("min(int_i)", 1));
+    expressions.put("longs", new ETP("min(long_lm)", 1L));
+    expressions.put("float", new ETP("min(float_f)", 1.0F));
+    expressions.put("doubles", new ETP("min(double_dm)", 1.0));
+    expressions.put("dates", new ETP("min(date_dt)", "1801-12-31T23:59:59Z"));
+    expressions.put("strings", new ETP("min(string_sm)", "str1"));
+
+    testExpressions(expressions);
   }
   
   @Test
-  public void medianTest() throws Exception { 
-    //Int
-    Double intResult = (Double)getStatResult("medr", "int_id", VAL_TYPE.DOUBLE);
-    Double intTest = (Double)calculateNumberStat(intTestStart, "median");
-    assertEquals(getRawResponse(), intResult,intTest);
-    
-    //Long
-    Double longResult = (Double)getStatResult("medr", "long_ld", VAL_TYPE.DOUBLE);
-    Double longTest = (Double)calculateNumberStat(longTestStart, "median");
-    assertEquals(getRawResponse(), longResult,longTest);
+  public void maxTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("max(int_i)", 6));
+    expressions.put("longs", new ETP("max(long_lm)", 11L));
+    expressions.put("float", new ETP("max(float_f)", 5.0F));
+    expressions.put("doubles", new ETP("max(double_dm)", 14.0));
+    expressions.put("dates", new ETP("max(date_dt)", "1802-12-31T23:59:59Z"));
+    expressions.put("strings", new ETP("max(string_sm)", "str3_second"));
+
+    testExpressions(expressions);
+  }
+  
+  @Test
+  public void sumTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("sum(int_i)", 57.0));
+    expressions.put("multi", new ETP("sum(long_lm)", 120.0));
     
-    //Float
-    Double floatResult = (Double)getStatResult("medr", "float_fd", VAL_TYPE.DOUBLE);
-    Double floatTest = (Double)calculateNumberStat(floatTestStart, "median");
-    assertEquals(getRawResponse(), floatResult,floatTest);
+    testExpressions(expressions);
+  }
+  
+  @Test
+  public void meanTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("mean(int_i)", 3.3529411764));
+    expressions.put("multi", new ETP("mean(long_lm)", 6.0));
     
-    //Double
-    Double doubleResult = (Double)getStatResult("medr", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateNumberStat(doubleTestStart, "median");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
+    testExpressions(expressions);
   }
   
   @Test
-  public void perc20Test() throws Exception {
-    //Int 20
-    Integer intResult = (Integer)getStatResult("p2r", "int_id", VAL_TYPE.INTEGER);
-    Integer intTest = (Integer)calculateStat(intTestStart, "perc_20");
-    assertEquals(getRawResponse(), intResult,intTest);
-
-    //Long 20
-    Long longResult = (Long)getStatResult("p2r", "long_ld", VAL_TYPE.LONG);
-    Long longTest = (Long)calculateStat(longTestStart, "perc_20");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float 20
-    Float floatResult = (Float)getStatResult("p2r", "float_fd", VAL_TYPE.FLOAT);
-    Float floatTest = (Float)calculateStat(floatTestStart, "perc_20");
-    //assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double 20
-    Double doubleResult = (Double)getStatResult("p2r", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateStat(doubleTestStart, "perc_20");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date 20
-    String dateResult = (String)getStatResult("p2r", "date_dtd", VAL_TYPE.DATE);
-    String dateTest = (String)calculateStat(dateTestStart, "perc_20");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String 20
-    String stringResult = (String)getStatResult("p2r", "string_sd", VAL_TYPE.STRING);
-    String stringTest = (String)calculateStat(stringTestStart, "perc_20");
-    assertEquals(getRawResponse(), stringResult,stringTest);
+  public void weightedMeanTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("wmean(int_i, long_l)", 3.33333333333));
+    expressions.put("multi", new ETP("wmean(double_d, float_f)", 2.470588235));
+    
+    testExpressions(expressions);
   }
   
   @Test
-  public void perc60Test() throws Exception { 
-    //Int 60
-    Integer intResult = (Integer)getStatResult("p6r", "int_id", VAL_TYPE.INTEGER);
-    Integer intTest = (Integer)calculateStat(intTestStart, "perc_60");
-    assertEquals(getRawResponse(), intResult,intTest);
-
-    //Long 60
-    Long longResult = (Long)getStatResult("p6r", "long_ld", VAL_TYPE.LONG);
-    Long longTest = (Long)calculateStat(longTestStart, "perc_60");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float 60
-    Float floatResult = (Float)getStatResult("p6r", "float_fd", VAL_TYPE.FLOAT);
-    Float floatTest = (Float)calculateStat(floatTestStart, "perc_60");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double 60
-    Double doubleResult = (Double)getStatResult("p6r", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateStat(doubleTestStart, "perc_60");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date 60
-    String dateResult = (String)getStatResult("p6r", "date_dtd", VAL_TYPE.DATE);
-    String dateTest = (String)calculateStat(dateTestStart, "perc_60");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String 60
-    String stringResult = (String)getStatResult("p6r", "string_sd", VAL_TYPE.STRING);
-    String stringTest = (String)calculateStat(stringTestStart, "perc_60");
-    assertEquals(getRawResponse(), stringResult,stringTest);
+  public void sumOfSquaresTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("sumofsquares(int_i)", 237.0));
+    expressions.put("multi", new ETP("sumofsquares(long_lm)", 1220.0));
+    
+    testExpressions(expressions);
   }
   
   @Test
-  public void minTest() throws Exception { 
-    //Int
-    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 longTest = (Long)calculateStat(longTestStart, "min");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float
-    Float floatResult = ((Float)getStatResult("mir", "float_fd", VAL_TYPE.FLOAT));
-    Float floatTest = (Float)calculateStat(floatTestStart, "min");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double
-    Double doubleResult = (Double)getStatResult("mir", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateStat(doubleTestStart, "min");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date
-    String dateResult = (String)getStatResult("mir", "date_dtd", VAL_TYPE.DATE);
-    String dateTest = (String)calculateStat(dateTestStart, "min");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String
-    String stringResult = (String)getStatResult("mir", "string_sd", VAL_TYPE.STRING);
-    String stringTest = (String)calculateStat(stringTestStart, "min");
-    assertEquals(getRawResponse(), stringResult,stringTest);
+  public void varianceTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("variance(int_i)", 2.6989619377162));
+    expressions.put("multi", new ETP("variance(long_lm)", 25.0));
+    
+    testExpressions(expressions);
   }
   
   @Test
-  public void maxTest() throws Exception { 
-    //Int
-    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 longTest = (Long)calculateStat(longTestStart, "max");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float
-    Float floatResult = ((Float)getStatResult("mar", "float_fd", VAL_TYPE.FLOAT));
-    Float floatTest = (Float)calculateStat(floatTestStart, "max");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double
-    Double doubleResult = (Double)getStatResult("mar", "double_dd", VAL_TYPE.DOUBLE);
-    Double doubleTest = (Double)calculateStat(doubleTestStart, "max");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date
-    String dateResult = (String)getStatResult("mar", "date_dtd", VAL_TYPE.DATE);
-    String dateTest = (String)calculateStat(dateTestStart, "max");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String
-    String stringResult = (String)getStatResult("mar", "string_sd", VAL_TYPE.STRING);
-    String stringTest = (String)calculateStat(stringTestStart, "max");
-    assertEquals(getRawResponse(), stringResult,stringTest);
+  public void standardDeviationTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("single", new ETP("stddev(int_i)", 1.6428517698551));
+    expressions.put("multi", new ETP("stddev(long_lm)", 5.0));
+    
+    testExpressions(expressions);
   }
   
   @Test
-  public void uniqueTest() throws Exception { 
-    //Int
-    Long intResult = (Long)getStatResult("ur", "int_id", VAL_TYPE.LONG);
-    Long intTest = (Long)calculateStat(intTestStart, "unique");
-    assertEquals(getRawResponse(), intResult,intTest);
-
-    //Long
-    Long longResult = (Long)getStatResult("ur", "long_ld", VAL_TYPE.LONG);
-    Long longTest = (Long)calculateStat(longTestStart, "unique");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float
-    Long floatResult = (Long)getStatResult("ur", "float_fd", VAL_TYPE.LONG);
-    Long floatTest = (Long)calculateStat(floatTestStart, "unique");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double
-    Long doubleResult = (Long)getStatResult("ur", "double_dd", VAL_TYPE.LONG);
-    Long doubleTest = (Long)calculateStat(doubleTestStart, "unique");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date
-    Long dateResult = (Long)getStatResult("ur", "date_dtd", VAL_TYPE.LONG);
-    Long dateTest = (Long)calculateStat(dateTestStart, "unique");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String
-    Long stringResult = (Long)getStatResult("ur", "string_sd", VAL_TYPE.LONG);
-    Long stringTest = (Long)calculateStat(stringTestStart, "unique");
-    assertEquals(getRawResponse(), stringResult,stringTest);
+  public void medianTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("median(int_i)", 3.0));
+    expressions.put("longs", new ETP("median(long_lm)", 6.0));
+    expressions.put("float", new ETP("median(float_f)", 3.0));
+    expressions.put("doubles", new ETP("median(double_dm)", 7.5));
+    expressions.put("dates", new ETP("median(date_dt)", "1801-12-31T23:59:59Z"));
+
+    testExpressions(expressions);
   }
   
   @Test
-  public void countTest() throws Exception { 
-    //Int
-    Long intResult = (Long)getStatResult("cr", "int_id", VAL_TYPE.LONG);
-    Long intTest = (Long)calculateStat(intTestStart, "count");
-    assertEquals(getRawResponse(), intResult,intTest);
-
-    //Long
-    Long longResult = (Long)getStatResult("cr", "long_ld", VAL_TYPE.LONG);
-    Long longTest = (Long)calculateStat(longTestStart, "count");
-    assertEquals(getRawResponse(), longResult,longTest);
-
-    //Float
-    Long floatResult = (Long)getStatResult("cr", "float_fd", VAL_TYPE.LONG);
-    Long floatTest = (Long)calculateStat(floatTestStart, "count");
-    assertEquals(getRawResponse(), floatResult,floatTest);
-
-    //Double
-    Long doubleResult = (Long)getStatResult("cr", "double_dd", VAL_TYPE.LONG);
-    Long doubleTest = (Long)calculateStat(doubleTestStart, "count");
-    assertEquals(getRawResponse(), doubleResult,doubleTest);
-
-    //Date
-    Long dateResult = (Long)getStatResult("cr", "date_dtd", VAL_TYPE.LONG);
-    Long dateTest = (Long)calculateStat(dateTestStart, "count");
-    assertEquals(getRawResponse(), dateResult,dateTest);
-
-    //String
-    Long stringResult = (Long)getStatResult("cr", "string_sd", VAL_TYPE.LONG);
-    Long stringTest = (Long)calculateStat(stringTestStart, "count");
-    assertEquals(getRawResponse(), stringResult,stringTest);
-  }  
-    
+  public void percentileTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("percentile(20,int_i)", 2));
+    expressions.put("longs", new ETP("percentile(80,long_lm)", 11L));
+    expressions.put("float", new ETP("percentile(40,float_f)", 2.0F));
+    expressions.put("doubles", new ETP("percentile(50,double_dm)", 11.0));
+    expressions.put("dates", new ETP("percentile(0,date_dt)", "1801-12-31T23:59:59Z"));
+    expressions.put("strings", new ETP("percentile(99.99,string_sm)", "str3_second"));
+
+    testExpressions(expressions);
+  }
+  
   @Test
-  public void missingDefaultTest() throws Exception { 
-    //Int
-    long intResult = (Long)getStatResult("misr", "int_id", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), intMissing,intResult);
-
-    //Long
-    long longResult = (Long)getStatResult("misr", "long_ld", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), longMissing,longResult);
-
-    //Float
-    long floatResult = (Long)getStatResult("misr", "float_fd", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), floatMissing,floatResult);
-
-    //Double
-    long doubleResult = (Long)getStatResult("misr", "double_dd", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), doubleMissing,doubleResult);
-
-    //Date
-    long dateResult = (Long)getStatResult("misr", "date_dtd", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), dateMissing,dateResult);
-
-    //String
-    long stringResult = (Long)getStatResult("misr", "string_sd", VAL_TYPE.LONG);
-    assertEquals(getRawResponse(), stringMissing, stringResult);
+  public void ordinalTest() throws Exception {
+    Map<String, ETP> expressions = new HashMap<>();
+    expressions.put("int", new ETP("ordinal(15,int_i)", 5));
+    expressions.put("longs", new ETP("ordinal(11,long_lm)", 11L));
+    expressions.put("float", new ETP("ordinal(-5,float_f)", 4.0F));
+    expressions.put("doubles", new ETP("ordinal(1,double_dm)", 1.0));
+    expressions.put("dates", new ETP("ordinal(-1,date_dt)", "1802-12-31T23:59:59Z"));
+    expressions.put("strings", new ETP("ordinal(6,string_sm)", "str1_second"));
+
+    testExpressions(expressions);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/86d84bff/solr/contrib/analytics/src/test/org/apache/solr/analytics/OverallAnalyticsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/OverallAnalyticsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/OverallAnalyticsTest.java
new file mode 100644
index 0000000..de6d6d2
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/OverallAnalyticsTest.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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.analytics.facet.SolrAnalyticsFacetTestCase;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class OverallAnalyticsTest extends SolrAnalyticsFacetTestCase {
+  
+  @BeforeClass
+  public static void populate() throws Exception {
+    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 dtm = (1800+j%DATE + 10) + "-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_i"); fields.add("" + i);
+        fields.add("int_im"); fields.add("" + i);
+        fields.add("int_im"); fields.add("" + (i+10));
+      }
+      
+      if ( l != 0l ) {
+        fields.add("long_l"); fields.add("" + l);
+        fields.add("long_lm"); fields.add("" + l);
+        fields.add("long_lm"); fields.add("" + (l+10));
+      }
+      
+      if ( f != 0.0f ) {
+        fields.add("float_f"); fields.add("" + f);
+        fields.add("float_fm"); fields.add("" + f);
+        fields.add("float_fm"); fields.add("" + (f+10));
+      }
+      
+      if ( d != 0.0d ) {
+        fields.add("double_d"); fields.add("" + d);
+        fields.add("double_dm"); fields.add("" + d);
+        fields.add("double_dm"); fields.add("" + (d+10));
+      }
+      
+      if ( (j%DATE) != 0 ) {
+        fields.add("date_dt"); fields.add(dt);
+        fields.add("date_dtm"); fields.add(dt);
+        fields.add("date_dtm"); fields.add(dtm);
+      }
+      
+      if ( (j%STRING) != 0 ) {
+        fields.add("string_s"); fields.add(s);
+        fields.add("string_sm"); fields.add(s);
+        fields.add("string_sm"); fields.add(s + "_second");
+      }
+
+      addDoc(fields);
+    }
+    commitDocs();
+  }
+  
+  static public final int INT = 7;
+  static public final int LONG = 2;
+  static public final int FLOAT = 6;
+  static public final int DOUBLE = 5;
+  static public final int DATE = 3;
+  static public final int STRING = 4;
+  static public final int NUM_LOOPS = 20;
+  
+  @Test
+  public void pivotFacetTest() throws Exception {
+    String analyticsRequest = "{"
+        + "\n 'expressions' : { "
+        + "\n   'floor_mean_add' : 'floor(mean(add(int_i,long_lm)))', "
+        + "\n   'consts' : 'max(mod(\\'_\\', string_s, 1800-01-01T11:59:59Z))' "
+        + "\n }, "
+        + "\n 'functions' : { "
+        + "\n   'mod(a,b..)' : 'concat_sep(a, b:concat(_,\\'-con\\'))', "
+        + "\n   'rep_0(num)' : 'fill_missing(num,0)' "
+        + "\n }, " 
+        + "\n 'groupings': { "
+        + "\n   'grouping0' : { "
+        + "\n     'expressions' : { "
+        + "\n       'mean' : 'mean(float_f)', "
+        + "\n       'count2' : 'count(string_sm)' "
+        + "\n     }, "
+        + "\n     'facets' : { "
+        + "\n       'ranges' : { "
+        + "\n         'type' : 'range', "
+        + "\n         'field': 'int_im', "
+        + "\n         'start': '2', "
+        + "\n         'end' : '13', "
+        + "\n         'gaps' : ['2', '5', '3'], "
+        + "\n         'hardend' : false "
+        + "\n       } "
+        + "\n     } "
+        + "\n   }, "
+        + "\n   'grouping1' : { "
+        + "\n     'expressions' : { "
+        + "\n       'mean' : 'mean(rep_0(int_i))', "
+        + "\n       'count' : 'count(long_lm)' "
+        + "\n     }, "
+        + "\n     'facets' : { "
+        + "\n       'queries' : { "
+        + "\n         'type' : 'query', "
+        + "\n         'queries' : { "
+        + "\n           'float < 3' : 'float_f:[* TO 3]', "
+        + "\n           'string = 1, date = 2' : 'string_s:\"str1\" AND date_dt:\"1802-12-31T23:59:59Z\"' "
+        + "\n         } "
+        + "\n       }, "
+        + "\n       'pivoting' : { "
+        + "\n         'type' : 'pivot', "
+        + "\n         'pivots' : [ "
+        + "\n           { "
+        + "\n             'name' : 'strings', "
+        + "\n             'expression' : 'string_sm', "
+        + "\n             'sort' : { "
+        + "\n               'criteria' : [ "
+        + "\n                 { "
+        + "\n                   'type' : 'expression', "
+        + "\n                   'expression' : 'mean', "
+        + "\n                   'direction' : 'ascending' "
+        + "\n                 }, "
+        + "\n                 { "
+        + "\n                   'type' : 'facetvalue', "
+        + "\n                   'direction' : 'descending' "
+        + "\n                 } "
+        + "\n               ], "
+        + "\n               'limit' : 3, "
+        + "\n               'offset' : 1 "
+        + "\n             } "
+        + "\n           }, "
+        + "\n           { "
+        + "\n             'name' : 'date', "
+        + "\n             'expression' : 'fill_missing(date_dt, \\'No Date\\')', "
+        + "\n             'sort' : { "
+        + "\n               'criteria' : [ "
+        + "\n                 { "
+        + "\n                   'type' : 'expression', "
+        + "\n                   'expression' : 'count', "
+        + "\n                   'direction' : 'ascending' "
+        + "\n                 }, "
+        + "\n                 { "
+        + "\n                   'type' : 'expression', "
+        + "\n                   'expression' : 'mean', "
+        + "\n                   'direction' : 'ascending' "
+        + "\n                 } "
+        + "\n               ], "
+        + "\n               'limit' : 2 "
+        + "\n             } "
+        + "\n           } "
+        + "\n         ] "
+        + "\n       } "
+        + "\n     } "
+        + "\n   } "
+        + "\n } "
+        + "\n} ";
+    
+    String test = "== {"
+        + "\n 'results' : { "
+        + "\n   'floor_mean_add' : 9, "
+        + "\n   'consts' : 'str3-con_1800-01-01T11:59:59Z-con' "
+        + "\n }, "
+        + "\n 'groupings' : { "
+        + "\n   'grouping0' : { "
+        + "\n     'ranges' : [ "
+        + "\n       { "
+        + "\n         'value' : '[2 TO 4)', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 3.5, "
+        + "\n           'count2' : 10 "
+        + "\n         } "
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'value' : '[4 TO 9)', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 3.2, "
+        + "\n           'count2' : 12 "
+        + "\n         } "
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'value' : '[9 TO 12)', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 2.0, "
+        + "\n           'count2' : 4 "
+        + "\n         } "
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'value' : '[12 TO 15)', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 3.75, "
+        + "\n           'count2' : 14 "
+        + "\n         } "
+        + "\n       } "
+        + "\n     ] "
+        + "\n   }, "
+        + "\n   'grouping1': { "
+        + "\n     'queries' : [ "
+        + "\n       { "
+        + "\n         'value' : 'float < 3', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 2.1, "
+        + "\n           'count' : 14 "
+        + "\n         } "
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'value' : 'string = 1, date = 2', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 4.0, "
+        + "\n           'count' : 4 "
+        + "\n         } "
+        + "\n       } "
+        + "\n     ], "
+        + "\n     'pivoting':["
+        + "\n       { "
+        + "\n         'pivot' : 'strings', "
+        + "\n         'value' : 'str3', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 2.6, "
+        + "\n           'count' : 10 "
+        + "\n         }, "
+        + "\n         'children' : [ "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : '1802-12-31T23:59:59Z', "
+        + "\n             'results' : { "
+        + "\n               'mean' : 4.0, "
+        + "\n               'count' : 2 "
+        + "\n             } "
+        + "\n           }, "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : 'No Date', "
+        + "\n               'results' : { "
+        + "\n               'mean' : 2.0, "
+        + "\n               'count' : 4 "
+        + "\n             } "
+        + "\n           } "
+        + "\n         ]"
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'pivot' : 'strings', "
+        + "\n         'value' : 'str2_second', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 3.0, "
+        + "\n           'count' : 0 "
+        + "\n         }, "
+        + "\n         'children' : [ "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : '1802-12-31T23:59:59Z', "
+        + "\n             'results' : { "
+        + "\n               'mean' : 1.0, "
+        + "\n               'count' : 0 "
+        + "\n             } "
+        + "\n           }, "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : '1801-12-31T23:59:59Z', "
+        + "\n             'results' : { "
+        + "\n               'mean' : 3.0, "
+        + "\n               'count' : 0 "
+        + "\n             } "
+        + "\n           } "
+        + "\n         ]"
+        + "\n       }, "
+        + "\n       { "
+        + "\n         'pivot' : 'strings', "
+        + "\n         'value' : 'str2', "
+        + "\n         'results' : { "
+        + "\n           'mean' : 3.0, "
+        + "\n           'count' : 0 "
+        + "\n         }, "
+        + "\n         'children' : [ "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : '1802-12-31T23:59:59Z', "
+        + "\n             'results' : { "
+        + "\n               'mean' : 1.0, "
+        + "\n               'count' : 0 "
+        + "\n             } "
+        + "\n           }, "
+        + "\n           { "
+        + "\n             'pivot' : 'date', "
+        + "\n             'value' : '1801-12-31T23:59:59Z', "
+        + "\n             'results' : { "
+        + "\n               'mean' : 3.0, "
+        + "\n               'count' : 0 "
+        + "\n             } "
+        + "\n           } "
+        + "\n         ]"
+        + "\n       } "
+        + "\n     ]"
+        + "\n   }"
+        + "\n }"
+        + "\n}";
+    
+    testAnalytics(analyticsRequest, test);
+  }
+}