This is an automated email from the ASF dual-hosted git repository.
xingtanzjr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 982140c9e7 Distribution plan for Align by device and GroupByLevel
(#6053)
982140c9e7 is described below
commit 982140c9e759756ddec974b393b180122aa795fa
Author: Zhang.Jinrui <[email protected]>
AuthorDate: Sat May 28 12:37:30 2022 +0800
Distribution plan for Align by device and GroupByLevel (#6053)
---
.../apache/iotdb/db/mpp/plan/analyze/Analysis.java | 4 +
.../db/mpp/plan/planner/LocalExecutionPlanner.java | 38 ++++++++-
.../planner/distribution/ExchangeNodeAdder.java | 23 +++++-
.../plan/planner/distribution/SourceRewriter.java | 91 +++++++++++++++++++++-
.../planner/plan/node/process/DeviceMergeNode.java | 9 ++-
.../planner/plan/node/process/DeviceViewNode.java | 14 +++-
.../plan/node/process/GroupByLevelNode.java | 9 +++
.../query/reader/chunk/MemAlignedPageReader.java | 1 -
.../plan/distribution/AlignedByDeviceTest.java | 36 +++++++++
9 files changed, 212 insertions(+), 13 deletions(-)
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
index 2e4eab4950..2a7137dd22 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
@@ -152,6 +152,10 @@ public class Analysis {
return dataPartition.getDataRegionReplicaSet(seriesPath.getDevice(), null);
}
+ public List<TRegionReplicaSet> getPartitionInfo(String deviceName, Filter
globalTimeFilter) {
+ return dataPartition.getDataRegionReplicaSet(deviceName, null);
+ }
+
public Statement getStatement() {
return statement;
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
index 6587e05306..e2a3176515 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LocalExecutionPlanner.java
@@ -143,6 +143,7 @@ import
org.apache.iotdb.db.mpp.plan.planner.plan.node.source.SeriesAggregationSc
import org.apache.iotdb.db.mpp.plan.planner.plan.node.source.SeriesScanNode;
import
org.apache.iotdb.db.mpp.plan.planner.plan.parameter.AggregationDescriptor;
import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.FillDescriptor;
+import
org.apache.iotdb.db.mpp.plan.planner.plan.parameter.GroupByLevelDescriptor;
import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.InputLocation;
import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.OutputColumn;
import org.apache.iotdb.db.mpp.plan.statement.component.FillPolicy;
@@ -785,7 +786,42 @@ public class LocalExecutionPlanner {
@Override
public Operator visitGroupByLevel(GroupByLevelNode node,
LocalExecutionPlanContext context) {
- return super.visitGroupByLevel(node, context);
+ checkArgument(
+ node.getGroupByLevelDescriptors().size() >= 1,
+ "GroupByLevel descriptorList cannot be empty");
+ List<Operator> children =
+ node.getChildren().stream()
+ .map(child -> child.accept(this, context))
+ .collect(Collectors.toList());
+ boolean ascending = node.getScanOrder() == OrderBy.TIMESTAMP_ASC;
+ List<Aggregator> aggregators = new ArrayList<>();
+ Map<String, List<InputLocation>> layout = makeLayout(node);
+ for (GroupByLevelDescriptor descriptor :
node.getGroupByLevelDescriptors()) {
+ List<String> inputColumnNames = descriptor.getInputColumnNames();
+ List<InputLocation[]> inputLocationList = new
ArrayList<>(inputColumnNames.size());
+ inputColumnNames.forEach(
+ inputColumnName ->
+ inputLocationList.add(layout.get(inputColumnName).toArray(new
InputLocation[0])));
+
+ aggregators.add(
+ new Aggregator(
+ AccumulatorFactory.createAccumulator(
+ descriptor.getAggregationType(),
+ context
+ .getTypeProvider()
+ // get the type of first inputExpression
+
.getType(descriptor.getInputExpressions().get(0).toString()),
+ ascending),
+ descriptor.getStep(),
+ inputLocationList));
+ }
+ OperatorContext operatorContext =
+ context.instanceContext.addOperatorContext(
+ context.getNextOperatorId(),
+ node.getPlanNodeId(),
+ AggregationOperator.class.getSimpleName());
+ return new AggregationOperator(
+ operatorContext, aggregators, children, ascending,
node.getGroupByTimeParameter());
}
@Override
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/ExchangeNodeAdder.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/ExchangeNodeAdder.java
index 6c502c464f..f85931231b 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/ExchangeNodeAdder.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/ExchangeNodeAdder.java
@@ -31,6 +31,8 @@ import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.SchemaQueryM
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.SchemaQueryScanNode;
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.AggregationNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceMergeNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceViewNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.ExchangeNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.GroupByLevelNode;
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.process.LastQueryMergeNode;
@@ -197,6 +199,16 @@ public class ExchangeNodeAdder extends
PlanVisitor<PlanNode, NodeGroupContext> {
return node;
}
+ @Override
+ public PlanNode visitDeviceView(DeviceViewNode node, NodeGroupContext
context) {
+ return processMultiChildNode(node, context);
+ }
+
+ @Override
+ public PlanNode visitDeviceMerge(DeviceMergeNode node, NodeGroupContext
context) {
+ return processMultiChildNode(node, context);
+ }
+
@Override
public PlanNode visitLastQueryMerge(LastQueryMergeNode node,
NodeGroupContext context) {
return processMultiChildNode(node, context);
@@ -263,7 +275,16 @@ public class ExchangeNodeAdder extends
PlanVisitor<PlanNode, NodeGroupContext> {
children.stream()
.collect(
Collectors.groupingBy(
- child ->
context.getNodeDistribution(child.getPlanNodeId()).region,
+ child -> {
+ TRegionReplicaSet region =
+
context.getNodeDistribution(child.getPlanNodeId()).region;
+ if (region == null
+ &&
context.getNodeDistribution(child.getPlanNodeId()).type
+ == NodeDistributionType.SAME_WITH_ALL_CHILDREN) {
+ return
calculateSchemaRegionByChildren(child.getChildren(), context);
+ }
+ return region;
+ },
Collectors.counting()));
// Step 2: return the RegionReplicaSet with max count
return Collections.max(groupByRegion.entrySet(),
Map.Entry.comparingByValue()).getKey();
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/SourceRewriter.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/SourceRewriter.java
index 72c1819c80..903e60d481 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/SourceRewriter.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/distribution/SourceRewriter.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.partition.RegionReplicaSetInfo;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.MPPQueryContext;
import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
import org.apache.iotdb.db.mpp.plan.analyze.Analysis;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
@@ -35,6 +36,8 @@ import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.SchemaQueryM
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.SchemaQueryScanNode;
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.AggregationNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceMergeNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceViewNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.GroupByLevelNode;
import
org.apache.iotdb.db.mpp.plan.planner.plan.node.process.LastQueryMergeNode;
import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.MultiChildNode;
@@ -74,9 +77,91 @@ public class SourceRewriter extends
SimplePlanNodeRewriter<DistributionPlanConte
this.analysis = analysis;
}
- // TODO: (xingtanzjr) implement the method visitDeviceMergeNode()
- public PlanNode visitDeviceMerge(TimeJoinNode node, DistributionPlanContext
context) {
- return null;
+ @Override
+ public PlanNode visitDeviceView(DeviceViewNode node, DistributionPlanContext
context) {
+ checkArgument(
+ node.getDevices().size() == node.getChildren().size(),
+ "size of devices and its children in DeviceViewNode should be same");
+
+ Set<TRegionReplicaSet> relatedDataRegions = new HashSet<>();
+
+ List<DeviceViewSplit> deviceViewSplits = new ArrayList<>();
+ // Step 1: constructs DeviceViewSplit
+ for (int i = 0; i < node.getDevices().size(); i++) {
+ String device = node.getDevices().get(i);
+ PlanNode child = node.getChildren().get(i);
+ List<TRegionReplicaSet> regionReplicaSets =
+ analysis.getPartitionInfo(device, analysis.getGlobalTimeFilter());
+ deviceViewSplits.add(new DeviceViewSplit(device, child,
regionReplicaSets));
+ relatedDataRegions.addAll(regionReplicaSets);
+ }
+
+ DeviceMergeNode deviceMergeNode =
+ new DeviceMergeNode(
+ context.queryContext.getQueryId().genPlanNodeId(),
+ node.getMergeOrders(),
+ node.getDevices());
+
+ // Step 2: Iterate all partition and create DeviceViewNode for each region
+ for (TRegionReplicaSet regionReplicaSet : relatedDataRegions) {
+ List<String> devices = new ArrayList<>();
+ List<PlanNode> children = new ArrayList<>();
+ for (DeviceViewSplit split : deviceViewSplits) {
+ if (split.needDistributeTo(regionReplicaSet)) {
+ devices.add(split.device);
+ children.add(split.buildPlanNodeInRegion(regionReplicaSet,
context.queryContext));
+ }
+ }
+ DeviceViewNode regionDeviceViewNode =
+ new DeviceViewNode(
+ context.queryContext.getQueryId().genPlanNodeId(),
+ node.getMergeOrders(),
+ node.getOutputColumnNames(),
+ node.getDeviceToMeasurementIndexesMap());
+ for (int i = 0; i < devices.size(); i++) {
+ regionDeviceViewNode.addChildDeviceNode(devices.get(i),
children.get(i));
+ }
+ deviceMergeNode.addChild(regionDeviceViewNode);
+ }
+
+ return deviceMergeNode;
+ }
+
+ private static class DeviceViewSplit {
+ protected String device;
+ protected PlanNode root;
+ protected Set<TRegionReplicaSet> dataPartitions;
+
+ protected DeviceViewSplit(
+ String device, PlanNode root, List<TRegionReplicaSet> dataPartitions) {
+ this.device = device;
+ this.root = root;
+ this.dataPartitions = new HashSet<>();
+ this.dataPartitions.addAll(dataPartitions);
+ }
+
+ protected PlanNode buildPlanNodeInRegion(
+ TRegionReplicaSet regionReplicaSet, MPPQueryContext context) {
+ return buildPlanNodeInRegion(this.root, regionReplicaSet, context);
+ }
+
+ protected boolean needDistributeTo(TRegionReplicaSet regionReplicaSet) {
+ return this.dataPartitions.contains(regionReplicaSet);
+ }
+
+ private PlanNode buildPlanNodeInRegion(
+ PlanNode root, TRegionReplicaSet regionReplicaSet, MPPQueryContext
context) {
+ List<PlanNode> children =
+ root.getChildren().stream()
+ .map(child -> buildPlanNodeInRegion(child, regionReplicaSet,
context))
+ .collect(Collectors.toList());
+ PlanNode newRoot = root.cloneWithChildren(children);
+ newRoot.setPlanNodeId(context.getQueryId().genPlanNodeId());
+ if (newRoot instanceof SourceNode) {
+ ((SourceNode) newRoot).setRegionReplicaSet(regionReplicaSet);
+ }
+ return newRoot;
+ }
}
public PlanNode visitDeleteTimeseries(
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceMergeNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceMergeNode.java
index 613277bd67..f10b69a474 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceMergeNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceMergeNode.java
@@ -32,7 +32,7 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-public class DeviceMergeNode extends ProcessNode {
+public class DeviceMergeNode extends MultiChildNode {
// The result output order, which could sort by device and time.
// The size of this list is 2 and the first OrderBy in this list has higher
priority.
@@ -41,8 +41,6 @@ public class DeviceMergeNode extends ProcessNode {
// the list of selected devices
private final List<String> devices;
- private final List<PlanNode> children;
-
public DeviceMergeNode(
PlanNodeId id, List<PlanNode> children, List<OrderBy> mergeOrders,
List<String> devices) {
super(id);
@@ -146,4 +144,9 @@ public class DeviceMergeNode extends ProcessNode {
public int hashCode() {
return Objects.hash(super.hashCode(), mergeOrders, devices, children);
}
+
+ @Override
+ public String toString() {
+ return "DeviceMerge-" + this.getPlanNodeId();
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceViewNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceViewNode.java
index 589e666297..a70252c55d 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceViewNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/DeviceViewNode.java
@@ -40,7 +40,7 @@ import java.util.Objects;
* same between these TsBlocks. If the input TsBlock contains n columns, the
device-based view will
* contain n+1 columns where the new column is Device column.
*/
-public class DeviceViewNode extends ProcessNode {
+public class DeviceViewNode extends MultiChildNode {
// The result output order, which could sort by device and time.
// The size of this list is 2 and the first OrderBy in this list has higher
priority.
@@ -49,9 +49,6 @@ public class DeviceViewNode extends ProcessNode {
// The size devices and children should be the same.
private final List<String> devices = new ArrayList<>();
- // each child node whose output TsBlock contains the data belonged to one
device.
- private final List<PlanNode> children = new ArrayList<>();
-
// Device column and measurement columns in result output
private final List<String> outputColumnNames;
@@ -117,6 +114,10 @@ public class DeviceViewNode extends ProcessNode {
getPlanNodeId(), mergeOrders, outputColumnNames, devices,
deviceToMeasurementIndexesMap);
}
+ public List<OrderBy> getMergeOrders() {
+ return mergeOrders;
+ }
+
@Override
public List<String> getOutputColumnNames() {
return outputColumnNames;
@@ -213,4 +214,9 @@ public class DeviceViewNode extends ProcessNode {
outputColumnNames,
deviceToMeasurementIndexesMap);
}
+
+ @Override
+ public String toString() {
+ return "DeviceView-" + this.getPlanNodeId();
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByLevelNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByLevelNode.java
index 7210bf449e..34c5bc7708 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByLevelNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByLevelNode.java
@@ -161,6 +161,15 @@ public class GroupByLevelNode extends MultiChildNode {
planNodeId, groupByLevelDescriptors, groupByTimeParameter, scanOrder);
}
+ @Nullable
+ public GroupByTimeParameter getGroupByTimeParameter() {
+ return groupByTimeParameter;
+ }
+
+ public OrderBy getScanOrder() {
+ return scanOrder;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/reader/chunk/MemAlignedPageReader.java
b/server/src/main/java/org/apache/iotdb/db/query/reader/chunk/MemAlignedPageReader.java
index a29d20bf12..6b561c4fed 100644
---
a/server/src/main/java/org/apache/iotdb/db/query/reader/chunk/MemAlignedPageReader.java
+++
b/server/src/main/java/org/apache/iotdb/db/query/reader/chunk/MemAlignedPageReader.java
@@ -41,7 +41,6 @@ public class MemAlignedPageReader implements IPageReader,
IAlignedPageReader {
private final TsBlock tsBlock;
private final AlignedChunkMetadata chunkMetadata;
private Filter valueFilter;
-
private TsBlockBuilder builder;
public MemAlignedPageReader(TsBlock tsBlock, AlignedChunkMetadata
chunkMetadata, Filter filter) {
diff --git
a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/distribution/AlignedByDeviceTest.java
b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/distribution/AlignedByDeviceTest.java
new file mode 100644
index 0000000000..af64fc39bb
--- /dev/null
+++
b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/distribution/AlignedByDeviceTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.iotdb.db.mpp.plan.plan.distribution;
+
+import org.apache.iotdb.db.mpp.plan.planner.plan.LogicalQueryPlan;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class AlignedByDeviceTest {
+
+ @Test
+ public void test1Device1Region() {}
+
+ private LogicalQueryPlan constructLogicalPlan(List<String> series) {
+ return null;
+ }
+}