You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jb...@apache.org on 2017/02/08 18:04:32 UTC
[1/3] lucene-solr:jira/solr-8593: SOLR-8593: Push down the HAVING
clause
Repository: lucene-solr
Updated Branches:
refs/heads/jira/solr-8593 63eecedbc -> de512d740
SOLR-8593: Push down the HAVING clause
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/de512d74
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/de512d74
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/de512d74
Branch: refs/heads/jira/solr-8593
Commit: de512d7402024acb61917cacfd98e9aaaed4a456
Parents: a9cf150
Author: Joel Bernstein <jb...@apache.org>
Authored: Wed Feb 8 12:55:18 2017 -0500
Committer: Joel Bernstein <jb...@apache.org>
Committed: Wed Feb 8 13:01:31 2017 -0500
----------------------------------------------------------------------
.../apache/solr/handler/sql/SolrAggregate.java | 3 +
.../org/apache/solr/handler/sql/SolrFilter.java | 231 ++++++++++++++++---
.../org/apache/solr/handler/sql/SolrMethod.java | 1 +
.../org/apache/solr/handler/sql/SolrRel.java | 14 ++
.../org/apache/solr/handler/sql/SolrRules.java | 4 +-
.../org/apache/solr/handler/sql/SolrTable.java | 90 ++++++--
.../handler/sql/SolrToEnumerableConverter.java | 3 +-
.../solr/client/solrj/io/ops/AndOperation.java | 59 ++---
.../solr/client/solrj/io/ops/OrOperation.java | 47 ++--
9 files changed, 354 insertions(+), 98 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrAggregate.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrAggregate.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrAggregate.java
index 5068b2e..983ab76 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrAggregate.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrAggregate.java
@@ -69,8 +69,11 @@ class SolrAggregate extends Aggregate implements SolrRel {
for(Pair<AggregateCall, String> namedAggCall : getNamedAggCalls()) {
+
AggregateCall aggCall = namedAggCall.getKey();
+
Pair<String, String> metric = toSolrMetric(implementor, aggCall, inNames);
+ implementor.addReverseAggMapping(namedAggCall.getValue(), metric.getKey().toLowerCase()+"("+metric.getValue()+")");
implementor.addMetricPair(namedAggCall.getValue(), metric.getKey(), metric.getValue());
if(aggCall.getName() == null) {
implementor.addFieldMapping(namedAggCall.getValue(),
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
index 01d3346..50102b1 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
@@ -29,6 +29,7 @@ import org.apache.calcite.util.Pair;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Implementation of a {@link org.apache.calcite.rel.core.Filter} relational expression in Solr.
@@ -54,13 +55,18 @@ class SolrFilter extends Filter implements SolrRel {
public void implement(Implementor implementor) {
implementor.visitChild(0, getInput());
- Translator translator = new Translator(SolrRules.solrFieldNames(getRowType()));
- String query = translator.translateMatch(condition);
- implementor.addQuery(query);
- implementor.setNegativeQuery(translator.negativeQuery);
+ if(getInput() instanceof SolrAggregate) {
+ HavingTranslator translator = new HavingTranslator(SolrRules.solrFieldNames(getRowType()), implementor.reverseAggMappings);
+ String havingPredicate = translator.translateMatch(condition);
+ implementor.setHavingPredicate(havingPredicate);
+ } else {
+ Translator translator = new Translator(SolrRules.solrFieldNames(getRowType()));
+ String query = translator.translateMatch(condition);
+ implementor.addQuery(query);
+ implementor.setNegativeQuery(translator.negativeQuery);
+ }
}
- /** Translates {@link RexNode} expressions into Solr query strings. */
private static class Translator {
private final List<String> fieldNames;
@@ -71,11 +77,11 @@ class SolrFilter extends Filter implements SolrRel {
}
private String translateMatch(RexNode condition) {
- if(condition.getKind().belongsTo(SqlKind.COMPARISON)) {
+ if (condition.getKind().belongsTo(SqlKind.COMPARISON)) {
return translateComparison(condition);
- } else if(condition.isA(SqlKind.AND)) {
- return "("+translateAnd(condition)+")";
- } else if(condition.isA(SqlKind.OR)) {
+ } else if (condition.isA(SqlKind.AND)) {
+ return "(" + translateAnd(condition) + ")";
+ } else if (condition.isA(SqlKind.OR)) {
return "(" + translateOr(condition) + ")";
} else {
return null;
@@ -90,8 +96,6 @@ class SolrFilter extends Filter implements SolrRel {
return String.join(" OR ", ors);
}
-
-
private String translateAnd(RexNode node0) {
List<String> andStrings = new ArrayList();
List<String> notStrings = new ArrayList();
@@ -101,18 +105,18 @@ class SolrFilter extends Filter implements SolrRel {
RelOptUtil.decomposeConjunction(node0, ands, nots);
- for(RexNode node: ands) {
+ for (RexNode node : ands) {
andStrings.add(translateMatch(node));
}
String andString = String.join(" AND ", andStrings);
- if(nots.size() > 0) {
- for(RexNode node: nots) {
+ if (nots.size() > 0) {
+ for (RexNode node : nots) {
notStrings.add(translateMatch(node));
}
String notString = String.join(" NOT ", notStrings);
- return "("+ andString +") NOT ("+notString+")";
+ return "(" + andString + ") NOT (" + notString + ")";
} else {
return andString;
}
@@ -126,45 +130,217 @@ class SolrFilter extends Filter implements SolrRel {
switch (node.getKind()) {
case NOT:
- return "-"+translateComparison(((RexCall) node).getOperands().get(0));
+ return "-" + translateComparison(((RexCall) node).getOperands().get(0));
case EQUALS:
String terms = binaryTranslated.getValue().getValue2().toString().trim();
- if(!terms.startsWith("(") && !terms.startsWith("[") && !terms.startsWith("{")){
- terms = "\""+terms+"\"";
+ if (!terms.startsWith("(") && !terms.startsWith("[") && !terms.startsWith("{")) {
+ terms = "\"" + terms + "\"";
}
String clause = binaryTranslated.getKey() + ":" + terms;
this.negativeQuery = false;
return clause;
case NOT_EQUALS:
- return "-(" + binaryTranslated.getKey() + ":" + binaryTranslated.getValue().getValue2()+")";
+ return "-(" + binaryTranslated.getKey() + ":" + binaryTranslated.getValue().getValue2() + ")";
case LESS_THAN:
this.negativeQuery = false;
- return "("+binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue().getValue2() + " })";
+ return "(" + binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue().getValue2() + " })";
case LESS_THAN_OR_EQUAL:
this.negativeQuery = false;
- return "("+binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue().getValue2() + " ])";
+ return "(" + binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue().getValue2() + " ])";
case GREATER_THAN:
this.negativeQuery = false;
- return "("+binaryTranslated.getKey() + ": { " + binaryTranslated.getValue().getValue2() + " TO * ])";
+ return "(" + binaryTranslated.getKey() + ": { " + binaryTranslated.getValue().getValue2() + " TO * ])";
case GREATER_THAN_OR_EQUAL:
this.negativeQuery = false;
- return "("+binaryTranslated.getKey() + ": [ " + binaryTranslated.getValue().getValue2() + " TO * ])";
+ return "(" + binaryTranslated.getKey() + ": [ " + binaryTranslated.getValue().getValue2() + " TO * ])";
+ default:
+ throw new AssertionError("cannot translate " + node);
+ }
+ }
+
+ /**
+ * Translates a call to a binary operator, reversing arguments if necessary.
+ */
+ private Pair<String, RexLiteral> translateBinary(RexCall call) {
+ List<RexNode> operands = call.getOperands();
+ if (operands.size() != 2) {
+ throw new AssertionError("Invalid number of arguments - " + operands.size());
+ }
+ final RexNode left = operands.get(0);
+ final RexNode right = operands.get(1);
+ final Pair<String, RexLiteral> a = translateBinary2(left, right);
+ if (a != null) {
+ return a;
+ }
+ final Pair<String, RexLiteral> b = translateBinary2(right, left);
+ if (b != null) {
+ return b;
+ }
+ throw new AssertionError("cannot translate call " + call);
+ }
+
+ /**
+ * Translates a call to a binary operator. Returns whether successful.
+ */
+ private Pair<String, RexLiteral> translateBinary2(RexNode left, RexNode right) {
+ switch (right.getKind()) {
+ case LITERAL:
+ break;
+ default:
+ return null;
+ }
+ final RexLiteral rightLiteral = (RexLiteral) right;
+ switch (left.getKind()) {
+ case INPUT_REF:
+ final RexInputRef left1 = (RexInputRef) left;
+ String name = fieldNames.get(left1.getIndex());
+ return new Pair<>(name, rightLiteral);
+ case CAST:
+ return translateBinary2(((RexCall) left).operands.get(0), right);
+// case OTHER_FUNCTION:
+// String itemName = SolrRules.isItem((RexCall) left);
+// if (itemName != null) {
+// return translateOp2(op, itemName, rightLiteral);
+// }
+ default:
+ return null;
+ }
+ }
+ }
+
+ private static class HavingTranslator {
+
+ private final List<String> fieldNames;
+ private Map<String,String> reverseAggMappings;
+
+ HavingTranslator(List<String> fieldNames, Map<String, String> reverseAggMappings) {
+ this.fieldNames = fieldNames;
+ this.reverseAggMappings = reverseAggMappings;
+ }
+
+ private String translateMatch(RexNode condition) {
+ if (condition.getKind().belongsTo(SqlKind.COMPARISON)) {
+ return translateComparison(condition);
+ } else if (condition.isA(SqlKind.AND)) {
+ return translateAnd(condition);
+ } else if (condition.isA(SqlKind.OR)) {
+ return translateOr(condition);
+ } else {
+ return null;
+ }
+ }
+
+ private String translateOr(RexNode condition) {
+ List<String> ors = new ArrayList<>();
+ for (RexNode node : RelOptUtil.disjunctions(condition)) {
+ ors.add(translateMatch(node));
+ }
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("or(");
+ int i = 0;
+ for (i = 0; i < ors.size(); i++) {
+ if (i > 0) {
+ builder.append(",");
+ }
+
+ builder.append(ors.get(i));
+ }
+ builder.append(")");
+ return builder.toString();
+ }
+
+ private String translateAnd(RexNode node0) {
+ List<String> andStrings = new ArrayList();
+ List<String> notStrings = new ArrayList();
+
+ List<RexNode> ands = new ArrayList();
+ List<RexNode> nots = new ArrayList();
+
+ RelOptUtil.decomposeConjunction(node0, ands, nots);
+
+ for (RexNode node : ands) {
+ andStrings.add(translateMatch(node));
+ }
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("and(");
+ for (int i = 0; i < andStrings.size(); i++) {
+ if (i > 0) {
+ builder.append(",");
+ }
+
+ builder.append(andStrings.get(i));
+ }
+ builder.append(")");
+
+
+ if (nots.size() > 0) {
+ for (RexNode node : nots) {
+ notStrings.add(translateMatch(node));
+ }
+
+ StringBuilder notBuilder = new StringBuilder();
+ for(int i=0; i< notStrings.size(); i++) {
+ if(i > 0) {
+ notBuilder.append(",");
+ }
+ notBuilder.append("not(");
+ notBuilder.append(notStrings.get(i));
+ notBuilder.append(")");
+ }
+
+ return "and(" + builder.toString() + ","+ notBuilder.toString()+")";
+ } else {
+ return builder.toString();
+ }
+ }
+
+ private String translateComparison(RexNode node) {
+ Pair<String, RexLiteral> binaryTranslated = null;
+ if (((RexCall) node).getOperands().size() == 2) {
+ binaryTranslated = translateBinary((RexCall) node);
+ }
+
+ switch (node.getKind()) {
+
+ case EQUALS:
+ String terms = binaryTranslated.getValue().getValue2().toString().trim();
+ String clause = "eq(" + binaryTranslated.getKey() + "," + terms + ")";
+ return clause;
+ case NOT_EQUALS:
+ return "not(eq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue().getValue2() + "))";
+ case LESS_THAN:
+ return "lt(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue().getValue2() + ")";
+ case LESS_THAN_OR_EQUAL:
+ return "lteq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue().getValue2() + ")";
+ case GREATER_THAN:
+ return "gt(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue().getValue2() + ")";
+ case GREATER_THAN_OR_EQUAL:
+ return "gteq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue().getValue2() + ")";
default:
throw new AssertionError("cannot translate " + node);
}
}
- /** Translates a call to a binary operator, reversing arguments if necessary. */
+ /**
+ * Translates a call to a binary operator, reversing arguments if necessary.
+ */
private Pair<String, RexLiteral> translateBinary(RexCall call) {
List<RexNode> operands = call.getOperands();
- if(operands.size() != 2) {
+ if (operands.size() != 2) {
throw new AssertionError("Invalid number of arguments - " + operands.size());
}
final RexNode left = operands.get(0);
final RexNode right = operands.get(1);
final Pair<String, RexLiteral> a = translateBinary2(left, right);
+
if (a != null) {
+ if(reverseAggMappings.containsKey(a.getKey())) {
+ return new Pair<String, RexLiteral>(reverseAggMappings.get(a.getKey()),a.getValue());
+ }
return a;
}
final Pair<String, RexLiteral> b = translateBinary2(right, left);
@@ -174,7 +350,9 @@ class SolrFilter extends Filter implements SolrRel {
throw new AssertionError("cannot translate call " + call);
}
- /** Translates a call to a binary operator. Returns whether successful. */
+ /**
+ * Translates a call to a binary operator. Returns whether successful.
+ */
private Pair<String, RexLiteral> translateBinary2(RexNode left, RexNode right) {
switch (right.getKind()) {
case LITERAL:
@@ -182,6 +360,7 @@ class SolrFilter extends Filter implements SolrRel {
default:
return null;
}
+
final RexLiteral rightLiteral = (RexLiteral) right;
switch (left.getKind()) {
case INPUT_REF:
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrMethod.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrMethod.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrMethod.java
index 4ec3fdb..b0bf801 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrMethod.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrMethod.java
@@ -33,6 +33,7 @@ enum SolrMethod {
List.class,
List.class,
String.class,
+ String.class,
String.class);
public final Method method;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrRel.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrRel.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrRel.java
index b7843d7..557cfe0 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrRel.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrRel.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.Convention;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.util.Pair;
+import org.apache.solr.client.solrj.io.ops.BooleanOperation;
import java.util.*;
@@ -35,7 +36,9 @@ interface SolrRel extends RelNode {
/** Callback for the implementation process that converts a tree of {@link SolrRel} nodes into a Solr query. */
class Implementor {
final Map<String, String> fieldMappings = new HashMap<>();
+ final Map<String, String> reverseAggMappings = new HashMap<>();
String query = null;
+ String havingPredicate;
boolean negativeQuery;
String limitValue = null;
final List<Pair<String, String>> orders = new ArrayList<>();
@@ -51,6 +54,12 @@ interface SolrRel extends RelNode {
}
}
+ void addReverseAggMapping(String key, String val) {
+ if(key != null && !reverseAggMappings.containsKey(key)) {
+ this.reverseAggMappings.put(key, val);
+ }
+ }
+
void addQuery(String query) {
this.query = query;
}
@@ -79,6 +88,11 @@ interface SolrRel extends RelNode {
}
}
+ void setHavingPredicate(String havingPredicate) {
+ this.havingPredicate = havingPredicate;
+ }
+
+
void setLimit(String limit) {
limitValue = limit;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrRules.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrRules.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrRules.java
index 118ec1a..4cbadda 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrRules.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrRules.java
@@ -111,7 +111,7 @@ class SolrRules {
}
<R extends RelNode> SolrConverterRule(Class<R> clazz, Predicate<RelNode> predicate, String description) {
- super(clazz, predicate::test, Convention.NONE, SolrRel.CONVENTION, description);
+ super(clazz, Convention.NONE, SolrRel.CONVENTION, description);
}
}
@@ -120,8 +120,10 @@ class SolrRules {
*/
private static class SolrFilterRule extends SolrConverterRule {
private static boolean isNotFilterByExpr(List<RexNode> rexNodes, List<String> fieldNames) {
+
// We dont have a way to filter by result of aggregator now
boolean result = true;
+
for (RexNode rexNode : rexNodes) {
if (rexNode instanceof RexCall) {
result = result && isNotFilterByExpr(((RexCall) rexNode).getOperands(), fieldNames);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
index fff6468..5f64231 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
@@ -32,7 +32,17 @@ import org.apache.solr.client.solrj.io.comp.ComparatorOrder;
import org.apache.solr.client.solrj.io.comp.FieldComparator;
import org.apache.solr.client.solrj.io.comp.MultipleFieldComparator;
import org.apache.solr.client.solrj.io.comp.StreamComparator;
+import org.apache.solr.client.solrj.io.ops.AndOperation;
+import org.apache.solr.client.solrj.io.ops.BooleanOperation;
+import org.apache.solr.client.solrj.io.ops.EqualsOperation;
+import org.apache.solr.client.solrj.io.ops.GreaterThanEqualToOperation;
+import org.apache.solr.client.solrj.io.ops.GreaterThanOperation;
+import org.apache.solr.client.solrj.io.ops.LessThanEqualToOperation;
+import org.apache.solr.client.solrj.io.ops.LessThanOperation;
+import org.apache.solr.client.solrj.io.ops.NotOperation;
+import org.apache.solr.client.solrj.io.ops.OrOperation;
import org.apache.solr.client.solrj.io.stream.*;
+import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParser;
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
import org.apache.solr.client.solrj.io.stream.metrics.*;
import org.apache.solr.common.params.CommonParams;
@@ -72,7 +82,7 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
private Enumerable<Object> query(final Properties properties) {
return query(properties, Collections.emptyList(), null, Collections.emptyList(), Collections.emptyList(),
- Collections.emptyList(), null, null);
+ Collections.emptyList(), null, null, null);
}
/** Executes a Solr query on the underlying table.
@@ -89,7 +99,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
final List<String> buckets,
final List<Pair<String, String>> metricPairs,
final String limit,
- final String negativeQuery) {
+ final String negativeQuery,
+ final String havingPredicate) {
// SolrParams should be a ModifiableParams instead of a map
boolean mapReduce = "map_reduce".equals(properties.getProperty("aggregationMode"));
boolean negative = Boolean.parseBoolean(negativeQuery);
@@ -106,8 +117,6 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
}
}
- System.out.println("####### Limit:"+limit);
-
TupleStream tupleStream;
String zk = properties.getProperty("zk");
try {
@@ -126,7 +135,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
orders,
buckets,
metricPairs,
- limit);
+ limit,
+ havingPredicate);
} else {
tupleStream = handleGroupByFacet(zk,
collection,
@@ -135,7 +145,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
orders,
buckets,
metricPairs,
- limit);
+ limit,
+ havingPredicate);
}
}
}
@@ -403,7 +414,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
final List<Pair<String, String>> orders,
final List<String> _buckets,
final List<Pair<String, String>> metricPairs,
- final String limit) throws IOException {
+ final String limit,
+ final String havingPredicate) throws IOException {
int numWorkers = Integer.parseInt(properties.getProperty("numWorkers", "1"));
@@ -438,21 +450,36 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
CloudSolrStream cstream = new CloudSolrStream(zk, collection, params);
tupleStream = new RollupStream(cstream, buckets, metrics);
+ StreamFactory factory = new StreamFactory()
+ .withFunctionName("search", CloudSolrStream.class)
+ .withFunctionName("parallel", ParallelStream.class)
+ .withFunctionName("rollup", RollupStream.class)
+ .withFunctionName("sum", SumMetric.class)
+ .withFunctionName("min", MinMetric.class)
+ .withFunctionName("max", MaxMetric.class)
+ .withFunctionName("avg", MeanMetric.class)
+ .withFunctionName("count", CountMetric.class)
+ .withFunctionName("and", AndOperation.class)
+ .withFunctionName("or", OrOperation.class)
+ .withFunctionName("not", NotOperation.class)
+ .withFunctionName("eq", EqualsOperation.class)
+ .withFunctionName("gt", GreaterThanOperation.class)
+ .withFunctionName("lt", LessThanOperation.class)
+ .withFunctionName("lteq", LessThanEqualToOperation.class)
+ .withFunctionName("having", HavingStream.class)
+ .withFunctionName("gteq", GreaterThanEqualToOperation.class);
+
+ if(havingPredicate != null) {
+ BooleanOperation booleanOperation = (BooleanOperation)factory.constructOperation(StreamExpressionParser.parse(havingPredicate));
+ tupleStream = new HavingStream(tupleStream, booleanOperation);
+ }
+
if(numWorkers > 1) {
// Do the rollups in parallel
// Maintain the sort of the Tuples coming from the workers.
StreamComparator comp = bucketSortComp(buckets, sortDirection);
ParallelStream parallelStream = new ParallelStream(zk, collection, tupleStream, numWorkers, comp);
- StreamFactory factory = new StreamFactory()
- .withFunctionName("search", CloudSolrStream.class)
- .withFunctionName("parallel", ParallelStream.class)
- .withFunctionName("rollup", RollupStream.class)
- .withFunctionName("sum", SumMetric.class)
- .withFunctionName("min", MinMetric.class)
- .withFunctionName("max", MaxMetric.class)
- .withFunctionName("avg", MeanMetric.class)
- .withFunctionName("count", CountMetric.class);
parallelStream.setStreamFactory(factory);
tupleStream = parallelStream;
@@ -508,7 +535,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
final List<Pair<String, String>> orders,
final List<String> bucketFields,
final List<Pair<String, String>> metricPairs,
- final String lim) throws IOException {
+ final String lim,
+ final String havingPredicate) throws IOException {
ModifiableSolrParams solrParams = new ModifiableSolrParams();
solrParams.add(CommonParams.Q, query);
@@ -542,6 +570,30 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
limit);
+
+ StreamFactory factory = new StreamFactory()
+ .withFunctionName("search", CloudSolrStream.class)
+ .withFunctionName("parallel", ParallelStream.class)
+ .withFunctionName("rollup", RollupStream.class)
+ .withFunctionName("sum", SumMetric.class)
+ .withFunctionName("min", MinMetric.class)
+ .withFunctionName("max", MaxMetric.class)
+ .withFunctionName("avg", MeanMetric.class)
+ .withFunctionName("count", CountMetric.class)
+ .withFunctionName("and", AndOperation.class)
+ .withFunctionName("or", OrOperation.class)
+ .withFunctionName("not", NotOperation.class)
+ .withFunctionName("eq", EqualsOperation.class)
+ .withFunctionName("gt", GreaterThanOperation.class)
+ .withFunctionName("lt", LessThanOperation.class)
+ .withFunctionName("lteq", LessThanEqualToOperation.class)
+ .withFunctionName("gteq", GreaterThanEqualToOperation.class);
+
+ if(havingPredicate != null) {
+ BooleanOperation booleanOperation = (BooleanOperation)factory.constructOperation(StreamExpressionParser.parse(havingPredicate));
+ tupleStream = new HavingStream(tupleStream, booleanOperation);
+ }
+
if(lim != null)
{
tupleStream = new LimitStream(tupleStream, limit);
@@ -623,8 +675,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
*/
@SuppressWarnings("UnusedDeclaration")
public Enumerable<Object> query(List<Map.Entry<String, Class>> fields, String query, List<Pair<String, String>> order,
- List<String> buckets, List<Pair<String, String>> metricPairs, String limit, String negativeQuery) {
- return getTable().query(getProperties(), fields, query, order, buckets, metricPairs, limit, negativeQuery);
+ List<String> buckets, List<Pair<String, String>> metricPairs, String limit, String negativeQuery, String havingPredicate) {
+ return getTable().query(getProperties(), fields, query, order, buckets, metricPairs, limit, negativeQuery, havingPredicate);
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/core/src/java/org/apache/solr/handler/sql/SolrToEnumerableConverter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrToEnumerableConverter.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrToEnumerableConverter.java
index 9b18891..10d4d4c 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrToEnumerableConverter.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrToEnumerableConverter.java
@@ -84,8 +84,9 @@ class SolrToEnumerableConverter extends ConverterImpl implements EnumerableRel {
final Expression metricPairs = list.append("metricPairs", constantArrayList(solrImplementor.metricPairs, Pair.class));
final Expression limit = list.append("limit", Expressions.constant(solrImplementor.limitValue));
final Expression negativeQuery = list.append("negativeQuery", Expressions.constant(Boolean.toString(solrImplementor.negativeQuery), String.class));
+ final Expression havingPredicate = list.append("havingTest", Expressions.constant(solrImplementor.havingPredicate, String.class));
Expression enumerable = list.append("enumerable", Expressions.call(table, SolrMethod.SOLR_QUERYABLE_QUERY.method,
- fields, query, orders, buckets, metricPairs, limit, negativeQuery));
+ fields, query, orders, buckets, metricPairs, limit, negativeQuery, havingPredicate));
Hook.QUERY_PLAN.run(query);
list.add(Expressions.return_(null, enumerable));
return implementor.result(physType, list.toBlock());
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/AndOperation.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/AndOperation.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/AndOperation.java
index f095f63..bebc777 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/AndOperation.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/AndOperation.java
@@ -18,12 +18,12 @@ package org.apache.solr.client.solrj.io.ops;
import java.io.IOException;
import java.util.List;
+import java.util.ArrayList;
import java.util.UUID;
import org.apache.solr.client.solrj.io.Tuple;
import org.apache.solr.client.solrj.io.stream.expr.Explanation;
import org.apache.solr.client.solrj.io.stream.expr.Explanation.ExpressionType;
-import org.apache.solr.client.solrj.io.stream.expr.Expressible;
import org.apache.solr.client.solrj.io.stream.expr.StreamExpression;
import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParameter;
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
@@ -33,60 +33,47 @@ public class AndOperation implements BooleanOperation {
private static final long serialVersionUID = 1;
private UUID operationNodeId = UUID.randomUUID();
- protected BooleanOperation leftOperand;
- protected BooleanOperation rightOperand;
+ private List<BooleanOperation> booleanOperations = new ArrayList();
public void operate(Tuple tuple) {
- leftOperand.operate(tuple);
- rightOperand.operate(tuple);
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ booleanOperation.operate(tuple);
+ }
}
- public AndOperation(BooleanOperation leftOperand, BooleanOperation rightOperand) {
- this.leftOperand = leftOperand;
- this.rightOperand = rightOperand;
+ public AndOperation(List<BooleanOperation> booleanOperations) {
+ this.booleanOperations = booleanOperations;
}
public AndOperation(StreamExpression expression, StreamFactory factory) throws IOException {
- List<StreamExpression> operationExpressions = factory.getExpressionOperandsRepresentingTypes(expression, BooleanOperation.class);
- if(operationExpressions != null && operationExpressions.size() == 2) {
- StreamExpression left = operationExpressions.get(0);
- StreamOperation leftOp = factory.constructOperation(left);
- if(leftOp instanceof BooleanOperation) {
- leftOperand = (BooleanOperation) leftOp;
- } else {
- throw new IOException("The And/Or Operation requires a BooleanOperation.");
- }
-
- StreamExpression right = operationExpressions.get(1);
- StreamOperation rightOp = factory.constructOperation(right);
- if(rightOp instanceof BooleanOperation) {
- rightOperand = (BooleanOperation) rightOp;
- } else {
- throw new IOException("The And/Or Operation requires a BooleanOperation.");
- }
+ List<StreamExpression> operationExpressions = factory.getExpressionOperandsRepresentingTypes(expression, BooleanOperation.class);
+ for(StreamExpression se : operationExpressions) {
+ StreamOperation op = factory.constructOperation(se);
+ if(op instanceof BooleanOperation) {
+ booleanOperations.add((BooleanOperation)op);
} else {
- throw new IOException("The And/Or Operation requires a BooleanOperations.");
+ throw new IOException("AndOperation requires BooleanOperation parameters");
}
+ }
}
public boolean evaluate() {
- return leftOperand.evaluate() && rightOperand.evaluate();
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ if(!booleanOperation.evaluate()) {
+ return false;
+ }
+ }
+ return true;
}
@Override
public StreamExpressionParameter toExpression(StreamFactory factory) throws IOException {
StreamExpression expression = new StreamExpression(factory.getFunctionName(this.getClass()));
- if(leftOperand instanceof Expressible) {
- expression.addParameter(leftOperand.toExpression(factory));
- } else {
- throw new IOException("This left operand of the AndOperation contains a non-expressible operation - it cannot be converted to an expression");
- }
- if(rightOperand instanceof Expressible) {
- expression.addParameter(rightOperand.toExpression(factory));
- } else {
- throw new IOException("This the right operand of the AndOperation contains a non-expressible operation - it cannot be converted to an expression");
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ expression.addParameter(booleanOperation.toExpression(factory));
}
+
return expression;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/de512d74/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/OrOperation.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/OrOperation.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/OrOperation.java
index faac5cd..2325a58 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/OrOperation.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/ops/OrOperation.java
@@ -17,46 +17,63 @@
package org.apache.solr.client.solrj.io.ops;
import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
import java.util.UUID;
+import org.apache.solr.client.solrj.io.Tuple;
import org.apache.solr.client.solrj.io.stream.expr.Explanation;
import org.apache.solr.client.solrj.io.stream.expr.Explanation.ExpressionType;
-import org.apache.solr.client.solrj.io.stream.expr.Expressible;
import org.apache.solr.client.solrj.io.stream.expr.StreamExpression;
import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParameter;
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
-public class OrOperation extends AndOperation {
+public class OrOperation implements BooleanOperation {
private static final long serialVersionUID = 1;
private UUID operationNodeId = UUID.randomUUID();
- public OrOperation(BooleanOperation leftOperand, BooleanOperation rightOperand) {
- super(leftOperand, rightOperand);
+ private List<BooleanOperation> booleanOperations = new ArrayList();
+
+ public void operate(Tuple tuple) {
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ booleanOperation.operate(tuple);
+ }
+ }
+
+ public OrOperation(List<BooleanOperation> booleanOperations) {
+ this.booleanOperations = booleanOperations;
}
public OrOperation(StreamExpression expression, StreamFactory factory) throws IOException {
- super(expression, factory);
+ List<StreamExpression> operationExpressions = factory.getExpressionOperandsRepresentingTypes(expression, BooleanOperation.class);
+ for(StreamExpression se : operationExpressions) {
+ StreamOperation op = factory.constructOperation(se);
+ if(op instanceof BooleanOperation) {
+ booleanOperations.add((BooleanOperation)op);
+ } else {
+ throw new IOException("AndOperation requires BooleanOperation parameters");
+ }
+ }
}
public boolean evaluate() {
- return leftOperand.evaluate() || rightOperand.evaluate();
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ if(booleanOperation.evaluate()) {
+ return true;
+ }
+ }
+ return false;
}
@Override
public StreamExpressionParameter toExpression(StreamFactory factory) throws IOException {
StreamExpression expression = new StreamExpression(factory.getFunctionName(this.getClass()));
- if(leftOperand instanceof Expressible) {
- expression.addParameter(leftOperand.toExpression(factory));
- } else {
- throw new IOException("This left operand of the OrOperation contains a non-expressible operation - it cannot be converted to an expression");
- }
- if(rightOperand instanceof Expressible) {
- expression.addParameter(rightOperand.toExpression(factory));
- } else {
- throw new IOException("This the right operand of the OrOperation contains a non-expressible operation - it cannot be converted to an expression");
+ for(BooleanOperation booleanOperation : booleanOperations) {
+ expression.addParameter(booleanOperation.toExpression(factory));
}
+
return expression;
}
[3/3] lucene-solr:jira/solr-8593: SOLR-8593: Ensure the SolrSort is
always pushed down
Posted by jb...@apache.org.
SOLR-8593: Ensure the SolrSort is always pushed down
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/4ea97b08
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/4ea97b08
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/4ea97b08
Branch: refs/heads/jira/solr-8593
Commit: 4ea97b08de1b853b1fc2a0f306db9a202e22db67
Parents: 63eeced
Author: Joel Bernstein <jb...@apache.org>
Authored: Sat Feb 4 13:59:56 2017 -0500
Committer: Joel Bernstein <jb...@apache.org>
Committed: Wed Feb 8 13:01:31 2017 -0500
----------------------------------------------------------------------
.../org/apache/solr/handler/sql/SolrFilter.java | 2 +-
.../org/apache/solr/handler/sql/SolrSort.java | 3 ++-
.../org/apache/solr/handler/sql/SolrTable.java | 18 ++++++++++++------
3 files changed, 15 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4ea97b08/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
index 5f30926..01d3346 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrFilter.java
@@ -129,7 +129,7 @@ class SolrFilter extends Filter implements SolrRel {
return "-"+translateComparison(((RexCall) node).getOperands().get(0));
case EQUALS:
String terms = binaryTranslated.getValue().getValue2().toString().trim();
- if(!terms.startsWith("(")){
+ if(!terms.startsWith("(") && !terms.startsWith("[") && !terms.startsWith("{")){
terms = "\""+terms+"\"";
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4ea97b08/solr/core/src/java/org/apache/solr/handler/sql/SolrSort.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrSort.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrSort.java
index 751e841..1c5274a 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrSort.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrSort.java
@@ -46,7 +46,7 @@ class SolrSort extends Sort implements SolrRel {
@Override
public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
- return super.computeSelfCost(planner, mq).multiplyBy(0.05);
+ return planner.getCostFactory().makeZeroCost();
}
@Override
@@ -71,6 +71,7 @@ class SolrSort extends Sort implements SolrRel {
}
}
+
if(fetch != null) {
implementor.setLimit(((RexLiteral) fetch).getValue().toString());
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4ea97b08/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java b/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
index 14e69e6..fff6468 100644
--- a/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
+++ b/solr/core/src/java/org/apache/solr/handler/sql/SolrTable.java
@@ -106,6 +106,8 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
}
}
+ System.out.println("####### Limit:"+limit);
+
TupleStream tupleStream;
String zk = properties.getProperty("zk");
try {
@@ -456,13 +458,12 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
tupleStream = parallelStream;
}
- //TODO: This should be done on the workers, but it won't serialize because it relies on Presto classes.
- // Once we make this a Expressionable the problem will be solved.
-
+ //TODO: Currently we are not pushing down the having clause.
+ // We need to push down the having clause to ensure that LIMIT does not cut off records prior to the having filter.
if(orders != null && orders.size() > 0) {
- int lim = limit == null ? 100 : Integer.parseInt(limit);
if(!sortsEqual(buckets, sortDirection, orders)) {
+ int lim = (limit == null) ? 100 : Integer.parseInt(limit);
StreamComparator comp = getComp(orders);
//Rank the Tuples
//If parallel stream is used ALL the Rolled up tuples from the workers will be ranked
@@ -471,10 +472,15 @@ class SolrTable extends AbstractQueryableTable implements TranslatableTable {
} else {
// Sort is the same as the same as the underlying stream
// Only need to limit the result, not Rank the result
- if(lim > -1) {
- tupleStream = new LimitStream(tupleStream, lim);
+ if(limit != null) {
+ tupleStream = new LimitStream(tupleStream, Integer.parseInt(limit));
}
}
+ } else {
+ //No order by, check for limit
+ if(limit != null) {
+ tupleStream = new LimitStream(tupleStream, Integer.parseInt(limit));
+ }
}
return tupleStream;
[2/3] lucene-solr:jira/solr-8593: SOLR-10094: /export handler (master
only) loses the sort deep into the result set
Posted by jb...@apache.org.
SOLR-10094: /export handler (master only) loses the sort deep into the result set
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/a9cf1503
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/a9cf1503
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/a9cf1503
Branch: refs/heads/jira/solr-8593
Commit: a9cf1503b59c24e8093459609dd56bb5339cda54
Parents: 4ea97b0
Author: Joel Bernstein <jb...@apache.org>
Authored: Sat Feb 4 23:48:03 2017 -0500
Committer: Joel Bernstein <jb...@apache.org>
Committed: Wed Feb 8 13:01:31 2017 -0500
----------------------------------------------------------------------
.../java/org/apache/solr/handler/ExportWriter.java | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a9cf1503/solr/core/src/java/org/apache/solr/handler/ExportWriter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/ExportWriter.java b/solr/core/src/java/org/apache/solr/handler/ExportWriter.java
index e432f94..8bdd959 100644
--- a/solr/core/src/java/org/apache/solr/handler/ExportWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/ExportWriter.java
@@ -1254,7 +1254,6 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
class StringValue implements SortValue {
protected SortedDocValues vals;
- protected SortedDocValues segmentVals[];
protected MultiDocValues.OrdinalMap ordinalMap;
protected LongValues globalOrds;
@@ -1264,11 +1263,11 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
protected int segment;
protected int currentOrd;
protected IntComp comp;
+ protected int lastDocID;
public StringValue(SortedDocValues vals, String field, IntComp comp) {
this.vals = vals;
if(vals instanceof MultiDocValues.MultiSortedDocValues) {
- this.segmentVals = ((MultiDocValues.MultiSortedDocValues) vals).values;
this.ordinalMap = ((MultiDocValues.MultiSortedDocValues) vals).mapping;
}
this.field = field;
@@ -1281,6 +1280,13 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
}
public void setCurrentValue(int docId) throws IOException {
+
+ if (docId < lastDocID) {
+ throw new AssertionError("docs were sent out-of-order: lastDocID=" + lastDocID + " vs doc=" + docId);
+ }
+
+ lastDocID = docId;
+
if (docId > currentVals.docID()) {
currentVals.advance(docId);
}
@@ -1301,14 +1307,13 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
this.currentOrd = v.currentOrd;
}
- public void setNextReader(LeafReaderContext context) {
+ public void setNextReader(LeafReaderContext context) throws IOException {
segment = context.ord;
if(ordinalMap != null) {
globalOrds = ordinalMap.getGlobalOrds(segment);
- currentVals = segmentVals[segment];
- } else {
- currentVals = vals;
}
+ currentVals = DocValues.getSorted(context.reader(), field);
+ lastDocID = 0;
}
public void reset() {