You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by tl...@apache.org on 2021/04/07 13:31:34 UTC
[ignite] branch sql-calcite updated: IGNITE-13546 Calcite
integration. Introduce hash index spool
This is an automated email from the ASF dual-hosted git repository.
tledkov pushed a commit to branch sql-calcite
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/sql-calcite by this push:
new 6df422f IGNITE-13546 Calcite integration. Introduce hash index spool
6df422f is described below
commit 6df422fe8c1fdbec810336dab34707d33731a252
Author: tledkov <tl...@gridgain.com>
AuthorDate: Wed Apr 7 16:31:16 2021 +0300
IGNITE-13546 Calcite integration. Introduce hash index spool
---
.../query/calcite/exec/LogicalRelImplementor.java | 25 +++-
.../query/calcite/exec/RuntimeHashIndex.java | 112 ++++++++++++++
.../query/calcite/exec/RuntimeIndex.java | 28 ++++
.../query/calcite/exec/RuntimeTreeIndex.java | 13 +-
.../query/calcite/exec/rel/IndexSpoolNode.java | 74 ++++++---
.../query/calcite/metadata/IgniteMdRowCount.java | 4 +-
.../calcite/metadata/IgniteMdSelectivity.java | 18 ++-
.../query/calcite/metadata/cost/IgniteCost.java | 3 +
.../processors/query/calcite/prepare/Cloner.java | 9 +-
.../query/calcite/prepare/IgniteRelShuttle.java | 10 +-
.../query/calcite/prepare/PlannerPhase.java | 6 +-
.../rel/IgniteCorrelatedNestedLoopJoin.java | 9 +-
...teIndexSpool.java => IgniteHashIndexSpool.java} | 72 ++++-----
.../query/calcite/rel/IgniteRelVisitor.java | 7 +-
.../processors/query/calcite/rel/IgniteSort.java | 5 +-
...IndexSpool.java => IgniteSortedIndexSpool.java} | 42 +++---
.../query/calcite/rel/IgniteTableSpool.java | 8 +-
.../rel/logical/IgniteLogicalIndexScan.java | 16 +-
...a => FilterSpoolMergeToHashIndexSpoolRule.java} | 41 +++--
...=> FilterSpoolMergeToSortedIndexSpoolRule.java} | 21 +--
.../query/calcite/util/IndexConditions.java | 13 +-
.../processors/query/calcite/util/RexUtils.java | 71 ++++++++-
.../exec/rel/HashIndexSpoolExecutionTest.java | 166 +++++++++++++++++++++
...nTest.java => TreeIndexSpoolExecutionTest.java} | 4 +-
.../query/calcite/planner/AbstractPlannerTest.java | 2 +
.../CorrelatedNestedLoopJoinPlannerTest.java | 4 +-
...nerTest.java => HashIndexSpoolPlannerTest.java} | 96 ++++--------
...rTest.java => SortedIndexSpoolPlannerTest.java} | 92 ++----------
.../calcite/planner/TableSpoolPlannerTest.java | 5 +-
.../ignite/testsuites/ExecutionTestSuite.java | 6 +-
.../apache/ignite/testsuites/PlannerTestSuite.java | 6 +-
31 files changed, 673 insertions(+), 315 deletions(-)
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java
index 0f891bb..f9cfcf5 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java
@@ -59,8 +59,8 @@ import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGr
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCorrelatedNestedLoopJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteExchange;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteLimit;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteMergeJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteNestedLoopJoin;
@@ -70,6 +70,7 @@ import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRelVisitor;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSender;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableModify;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
@@ -375,7 +376,7 @@ public class LogicalRelImplementor<Row> implements IgniteRelVisitor<Node<Row>> {
}
/** {@inheritDoc} */
- @Override public Node<Row> visit(IgniteIndexSpool rel) {
+ @Override public Node<Row> visit(IgniteSortedIndexSpool rel) {
RelCollation collation = rel.collation();
assert rel.indexCondition() != null : rel;
@@ -387,7 +388,7 @@ public class LogicalRelImplementor<Row> implements IgniteRelVisitor<Node<Row>> {
Supplier<Row> lower = lowerBound == null ? null : expressionFactory.rowSource(lowerBound);
Supplier<Row> upper = upperBound == null ? null : expressionFactory.rowSource(upperBound);
- IndexSpoolNode<Row> node = new IndexSpoolNode<>(
+ IndexSpoolNode<Row> node = IndexSpoolNode.createTreeSpool(
ctx,
rel.getRowType(),
collation,
@@ -405,6 +406,24 @@ public class LogicalRelImplementor<Row> implements IgniteRelVisitor<Node<Row>> {
}
/** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteHashIndexSpool rel) {
+ Supplier<Row> searchRow = expressionFactory.rowSource(rel.searchRow());
+
+ IndexSpoolNode<Row> node = IndexSpoolNode.createHashSpool(
+ ctx,
+ rel.getRowType(),
+ ImmutableBitSet.of(rel.keys()),
+ searchRow
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
@Override public Node<Row> visit(IgniteTableModify rel) {
switch (rel.getOperation()) {
case INSERT:
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java
new file mode 100644
index 0000000..1666ba2
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.internal.processors.query.calcite.exec;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.GroupKey;
+import org.apache.ignite.internal.util.typedef.F;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Runtime hash index based on on-heap hash map.
+ */
+public class RuntimeHashIndex<Row> implements RuntimeIndex<Row> {
+ /** */
+ protected final ExecutionContext<Row> ectx;
+
+ /** */
+ private final ImmutableBitSet keys;
+
+ /** Rows. */
+ private HashMap<GroupKey, List<Row>> rows;
+
+ /**
+ *
+ */
+ public RuntimeHashIndex(
+ ExecutionContext<Row> ectx,
+ ImmutableBitSet keys
+ ) {
+ this.ectx = ectx;
+
+ assert !F.isEmpty(keys);
+
+ this.keys = keys;
+ rows = new HashMap<>();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void push(Row r) {
+ List<Row> eqRows = rows.computeIfAbsent(key(r), k -> new ArrayList<>());
+
+ eqRows.add(r);
+ }
+
+ /** */
+ @Override public void close() {
+ rows.clear();
+ }
+
+ /** */
+ public Iterable<Row> scan(Supplier<Row> searchRow) {
+ return new IndexScan(searchRow);
+ }
+
+ /** */
+ private GroupKey key(Row r) {
+ GroupKey.Builder b = GroupKey.builder(keys.cardinality());
+
+ for (Integer field : keys)
+ b.add(ectx.rowHandler().get(field, r));
+
+ return b.build();
+ }
+
+ /**
+ *
+ */
+ private class IndexScan implements Iterable<Row>, AutoCloseable {
+ /** Search row. */
+ private final Supplier<Row> searchRow;
+
+ /**
+ * @param searchRow Search row.
+ */
+ IndexScan(Supplier<Row> searchRow) {
+ this.searchRow = searchRow;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override public Iterator<Row> iterator() {
+ List<Row> eqRows = rows.get(key(searchRow.get()));
+
+ return eqRows == null ? Collections.emptyIterator() : eqRows.iterator();
+ }
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java
new file mode 100644
index 0000000..01d257c
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.internal.processors.query.calcite.exec;
+
+/**
+ * Runtime index interface.
+ * The temporary index is built and available only on query execution. Not stored at the schema.
+ */
+public interface RuntimeIndex<Row> extends AutoCloseable {
+ /**
+ * Add row to index.
+ */
+ void push(Row r);
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeTreeIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeTreeIndex.java
index cfd5669..541ba60 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeTreeIndex.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeTreeIndex.java
@@ -38,7 +38,7 @@ import org.apache.ignite.internal.util.typedef.F;
/**
* Runtime sorted index based on on-heap tree.
*/
-public class RuntimeTreeIndex<Row> implements GridIndex<Row>, AutoCloseable {
+public class RuntimeTreeIndex<Row> implements RuntimeIndex<Row>, GridIndex<Row> {
/** */
protected final ExecutionContext<Row> ectx;
@@ -68,10 +68,8 @@ public class RuntimeTreeIndex<Row> implements GridIndex<Row>, AutoCloseable {
rows = new TreeMap<>(comp);
}
- /**
- * Add row to index.
- */
- public void push(Row r) {
+ /** {@inheritDoc} */
+ @Override public void push(Row r) {
List<Row> newEqRows = new ArrayList<>();
List<Row> eqRows = rows.putIfAbsent(r, newEqRows);
@@ -82,7 +80,7 @@ public class RuntimeTreeIndex<Row> implements GridIndex<Row>, AutoCloseable {
newEqRows.add(r);
}
- /** */
+ /** {@inheritDoc} */
@Override public void close() {
rows.clear();
}
@@ -104,8 +102,7 @@ public class RuntimeTreeIndex<Row> implements GridIndex<Row>, AutoCloseable {
}
/**
- * Return an iterable to scan index range from lower to upper bounds inclusive,
- * filtered by {@code filter} predicate.
+ * Creates iterable on the index.
*/
public Iterable<Row> scan(
ExecutionContext<Row> ectx,
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolNode.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolNode.java
index 51607d3..6287688 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolNode.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolNode.java
@@ -23,7 +23,10 @@ import java.util.function.Supplier;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.util.ImmutableBitSet;
import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import org.apache.ignite.internal.processors.query.calcite.exec.RuntimeHashIndex;
+import org.apache.ignite.internal.processors.query.calcite.exec.RuntimeIndex;
import org.apache.ignite.internal.processors.query.calcite.exec.RuntimeTreeIndex;
import org.apache.ignite.internal.util.typedef.F;
@@ -35,7 +38,7 @@ public class IndexSpoolNode<Row> extends AbstractNode<Row> implements SingleNode
private final ScanNode<Row> scan;
/** Runtime index */
- private final RuntimeTreeIndex<Row> idx;
+ private final RuntimeIndex<Row> idx;
/** */
private int requested;
@@ -46,30 +49,16 @@ public class IndexSpoolNode<Row> extends AbstractNode<Row> implements SingleNode
/**
* @param ctx Execution context.
*/
- public IndexSpoolNode(
+ private IndexSpoolNode(
ExecutionContext<Row> ctx,
RelDataType rowType,
- RelCollation collation,
- Comparator<Row> comp,
- Predicate<Row> filter,
- Supplier<Row> lowerIdxBound,
- Supplier<Row> upperIdxBound
+ RuntimeIndex<Row> idx,
+ ScanNode<Row> scan
) {
super(ctx, rowType);
- idx = new RuntimeTreeIndex<>(ctx, collation, comp);
-
- scan = new ScanNode<>(
- ctx,
- rowType,
- idx.scan(
- ctx,
- rowType,
- filter,
- lowerIdxBound,
- upperIdxBound
- )
- );
+ this.idx = idx;
+ this.scan = scan;
}
/** */
@@ -167,4 +156,49 @@ public class IndexSpoolNode<Row> extends AbstractNode<Row> implements SingleNode
private boolean indexReady() {
return waiting == -1;
}
+
+ /** */
+ public static <Row> IndexSpoolNode<Row> createTreeSpool(
+ ExecutionContext<Row> ctx,
+ RelDataType rowType,
+ RelCollation collation,
+ Comparator<Row> comp,
+ Predicate<Row> filter,
+ Supplier<Row> lowerIdxBound,
+ Supplier<Row> upperIdxBound
+ ) {
+ RuntimeTreeIndex<Row> idx = new RuntimeTreeIndex<>(ctx, collation, comp);
+
+ ScanNode<Row> scan = new ScanNode<>(
+ ctx,
+ rowType,
+ idx.scan(
+ ctx,
+ rowType,
+ filter,
+ lowerIdxBound,
+ upperIdxBound
+ )
+ );
+
+ return new IndexSpoolNode<>(ctx, rowType, idx, scan);
+ }
+
+ /** */
+ public static <Row> IndexSpoolNode<Row> createHashSpool(
+ ExecutionContext<Row> ctx,
+ RelDataType rowType,
+ ImmutableBitSet keys,
+ Supplier<Row> searchRow
+ ) {
+ RuntimeHashIndex<Row> idx = new RuntimeHashIndex<>(ctx, keys);
+
+ ScanNode<Row> scan = new ScanNode<>(
+ ctx,
+ rowType,
+ idx.scan(searchRow)
+ );
+
+ return new IndexSpoolNode<>(ctx, rowType, idx, scan);
+ }
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdRowCount.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdRowCount.java
index 57cc7b2..8be9f1a 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdRowCount.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdRowCount.java
@@ -30,7 +30,7 @@ import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Util;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.util.typedef.F;
import org.jetbrains.annotations.Nullable;
@@ -111,7 +111,7 @@ public class IgniteMdRowCount extends RelMdRowCount {
* but IndexSpool has internal filter that could filter out some rows,
* hence we need to estimate it differently.
*/
- public double getRowCount(IgniteIndexSpool rel, RelMetadataQuery mq) {
+ public double getRowCount(IgniteSortedIndexSpool rel, RelMetadataQuery mq) {
return rel.estimateRowCount(mq);
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdSelectivity.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdSelectivity.java
index 624466c..86ad57a 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdSelectivity.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdSelectivity.java
@@ -31,7 +31,8 @@ import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.ignite.internal.processors.query.calcite.rel.AbstractIndexScan;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.ProjectableFilterableTableScan;
import org.apache.ignite.internal.processors.query.calcite.util.RexUtils;
import org.apache.ignite.internal.util.typedef.F;
@@ -95,7 +96,20 @@ public class IgniteMdSelectivity extends RelMdSelectivity {
}
/** */
- public Double getSelectivity(IgniteIndexSpool rel, RelMetadataQuery mq, RexNode predicate) {
+ public Double getSelectivity(IgniteSortedIndexSpool rel, RelMetadataQuery mq, RexNode predicate) {
+ if (predicate != null) {
+ return mq.getSelectivity(rel.getInput(),
+ RelMdUtil.minusPreds(
+ rel.getCluster().getRexBuilder(),
+ predicate,
+ rel.condition()));
+ }
+
+ return mq.getSelectivity(rel.getInput(), rel.condition());
+ }
+
+ /** */
+ public Double getSelectivity(IgniteHashIndexSpool rel, RelMetadataQuery mq, RexNode predicate) {
if (predicate != null) {
return mq.getSelectivity(rel.getInput(),
RelMdUtil.minusPreds(
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/cost/IgniteCost.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/cost/IgniteCost.java
index 60bd64e..84d40f3 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/cost/IgniteCost.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/cost/IgniteCost.java
@@ -40,6 +40,9 @@ public class IgniteCost implements RelOptCost {
/** Memory cost of a aggregate call. */
public static final double AGG_CALL_MEM_COST = 5;
+ /** Cost of a lookup at the hash. */
+ public static final double HASH_LOOKUP_COST = 10;
+
/**
* With broadcast distribution each row will be sent to the each distination node,
* thus the total bytes amount will be multiplies of the destination nodes count.
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/Cloner.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/Cloner.java
index 1b2d530..5ef854a 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/Cloner.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/Cloner.java
@@ -22,8 +22,8 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCorrelatedNestedLoopJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteExchange;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteLimit;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteMergeJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteNestedLoopJoin;
@@ -33,6 +33,7 @@ import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRelVisitor;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSender;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableModify;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
@@ -170,7 +171,7 @@ public class Cloner implements IgniteRelVisitor<IgniteRel> {
}
/** {@inheritDoc} */
- @Override public IgniteRel visit(IgniteIndexSpool rel) {
+ @Override public IgniteRel visit(IgniteSortedIndexSpool rel) {
return rel.clone(cluster, F.asList(visit((IgniteRel) rel.getInput())));
}
@@ -218,6 +219,10 @@ public class Cloner implements IgniteRelVisitor<IgniteRel> {
return rel.clone(cluster, F.asList(visit((IgniteRel) rel.getInput())));
}
+ @Override public IgniteRel visit(IgniteHashIndexSpool rel) {
+ return rel.clone(cluster, F.asList(visit((IgniteRel) rel.getInput())));
+ }
+
/** {@inheritDoc} */
@Override public IgniteRel visit(IgniteRel rel) {
return rel.accept(this);
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteRelShuttle.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteRelShuttle.java
index 5f05cc6..a069f19 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteRelShuttle.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteRelShuttle.java
@@ -22,8 +22,8 @@ import java.util.List;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCorrelatedNestedLoopJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteExchange;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteLimit;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteMergeJoin;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteNestedLoopJoin;
@@ -33,6 +33,7 @@ import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRelVisitor;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSender;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableModify;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
@@ -165,7 +166,12 @@ public class IgniteRelShuttle implements IgniteRelVisitor<IgniteRel> {
}
/** {@inheritDoc} */
- @Override public IgniteRel visit(IgniteIndexSpool rel) {
+ @Override public IgniteRel visit(IgniteSortedIndexSpool rel) {
+ return processNode(rel);
+ }
+
+ /** {@inheritDoc} */
+ @Override public IgniteRel visit(IgniteHashIndexSpool rel) {
return processNode(rel);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java
index e108efa..3dced8d 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java
@@ -41,7 +41,8 @@ import org.apache.calcite.tools.RuleSet;
import org.apache.calcite.tools.RuleSets;
import org.apache.ignite.internal.processors.query.calcite.rule.CorrelatedNestedLoopJoinRule;
import org.apache.ignite.internal.processors.query.calcite.rule.FilterConverterRule;
-import org.apache.ignite.internal.processors.query.calcite.rule.FilterSpoolMergeRule;
+import org.apache.ignite.internal.processors.query.calcite.rule.FilterSpoolMergeToHashIndexSpoolRule;
+import org.apache.ignite.internal.processors.query.calcite.rule.FilterSpoolMergeToSortedIndexSpoolRule;
import org.apache.ignite.internal.processors.query.calcite.rule.HashAggregateConverterRule;
import org.apache.ignite.internal.processors.query.calcite.rule.LogicalScanConverterRule;
import org.apache.ignite.internal.processors.query.calcite.rule.MergeJoinConverterRule;
@@ -174,7 +175,8 @@ public enum PlannerPhase {
TableModifyConverterRule.INSTANCE,
UnionConverterRule.INSTANCE,
SortConverterRule.INSTANCE,
- FilterSpoolMergeRule.INSTANCE
+ FilterSpoolMergeToSortedIndexSpoolRule.INSTANCE,
+ FilterSpoolMergeToHashIndexSpoolRule.INSTANCE
)
);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteCorrelatedNestedLoopJoin.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteCorrelatedNestedLoopJoin.java
index da6cab5..c760dc6 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteCorrelatedNestedLoopJoin.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteCorrelatedNestedLoopJoin.java
@@ -106,7 +106,7 @@ public class IgniteCorrelatedNestedLoopJoin extends AbstractIgniteJoin {
List<Integer> newRightCollationFields = maxPrefix(rightCollation.getKeys(), joinInfo.leftKeys);
if (F.isEmpty(newRightCollationFields))
- return ImmutableList.of();
+ return ImmutableList.of(Pair.of(nodeTraits.replace(RelCollations.EMPTY), inputTraits));
// We preserve left edge collation only if batch size == 1
if (variablesSet.size() == 1)
@@ -138,9 +138,6 @@ public class IgniteCorrelatedNestedLoopJoin extends AbstractIgniteJoin {
) {
RelTraitSet left = inputTraits.get(0), right = inputTraits.get(1);
- // Index lookup (collation) is required for right input.
- RelCollation rightReplace = RelCollations.of(joinInfo.rightKeys);
-
// We preserve left edge collation only if batch size == 1
if (variablesSet.size() == 1) {
Pair<RelTraitSet, List<RelTraitSet>> baseTraits = super.passThroughCollation(nodeTraits, inputTraits);
@@ -149,13 +146,13 @@ public class IgniteCorrelatedNestedLoopJoin extends AbstractIgniteJoin {
baseTraits.getKey(),
ImmutableList.of(
baseTraits.getValue().get(0),
- baseTraits.getValue().get(1).replace(rightReplace)
+ baseTraits.getValue().get(1)
)
);
}
return Pair.of(nodeTraits.replace(RelCollations.EMPTY),
- ImmutableList.of(left.replace(RelCollations.EMPTY), right.replace(rightReplace)));
+ ImmutableList.of(left.replace(RelCollations.EMPTY), right));
}
/** {@inheritDoc} */
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteHashIndexSpool.java
similarity index 67%
copy from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteHashIndexSpool.java
index dc9e062..055d192 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteHashIndexSpool.java
@@ -18,54 +18,53 @@
package org.apache.ignite.internal.processors.query.calcite.rel;
import java.util.List;
-import java.util.Objects;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelInput;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.core.Spool;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.util.ImmutableBitSet;
import org.apache.ignite.internal.processors.query.calcite.metadata.cost.IgniteCost;
import org.apache.ignite.internal.processors.query.calcite.metadata.cost.IgniteCostFactory;
-import org.apache.ignite.internal.processors.query.calcite.util.IndexConditions;
+import org.apache.ignite.internal.processors.query.calcite.util.RexUtils;
+import org.apache.ignite.internal.util.typedef.F;
/**
- * Relational operator that returns the sorted contents of a table
- * and allow to lookup rows by specified bounds.
+ * Relational operator that returns the hashed contents of a table
+ * and allow to lookup rows by specified keys.
*/
-public class IgniteIndexSpool extends Spool implements IgniteRel {
- /** */
- private final RelCollation collation;
+public class IgniteHashIndexSpool extends Spool implements IgniteRel {
+ /** Search row. */
+ private final List<RexNode> searchRow;
- /** Index condition. */
- private final IndexConditions idxCond;
+ /** Keys (number of the columns at the input row) to build hash index. */
+ private final ImmutableBitSet keys;
- /** Filters. */
- protected final RexNode condition;
+ /** Condition (used to calculate selectivity). */
+ private final RexNode cond;
/** */
- public IgniteIndexSpool(
+ public IgniteHashIndexSpool(
RelOptCluster cluster,
RelTraitSet traits,
RelNode input,
- RelCollation collation,
- RexNode condition,
- IndexConditions idxCond
+ List<RexNode> searchRow,
+ RexNode cond
) {
super(cluster, traits, input, Type.LAZY, Type.EAGER);
- assert Objects.nonNull(idxCond);
- assert Objects.nonNull(condition);
+ assert !F.isEmpty(searchRow);
+
+ this.searchRow = searchRow;
+ this.cond = cond;
- this.idxCond = idxCond;
- this.condition = condition;
- this.collation = collation;
+ keys = ImmutableBitSet.of(RexUtils.notNullKeys(searchRow));
}
/**
@@ -73,13 +72,12 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
*
* @param input Serialized representation.
*/
- public IgniteIndexSpool(RelInput input) {
+ public IgniteHashIndexSpool(RelInput input) {
this(input.getCluster(),
input.getTraitSet().replace(IgniteConvention.INSTANCE),
input.getInputs().get(0),
- input.getCollation(),
- input.getExpression("condition"),
- new IndexConditions(input)
+ input.getExpressionList("searchRow"),
+ null
);
}
@@ -90,12 +88,12 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
/** */
@Override public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
- return new IgniteIndexSpool(cluster, getTraitSet(), inputs.get(0), collation, condition, idxCond);
+ return new IgniteHashIndexSpool(cluster, getTraitSet(), inputs.get(0), searchRow, cond);
}
/** {@inheritDoc} */
@Override protected Spool copy(RelTraitSet traitSet, RelNode input, Type readType, Type writeType) {
- return new IgniteIndexSpool(getCluster(), traitSet, input, collation, condition, idxCond);
+ return new IgniteHashIndexSpool(getCluster(), traitSet, input, searchRow, cond);
}
/** {@inheritDoc} */
@@ -107,10 +105,7 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
@Override public RelWriter explainTerms(RelWriter pw) {
RelWriter writer = super.explainTerms(pw);
- writer.item("condition", condition);
- writer.item("collation", collation);
-
- return idxCond.explainTerms(writer);
+ return writer.item("searchRow", searchRow);
}
/** {@inheritDoc} */
@@ -118,10 +113,7 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
double rowCnt = mq.getRowCount(getInput());
double bytesPerRow = getRowType().getFieldCount() * IgniteCost.AVERAGE_FIELD_SIZE;
double totalBytes = rowCnt * bytesPerRow;
- double cpuCost = rowCnt * IgniteCost.ROW_PASS_THROUGH_COST;
-
- if (idxCond.lowerCondition() != null)
- cpuCost += Math.log(rowCnt) * IgniteCost.ROW_COMPARISON_COST;
+ double cpuCost = IgniteCost.HASH_LOOKUP_COST;
IgniteCostFactory costFactory = (IgniteCostFactory)planner.getCostFactory();
@@ -134,17 +126,17 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
}
/** */
- public IndexConditions indexCondition() {
- return idxCond;
+ public List<RexNode> searchRow() {
+ return searchRow;
}
/** */
- @Override public RelCollation collation() {
- return collation;
+ public ImmutableBitSet keys() {
+ return keys;
}
/** */
public RexNode condition() {
- return condition;
+ return cond;
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteRelVisitor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteRelVisitor.java
index e47dbf6..072b587e 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteRelVisitor.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteRelVisitor.java
@@ -141,7 +141,7 @@ public interface IgniteRelVisitor<T> {
/**
* See {@link IgniteRelVisitor#visit(IgniteRel)}
*/
- T visit(IgniteIndexSpool rel);
+ T visit(IgniteSortedIndexSpool rel);
/**
* See {@link IgniteRelVisitor#visit(IgniteRel)}
@@ -149,6 +149,11 @@ public interface IgniteRelVisitor<T> {
T visit(IgniteLimit rel);
/**
+ * See {@link IgniteRelVisitor#visit(IgniteRel)}
+ */
+ T visit(IgniteHashIndexSpool rel);
+
+ /**
* Visits a relational node and calculates a result on the basis of node meta information.
* @param rel Relational node.
* @return Visit result.
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSort.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSort.java
index 964204b..b0cf10e 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSort.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSort.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.processors.query.calcite.rel;
import java.util.List;
+
import com.google.common.collect.ImmutableList;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
@@ -109,12 +110,12 @@ public class IgniteSort extends Sort implements IgniteRel {
@Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
double rows = mq.getRowCount(getInput());
- double cost = rows * IgniteCost.ROW_PASS_THROUGH_COST + Util.nLogN(rows) * IgniteCost.ROW_COMPARISON_COST;
+ double cpuCost = rows * IgniteCost.ROW_PASS_THROUGH_COST + Util.nLogN(rows) * IgniteCost.ROW_COMPARISON_COST;
double memory = rows * getRowType().getFieldCount() * IgniteCost.AVERAGE_FIELD_SIZE;
IgniteCostFactory costFactory = (IgniteCostFactory)planner.getCostFactory();
- return costFactory.makeCost(rows, cost, 0, memory, 0);
+ return costFactory.makeCost(rows, cpuCost, 0, memory, 0);
}
/** {@inheritDoc} */
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSortedIndexSpool.java
similarity index 89%
rename from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java
rename to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSortedIndexSpool.java
index dc9e062..8dfea74 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexSpool.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteSortedIndexSpool.java
@@ -39,7 +39,7 @@ import org.apache.ignite.internal.processors.query.calcite.util.IndexConditions;
* Relational operator that returns the sorted contents of a table
* and allow to lookup rows by specified bounds.
*/
-public class IgniteIndexSpool extends Spool implements IgniteRel {
+public class IgniteSortedIndexSpool extends Spool implements IgniteRel {
/** */
private final RelCollation collation;
@@ -50,7 +50,7 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
protected final RexNode condition;
/** */
- public IgniteIndexSpool(
+ public IgniteSortedIndexSpool(
RelOptCluster cluster,
RelTraitSet traits,
RelNode input,
@@ -73,7 +73,7 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
*
* @param input Serialized representation.
*/
- public IgniteIndexSpool(RelInput input) {
+ public IgniteSortedIndexSpool(RelInput input) {
this(input.getCluster(),
input.getTraitSet().replace(IgniteConvention.INSTANCE),
input.getInputs().get(0),
@@ -90,12 +90,12 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
/** */
@Override public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
- return new IgniteIndexSpool(cluster, getTraitSet(), inputs.get(0), collation, condition, idxCond);
+ return new IgniteSortedIndexSpool(cluster, getTraitSet(), inputs.get(0), collation, condition, idxCond);
}
/** {@inheritDoc} */
@Override protected Spool copy(RelTraitSet traitSet, RelNode input, Type readType, Type writeType) {
- return new IgniteIndexSpool(getCluster(), traitSet, input, collation, condition, idxCond);
+ return new IgniteSortedIndexSpool(getCluster(), traitSet, input, collation, condition, idxCond);
}
/** {@inheritDoc} */
@@ -114,21 +114,6 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
}
/** {@inheritDoc} */
- @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
- double rowCnt = mq.getRowCount(getInput());
- double bytesPerRow = getRowType().getFieldCount() * IgniteCost.AVERAGE_FIELD_SIZE;
- double totalBytes = rowCnt * bytesPerRow;
- double cpuCost = rowCnt * IgniteCost.ROW_PASS_THROUGH_COST;
-
- if (idxCond.lowerCondition() != null)
- cpuCost += Math.log(rowCnt) * IgniteCost.ROW_COMPARISON_COST;
-
- IgniteCostFactory costFactory = (IgniteCostFactory)planner.getCostFactory();
-
- return costFactory.makeCost(rowCnt, cpuCost, 0, totalBytes, 0);
- }
-
- /** {@inheritDoc} */
@Override public double estimateRowCount(RelMetadataQuery mq) {
return mq.getRowCount(getInput()) * mq.getSelectivity(this, null);
}
@@ -147,4 +132,21 @@ public class IgniteIndexSpool extends Spool implements IgniteRel {
public RexNode condition() {
return condition;
}
+
+ /** {@inheritDoc} */
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
+ double rowCnt = mq.getRowCount(getInput());
+ double bytesPerRow = getRowType().getFieldCount() * IgniteCost.AVERAGE_FIELD_SIZE;
+ double totalBytes = rowCnt * bytesPerRow;
+ double cpuCost;
+
+ if (idxCond.lowerCondition() != null)
+ cpuCost = Math.log(rowCnt) * IgniteCost.ROW_COMPARISON_COST;
+ else
+ cpuCost = rowCnt * IgniteCost.ROW_PASS_THROUGH_COST;
+
+ IgniteCostFactory costFactory = (IgniteCostFactory)planner.getCostFactory();
+
+ return costFactory.makeCost(rowCnt, cpuCost, 0, totalBytes, 0);
+ }
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableSpool.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableSpool.java
index da8c441..fc5d095 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableSpool.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableSpool.java
@@ -80,13 +80,13 @@ public class IgniteTableSpool extends Spool implements IgniteRel {
/** {@inheritDoc} */
@Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
- double rowCount = mq.getRowCount(getInput());
+ double rowCnt = mq.getRowCount(getInput());
double bytesPerRow = getRowType().getFieldCount() * IgniteCost.AVERAGE_FIELD_SIZE;
- double totalBytes = rowCount * bytesPerRow;
+ double totalBytes = rowCnt * bytesPerRow;
+ double cpuCost = rowCnt * IgniteCost.ROW_PASS_THROUGH_COST;
IgniteCostFactory costFactory = (IgniteCostFactory)planner.getCostFactory();
- return costFactory.makeCost(rowCount,
- rowCount * IgniteCost.ROW_PASS_THROUGH_COST, 0, totalBytes, 0);
+ return costFactory.makeCost(rowCnt, cpuCost, 0, totalBytes, 0);
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java
index a174cf8..a28c59b 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java
@@ -62,12 +62,16 @@ public class IgniteLogicalIndexScan extends AbstractIndexScan {
collation = TraitUtils.projectCollation(collation, proj, rowType);
}
- IndexConditions idxCond = RexUtils.buildIndexConditions(
- cluster,
- collation,
- cond,
- tbl.getRowType(typeFactory),
- requiredColumns);
+ IndexConditions idxCond = new IndexConditions();
+
+ if (collation != null && !collation.getFieldCollations().isEmpty()) {
+ idxCond = RexUtils.buildSortedIndexConditions(
+ cluster,
+ collation,
+ cond,
+ tbl.getRowType(typeFactory),
+ requiredColumns);
+ }
return new IgniteLogicalIndexScan(
cluster,
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToHashIndexSpoolRule.java
similarity index 76%
copy from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToHashIndexSpoolRule.java
index eb989ea..cd1e0bd 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToHashIndexSpoolRule.java
@@ -16,34 +16,36 @@
*/
package org.apache.ignite.internal.processors.query.calcite.rule;
+import java.util.List;
+
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelRule;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Spool;
+import org.apache.calcite.rex.RexNode;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
import org.apache.ignite.internal.processors.query.calcite.trait.CorrelationTrait;
import org.apache.ignite.internal.processors.query.calcite.trait.TraitUtils;
-import org.apache.ignite.internal.processors.query.calcite.util.IndexConditions;
import org.apache.ignite.internal.processors.query.calcite.util.RexUtils;
import org.apache.ignite.internal.util.typedef.F;
/**
* Rule that pushes filter into the spool.
*/
-public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
+public class FilterSpoolMergeToHashIndexSpoolRule extends RelRule<FilterSpoolMergeToHashIndexSpoolRule.Config> {
/** Instance. */
public static final RelOptRule INSTANCE = Config.DEFAULT.toRule();
/** */
- private FilterSpoolMergeRule(Config cfg) {
+ private FilterSpoolMergeToHashIndexSpoolRule(Config cfg) {
super(cfg);
}
@@ -62,26 +64,21 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
RelNode input = spool.getInput();
- IndexConditions idxCond = RexUtils.buildIndexConditions(
+ List<RexNode> searchRow = RexUtils.buildHashSearchRow(
cluster,
- TraitUtils.collation(input),
filter.getCondition(),
- spool.getRowType(),
- null
+ spool.getRowType()
);
- if (F.isEmpty(idxCond.lowerCondition()) && F.isEmpty(idxCond.upperCondition()))
+ if (F.isEmpty(searchRow))
return;
- RelCollation collation = TraitUtils.collation(input);
-
- RelNode res = new IgniteIndexSpool(
+ RelNode res = new IgniteHashIndexSpool(
cluster,
- trait.replace(collation),
- convert(input, input.getTraitSet().replace(collation)),
- collation,
- filter.getCondition(),
- idxCond
+ trait.replace(RelCollations.EMPTY),
+ input,
+ searchRow,
+ filter.getCondition()
);
call.transformTo(res);
@@ -93,8 +90,8 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
/** */
Config DEFAULT = RelRule.Config.EMPTY
.withRelBuilderFactory(RelFactories.LOGICAL_BUILDER)
- .withDescription("FilterSpoolMergeRule")
- .as(FilterSpoolMergeRule.Config.class)
+ .withDescription("FilterSpoolMergeToHashIndexSpoolRule")
+ .as(FilterSpoolMergeToHashIndexSpoolRule.Config.class)
.withOperandFor(IgniteFilter.class, IgniteTableSpool.class);
/** Defines an operand tree for the given classes. */
@@ -109,8 +106,8 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
}
/** {@inheritDoc} */
- @Override default FilterSpoolMergeRule toRule() {
- return new FilterSpoolMergeRule(this);
+ @Override default FilterSpoolMergeToHashIndexSpoolRule toRule() {
+ return new FilterSpoolMergeToHashIndexSpoolRule(this);
}
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToSortedIndexSpoolRule.java
similarity index 83%
rename from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java
rename to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToSortedIndexSpoolRule.java
index eb989ea..a447997 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeRule.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/FilterSpoolMergeToSortedIndexSpoolRule.java
@@ -16,6 +16,7 @@
*/
package org.apache.ignite.internal.processors.query.calcite.rule;
+import com.google.common.collect.ImmutableList;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
@@ -27,7 +28,7 @@ import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Spool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
import org.apache.ignite.internal.processors.query.calcite.trait.CorrelationTrait;
import org.apache.ignite.internal.processors.query.calcite.trait.TraitUtils;
@@ -38,12 +39,12 @@ import org.apache.ignite.internal.util.typedef.F;
/**
* Rule that pushes filter into the spool.
*/
-public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
+public class FilterSpoolMergeToSortedIndexSpoolRule extends RelRule<FilterSpoolMergeToSortedIndexSpoolRule.Config> {
/** Instance. */
public static final RelOptRule INSTANCE = Config.DEFAULT.toRule();
/** */
- private FilterSpoolMergeRule(Config cfg) {
+ private FilterSpoolMergeToSortedIndexSpoolRule(Config cfg) {
super(cfg);
}
@@ -62,7 +63,7 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
RelNode input = spool.getInput();
- IndexConditions idxCond = RexUtils.buildIndexConditions(
+ IndexConditions idxCond = RexUtils.buildSortedIndexConditions(
cluster,
TraitUtils.collation(input),
filter.getCondition(),
@@ -73,9 +74,9 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
if (F.isEmpty(idxCond.lowerCondition()) && F.isEmpty(idxCond.upperCondition()))
return;
- RelCollation collation = TraitUtils.collation(input);
+ RelCollation collation = TraitUtils.createCollation(ImmutableList.copyOf(idxCond.keys()));
- RelNode res = new IgniteIndexSpool(
+ RelNode res = new IgniteSortedIndexSpool(
cluster,
trait.replace(collation),
convert(input, input.getTraitSet().replace(collation)),
@@ -93,8 +94,8 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
/** */
Config DEFAULT = RelRule.Config.EMPTY
.withRelBuilderFactory(RelFactories.LOGICAL_BUILDER)
- .withDescription("FilterSpoolMergeRule")
- .as(FilterSpoolMergeRule.Config.class)
+ .withDescription("FilterSpoolMergeToSortedIndexSpoolRule")
+ .as(FilterSpoolMergeToSortedIndexSpoolRule.Config.class)
.withOperandFor(IgniteFilter.class, IgniteTableSpool.class);
/** Defines an operand tree for the given classes. */
@@ -109,8 +110,8 @@ public class FilterSpoolMergeRule extends RelRule<FilterSpoolMergeRule.Config> {
}
/** {@inheritDoc} */
- @Override default FilterSpoolMergeRule toRule() {
- return new FilterSpoolMergeRule(this);
+ @Override default FilterSpoolMergeToSortedIndexSpoolRule toRule() {
+ return new FilterSpoolMergeToSortedIndexSpoolRule(this);
}
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IndexConditions.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IndexConditions.java
index 230652b..b0a0212 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IndexConditions.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IndexConditions.java
@@ -17,13 +17,14 @@
package org.apache.ignite.internal.processors.query.calcite.util;
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import org.apache.calcite.rel.RelInput;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.util.ImmutableIntList;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.jetbrains.annotations.Nullable;
@@ -101,11 +102,11 @@ public class IndexConditions {
}
/** */
- public ImmutableIntList keys() {
+ public Set<Integer> keys() {
if (upperBound == null && lowerBound == null)
- return ImmutableIntList.of();
+ return Collections.emptySet();
- List<Integer> keys = new ArrayList<>();
+ Set<Integer> keys = new HashSet<>();
int cols = lowerBound != null ? lowerBound.size() : upperBound.size();
@@ -115,7 +116,7 @@ public class IndexConditions {
keys.add(i);
}
- return ImmutableIntList.copyOf(keys);
+ return Collections.unmodifiableSet(keys);
}
/**
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
index da3a94e..047f0c2 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
@@ -32,6 +32,7 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.CorrelationId;
@@ -59,6 +60,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.ControlFlowException;
import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Util;
import org.apache.calcite.util.mapping.MappingType;
@@ -159,14 +161,14 @@ public class RexUtils {
/**
* Builds index conditions.
*/
- public static IndexConditions buildIndexConditions(
+ public static IndexConditions buildSortedIndexConditions(
RelOptCluster cluster,
RelCollation collation,
RexNode condition,
RelDataType rowType,
ImmutableBitSet requiredColumns
) {
- if (condition == null || collation == null || collation.getFieldCollations().isEmpty())
+ if (condition == null)
return new IndexConditions();
condition = RexUtil.toCnf(builder(cluster), condition);
@@ -179,6 +181,10 @@ public class RexUtils {
List<RexNode> lower = new ArrayList<>();
List<RexNode> upper = new ArrayList<>();
+ // Force collation for all fields of the condition.
+ if (collation == null || collation.isDefault())
+ collation = RelCollations.of(ImmutableIntList.copyOf(fieldsToPredicates.keySet()));
+
for (int i = 0; i < collation.getFieldCollations().size(); i++) {
RelFieldCollation fc = collation.getFieldCollations().get(i);
@@ -275,6 +281,52 @@ public class RexUtils {
return new IndexConditions(lower, upper, lowerBound, upperBound);
}
+ /**
+ * Builds index conditions.
+ */
+ public static List<RexNode> buildHashSearchRow(
+ RelOptCluster cluster,
+ RexNode condition,
+ RelDataType rowType
+ ) {
+ condition = RexUtil.toCnf(builder(cluster), condition);
+
+ Map<Integer, List<RexCall>> fieldsToPredicates = mapPredicatesToFields(condition, cluster);
+
+ if (F.isEmpty(fieldsToPredicates))
+ return null;
+
+ List<RexNode> searchPreds = null;
+
+ for (int fldIdx : fieldsToPredicates.keySet()) {
+ List<RexCall> collFldPreds = fieldsToPredicates.get(fldIdx);
+
+ if (F.isEmpty(collFldPreds))
+ break;
+
+ for (RexCall pred : collFldPreds) {
+ if (U.assertionsEnabled()) {
+ RexNode cond = RexUtil.removeCast(pred.operands.get(1));
+
+ assert idxOpSupports(cond) : cond;
+ }
+
+ if (pred.getOperator().kind != SqlKind.EQUALS)
+ return null;
+
+ if (searchPreds == null)
+ searchPreds = new ArrayList<>();
+
+ searchPreds.add(pred);
+ }
+ }
+
+ if (searchPreds == null)
+ return null;
+
+ return asBound(cluster, searchPreds, rowType, null);
+ }
+
/** */
private static Map<Integer, List<RexCall>> mapPredicatesToFields(RexNode condition, RelOptCluster cluster) {
List<RexNode> conjunctions = RelOptUtil.conjunctions(condition);
@@ -469,6 +521,21 @@ public class RexUtils {
}
/** */
+ public static Set<Integer> notNullKeys(List<RexNode> row) {
+ if (F.isEmpty(row))
+ return Collections.emptySet();
+
+ Set<Integer> keys = new HashSet<>();
+
+ for (int i = 0; i < row.size(); ++i ) {
+ if (isNotNull(row.get(i)))
+ keys.add(i);
+ }
+
+ return keys;
+ }
+
+ /** */
public static Set<CorrelationId> extractCorrelationIds(List<RexNode> nodes) {
final Set<CorrelationId> cors = new HashSet<>();
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/HashIndexSpoolExecutionTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/HashIndexSpoolExecutionTest.java
new file mode 100644
index 0000000..be17583
--- /dev/null
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/HashIndexSpoolExecutionTest.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.ignite.internal.processors.query.calcite.exec.rel;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.UUID;
+import java.util.function.Predicate;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+import org.apache.ignite.internal.util.lang.GridTuple3;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+@WithSystemProperty(key = "calcite.debug", value = "true")
+public class HashIndexSpoolExecutionTest extends AbstractExecutionTest {
+ /**
+ * @throws Exception If failed.
+ */
+ @Before
+ @Override public void setup() throws Exception {
+ nodesCnt = 1;
+ super.setup();
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void testIndexSpool() throws Exception {
+ ExecutionContext<Object[]> ctx = executionContext(F.first(nodes()), UUID.randomUUID(), 0);
+ IgniteTypeFactory tf = ctx.getTypeFactory();
+ RelDataType rowType = TypeUtils.createRowType(tf, int.class, String.class, int.class);
+
+ int inBufSize = U.field(AbstractNode.class, "IN_BUFFER_SIZE");
+
+ int[] sizes = {1, inBufSize / 2 - 1, inBufSize / 2, inBufSize / 2 + 1, inBufSize, inBufSize + 1, inBufSize * 4};
+ int[] eqCnts = {1, 10};
+
+ for (int size : sizes) {
+ for (int eqCnt : eqCnts) {
+ // (filter, search, expected result size)
+ GridTuple3<Predicate<Object[]>, Object[], Integer>[] testBounds;
+
+ if (size == 1) {
+ testBounds = new GridTuple3[] {
+ new GridTuple3(null, new Object[] {0, null, null}, eqCnt)
+ };
+ }
+ else {
+ testBounds = new GridTuple3[] {
+ new GridTuple3(
+ null,
+ new Object[] {size / 2, null, null},
+ eqCnt
+ ),
+ new GridTuple3(
+ null,
+ new Object[] {size / 2 + 1, null, null},
+ eqCnt
+ )
+ };
+ }
+
+ log.info("Check: size=" + size);
+
+ ScanNode<Object[]> scan = new ScanNode<>(ctx, rowType, new TestTable(
+ size * eqCnt,
+ rowType,
+ (rowId) -> rowId / eqCnt,
+ (rowId) -> "val_" + (rowId % eqCnt),
+ (rowId) -> rowId % eqCnt
+ ) {
+ boolean first = true;
+
+ @Override public @NotNull Iterator<Object[]> iterator() {
+ assertTrue("Rewind right", first);
+
+ first = false;
+ return super.iterator();
+ }
+ });
+
+ Object[] searchRow = new Object[3];
+ TestPredicate testFilter = new TestPredicate();
+
+ IndexSpoolNode<Object[]> spool = IndexSpoolNode.createHashSpool(
+ ctx,
+ rowType,
+ ImmutableBitSet.of(0),
+ () -> searchRow
+ );
+
+ spool.register(Arrays.asList(scan));
+
+ RootRewindable<Object[]> root = new RootRewindable<>(ctx, rowType);
+ root.register(spool);
+
+ for (GridTuple3<Predicate<Object[]>, Object[], Integer> bound : testBounds) {
+ log.info("Check: bound=" + bound);
+
+ // Set up bounds
+ testFilter.delegate = bound.get1();
+ System.arraycopy(bound.get2(), 0, searchRow, 0, searchRow.length);
+
+ int cnt = 0;
+
+ while (root.hasNext()) {
+ root.next();
+
+ cnt++;
+ }
+
+ assertEquals(
+ "Invalid result size",
+ (int)bound.get3(),
+ cnt);
+
+ root.rewind();
+ }
+
+ root.closeRewindableRoot();
+ }
+ }
+ }
+
+ /** */
+ static class TestPredicate implements Predicate<Object[]> {
+ /** */
+ Predicate<Object[]> delegate;
+
+ /** {@inheritDoc} */
+ @Override public boolean test(Object[] objects) {
+ if (delegate == null)
+ return true;
+ else
+ return delegate.test(objects);
+ }
+ }
+}
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolExecutionTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/TreeIndexSpoolExecutionTest.java
similarity index 97%
rename from modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolExecutionTest.java
rename to modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/TreeIndexSpoolExecutionTest.java
index e0b0806..04c2ae7 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/IndexSpoolExecutionTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/TreeIndexSpoolExecutionTest.java
@@ -41,7 +41,7 @@ import org.junit.Test;
*/
@SuppressWarnings("TypeMayBeWeakened")
@WithSystemProperty(key = "calcite.debug", value = "true")
-public class IndexSpoolExecutionTest extends AbstractExecutionTest {
+public class TreeIndexSpoolExecutionTest extends AbstractExecutionTest {
/**
* @throws Exception If failed.
*/
@@ -132,7 +132,7 @@ public class IndexSpoolExecutionTest extends AbstractExecutionTest {
Object[] upper = new Object[3];
TestPredicate testFilter = new TestPredicate();
- IndexSpoolNode<Object[]> spool = new IndexSpoolNode<>(
+ IndexSpoolNode<Object[]> spool = IndexSpoolNode.createTreeSpool(
ctx,
rowType,
RelCollations.of(ImmutableIntList.of(0)),
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/AbstractPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/AbstractPlannerTest.java
index d172fad..03a92bb 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/AbstractPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/AbstractPlannerTest.java
@@ -264,6 +264,8 @@ public abstract class AbstractPlannerTest extends GridCommonAbstractTest {
try {
IgniteRel res = planner.transform(PlannerPhase.OPTIMIZATION, desired, rel);
+// System.out.println(planner.dump());
+
return res;
}
catch (Throwable ex) {
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/CorrelatedNestedLoopJoinPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/CorrelatedNestedLoopJoinPlannerTest.java
index 6c1e3bf..e735993 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/CorrelatedNestedLoopJoinPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/CorrelatedNestedLoopJoinPlannerTest.java
@@ -86,9 +86,11 @@ public class CorrelatedNestedLoopJoinPlannerTest extends AbstractPlannerTest {
IgniteRel phys = physicalPlan(
sql,
publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeRule"
+ "MergeJoinConverter", "NestedLoopJoinConverter"
);
+ System.out.println("+++ " + RelOptUtil.toString(phys));
+
assertNotNull(phys);
checkSplitAndSerialization(phys, publicSchema);
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
similarity index 70%
copy from modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java
copy to modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
index f6d1c37..fa33898 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
@@ -19,15 +19,15 @@ package org.apache.ignite.internal.processors.query.calcite.planner;
import java.util.List;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexFieldAccess;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.util.ImmutableIntList;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
import org.apache.ignite.internal.processors.query.calcite.schema.IgniteSchema;
import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution;
import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions;
@@ -38,14 +38,13 @@ import org.junit.Test;
/**
*
*/
-@SuppressWarnings({"FieldCanBeLocal"})
-public class IndexSpoolPlannerTest extends AbstractPlannerTest {
+public class HashIndexSpoolPlannerTest extends AbstractPlannerTest {
/**
* Check equi-join on not colocated fields.
* CorrelatedNestedLoopJoinTest is applicable for this case only with IndexSpool.
*/
@Test
- public void test() throws Exception {
+ public void testSingleKey() throws Exception {
IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE);
@@ -88,38 +87,28 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
IgniteRel phys = physicalPlan(
sql,
publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter"
+ "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeToSortedIndexSpoolRule"
);
- checkSplitAndSerialization(phys, publicSchema);
-
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
-
- List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
+ System.out.println("+++\n" + RelOptUtil.toString(phys));
- assertNotNull(lBound);
- assertEquals(3, lBound.size());
+ checkSplitAndSerialization(phys, publicSchema);
- assertTrue(((RexLiteral)lBound.get(0)).isNull());
- assertTrue(((RexLiteral)lBound.get(2)).isNull());
- assertTrue(lBound.get(1) instanceof RexFieldAccess);
+ IgniteHashIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteHashIndexSpool.class));
- List<RexNode> uBound = idxSpool.indexCondition().upperBound();
+ List<RexNode> searchRow = idxSpool.searchRow();
- assertNotNull(uBound);
- assertEquals(3, uBound.size());
+ assertNotNull(searchRow);
+ assertEquals(3, searchRow.size());
- assertTrue(((RexLiteral)uBound.get(0)).isNull());
- assertTrue(((RexLiteral)uBound.get(2)).isNull());
- assertTrue(uBound.get(1) instanceof RexFieldAccess);
+ assertTrue(((RexLiteral)searchRow.get(0)).isNull());
+ assertTrue(((RexLiteral)searchRow.get(2)).isNull());
+ assertTrue(searchRow.get(1) instanceof RexFieldAccess);
}
- /**
- * Check case when exists index (collation) isn't applied not for whole join condition
- * but may be used by part of condition.
- */
+ /** */
@Test
- public void testPartialIndexForCondition() throws Exception {
+ public void testMultipleKeys() throws Exception {
IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE);
@@ -163,32 +152,22 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
IgniteRel phys = physicalPlan(
sql,
publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter"
+ "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeToSortedIndexSpoolRule"
);
checkSplitAndSerialization(phys, publicSchema);
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
+ IgniteHashIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteHashIndexSpool.class));
- List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
+ List<RexNode> searcRow = idxSpool.searchRow();
- assertNotNull(lBound);
- assertEquals(4, lBound.size());
+ assertNotNull(searcRow);
+ assertEquals(4, searcRow.size());
- assertTrue(((RexLiteral)lBound.get(0)).isNull());
- assertTrue(((RexLiteral)lBound.get(2)).isNull());
- assertTrue(((RexLiteral)lBound.get(3)).isNull());
- assertTrue(lBound.get(1) instanceof RexFieldAccess);
-
- List<RexNode> uBound = idxSpool.indexCondition().upperBound();
-
- assertNotNull(uBound);
- assertEquals(4, uBound.size());
-
- assertTrue(((RexLiteral)uBound.get(0)).isNull());
- assertTrue(((RexLiteral)lBound.get(2)).isNull());
- assertTrue(((RexLiteral)lBound.get(3)).isNull());
- assertTrue(uBound.get(1) instanceof RexFieldAccess);
+ assertTrue(((RexLiteral)searcRow.get(0)).isNull());
+ assertTrue(searcRow.get(1) instanceof RexFieldAccess);
+ assertTrue(searcRow.get(2) instanceof RexFieldAccess);
+ assertTrue(((RexLiteral)searcRow.get(3)).isNull());
}
/**
@@ -241,26 +220,15 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
checkSplitAndSerialization(phys, publicSchema);
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
-
- assertTrue(idxSpool.getInput() instanceof IgniteSort);
-
- List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
-
- assertNotNull(lBound);
- assertEquals(3, lBound.size());
-
- assertTrue(((RexLiteral)lBound.get(0)).isNull());
- assertTrue(((RexLiteral)lBound.get(2)).isNull());
- assertTrue(lBound.get(1) instanceof RexFieldAccess);
+ IgniteHashIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteHashIndexSpool.class));
- List<RexNode> uBound = idxSpool.indexCondition().upperBound();
+ List<RexNode> searchRow = idxSpool.searchRow();
- assertNotNull(uBound);
- assertEquals(3, uBound.size());
+ assertNotNull(searchRow);
+ assertEquals(3, searchRow.size());
- assertTrue(((RexLiteral)uBound.get(0)).isNull());
- assertTrue(((RexLiteral)uBound.get(2)).isNull());
- assertTrue(uBound.get(1) instanceof RexFieldAccess);
+ assertTrue(((RexLiteral)searchRow.get(0)).isNull());
+ assertTrue(((RexLiteral)searchRow.get(2)).isNull());
+ assertTrue(searchRow.get(1) instanceof RexFieldAccess);
}
}
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SortedIndexSpoolPlannerTest.java
similarity index 69%
rename from modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java
rename to modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SortedIndexSpoolPlannerTest.java
index f6d1c37..f6840b2 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSpoolPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SortedIndexSpoolPlannerTest.java
@@ -19,15 +19,15 @@ package org.apache.ignite.internal.processors.query.calcite.planner;
import java.util.List;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexFieldAccess;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.util.ImmutableIntList;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
-import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
import org.apache.ignite.internal.processors.query.calcite.schema.IgniteSchema;
import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution;
import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions;
@@ -38,14 +38,13 @@ import org.junit.Test;
/**
*
*/
-@SuppressWarnings({"FieldCanBeLocal"})
-public class IndexSpoolPlannerTest extends AbstractPlannerTest {
+public class SortedIndexSpoolPlannerTest extends AbstractPlannerTest {
/**
* Check equi-join on not colocated fields.
* CorrelatedNestedLoopJoinTest is applicable for this case only with IndexSpool.
*/
@Test
- public void test() throws Exception {
+ public void testNotColocatedEqJoin() throws Exception {
IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE);
@@ -88,12 +87,12 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
IgniteRel phys = physicalPlan(
sql,
publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter"
+ "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeToHashIndexSpoolRule"
);
checkSplitAndSerialization(phys, publicSchema);
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
+ IgniteSortedIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteSortedIndexSpool.class));
List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
@@ -163,12 +162,14 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
IgniteRel phys = physicalPlan(
sql,
publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter"
+ "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeToHashIndexSpoolRule"
);
+ System.out.println("+++ \n" + RelOptUtil.toString(phys));
+
checkSplitAndSerialization(phys, publicSchema);
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
+ IgniteSortedIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteSortedIndexSpool.class));
List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
@@ -190,77 +191,4 @@ public class IndexSpoolPlannerTest extends AbstractPlannerTest {
assertTrue(((RexLiteral)lBound.get(3)).isNull());
assertTrue(uBound.get(1) instanceof RexFieldAccess);
}
-
- /**
- * Check equi-join on not colocated fields without indexes.
- */
- @Test
- public void testSourceWithoutCollation() throws Exception {
- IgniteSchema publicSchema = new IgniteSchema("PUBLIC");
- IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE);
-
- publicSchema.addTable(
- "T0",
- new TestTable(
- new RelDataTypeFactory.Builder(f)
- .add("ID", f.createJavaType(Integer.class))
- .add("JID", f.createJavaType(Integer.class))
- .add("VAL", f.createJavaType(String.class))
- .build()) {
-
- @Override public IgniteDistribution distribution() {
- return IgniteDistributions.affinity(0, "T0", "hash");
- }
- }
- );
-
- publicSchema.addTable(
- "T1",
- new TestTable(
- new RelDataTypeFactory.Builder(f)
- .add("ID", f.createJavaType(Integer.class))
- .add("JID", f.createJavaType(Integer.class))
- .add("VAL", f.createJavaType(String.class))
- .build()) {
-
- @Override public IgniteDistribution distribution() {
- return IgniteDistributions.affinity(0, "T1", "hash");
- }
- }
- );
-
- String sql = "select * " +
- "from t0 " +
- "join t1 on t0.jid = t1.jid";
-
- IgniteRel phys = physicalPlan(
- sql,
- publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter"
- );
-
- checkSplitAndSerialization(phys, publicSchema);
-
- IgniteIndexSpool idxSpool = findFirstNode(phys, byClass(IgniteIndexSpool.class));
-
- assertTrue(idxSpool.getInput() instanceof IgniteSort);
-
- List<RexNode> lBound = idxSpool.indexCondition().lowerBound();
-
- assertNotNull(lBound);
- assertEquals(3, lBound.size());
-
- assertTrue(((RexLiteral)lBound.get(0)).isNull());
- assertTrue(((RexLiteral)lBound.get(2)).isNull());
- assertTrue(lBound.get(1) instanceof RexFieldAccess);
-
- List<RexNode> uBound = idxSpool.indexCondition().upperBound();
-
- assertNotNull(uBound);
- assertEquals(3, uBound.size());
-
- assertTrue(((RexLiteral)uBound.get(0)).isNull());
- assertTrue(((RexLiteral)uBound.get(2)).isNull());
- assertTrue(uBound.get(1) instanceof RexFieldAccess);
- }
}
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TableSpoolPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TableSpoolPlannerTest.java
index c472142..a475b10 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TableSpoolPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TableSpoolPlannerTest.java
@@ -72,7 +72,7 @@ public class TableSpoolPlannerTest extends AbstractPlannerTest {
String sql = "select * " +
"from t0 " +
- "join t1 on t0.jid = t1.jid";
+ "join t1 on t0.jid > t1.jid";
RelNode phys = physicalPlan(sql, publicSchema,
"MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeRule");
@@ -127,7 +127,8 @@ public class TableSpoolPlannerTest extends AbstractPlannerTest {
"join t1 on t0.jid = t1.jid";
RelNode phys = physicalPlan(sql, publicSchema,
- "MergeJoinConverter", "NestedLoopJoinConverter", "FilterSpoolMergeRule");
+ "MergeJoinConverter", "NestedLoopJoinConverter",
+ "FilterSpoolMergeToHashIndexSpoolRule", "FilterSpoolMergeToSortIndexSpoolRule");
assertNotNull(phys);
diff --git a/modules/calcite/src/test/java/org/apache/ignite/testsuites/ExecutionTestSuite.java b/modules/calcite/src/test/java/org/apache/ignite/testsuites/ExecutionTestSuite.java
index 2925782..2ab4fcb 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/testsuites/ExecutionTestSuite.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/testsuites/ExecutionTestSuite.java
@@ -21,11 +21,12 @@ import org.apache.ignite.internal.processors.query.calcite.exec.rel.ContinuousEx
import org.apache.ignite.internal.processors.query.calcite.exec.rel.ExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.HashAggregateExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.HashAggregateSingleGroupExecutionTest;
-import org.apache.ignite.internal.processors.query.calcite.exec.rel.IndexSpoolExecutionTest;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.HashIndexSpoolExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.MergeJoinExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.NestedLoopJoinExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.SortAggregateExecutionTest;
import org.apache.ignite.internal.processors.query.calcite.exec.rel.TableSpoolExecutionTest;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.TreeIndexSpoolExecutionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -39,7 +40,8 @@ import org.junit.runners.Suite;
MergeJoinExecutionTest.class,
NestedLoopJoinExecutionTest.class,
TableSpoolExecutionTest.class,
- IndexSpoolExecutionTest.class,
+ TreeIndexSpoolExecutionTest.class,
+ HashIndexSpoolExecutionTest.class,
HashAggregateExecutionTest.class,
HashAggregateSingleGroupExecutionTest.class,
SortAggregateExecutionTest.class,
diff --git a/modules/calcite/src/test/java/org/apache/ignite/testsuites/PlannerTestSuite.java b/modules/calcite/src/test/java/org/apache/ignite/testsuites/PlannerTestSuite.java
index 50c715f..a6d7767 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/testsuites/PlannerTestSuite.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/testsuites/PlannerTestSuite.java
@@ -21,10 +21,11 @@ import org.apache.ignite.internal.processors.query.calcite.planner.AggregateDist
import org.apache.ignite.internal.processors.query.calcite.planner.AggregatePlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.CorrelatedNestedLoopJoinPlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.HashAggregatePlannerTest;
-import org.apache.ignite.internal.processors.query.calcite.planner.IndexSpoolPlannerTest;
+import org.apache.ignite.internal.processors.query.calcite.planner.HashIndexSpoolPlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.JoinColocationPlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.PlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.SortAggregatePlannerTest;
+import org.apache.ignite.internal.processors.query.calcite.planner.SortedIndexSpoolPlannerTest;
import org.apache.ignite.internal.processors.query.calcite.planner.TableSpoolPlannerTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -37,7 +38,8 @@ import org.junit.runners.Suite;
PlannerTest.class,
CorrelatedNestedLoopJoinPlannerTest.class,
TableSpoolPlannerTest.class,
- IndexSpoolPlannerTest.class,
+ SortedIndexSpoolPlannerTest.class,
+ HashIndexSpoolPlannerTest.class,
AggregatePlannerTest.class,
AggregateDistinctPlannerTest.class,
HashAggregatePlannerTest.class,