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());
+ }
+ }
}