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/07/03 11:57:45 UTC

[05/58] [abbrv] lucene-solr:jira/solr-10879: SOLR-10123: Upgraded the Analytics Component to version 2.0

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;
+
+