You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dp...@apache.org on 2017/06/28 18:17:41 UTC
[18/20] lucene-solr:master: 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/accumulator/facet/FieldFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java
deleted file mode 100644
index fb0884b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.lucene.index.SortedSetDocValues;
-import org.apache.lucene.util.BytesRef;
-import org.apache.solr.analytics.accumulator.FacetingAccumulator;
-import org.apache.solr.analytics.accumulator.ValueAccumulator;
-import org.apache.solr.analytics.util.AnalyticsParsers.NumericParser;
-import org.apache.solr.analytics.util.AnalyticsParsers.Parser;
-import org.apache.solr.analytics.util.AnalyticsParsers;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.schema.DateValueFieldType;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.search.SolrIndexSearcher;
-
-/**
- * An Accumulator that manages the faceting for fieldFacets.
- * Collects the field facet values.
- */
-public class FieldFacetAccumulator extends ValueAccumulator {
- protected final Parser parser;
- protected final FacetValueAccumulator parent;
- protected final String name;
- protected final SolrIndexSearcher searcher;
- protected final SchemaField schemaField;
- protected final boolean multiValued;
- protected final boolean numField;
- protected final boolean dateField;
- protected SortedSetDocValues setValues;
- protected SortedDocValues sortValues;
- protected NumericDocValues numValues;
-
- public FieldFacetAccumulator(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField schemaField) throws IOException {
- if( !schemaField.hasDocValues() ){
- throw new IOException("Field '"+schemaField.getName()+"' does not have docValues and therefore cannot be faceted over.");
- }
- this.searcher = searcher;
- this.schemaField = schemaField;
- this.name = schemaField.getName();
- this.multiValued = schemaField.multiValued();
- this.numField = schemaField.getType().getNumberType()!=null;
- this.dateField = schemaField.getType() instanceof DateValueFieldType;
- this.parent = parent;
- this.parser = AnalyticsParsers.getParser(schemaField.getType().getClass());
- }
-
- public static FieldFacetAccumulator create(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField facetField) throws IOException{
- return new FieldFacetAccumulator(searcher,parent,facetField);
- }
-
- /**
- * Move to the next set of documents to add to the field facet.
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- if (multiValued) {
- setValues = context.reader().getSortedSetDocValues(name);
- } else {
- if (numField) {
- numValues = context.reader().getNumericDocValues(name);
- } else {
- sortValues = context.reader().getSortedDocValues(name);
- }
- }
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given fieldFacet and value(s).
- */
- @Override
- public void collect(int doc) throws IOException {
- if (multiValued) {
- boolean exists = false;
- if (setValues!=null) {
- if (doc > setValues.docID()) {
- setValues.advance(doc);
- }
- if (doc == setValues.docID()) {
- int term;
- while ((term = (int)setValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
- exists = true;
- final BytesRef value = setValues.lookupOrd(term);
- parent.collectField(doc, name, parser.parse(value) );
- }
- }
- }
- if (!exists) {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- if(numField){
- if(numValues != null) {
- int valuesDocID = numValues.docID();
- if (valuesDocID < doc) {
- valuesDocID = numValues.advance(doc);
- }
- if (valuesDocID == doc) {
- parent.collectField(doc, name, ((NumericParser)parser).parseNum(numValues.longValue()));
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- if(sortValues != null) {
- if (doc > sortValues.docID()) {
- sortValues.advance(doc);
- }
- if (doc == sortValues.docID()) {
- parent.collectField(doc, name, parser.parse(sortValues.lookupOrd(sortValues.ordValue())) );
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- } else {
- parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
- }
- }
- }
- }
-
- @Override
- public void compute() {}
-
- @Override
- public NamedList<?> export() { return null; }
-
- @Override
- public boolean needsScores() {
- return true; // TODO: is this true?
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
deleted file mode 100644
index 8b92ba0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.analytics.accumulator.ValueAccumulator;
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.common.util.NamedList;
-
-/**
- * An Accumulator that manages a certain query of a given query facet.
- */
-public class QueryFacetAccumulator extends ValueAccumulator {
- protected final FacetValueAccumulator parent;
- protected final String facetName;
- protected final String facetValue;
-
- public QueryFacetAccumulator(FacetValueAccumulator parent, String facetName, String facetValue) {
- this.parent = parent;
- this.facetName = facetName;
- this.facetValue = facetValue;
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given queryFacet and query.
- */
- @Override
- public void collect(int doc) throws IOException {
- parent.collectQuery(doc, facetName, facetValue);
- }
-
- /**
- * Update the readers of the queryFacet {@link StatsCollector}s in FacetingAccumulator
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- parent.setQueryStatsCollectorReaders(context);
- }
-
- @Override
- public void compute() {
- // NOP
- }
-
- @Override
- public NamedList<?> export() {
- // NOP
- return null;
- }
-
- @Override
- public boolean needsScores() {
- return true; // TODO: is this true?
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
deleted file mode 100644
index 59cf428..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/RangeFacetAccumulator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.accumulator.facet;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.analytics.statistics.StatsCollector;
-
-/**
- * An Accumulator that manages a certain range of a given range facet.
- */
-public class RangeFacetAccumulator extends QueryFacetAccumulator {
- public RangeFacetAccumulator(FacetValueAccumulator parent, String facetName, String facetValue) {
- super(parent, facetName, facetValue);
- }
-
- /**
- * Tell the FacetingAccumulator to collect the doc with the
- * given rangeFacet and range.
- */
- @Override
- public void collect(int doc) throws IOException {
- parent.collectRange(doc, facetName, facetValue);
- }
-
- /**
- * Update the readers of the rangeFacet {@link StatsCollector}s in FacetingAccumulator
- */
- @Override
- protected void doSetNextReader(LeafReaderContext context) throws IOException {
- parent.setRangeStatsCollectorReaders(context);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
deleted file mode 100644
index 3daf103..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Accumulators for accumulating over differnt types of facets
-
- */
-package org.apache.solr.analytics.accumulator.facet;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
deleted file mode 100644
index 0abe00a..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Accumulators accumulate values over different types of strucuture (eg result, facet, etc..)
- */
-package org.apache.solr.analytics.accumulator;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
deleted file mode 100644
index 2f0326b..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/BaseExpression.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-import java.util.Date;
-
-import org.apache.solr.analytics.statistics.StatsCollector;
-
-
-/**
- * <code>BaseExpression</code> returns the value returned by the {@link StatsCollector} for the specified stat.
- */
-public class BaseExpression extends Expression {
- protected final StatsCollector statsCollector;
- protected final String stat;
-
- public BaseExpression(StatsCollector statsCollector, String stat) {
- this.statsCollector = statsCollector;
- this.stat = stat;
- }
-
- public Comparable getValue() {
- if(statsCollector.getStatsList().contains(stat)) {
- return statsCollector.getStat(stat);
- }
- return null;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant double.
- */
-class ConstantNumberExpression extends Expression {
- protected final Double constant;
-
- public ConstantNumberExpression(double d) {
- constant = new Double(d);
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant date.
- */
-class ConstantDateExpression extends Expression {
- protected final Date constant;
-
- public ConstantDateExpression(Date date) {
- constant = date;
- }
-
- public ConstantDateExpression(Long date) {
- constant = new Date(date);
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
-/**
- * <code>ConstantStringExpression</code> returns the specified constant string.
- */
-class ConstantStringExpression extends Expression {
- protected final String constant;
-
- public ConstantStringExpression(String str) {
- constant = str;
- }
-
- public Comparable getValue() {
- return constant;
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
deleted file mode 100644
index f906b47..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/DualDelegateExpression.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-/**
- * Abstraction of an expression that applies a function to two delegate expressions.
- */
-public abstract class DualDelegateExpression extends Expression {
- protected Expression a;
- protected Expression b;
- public DualDelegateExpression(Expression a, Expression b) {
- this.a = a;
- this.b = b;
- }
-}
-/**
- * <code>DivideExpression</code> returns the quotient of 'a' and 'b'.
- */
-class DivideExpression extends DualDelegateExpression {
-
- /**
- * @param a numerator
- * @param b divisor
- */
- public DivideExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- double div = ((Number)aComp).doubleValue();
- div = div / ((Number)bComp).doubleValue();
- return new Double(div);
- }
-}
-/**
- * <code>PowerExpression</code> returns 'a' to the power of 'b'.
- */
-class PowerExpression extends DualDelegateExpression {
-
- /**
- * @param a base
- * @param b exponent
- */
- public PowerExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- return new Double(Math.pow(((Number)aComp).doubleValue(),((Number)bComp).doubleValue()));
- }
-}
-/**
- * <code>LogExpression</code> returns the log of the delegate's value given a base number.
- */
-class LogExpression extends DualDelegateExpression {
- /**
- * @param a number
- * @param b base
- */
- public LogExpression(Expression a, Expression b) {
- super(a,b);
- }
-
- @Override
- public Comparable getValue() {
- Comparable aComp = a.getValue();
- Comparable bComp = b.getValue();
- if (aComp==null || bComp==null) {
- return null;
- }
- return Math.log(((Number)aComp).doubleValue())/Math.log(((Number)bComp).doubleValue());
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
deleted file mode 100644
index ba26d9a..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/Expression.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-import java.util.Comparator;
-
-import org.apache.solr.analytics.request.FieldFacetRequest.FacetSortDirection;
-
-/**
- * Expressions map either zero, one, two or many inputs to a single value.
- * They can be defined recursively to compute complex math.
- */
-public abstract class Expression {
- public abstract Comparable getValue();
-
- public Comparator<Expression> comparator(final FacetSortDirection direction) {
- return (a, b) -> {
- if( direction == FacetSortDirection.ASCENDING ){
- return a.getValue().compareTo(b.getValue());
- } else {
- return b.getValue().compareTo(a.getValue());
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
deleted file mode 100644
index 1f2d0e0..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/ExpressionFactory.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.solr.analytics.statistics.StatsCollector;
-import org.apache.solr.analytics.util.AnalyticsParams;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.util.DateMathParser;
-
-public class ExpressionFactory {
-
- /**
- * Creates a single expression that contains delegate expressions and/or
- * a StatsCollector.
- * StatsCollectors are given as input and not created within the method so that
- * expressions can share the same StatsCollectors, minimizing computation.
- *
- * @param expression String representation of the desired expression
- * @param statsCollectors List of StatsCollectors to build the expression with.
- * @return the expression
- */
- @SuppressWarnings("deprecation")
- public static Expression create(String expression, StatsCollector[] statsCollectors) {
- int paren = expression.indexOf('(');
- if (paren<=0) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "The expression ["+expression+"] has no arguments and is not supported.");
- }
- String topOperation = expression.substring(0,paren).trim();
- String operands;
- try {
- operands = expression.substring(paren+1, expression.lastIndexOf(')')).trim();
- } catch (Exception e) {
- throw new SolrException(ErrorCode.BAD_REQUEST,"Missing closing parenthesis in ["+expression+"]",e);
- }
-
- // Builds a statistic, constant or recursively builds an expression tree
-
- // Statistic
- if (AnalyticsParams.ALL_STAT_SET.contains(topOperation)) {
- if (topOperation.equals(AnalyticsParams.STAT_PERCENTILE)) {
- operands = expression.substring(expression.indexOf(',')+1, expression.lastIndexOf(')')).trim();
- topOperation = topOperation+"_"+expression.substring(expression.indexOf('(')+1, expression.indexOf(',')).trim();
- }
- StatsCollector collector = null;
- // Finds the desired counter and builds an expression around it and the desired statistic.
- for (StatsCollector c : statsCollectors) {
- if (c.valueSourceString().equals(operands)) {
- collector = c;
- break;
- }
- }
- if (collector == null) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "ValueSource ["+operands+"] in Expression ["+expression+"] not found.");
- }
- return new BaseExpression(collector, topOperation);
- }
- // Constant
- if (topOperation.equals(AnalyticsParams.CONSTANT_NUMBER)) {
- try {
- return new ConstantNumberExpression(Double.parseDouble(operands));
- } catch (NumberFormatException e) {
- throw new SolrException(ErrorCode.BAD_REQUEST, "The constant "+operands+" cannot be converted into a number.",e);
- }
- } else if (topOperation.equals(AnalyticsParams.CONSTANT_DATE)) {
- return new ConstantDateExpression(DateMathParser.parseMath(null, operands));
- } else if (topOperation.equals(AnalyticsParams.CONSTANT_STRING)) {
- operands = expression.substring(paren+1, expression.lastIndexOf(')'));
- return new ConstantStringExpression(operands);
- }
-
- // Complex Delegating Expressions
- String[] arguments = getArguments(operands);
- Expression[] expArgs = new Expression[arguments.length];
- for (int count = 0; count < arguments.length; count++) {
- // Recursively builds delegate expressions
- expArgs[count] = create(arguments[count], statsCollectors);
- }
-
- // Single Delegate Expressions
- if (expArgs.length==1) {
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.NEGATE)) {
- return new NegateExpression(expArgs[0]);
- }
- if (topOperation.equals(AnalyticsParams.ABSOLUTE_VALUE)) {
- return new AbsoluteValueExpression(expArgs[0]);
- }
- // String Expression
- else if (topOperation.equals(AnalyticsParams.REVERSE)) {
- return new ReverseExpression(expArgs[0]);
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments.");
- } else {
- // Multi Delegate Expressions
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.ADD)) {
- return new AddExpression(expArgs);
- } else if (topOperation.equals(AnalyticsParams.MULTIPLY)) {
- return new MultiplyExpression(expArgs);
- }
- // Date Expression
- else if (topOperation.equals(AnalyticsParams.DATE_MATH)) {
- return new DateMathExpression(expArgs);
- }
- // String Expression
- else if (topOperation.equals(AnalyticsParams.CONCATENATE)) {
- return new ConcatenateExpression(expArgs);
- }
- // Dual Delegate Expressions
- else if (expArgs.length==2 && (topOperation.equals(AnalyticsParams.DIVIDE) || topOperation.equals(AnalyticsParams.POWER)
- || topOperation.equals(AnalyticsParams.LOG))) {
- // Numeric Expression
- if (topOperation.equals(AnalyticsParams.DIVIDE)) {
- return new DivideExpression(expArgs[0], expArgs[1]);
- } else if (topOperation.equals(AnalyticsParams.POWER)) {
- return new PowerExpression(expArgs[0], expArgs[1]);
- } else if (topOperation.equals(AnalyticsParams.LOG)) {
- return new LogExpression(expArgs[0], expArgs[1]);
- }
- return null;
- }
- throw new SolrException(ErrorCode.BAD_REQUEST, topOperation+" does not have the correct number of arguments or is unsupported.");
- }
-
- }
-
- /**
- * Splits up an Expression's arguments.
- *
- * @param expression Current expression string
- * @return List The list of arguments
- */
- public static String[] getArguments(String expression) {
- String[] strings = new String[1];
- int stack = 0;
- int start = 0;
- List<String> arguments = new ArrayList<>();
- char[] chars = expression.toCharArray();
- for (int count = 0; count < expression.length(); count++) {
- char c = chars[count];
- if (c==',' && stack == 0) {
- arguments.add(expression.substring(start, count).replace("\\(","(").replace("\\)",")").replace("\\,",",").trim());
- start = count+1;
- } else if (c == '(') {
- stack ++;
- } else if (c == ')') {
- stack --;
- } else if (c == '\\') {
- ; // Do nothing.
- }
- }
- if (stack==0) {
- arguments.add(expression.substring(start).trim());
- }
- return arguments.toArray(strings);
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
deleted file mode 100644
index 4ea66fa..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/MultiDelegateExpression.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-import java.text.ParseException;
-import java.util.Date;
-
-import org.apache.solr.util.DateMathParser;
-
-/**
- * Abstraction of an expression that applies a function to an array of delegate expressions.
- */
-public abstract class MultiDelegateExpression extends Expression {
- protected final Expression[] delegates;
-
- public MultiDelegateExpression(Expression[] delegates) {
- this.delegates = delegates;
- }
-}
-/**
- * <code>AddExpression</code> returns the sum of its components' values.
- */
-class AddExpression extends MultiDelegateExpression {
- public AddExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- double sum = 0;
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- } else if (dComp.getClass().equals(Date.class)) {
- dComp = new Long(((Date)dComp).getTime());
- }
- sum += ((Number)dComp).doubleValue();
- }
- return new Double(sum);
- }
-}
-/**
- * <code>MultiplyExpression</code> returns the product of its delegates' values.
- */
-class MultiplyExpression extends MultiDelegateExpression {
- public MultiplyExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- double prod = 1;
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- }
- prod *= ((Number)dComp).doubleValue();
- }
- return new Double(prod);
- }
-}
-/**
- * <code>DateMathExpression</code> returns the start date modified by the DateMath operations
- */
-class DateMathExpression extends MultiDelegateExpression {
- /**
- * @param delegates A list of Expressions. The first element in the list
- * should be a numeric Expression which represents the starting date.
- * The rest of the field should be string Expression objects which contain
- * the DateMath operations to perform on the start date.
- */
- public DateMathExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- DateMathParser parser = new DateMathParser();
- parser.setNow((Date)delegates[0].getValue());
- try {
- for (int count = 1; count<delegates.length; count++) {
- Comparable dComp = delegates[count].getValue();
- if (dComp==null) {
- return null;
- }
- parser.setNow(parser.parseMath((String)dComp));
- }
- return parser.getNow();
- } catch (ParseException e) {
- e.printStackTrace();
- return parser.getNow();
- }
- }
-}
-/**
- * <code>ConcatenateExpression</code> returns the concatenation of its delegates' values in the order given.
- */
-class ConcatenateExpression extends MultiDelegateExpression {
- public ConcatenateExpression(Expression[] delegates) {
- super(delegates);
- }
-
- @Override
- public Comparable getValue() {
- StringBuilder builder = new StringBuilder();
- for (Expression delegate : delegates) {
- Comparable dComp = delegate.getValue();
- if (dComp==null) {
- return null;
- }
- builder.append(dComp.toString());
- }
- return builder.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
deleted file mode 100644
index 8d94ece..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/SingleDelegateExpression.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.analytics.expression;
-
-import java.util.Date;
-
-/**
- * Abstraction of an expression that applies a function to one delegate expression.
- */
-public abstract class SingleDelegateExpression extends Expression {
- protected Expression delegate;
-
- public SingleDelegateExpression(Expression delegate) {
- this.delegate = delegate;
- }
-}
-/**
- * <code>NegateExpression</code> returns the negation of the delegate's value.
- */
-class NegateExpression extends SingleDelegateExpression {
- public NegateExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable nComp = delegate.getValue();
- if (nComp==null) {
- return null;
- } else if (nComp.getClass().equals(Date.class)) {
- nComp = new Long(((Date)nComp).getTime());
- }
- return new Double(((Number)nComp).doubleValue()*-1);
- }
-}
-/**
- * <code>AbsoluteValueExpression</code> returns the negation of the delegate's value.
- */
-class AbsoluteValueExpression extends SingleDelegateExpression {
- public AbsoluteValueExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable nComp = delegate.getValue();
- if (nComp==null) {
- return null;
- }
- double d = ((Number)nComp).doubleValue();
- if (d<0) {
- return new Double(d*-1);
- } else {
- return new Double(d);
- }
- }
-}
-/**
- * <code>StringExpression</code> returns the reverse of the delegate's string value.
- */
-class ReverseExpression extends SingleDelegateExpression {
- public ReverseExpression(Expression delegate) {
- super(delegate);
- }
-
- @Override
- public Comparable getValue() {
- Comparable rComp = delegate.getValue();
- if (rComp==null) {
- return null;
- }
- return new StringBuilder(rComp.toString()).reverse().toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
deleted file mode 100644
index 8c6f70e..0000000
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/expression/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Expressions map either zero, one, two or many inputs to a single value. They can be defined recursively to compute complex math.
- */
-package org.apache.solr.analytics.expression;
-
-
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
new file mode 100644
index 0000000..d06cfa3
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SimpleCollector;
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.SolrIndexSearcher;
+
+/**
+ * Solr Query Facets are AnalyticsFacets that are calculated after the document streaming phase has occurred in the {@link AnalyticsDriver}
+ * (during which StreamingFacets and overall expressions are calculated). {@link AbstractSolrQueryFacet}s should not be confused with {@link QueryFacet}s,
+ * which are a specific sub-type.
+ *
+ * <p>
+ * The filtering for these facets is done through issuing additional Solr queries, and collecting on the resulting documents.
+ * Unlike streaming facets, which have an unspecified amount of facet values (facet buckets), the amount of facet values is determined by the user and
+ * a Solr query is issued for each requested facet value.
+ */
+public abstract class AbstractSolrQueryFacet extends AnalyticsFacet {
+
+ protected AbstractSolrQueryFacet(String name) {
+ super(name);
+ }
+
+ /**
+ * Returns the set of {@link FacetValueQueryExecuter}s, one for each facet value, through the given consumer.
+ *
+ * Each of these executors will be executed after the streaming phase in the {@link AnalyticsDriver}.
+ *
+ * @param filter the overall filter representing the documents being used for the analytics request
+ * @param queryRequest the queryRequest
+ * @param consumer the consumer of each facet value's executer
+ */
+ public abstract void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer);
+
+ /**
+ * This executer is in charge of issuing the Solr query for a facet value and collecting results as the query is processed.
+ */
+ public class FacetValueQueryExecuter extends SimpleCollector {
+ private final ReductionDataCollection collection;
+ private final Query query;
+
+ /**
+ * Create an executer to collect the given reduction data from the given Solr query.
+ *
+ * @param collection The reduction data to collect while querying
+ * @param query The query used to filter for the facet value
+ */
+ public FacetValueQueryExecuter(ReductionDataCollection collection, Query query) {
+ this.collection = collection;
+ this.query = query;
+ }
+
+ @Override
+ public boolean needsScores() {
+ return false;
+ }
+
+ @Override
+ public void doSetNextReader(LeafReaderContext context) throws IOException {
+ collectionManager.doSetNextReader(context);
+ }
+
+ @Override
+ public void collect(int doc) throws IOException {
+ collectionManager.collect(doc);
+ collectionManager.apply();
+ }
+
+ /**
+ * Start the collection for this facet value.
+ *
+ * @param searcher the solr searcher
+ * @throws IOException if an exception occurs during the querying
+ */
+ public void execute(SolrIndexSearcher searcher) throws IOException {
+ collectionManager.clearLastingCollectTargets();
+ collectionManager.addLastingCollectTarget(collection);
+ searcher.search(query, this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
new file mode 100644
index 0000000..d9c0f8c
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AnalyticsFacet.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * An abstract Facet to break up Analytics data over.
+ */
+public abstract class AnalyticsFacet {
+ protected final Map<String,ReductionDataCollection> reductionData;
+ protected ReductionCollectionManager collectionManager;
+ protected ExpressionCalculator expressionCalculator;
+
+ protected final String name;
+
+ public AnalyticsFacet(String name) {
+ this.reductionData = new LinkedHashMap<>();
+ this.name = name;
+ }
+
+ /**
+ * Set the {@link ReductionCollectionManager} that manages the collection of the expressions
+ * calculated with this facet.
+ *
+ * @param collectionManager The manager for relevant expressions
+ */
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ this.collectionManager = collectionManager;
+ }
+
+ /**
+ * Set the {@link ExpressionCalculator} that calculates the collection of the expressions
+ * requested for this facet.
+ *
+ * @param expressionCalculator The calculator for relevant expressions
+ */
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ this.expressionCalculator = expressionCalculator;
+ }
+
+ /**
+ * Import the shard data from a bit-stream, exported by the {@link #exportShardData} method
+ * in the each of the collection's shards.
+ *
+ * @param input The bit-stream to import the data from
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public void importShardData(DataInput input) throws IOException {
+ int size = input.readInt();
+ for (int i = 0; i < size; ++i) {
+ importFacetValue(input, input.readUTF());
+ }
+ }
+ /**
+ * Import the next facet value's set of {@link ReductionData}.
+ *
+ * @param input the bit-stream to import the reduction data from
+ * @param facetValue the next facet value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected void importFacetValue(DataInput input, String facetValue) throws IOException {
+ ReductionDataCollection dataCollection = reductionData.get(facetValue);
+ if (dataCollection == null) {
+ reductionData.put(facetValue, collectionManager.newDataCollectionIO());
+ } else {
+ collectionManager.prepareReductionDataIO(dataCollection);
+ }
+
+ collectionManager.mergeData();
+ }
+
+ /**
+ * Export the shard data through a bit-stream, to be imported by the {@link #importShardData} method
+ * in the originating shard.
+ *
+ * @param output The bit-stream to output the data through
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportShardData(DataOutput output) throws IOException {
+ output.writeInt(reductionData.size());
+ for (String facetValue : reductionData.keySet()) {
+ exportFacetValue(output, facetValue);
+ }
+ }
+ /**
+ * Export the next facet value's set of {@link ReductionData}.
+ *
+ * @param output the bit-stream to output the reduction data to
+ * @param facetValue the next facet value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected void exportFacetValue(DataOutput output, String facetValue) throws IOException {
+ output.writeUTF(facetValue);
+
+ collectionManager.prepareReductionDataIO(reductionData.get(facetValue));
+ collectionManager.exportData();
+ }
+
+ /**
+ * Create the old olap-style response of the facet to be returned in the overall analytics response.
+ *
+ * @return the response of the facet
+ */
+ public NamedList<Object> createOldResponse() {
+ NamedList<Object> nl = new NamedList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ nl.add(facetVal, new NamedList<>(expressionCalculator.getResults()));
+ });
+ return nl;
+ }
+
+ /**
+ * Create the response of the facet to be returned in the overall analytics response.
+ *
+ * @return the response of the facet
+ */
+ public Iterable<Map<String,Object>> createResponse() {
+ LinkedList<Map<String,Object>> list = new LinkedList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ Map<String, Object> bucket = new HashMap<>();
+ bucket.put(AnalyticsResponseHeadings.FACET_VALUE, facetVal);
+ collectionManager.setData(dataCol);
+ expressionCalculator.addResults(bucket);
+ list.add(bucket);
+ });
+ return list;
+ }
+
+ /**
+ * Get the name of the Facet. This is unique for the grouping.
+ *
+ * @return The name of the Facet
+ */
+ public String getName() {
+ return name;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
new file mode 100644
index 0000000..f9e35f7
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotFacet.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * A facet that takes in multiple ValueFacet expressions and does analytics calculations over each dimension given.
+ */
+public class PivotFacet extends AnalyticsFacet implements StreamingFacet {
+ private final PivotHead<?> pivotHead;
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public PivotFacet(String name, PivotNode<?> topPivot) {
+ super(name);
+ this.pivotHead = new PivotHead(topPivot);
+ }
+
+ @Override
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ pivotHead.setReductionCollectionManager(collectionManager);
+ }
+
+ @Override
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ pivotHead.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ pivotHead.addFacetValueCollectionTargets();
+ }
+
+ @Override
+ public void importShardData(DataInput input) throws IOException {
+ pivotHead.importShardData(input);
+ }
+
+ @Override
+ public void exportShardData(DataOutput output) throws IOException {
+ pivotHead.exportShardData(output);
+ }
+
+ @Override
+ public NamedList<Object> createOldResponse() {
+ return new NamedList<>();
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> createResponse() {
+ return pivotHead.createResponse();
+ }
+}
+/**
+ * Typed Pivot class that stores the overall Pivot data and head of the Pivot node chain.
+ *
+ * This class exists so that the {@link PivotFacet} class doesn't have to be typed ( {@code <T>} ).
+ */
+class PivotHead<T> implements StreamingFacet {
+ private final PivotNode<T> topPivot;
+ private final Map<String, T> pivotValues;
+
+ public PivotHead(PivotNode<T> topPivot) {
+ this.topPivot = topPivot;
+ this.pivotValues = new HashMap<>();
+ }
+
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ topPivot.setReductionCollectionManager(collectionManager);
+ }
+
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ topPivot.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ topPivot.addFacetValueCollectionTargets(pivotValues);
+ }
+
+ public void importShardData(DataInput input) throws IOException {
+ topPivot.importPivot(input, pivotValues);
+ }
+
+ public void exportShardData(DataOutput output) throws IOException {
+ topPivot.exportPivot(output, pivotValues);
+ }
+
+ public Iterable<Map<String,Object>> createResponse() {
+ return topPivot.getPivotedResponse(pivotValues);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
new file mode 100644
index 0000000..c6c0dc4
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/PivotNode.java
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ExpressionCalculator;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.function.reduction.data.ReductionData;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * Representation of one layer of a Pivot Facet. A PivotFacet node is individually sortable,
+ * and is collected during the streaming phase of the {@link AnalyticsDriver}.
+ */
+public abstract class PivotNode<T> extends SortableFacet implements Consumer<String> {
+ private StringValueStream expression;
+ protected Map<String,T> currentPivot;
+
+ public PivotNode(String name, StringValueStream expression) {
+ super(name);
+ this.expression = expression;
+ }
+
+ /**
+ * Determine which facet values match the current document. Add the {@link ReductionDataCollection}s of the relevant facet values
+ * to the targets of the streaming {@link ReductionCollectionManager} so that they are updated with the current document's data.
+ */
+ public void addFacetValueCollectionTargets(Map<String,T> pivot) {
+ currentPivot = pivot;
+ expression.streamStrings(this);
+ }
+
+ /**
+ * Import the shard data from a bit-stream for the given pivot, exported by the {@link #exportPivot} method
+ * in the each of the collection's shards.
+ *
+ * @param input The bit-stream to import the data from
+ * @param pivot the values for this pivot node and the pivot children (if they exist)
+ * @throws IOException if an exception occurs while reading from the {@link DataInput}
+ */
+ public void importPivot(DataInput input, Map<String,T> pivot) throws IOException {
+ int size = input.readInt();
+ currentPivot = pivot;
+ for (int i = 0; i < size; ++i) {
+ importPivotValue(input, input.readUTF());
+ }
+ }
+ /**
+ * Import the next pivot value's set of {@link ReductionData} and children's {@link ReductionData} if they exist.
+ *
+ * @param input the bit-stream to import the reduction data from
+ * @param pivotValue the next pivot value
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected abstract void importPivotValue(DataInput input, String pivotValue) throws IOException;
+
+ /**
+ * Export the shard data through a bit-stream for the given pivot,
+ * to be imported by the {@link #importPivot} method in the originating shard.
+ *
+ * @param output The bit-stream to output the data through
+ * @param pivot the values for this pivot node and the pivot children (if they exist)
+ * @throws IOException if an exception occurs while writing to the {@link DataOutput}
+ */
+ public void exportPivot(DataOutput output, Map<String,T> pivot) throws IOException {
+ output.writeInt(pivot.size());
+ for (String pivotValue : pivot.keySet()) {
+ output.writeUTF(pivotValue);
+ exportPivotValue(output, pivot.get(pivotValue));
+ }
+ }
+ /**
+ * Export the given pivot data, containing {@link ReductionData} and pivot children if they exist.
+ *
+ * @param output the bit-stream to output the reduction data to
+ * @param pivotData the next pivot value data
+ * @throws IOException if an exception occurs while reading from the input
+ */
+ protected abstract void exportPivotValue(DataOutput output, T pivotData) throws IOException;
+
+ /**
+ * Create the response of the facet to be returned in the overall analytics response.
+ *
+ * @param pivot the pivot to create a response for
+ * @return the response of the facet
+ */
+ public abstract Iterable<Map<String,Object>> getPivotedResponse(Map<String,T> pivot);
+
+ /**
+ * A pivot node that has no pivot children.
+ */
+ public static class PivotLeaf extends PivotNode<ReductionDataCollection> {
+
+ public PivotLeaf(String name, StringValueStream expression) {
+ super(name, expression);
+ }
+
+ @Override
+ public void accept(String pivotValue) {
+ ReductionDataCollection collection = currentPivot.get(pivotValue);
+ if (collection == null) {
+ collection = collectionManager.newDataCollectionTarget();
+ currentPivot.put(pivotValue, collection);
+ } else {
+ collectionManager.addCollectTarget(collection);
+ }
+ }
+
+ @Override
+ protected void importPivotValue(DataInput input, String pivotValue) throws IOException {
+ ReductionDataCollection dataCollection = currentPivot.get(pivotValue);
+ if (dataCollection == null) {
+ currentPivot.put(pivotValue, collectionManager.newDataCollectionIO());
+ } else {
+ collectionManager.prepareReductionDataIO(dataCollection);
+ }
+ collectionManager.mergeData();
+ }
+
+ @Override
+ protected void exportPivotValue(DataOutput output, ReductionDataCollection pivotData) throws IOException {
+ collectionManager.prepareReductionDataIO(pivotData);
+ collectionManager.exportData();
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> getPivotedResponse(Map<String,ReductionDataCollection> pivot) {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ pivot.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ Iterable<FacetBucket> facetResultsIter = applyOptions(facetResults);
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : facetResultsIter) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_NAME, name);
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ results.add(bucketMap);
+ }
+ return results;
+ }
+ }
+
+ /**
+ * A pivot node that has pivot children.
+ */
+ public static class PivotBranch<T> extends PivotNode<PivotBranch.PivotDataPair<T>> {
+ private final PivotNode<T> childPivot;
+ public PivotBranch(String name, StringValueStream expression, PivotNode<T> childPivot) {
+ super(name, expression);
+ this.childPivot = childPivot;
+ }
+
+ @Override
+ public void setReductionCollectionManager(ReductionCollectionManager collectionManager) {
+ super.setReductionCollectionManager(collectionManager);
+ childPivot.setReductionCollectionManager(collectionManager);
+ }
+
+ @Override
+ public void setExpressionCalculator(ExpressionCalculator expressionCalculator) {
+ super.setExpressionCalculator(expressionCalculator);
+ childPivot.setExpressionCalculator(expressionCalculator);
+ }
+
+ @Override
+ public void accept(String pivotValue) {
+ PivotDataPair<T> pivotData = currentPivot.get(pivotValue);
+ if (pivotData == null) {
+ pivotData = new PivotDataPair<>();
+ pivotData.childPivots = new HashMap<>();
+ pivotData.pivotReduction = collectionManager.newDataCollectionTarget();
+ currentPivot.put(pivotValue, pivotData);
+ } else {
+ collectionManager.addCollectTarget(pivotData.pivotReduction);
+ }
+ childPivot.addFacetValueCollectionTargets(pivotData.childPivots);
+ }
+
+ @Override
+ protected void importPivotValue(DataInput input, String pivotValue) throws IOException {
+ PivotDataPair<T> pivotData = currentPivot.get(pivotValue);
+ if (pivotData == null) {
+ pivotData = new PivotDataPair<>();
+ pivotData.childPivots = new HashMap<>();
+ pivotData.pivotReduction = collectionManager.newDataCollectionIO();
+ currentPivot.put(pivotValue, pivotData);
+ } else {
+ collectionManager.prepareReductionDataIO(pivotData.pivotReduction);
+ }
+ collectionManager.mergeData();
+ childPivot.importPivot(input, pivotData.childPivots);
+ }
+
+ @Override
+ protected void exportPivotValue(DataOutput output, PivotDataPair<T> pivotData) throws IOException {
+ collectionManager.prepareReductionDataIO(pivotData.pivotReduction);
+ collectionManager.exportData();
+
+ childPivot.exportPivot(output, pivotData.childPivots);
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> getPivotedResponse(Map<String,PivotDataPair<T>> pivot) {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ pivot.forEach((facetVal, dataPair) -> {
+ collectionManager.setData(dataPair.pivotReduction);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ Iterable<FacetBucket> facetResultsIter = applyOptions(facetResults);
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : facetResultsIter) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_NAME, name);
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ bucketMap.put(AnalyticsResponseHeadings.PIVOT_CHILDREN, childPivot.getPivotedResponse(pivot.get(bucket.getFacetValue()).childPivots));
+ results.add(bucketMap);
+ }
+ return results;
+ }
+
+ /**
+ * Contains pivot data for {@link PivotNode.PivotBranch} classes.
+ */
+ protected static class PivotDataPair<T> {
+ ReductionDataCollection pivotReduction;
+ Map<String,T> childPivots;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
new file mode 100644
index 0000000..f880809
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/QueryFacet.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.Filter;
+import org.apache.solr.search.QParser;
+
+/**
+ * A facet that breaks down the data by additional Solr Queries.
+ */
+public class QueryFacet extends AbstractSolrQueryFacet {
+ private final Map<String,String> queries;
+
+ public QueryFacet(String name, Map<String, String> queries) {
+ super(name);
+ this.queries = queries;
+ }
+
+ @Override
+ public void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer) {
+ queries.forEach( (queryName, query) -> {
+ final Query q;
+ try {
+ q = QParser.getParser(query, queryRequest).getQuery();
+ } catch( Exception e ){
+ throw new SolrException(ErrorCode.BAD_REQUEST,"Invalid query '"+query+"' in query facet '" + getName() + "'",e);
+ }
+ // The searcher sends docIds to the QueryFacetAccumulator which forwards
+ // them to <code>collectQuery()</code> in this class for collection.
+ Query queryQuery = new BooleanQuery.Builder()
+ .add(q, Occur.MUST)
+ .add(filter, Occur.FILTER)
+ .build();
+
+ ReductionDataCollection dataCol = collectionManager.newDataCollection();
+ reductionData.put(queryName, dataCol);
+ consumer.accept(new FacetValueQueryExecuter(dataCol, queryQuery));
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
new file mode 100644
index 0000000..80e8d21
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/RangeFacet.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.util.FacetRangeGenerator;
+import org.apache.solr.analytics.util.FacetRangeGenerator.FacetRange;
+import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
+import org.apache.solr.common.params.FacetParams.FacetRangeOther;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.search.Filter;
+
+/**
+ * A facet that groups data by a discrete set of ranges.
+ */
+public class RangeFacet extends AbstractSolrQueryFacet {
+ protected final SchemaField field;
+ protected final String start;
+ protected final String end;
+ protected final List<String> gaps;
+ protected boolean hardEnd = false;
+ protected EnumSet<FacetRangeInclude> include;
+ protected EnumSet<FacetRangeOther> others;
+
+ public RangeFacet(String name, SchemaField field, String start, String end, List<String> gaps) {
+ super(name);
+ this.field = field;
+ this.start = start;
+ this.end = end;
+ this.gaps = gaps;
+ include = EnumSet.of(FacetRangeInclude.LOWER);
+ others = EnumSet.of(FacetRangeOther.NONE);
+ }
+
+ @Override
+ public void createFacetValueExecuters(final Filter filter, SolrQueryRequest queryRequest, Consumer<FacetValueQueryExecuter> consumer) {
+ // Computes the end points of the ranges in the rangeFacet
+ final FacetRangeGenerator<? extends Comparable<?>> rec = FacetRangeGenerator.create(this);
+ final SchemaField sf = field;
+
+ // Create a rangeFacetAccumulator for each range and
+ // collect the documents for that range.
+ for (FacetRange range : rec.getRanges()) {
+ Query q = sf.getType().getRangeQuery(null, sf, range.lower, range.upper, range.includeLower,range.includeUpper);
+ // The searcher sends docIds to the RangeFacetAccumulator which forwards
+ // them to <code>collectRange()</code> in this class for collection.
+ Query rangeQuery = new BooleanQuery.Builder()
+ .add(q, Occur.MUST)
+ .add(filter, Occur.FILTER)
+ .build();
+
+ ReductionDataCollection dataCol = collectionManager.newDataCollection();
+ reductionData.put(range.toString(), dataCol);
+ consumer.accept(new FacetValueQueryExecuter(dataCol, rangeQuery));
+ }
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public EnumSet<FacetRangeInclude> getInclude() {
+ return include;
+ }
+
+ public void setInclude(EnumSet<FacetRangeInclude> include) {
+ this.include = include;
+ }
+
+ public List<String> getGaps() {
+ return gaps;
+ }
+
+ public boolean isHardEnd() {
+ return hardEnd;
+ }
+
+ public void setHardEnd(boolean hardEnd) {
+ this.hardEnd = hardEnd;
+ }
+
+ public EnumSet<FacetRangeOther> getOthers() {
+ return others;
+ }
+
+ public void setOthers(EnumSet<FacetRangeOther> others) {
+ this.others = others;
+ }
+
+ public SchemaField getField() {
+ return field;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
new file mode 100644
index 0000000..ef1e04b
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.solr.analytics.facet.compare.FacetResultsComparator;
+import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
+import org.apache.solr.common.util.NamedList;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * A facet that can be sorted by either the facet value or an expression value.
+ */
+public abstract class SortableFacet extends AnalyticsFacet {
+ protected FacetSortSpecification sort = null;
+
+ protected SortableFacet(String name) {
+ super(name);
+ }
+
+ @Override
+ public NamedList<Object> createOldResponse() {
+ final NamedList<Object> results = new NamedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : getBuckets()) {
+ results.add(bucket.getFacetValue(), new NamedList<>(bucket.getResults()));
+ }
+ return results;
+ }
+
+ @Override
+ public Iterable<Map<String,Object>> createResponse() {
+ final LinkedList<Map<String,Object>> results = new LinkedList<>();
+ // Export each expression in the bucket.
+ for (FacetBucket bucket : getBuckets()) {
+ Map<String, Object> bucketMap = new HashMap<>();
+ bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
+ bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
+ results.add(bucketMap);
+ }
+ return results;
+ }
+
+ private Iterable<FacetBucket> getBuckets() {
+ final List<FacetBucket> facetResults = new ArrayList<>();
+ reductionData.forEach((facetVal, dataCol) -> {
+ collectionManager.setData(dataCol);
+ facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
+ });
+
+ return applyOptions(facetResults);
+ }
+
+ /**
+ * Apply the sorting options to the given facet results.
+ *
+ * @param facetResults to apply sorting options to
+ * @return the sorted results
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ protected Iterable<FacetBucket> applyOptions(List<FacetBucket> facetResults) {
+ // Sorting the buckets if a sort specification is provided
+ if (sort == null || facetResults.isEmpty()) {
+ return facetResults;
+ }
+ Comparator comp = sort.getComparator();
+ Collections.sort(facetResults, comp);
+
+ Iterable<FacetBucket> facetResultsIter = facetResults;
+ // apply the limit
+ if (sort.getLimit() > 0) {
+ if (sort.getOffset() > 0) {
+ facetResultsIter = Iterables.skip(facetResultsIter, sort.getOffset());
+ }
+ facetResultsIter = Iterables.limit(facetResultsIter, sort.getLimit());
+ } else if (sort.getLimit() == 0) {
+ return new LinkedList<FacetBucket>();
+ }
+ return facetResultsIter;
+ }
+
+ /**
+ * Specifies how to sort the buckets of a sortable facet.
+ */
+ public static class FacetSortSpecification {
+ private FacetResultsComparator comparator;
+ protected int limit;
+ protected int offset;
+
+ public FacetSortSpecification(FacetResultsComparator comparator, int limit, int offset) {
+ this.comparator = comparator;
+ this.limit = limit;
+ this.offset = offset;
+ }
+
+ public FacetResultsComparator getComparator() {
+ return comparator;
+ }
+
+ /**
+ * Get the maximum number of buckets to be returned.
+ *
+ * @return the limit
+ */
+ public int getLimit() {
+ return limit;
+ }
+ /**
+ * Set the maximum number of buckets to be returned.
+ *
+ * @param limit the maximum number of buckets
+ */
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ /**
+ * Get the first bucket to return, has to be used with the {@code limit} option.
+ *
+ * @return the bucket offset
+ */
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+ public SortableFacet.FacetSortSpecification getSort() {
+ return sort;
+ }
+
+ public void setSort(SortableFacet.FacetSortSpecification sort) {
+ this.sort = sort;
+ }
+
+ public static class FacetBucket {
+ private final String facetValue;
+ private final Map<String,Object> expressionResults;
+
+ public FacetBucket(String facetValue, Map<String,Object> expressionResults) {
+ this.facetValue = facetValue;
+ this.expressionResults = expressionResults;
+ }
+
+ public Object getResult(String expression) {
+ return expressionResults.get(expression);
+ }
+
+ public Map<String,Object> getResults() {
+ return expressionResults;
+ }
+
+ public String getFacetValue() {
+ return facetValue;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
new file mode 100644
index 0000000..6cca041
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/StreamingFacet.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import org.apache.solr.analytics.AnalyticsDriver;
+import org.apache.solr.analytics.function.ReductionCollectionManager;
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+
+/**
+ * A facet that is collected during the streaming phase of the {@link AnalyticsDriver}.
+ */
+public interface StreamingFacet {
+ /**
+ * Determine which facet values match the current document. Add the {@link ReductionDataCollection}s of the relevant facet values
+ * to the targets of the streaming {@link ReductionCollectionManager} so that they are updated with the current document's data.
+ */
+ void addFacetValueCollectionTargets();
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5963beb/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java
new file mode 100644
index 0000000..b1d84ba
--- /dev/null
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/ValueFacet.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.analytics.facet;
+
+import java.util.function.Consumer;
+
+import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection;
+import org.apache.solr.analytics.value.StringValueStream;
+
+/**
+ * A facet that breaks up data by the values of a mapping expression or field.
+ * The mapping expression must be castable to a {@link StringValueStream}.
+ */
+public class ValueFacet extends SortableFacet implements StreamingFacet, Consumer<String> {
+ private StringValueStream expression;
+
+ public ValueFacet(String name, StringValueStream expression) {
+ super(name);
+ this.expression = expression;
+ }
+
+ @Override
+ public void addFacetValueCollectionTargets() {
+ expression.streamStrings(this);
+ }
+
+ @Override
+ public void accept(String t) {
+ ReductionDataCollection collection = reductionData.get(t);
+ if (collection == null) {
+ collection = collectionManager.newDataCollectionTarget();
+ reductionData.put(t, collection);
+ } else {
+ collectionManager.addCollectTarget(collection);
+ }
+ }
+
+ /**
+ * Get the expression used to create the facet values.
+ *
+ * @return a string mapping expression
+ */
+ public StringValueStream getExpression() {
+ return expression;
+ }
+}
\ No newline at end of file