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

haonan pushed a commit to branch rel/0.12
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/0.12 by this push:
     new ef07268  [ISSUE-3945] Fuzzy query support multiDevices and 
alignByDevice Dataset (#3953)
ef07268 is described below

commit ef07268f5fde837a0ecb68fb1e4bc9afd6c8ee2f
Author: Hang Ji <[email protected]>
AuthorDate: Tue Sep 14 15:24:27 2021 +0800

    [ISSUE-3945] Fuzzy query support multiDevices and alignByDevice Dataset 
(#3953)
---
 .../iotdb/db/qp/logical/crud/LikeOperator.java     |   4 +
 .../iotdb/db/qp/logical/crud/RegexpOperator.java   |   4 +
 .../iotdb/db/qp/strategy/PhysicalGenerator.java    |  19 +++-
 .../qp/strategy/optimizer/ConcatPathOptimizer.java |  34 ++++--
 .../{IoTDBLikeIT.java => IoTDBFuzzyQueryIT.java}   | 125 ++++++++++++++++++++-
 5 files changed, 173 insertions(+), 13 deletions(-)

diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
index 0ac51bc..adc8dc0 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
@@ -123,4 +123,8 @@ public class LikeOperator extends FunctionOperator {
   public String toString() {
     return "[" + singlePath.getFullPath() + tokenSymbol + value + "]";
   }
+
+  public String getValue() {
+    return value;
+  }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
index 9703aae..8073eb1 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
@@ -123,4 +123,8 @@ public class RegexpOperator extends FunctionOperator {
   public String toString() {
     return "[" + singlePath.getFullPath() + value + "]";
   }
+
+  public String getValue() {
+    return value;
+  }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
index cdaba7e..8802493 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
@@ -35,7 +35,9 @@ import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
 import org.apache.iotdb.db.qp.logical.crud.FunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.InOperator;
 import org.apache.iotdb.db.qp.logical.crud.InsertOperator;
+import org.apache.iotdb.db.qp.logical.crud.LikeOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.RegexpOperator;
 import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator;
 import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
 import org.apache.iotdb.db.qp.logical.sys.CountOperator;
@@ -843,10 +845,19 @@ public class PhysicalGenerator {
     }
 
     FunctionOperator basicOperator;
-    if (operator instanceof InOperator) {
-      basicOperator = (InOperator) operator;
-    } else {
-      basicOperator = (BasicFunctionOperator) operator;
+    switch (operator.getType()) {
+      case IN:
+        basicOperator = (InOperator) operator;
+        break;
+      case LIKE:
+        basicOperator = (LikeOperator) operator;
+        break;
+      case REGEXP:
+        basicOperator = (RegexpOperator) operator;
+        break;
+      default:
+        basicOperator = (BasicFunctionOperator) operator;
+        break;
     }
 
     PartialPath filterPath = basicOperator.getSinglePath();
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
index d07292e..0a03ea6 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
@@ -31,7 +31,9 @@ import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
 import org.apache.iotdb.db.qp.logical.crud.FromOperator;
 import org.apache.iotdb.db.qp.logical.crud.FunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.InOperator;
+import org.apache.iotdb.db.qp.logical.crud.LikeOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.RegexpOperator;
 import org.apache.iotdb.db.qp.logical.crud.SFWOperator;
 import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
 import org.apache.iotdb.db.query.udf.core.context.UDFContext;
@@ -292,23 +294,39 @@ public class ConcatPathOptimizer implements 
ILogicalOptimizer {
         currentNode.addChildOperator(newInnerNode);
         currentNode = newInnerNode;
       }
-      try {
-        if (operator instanceof InOperator) {
+      switch (operator.getType()) {
+        case IN:
           currentNode.addChildOperator(
               new InOperator(
                   operator.getTokenIntType(),
                   noStarPaths.get(i),
                   ((InOperator) operator).getNot(),
                   ((InOperator) operator).getValues()));
-        } else {
+          break;
+        case LIKE:
           currentNode.addChildOperator(
-              new BasicFunctionOperator(
+              new LikeOperator(
                   operator.getTokenIntType(),
                   noStarPaths.get(i),
-                  ((BasicFunctionOperator) operator).getValue()));
-        }
-      } catch (SQLParserException e) {
-        throw new LogicalOptimizeException(e.getMessage());
+                  ((LikeOperator) operator).getValue()));
+          break;
+        case REGEXP:
+          currentNode.addChildOperator(
+              new RegexpOperator(
+                  operator.getTokenIntType(),
+                  noStarPaths.get(i),
+                  ((RegexpOperator) operator).getValue()));
+          break;
+        default:
+          try {
+            currentNode.addChildOperator(
+                new BasicFunctionOperator(
+                    operator.getTokenIntType(),
+                    noStarPaths.get(i),
+                    ((BasicFunctionOperator) operator).getValue()));
+          } catch (SQLParserException e) {
+            throw new LogicalOptimizeException(e.getMessage());
+          }
       }
     }
     return filterBinaryTree;
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLikeIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
similarity index 57%
rename from 
server/src/test/java/org/apache/iotdb/db/integration/IoTDBLikeIT.java
rename to 
server/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
index 030397e..d7d33d2 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLikeIT.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
@@ -30,13 +30,19 @@ import org.junit.Test;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.Types;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
-public class IoTDBLikeIT {
+import static org.junit.Assert.fail;
+
+public class IoTDBFuzzyQueryIT {
   private static List<String> sqls = new ArrayList<>();
   private static Connection connection;
 
@@ -68,6 +74,8 @@ public class IoTDBLikeIT {
     sqls.add("SET STORAGE GROUP TO root.t1");
     sqls.add("CREATE TIMESERIES root.t1.wf01.wt01.status WITH DATATYPE=TEXT, 
ENCODING=PLAIN");
     sqls.add("CREATE TIMESERIES root.t1.wf01.wt01.temperature WITH 
DATATYPE=FLOAT, ENCODING=RLE");
+    sqls.add("CREATE TIMESERIES root.t1.wf01.wt02.status WITH DATATYPE=TEXT, 
ENCODING=PLAIN");
+
     sqls.add(
         "insert into root.t1.wf01.wt01 (time,status,temperature) values 
(1509465600000,'1',12.1)");
     sqls.add(
@@ -88,6 +96,7 @@ public class IoTDBLikeIT {
         "insert into root.t1.wf01.wt01 (time,status,temperature) values 
(1509466080000,'123%',18.3)");
     sqls.add(
         "insert into root.t1.wf01.wt01 (time,status,temperature) values 
(1509466090000,'\\',10.3)");
+    sqls.add("insert into root.t1.wf01.wt02 (time,status) values 
(1509465600000,'14')");
   }
 
   private static void insertData() throws ClassNotFoundException, SQLException 
{
@@ -166,4 +175,118 @@ public class IoTDBLikeIT {
     String result = resultBuilder.toString();
     return result.substring(0, result.length() - 1);
   }
+
+  private List<Integer> checkHeader(
+      ResultSetMetaData resultSetMetaData, String expectedHeaderStrings, int[] 
expectedTypes)
+      throws SQLException {
+    String[] expectedHeaders = expectedHeaderStrings.split(",");
+    Map<String, Integer> expectedHeaderToTypeIndexMap = new HashMap<>();
+    for (int i = 0; i < expectedHeaders.length; ++i) {
+      expectedHeaderToTypeIndexMap.put(expectedHeaders[i], i);
+    }
+
+    List<Integer> actualIndexToExpectedIndexList = new ArrayList<>();
+    for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+      Integer typeIndex = 
expectedHeaderToTypeIndexMap.get(resultSetMetaData.getColumnName(i));
+      Assert.assertNotNull(typeIndex);
+      Assert.assertEquals(expectedTypes[typeIndex], 
resultSetMetaData.getColumnType(i));
+      actualIndexToExpectedIndexList.add(typeIndex);
+    }
+    return actualIndexToExpectedIndexList;
+  }
+
+  @Test
+  public void selectLikeAlignByDevice() throws ClassNotFoundException {
+    String[] retArray =
+        new String[] {"1509465660000,root.t1.wf01.wt01,14,", 
"1509465600000,root.t1.wf01.wt02,14"};
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection =
+            DriverManager.getConnection(
+                Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet =
+          statement.execute(
+              "select status from root.t1.wf01.wt0* where status like '14%' 
align by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "Time,Device,status,",
+                new int[] {Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR});
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            actualBuilder.append(resultSet.getString(i)).append(",");
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 
1)])
+                .append(",");
+          }
+          Assert.assertEquals(expectedBuilder.toString(), 
actualBuilder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectRegexpAlignByDevice() throws ClassNotFoundException {
+    String[] retArray =
+        new String[] {
+          "1509465600000,root.t1.wf01.wt01,1,",
+          "1509465660000,root.t1.wf01.wt01,14,",
+          "1509466080000,root.t1.wf01.wt01,123%,",
+          "1509465600000,root.t1.wf01.wt02,14,"
+        };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection =
+            DriverManager.getConnection(
+                Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet =
+          statement.execute(
+              "select status from root.t1.wf01.wt0* where status regexp '^1.*' 
align by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "Time,Device,status,",
+                new int[] {Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR});
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            actualBuilder.append(resultSet.getString(i)).append(",");
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 
1)])
+                .append(",");
+          }
+          Assert.assertEquals(expectedBuilder.toString(), 
actualBuilder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(4, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
 }

Reply via email to