You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by xu...@apache.org on 2020/02/27 03:30:18 UTC

[incubator-iotdb] branch new_series_reader updated: [IOTDB-476] Improve the ExpressionOptimizer (#841)

This is an automated email from the ASF dual-hosted git repository.

xuekaifeng pushed a commit to branch new_series_reader
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/new_series_reader by this push:
     new 9bc8ec5  [IOTDB-476] Improve the ExpressionOptimizer (#841)
9bc8ec5 is described below

commit 9bc8ec562e9e9241d7e4e847e850295c0364c0a9
Author: Ring-k <36...@users.noreply.github.com>
AuthorDate: Thu Feb 27 11:30:08 2020 +0800

    [IOTDB-476] Improve the ExpressionOptimizer (#841)
    
    * optimize expression
    
    * google code style
    
    * remove temp test
    
    * change if else statement
    
    * update test
---
 .../read/expression/util/ExpressionOptimizer.java  | 59 ++++++++++++++++++++--
 .../read/filter/IExpressionOptimizerTest.java      | 16 +++---
 2 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/expression/util/ExpressionOptimizer.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/expression/util/ExpressionOptimizer.java
index da83d1b..e8b0eb8 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/expression/util/ExpressionOptimizer.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/expression/util/ExpressionOptimizer.java
@@ -45,7 +45,7 @@ public class ExpressionOptimizer {
   /**
    * try to remove GlobalTimeExpression.
    *
-   * @param expression IExpression to be transferred
+   * @param expression     IExpression to be transferred
    * @param selectedSeries selected series
    * @return an executable query filter, whether a GlobalTimeExpression or All leaf nodes are
    * SingleSeriesExpression
@@ -108,14 +108,65 @@ public class ExpressionOptimizer {
       addTimeFilterToQueryFilter((globalTimeExpression).getFilter(), regularRightIExpression);
       return regularRightIExpression;
     } else if (relation == ExpressionType.OR) {
-      return BinaryExpression
-          .or(pushGlobalTimeFilterToAllSeries(globalTimeExpression, selectedSeries),
-              regularRightIExpression);
+      IExpression afterTransform = pushGlobalTimeFilterToAllSeries(globalTimeExpression,
+          selectedSeries);
+      return mergeSecondTreeToFirstTree(afterTransform, regularRightIExpression);
     }
     throw new QueryFilterOptimizationException("unknown relation in IExpression:" + relation);
   }
 
   /**
+   * This method merge the second input, which is of tree structure, to the first parameter. It
+   * visits all leaf nodes, which are SingleSeriesExpressions, or AndExpression in right Expression,
+   * merge them to the right position in leftExpression.
+   *
+   * @param leftExpression  The IExpression transformed from GlobalTimeExpression, which might have
+   *                        already be updated and merged.
+   * @param rightExpression The IExpression to be merged into the first IExpression
+   * @return a merged IExpression, which is initially based on the input leftExpression
+   */
+  private IExpression mergeSecondTreeToFirstTree(IExpression leftExpression,
+      IExpression rightExpression) {
+    if (rightExpression.getType() == ExpressionType.SERIES) {
+      SingleSeriesExpression leaf = (SingleSeriesExpression) rightExpression;
+      updateFilterWithOr(leftExpression, leaf.getFilter(), leaf.getSeriesPath());
+      return leftExpression;
+    } else if (rightExpression.getType() == ExpressionType.OR) {
+      IExpression leftChild = ((BinaryExpression) rightExpression).getLeft();
+      IExpression rightChild = ((BinaryExpression) rightExpression).getRight();
+      leftExpression = mergeSecondTreeToFirstTree(leftExpression, leftChild);
+      leftExpression = mergeSecondTreeToFirstTree(leftExpression, rightChild);
+      return leftExpression;
+    } else {
+      return BinaryExpression.or(leftExpression, rightExpression);
+    }
+  }
+
+  /**
+   * This method search  the node in the input expression, whose path is identical to the input
+   * path, then merges its filter and the input filter with relation OR.
+   *
+   * @return true if the input filter is merged.
+   */
+  private boolean updateFilterWithOr(IExpression expression, Filter filter, Path path) {
+    if (expression.getType() == ExpressionType.SERIES && ((SingleSeriesExpression) expression)
+        .getSeriesPath().equals(path)) {
+      Filter nodeFilter = ((SingleSeriesExpression) expression).getFilter();
+      nodeFilter = FilterFactory.or(nodeFilter, filter);
+      ((SingleSeriesExpression) expression).setFilter(nodeFilter);
+      return true;
+    } else if (expression.getType() == ExpressionType.OR) {
+      assert expression instanceof BinaryExpression;
+      IExpression left = ((BinaryExpression) expression).getLeft();
+      IExpression right = ((BinaryExpression) expression).getRight();
+      return updateFilterWithOr(left, filter, path) || updateFilterWithOr(right, filter, path);
+    } else {
+      return false;
+    }
+  }
+
+
+  /**
    * Combine GlobalTimeExpression with all selected series. example: input:
    * GlobalTimeExpression(timeFilter) Selected Series: path1, path2, path3 output: QueryFilterOR(
    * QueryFilterOR( SingleSeriesExpression(path1, timeFilter), SingleSeriesExpression(path2,
diff --git a/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/IExpressionOptimizerTest.java b/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/IExpressionOptimizerTest.java
index 8bf416d..c64afe2 100644
--- a/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/IExpressionOptimizerTest.java
+++ b/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/IExpressionOptimizerTest.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.tsfile.read.filter;
 
 import java.util.ArrayList;
 import java.util.List;
+
 import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
 import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.expression.IExpression;
@@ -143,7 +144,7 @@ public class IExpressionOptimizerTest {
         .or(BinaryExpression.and(singleSeriesExp1, globalTimeFilter),
             globalTimeFilter2);
     try {
-      String rightRet = "[[[[[d1.s1:time > 1] || [d2.s1:time > 1]] || [d1.s2:time > 1]] || [d2.s2:time > 1]] || [d2.s1:((value > 100 || value < 50) && time < 14001234)]]";
+      String rightRet = "[[[[d1.s1:time > 1] || [d2.s1:(time > 1 || ((value > 100 || value < 50) && time < 14001234))]] || [d1.s2:time > 1]] || [d2.s2:time > 1]]";
       IExpression regularFilter = expressionOptimizer.optimize(expression, selectedSeries);
       Assert.assertEquals(rightRet, regularFilter.toString());
     } catch (QueryFilterOptimizationException e) {
@@ -189,8 +190,10 @@ public class IExpressionOptimizerTest {
 
     try {
       String rightRet =
-          "[[[[[d1.s1:time < 14001234] || [d2.s1:time < 14001234]] || [d1.s2:time < 14001234]] "
-              + "|| [d2.s2:time < 14001234]] || [[d2.s1:(value > 100 || value < 50)] || [d1.s2:(value > 100.5 || value < 50.6)]]]";
+          "[[[[d1.s1:time < 14001234] "
+              + "|| [d2.s1:(time < 14001234 || (value > 100 || value < 50))]] "
+              + "|| [d1.s2:(time < 14001234 || (value > 100.5 || value < 50.6))]] "
+              + "|| [d2.s2:time < 14001234]]";
       IExpression regularFilter = expressionOptimizer.optimize(expression, selectedSeries);
       Assert.assertEquals(rightRet, regularFilter.toString());
     } catch (QueryFilterOptimizationException e) {
@@ -216,9 +219,10 @@ public class IExpressionOptimizerTest {
 
     try {
       String rightRet =
-          "[[[[[d1.s1:(time < 14001234 && time > 14001000)] || [d2.s1:(time < 14001234 "
-              + "&& time > 14001000)]] || [d1.s2:(time < 14001234 && time > 14001000)]] || [d2.s2:(time < 14001234 "
-              + "&& time > 14001000)]] || [[d2.s1:(value > 100 || value < 50)] || [d1.s2:(value > 100.5 || value < 50.6)]]]";
+          "[[[[d1.s1:(time < 14001234 && time > 14001000)] "
+              + "|| [d2.s1:((time < 14001234 && time > 14001000) || (value > 100 || value < 50))]] "
+              + "|| [d1.s2:((time < 14001234 && time > 14001000) || (value > 100.5 || value < 50.6))]] "
+              + "|| [d2.s2:(time < 14001234 && time > 14001000)]]";
       IExpression regularFilter = expressionOptimizer.optimize(expression, selectedSeries);
       Assert.assertEquals(rightRet, regularFilter.toString());
     } catch (QueryFilterOptimizationException e) {