This is an automated email from the ASF dual-hosted git repository.
qiaojialin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 0391873 optimize tsfile expression
new 9b943d2 Merge pull request #894 from Ring-k/master
0391873 is described below
commit 0391873f8eadd8af56cf3dbb246a1595d6aa0aae
Author: Ring-k <[email protected]>
AuthorDate: Sun Mar 8 22:33:12 2020 +0800
optimize tsfile expression
---
.../SystemDesign/1-TsFile/4-Read.md | 4 +-
docs/Documentation/SystemDesign/1-TsFile/4-Read.md | 8 +--
.../read/expression/util/ExpressionOptimizer.java | 58 ++++++++++++++++++++--
.../read/filter/IExpressionOptimizerTest.java | 15 +++---
4 files changed, 69 insertions(+), 16 deletions(-)
diff --git a/docs/Documentation-CHN/SystemDesign/1-TsFile/4-Read.md
b/docs/Documentation-CHN/SystemDesign/1-TsFile/4-Read.md
index 1fde5ac..55450ab 100644
--- a/docs/Documentation-CHN/SystemDesign/1-TsFile/4-Read.md
+++ b/docs/Documentation-CHN/SystemDesign/1-TsFile/4-Read.md
@@ -384,8 +384,8 @@ IExpression 为查询过滤条件。一个 IExpression 可以是一个 SingleSer
*情况二*:GlobalTimeExpression 和 IExpression 的关系为 OR。该情况下的合并步骤如下:
1. 得到该查询所要投影的所有时间序列,其为一个 Path 的集合,以一个包含三个投影时间序列的查询为例,记所有要投影的列为
PathList{path1, path2, path3}。
- 2. 记 GlobalTimeExpression 的 Filter 为 tFilter,调用
pushGlobalTimeFilterToAllSeries() 方法为每个 Path 创建一个对应的 SingleSeriesExpression,且每个
SingleSeriesExpression 的 Filter 值均为 tFilter;将所有新创建的 SingleSeriesExpression 用 OR
运算符进行连接,得到一个 OrExpression,记其为 orExpression
- 3. 将步骤二得到的 orExpression 与 IExpression 按照关系 OR 进行合并,得到最终的结果。
+ 2. 记 GlobalTimeExpression 的 Filter 为 tFilter,调用
pushGlobalTimeFilterToAllSeries() 方法为每个 Path 创建一个对应的 SingleSeriesExpression,且每个
SingleSeriesExpression 的 Filter 值均为 tFilter;将所有新创建的 SingleSeriesExpression 用 OR
运算符进行连接,得到一个 OrExpression,记其为 orExpression。
+ 3. 调用 mergeSecondTreeToFirstTree 方法将 IExpression 中的节点与步骤二得到的 orExpression
中的节点进行合并,返回合并后的表达式。
例如,将如下 GlobaLTimeFilter 和 IExpression 按照关系 OR 进行合并,设该查询的被投影列为
PathList{path1, path2, path3}
diff --git a/docs/Documentation/SystemDesign/1-TsFile/4-Read.md
b/docs/Documentation/SystemDesign/1-TsFile/4-Read.md
index 3c3b710..59569f8 100644
--- a/docs/Documentation/SystemDesign/1-TsFile/4-Read.md
+++ b/docs/Documentation/SystemDesign/1-TsFile/4-Read.md
@@ -384,11 +384,11 @@ Before the introducing the optimize() method in detail,
we first show how to com
*Case 2*: The relation between GlobalTimeExpression and IExpression is OR.
In this case, the merge steps include:
1. Analyse the projected time series, which is a set of Path. To take a
query with 3 projected time series as an example, denote that projected time
series as a set, PathList{path1, path2, path3}。
2. Denote the Filter in GlobalTimeExpression to be tFilter. The method
calls pushGlobalTimeFilterToAllSeries() to generate a corresponding
SingleSeriesExpression for each Path. Set the Filters of
SingleSeriesExpressions to be tFilter. Join the generated
SingleSeriesExpression with OR operator to get an OrExpression, which is
denoted as orExpression.
- 3. Combine the result of step 2, the orExpression, and the IExpression
with OR operation, to generate the final result.
-
- For example, to combine the following GlobaLTimeFilter and IExpression
using OR relation, denote the projected time series as PathList{path1, path2,
path3}
+ 3. Call mergeSecondTreeToFirstTree method to combine the nodes in
IExpression with the nodes in the orExpression, which is generated from step 2.
The combined structure is the result expression.
+
+ For example, to combine the following GlobalTimeFilter and IExpression
using OR relation, denote the projected time series as PathList{path1, path2,
path3}
- 1. GlobaLTimeFilter(tFilter)
+ 1. GlobalTimeFilter(tFilter)
2. IExpression
AndExpression
SingleSeriesExpression("path1", filter1)
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..85af26c 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,64 @@ 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..d340b18 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
@@ -143,7 +143,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 +189,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 +218,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) {