mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-27 10:54:21 +08:00
Compare commits
6 Commits
master
...
7c4e988141
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c4e988141 | ||
|
|
9c10089707 | ||
|
|
0e6050e8ce | ||
|
|
61685d31f3 | ||
|
|
738093bc88 | ||
|
|
b6d1525daa |
@@ -24,6 +24,8 @@ public class ModelDetail {
|
|||||||
|
|
||||||
private String tableQuery;
|
private String tableQuery;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private List<Identify> identifiers = Lists.newArrayList();
|
private List<Identify> identifiers = Lists.newArrayList();
|
||||||
|
|
||||||
private List<Dimension> dimensions = Lists.newArrayList();
|
private List<Dimension> dimensions = Lists.newArrayList();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public class ModelBuildReq {
|
|||||||
|
|
||||||
private String sql;
|
private String sql;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private String catalog;
|
private String catalog;
|
||||||
|
|
||||||
private String db;
|
private String db;
|
||||||
|
|||||||
@@ -50,19 +50,19 @@ public class SqlQueryParser implements QueryParser {
|
|||||||
queryFields.removeAll(queryAliases);
|
queryFields.removeAll(queryAliases);
|
||||||
Ontology ontology = queryStatement.getOntology();
|
Ontology ontology = queryStatement.getOntology();
|
||||||
OntologyQuery ontologyQuery = buildOntologyQuery(ontology, queryFields);
|
OntologyQuery ontologyQuery = buildOntologyQuery(ontology, queryFields);
|
||||||
// check if there are fields not matched with any metric or dimension
|
// // check if there are fields not matched with any metric or dimension
|
||||||
if (queryFields.size() > ontologyQuery.getMetrics().size()
|
// if (queryFields.size() > ontologyQuery.getMetrics().size()
|
||||||
+ ontologyQuery.getDimensions().size()) {
|
// + ontologyQuery.getDimensions().size()) {
|
||||||
List<String> semanticFields = Lists.newArrayList();
|
// List<String> semanticFields = Lists.newArrayList();
|
||||||
ontologyQuery.getMetrics().forEach(m -> semanticFields.add(m.getName()));
|
// ontologyQuery.getMetrics().forEach(m -> semanticFields.add(m.getName()));
|
||||||
ontologyQuery.getDimensions().forEach(d -> semanticFields.add(d.getName()));
|
// ontologyQuery.getDimensions().forEach(d -> semanticFields.add(d.getName()));
|
||||||
String errMsg =
|
// String errMsg =
|
||||||
String.format("Querying columns[%s] not matched with semantic fields[%s].",
|
// String.format("Querying columns[%s] not matched with semantic fields[%s].",
|
||||||
queryFields, semanticFields);
|
// queryFields, semanticFields);
|
||||||
queryStatement.setErrMsg(errMsg);
|
// queryStatement.setErrMsg(errMsg);
|
||||||
queryStatement.setStatus(QueryState.INVALID);
|
// queryStatement.setStatus(QueryState.INVALID);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
queryStatement.setOntologyQuery(ontologyQuery);
|
queryStatement.setOntologyQuery(ontologyQuery);
|
||||||
|
|
||||||
AggOption sqlQueryAggOption = getAggOption(sqlQuery.getSql(), ontologyQuery.getMetrics());
|
AggOption sqlQueryAggOption = getAggOption(sqlQuery.getSql(), ontologyQuery.getMetrics());
|
||||||
|
|||||||
@@ -40,11 +40,23 @@ public class DataModelNode extends SemanticNode {
|
|||||||
.equalsIgnoreCase(EngineType.POSTGRESQL.getName())) {
|
.equalsIgnoreCase(EngineType.POSTGRESQL.getName())) {
|
||||||
String fullTableName = String.join(".public.",
|
String fullTableName = String.join(".public.",
|
||||||
dataModel.getModelDetail().getTableQuery().split("\\."));
|
dataModel.getModelDetail().getTableQuery().split("\\."));
|
||||||
sqlTable = "select * from " + fullTableName;
|
sqlTable = "SELECT * FROM " + fullTableName;
|
||||||
} else {
|
} else {
|
||||||
sqlTable = "select * from " + dataModel.getModelDetail().getTableQuery();
|
sqlTable = "SELECT * FROM " + dataModel.getModelDetail().getTableQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String filterSql = dataModel.getFilterSql();
|
||||||
|
String filterSql = dataModel.getModelDetail().getFilterSql();
|
||||||
|
if (filterSql != null && !filterSql.isEmpty()) {
|
||||||
|
boolean sqlContainWhere = sqlTable.toUpperCase().matches("(?s).*\\bWHERE\\b.*");
|
||||||
|
if (sqlContainWhere) {
|
||||||
|
sqlTable = String.format("%s AND %s", sqlTable, filterSql);
|
||||||
|
} else {
|
||||||
|
sqlTable = String.format("%s WHERE %s", sqlTable, filterSql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sqlTable.isEmpty()) {
|
if (sqlTable.isEmpty()) {
|
||||||
throw new Exception("DataModelNode build error [tableSqlNode not found]");
|
throw new Exception("DataModelNode build error [tableSqlNode not found]");
|
||||||
}
|
}
|
||||||
@@ -69,7 +81,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void addSchemaTable(SqlValidatorScope scope, ModelResp dataModel, String db,
|
private static void addSchemaTable(SqlValidatorScope scope, ModelResp dataModel, String db,
|
||||||
String tb, Set<String> fields) throws Exception {
|
String tb, Set<String> fields) throws Exception {
|
||||||
Set<String> dateInfo = new HashSet<>();
|
Set<String> dateInfo = new HashSet<>();
|
||||||
Set<String> dimensions = new HashSet<>();
|
Set<String> dimensions = new HashSet<>();
|
||||||
Set<String> metrics = new HashSet<>();
|
Set<String> metrics = new HashSet<>();
|
||||||
@@ -106,7 +118,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<SqlNode> getExtendField(Map<String, String> exprList,
|
public static List<SqlNode> getExtendField(Map<String, String> exprList,
|
||||||
SqlValidatorScope scope, EngineType engineType) throws Exception {
|
SqlValidatorScope scope, EngineType engineType) throws Exception {
|
||||||
List<SqlNode> sqlNodeList = new ArrayList<>();
|
List<SqlNode> sqlNodeList = new ArrayList<>();
|
||||||
for (String expr : exprList.keySet()) {
|
for (String expr : exprList.keySet()) {
|
||||||
sqlNodeList.add(parse(expr, scope, engineType));
|
sqlNodeList.add(parse(expr, scope, engineType));
|
||||||
@@ -127,7 +139,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<ModelResp> getQueryDataModels(Ontology ontology,
|
public static List<ModelResp> getQueryDataModels(Ontology ontology,
|
||||||
OntologyQuery ontologyQuery) {
|
OntologyQuery ontologyQuery) {
|
||||||
// get query measures and dimensions
|
// get query measures and dimensions
|
||||||
Set<String> queryMeasures = new HashSet<>();
|
Set<String> queryMeasures = new HashSet<>();
|
||||||
Set<String> queryDimensions = new HashSet<>();
|
Set<String> queryDimensions = new HashSet<>();
|
||||||
@@ -162,7 +174,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void getQueryDimensionMeasure(Ontology ontology, OntologyQuery ontologyQuery,
|
public static void getQueryDimensionMeasure(Ontology ontology, OntologyQuery ontologyQuery,
|
||||||
Set<String> queryDimensions, Set<String> queryMeasures) {
|
Set<String> queryDimensions, Set<String> queryMeasures) {
|
||||||
ontologyQuery.getMetrics().forEach(m -> {
|
ontologyQuery.getMetrics().forEach(m -> {
|
||||||
if (Objects.nonNull(m.getMetricDefineByMeasureParams())) {
|
if (Objects.nonNull(m.getMetricDefineByMeasureParams())) {
|
||||||
m.getMetricDefineByMeasureParams().getMeasures()
|
m.getMetricDefineByMeasureParams().getMeasures()
|
||||||
@@ -215,7 +227,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkMatch(ModelResp baseDataModel, Set<String> queryMeasures,
|
private static boolean checkMatch(ModelResp baseDataModel, Set<String> queryMeasures,
|
||||||
Set<String> queryDimension) {
|
Set<String> queryDimension) {
|
||||||
boolean isAllMatch = true;
|
boolean isAllMatch = true;
|
||||||
Set<String> baseMeasures = baseDataModel.getMeasures().stream().map(Measure::getName)
|
Set<String> baseMeasures = baseDataModel.getMeasures().stream().map(Measure::getName)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@@ -248,8 +260,8 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<ModelResp> findRelatedModelsByRelation(Ontology ontology,
|
private static List<ModelResp> findRelatedModelsByRelation(Ontology ontology,
|
||||||
OntologyQuery ontologyQuery, ModelResp baseDataModel, Set<String> queryDimensions,
|
OntologyQuery ontologyQuery, ModelResp baseDataModel, Set<String> queryDimensions,
|
||||||
Set<String> queryMeasures) {
|
Set<String> queryMeasures) {
|
||||||
Set<String> joinDataModelNames = new HashSet<>();
|
Set<String> joinDataModelNames = new HashSet<>();
|
||||||
List<ModelResp> joinDataModels = new ArrayList<>();
|
List<ModelResp> joinDataModels = new ArrayList<>();
|
||||||
Set<String> before = new HashSet<>();
|
Set<String> before = new HashSet<>();
|
||||||
@@ -333,7 +345,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void sortJoinRelation(List<JoinRelation> joinRelations, String next,
|
private static void sortJoinRelation(List<JoinRelation> joinRelations, String next,
|
||||||
Set<Long> visited, List<JoinRelation> sortedJoins) {
|
Set<Long> visited, List<JoinRelation> sortedJoins) {
|
||||||
for (JoinRelation link : joinRelations) {
|
for (JoinRelation link : joinRelations) {
|
||||||
if (!visited.contains(link.getId())) {
|
if (!visited.contains(link.getId())) {
|
||||||
if (link.getLeft().equals(next) || link.getRight().equals(next)) {
|
if (link.getLeft().equals(next) || link.getRight().equals(next)) {
|
||||||
@@ -348,7 +360,7 @@ public class DataModelNode extends SemanticNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<ModelResp> findRelatedModelsByIdentifier(Ontology ontology,
|
private static List<ModelResp> findRelatedModelsByIdentifier(Ontology ontology,
|
||||||
ModelResp baseDataModel, Set<String> queryDimension, Set<String> measures) {
|
ModelResp baseDataModel, Set<String> queryDimension, Set<String> measures) {
|
||||||
Set<String> baseIdentifiers = baseDataModel.getModelDetail().getIdentifiers().stream()
|
Set<String> baseIdentifiers = baseDataModel.getModelDetail().getIdentifiers().stream()
|
||||||
.map(Identify::getName).collect(Collectors.toSet());
|
.map(Identify::getName).collect(Collectors.toSet());
|
||||||
if (baseIdentifiers.isEmpty()) {
|
if (baseIdentifiers.isEmpty()) {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class ModelYamlManager {
|
|||||||
} else {
|
} else {
|
||||||
dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery());
|
dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery());
|
||||||
}
|
}
|
||||||
|
dataModelYamlTpl.setFilterSql(modelDetail.getFilterSql());
|
||||||
dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields());
|
dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields());
|
||||||
dataModelYamlTpl.setId(modelResp.getId());
|
dataModelYamlTpl.setId(modelResp.getId());
|
||||||
return dataModelYamlTpl;
|
return dataModelYamlTpl;
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public class SemanticSchemaManager {
|
|||||||
modelDetail.setDbType(d.getType());
|
modelDetail.setDbType(d.getType());
|
||||||
modelDetail.setSqlQuery(d.getSqlQuery());
|
modelDetail.setSqlQuery(d.getSqlQuery());
|
||||||
modelDetail.setTableQuery(d.getTableQuery());
|
modelDetail.setTableQuery(d.getTableQuery());
|
||||||
|
modelDetail.setFilterSql(d.getFilterSql());
|
||||||
modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers()));
|
modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers()));
|
||||||
modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures()));
|
modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures()));
|
||||||
modelDetail.getDimensions().addAll(getDimensions(d.getDimensions()));
|
modelDetail.getDimensions().addAll(getDimensions(d.getDimensions()));
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ public class DataModelYamlTpl {
|
|||||||
|
|
||||||
private String tableQuery;
|
private String tableQuery;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private List<IdentifyYamlTpl> identifiers;
|
private List<IdentifyYamlTpl> identifiers;
|
||||||
|
|
||||||
private List<DimensionYamlTpl> dimensions;
|
private List<DimensionYamlTpl> dimensions;
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ public class ModelConverter {
|
|||||||
modelDetail.setQueryType(ModelDefineType.TABLE_QUERY.getName());
|
modelDetail.setQueryType(ModelDefineType.TABLE_QUERY.getName());
|
||||||
modelDetail.setTableQuery(String.format("%s.%s", modelBuildReq.getDb(), tableName));
|
modelDetail.setTableQuery(String.format("%s.%s", modelBuildReq.getDb(), tableName));
|
||||||
}
|
}
|
||||||
|
modelDetail.setFilterSql(modelBuildReq.getFilterSql());
|
||||||
for (ColumnSchema columnSchema : modelSchema.getColumnSchemas()) {
|
for (ColumnSchema columnSchema : modelSchema.getColumnSchemas()) {
|
||||||
FieldType fieldType = columnSchema.getFiledType();
|
FieldType fieldType = columnSchema.getFiledType();
|
||||||
if (getIdentifyType(fieldType) != null) {
|
if (getIdentifyType(fieldType) != null) {
|
||||||
|
|||||||
@@ -48,12 +48,13 @@ const MetricTrend: React.FC<Props> = ({
|
|||||||
const { queryColumns, queryResults, aggregateInfo, entityInfo, chatContext } = data;
|
const { queryColumns, queryResults, aggregateInfo, entityInfo, chatContext } = data;
|
||||||
const [chartType, setChartType] = useState('line');
|
const [chartType, setChartType] = useState('line');
|
||||||
|
|
||||||
const dateField: any = queryColumns?.find(
|
const dateField = queryColumns?.find(
|
||||||
(column: any) => column.showType === 'DATE' || column.type === 'DATE'
|
(column: any) => column.showType === 'DATE' || column.type === 'DATE'
|
||||||
);
|
);
|
||||||
const dateColumnName = dateField?.bizName || '';
|
const dateColumnName = dateField?.bizName || '';
|
||||||
const categoryColumnName =
|
let categoryColumnName =
|
||||||
queryColumns?.find((column: any) => column.showType === 'CATEGORY')?.bizName || '';
|
queryColumns?.find((column: any) => column.showType === 'CATEGORY')?.bizName || '';
|
||||||
|
categoryColumnName = categoryColumnName === dateColumnName ? '' : categoryColumnName;
|
||||||
const metricFields = queryColumns?.filter((column: any) => column.showType === 'NUMBER');
|
const metricFields = queryColumns?.filter((column: any) => column.showType === 'NUMBER');
|
||||||
|
|
||||||
const currentMetricField = queryColumns?.find((column: any) => column.showType === 'NUMBER');
|
const currentMetricField = queryColumns?.find((column: any) => column.showType === 'NUMBER');
|
||||||
@@ -80,11 +81,11 @@ const MetricTrend: React.FC<Props> = ({
|
|||||||
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
|
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
|
||||||
)}
|
)}
|
||||||
<div className={`${prefixCls}-select-options`}>
|
<div className={`${prefixCls}-select-options`}>
|
||||||
<DateOptions
|
{/*<DateOptions*/}
|
||||||
chatContext={chatContext}
|
{/* chatContext={chatContext}*/}
|
||||||
currentDateOption={currentDateOption}
|
{/* currentDateOption={currentDateOption}*/}
|
||||||
onSelectDateOption={onSelectDateOption}
|
{/* onSelectDateOption={onSelectDateOption}*/}
|
||||||
/>
|
{/*/>*/}
|
||||||
<div>
|
<div>
|
||||||
<Select
|
<Select
|
||||||
defaultValue="line"
|
defaultValue="line"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ISemantic } from '../../data';
|
|||||||
import {
|
import {
|
||||||
AGG_OPTIONS,
|
AGG_OPTIONS,
|
||||||
DATE_FORMATTER,
|
DATE_FORMATTER,
|
||||||
DATE_OPTIONS,
|
// DATE_OPTIONS,
|
||||||
DIM_OPTIONS,
|
DIM_OPTIONS,
|
||||||
EnumDataSourceType,
|
EnumDataSourceType,
|
||||||
EnumModelDataType,
|
EnumModelDataType,
|
||||||
@@ -275,7 +275,7 @@ const ModelFieldForm: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ([EnumDataSourceType.TIME, EnumDataSourceType.PARTITION_TIME].includes(type)) {
|
if ([EnumDataSourceType.TIME, EnumDataSourceType.PARTITION_TIME].includes(type)) {
|
||||||
const { dateFormat, timeGranularity } = record;
|
const { dateFormat } = record;
|
||||||
const dateFormatterOptions =
|
const dateFormatterOptions =
|
||||||
type === EnumDataSourceType.PARTITION_TIME ? PARTITION_TIME_FORMATTER : DATE_FORMATTER;
|
type === EnumDataSourceType.PARTITION_TIME ? PARTITION_TIME_FORMATTER : DATE_FORMATTER;
|
||||||
|
|
||||||
@@ -302,25 +302,25 @@ const ModelFieldForm: React.FC<Props> = ({
|
|||||||
<ExclamationCircleOutlined />
|
<ExclamationCircleOutlined />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
{/*<Space>*/}
|
||||||
<span>时间粒度:</span>
|
{/* <span>时间粒度:</span>*/}
|
||||||
<Select
|
{/* <Select*/}
|
||||||
placeholder="时间粒度"
|
{/* placeholder="时间粒度"*/}
|
||||||
value={timeGranularity === '' ? undefined : timeGranularity}
|
{/* value={timeGranularity === '' ? undefined : timeGranularity}*/}
|
||||||
onChange={(value) => {
|
{/* onChange={(value) => {*/}
|
||||||
handleFieldChange(record, 'timeGranularity', value);
|
{/* handleFieldChange(record, 'timeGranularity', value);*/}
|
||||||
}}
|
{/* }}*/}
|
||||||
defaultValue={timeGranularity === '' ? undefined : DATE_OPTIONS[0]}
|
{/* defaultValue={timeGranularity === '' ? undefined : DATE_OPTIONS[0]}*/}
|
||||||
style={{ minWidth: 180 }}
|
{/* style={{ minWidth: 180 }}*/}
|
||||||
allowClear
|
{/* allowClear*/}
|
||||||
>
|
{/* >*/}
|
||||||
{DATE_OPTIONS.map((item) => (
|
{/* {DATE_OPTIONS.map((item) => (*/}
|
||||||
<Option key={item} value={item}>
|
{/* <Option key={item} value={item}>*/}
|
||||||
{item}
|
{/* {item}*/}
|
||||||
</Option>
|
{/* </Option>*/}
|
||||||
))}
|
{/* ))}*/}
|
||||||
</Select>
|
{/* </Select>*/}
|
||||||
</Space>
|
{/*</Space>*/}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user