未验证 提交 393a91f4 编写于 作者: X Xiangwei Wei 提交者: GitHub

[New feature] Add the alias and show it as column name when querying (#1621)

上级 11323fe2
......@@ -103,8 +103,9 @@ statement
selectElements
: functionCall (COMMA functionCall)* #functionElement
| suffixPath (COMMA suffixPath)* #selectElement
| stringLiteral (COMMA stringLiteral)* #selectConstElement
| lastClause #lastElement
| asClause (COMMA asClause)* #asElement
| functionAsClause (COMMA functionAsClause)* #functionAsElement
;
functionCall
......@@ -123,8 +124,17 @@ functionName
| LAST_VALUE
;
functionAsClause
: functionCall (AS ID)?
;
lastClause
: LAST suffixPath (COMMA suffixPath)*
| LAST asClause (COMMA asClause)*
;
asClause
: suffixPath (AS ID)?
;
alias
......@@ -1056,6 +1066,10 @@ COMPRESSION
: C O M P R E S S I O N
;
AS
: A S
;
TIME
: T I M E
;
......
......@@ -704,6 +704,22 @@ The result is shown below:
<center><img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/13203019/51577879-64984680-1ef6-11e9-9d7b-57dd60fab60e.jpg"></center>
### Use Alias
Since the unique data model of IoTDB, lots of additional information like device will be carried before each sensor. Sometimes, we want to query just one specific device, then these prefix information show frequently will be redundant in this situation, influencing the analysis of result set. At this time, we can use `AS` function provided by IoTDB, assign an alias to time series selected in query.
For example:
```
select s1 as temperature, s2 as speed from root.ln.wf01.wt01;
```
The result set will be like:
| Time | temperature | speed |
| ---- | ----------- | ----- |
| ... | ... | ... |
#### Other ResultSet Format
In addition, IoTDB supports two another resultset format: 'align by device' and 'disable align'.
......@@ -713,7 +729,7 @@ The 'align by device' indicates that the deviceId is considered as a column. The
The SQL statement is:
```
select s1,s2 from root.sg1.* GROUP BY DEVICE
select s1,s2 from root.sg1.* ALIGN BY DEVICE
```
For more syntax description, please read SQL REFERENCE.
......
......@@ -614,6 +614,53 @@ For example, "select last s1, s2 from root.sg.d1, root.sg.d2", the query result
```
* As Statement
As statement assigns an alias to time seires queried in SELECT statement
```
You can use as statement in all query type.
1. Raw data query
select s1 as speed, s2 as temperature from root.sg.d1
The result set will be like:
| Time | speed | temperature |
| ... | ... | .... |
2. Aggregation query
select count(s1) as s1_num, max_value(s2) as s2_max from root.sg.d1
3. Down-frequence query
select count(s1) as s1_num from root.sg.d1 group by ([100,500), 80ms)
4. Align by device query
select s1 as speed, s2 as temperature from root.sg.d1 align by device
select count(s1) as s1_num, count(s2), count(s3) as s3_num from root.sg.d2 align by device
5. Last query
select last s1 as speed, s2 from root.sg.d1
Rules:
1. In addition to Align by device query,each AS statement has to corresponding to one time series exactly.
E.g. select s1 as temperature from root.sg.*
At this time if `root.sg.*` includes more than one device,then an exception will be thrown。
2. In align by device query,the prefix path that each AS statement corresponding to can includes multiple device, but the suffix path can only be single sensor.
E.g. select s1 as temperature from root.sg.*
In this situation, it will be show correctly even if multiple devices are selected.
E.g. select * as temperature from root.sg.d1
In this situation, it will throws an exception if * corresponds to multiple sensors.
```
## Database Management Statement
* Create User
......
......@@ -753,6 +753,22 @@ select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0
<center><img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/13203019/51577879-64984680-1ef6-11e9-9d7b-57dd60fab60e.jpg"></center>
### 使用别名
由于 IoTDB 独特的数据模型,在每个传感器前都附带有设备等诸多额外信息。有时,我们只针对某个具体设备查询,而这些前缀信息频繁显示造成了冗余,影响了结果集的显示与分析。这时我们可以使用 IoTDB 提供的 AS 函数,将查询中出现的时间序列给定一个别名。
例如:
```
select s1 as temperature, s2 as speed from root.ln.wf01.wt01;
```
则结果集将显示为:
| Time | temperature | speed |
| ---- | ----------- | ----- |
| ... | ... | ... |
#### 其他结果集格式
此外,IoTDB支持两种其他结果集格式:“按设备对齐”和“禁用对齐”。
......@@ -762,7 +778,7 @@ select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0
SQL语句是:
```
select s1,s2 from root.sg1.* GROUP BY DEVICE
select s1,s2 from root.sg1.* ALIGN BY DEVICE
```
......
......@@ -603,6 +603,53 @@ Eg. SELECT LAST s1 FROM root.sg.d1, root.sg.d2
```
* As 语句
As 语句为 SELECT 语句中出现的时间序列规定一个别名
```
在每个查询中都可以使用 As 语句来规定时间序列的别名。
1. 原始数据查询:
select s1 as speed, s2 as temperature from root.sg.d1
结果集将显示为:
| Time | speed | temperature |
| ... | ... | .... |
2. 聚合查询
select count(s1) as s1_num, max_value(s2) as s2_max from root.sg.d1
3. 降频聚合查询
select count(s1) as s1_num from root.sg.d1 group by ([100,500), 80ms)
4. 按设备对齐查询
select s1 as speed, s2 as temperature from root.sg.d1 align by device
select count(s1) as s1_num, count(s2), count(s3) as s3_num from root.sg.d2 align by device
5. Last 查询
select last s1 as speed, s2 from root.sg.d1
规则:
1. 除按设备对齐查询外,每一个 AS 语句必须唯一对应一个时间序列。
E.g. select s1 as temperature from root.sg.*
此时如果存储组 root.sg.* 中含有多个设备,则会抛出异常。
2. 按设备对齐查询中,每个 AS 语句对应的前缀路径可以含多个设备,而后缀路径不能含多个传感器。
E.g. select s1 as temperature from root.sg.*
这种情况即使有多个设备,也可以正常显示。
E.g. select * as temperature from root.sg.d1
这种情况如果 * 匹配多个传感器,则无法正常显示。
```
## 数据库管理语句
* 创建用户
......
......@@ -585,7 +585,7 @@ public class MTree implements Serializable {
List<PartialPath> paths = new ArrayList<>();
for (Pair<PartialPath, String[]> p : res) {
if (prePath.getMeasurement().equals(p.right[0])) {
p.left.setAlias(p.right[0]);
p.left.setMeasurementAlias(p.right[0]);
}
paths.add(p.left);
}
......
......@@ -31,7 +31,10 @@ import org.apache.iotdb.tsfile.read.common.Path;
public class PartialPath extends Path implements Comparable<Path> {
private String[] nodes;
private String alias;
// alias of measurement
private String measurementAlias = null;
// alias of time series used in SELECT AS
private String tsAlias = null;
public PartialPath(String path) throws IllegalPathException {
this.nodes = MetaUtils.splitPathToDetachedPath(path);
......@@ -144,13 +147,23 @@ public class PartialPath extends Path implements Comparable<Path> {
}
}
public void setAlias(String alias) {
this.alias = alias;
public String getMeasurementAlias() {
return measurementAlias;
}
public void setMeasurementAlias(String measurementAlias) { this.measurementAlias = measurementAlias; }
public String getTsAlias() {
return tsAlias;
}
public void setTsAlias(String tsAlias) {
this.tsAlias = tsAlias;
}
@Override
public String getFullPathWithAlias() {
return getDevice() + IoTDBConstant.PATH_SEPARATOR + alias;
return getDevice() + IoTDBConstant.PATH_SEPARATOR + measurementAlias;
}
@Override
......@@ -159,10 +172,6 @@ public class PartialPath extends Path implements Comparable<Path> {
return this.getFullPath().compareTo(partialPath.getFullPath());
}
public String getAlias() {
return alias;
}
public boolean startsWith(String[] otherNodes) {
for (int i = 0; i < otherNodes.length; i++) {
if (!nodes[i].equals(otherNodes[i])) {
......
......@@ -29,6 +29,7 @@ import org.apache.iotdb.tsfile.read.expression.IExpression;
public class AlignByDevicePlan extends QueryPlan {
private List<String> measurements; // to record result measurement columns, e.g. temperature, status, speed
private Map<String, String> measurementAliasMap; // select s1, s2 as speed from root, then s2 -> speed
// to check data type consistency for the same name sensor of different devices
private List<PartialPath> devices;
// to record the datatype of the column in the result set
......@@ -57,6 +58,15 @@ public class AlignByDevicePlan extends QueryPlan {
return measurements;
}
public void setMeasurementAliasMap(
Map<String, String> measurementAliasMap) {
this.measurementAliasMap = measurementAliasMap;
}
public Map<String, String> getMeasurementAliasMap() {
return measurementAliasMap;
}
public void setDevices(List<PartialPath> devices) {
this.devices = devices;
}
......
......@@ -78,6 +78,8 @@ import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AliasContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AlignByDeviceClauseContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AlterUserContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AndExpressionContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AsClauseContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AsElementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AttributeClauseContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.AttributeClausesContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.ConstantContext;
......@@ -99,6 +101,8 @@ import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FlushContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FromClauseContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FullMergeContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FullPathContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FunctionAsClauseContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FunctionAsElementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FunctionCallContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.FunctionElementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.GrantRoleContext;
......@@ -140,7 +144,6 @@ import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeRoleFromUserContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeUserContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeWatermarkEmbeddingContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RootOrIdContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectConstElementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectElementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectStatementContext;
import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SetColContext;
......@@ -1227,14 +1230,6 @@ public class LogicalGenerator extends SqlBaseBaseListener {
initializedOperator = queryOp;
}
@Override
public void enterSelectConstElement(SelectConstElementContext ctx) {
super.enterSelectConstElement(ctx);
operatorType = SQLConstant.TOK_QUERY;
queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
initializedOperator = queryOp;
}
@Override
public void enterFromClause(FromClauseContext ctx) {
super.enterFromClause(ctx);
......@@ -1277,11 +1272,49 @@ public class LogicalGenerator extends SqlBaseBaseListener {
selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
selectOp.setLastQuery();
LastClauseContext lastClauseContext = ctx.lastClause();
List<SuffixPathContext> suffixPaths = lastClauseContext.suffixPath();
for (SuffixPathContext suffixPath : suffixPaths) {
PartialPath path = parseSuffixPath(suffixPath);
if (lastClauseContext.asClause().size() != 0) {
parseAsClause(lastClauseContext.asClause());
} else {
List<SuffixPathContext> suffixPaths = lastClauseContext.suffixPath();
for (SuffixPathContext suffixPath : suffixPaths) {
PartialPath path = parseSuffixPath(suffixPath);
selectOp.addSelectPath(path);
}
}
queryOp.setSelectOperator(selectOp);
}
@Override
public void enterAsElement(AsElementContext ctx) {
super.enterAsElement(ctx);
selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
parseAsClause(ctx.asClause());
queryOp.setSelectOperator(selectOp);
}
public void parseAsClause(List<AsClauseContext> asClauseContexts) {
for (AsClauseContext asClauseContext : asClauseContexts) {
PartialPath path = parseSuffixPath(asClauseContext.suffixPath());
if (asClauseContext.ID() != null) {
path.setTsAlias(asClauseContext.ID().toString());
}
selectOp.addSelectPath(path);
}
}
@Override
public void enterFunctionAsElement(FunctionAsElementContext ctx) {
super.enterFunctionAsElement(ctx);
selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
List<FunctionAsClauseContext> functionAsClauseContexts = ctx.functionAsClause();
for (FunctionAsClauseContext functionAsClauseContext : functionAsClauseContexts) {
FunctionCallContext functionCallContext = functionAsClauseContext.functionCall();
PartialPath path = parseSuffixPath(functionCallContext.suffixPath());
if (functionAsClauseContext.ID() != null) {
path.setTsAlias(functionAsClauseContext.ID().toString());
}
selectOp.addClusterPath(path, functionCallContext.functionName().getText());
}
queryOp.setSelectOperator(selectOp);
}
......
......@@ -422,6 +422,7 @@ public class PhysicalGenerator {
// to record result measurement columns
List<String> measurements = new ArrayList<>();
Map<String, String> measurementAliasMap = new HashMap<>();
// to check the same measurement of different devices having the same datatype
// record the data type of each column of result set
Map<String, TSDataType> columnDataTypeMap = new HashMap<>();
......@@ -450,6 +451,20 @@ public class PhysicalGenerator {
try {
// remove stars in SELECT to get actual paths
List<PartialPath> actualPaths = getMatchedTimeseries(fullPath);
if (suffixPath.getTsAlias() != null) {
if (actualPaths.size() == 1) {
String columnName = actualPaths.get(0).getMeasurement();
if (originAggregations != null && !originAggregations.isEmpty()) {
measurementAliasMap.put(originAggregations.get(i) + "(" + columnName + ")", suffixPath.getTsAlias());
} else {
measurementAliasMap.put(columnName, suffixPath.getTsAlias());
}
} else if (actualPaths.size() >= 2) {
throw new QueryProcessException(
"alias '" + suffixPath.getTsAlias() + "' can only be matched with one time series");
}
}
// for actual non exist path
if (originAggregations != null && actualPaths.isEmpty() && originAggregations
.isEmpty()) {
......@@ -506,6 +521,7 @@ public class PhysicalGenerator {
|| measurementTypeMap.get(measurementChecked) != MeasurementType.Exist) {
measurementTypeMap.put(measurementChecked, MeasurementType.Exist);
}
// update paths
paths.add(path);
}
......@@ -537,6 +553,7 @@ public class PhysicalGenerator {
// assigns to alignByDevicePlan
alignByDevicePlan.setMeasurements(measurements);
alignByDevicePlan.setMeasurementAliasMap(measurementAliasMap);
alignByDevicePlan.setDevices(devices);
alignByDevicePlan.setColumnDataTypeMap(columnDataTypeMap);
alignByDevicePlan.setMeasurementTypeMap(measurementTypeMap);
......@@ -668,11 +685,9 @@ public class PhysicalGenerator {
if (queryPlan instanceof LastQueryPlan) {
for (int i = 0; i < paths.size(); i++) {
PartialPath path = paths.get(i);
String column;
if (path.getAlias() != null) {
column = path.getFullPathWithAlias();
} else {
column = path.getFullPath();
String column = path.getTsAlias();
if (column == null) {
column = path.getMeasurementAlias() != null ? path.getFullPathWithAlias() : path.toString();
}
if (!columnSet.contains(column)) {
TSDataType seriesType = dataTypes.get(i);
......@@ -693,14 +708,13 @@ public class PhysicalGenerator {
int index = 0;
for (Pair<PartialPath, Integer> indexedPath : indexedPaths) {
String column;
if (indexedPath.left.getAlias() != null) {
column = indexedPath.left.getFullPathWithAlias();
} else {
column = indexedPath.left.getFullPath();
}
if (queryPlan instanceof AggregationPlan) {
column = queryPlan.getAggregations().get(indexedPath.right) + "(" + column + ")";
String column = indexedPath.left.getTsAlias();
if (column == null) {
column = indexedPath.left.getMeasurementAlias() != null ? indexedPath.left.getFullPathWithAlias()
: indexedPath.left.toString();
if (queryPlan instanceof AggregationPlan) {
column = queryPlan.getAggregations().get(indexedPath.right) + "(" + column + ")";
}
}
if (!columnSet.contains(column)) {
TSDataType seriesType = dataTypes.get(indexedPath.right);
......
......@@ -18,22 +18,27 @@
*/
package org.apache.iotdb.db.qp.strategy.optimizer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
import org.apache.iotdb.db.exception.runtime.SQLParserException;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.db.qp.logical.Operator;
import org.apache.iotdb.db.qp.logical.crud.*;
import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
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.QueryOperator;
import org.apache.iotdb.db.qp.logical.crud.SFWOperator;
import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
import org.apache.iotdb.db.service.IoTDB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* concat paths in select and from clause.
*/
......@@ -80,7 +85,8 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
boolean isAlignByDevice = false;
if (operator instanceof QueryOperator) {
if (!((QueryOperator) operator).isAlignByDevice() || ((QueryOperator) operator).isLastQuery()) {
if (!((QueryOperator) operator).isAlignByDevice() || ((QueryOperator) operator)
.isLastQuery()) {
concatSelect(prefixPaths, select); // concat and remove star
if (((QueryOperator) operator).hasSlimit()) {
......@@ -94,9 +100,9 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
String device = path.getDevice();
if (!device.isEmpty()) {
throw new LogicalOptimizeException(
"The paths of the SELECT clause can only be single level. In other words, "
+ "the paths of the SELECT clause can only be measurements or STAR, without DOT."
+ " For more details please refer to the SQL document.");
"The paths of the SELECT clause can only be single level. In other words, "
+ "the paths of the SELECT clause can only be measurements or STAR, without DOT."
+ " For more details please refer to the SQL document.");
}
}
// ALIGN_BY_DEVICE leaves the 1) concat, 2) remove star, 3) slimit tasks to the next phase,
......@@ -110,7 +116,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
if (filter == null) {
return operator;
}
if(!isAlignByDevice){
if (!isAlignByDevice) {
sfwOperator.setFilterOperator(concatFilter(prefixPaths, filter, filterPaths));
}
sfwOperator.getFilterOperator().setPathSet(filterPaths);
......@@ -164,7 +170,11 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
// selectPath cannot start with ROOT, which is guaranteed by TSParser
PartialPath selectPath = suffixPaths.get(i);
for (PartialPath fromPath : fromPaths) {
allPaths.add(fromPath.concatPath(selectPath));
PartialPath fullPath = fromPath.concatPath(selectPath);
if (selectPath.getTsAlias() != null) {
fullPath.setTsAlias(selectPath.getTsAlias());
}
allPaths.add(fullPath);
extendListSafely(originAggregations, i, afterConcatAggregations);
}
}
......@@ -176,7 +186,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
* Make 'SLIMIT&SOFFSET' take effect by trimming the suffixList and aggregations of the
* selectOperator.
*
* @param seriesLimit is ensured to be positive integer
* @param seriesLimit is ensured to be positive integer
* @param seriesOffset is ensured to be non-negative integer
*/
private void slimitTrim(SelectOperator select, int seriesLimit, int seriesOffset)
......@@ -297,6 +307,14 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
for (int i = 0; i < paths.size(); i++) {
try {
List<PartialPath> actualPaths = removeWildcard(paths.get(i));
if (paths.get(i).getTsAlias() != null) {
if (actualPaths.size() == 1) {
actualPaths.get(0).setTsAlias(paths.get(i).getTsAlias());
} else if (actualPaths.size() >= 2) {
throw new LogicalOptimizeException(
"alias '" + paths.get(i).getTsAlias() + "' can only be matched with one time series");
}
}
for (PartialPath actualPath : actualPaths) {
retPaths.add(actualPath);
if (afterConcatAggregations != null && !afterConcatAggregations.isEmpty()) {
......
......@@ -90,10 +90,14 @@ public class LastQueryExecutor {
if (lastTimeValuePair.getValue() != null) {
RowRecord resultRecord = new RowRecord(lastTimeValuePair.getTimestamp());
Field pathField = new Field(TSDataType.TEXT);
if (selectedSeries.get(i).getAlias() != null) {
pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPathWithAlias()));
if (selectedSeries.get(i).getTsAlias() != null) {
pathField.setBinaryV(new Binary(selectedSeries.get(i).getTsAlias()));
} else {
pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPath()));
if (selectedSeries.get(i).getMeasurementAlias() != null) {
pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPathWithAlias()));
} else {
pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPath()));
}
}
resultRecord.addField(pathField);
......
......@@ -346,9 +346,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
status = RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS);
break;
case "COLUMN":
List<TSDataType> dataTypes =
getSeriesTypesByString(Collections.singletonList(new PartialPath(req.getColumnPath())), null);
resp.setDataType(dataTypes.get(0).toString());
resp.setDataType(getSeriesTypeByPath(new PartialPath(req.getColumnPath())).toString());
status = RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS);
break;
case "ALL_COLUMNS":
......@@ -767,18 +765,18 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
// Restore column header of aggregate to func(column_name), only
// support single aggregate function for now
List<PartialPath> paths = plan.getPaths();
List<TSDataType> seriesTypes;
List<TSDataType> seriesTypes = new ArrayList<>();
switch (plan.getOperatorType()) {
case QUERY:
case FILL:
for (PartialPath path : paths) {
if (path.getAlias() != null) {
respColumns.add(path.getFullPathWithAlias());
} else {
respColumns.add(path.getFullPath());
String column = path.getTsAlias();
if (column == null) {
column = path.getMeasurementAlias() != null ? path.getFullPathWithAlias() : path.getFullPath();
}
respColumns.add(column);
seriesTypes.add(getSeriesTypeByPath(path));
}
seriesTypes = getSeriesTypesByString(paths, null);
break;
case AGGREGATION:
case GROUPBYTIME:
......@@ -790,13 +788,16 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
}
}
for (int i = 0; i < paths.size(); i++) {
if (paths.get(i).getAlias() != null) {
respColumns.add(aggregations.get(i) + "(" + paths.get(i).getFullPathWithAlias() + ")");
} else {
respColumns.add(aggregations.get(i) + "(" + paths.get(i).getFullPath() + ")");
PartialPath path = paths.get(i);
String column = path.getTsAlias();
if (column == null) {
column = path.getMeasurementAlias() != null
? aggregations.get(i) + "(" + paths.get(i).getFullPathWithAlias() + ")"
: aggregations.get(i) + "(" + paths.get(i).getFullPath() + ")";
}
respColumns.add(column);
}
seriesTypes = getSeriesTypesByPath(paths, aggregations);
seriesTypes = getSeriesTypesByPaths(paths, aggregations);
break;
default:
throw new TException("unsupported query type: " + plan.getOperatorType());
......@@ -822,6 +823,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
// build column header with constant and non exist column and deduplication
List<String> measurements = plan.getMeasurements();
Map<String, String> measurementAliasMap = plan.getMeasurementAliasMap();
Map<String, MeasurementType> measurementTypeMap = plan.getMeasurementTypeMap();
for (String measurement : measurements) {
TSDataType type = null;
......@@ -833,7 +835,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
case Constant:
type = TSDataType.TEXT;
}
respColumns.add(measurement);
respColumns.add(measurementAliasMap.getOrDefault(measurement, measurement));
columnTypes.add(type.toString());
if (!deduplicatedMeasurements.contains(measurement)) {
......@@ -1608,13 +1610,13 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
return QueryResourceManager.getInstance().assignQueryId(isDataQuery);
}
protected List<TSDataType> getSeriesTypesByPath(List<PartialPath> paths, List<String> aggregations)
protected List<TSDataType> getSeriesTypesByPaths(List<PartialPath> paths, List<String> aggregations)
throws MetadataException {
return SchemaUtils.getSeriesTypesByPath(paths, aggregations);
return SchemaUtils.getSeriesTypesByPaths(paths, aggregations);
}
protected List<TSDataType> getSeriesTypesByString(List<PartialPath> paths, String aggregation)
throws MetadataException {
return SchemaUtils.getSeriesTypesByString(paths, aggregation);
protected TSDataType getSeriesTypeByPath(PartialPath path) throws MetadataException {
return SchemaUtils.getSeriesTypeByPath(path);
}
}
......@@ -100,7 +100,7 @@ public class SchemaUtils {
}
/**
* @param paths time series paths
* @param paths time series paths
* @param aggregation aggregation function, may be null
* @return The data type of aggregation or (data type of paths if aggregation is null)
*/
......@@ -117,7 +117,11 @@ public class SchemaUtils {
return dataTypes;
}
public static List<TSDataType> getSeriesTypesByPath(List<PartialPath> paths,
public static TSDataType getSeriesTypeByPath(PartialPath path) throws MetadataException {
return IoTDB.metaManager.getSeriesType(path);
}
public static List<TSDataType> getSeriesTypesByPaths(List<PartialPath> paths,
List<String> aggregations) throws MetadataException {
List<TSDataType> tsDataTypes = new ArrayList<>();
for (int i = 0; i < paths.size(); i++) {
......@@ -160,8 +164,9 @@ public class SchemaUtils {
public static void checkDataTypeWithEncoding(TSDataType dataType, TSEncoding encoding)
throws MetadataException {
if(!schemaChecker.get(dataType).contains(encoding)) {
throw new MetadataException(String.format("encoding %s does not support %s", dataType.toString(), encoding.toString()));
if (!schemaChecker.get(dataType).contains(encoding)) {
throw new MetadataException(String
.format("encoding %s does not support %s", dataType.toString(), encoding.toString()));
}
}
}
......@@ -186,9 +186,9 @@ public class MTreeTest {
List<PartialPath> result2 = root.getAllTimeseriesPathWithAlias(new PartialPath("root.a.*.s0"));
assertEquals(2, result2.size());
assertEquals("root.a.d0.s0", result2.get(0).getFullPath());
assertNull(result2.get(0).getAlias());
assertNull(result2.get(0).getMeasurementAlias());
assertEquals("root.a.d1.s0", result2.get(1).getFullPath());
assertNull(result2.get(1).getAlias());
assertNull(result2.get(1).getMeasurementAlias());
result2 = root.getAllTimeseriesPathWithAlias(new PartialPath("root.a.*.temperature"));
assertEquals(2, result2.size());
......
......@@ -35,7 +35,6 @@ public class Path implements Serializable, Comparable<Path> {
protected String fullPath;
private static final String ILLEGAL_PATH_ARGUMENT = "Path parameter is null";
public Path() {}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册