summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorliuyongqiang <[email protected]>2020-12-01 11:02:11 +0800
committerliuyongqiang <[email protected]>2020-12-01 11:02:11 +0800
commit5b530df5105912d48c091a796290e995885a1913 (patch)
treec00116d948ed7d6dbebdf65384e9e7746879e77a
parentee38423b7d67b004dffd7c11ec8286577c0334fd (diff)
galaxy-qgw-service工程迁移完成
-rw-r--r--galaxy-query-engine/config/application.yml55
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/active_defence_event_log.avsc133
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/columns_cluster.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/connection_record_log.avsc829
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_client_ip.avsc56
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_server_ip.avsc56
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_subscriber_id.avsc56
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/connection_record_log_http_domain.avsc56
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/disks_cluster.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/parts_cluster.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/processes.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/proxy_event_log.avsc636
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/proxy_ip_info.avsc22
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/query_log.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/query_log_cluster.avsc11
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/radius_onff_log.avsc37
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/radius_record_log.avsc497
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/security_event_log.avsc835
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/security_ip_info.avsc33
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/security_website_domain_info.avsc47
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/sys_packet_capture_log.avsc338
-rw-r--r--galaxy-query-engine/config/avro/clickhouse/tables_cluster.avsc11
-rw-r--r--galaxy-query-engine/config/avro/druid/proxy_event_hits_log.avsc56
-rw-r--r--galaxy-query-engine/config/avro/druid/security_event_hits_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/source_country_ip_num_log.avsc20
-rw-r--r--galaxy-query-engine/config/avro/druid/sys_storage_log.avsc32
-rw-r--r--galaxy-query-engine/config/avro/druid/top_client_ip_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_domain_recommend_daily_log.avsc32
-rw-r--r--galaxy-query-engine/config/avro/druid/top_external_host_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_internal_host_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_server_ip_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_urls_log.avsc20
-rw-r--r--galaxy-query-engine/config/avro/druid/top_user_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_website_domain_log.avsc40
-rw-r--r--galaxy-query-engine/config/avro/druid/top_website_urls_daily_log.avsc28
-rw-r--r--galaxy-query-engine/config/avro/druid/traffic_metrics_log.avsc212
-rw-r--r--galaxy-query-engine/config/avro/druid/traffic_protocol_stat_log.avsc72
-rw-r--r--galaxy-query-engine/config/avro/druid/traffic_summary_log.avsc72
-rw-r--r--galaxy-query-engine/config/avro/etl/liveChart.avsc10
-rw-r--r--galaxy-query-engine/config/memorySchema.json13
-rw-r--r--galaxy-query-engine/config/version.json95
-rw-r--r--galaxy-query-engine/dat/asn_v4.mmdbbin0 -> 3353311 bytes
-rw-r--r--galaxy-query-engine/dat/asn_v6.mmdbbin0 -> 1183044 bytes
-rw-r--r--galaxy-query-engine/dat/ip_private_v4.mmdbbin0 -> 3336 bytes
-rw-r--r--galaxy-query-engine/dat/ip_private_v6.mmdbbin0 -> 6732 bytes
-rw-r--r--galaxy-query-engine/dat/ip_v4.mmdbbin0 -> 84352178 bytes
-rw-r--r--galaxy-query-engine/dat/ip_v6.mmdbbin0 -> 6732 bytes
-rw-r--r--galaxy-query-engine/pom.xml53
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/GalaxyQueryEngine.java32
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java170
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchema.java31
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchemaFactory.java19
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemoryTable.java82
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/DataTypeMapping.java77
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/Storage.java100
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResult.java54
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResultGenerator.java207
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java31
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/BifangMysqlConfiguration.java26
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java34
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseProperties.java23
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoConfiguration.java33
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoProperties.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineConfiguration.java47
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineProperties.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseConfiguration.java63
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseProperties.java18
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminConfiguration.java30
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminProperties.java16
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectAuthorProperties.java20
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectProperties.java107
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/BooleanEnum.java30
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/CookieEnum.java23
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/DBTypeEnum.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentEnum.java30
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentGroupEnum.java45
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/JobHandlerEnum.java21
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryFormatEnum.java11
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryOptionEnum.java14
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryParamEnum.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultCodeEnum.java30
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultStatusEnum.java33
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/enums/SessionEnum.java24
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/exception/BusinessException.java51
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ActiveRecordInit.java33
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ArpStartPlugin.java29
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/support/IConvertor.java20
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/BigDecimalUtil.java179
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java350
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java84
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/JsonMapper.java237
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/PropertiesFileUtil.java162
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java62
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/RandomUtil.java58
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java83
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java1409
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLHelper.java95
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/SchemaCacheUtils.java62
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/SpringContextUtil.java95
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/StringUtil.java284
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java786
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java100
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/engine/GalaxyQueryEngine.java14
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLVerification.java (renamed from galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLValidate.java)2
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/engine/controller/DslQueryController.java6
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/config/ArangoConfig.java39
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/Constant.java15
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/HttpConfig.java64
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java54
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java46
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/DSLObject.java26
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java56
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Parameters.java22
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/QueryExp.java18
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Range.java13
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Sort.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseDocument.java49
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseEdgeDocument.java43
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/IpLearningPath.java84
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/SubscriberIdPath.java37
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/DataSourceEnum.java24
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/MatchEnum.java45
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/QueryTypeEnum.java23
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/RangeEnum.java46
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java163
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java88
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java191
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java80
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/QueryProvider.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java84
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/controller/NetworkMonitorController.java44
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLObject.java40
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLValidate.java132
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/dsl/Parameter.java10
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/service/NetworkMonitorService.java17
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/network/service/impl/NetworkMonitorServiceImpl.java402
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/openapi/controller/OpenApiController.java49
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/openapi/service/OpenApiService.java29
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/openapi/service/impl/OpenApiServiceImpl.java61
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java37
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java113
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ControllerFilter.java29
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/GlobalExceptionHandler.java35
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java32
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MonitorController.java40
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/RequestParamWrapper.java50
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java81
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/TestController.java125
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java80
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java49
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java1016
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/Dialect.java54
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java425
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java151
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java90
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java42
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditLog.java14
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditServiceLog.java34
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/CachedSubmitCheck.java11
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpQuery.java17
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpSource.java24
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/DruidIoHttpSource.java12
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/EngineConfigSource.java13
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/HBaseAPISource.java20
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/JobAdminHttpSource.java16
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java94
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java59
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java59
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java63
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java276
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDF.java10
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDFElements.java16
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/ExecutorParam.java9
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/StorageDeletionInfo.java16
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/XxlJobInfo.java30
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java69
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java78
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ClickHouseHealthIndicator.java59
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/DruidHealthIndicator.java74
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/HbaseHealthIndicator.java50
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/JobAdminHealthIndicator.java65
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/MariaDBHealthIndicator.java45
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/ApiService.java10
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/MetadataService.java57
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/SystemService.java44
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java815
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java427
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java218
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java491
-rw-r--r--galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java617
-rw-r--r--galaxy-query-engine/src/main/resources/dsl-validation.json231
-rw-r--r--galaxy-query-engine/src/main/resources/sql-temelate.sql7
-rw-r--r--pom.xml17
194 files changed, 19205 insertions, 29 deletions
diff --git a/galaxy-query-engine/config/application.yml b/galaxy-query-engine/config/application.yml
index bb3f2d8..f695b5d 100644
--- a/galaxy-query-engine/config/application.yml
+++ b/galaxy-query-engine/config/application.yml
@@ -4,6 +4,11 @@ server:
spring:
application:
name: galaxy-query-engine
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://192.168.44.3:3306/tsg-bifang?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
+ username: root
+ password: 111111
cloud:
consul:
host: 192.168.40.152
@@ -31,15 +36,18 @@ engine:
defaultResultNum: 100000
## druid config
druid:
+ address: 192.168.40.152:8082
dbname: druid
socketTimeOut: 60000
- address: 192.168.40.152:8082
+ url: ${druid.address}/druid/v2/sql
query: http://${druid.address}/druid/v2/sql
-## clickhouse config
+## clickhHouse configuration
clickhouse:
address: 192.168.44.12:8123
- dbname: tsg_galaxy_v3
query: http://${clickhouse.address}
+ url: jdbc:clickhouse://${clickhouse.address}
+ driverClassName: ru.yandex.clickhouse.ClickHouseDriver
+ dbname: tsg_galaxy_v3
realTimeAccount:
username: tsg_query
password: ceiec2018
@@ -47,4 +55,43 @@ clickhouse:
longTermAccount:
username: tsg_report
password: ceiec2019
- socketTimeOut: 21700000 \ No newline at end of file
+ socketTimeOut: 21700000
+## hbase configuration
+hbase:
+ zookeeperQuorum: 192.168.44.12
+ zookeeperPropertyClientPort: 2181
+ zookeeperZnodeParent: /hbase
+ dbname: tsg
+ tableName: report_result
+ columnFamily: response
+ columnName: result
+ clientIpcPoolSize: 60
+ rpcTimeout: 60000
+## xxl-job-admin configuration
+xxl-job-admin:
+ url: http://192.168.44.12:8181/xxl-job-admin
+ userName: query
+ password: ceiec2018
+## arangoDB configuration
+arango:
+ server: http://192.168.44.12:8529
+ database: tsg_galaxy_v3
+ username: query
+ password: ceiec2018
+ jwturl: ${arango.server}/_db/${arango.database}/_open/auth
+ queryurl: ${arango.server}/_db/${arango.database}/_api/cursor
+ maxrows: 10000
+ socketTimeOut: 300000
+## http pool config
+http:
+ pool:
+ connect:
+ timeout: 30000
+ max:
+ connection: 500
+ per:
+ route: 200
+ request:
+ timeout: 10000
+ response:
+ timeout: 10000 \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/active_defence_event_log.avsc b/galaxy-query-engine/config/avro/clickhouse/active_defence_event_log.avsc
new file mode 100644
index 0000000..5649330
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/active_defence_event_log.avsc
@@ -0,0 +1,133 @@
+{
+ "type": "record",
+ "name": "active_defence_event_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\",\"schema_query\":{\"dimensions\":[\"common_policy_id\",\"ad_target_ip\",\"ad_cc_target_url\"],\"metrics\":[\"ad_target_ip\",\"ad_sent_byte_num\",\"ad_sent_pkt_num\",\"ad_cc_initiate_connection_num\",\"ad_cc_established_connection_num\",\"ad_cc_rejected_connection_num\"],\"filters\":[\"common_policy_id\",\"ad_target_ip\",\"ad_target_port\",\"ad_protocol\",\"common_address_type\",\"ad_sent_byte_num\",\"ad_sent_pkt_num\",\"ad_cc_initiate_connection_num\",\"ad_cc_established_connection_num\",\"ad_cc_rejected_connection_num\"]},\"schema_type\":{\"REFLECTION\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_address_type\",\"common_device_id\",\"common_link_id\",\"common_entrance_id\",\"common_user_region\",\"ad_method\",\"ad_protocol\",\"ad_target_ip\",\"ad_target_port\",\"ad_target_ip_location\",\"ad_target_ip_asn\",\"ad_reflector_profile_id\",\"ad_sent_pkt_num\",\"ad_sent_byte_num\",\"ad_generate_time\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"ad_target_ip\",\"ad_target_port\",\"ad_reflector_profile_id\",\"ad_sent_pkt_num\",\"ad_sent_byte_num\"]},\"FLOOD\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_address_type\",\"common_device_id\",\"common_link_id\",\"common_entrance_id\",\"common_user_region\",\"ad_method\",\"ad_protocol\",\"ad_target_ip\",\"ad_target_port\",\"ad_target_ip_location\",\"ad_target_ip_asn\",\"ad_claimed_src_ip_profile_id\",\"ad_sent_pkt_num\",\"ad_sent_byte_num\",\"ad_generate_time\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"ad_target_ip\",\"ad_target_port\",\"ad_claimed_src_ip_profile_id\",\"ad_protocol\"]},\"CC\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_address_type\",\"common_device_id\",\"common_link_id\",\"common_entrance_id\",\"common_user_region\",\"ad_method\",\"ad_protocol\",\"ad_cc_target_url\",\"ad_claimed_src_ip_profile_id\",\"ad_cc_initiate_connection_num\",\"ad_cc_established_connection_num\",\"ad_cc_rejected_connection_num\",\"ad_generate_time\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"ad_cc_target_url\",\"ad_claimed_src_ip_profile_id\",\"ad_protocol\"]}},\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"ad_target_ip\",\"ad_target_port\",\"ad_cc_target_url\"]}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "ad_target_ip",
+ "label": "Target IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_ip_country,geo_asn\",\"appendTo\":\"ad_target_ip_location,ad_target_ip_asn\"}}"
+ },
+ {
+ "name": "ad_target_port",
+ "label": "Target Port",
+ "type": "int"
+ },
+ {
+ "name": "ad_cc_target_url",
+ "label": "Target URL",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "ad_target_ip_location",
+ "label": "Target Location",
+ "type": "string"
+ },
+ {
+ "name": "ad_target_ip_asn",
+ "label": "Target ASN",
+ "type": "string"
+ },
+ {
+ "name": "ad_protocol",
+ "label": "Protocol",
+ "type": "string"
+ },
+ {
+ "name": "ad_method",
+ "label": "Method",
+ "type": "string"
+ },
+ {
+ "name": "ad_claimed_src_ip_profile_id",
+ "label": "Claimed Profile ID",
+ "type": "int"
+ },
+ {
+ "name": "ad_reflector_profile_id",
+ "label": "Reflector Profile ID",
+ "type": "int"
+ },
+ {
+ "name": "ad_sent_pkt_num",
+ "label": "Packets Sent",
+ "type": "int"
+ },
+ {
+ "name": "ad_sent_byte_num",
+ "label": "Bytes Sent",
+ "type": "int"
+ },
+ {
+ "name": "ad_cc_initiate_connection_num",
+ "label": "Initiate Numbers",
+ "type": "int"
+ },
+ {
+ "name": "ad_cc_established_connection_num",
+ "label": "Established Numbers",
+ "type": "int"
+ },
+ {
+ "name": "ad_cc_rejected_connection_num",
+ "label": "Rejected Numbers",
+ "type": "int"
+ },
+ {
+ "name": "ad_generate_time",
+ "label": "Generate Time",
+ "type": "int",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"}}"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/columns_cluster.avsc b/galaxy-query-engine/config/avro/clickhouse/columns_cluster.avsc
new file mode 100644
index 0000000..d190d3c
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/columns_cluster.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "columns_cluster",
+ "fields": [
+ {
+ "name": "database",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/connection_record_log.avsc b/galaxy-query-engine/config/avro/clickhouse/connection_record_log.avsc
new file mode 100644
index 0000000..aa0aa5f
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/connection_record_log.avsc
@@ -0,0 +1,829 @@
+{
+ "type": "record",
+ "name": "connection_record_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\",\"index_table\":\"connection_record_log_common_client_ip,connection_record_log_common_server_ip,connection_record_log_common_subscriber_id,connection_record_log_http_domain\",\"schema_query\":{\"dimensions\":[\"common_server_ip\",\"common_client_ip\",\"common_internal_ip\",\"common_external_ip\",\"common_sled_ip\",\"common_server_location\",\"common_subscriber_id\",\"common_server_port\",\"http_domain\"],\"metrics\":[\"common_server_ip\",\"common_client_ip\",\"common_internal_ip\",\"common_external_ip\",\"common_subscriber_id\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_sessions\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\"],\"filters\":[\"common_address_type\",\"common_server_ip\",\"common_client_ip\",\"common_internal_ip\",\"common_external_ip\",\"common_server_port\",\"common_server_location\",\"common_subscriber_id\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_l4_protocol\",\"common_stream_dir\",\"common_direction\",\"common_data_center\",\"http_domain\",\"ssl_sni\"]},\"schema_type\":{\"BASE\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_server_ip\",\"common_server_port\"]},\"HTTP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"http_url\",\"http_host\",\"http_domain\",\"http_request_line\",\"http_response_line\",\"http_request_header\",\"http_response_header\",\"http_request_body\",\"http_response_body\",\"http_request_body_key\",\"http_response_body_key\",\"http_proxy_flag\",\"http_sequence\",\"http_snapshot\",\"http_cookie\",\"http_referer\",\"http_user_agent\",\"http_content_length\",\"http_content_type\",\"http_set_cookie\",\"http_version\",\"http_response_lantency_ms\",\"http_session_duration_ms\",\"http_action_file_size\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"http_url\",\"common_server_port\"]},\"MAIL\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"mail_protocol_type\",\"mail_account\",\"mail_from_cmd\",\"mail_to_cmd\",\"mail_from\",\"mail_to\",\"mail_cc\",\"mail_bcc\",\"mail_subject\",\"mail_subject_charset\",\"mail_content\",\"mail_content_charset\",\"mail_attachment_name\",\"mail_attachment_name_charset\",\"mail_attachment_content\",\"mail_eml_file\",\"mail_snapshot\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"mail_from\",\"mail_to\",\"mail_subject\"]},\"DNS\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"dns_message_id\",\"dns_qr\",\"dns_opcode\",\"dns_aa\",\"dns_tc\",\"dns_rd\",\"dns_ra\",\"dns_rcode\",\"dns_qdcount\",\"dns_ancount\",\"dns_nscount\",\"dns_arcount\",\"dns_qname\",\"dns_qtype\",\"dns_qclass\",\"dns_cname\",\"dns_sub\",\"dns_rr\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_client_ip\",\"dns_qr\",\"dns_qname\",\"dns_qtype\"]},\"SSL\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"ssl_sni\",\"ssl_san\",\"ssl_cn\",\"ssl_pinningst\",\"ssl_intercept_state\",\"ssl_server_side_latency\",\"ssl_client_side_latency\",\"ssl_server_side_version\",\"ssl_client_side_version\",\"ssl_cert_verify\",\"ssl_error\",\"ssl_con_latency_ms\",\"ssl_ja3_fingerprint\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"ssl_sni\",\"common_server_ip\",\"common_server_port\"]},\"QUIC\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"quic_version\",\"quic_sni\",\"quic_user_agent\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"quic_sni\",\"common_server_ip\",\"common_server_port\"]},\"FTP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"ftp_account\",\"ftp_url\",\"ftp_content\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"ftp_url\",\"common_server_ip\",\"common_server_port\"]},\"BGP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"bgp_type\",\"bgp_as_num\",\"bgp_route\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"bgp_type\",\"bgp_as_num\",\"common_server_ip\",\"common_server_port\"]},\"VOIP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"voip_calling_account\",\"voip_called_account\",\"voip_calling_number\",\"voip_called_number\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"voip_calling_account\",\"voip_called_account\",\"common_server_ip\",\"common_server_port\"]},\"APP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"app_extra_info\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_app_id\",\"common_app_label\",\"app_extra_info\",\"common_server_ip\",\"common_server_port\"]}},\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_server_ip\",\"common_server_port\",\"common_schema_type\"]}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_subscriber_id",
+ "label": "Subscriber ID",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_client_ip",
+ "label": "Client IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn,radius_match\",\"appendTo\":\"common_client_asn,common_subscriber_id\"}}"
+ },
+ {
+ "name": "common_internal_ip",
+ "label": "Internal IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=69,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_client_port",
+ "label": "Client Port",
+ "type": "int"
+ },
+ {
+ "name": "common_l4_protocol",
+ "label": "L4 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_server_ip",
+ "label": "Server IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn\",\"appendTo\":\"common_server_asn\"}}"
+ },
+ {
+ "name": "common_server_port",
+ "label": "Server Port",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_external_ip",
+ "label": "External IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=73,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_action",
+ "label": "Action",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"None\"},{\"code\":\"1\",\"value\":\"Monitor\"},{\"code\":\"2\",\"value\":\"Intercept\"},{\"code\":\"16\",\"value\":\"Deny\"},{\"code\":\"128\",\"value\":\"Allow\"}]}"
+ },
+ {
+ "name": "common_direction",
+ "label": "Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"69\",\"value\":\"outbound\"},{\"code\":\"73\",\"value\":\"inbound\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sled_ip",
+ "label": "Sled IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_location",
+ "label": "Client Location",
+ "type": "string"
+ },
+ {
+ "name": "common_client_asn",
+ "label": "Client ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_server_location",
+ "label": "Server Location",
+ "type": "string"
+ },
+ {
+ "name": "common_server_asn",
+ "label": "Server ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_sessions",
+ "label": "Sessions",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_pkt_num",
+ "label": "Packets Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_pkt_num",
+ "label": "Packets Received",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_byte_num",
+ "label": "Bytes Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_byte_num",
+ "label": "Bytes Received",
+ "type": "long"
+ },
+ {
+ "name": "common_service",
+ "label": "Service",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_schema_type",
+ "label": "Schema Type",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"BASE\",\"value\":\"BASE\"},{\"code\":\"MAIL\",\"value\":\"MAIL\"},{\"code\":\"DNS\",\"value\":\"DNS\"},{\"code\":\"HTTP\",\"value\":\"HTTP\"},{\"code\":\"SSL\",\"value\":\"SSL\"},{\"code\":\"APP\",\"value\":\"APP\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_user_tags",
+ "label": "User Tags",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sub_action",
+ "label": "Sub Action",
+ "type": "string"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_isp",
+ "label": "ISP",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_tag",
+ "label": "Device Tag",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_data_center",
+ "label": "Data Center",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"Nur-sultan\",\"value\":\"Nur-sultan\"},{\"code\":\"Aktau\",\"value\":\"Aktau\"},{\"code\":\"Aktubinsk\",\"value\":\"Aktubinsk\"},{\"code\":\"Almaty\",\"value\":\"Almaty\"},{\"code\":\"Atyrau\",\"value\":\"Atyrau\"},{\"code\":\"Karaganda\",\"value\":\"Karaganda\"},{\"code\":\"Kokshetau\",\"value\":\"Kokshetau\"},{\"code\":\"Kostanay\",\"value\":\"Kostanay\"},{\"code\":\"Kyzylorda\",\"value\":\"Kyzylorda\"},{\"code\":\"Pavlodar\",\"value\":\"Pavlodar\"},{\"code\":\"Petropavl\",\"value\":\"Petropavl\"},{\"code\":\"Semey\",\"value\":\"Semey\"},{\"code\":\"Shymkent\",\"value\":\"Shymkent\"},{\"code\":\"Taldykurgan\",\"value\":\"Taldykurgan\"},{\"code\":\"Taraz\",\"value\":\"Taraz\"},{\"code\":\"Uralsk\",\"value\":\"Uralsk\"},{\"code\":\"Ust-Kamenogorsk\",\"value\":\"Ust-Kamenogorsk\"},{\"code\":\"Zhezkazgan\",\"value\":\"Zhezkazgan\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_encapsulation",
+ "label": "Encapsulation",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Ethernet\"},{\"code\":\"8\",\"value\":\"PPP\"},{\"code\":\"12\",\"value\":\"CiscoHDLC\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_label",
+ "label": "Application Label",
+ "type": "string"
+ },
+ {
+ "name": "common_protocol_label",
+ "label": "Protocol Label",
+ "type": "string"
+ },
+ {
+ "name": "common_app_id",
+ "label": "Application ID",
+ "type": "int"
+ },
+ {
+ "name": "common_app_surrogate_id",
+ "label": "Surrogate ID",
+ "type": "int"
+ },
+ {
+ "name": "common_l7_protocol",
+ "label": "L7 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_start_time",
+ "label": "Start Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_end_time",
+ "label": "End Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"get_value\",\"appendTo\":\"common_recv_time\"}}"
+ },
+ {
+ "name": "common_establish_latency_ms",
+ "label": "Establish Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_con_duration_ms",
+ "label": "Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_stream_dir",
+ "label": "Stream Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"c2s\"},{\"code\":\"2\",\"value\":\"s2c\"},{\"code\":\"3\",\"value\":\"double\"}]}"
+ },
+ {
+ "name": "common_address_list",
+ "label": "Address List",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_has_dup_traffic",
+ "label": "Duplication Traffic",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_error",
+ "label": "Stream Error",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "label": "Session ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_link_info_c2s",
+ "label": "Link Info(c2s)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_link_info_s2c",
+ "label": "Link Info(s2c)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_ipfrag_num",
+ "label": "Fragmentation Packets(c2s)",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_ipfrag_num",
+ "label": "Fragmentation Packets(s2c)",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_tcp_lostlen",
+ "label": "Sequence Gap Loss(c2s)",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_tcp_lostlen",
+ "label": "Sequence Gap Loss(s2c)",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_tcp_unorder_num",
+ "label": "Unorder Packets(c2s)",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_tcp_unorder_num",
+ "label": "Unorder Packets(s2c)",
+ "type": "long"
+ },
+ {
+ "name": "common_processing_time",
+ "label": "Processing Time",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}",
+ "type": "long"
+ },
+ {
+ "name": "http_url",
+ "label": "Http.URL",
+ "type": "string"
+ },
+ {
+ "name": "http_host",
+ "label": "Http.Host",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "http_domain",
+ "label": "Http.Domain",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "http_request_line",
+ "label": "Http.Request Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_line",
+ "label": "Http.Response Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_request_header",
+ "label": "Http.Request Headers",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_response_header",
+ "label": "Http.Response Headers",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_request_body",
+ "label": "Http.Request Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"},\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_body",
+ "label": "Http.Response Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"},\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_request_body_key",
+ "label": "Http.Request Body Key",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_body_key",
+ "label": "Http.Response Body Key",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_proxy_flag",
+ "label": "Http.Proxy Flag",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_sequence",
+ "label": "Http.Sequence",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_snapshot",
+ "label": "Http.Snapshot",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_cookie",
+ "label": "Http.Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_referer",
+ "label": "Http.Referer",
+ "type": "string"
+ },
+ {
+ "name": "http_user_agent",
+ "label": "Http.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "http_content_length",
+ "label": "Http.Content Length",
+ "type": "string"
+ },
+ {
+ "name": "http_content_type",
+ "label": "Http.Content Type",
+ "type": "string"
+ },
+ {
+ "name": "http_set_cookie",
+ "label": "Http.Set Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_version",
+ "label": "Http.Version",
+ "type": "string"
+ },
+ {
+ "name": "http_response_lantency_ms",
+ "label": "Http.Response Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "http_session_duration_ms",
+ "label": "Http.Session Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "http_action_file_size",
+ "label": "Http.Action File Size",
+ "type": "int"
+ },
+ {
+ "name": "mail_protocol_type",
+ "label": "Mail.Protocol Type",
+ "type": "string"
+ },
+ {
+ "name": "mail_account",
+ "label": "Mail.Account",
+ "type": "string"
+ },
+ {
+ "name": "mail_from_cmd",
+ "label": "Mail.From CMD",
+ "type": "string"
+ },
+ {
+ "name": "mail_to_cmd",
+ "label": "Mail.To CMD",
+ "type": "string"
+ },
+ {
+ "name": "mail_from",
+ "label": "Mail.From",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"email\"}}"
+ },
+ {
+ "name": "mail_to",
+ "label": "Mail.To",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"email\"}}"
+ },
+ {
+ "name": "mail_cc",
+ "label": "Mail.CC",
+ "type": "string"
+ },
+ {
+ "name": "mail_bcc",
+ "label": "Mail.BCC",
+ "type": "string"
+ },
+ {
+ "name": "mail_subject",
+ "label": "Mail.Subject",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"decode_of_base64\",\"param\":\"$.mail_subject_charset\"}}"
+ },
+ {
+ "name": "mail_subject_charset",
+ "label": "Mail.Subject Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_content",
+ "label": "Mail.Content",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_content_charset",
+ "label": "Mail.Content Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_attachment_name",
+ "label": "Mail.Attachment",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"decode_of_base64\",\"param\":\"$.mail_attachment_name_charset\"}}"
+ },
+ {
+ "name": "mail_attachment_name_charset",
+ "label": "Mail.Attachment Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_attachment_content",
+ "label": "Mail.Attachment Content",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_eml_file",
+ "label": "Mail.EML File",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"}}"
+ },
+ {
+ "name": "mail_snapshot",
+ "label": "Mail.Snapshot",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "dns_message_id",
+ "label": "Dns.Message ID",
+ "type": "int"
+ },
+ {
+ "name": "dns_qr",
+ "label": "Dns.QR",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"REESPONSE\"}]}"
+ },
+ {
+ "name": "dns_opcode",
+ "label": "Dns.OPCODE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"IQUERY\"},{\"code\":\"2\",\"value\":\"STATUS\"},{\"code\":\"5\",\"value\":\"UPDATE\"}]}"
+ },
+ {
+ "name": "dns_aa",
+ "label": "Dns.AA",
+ "type": "int"
+ },
+ {
+ "name": "dns_tc",
+ "label": "Dns.TC",
+ "type": "int"
+ },
+ {
+ "name": "dns_rd",
+ "label": "Dns.RD",
+ "type": "int"
+ },
+ {
+ "name": "dns_ra",
+ "label": "Dns.RA",
+ "type": "int"
+ },
+ {
+ "name": "dns_rcode",
+ "label": "Dns.RCODE",
+ "type": "int"
+ },
+ {
+ "name": "dns_qdcount",
+ "label": "Dns.QDCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_ancount",
+ "label": "Dns.ANCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_nscount",
+ "label": "Dns.NSCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_arcount",
+ "label": "Dns.ARCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_qname",
+ "label": "Dns.QNAME",
+ "type": "string"
+ },
+ {
+ "name": "dns_qtype",
+ "label": "Dns.QTYPE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"A\"},{\"code\":\"2\",\"value\":\"NS\"},{\"code\":\"5\",\"value\":\"CNAME\"},{\"code\":\"6\",\"value\":\"SOA\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"12\",\"value\":\"PTR\"},{\"code\":\"13\",\"value\":\"HINFO\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"15\",\"value\":\"MX\"},{\"code\":\"28\",\"value\":\"AAAA\"}]}"
+ },
+ {
+ "name": "dns_qclass",
+ "label": "Dns.QCLASS",
+ "type": "int"
+ },
+ {
+ "name": "dns_cname",
+ "label": "Dns.CNAME",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "dns_sub",
+ "label": "Dns.SUB",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"DNS\"},{\"code\":\"2\",\"value\":\"DNSSEC\"}]}"
+ },
+ {
+ "name": "dns_rr",
+ "label": "Dns.RR",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_version",
+ "label": "SSL.Version",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_sni",
+ "label": "SSL.SNI",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "ssl_san",
+ "label": "SSL.SAN",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_cn",
+ "label": "SSL.CN",
+ "type": "string"
+ },
+ {
+ "name": "ssl_pinningst",
+ "label": "SSL.Pinning",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Not Pinning\"},{\"code\":\"1\",\"value\":\"Pinning\"},{\"code\":\"2\",\"value\":\"Maybe Pinning\"}]}"
+ },
+ {
+ "name": "ssl_intercept_state",
+ "label": "SSL.Intercept State",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Passthrough\"},{\"code\":\"1\",\"value\":\"Intercept\"},{\"code\":\"2\",\"value\":\"Shutdown\"}]}"
+ },
+ {
+ "name": "ssl_server_side_latency",
+ "label": "SSL.Server Side Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "ssl_client_side_latency",
+ "label": "SSL.Client Side Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "ssl_server_side_version",
+ "label": "SSL.Server Side Version",
+ "type": "string"
+ },
+ {
+ "name": "ssl_client_side_version",
+ "label": "SSL.Client Side Version",
+ "type": "string"
+ },
+ {
+ "name": "ssl_cert_verify",
+ "label": "SSL.Certificate Verify",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}]}"
+ },
+ {
+ "name": "ssl_error",
+ "label": "SSL.Error",
+ "type": "string"
+ },
+ {
+ "name": "ssl_con_latency_ms",
+ "label": "SSL.Connection Latency(ms)",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_ja3_fingerprint",
+ "label": "SSL.JA3",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "quic_version",
+ "label": "Quic.Version",
+ "type": "string"
+ },
+ {
+ "name": "quic_sni",
+ "label": "Quic.SNI",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "quic_user_agent",
+ "label": "Quic.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "ftp_account",
+ "label": "Ftp.Account",
+ "type": "string"
+ },
+ {
+ "name": "ftp_url",
+ "label": "Ftp.URL",
+ "type": "string"
+ },
+ {
+ "name": "ftp_content",
+ "label": "Ftp.Content",
+ "type": "string"
+ },
+ {
+ "name": "bgp_type",
+ "label": "BGP.Type",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "bgp_as_num",
+ "label": "BGP.AS Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "bgp_route",
+ "label": "BGP.Route",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_calling_account",
+ "label": "Voip.Calling Account",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_called_account",
+ "label": "Voip.Called Account",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_calling_number",
+ "label": "Voip.Calling Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_called_number",
+ "label": "Voip.Called Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "streaming_media_url",
+ "label": "Streaming.Media URL",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "streaming_media_protocol",
+ "label": "Streaming.Media Protocol",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "app_extra_info",
+ "label": "APP.Extra Info",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_client_ip.avsc b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_client_ip.avsc
new file mode 100644
index 0000000..98215ce
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_client_ip.avsc
@@ -0,0 +1,56 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "connection_record_log_common_client_ip",
+ "doc": "{\"primary_key\":\"common_log_id\",\"index_key\":\"common_client_ip\"}",
+ "fields": [
+ {
+ "name": "common_log_id",
+ "type": "long"
+ },
+ {
+ "name": "common_recv_time",
+ "type": "long"
+ },
+ {
+ "name": "common_policy_id",
+ "type": "long"
+ },
+ {
+ "name": "common_action",
+ "type": "int"
+ },
+ {
+ "name": "common_server_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_client_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_sled_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_entrance_id",
+ "type": "int"
+ },
+ {
+ "name": "common_subscriber_id",
+ "type": "string"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "type": "long"
+ },
+ {
+ "name": "http_domain",
+ "type": "string"
+ },
+ {
+ "name": "ssl_sni",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_server_ip.avsc b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_server_ip.avsc
new file mode 100644
index 0000000..b47449c
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_server_ip.avsc
@@ -0,0 +1,56 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "connection_record_log_common_server_ip",
+ "doc": "{\"primary_key\":\"common_log_id\",\"index_key\":\"common_server_ip\"}",
+ "fields": [
+ {
+ "name": "common_log_id",
+ "type": "long"
+ },
+ {
+ "name": "common_recv_time",
+ "type": "long"
+ },
+ {
+ "name": "common_policy_id",
+ "type": "long"
+ },
+ {
+ "name": "common_action",
+ "type": "int"
+ },
+ {
+ "name": "common_server_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_client_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_sled_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_entrance_id",
+ "type": "int"
+ },
+ {
+ "name": "common_subscriber_id",
+ "type": "string"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "type": "long"
+ },
+ {
+ "name": "http_domain",
+ "type": "string"
+ },
+ {
+ "name": "ssl_sni",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_subscriber_id.avsc b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_subscriber_id.avsc
new file mode 100644
index 0000000..358fe9e
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_common_subscriber_id.avsc
@@ -0,0 +1,56 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "connection_record_log_common_subscriber_id",
+ "doc": "{\"primary_key\":\"common_log_id\",\"index_key\":\"common_subscriber_id\"}",
+ "fields": [
+ {
+ "name": "common_log_id",
+ "type": "long"
+ },
+ {
+ "name": "common_recv_time",
+ "type": "long"
+ },
+ {
+ "name": "common_policy_id",
+ "type": "long"
+ },
+ {
+ "name": "common_action",
+ "type": "int"
+ },
+ {
+ "name": "common_server_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_client_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_sled_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_entrance_id",
+ "type": "int"
+ },
+ {
+ "name": "common_subscriber_id",
+ "type": "string"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "type": "long"
+ },
+ {
+ "name": "http_domain",
+ "type": "string"
+ },
+ {
+ "name": "ssl_sni",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/connection_record_log_http_domain.avsc b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_http_domain.avsc
new file mode 100644
index 0000000..0ca111c
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/connection_record_log_http_domain.avsc
@@ -0,0 +1,56 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "connection_record_log_http_domain",
+ "doc": "{\"primary_key\":\"common_log_id\",\"index_key\":\"http_domain\"}",
+ "fields": [
+ {
+ "name": "common_log_id",
+ "type": "long"
+ },
+ {
+ "name": "common_recv_time",
+ "type": "long"
+ },
+ {
+ "name": "common_policy_id",
+ "type": "long"
+ },
+ {
+ "name": "common_action",
+ "type": "int"
+ },
+ {
+ "name": "common_server_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_client_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_sled_ip",
+ "type": "string"
+ },
+ {
+ "name": "common_entrance_id",
+ "type": "int"
+ },
+ {
+ "name": "common_subscriber_id",
+ "type": "string"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "type": "long"
+ },
+ {
+ "name": "http_domain",
+ "type": "string"
+ },
+ {
+ "name": "ssl_sni",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/disks_cluster.avsc b/galaxy-query-engine/config/avro/clickhouse/disks_cluster.avsc
new file mode 100644
index 0000000..70777c6
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/disks_cluster.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "disks_cluster",
+ "fields": [
+ {
+ "name": "name",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/parts_cluster.avsc b/galaxy-query-engine/config/avro/clickhouse/parts_cluster.avsc
new file mode 100644
index 0000000..c311abf
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/parts_cluster.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "parts_cluster",
+ "fields": [
+ {
+ "name": "name",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/processes.avsc b/galaxy-query-engine/config/avro/clickhouse/processes.avsc
new file mode 100644
index 0000000..75d74a9
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/processes.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "processes",
+ "fields": [
+ {
+ "name": "query_id",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/proxy_event_log.avsc b/galaxy-query-engine/config/avro/clickhouse/proxy_event_log.avsc
new file mode 100644
index 0000000..aa7eb66
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/proxy_event_log.avsc
@@ -0,0 +1,636 @@
+{
+ "type": "record",
+ "name": "proxy_event_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\",\"schema_query\":{\"dimensions\":[\"common_server_ip\",\"common_client_ip\",\"common_policy_id\",\"common_sub_action\",\"common_sled_ip\",\"common_server_location\",\"common_subscriber_id\",\"common_server_port\",\"http_domain\",\"http_url\"],\"metrics\":[\"common_server_ip\",\"common_client_ip\",\"common_subscriber_id\",\"common_c2s_byte_num\",\"common_s2c_byte_num\"],\"filters\":[\"common_policy_id\",\"common_sub_action\",\"common_address_type\",\"common_server_ip\",\"common_client_ip\",\"common_server_port\",\"common_server_location\",\"common_subscriber_id\",\"common_l4_protocol\",\"common_data_center\",\"common_direction\",\"http_domain\",\"http_url\",\"http_content_type\"]},\"schema_type\":{\"HTTP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"http_url\",\"http_host\",\"http_domain\",\"http_request_line\",\"http_response_line\",\"http_request_header\",\"http_response_header\",\"http_request_body\",\"http_response_body\",\"http_request_body_key\",\"http_response_body_key\",\"http_proxy_flag\",\"http_sequence\",\"http_snapshot\",\"http_cookie\",\"http_referer\",\"http_user_agent\",\"http_content_length\",\"http_content_type\",\"http_set_cookie\",\"http_version\",\"http_response_lantency_ms\",\"http_session_duration_ms\",\"http_action_file_size\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"http_url\",\"common_sub_action\"]},\"DoH\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"doh_url\",\"doh_host\",\"doh_request_line\",\"doh_response_line\",\"doh_cookie\",\"doh_referer\",\"doh_user_agent\",\"doh_content_length\",\"doh_content_type\",\"doh_set_cookie\",\"doh_version\",\"doh_message_id\",\"doh_qr\",\"doh_opcode\",\"doh_aa\",\"doh_tc\",\"doh_rd\",\"doh_ra\",\"doh_rcode\",\"doh_qdcount\",\"doh_ancount\",\"doh_nscount\",\"doh_arcount\",\"doh_qname\",\"doh_qtype\",\"doh_qclass\",\"doh_cname\",\"doh_sub\",\"doh_rr\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_client_ip\",\"doh_url\",\"doh_qname\",\"common_server_port\"]}},\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_client_ip\",\"common_server_ip\",\"common_server_port\",\"common_sub_action\",\"common_schema_type\"]}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_subscriber_id",
+ "label": "Subscriber ID",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_client_ip",
+ "label": "Client IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn,radius_match\",\"appendTo\":\"common_client_asn,common_subscriber_id\"}}"
+ },
+ {
+ "name": "common_internal_ip",
+ "label": "Internal IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=69,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_client_port",
+ "label": "Client Port",
+ "type": "int"
+ },
+ {
+ "name": "common_l4_protocol",
+ "label": "L4 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_server_ip",
+ "label": "Server IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn\",\"appendTo\":\"common_server_asn\"}}"
+ },
+ {
+ "name": "common_server_port",
+ "label": "Server Port",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_external_ip",
+ "label": "External IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=73,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_action",
+ "label": "Action",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"None\"},{\"code\":\"1\",\"value\":\"Monitor\"},{\"code\":\"2\",\"value\":\"Intercept\"},{\"code\":\"16\",\"value\":\"Deny\"},{\"code\":\"48\",\"value\":\"Manipulation\"},{\"code\":\"128\",\"value\":\"Allow\"}]}"
+ },
+ {
+ "name": "common_direction",
+ "label": "Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"69\",\"value\":\"outbound\"},{\"code\":\"73\",\"value\":\"inbound\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sled_ip",
+ "label": "Sled IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_location",
+ "label": "Client Location",
+ "type": "string"
+ },
+ {
+ "name": "common_client_asn",
+ "label": "Client ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_server_location",
+ "label": "Server Location",
+ "type": "string"
+ },
+ {
+ "name": "common_server_asn",
+ "label": "Server ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_sessions",
+ "label": "Sessions",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_pkt_num",
+ "label": "Packets Sent",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_pkt_num",
+ "label": "Packets Received",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_byte_num",
+ "label": "Bytes Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_byte_num",
+ "label": "Bytes Received",
+ "type": "long"
+ },
+ {
+ "name": "common_service",
+ "label": "Service",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_schema_type",
+ "label": "Schema Type",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"data\":[{\"code\":\"HTTP\",\"value\":\"HTTP\"},{\"code\":\"DoH\",\"value\":\"DoH\"}]}"
+ },
+ {
+ "name": "common_user_tags",
+ "label": "User Tags",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sub_action",
+ "label": "Sub Action",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"allow\",\"value\":\"allow\"},{\"code\":\"deny\",\"value\":\"deny\"},{\"code\":\"monitor\",\"value\":\"monitor\"},{\"code\":\"replace\",\"value\":\"replace\"},{\"code\":\"redirect\",\"value\":\"redirect\"},{\"code\":\"insert\",\"value\":\"insert\"},{\"code\":\"hijack\",\"value\":\"hijack\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_isp",
+ "label": "ISP",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_tag",
+ "label": "Device Tag",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_data_center",
+ "label": "Data Center",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"Nur-sultan\",\"value\":\"Nur-sultan\"},{\"code\":\"Aktau\",\"value\":\"Aktau\"},{\"code\":\"Aktubinsk\",\"value\":\"Aktubinsk\"},{\"code\":\"Almaty\",\"value\":\"Almaty\"},{\"code\":\"Atyrau\",\"value\":\"Atyrau\"},{\"code\":\"Karaganda\",\"value\":\"Karaganda\"},{\"code\":\"Kokshetau\",\"value\":\"Kokshetau\"},{\"code\":\"Kostanay\",\"value\":\"Kostanay\"},{\"code\":\"Kyzylorda\",\"value\":\"Kyzylorda\"},{\"code\":\"Pavlodar\",\"value\":\"Pavlodar\"},{\"code\":\"Petropavl\",\"value\":\"Petropavl\"},{\"code\":\"Semey\",\"value\":\"Semey\"},{\"code\":\"Shymkent\",\"value\":\"Shymkent\"},{\"code\":\"Taldykurgan\",\"value\":\"Taldykurgan\"},{\"code\":\"Taraz\",\"value\":\"Taraz\"},{\"code\":\"Uralsk\",\"value\":\"Uralsk\"},{\"code\":\"Ust-Kamenogorsk\",\"value\":\"Ust-Kamenogorsk\"},{\"code\":\"Zhezkazgan\",\"value\":\"Zhezkazgan\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_encapsulation",
+ "label": "Encapsulation",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Ethernet\"},{\"code\":\"8\",\"value\":\"PPP\"},{\"code\":\"12\",\"value\":\"CiscoHDLC\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_label",
+ "label": "Application Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_protocol_label",
+ "label": "Protocol Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_id",
+ "label": "Application ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_surrogate_id",
+ "label": "Surrogate ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_l7_protocol",
+ "label": "L7 Protocol",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_start_time",
+ "label": "Start Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_end_time",
+ "label": "End Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"get_value\",\"appendTo\":\"common_recv_time\"}}"
+ },
+ {
+ "name": "common_establish_latency_ms",
+ "label": "Establish Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_con_duration_ms",
+ "label": "Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_stream_dir",
+ "label": "Stream Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"c2s\"},{\"code\":\"2\",\"value\":\"s2c\"},{\"code\":\"3\",\"value\":\"double\"}]}"
+ },
+ {
+ "name": "common_address_list",
+ "label": "Address List",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_has_dup_traffic",
+ "label": "Duplication Traffic",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_error",
+ "label": "Stream Error",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "label": "Session ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_link_info_c2s",
+ "label": "Link Info(c2s)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_link_info_s2c",
+ "label": "Link Info(s2c)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_ipfrag_num",
+ "label": "Fragmentation Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_ipfrag_num",
+ "label": "Fragmentation Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_lostlen",
+ "label": "Sequence Gap Loss(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_lostlen",
+ "label": "Sequence Gap Loss(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_unorder_num",
+ "label": "Unorder Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_unorder_num",
+ "label": "Unorder Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_processing_time",
+ "label": "Processing Time",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}",
+ "type": "long"
+ },
+ {
+ "name": "http_url",
+ "label": "Http.URL",
+ "type": "string"
+ },
+ {
+ "name": "http_host",
+ "label": "Http.Host",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "http_domain",
+ "label": "Http.Domain",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "http_request_line",
+ "label": "Http.Request Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_line",
+ "label": "Http.Response Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_request_header",
+ "label": "Http.Request Header",
+ "type": "string"
+ },
+ {
+ "name": "http_response_header",
+ "label": "Http.Response Header",
+ "type": "string"
+ },
+ {
+ "name": "http_request_body",
+ "label": "Http.Request Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"}}"
+ },
+ {
+ "name": "http_response_body",
+ "label": "Http.Response Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"}}"
+ },
+ {
+ "name": "http_request_body_key",
+ "label": "Http.Request Body Key",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_body_key",
+ "label": "Http.Response Body Key",
+ "type":"string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_proxy_flag",
+ "label": "Http.Proxy Flag",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_sequence",
+ "label": "Http.Sequence",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_snapshot",
+ "label": "Http.Snapshot",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_cookie",
+ "label": "Http.Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_referer",
+ "label": "Http.Referer",
+ "type": "string"
+ },
+ {
+ "name": "http_user_agent",
+ "label": "Http.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "http_content_length",
+ "label": "Http.Content Length",
+ "type": "string"
+ },
+ {
+ "name": "http_content_type",
+ "label": "Http.Content Type",
+ "type": "string"
+ },
+ {
+ "name": "http_set_cookie",
+ "label": "Http.Set Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_version",
+ "label": "Http.Version",
+ "type": "string"
+ },
+ {
+ "name": "http_response_lantency_ms",
+ "label": "Http.Response Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "http_session_duration_ms",
+ "label": "Http.Session Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "http_action_file_size",
+ "label": "Http.Action File Size",
+ "type": "int"
+ },
+ {
+ "name": "doh_url",
+ "label": "DoH.URL",
+ "type": "string"
+ },
+ {
+ "name": "doh_host",
+ "label": "DoH.Host",
+ "type": "string"
+ },
+ {
+ "name": "doh_request_line",
+ "label": "DoH.Request Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "doh_response_line",
+ "label": "DoH.Response Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "doh_cookie",
+ "label": "DoH.Cookie",
+ "type": "string"
+ },
+ {
+ "name": "doh_referer",
+ "label": "DoH.Referer",
+ "type": "string"
+ },
+ {
+ "name": "doh_user_agent",
+ "label": "DoH.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "doh_content_length",
+ "label": "DoH.Content Length",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "doh_content_type",
+ "label": "DoH.Content Type",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "doh_set_cookie",
+ "label": "DoH.Set Cookie",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "doh_version",
+ "label": "DoH.Version",
+ "type": "string"
+ },
+ {
+ "name": "doh_message_id",
+ "label": "DoH.Message ID",
+ "type": "int"
+ },
+ {
+ "name": "doh_qr",
+ "label": "DoH.QR",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"REESPONSE\"}]}"
+ },
+ {
+ "name": "doh_opcode",
+ "label": "DoH.OPCODE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"IQUERY\"},{\"code\":\"2\",\"value\":\"STATUS\"},{\"code\":\"5\",\"value\":\"UPDATE\"}]}"
+ },
+ {
+ "name": "doh_aa",
+ "label": "DoH.AA",
+ "type": "int"
+ },
+ {
+ "name": "doh_tc",
+ "label": "DoH.TC",
+ "type": "int"
+ },
+ {
+ "name": "doh_rd",
+ "label": "DoH.RD",
+ "type": "int"
+ },
+ {
+ "name": "doh_ra",
+ "label": "DoH.RA",
+ "type": "int"
+ },
+ {
+ "name": "doh_rcode",
+ "label": "DoH.RCODE",
+ "type": "int"
+ },
+ {
+ "name": "doh_qdcount",
+ "label": "DoH.QDCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "doh_ancount",
+ "label": "DoH.ANCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "doh_nscount",
+ "label": "DoH.NSCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "doh_arcount",
+ "label": "DoH.ARCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "doh_qname",
+ "label": "DoH.QNAME",
+ "type": "string"
+ },
+ {
+ "name": "doh_qtype",
+ "label": "DoH.QTYPE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"A\"},{\"code\":\"2\",\"value\":\"NS\"},{\"code\":\"5\",\"value\":\"CNAME\"},{\"code\":\"6\",\"value\":\"SOA\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"12\",\"value\":\"PTR\"},{\"code\":\"13\",\"value\":\"HINFO\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"15\",\"value\":\"MX\"},{\"code\":\"28\",\"value\":\"AAAA\"}]}"
+ },
+ {
+ "name": "doh_qclass",
+ "label": "DoH.QCLASS",
+ "type": "int"
+ },
+ {
+ "name": "doh_cname",
+ "label": "DoH.CNAME",
+ "type": "string"
+ },
+ {
+ "name": "doh_sub",
+ "label": "DoH.SUB",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"DNS\"},{\"code\":\"2\",\"value\":\"DNSSEC\"}]}"
+ },
+ {
+ "name": "doh_rr",
+ "label": "DoH.RR",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/proxy_ip_info.avsc b/galaxy-query-engine/config/avro/clickhouse/proxy_ip_info.avsc
new file mode 100644
index 0000000..42e944d
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/proxy_ip_info.avsc
@@ -0,0 +1,22 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "proxy_ip_info",
+ "fields": [
+ {
+ "name": "stat_time",
+ "type": "int"
+ },
+ {
+ "name": "policy_id",
+ "type": "long"
+ },
+ {
+ "name": "ip_list",
+ "type": {
+ "type": "array",
+ "items": "string"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/query_log.avsc b/galaxy-query-engine/config/avro/clickhouse/query_log.avsc
new file mode 100644
index 0000000..4f5e8d5
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/query_log.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "query_log",
+ "fields": [
+ {
+ "name": "query_id",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/query_log_cluster.avsc b/galaxy-query-engine/config/avro/clickhouse/query_log_cluster.avsc
new file mode 100644
index 0000000..d6e7583
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/query_log_cluster.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "query_log_cluster",
+ "fields": [
+ {
+ "name": "type",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/radius_onff_log.avsc b/galaxy-query-engine/config/avro/clickhouse/radius_onff_log.avsc
new file mode 100644
index 0000000..9201ebb
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/radius_onff_log.avsc
@@ -0,0 +1,37 @@
+{
+ "type": "record",
+ "name": "radius_onff_log",
+ "namespace": "tsg_galaxy_v3",
+ "fields": [
+ {
+ "name": "event_timestamp",
+ "label": "Event Time",
+ "type": "long"
+ },
+ {
+ "name": "account",
+ "label": "Account",
+ "type": "string"
+ },
+ {
+ "name": "framed_ip",
+ "label": "Framed IP",
+ "type": "string"
+ },
+ {
+ "name": "acct_session_id",
+ "label": "Acct Session ID",
+ "type": "string"
+ },
+ {
+ "name": "acct_status_type",
+ "label": "Acct Status Type",
+ "type": "int"
+ },
+ {
+ "name": "acct_session_time",
+ "label": "Acct Session Time",
+ "type": "int"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/radius_record_log.avsc b/galaxy-query-engine/config/avro/clickhouse/radius_record_log.avsc
new file mode 100644
index 0000000..d578adb
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/radius_record_log.avsc
@@ -0,0 +1,497 @@
+{
+ "type": "record",
+ "name": "radius_record_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\",\"schema_query\":{\"dimensions\":[\"radius_nas_ip\",\"radius_framed_ip\",\"common_subscriber_id\"],\"metrics\":[\"radius_framed_ip\",\"radius_event_timestamp\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\"],\"filters\":[\"radius_framed_ip\",\"common_subscriber_id\",\"radius_packet_type\",\"radius_acct_session_id\",\"radius_acct_multi_session_id\",\"radius_acct_status_type\"]},\"schema_type\":{\"RADIUS\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"radius_packet_type\",\"radius_nas_ip\",\"radius_framed_ip\",\"radius_account\",\"radius_session_timeout\",\"radius_idle_timeout\",\"radius_acct_status_type\",\"radius_acct_terminate_cause\",\"radius_event_timestamp\",\"radius_nas_port\",\"radius_service_type\",\"radius_framed_protocol\",\"radius_callback_number\",\"radius_callback_id\",\"radius_termination_action\",\"radius_called_station_id\",\"radius_calling_station_id\",\"radius_acct_delay_time\",\"radius_acct_session_id\",\"radius_acct_multi_session_id\",\"radius_acct_input_octets\",\"radius_acct_output_octets\",\"radius_acct_input_packets\",\"radius_acct_output_packets\",\"radius_acct_session_time\",\"radius_acct_link_count\",\"radius_acct_interim_interval\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"radius_nas_ip\",\"radius_framed_ip\",\"radius_acct_status_type\"]}},\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_subscriber_id\",\"radius_nas_ip\",\"radius_framed_ip\",\"radius_acct_status_type\"]}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc":"{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_subscriber_id",
+ "label": "Subscriber ID",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_client_ip",
+ "label": "Client IP",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_client_port",
+ "label": "Client Port",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_internal_ip",
+ "label": "Internal IP",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_l4_protocol",
+ "label": "L4 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_server_ip",
+ "label": "Server IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn\",\"appendTo\":\"common_server_asn\"}}"
+ },
+ {
+ "name": "common_server_port",
+ "label": "Server Port",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_external_ip",
+ "label": "External IP",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_action",
+ "label": "Action",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\",\"data\":[{\"code\":\"0\",\"value\":\"None\"},{\"code\":\"1\",\"value\":\"Monitor\"},{\"code\":\"2\",\"value\":\"Intercept\"},{\"code\":\"16\",\"value\":\"Deny\"},{\"code\":\"48\",\"value\":\"Manipulation\"},{\"code\":\"128\",\"value\":\"Allow\"}]}"
+ },
+ {
+ "name": "common_direction",
+ "label": "Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"69\",\"value\":\"outbound\"},{\"code\":\"73\",\"value\":\"inbound\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sled_ip",
+ "label": "Sled IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_location",
+ "label": "Client Location",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_client_asn",
+ "label": "Client ASN",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_server_location",
+ "label": "Server Location",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_server_asn",
+ "label": "Server ASN",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_sessions",
+ "label": "Sessions",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_pkt_num",
+ "label": "Packets Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_pkt_num",
+ "label": "Packets Received",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_byte_num",
+ "label": "Bytes Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_byte_num",
+ "label": "Bytes Received",
+ "type": "long"
+ },
+ {
+ "name": "common_service",
+ "label": "Service",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_schema_type",
+ "label": "Schema Type",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"BASE\",\"value\":\"BASE\"},{\"code\":\"HTTP\",\"value\":\"HTTP\"},{\"code\":\"MAIL\",\"value\":\"MAIL\"},{\"code\":\"DNS\",\"value\":\"DNS\"},{\"code\":\"SSL\",\"value\":\"SSL\"},{\"code\":\"FTP\",\"value\":\"FTP\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_user_tags",
+ "label": "User Tags",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sub_action",
+ "label": "Sub Action",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_isp",
+ "label": "ISP",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_tag",
+ "label": "Device Tag",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_data_center",
+ "label": "Data Center",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"Nur-sultan\",\"value\":\"Nur-sultan\"},{\"code\":\"Aktau\",\"value\":\"Aktau\"},{\"code\":\"Aktubinsk\",\"value\":\"Aktubinsk\"},{\"code\":\"Almaty\",\"value\":\"Almaty\"},{\"code\":\"Atyrau\",\"value\":\"Atyrau\"},{\"code\":\"Karaganda\",\"value\":\"Karaganda\"},{\"code\":\"Kokshetau\",\"value\":\"Kokshetau\"},{\"code\":\"Kostanay\",\"value\":\"Kostanay\"},{\"code\":\"Kyzylorda\",\"value\":\"Kyzylorda\"},{\"code\":\"Pavlodar\",\"value\":\"Pavlodar\"},{\"code\":\"Petropavl\",\"value\":\"Petropavl\"},{\"code\":\"Semey\",\"value\":\"Semey\"},{\"code\":\"Shymkent\",\"value\":\"Shymkent\"},{\"code\":\"Taldykurgan\",\"value\":\"Taldykurgan\"},{\"code\":\"Taraz\",\"value\":\"Taraz\"},{\"code\":\"Uralsk\",\"value\":\"Uralsk\"},{\"code\":\"Ust-Kamenogorsk\",\"value\":\"Ust-Kamenogorsk\"},{\"code\":\"Zhezkazgan\",\"value\":\"Zhezkazgan\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_encapsulation",
+ "label": "Encapsulation",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Ethernet\"},{\"code\":\"8\",\"value\":\"PPP\"},{\"code\":\"12\",\"value\":\"CiscoHDLC\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_label",
+ "label": "Application Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_protocol_label",
+ "label": "Protocol Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_id",
+ "label": "Application ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_surrogate_id",
+ "label": "Surrogate ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_l7_protocol",
+ "label": "L7 Protocol",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_start_time",
+ "label": "Start Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_end_time",
+ "label": "End Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"get_value\",\"appendTo\":\"common_recv_time\"},\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_establish_latency_ms",
+ "label": "Establish Latency(ms)",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_con_duration_ms",
+ "label": "Duration(ms)",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_dir",
+ "label": "Stream Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"c2s\"},{\"code\":\"2\",\"value\":\"s2c\"},{\"code\":\"3\",\"value\":\"double\"}]}"
+ },
+ {
+ "name": "common_address_list",
+ "label": "Address List",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_has_dup_traffic",
+ "label": "Duplication Traffic",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_error",
+ "label": "Stream Error",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "label": "Session ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_link_info_c2s",
+ "label": "Link Info(c2s)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_link_info_s2c",
+ "label": "Link Info(s2c)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_ipfrag_num",
+ "label": "Fragmentation Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_ipfrag_num",
+ "label": "Fragmentation Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_lostlen",
+ "label": "Sequence Gap Loss(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_lostlen",
+ "label": "Sequence Gap Loss(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_unorder_num",
+ "label": "Unorder Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_unorder_num",
+ "label": "Unorder Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_processing_time",
+ "label": "Processing Time",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}",
+ "type": "long"
+ },
+ {
+ "name": "radius_packet_type",
+ "label": "Packet Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"Access-Request\"},{\"code\":\"2\",\"value\":\"Access-Accept\"},{\"code\":\"3\",\"value\":\"Access-Reject\"},{\"code\":\"4\",\"value\":\"Accounting-Request\"},{\"code\":\"5\",\"value\":\"Accounting-Response\"},{\"code\":\"11\",\"value\":\"Access-Challenge\"}]}"
+ },
+ {
+ "name": "radius_account",
+ "label": "Account",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"get_value\",\"appendTo\":\"common_subscriber_id\"}}"
+ },
+ {
+ "name": "radius_nas_ip",
+ "label": "Nas IP",
+ "type": "string"
+ },
+ {
+ "name": "radius_framed_ip",
+ "label": "Framed IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "radius_session_timeout",
+ "label": "Session Timeout",
+ "type": "int"
+ },
+ {
+ "name": "radius_idle_timeout",
+ "label": "Idle Timeout",
+ "type": "int"
+ },
+ {
+ "name": "radius_acct_status_type",
+ "label": "ACC Status Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"Start\"},{\"code\":\"2\",\"value\":\"Stop\"},{\"code\":\"3\",\"value\":\"Interim-Update\"},{\"code\":\"7\",\"value\":\"Accounting-On\"},{\"code\":\"8\",\"value\":\"Accounting-Off\"}]}"
+ },
+ {
+ "name": "radius_acct_terminate_cause",
+ "label": "Acct Terminate Cause",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"User Request\"},{\"code\":\"2\",\"value\":\"Lost Carrier\"},{\"code\":\"3\",\"value\":\"Lost Service\"},{\"code\":\"4\",\"value\":\"Idle Timeout\"},{\"code\":\"5\",\"value\":\"Session Timeout\"},{\"code\":\"6\",\"value\":\"Admin Reset\"},{\"code\":\"7\",\"value\":\"Admin Reboot\"},{\"code\":\"8\",\"value\":\"Port Error\"},{\"code\":\"9\",\"value\":\"NAS Error\"},{\"code\":\"10\",\"value\":\"NAS Request\"},{\"code\":\"11\",\"value\":\"NAS Reboot\"},{\"code\":\"12\",\"value\":\"Port Unneeded\"},{\"code\":\"13\",\"value\":\"Port Preempted\"},{\"code\":\"14\",\"value\":\"Port Suspended\"},{\"code\":\"15\",\"value\":\"Service Unavailable\"},{\"code\":\"16\",\"value\":\"Callback\"},{\"code\":\"17\",\"value\":\"User Error\"},{\"code\":\"18\",\"value\":\"Host Request\"}]}"
+ },
+ {
+ "name": "radius_event_timestamp",
+ "label": "Event Timestamp",
+ "type": "int"
+ },
+ {
+ "name": "radius_service_type",
+ "label": "Service Type",
+ "type": "int"
+ },
+ {
+ "name": "radius_nas_port",
+ "label": "Nas Port",
+ "type": "int"
+ },
+ {
+ "name": "radius_framed_protocol",
+ "label": "Framed Protocol",
+ "type": "int"
+ },
+ {
+ "name": "radius_callback_number",
+ "label": "Callback Number",
+ "type": "string"
+ },
+ {
+ "name": "radius_callback_id",
+ "label": "Callback ID",
+ "type": "string"
+ },
+ {
+ "name": "radius_termination_action",
+ "label": "Termination Action",
+ "type": "int"
+ },
+ {
+ "name": "radius_called_station_id",
+ "label": "Called Station Id",
+ "type": "string"
+ },
+ {
+ "name": "radius_calling_station_id",
+ "label": "Calling Station Id",
+ "type": "string"
+ },
+ {
+ "name": "radius_acct_delay_time",
+ "label": "Acct Delay Time",
+ "type": "int"
+ },
+ {
+ "name": "radius_acct_session_id",
+ "label": "Acct Session ID",
+ "type": "string"
+ },
+ {
+ "name": "radius_acct_multi_session_id",
+ "label": "Acct Multi Session ID",
+ "type": "string"
+ },
+ {
+ "name": "radius_acct_input_octets",
+ "label": "Acct Input Octets",
+ "type": "long"
+ },
+ {
+ "name": "radius_acct_output_octets",
+ "label": "Acct Output Octets",
+ "type": "long"
+ },
+ {
+ "name": "radius_acct_input_packets",
+ "label": "Acct Input Packets",
+ "type": "long"
+ },
+ {
+ "name": "radius_acct_output_packets",
+ "label": "Acct Output Packets",
+ "type": "long"
+ },
+ {
+ "name": "radius_acct_session_time",
+ "label": "Acct Session Time",
+ "type": "int"
+ },
+ {
+ "name": "radius_acct_link_count",
+ "label": "Acct Link Count",
+ "type": "int"
+ },
+ {
+ "name": "radius_acct_interim_interval",
+ "label": "Acct Interim Interval",
+ "type": "int"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/security_event_log.avsc b/galaxy-query-engine/config/avro/clickhouse/security_event_log.avsc
new file mode 100644
index 0000000..9a98f67
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/security_event_log.avsc
@@ -0,0 +1,835 @@
+{
+ "type": "record",
+ "name": "security_event_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\",\"schema_query\":{\"dimensions\":[\"common_server_ip\",\"common_client_ip\",\"common_policy_id\",\"common_action\",\"common_sled_ip\",\"common_server_location\",\"common_subscriber_id\",\"common_server_port\",\"http_domain\",\"http_url\",\"ssl_sni\"],\"metrics\":[\"common_server_ip\",\"common_client_ip\",\"common_subscriber_id\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\"],\"filters\":[\"common_policy_id\",\"common_action\",\"common_address_type\",\"common_server_ip\",\"common_client_ip\",\"common_server_port\",\"common_server_location\",\"common_subscriber_id\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_l4_protocol\",\"common_data_center\",\"common_direction\",\"http_domain\",\"http_url\",\"http_content_type\",\"ssl_sni\",\"ssl_pinningst\",\"ssl_intercept_state\"]},\"schema_type\":{\"BASE\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_server_ip\",\"common_server_port\"]},\"HTTP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"http_url\",\"http_host\",\"http_domain\",\"http_request_line\",\"http_response_line\",\"http_request_header\",\"http_response_header\",\"http_request_body\",\"http_response_body\",\"http_request_body_key\",\"http_response_body_key\",\"http_proxy_flag\",\"http_sequence\",\"http_snapshot\",\"http_cookie\",\"http_referer\",\"http_user_agent\",\"http_content_length\",\"http_content_type\",\"http_set_cookie\",\"http_version\",\"http_response_lantency_ms\",\"http_session_duration_ms\",\"http_action_file_size\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"http_url\",\"common_server_port\"]},\"MAIL\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"mail_protocol_type\",\"mail_account\",\"mail_from_cmd\",\"mail_to_cmd\",\"mail_from\",\"mail_to\",\"mail_cc\",\"mail_bcc\",\"mail_subject\",\"mail_subject_charset\",\"mail_content\",\"mail_content_charset\",\"mail_attachment_name\",\"mail_attachment_name_charset\",\"mail_attachment_content\",\"mail_eml_file\",\"mail_snapshot\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"mail_from\",\"mail_to\",\"mail_subject\"]},\"DNS\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"dns_message_id\",\"dns_qr\",\"dns_opcode\",\"dns_aa\",\"dns_tc\",\"dns_rd\",\"dns_ra\",\"dns_rcode\",\"dns_qdcount\",\"dns_ancount\",\"dns_nscount\",\"dns_arcount\",\"dns_qname\",\"dns_qtype\",\"dns_qclass\",\"dns_cname\",\"dns_sub\",\"dns_rr\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_client_ip\",\"dns_qr\",\"dns_qname\",\"dns_qtype\"]},\"SSL\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"ssl_sni\",\"ssl_san\",\"ssl_cn\",\"ssl_pinningst\",\"ssl_intercept_state\",\"ssl_server_side_latency\",\"ssl_client_side_latency\",\"ssl_server_side_version\",\"ssl_client_side_version\",\"ssl_cert_verify\",\"ssl_error\",\"ssl_con_latency_ms\",\"ssl_ja3_fingerprint\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"ssl_sni\",\"common_server_ip\",\"common_server_port\"]},\"QUIC\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"quic_version\",\"quic_sni\",\"quic_user_agent\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"quic_sni\",\"common_server_ip\",\"common_server_port\"]},\"FTP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"ftp_account\",\"ftp_url\",\"ftp_content\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"ftp_url\",\"common_server_ip\",\"common_server_port\"]},\"BGP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"bgp_type\",\"bgp_as_num\",\"bgp_route\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"bgp_type\",\"bgp_as_num\",\"common_server_ip\",\"common_server_port\"]},\"VOIP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"voip_calling_account\",\"voip_called_account\",\"voip_calling_number\",\"voip_called_number\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"voip_calling_account\",\"voip_called_account\",\"common_server_ip\",\"common_server_port\"]},\"APP\":{\"columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_client_port\",\"common_internal_ip\",\"common_l4_protocol\",\"common_address_type\",\"common_server_ip\",\"common_server_port\",\"common_external_ip\",\"common_action\",\"common_direction\",\"common_entrance_id\",\"common_sled_ip\",\"common_client_location\",\"common_client_asn\",\"common_server_location\",\"common_server_asn\",\"common_sessions\",\"common_c2s_pkt_num\",\"common_s2c_pkt_num\",\"common_c2s_byte_num\",\"common_s2c_byte_num\",\"common_service\",\"common_schema_type\",\"common_user_tags\",\"common_sub_action\",\"common_user_region\",\"common_device_id\",\"common_link_id\",\"common_isp\",\"common_device_tag\",\"common_data_center\",\"common_encapsulation\",\"common_app_label\",\"common_protocol_label\",\"common_app_id\",\"common_app_surrogate_id\",\"common_l7_protocol\",\"common_start_time\",\"common_end_time\",\"common_establish_latency_ms\",\"common_con_duration_ms\",\"common_stream_dir\",\"common_address_list\",\"common_has_dup_traffic\",\"common_stream_error\",\"common_stream_trace_id\",\"common_link_info_c2s\",\"common_link_info_s2c\",\"common_c2s_ipfrag_num\",\"common_s2c_ipfrag_num\",\"common_c2s_tcp_lostlen\",\"common_s2c_tcp_lostlen\",\"common_c2s_tcp_unorder_num\",\"common_s2c_tcp_unorder_num\",\"common_processing_time\",\"app_extra_info\"],\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_app_id\",\"common_app_label\",\"app_extra_info\",\"common_server_ip\",\"common_server_port\"]}},\"default_columns\":[\"common_recv_time\",\"common_log_id\",\"common_policy_id\",\"common_subscriber_id\",\"common_client_ip\",\"common_server_ip\",\"common_server_port\",\"common_schema_type\"]}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_subscriber_id",
+ "label": "Subscriber ID",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_client_ip",
+ "label": "Client IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn,radius_match\",\"appendTo\":\"common_client_asn,common_subscriber_id\"}}"
+ },
+ {
+ "name": "common_internal_ip",
+ "label": "Internal IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=69,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_client_port",
+ "label": "Client Port",
+ "type": "int"
+ },
+ {
+ "name": "common_l4_protocol",
+ "label": "L4 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_server_ip",
+ "label": "Server IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"geo_asn\",\"appendTo\":\"common_server_asn\"}}"
+ },
+ {
+ "name": "common_server_port",
+ "label": "Server Port",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_external_ip",
+ "label": "External IP",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"ip\"},\"format\":{\"functions\":\"if\",\"param\":\"$.common_direction=73,$.common_client_ip,$.common_server_ip\"}}"
+ },
+ {
+ "name": "common_action",
+ "label": "Action",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\",\"data\":[{\"code\":\"1\",\"value\":\"Monitor\"},{\"code\":\"2\",\"value\":\"Intercept\"},{\"code\":\"16\",\"value\":\"Deny\"},{\"code\":\"128\",\"value\":\"Allow\"}]}"
+ },
+ {
+ "name": "common_direction",
+ "label": "Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"69\",\"value\":\"outbound\"},{\"code\":\"73\",\"value\":\"inbound\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sled_ip",
+ "label": "Sled IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_location",
+ "label": "Client Location",
+ "type": "string"
+ },
+ {
+ "name": "common_client_asn",
+ "label": "Client ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_server_location",
+ "label": "Server Location",
+ "type": "string"
+ },
+ {
+ "name": "common_server_asn",
+ "label": "Server ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_sessions",
+ "label": "Sessions",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_pkt_num",
+ "label": "Packets Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_pkt_num",
+ "label": "Packets Received",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_byte_num",
+ "label": "Bytes Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_byte_num",
+ "label": "Bytes Received",
+ "type": "long"
+ },
+ {
+ "name": "common_service",
+ "label": "Service",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_schema_type",
+ "label": "Schema Type",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"HTTP\",\"value\":\"HTTP\"},{\"code\":\"MAIL\",\"value\":\"MAIL\"},{\"code\":\"DNS\",\"value\":\"DNS\"},{\"code\":\"SSL\",\"value\":\"SSL\"},{\"code\":\"QUIC\",\"value\":\"QUIC\"},{\"code\":\"FTP\",\"value\":\"FTP\"},{\"code\":\"APP\",\"value\":\"APP\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_user_tags",
+ "label": "User Tags",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sub_action",
+ "label": "Sub Action",
+ "type": "string"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_isp",
+ "label": "ISP",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_tag",
+ "label": "Device Tag",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_data_center",
+ "label": "Data Center",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"Nur-sultan\",\"value\":\"Nur-sultan\"},{\"code\":\"Aktau\",\"value\":\"Aktau\"},{\"code\":\"Aktubinsk\",\"value\":\"Aktubinsk\"},{\"code\":\"Almaty\",\"value\":\"Almaty\"},{\"code\":\"Atyrau\",\"value\":\"Atyrau\"},{\"code\":\"Karaganda\",\"value\":\"Karaganda\"},{\"code\":\"Kokshetau\",\"value\":\"Kokshetau\"},{\"code\":\"Kostanay\",\"value\":\"Kostanay\"},{\"code\":\"Kyzylorda\",\"value\":\"Kyzylorda\"},{\"code\":\"Pavlodar\",\"value\":\"Pavlodar\"},{\"code\":\"Petropavl\",\"value\":\"Petropavl\"},{\"code\":\"Semey\",\"value\":\"Semey\"},{\"code\":\"Shymkent\",\"value\":\"Shymkent\"},{\"code\":\"Taldykurgan\",\"value\":\"Taldykurgan\"},{\"code\":\"Taraz\",\"value\":\"Taraz\"},{\"code\":\"Uralsk\",\"value\":\"Uralsk\"},{\"code\":\"Ust-Kamenogorsk\",\"value\":\"Ust-Kamenogorsk\"},{\"code\":\"Zhezkazgan\",\"value\":\"Zhezkazgan\"}],\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_encapsulation",
+ "label": "Encapsulation",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Ethernet\"},{\"code\":\"8\",\"value\":\"PPP\"},{\"code\":\"12\",\"value\":\"CiscoHDLC\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_app_label",
+ "label": "Application Label",
+ "type": "string"
+ },
+ {
+ "name": "common_protocol_label",
+ "label": "Protocol Label",
+ "type": "string"
+ },
+ {
+ "name": "common_app_id",
+ "label": "Application ID",
+ "type": "int"
+ },
+ {
+ "name": "common_app_surrogate_id",
+ "label": "Surrogate ID",
+ "type": "int"
+ },
+ {
+ "name": "common_l7_protocol",
+ "label": "L7 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_start_time",
+ "label": "Start Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"}}"
+ },
+ {
+ "name": "common_end_time",
+ "label": "End Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"get_value\",\"appendTo\":\"common_recv_time\"}}"
+ },
+ {
+ "name": "common_establish_latency_ms",
+ "label": "Establish Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_con_duration_ms",
+ "label": "Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "common_stream_dir",
+ "label": "Stream Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"c2s\"},{\"code\":\"2\",\"value\":\"s2c\"},{\"code\":\"3\",\"value\":\"double\"}]}"
+ },
+ {
+ "name": "common_address_list",
+ "label": "Address List",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_has_dup_traffic",
+ "label": "Duplication Traffic",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_error",
+ "label": "Stream Error",
+ "type": "string"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "label": "Session ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_link_info_c2s",
+ "label": "Link Info(c2s)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_link_info_s2c",
+ "label": "Link Info(s2c)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_ipfrag_num",
+ "label": "Fragmentation Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_ipfrag_num",
+ "label": "Fragmentation Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_lostlen",
+ "label": "Sequence Gap Loss(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_lostlen",
+ "label": "Sequence Gap Loss(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_unorder_num",
+ "label": "Unorder Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_unorder_num",
+ "label": "Unorder Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_processing_time",
+ "label": "Processing Time",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}",
+ "type": "long"
+ },
+ {
+ "name": "http_url",
+ "label": "Http.URL",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "http_host",
+ "label": "Http.Host",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "http_domain",
+ "label": "Http.Domain",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "http_request_line",
+ "label": "Http.Request Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_line",
+ "label": "Http.Response Line",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_request_header",
+ "label": "Http.Request Header",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_response_header",
+ "label": "Http.Response Header",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_request_body",
+ "label": "Http.Request Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"},\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_body",
+ "label": "Http.Response Body",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"},\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_request_body_key",
+ "label": "Http.Request Body Key",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_response_body_key",
+ "label": "Http.Response Body Key",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "http_proxy_flag",
+ "label": "http.Proxy Flag",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_sequence",
+ "label": "Http.Sequence",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_snapshot",
+ "label": "Http.Snapshot",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "http_cookie",
+ "label": "Http.Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_referer",
+ "label": "Http.Referer",
+ "type": "string"
+ },
+ {
+ "name": "http_user_agent",
+ "label": "Http.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "http_content_length",
+ "label": "Http.Content Length",
+ "type": "string"
+ },
+ {
+ "name": "http_content_type",
+ "label": "Http.Content Type",
+ "type": "string"
+ },
+ {
+ "name": "http_set_cookie",
+ "label": "Http.Set Cookie",
+ "type": "string"
+ },
+ {
+ "name": "http_version",
+ "label": "Http.Version",
+ "type": "string"
+ },
+ {
+ "name": "http_response_lantency_ms",
+ "label": "Http.Response Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "http_action_file_size",
+ "label": "Http.Action File Size",
+ "type": "int"
+ },
+ {
+ "name": "http_session_duration_ms",
+ "label": "Http.Session Duration(ms)",
+ "type": "int"
+ },
+ {
+ "name": "mail_protocol_type",
+ "label": "Mail.Protocol Type",
+ "type": "string"
+ },
+ {
+ "name": "mail_account",
+ "label": "Mail.Account",
+ "type": "string"
+ },
+ {
+ "name": "mail_from_cmd",
+ "label": "Mail.From CMD",
+ "type": "string"
+ },
+ {
+ "name": "mail_to_cmd",
+ "label": "Mail.To CMD",
+ "type": "string"
+ },
+ {
+ "name": "mail_from",
+ "label": "Mail.From",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"email\"}}"
+ },
+ {
+ "name": "mail_to",
+ "label": "Mail.To",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"email\"}}"
+ },
+ {
+ "name": "mail_cc",
+ "label": "Mail.CC",
+ "type": "string"
+ },
+ {
+ "name": "mail_bcc",
+ "label": "Mail.BCC",
+ "type": "string"
+ },
+ {
+ "name": "mail_subject",
+ "label": "Mail.Subject",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"decode_of_base64\",\"param\":\"$.mail_subject_charset\"}}"
+ },
+ {
+ "name": "mail_subject_charset",
+ "label": "Mail.Subject Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_content",
+ "label": "Mail.Content",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_content_charset",
+ "label": "Mail.Content Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_attachment_name",
+ "label": "Mail.Attachment",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"decode_of_base64\",\"param\":\"$.mail_attachment_name_charset\"}}"
+ },
+ {
+ "name": "mail_attachment_name_charset",
+ "label": "Mail.Attachment Charset",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_attachment_content",
+ "label": "Mail.Attachment Content",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "mail_eml_file",
+ "label": "Mail.EML File",
+ "type": "string",
+ "doc": "{\"constraints\":{\"type\":\"file\"}}"
+ },
+ {
+ "name": "mail_snapshot",
+ "label": "Mail.Snapshot",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "dns_message_id",
+ "label": "Dns.Message ID",
+ "type": "int"
+ },
+ {
+ "name": "dns_qr",
+ "label": "Dns.QR",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"REESPONSE\"}]}"
+ },
+ {
+ "name": "dns_opcode",
+ "label": "Dns.OPCODE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"QUERY\"},{\"code\":\"1\",\"value\":\"IQUERY\"},{\"code\":\"2\",\"value\":\"STATUS\"},{\"code\":\"5\",\"value\":\"UPDATE\"}]}"
+ },
+ {
+ "name": "dns_aa",
+ "label": "Dns.AA",
+ "type": "int"
+ },
+ {
+ "name": "dns_tc",
+ "label": "Dns.TC",
+ "type": "int"
+ },
+ {
+ "name": "dns_rd",
+ "label": "Dns.RD",
+ "type": "int"
+ },
+ {
+ "name": "dns_ra",
+ "label": "Dns.RA",
+ "type": "int"
+ },
+ {
+ "name": "dns_rcode",
+ "label": "Dns.RCODE",
+ "type": "int"
+ },
+ {
+ "name": "dns_qdcount",
+ "label": "Dns.QDCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_ancount",
+ "label": "Dns.ANCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_nscount",
+ "label": "Dns.NSCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_arcount",
+ "label": "Dns.ARCOUNT",
+ "type": "int"
+ },
+ {
+ "name": "dns_qname",
+ "label": "Dns.QNAME",
+ "type": "string"
+ },
+ {
+ "name": "dns_qtype",
+ "label": "Dns.QTYPE",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"A\"},{\"code\":\"2\",\"value\":\"NS\"},{\"code\":\"5\",\"value\":\"CNAME\"},{\"code\":\"6\",\"value\":\"SOA\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"12\",\"value\":\"PTR\"},{\"code\":\"13\",\"value\":\"HINFO\"},{\"code\":\"11\",\"value\":\"WKS\"},{\"code\":\"15\",\"value\":\"MX\"},{\"code\":\"28\",\"value\":\"AAAA\"}]}"
+ },
+ {
+ "name": "dns_qclass",
+ "label": "Dns.QCLASS",
+ "type": "int"
+ },
+ {
+ "name": "dns_cname",
+ "label": "Dns.CNAME",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "dns_sub",
+ "label": "Dns.SUB",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"DNS\"},{\"code\":\"2\",\"value\":\"DNSSEC\"}]}"
+ },
+ {
+ "name": "dns_rr",
+ "label": "Dns.RR",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_version",
+ "label": "SSL.Version",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_sni",
+ "label": "SSL.SNI",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "ssl_san",
+ "label": "SSL.SAN",
+ "type": "string"
+ },
+ {
+ "name": "ssl_cn",
+ "label": "SSL.CN",
+ "type": "string"
+ },
+ {
+ "name": "ssl_pinningst",
+ "label": "SSL.Pinning",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Not Pinning\"},{\"code\":\"1\",\"value\":\"Pinning\"},{\"code\":\"2\",\"value\":\"Maybe Pinning\"}]}"
+ },
+ {
+ "name": "ssl_intercept_state",
+ "label": "SSL.Intercept State",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Passthrough\"},{\"code\":\"1\",\"value\":\"Intercept\"},{\"code\":\"2\",\"value\":\"Shutdown\"}]}"
+ },
+ {
+ "name": "ssl_server_side_latency",
+ "label": "SSL.Server Side Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "ssl_client_side_latency",
+ "label": "SSL.Client Side Latency(ms)",
+ "type": "int"
+ },
+ {
+ "name": "ssl_server_side_version",
+ "label": "SSL.Server Side Version",
+ "type": "string"
+ },
+ {
+ "name": "ssl_client_side_version",
+ "label": "SSL.Client Side Version",
+ "type": "string"
+ },
+ {
+ "name": "ssl_cert_verify",
+ "label": "SSL.Certificate Verify",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}]}"
+ },
+ {
+ "name": "ssl_error",
+ "label": "SSL.Error",
+ "type": "string"
+ },
+ {
+ "name": "ssl_con_latency_ms",
+ "label": "SSL.Connection Latency(ms)",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "ssl_ja3_fingerprint",
+ "label": "SSL.JA3",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "quic_version",
+ "label": "Quic.Version",
+ "type": "string"
+ },
+ {
+ "name": "quic_sni",
+ "label": "Quic.SNI",
+ "type": "string",
+ "doc": "{\"format\":{\"functions\":\"sub_domain\",\"appendTo\":\"http_domain\"}}"
+ },
+ {
+ "name": "quic_user_agent",
+ "label": "Quic.User Agent",
+ "type": "string"
+ },
+ {
+ "name": "ftp_account",
+ "label": "Ftp.Account",
+ "type": "string"
+ },
+ {
+ "name": "ftp_url",
+ "label": "Ftp.URL",
+ "type": "string"
+ },
+ {
+ "name": "ftp_content",
+ "label": "Ftp.Content",
+ "type": "string"
+ },
+ {
+ "name": "bgp_type",
+ "label": "BGP.Type",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "bgp_as_num",
+ "label": "BGP.AS Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "bgp_route",
+ "label": "BGP.Route",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_calling_account",
+ "label": "Voip.Calling Account",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_called_account",
+ "label": "Voip.Called Account",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_calling_number",
+ "label": "Voip.Calling Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "voip_called_number",
+ "label": "Voip.Called Number",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "streaming_media_url",
+ "label": "Streaming.Media URL",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "streaming_media_protocol",
+ "label": "Streaming.Media Protocol",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "app_extra_info",
+ "label": "APP.Extra Info",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/security_ip_info.avsc b/galaxy-query-engine/config/avro/clickhouse/security_ip_info.avsc
new file mode 100644
index 0000000..1744326
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/security_ip_info.avsc
@@ -0,0 +1,33 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "security_ip_info",
+ "fields": [
+ {
+ "name": "stat_time",
+ "type": "int"
+ },
+ {
+ "name": "policy_id",
+ "type": "long"
+ },
+ {
+ "name": "ip",
+ "type": "string"
+ },
+ {
+ "name": "domain_list",
+ "type": {
+ "type": "array",
+ "items": "string"
+ }
+ },
+ {
+ "name": "port_list",
+ "type": {
+ "type": "array",
+ "items": "int"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/security_website_domain_info.avsc b/galaxy-query-engine/config/avro/clickhouse/security_website_domain_info.avsc
new file mode 100644
index 0000000..02a942e
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/security_website_domain_info.avsc
@@ -0,0 +1,47 @@
+{
+ "namespace": "tsg_galaxy_v3",
+ "type": "record",
+ "name": "security_website_domain_info",
+ "fields": [
+ {
+ "name": "stat_time",
+ "type": "int"
+ },
+ {
+ "name": "policy_id",
+ "type": "long"
+ },
+ {
+ "name": "domain",
+ "type": "string"
+ },
+ {
+ "name": "ip_list",
+ "type": {
+ "type": "array",
+ "items": "string"
+ }
+ },
+ {
+ "name": "cdn_list",
+ "type": {
+ "type": "array",
+ "items": "string"
+ }
+ },
+ {
+ "name": "protocol_type_list",
+ "type": {
+ "type": "array",
+ "items": "string"
+ }
+ },
+ {
+ "name": "port_list",
+ "type": {
+ "type": "array",
+ "items": "int"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/sys_packet_capture_log.avsc b/galaxy-query-engine/config/avro/clickhouse/sys_packet_capture_log.avsc
new file mode 100644
index 0000000..2d3adb6
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/sys_packet_capture_log.avsc
@@ -0,0 +1,338 @@
+{
+ "type": "record",
+ "name": "sys_packet_capture_log",
+ "namespace": "tsg_galaxy_v3",
+ "doc": "{\"primary_key\":\"common_log_id\",\"partition_key\":\"common_recv_time\"}",
+ "fields": [
+ {
+ "name": "common_recv_time",
+ "label": "Receive Time",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"timestamp\"},\"format\":{\"functions\":\"current_timestamp\"}}"
+ },
+ {
+ "name": "common_log_id",
+ "label": "Log ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\",\"format\":{\"functions\":\"snowflake_id\"}}"
+ },
+ {
+ "name": "common_policy_id",
+ "label": "Policy ID",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_subscriber_id",
+ "label": "Subscriber ID",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_client_ip",
+ "label": "Client IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_port",
+ "label": "Client Port",
+ "type": "int"
+ },
+ {
+ "name": "common_l4_protocol",
+ "label": "L4 Protocol",
+ "type": "string"
+ },
+ {
+ "name": "common_address_type",
+ "label": "Address Type",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"4\",\"value\":\"ipv4\"},{\"code\":\"6\",\"value\":\"ipv6\"}]}"
+ },
+ {
+ "name": "common_server_ip",
+ "label": "Server IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_server_port",
+ "label": "Server Port",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_action",
+ "label": "Action",
+ "type": "int",
+ "doc": "{\"allow_query\":\"true\",\"data\":[{\"code\":\"0\",\"value\":\"None\"},{\"code\":\"1\",\"value\":\"Monitor\"},{\"code\":\"2\",\"value\":\"Intercept\"},{\"code\":\"16\",\"value\":\"Deny\"},{\"code\":\"128\",\"value\":\"Allow\"}]}"
+ },
+ {
+ "name": "common_direction",
+ "label": "Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"69\",\"value\":\"outbound\"},{\"code\":\"73\",\"value\":\"inbound\"}]}"
+ },
+ {
+ "name": "common_entrance_id",
+ "label": "Entrance ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sled_ip",
+ "label": "Sled IP",
+ "type": "string",
+ "doc": "{\"allow_query\":\"true\",\"constraints\":{\"type\":\"ip\"}}"
+ },
+ {
+ "name": "common_client_location",
+ "label": "Client Location",
+ "type": "string"
+ },
+ {
+ "name": "common_client_asn",
+ "label": "Client ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_server_location",
+ "label": "Server Location",
+ "type": "string"
+ },
+ {
+ "name": "common_server_asn",
+ "label": "Server ASN",
+ "type": "string"
+ },
+ {
+ "name": "common_sessions",
+ "label": "Sessions",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_pkt_num",
+ "label": "Packets Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_pkt_num",
+ "label": "Packets Received",
+ "type": "long"
+ },
+ {
+ "name": "common_c2s_byte_num",
+ "label": "Bytes Sent",
+ "type": "long"
+ },
+ {
+ "name": "common_s2c_byte_num",
+ "label": "Bytes Received",
+ "type": "long"
+ },
+ {
+ "name": "common_service",
+ "label": "Service",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_schema_type",
+ "label": "Schema Type",
+ "type": "string",
+ "doc": "{\"data\":[{\"code\":\"BASE\",\"value\":\"BASE\"},{\"code\":\"HTTP\",\"value\":\"HTTP\"},{\"code\":\"MAIL\",\"value\":\"MAIL\"},{\"code\":\"DNS\",\"value\":\"DNS\"},{\"code\":\"SSL\",\"value\":\"SSL\"},{\"code\":\"FTP\",\"value\":\"FTP\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_user_tags",
+ "label": "User Tags",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_sub_action",
+ "label": "Sub Action",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_user_region",
+ "label": "User Region",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_device_id",
+ "label": "Device ID",
+ "type": "string"
+ },
+ {
+ "name": "common_link_id",
+ "label": "Link ID",
+ "type": "int",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_isp",
+ "label": "ISP",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_device_tag",
+ "label": "Device Tag",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_data_center",
+ "label": "Data Center",
+ "type": "string"
+ },
+ {
+ "name": "common_encapsulation",
+ "label": "Encapsulation",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"Ethernet\"},{\"code\":\"8\",\"value\":\"PPP\"},{\"code\":\"12\",\"value\":\"CiscoHDLC\"}]}"
+ },
+ {
+ "name": "common_app_label",
+ "label": "Application Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_protocol_label",
+ "label": "Protocol Label",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_start_time",
+ "label": "Start Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_end_time",
+ "label": "End Time",
+ "type": "long",
+ "doc": "{\"constraints\":{\"type\":\"timestamp\"},\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_establish_latency_ms",
+ "type": "int",
+ "label": "Establish Latency(ms)",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_con_duration_ms",
+ "label": "Duration(ms)",
+ "type": "int",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_dir",
+ "label": "Stream Direction",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"1\",\"value\":\"c2s\"},{\"code\":\"2\",\"value\":\"s2c\"},{\"code\":\"3\",\"value\":\"double\"}]}"
+ },
+ {
+ "name": "common_address_list",
+ "label": "Address List",
+ "type": "string",
+ "doc": "{\"visibility\":\"disabled\"}"
+ },
+ {
+ "name": "common_has_dup_traffic",
+ "label": "Duplication Traffic",
+ "type": "int",
+ "doc": "{\"data\":[{\"code\":\"0\",\"value\":\"No\"},{\"code\":\"1\",\"value\":\"Yes\"}],\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_error",
+ "label": "Stream Error",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_stream_trace_id",
+ "label": "Session ID",
+ "type": "long",
+ "doc": "{\"allow_query\":\"true\"}"
+ },
+ {
+ "name": "common_link_info_c2s",
+ "label": "Link Info(c2s)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_link_info_s2c",
+ "label": "Link Info(s2c)",
+ "type": "string",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_ipfrag_num",
+ "label": "Fragmentation Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_ipfrag_num",
+ "label": "Fragmentation Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_lostlen",
+ "label": "Sequence Gap Loss(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_lostlen",
+ "label": "Sequence Gap Loss(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_c2s_tcp_unorder_num",
+ "label": "Unorder Packets(c2s)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "common_s2c_tcp_unorder_num",
+ "label": "Unorder Packets(s2c)",
+ "type": "long",
+ "doc": "{\"visibility\":\"hidden\"}"
+ },
+ {
+ "name": "nic_name",
+ "label": "Nic Name",
+ "type": "string"
+ },
+ {
+ "name": "origin_source_mac",
+ "label": "Origin Source Mac",
+ "type": "string"
+ },
+ {
+ "name": "origin_dest_mac",
+ "label": "Origin Dest Mac",
+ "type": "string"
+ },
+ {
+ "name": "packet_url",
+ "label": "Packet URL",
+ "type": "string"
+ },
+ {
+ "name": "pcap_storage_task_id",
+ "label": "Task ID",
+ "type": "int"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/clickhouse/tables_cluster.avsc b/galaxy-query-engine/config/avro/clickhouse/tables_cluster.avsc
new file mode 100644
index 0000000..4765d85
--- /dev/null
+++ b/galaxy-query-engine/config/avro/clickhouse/tables_cluster.avsc
@@ -0,0 +1,11 @@
+{
+ "namespace": "system",
+ "type": "record",
+ "name": "tables_cluster",
+ "fields": [
+ {
+ "name": "database",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/proxy_event_hits_log.avsc b/galaxy-query-engine/config/avro/druid/proxy_event_hits_log.avsc
new file mode 100644
index 0000000..f6f700c
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/proxy_event_hits_log.avsc
@@ -0,0 +1,56 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "proxy_event_hits_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "action",
+ "type": "long"
+ },
+ {
+ "name": "isp",
+ "type": "string"
+ },
+ {
+ "name": "entrance_id",
+ "type": "long"
+ },
+ {
+ "name": "hits",
+ "type": "long"
+ },
+ {
+ "name": "policy_id",
+ "type": "long"
+ },
+ {
+ "name": "sub_action",
+ "type": "string"
+ },
+ {
+ "name": "country",
+ "type": "string"
+ },
+ {
+ "name": "location",
+ "type": "string"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "ip_object",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/security_event_hits_log.avsc b/galaxy-query-engine/config/avro/druid/security_event_hits_log.avsc
new file mode 100644
index 0000000..740c124
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/security_event_hits_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "security_event_hits_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "action",
+ "type": "long"
+ },
+ {
+ "name": "entrance_id",
+ "type": "long"
+ },
+ {
+ "name": "hits",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "isp",
+ "type": "string"
+ },
+ {
+ "name": "policy_id",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/source_country_ip_num_log.avsc b/galaxy-query-engine/config/avro/druid/source_country_ip_num_log.avsc
new file mode 100644
index 0000000..908fa08
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/source_country_ip_num_log.avsc
@@ -0,0 +1,20 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "source_country_ip_num_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "country",
+ "type": "string"
+ },
+ {
+ "name": "ip_object",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/sys_storage_log.avsc b/galaxy-query-engine/config/avro/druid/sys_storage_log.avsc
new file mode 100644
index 0000000..1ab7b1c
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/sys_storage_log.avsc
@@ -0,0 +1,32 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "sys_storage_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "log_type",
+ "type": "string"
+ },
+ {
+ "name": "max_size",
+ "type": "long"
+ },
+ {
+ "name": "used_size",
+ "type": "long"
+ },
+ {
+ "name": "aggregate_size",
+ "type": "long"
+ },
+ {
+ "name": "last_storage",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_client_ip_log.avsc b/galaxy-query-engine/config/avro/druid/top_client_ip_log.avsc
new file mode 100644
index 0000000..8dd059d
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_client_ip_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_client_ip_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "source",
+ "type": "string"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_domain_recommend_daily_log.avsc b/galaxy-query-engine/config/avro/druid/top_domain_recommend_daily_log.avsc
new file mode 100644
index 0000000..76766b5
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_domain_recommend_daily_log.avsc
@@ -0,0 +1,32 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_domain_recommend_daily_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "domain",
+ "type": "string"
+ },
+ {
+ "name": "ip_num",
+ "type": "long"
+ },
+ {
+ "name": "order_num",
+ "type": "long"
+ },
+ {
+ "name": "protocol_type",
+ "type": "string"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_external_host_log.avsc b/galaxy-query-engine/config/avro/druid/top_external_host_log.avsc
new file mode 100644
index 0000000..700e774
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_external_host_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_external_host_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "destination",
+ "type": "string"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_internal_host_log.avsc b/galaxy-query-engine/config/avro/druid/top_internal_host_log.avsc
new file mode 100644
index 0000000..8ecf953
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_internal_host_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_internal_host_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "source",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_server_ip_log.avsc b/galaxy-query-engine/config/avro/druid/top_server_ip_log.avsc
new file mode 100644
index 0000000..543d8f7
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_server_ip_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_server_ip_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "destination",
+ "type": "string"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_urls_log.avsc b/galaxy-query-engine/config/avro/druid/top_urls_log.avsc
new file mode 100644
index 0000000..44b5dbd
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_urls_log.avsc
@@ -0,0 +1,20 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_urls_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "url",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_user_log.avsc b/galaxy-query-engine/config/avro/druid/top_user_log.avsc
new file mode 100644
index 0000000..1f8dc0f
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_user_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_user_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "subscriber_id",
+ "type": "string"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_website_domain_log.avsc b/galaxy-query-engine/config/avro/druid/top_website_domain_log.avsc
new file mode 100644
index 0000000..b6bfc7f
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_website_domain_log.avsc
@@ -0,0 +1,40 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_website_domain_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "domain",
+ "type": "string"
+ },
+ {
+ "name": "order_by",
+ "type": "string"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/top_website_urls_daily_log.avsc b/galaxy-query-engine/config/avro/druid/top_website_urls_daily_log.avsc
new file mode 100644
index 0000000..5679d14
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/top_website_urls_daily_log.avsc
@@ -0,0 +1,28 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "top_website_urls_daily_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "url",
+ "type": "string"
+ },
+ {
+ "name": "ip_num",
+ "type": "long"
+ },
+ {
+ "name": "session_num",
+ "type": "long"
+ },
+ {
+ "name": "content_length",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/traffic_metrics_log.avsc b/galaxy-query-engine/config/avro/druid/traffic_metrics_log.avsc
new file mode 100644
index 0000000..ae67299
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/traffic_metrics_log.avsc
@@ -0,0 +1,212 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "traffic_metrics_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "allow_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "allow_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "allow_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "allow_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "allow_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "close_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "default_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "default_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "default_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "default_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "default_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "deny_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "deny_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "deny_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "deny_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "deny_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "device_id",
+ "type": "string"
+ },
+ {
+ "name": "entrance_id",
+ "type": "long"
+ },
+ {
+ "name": "intercept_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "intercept_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "intercept_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "intercept_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "intercept_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "established_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "monitor_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "monitor_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "monitor_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "monitor_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "monitor_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "new_conn_num",
+ "type": "long"
+ },
+ {
+ "name": "total_in_bytes",
+ "type": "long"
+ },
+ {
+ "name": "total_in_packets",
+ "type": "long"
+ },
+ {
+ "name": "total_out_bytes",
+ "type": "long"
+ },
+ {
+ "name": "total_out_packets",
+ "type": "long"
+ },
+ {
+ "name": "alert_bytes",
+ "type": "long"
+ },
+ {
+ "name": "hijk_bytes",
+ "type": "long"
+ },
+ {
+ "name": "ins_bytes",
+ "type": "long"
+ },
+ {
+ "name": "intcp_allow_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_deny_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_hijk_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_ins_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_mon_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_rdirt_num",
+ "type": "long"
+ },
+ {
+ "name": "intcp_repl_num",
+ "type": "long"
+ },
+ {
+ "name": "maybe_pinning_num",
+ "type": "long"
+ },
+ {
+ "name": "not_pinning_num",
+ "type": "long"
+ },
+ {
+ "name": "pinning_num",
+ "type": "long"
+ },
+ {
+ "name": "ad_cc_bytes",
+ "type": "long"
+ },
+ {
+ "name": "ad_flood_bytes",
+ "type": "long"
+ },
+ {
+ "name": "ad_reflection_bytes",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/traffic_protocol_stat_log.avsc b/galaxy-query-engine/config/avro/druid/traffic_protocol_stat_log.avsc
new file mode 100644
index 0000000..8945ffa
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/traffic_protocol_stat_log.avsc
@@ -0,0 +1,72 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "traffic_protocol_stat_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "protocol_id",
+ "type": "string"
+ },
+ {
+ "name": "isp",
+ "type": "string"
+ },
+ {
+ "name": "entrance_id",
+ "type": "long"
+ },
+ {
+ "name": "data_center",
+ "type": "string"
+ },
+ {
+ "name": "sessions",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_ipfrag_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_ipfrag_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_tcp_lostlen",
+ "type": "long"
+ },
+ {
+ "name": "s2c_tcp_lostlen",
+ "type": "long"
+ },
+ {
+ "name": "c2s_tcp_unorder_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_tcp_unorder_num",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/druid/traffic_summary_log.avsc b/galaxy-query-engine/config/avro/druid/traffic_summary_log.avsc
new file mode 100644
index 0000000..e361e88
--- /dev/null
+++ b/galaxy-query-engine/config/avro/druid/traffic_summary_log.avsc
@@ -0,0 +1,72 @@
+{
+ "namespace": "druid",
+ "type": "record",
+ "name": "traffic_summary_log",
+ "doc": "{\"partition_key\":\"__time\"}",
+ "fields": [
+ {
+ "name": "__time",
+ "type": "long"
+ },
+ {
+ "name": "isp",
+ "type": "string"
+ },
+ {
+ "name": "entrance_id",
+ "type": "long"
+ },
+ {
+ "name": "data_center",
+ "type": "string"
+ },
+ {
+ "name": "schema_type",
+ "type": "string"
+ },
+ {
+ "name": "ip_object",
+ "type": "string"
+ },
+ {
+ "name": "sessions",
+ "type": "long"
+ },
+ {
+ "name": "c2s_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_pkt_num",
+ "type": "long"
+ },
+ {
+ "name": "c2s_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "s2c_byte_num",
+ "type": "long"
+ },
+ {
+ "name": "one_sided_connections",
+ "type": "long"
+ },
+ {
+ "name": "uncategorized_bytes",
+ "type": "long"
+ },
+ {
+ "name": "fragmentation_packets",
+ "type": "long"
+ },
+ {
+ "name": "sequence_gap_loss",
+ "type": "long"
+ },
+ {
+ "name": "unorder_packets",
+ "type": "long"
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/avro/etl/liveChart.avsc b/galaxy-query-engine/config/avro/etl/liveChart.avsc
new file mode 100644
index 0000000..9f3b5cd
--- /dev/null
+++ b/galaxy-query-engine/config/avro/etl/liveChart.avsc
@@ -0,0 +1,10 @@
+{
+ "type": "record",
+ "name": "liveChart",
+ "task": "Protocol-Distribution",
+ "in": "CONNECTION-RECORD-COMPLETED-LOG",
+ "out": "TRAFFIC-PROTOCOL-STAT-LOG",
+ "doc": "{\"timestamp\":{\"name\":\"stat_time\",\"type\":\"Long\"},\"dimensions\":[{\"name\":\"protocol_id\",\"fieldName\":\"common_protocol_label\",\"type\":\"String\"},{\"name\":\"entrance_id\",\"fieldName\":\"common_entrance_id\",\"type\":\"String\"},{\"name\":\"isp\",\"fieldName\":\"common_isp\",\"type\":\"String\"},{\"name\":\"data_center\",\"fieldName\":\"common_data_center\",\"type\":\"String\"}],\"metrics\":[{\"function\":\"sum\",\"name\":\"sessions\",\"fieldName\":\"common_sessions\"},{\"function\":\"sum\",\"name\":\"c2s_byte_num\",\"fieldName\":\"common_c2s_byte_num\"},{\"function\":\"sum\",\"name\":\"s2c_byte_num\",\"fieldName\":\"common_s2c_byte_num\"},{\"function\":\"sum\",\"name\":\"c2s_pkt_num\",\"fieldName\":\"common_c2s_pkt_num\"},{\"function\":\"sum\",\"name\":\"s2c_pkt_num\",\"fieldName\":\"common_s2c_pkt_num\"},{\"function\":\"sum\",\"name\":\"c2s_ipfrag_num\",\"fieldName\":\"common_c2s_ipfrag_num\"},{\"function\":\"sum\",\"name\":\"s2c_ipfrag_num\",\"fieldName\":\"common_s2c_ipfrag_num\"},{\"function\":\"sum\",\"name\":\"c2s_tcp_lostlen\",\"fieldName\":\"common_c2s_tcp_lostlen\"},{\"function\":\"sum\",\"name\":\"s2c_tcp_lostlen\",\"fieldName\":\"common_s2c_tcp_lostlen\"},{\"function\":\"sum\",\"name\":\"c2s_tcp_unorder_num\",\"fieldName\":\"common_c2s_tcp_unorder_num\"},{\"function\":\"sum\",\"name\":\"s2c_tcp_unorder_num\",\"fieldName\":\"common_s2c_tcp_unorder_num\"},{\"function\":\"disCount\",\"name\":\"unique_sip_num\",\"fieldName\":\"common_server_ip\"},{\"function\":\"disCount\",\"name\":\"unique_cip_num\",\"fieldName\":\"common_client_ip\"}],\"filters\":{\"type\":\"and\",\"fields\":[{\"fieldName\":\"common_protocol_label\",\"type\":\"not\",\"values\":null}]},\"transforms\":[{\"fieldName\":\"common_app_label\",\"function\":\"alignment\",\"name\":\"common_app_label\",\"parameters\":\"0,/\"},{\"function\":\"combination\",\"name\":\"protocol_id\",\"fieldName\":\"common_protocol_label\",\"parameters\":\"common_app_label,/\"},{\"function\":\"hierarchy\",\"name\":\"protocol_id\",\"fieldName\":\"common_protocol_label\",\"parameters\":\"/\"}],\"action\":[{\"label\":\"Default\",\"metrics\":\"sessions,c2s_byte_num,s2c_byte_num,c2s_pkt_num,s2c_pkt_num,c2s_ipfrag_num,s2c_ipfrag_num,c2s_tcp_lostlen,s2c_tcp_lostlen,c2s_tcp_unorder_num,s2c_tcp_unorder_num\"}],\"granularity\":{\"type\":\"period\",\"period\":\"5M\"}}",
+ "fields": [
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/memorySchema.json b/galaxy-query-engine/config/memorySchema.json
new file mode 100644
index 0000000..a034ee1
--- /dev/null
+++ b/galaxy-query-engine/config/memorySchema.json
@@ -0,0 +1,13 @@
+{
+ "version": "1.0",
+ "defaultSchema": "memorySchema",
+ "schemas": [
+ {
+ "type": "custom",
+ "name": "memorySchema",
+ "factory": "com.mesalab.calcite.InMemorySchemaFactory",
+ "operand": {
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/galaxy-query-engine/config/version.json b/galaxy-query-engine/config/version.json
new file mode 100644
index 0000000..6388864
--- /dev/null
+++ b/galaxy-query-engine/config/version.json
@@ -0,0 +1,95 @@
+{
+ "product": "186 Environment",
+ "version": "20.08",
+ "registered": "Geedge",
+ "updated":"2020-08-01 00:00:00",
+ "components": {
+ "oss": [
+ {
+ "name": "zookeeper",
+ "version": "3.4.9",
+ "licenseType": "Apache License 2.0",
+ "description": "分布式应用程序协调服务"
+ },
+ {
+ "name": "kafka",
+ "version": "2.11_1.0.0",
+ "licenseType": "Apache License 2.0",
+ "description": "消息队列"
+ },
+ {
+ "name": "habse",
+ "version": "2.2.3",
+ "licenseType": "Apache License 2.0",
+ "description": "用于文件系统和存储Radius数据"
+ },
+ {
+ "name": "flume",
+ "version": "1.9.0",
+ "licenseType": "Apache License 2.0",
+ "description": "日志补全传输"
+ },
+ {
+ "name": "clickhouse",
+ "version": "19.17.4.11",
+ "licenseType": "Apache License 2.0",
+ "description": "原始日志数据库"
+ },
+ {
+ "name": "druid",
+ "version": "0.16.0",
+ "licenseType": "Apache License 2.0",
+ "description": "分析实时数据并提供低延迟查询的OLAP应用程序"
+ },
+ {
+ "name": "gohangout",
+ "version": "1.14.4.20200616",
+ "description": "动态获取原始日志表schema入库程序"
+ }
+ ],
+ "apps": [
+ {
+ "name": "galaxy-qgw-service",
+ "version": "v3.2.200730",
+ "description": "数据平台对外统一查询网关"
+ },
+ {
+ "name": "galaxy-report-service",
+ "version": "20.07.08",
+ "description": "自定义报表查询服务"
+ },
+ {
+ "name": "galaxy-hos-service",
+ "version": "20.07.17",
+ "description": "对象存储服务"
+ },
+ {
+ "name": "xxl-job-admin",
+ "version": "v1.0.2.20200506",
+ "description": "分布式任务调度平台"
+ },
+ {
+ "name": "xxl-job",
+ "version": "v1.0.2.20200628",
+ "description": "分布式任务调度平台-执行器"
+ }
+ ],
+ "tasks": [
+ {
+ "name": "flume",
+ "version": "flume-config-20.08",
+ "description": "原始日志补全、subscriber更新、Radius上下线功能"
+ },
+ {
+ "name": "druid",
+ "version": "druid-config-20.08",
+ "description": "所有分析日志任务"
+ },
+ {
+ "name": "gohangout",
+ "version": "gohangout-config-20.08",
+ "description": "原始日志入库、上下线日志入库"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/galaxy-query-engine/dat/asn_v4.mmdb b/galaxy-query-engine/dat/asn_v4.mmdb
new file mode 100644
index 0000000..4508ea2
--- /dev/null
+++ b/galaxy-query-engine/dat/asn_v4.mmdb
Binary files differ
diff --git a/galaxy-query-engine/dat/asn_v6.mmdb b/galaxy-query-engine/dat/asn_v6.mmdb
new file mode 100644
index 0000000..a779312
--- /dev/null
+++ b/galaxy-query-engine/dat/asn_v6.mmdb
Binary files differ
diff --git a/galaxy-query-engine/dat/ip_private_v4.mmdb b/galaxy-query-engine/dat/ip_private_v4.mmdb
new file mode 100644
index 0000000..445f2aa
--- /dev/null
+++ b/galaxy-query-engine/dat/ip_private_v4.mmdb
Binary files differ
diff --git a/galaxy-query-engine/dat/ip_private_v6.mmdb b/galaxy-query-engine/dat/ip_private_v6.mmdb
new file mode 100644
index 0000000..cf82ebe
--- /dev/null
+++ b/galaxy-query-engine/dat/ip_private_v6.mmdb
Binary files differ
diff --git a/galaxy-query-engine/dat/ip_v4.mmdb b/galaxy-query-engine/dat/ip_v4.mmdb
new file mode 100644
index 0000000..842cce9
--- /dev/null
+++ b/galaxy-query-engine/dat/ip_v4.mmdb
Binary files differ
diff --git a/galaxy-query-engine/dat/ip_v6.mmdb b/galaxy-query-engine/dat/ip_v6.mmdb
new file mode 100644
index 0000000..cf82ebe
--- /dev/null
+++ b/galaxy-query-engine/dat/ip_v6.mmdb
Binary files differ
diff --git a/galaxy-query-engine/pom.xml b/galaxy-query-engine/pom.xml
index d0d800e..3ed341f 100644
--- a/galaxy-query-engine/pom.xml
+++ b/galaxy-query-engine/pom.xml
@@ -31,6 +31,15 @@
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-jdbc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${mysql.connector.version}</version>
+ </dependency>
+ <dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
@@ -67,7 +76,47 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-core</artifactId>
+ <version>${apache.calcite.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.jfinal</groupId>
+ <artifactId>activerecord</artifactId>
+ <version>${active.record.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hbase</groupId>
+ <artifactId>hbase-client</artifactId>
+ <version>${hbase.client.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.nutz</groupId>
+ <artifactId>nutz</artifactId>
+ <version>${nutz.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>druid-spring-boot-starter</artifactId>
+ <version>${starter.druid.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.jsqlparser</groupId>
+ <artifactId>jsqlparser</artifactId>
+ <version>${jsqlparser.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.avro</groupId>
+ <artifactId>avro</artifactId>
+ <version>${avro.version}</version>
+ </dependency>
</dependencies>
<build>
@@ -87,7 +136,7 @@
</executions>
<configuration>
<includeSystemScope>true</includeSystemScope>
- <mainClass>com.mesalab.engine.GalaxyQueryEngine</mainClass>
+ <mainClass>com.mesalab.GalaxyQueryEngine</mainClass>
</configuration>
</plugin>
<plugin>
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/GalaxyQueryEngine.java b/galaxy-query-engine/src/main/java/com/mesalab/GalaxyQueryEngine.java
new file mode 100644
index 0000000..651ea52
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/GalaxyQueryEngine.java
@@ -0,0 +1,32 @@
+package com.mesalab;
+
+import com.mesalab.qgw.interceptor.QuerySubmitInterceptor;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@EnableDiscoveryClient
+@SpringBootApplication
+public class GalaxyQueryEngine implements WebMvcConfigurer {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GalaxyQueryEngine.class);
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new QuerySubmitInterceptor()).addPathPatterns("/**");
+ }
+
+ @Bean
+ public ServletWebServerFactory webServerFactory() {
+ TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+ factory.addConnectorCustomizers(connector -> connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}"));
+ return factory;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java
new file mode 100644
index 0000000..c84cdb7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/CalciteMemoryUtils.java
@@ -0,0 +1,170 @@
+package com.mesalab.calcite;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Splitter;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mesalab.calcite.storage.DataTypeMapping;
+import com.mesalab.calcite.storage.Storage;
+import com.mesalab.common.exception.BusinessException;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.sql.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import static com.zdjizhi.utils.StringUtil.setDefaultIfEmpty;
+import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
+
+@Slf4j
+public class CalciteMemoryUtils {
+
+ public static Map<String, Object> executeMemoryQuery(String tableName, List<Map<String, String>> meta,
+ List<Map<String, Object>> data, String sql) {
+ Map<String, Object> result = Maps.newHashMap();
+ if (meta.isEmpty() || data.isEmpty()) {
+ data.clear();
+ meta.clear();
+ result.put("meta", meta);
+ result.put("data", data);
+ return result;
+ }
+ ResultSet resultSet = null;
+ java.sql.Statement statement = null;
+ Connection connection = null;
+ try {
+ Class.forName("org.apache.calcite.jdbc.Driver");
+ Properties info = new Properties();
+ info.setProperty("lex", "MYSQL_ANSI");
+ String jsonModel = new File("").getCanonicalPath() + "/config/memorySchema.json";
+ connection = DriverManager.getConnection("jdbc:calcite:model=" + jsonModel, info);
+ CalciteConnection calciteConn = connection.unwrap(CalciteConnection.class);
+
+ log.debug("Calcite: 加载数据的数量: " + data.size());
+ //将数据存入缓存表
+ Storage.DummyTable table = buildDummyTable(meta, tableName);
+ table = loadData(table, data);
+ InMemoryTable inMemoryTable = new InMemoryTable(tableName, table);
+
+ //将缓存表植入rootSchema
+ calciteConn.getRootSchema().add(tableName, inMemoryTable);
+ statement = connection.createStatement();
+ resultSet = statement.executeQuery(sql);
+ ResultSetMetaData metaData = resultSet.getMetaData();
+ meta.clear();
+ data.clear();
+
+ for (int i = 1; i <= metaData.getColumnCount(); i++) {
+ Map<String, String> metaMap = Maps.newLinkedHashMap();
+ metaMap.put("name", metaData.getColumnLabel(i));
+ metaMap.put("type", metaData.getColumnTypeName(i));
+ meta.add(metaMap);
+ }
+
+ while (resultSet.next()) {
+ Map<String, Object> rowData = Maps.newLinkedHashMap();
+ for (int i = 1; i <= metaData.getColumnCount(); i++) {
+ rowData.put(metaData.getColumnLabel(i), resultSet.getObject(i));
+ }
+ data.add(rowData);
+ }
+
+ result.put("meta", meta);
+ result.put("data", data);
+
+ } catch (Exception e) {
+ throw new BusinessException("Engine execution SQL Error - ", e);
+
+ } finally {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException sqlException) {
+ sqlException.printStackTrace();
+ }
+ }
+
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException sqlException) {
+ sqlException.printStackTrace();
+ }
+ }
+
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException sqlException) {
+ sqlException.printStackTrace();
+ }
+ }
+ }
+
+
+ return result;
+ }
+
+
+ /**
+ * 数据加载 : MAP To List
+ * @param table 转换为table
+ * @param data 原始结果集合
+ * @return
+ */
+ private static Storage.DummyTable loadData(Storage.DummyTable table, List<Map<String, Object>> data) {
+ List<Storage.DummyColumn> columns = table.getColumns();
+ data.stream().forEach(item -> {
+ List list = Lists.newArrayList();
+ for (Storage.DummyColumn column : columns) {
+ if (DataTypeMapping.BIGINT.equals(column.getType())) {
+ list.add(Long.valueOf(setDefaultIfEmpty(item.get(column.getName()), "0").toString()));
+ } else if (DataTypeMapping.DOUBLE.equals(column.getType())) {
+ list.add(Double.valueOf(setDefaultIfEmpty(item.get(column.getName()), "0").toString()));
+ } else {
+ list.add(setDefaultIfEmpty(item.get(column.getName()), "").toString());
+ }
+
+
+ }
+
+ table.addRow(list.toArray());
+
+ });
+ return table;
+ }
+
+ /**
+ * 生成虚拟表
+ * @param meta schema 表结构字段
+ * @param tableName 表名
+ * @return
+ */
+ private static Storage.DummyTable buildDummyTable(List<Map<String, String>> meta, String tableName) {
+ Storage.DummyTable dummyTable = new Storage.DummyTable(tableName);
+ for (Map<String, String> column : meta) {
+ String fieldName = column.get("name");
+ String fieldType = column.get("type");
+ String dummyColumnType;
+ if (Splitter.on(",").trimResults().omitEmptyStrings().splitToList(intUnits).contains(fieldType)) {
+ dummyColumnType = DataTypeMapping.BIGINT;
+ } else if (Splitter.on(",").trimResults().omitEmptyStrings().splitToList(doubleUnits).contains(fieldType)) {
+ dummyColumnType = DataTypeMapping.DOUBLE;
+ } else {
+ dummyColumnType = DataTypeMapping.VARCHAR;
+ }
+ Storage.DummyColumn name = new Storage.DummyColumn(fieldName, dummyColumnType);
+ dummyTable.addColumn(name);
+ }
+ return dummyTable;
+ }
+
+ private static String intUnits = "Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64,bigint";
+ private static String doubleUnits = "Float32,Float64,float,double";
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchema.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchema.java
new file mode 100644
index 0000000..81b99f7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchema.java
@@ -0,0 +1,31 @@
+package com.mesalab.calcite;
+
+import com.mesalab.calcite.storage.Storage;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractSchema;
+
+import java.util.*;
+
+public class InMemorySchema extends AbstractSchema {
+
+ private String dbName;
+ private Map<String, Object> operand;
+
+ public InMemorySchema(String name, Map<String, Object> operand) {
+ this.operand = operand;
+ this.dbName = name;
+ }
+
+ @Override
+ public Map<String, Table> getTableMap() {
+
+ Map<String, Table> tables = new HashMap<String, Table>();
+
+ Storage.getTables().forEach(it -> {
+ tables.put(it.getName(), new InMemoryTable(it.getName(), it));
+ });
+
+ return tables;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchemaFactory.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchemaFactory.java
new file mode 100644
index 0000000..a3a9dea
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemorySchemaFactory.java
@@ -0,0 +1,19 @@
+package com.mesalab.calcite;
+
+import com.mesalab.calcite.function.DateFunction;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.SchemaFactory;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.impl.ScalarFunctionImpl;
+
+import java.util.Map;
+
+public class InMemorySchemaFactory implements SchemaFactory {
+
+
+ @Override
+ public Schema create(SchemaPlus parentSchema, String name, Map<String, Object> operand) {
+ parentSchema.add("FROM_UNIXTIME", ScalarFunctionImpl.create(DateFunction.class, "fromUnixTimeToDateTime24"));
+ return new InMemorySchema(name, operand);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemoryTable.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemoryTable.java
new file mode 100644
index 0000000..74af0d5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/InMemoryTable.java
@@ -0,0 +1,82 @@
+package com.mesalab.calcite;
+
+import com.mesalab.calcite.storage.Storage;
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.AbstractEnumerable;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.schema.*;
+import org.apache.calcite.schema.impl.AbstractTable;
+import org.apache.calcite.sql.type.SqlTypeUtil;
+
+
+public class InMemoryTable extends AbstractTable implements ScannableTable {
+ private String name;
+ private Storage.DummyTable _table;
+ private RelDataType dataType;
+
+ InMemoryTable(String name) {
+ this.name = name;
+ }
+
+ public InMemoryTable(String name, Storage.DummyTable it) {
+ this.name = name;
+ this._table = it;
+ }
+
+
+ @Override
+ public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+ if (dataType == null) {
+ RelDataTypeFactory.FieldInfoBuilder fieldInfo = typeFactory.builder();
+ for (Storage.DummyColumn column : this._table.getColumns()) {
+ RelDataType sqlType = typeFactory.createJavaType(column.getJavaClass());
+ sqlType = SqlTypeUtil.addCharsetAndCollation(sqlType, typeFactory);
+ fieldInfo.add(column.getName(), sqlType);
+ }
+ this.dataType = typeFactory.createStructType(fieldInfo);
+ }
+ return this.dataType;
+ }
+
+
+ @Override
+ public Enumerable<Object[]> scan(DataContext root) {
+ return new AbstractEnumerable<Object[]>() {
+ @Override
+ public Enumerator<Object[]> enumerator() {
+ return new Enumerator<Object[]>() {
+ private int cur = 0;
+ private int count = 0;
+
+ @Override
+ public Object[] current() {
+ Object[] data = _table.getData(cur);
+ return data;
+ }
+
+ @Override
+ public boolean moveNext() {
+ if (cur != 0 || count >= 1) {
+ ++cur;
+ }
+ if (count++ >= 1 && cur == 0) {
+ return false;
+ }
+ return cur < _table.getRowCount();
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java
new file mode 100644
index 0000000..1801c9c
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/function/DateFunction.java
@@ -0,0 +1,12 @@
+package com.mesalab.calcite.function;
+
+import com.zdjizhi.utils.DateUtils;
+
+public class DateFunction {
+
+ public String fromUnixTimeToDateTime24(Object i) {
+ Long aLong = Long.valueOf(String.valueOf(i));
+ String s = DateUtils.convertTimestampToString(aLong, DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ return s;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/DataTypeMapping.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/DataTypeMapping.java
new file mode 100644
index 0000000..b05024d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/DataTypeMapping.java
@@ -0,0 +1,77 @@
+package com.mesalab.calcite.storage;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.util.Set;
+
+/**
+ * 这里使用了GUAVA的table 作为存SQL和JAVA数据类型的数据结构
+ * 这并不是一个好的设计,而是为了让大家更容易理解而做的设计
+ */
+public class DataTypeMapping {
+
+ public static Table<String, SqlTypeName, Class> TYPEMAPPING = HashBasedTable.create();
+ public static final String CHAR = "char";
+ public static final String VARCHAR = "varchar";
+ public static final String BOOLEAN = "boolean";
+ public static final String DATE = "date";
+ public static final String INTEGER = "integer";
+ public static final String INT = "int";
+ public static final String TINYINT = "tinyint";
+ public static final String SMALLINT = "smallint";
+ public static final String BIGINT = "bigint";
+ public static final String DECIMAL = "decimal";
+ public static final String NUMERIC = "numeric";
+ public static final String FLOAT = "float";
+ public static final String REAL = "real";
+ public static final String DOUBLE = "double";
+ public static final String TIME = "time";
+ public static final String TIMESTAMP = "timestamp";
+ public static final String ANY = "any";
+
+ static {
+ TYPEMAPPING.put(DataTypeMapping.CHAR, SqlTypeName.CHAR, Character.class);
+ TYPEMAPPING.put(DataTypeMapping.VARCHAR, SqlTypeName.VARCHAR, String.class);
+ TYPEMAPPING.put(DataTypeMapping.BOOLEAN, SqlTypeName.BOOLEAN, Boolean.class);
+ TYPEMAPPING.put(DataTypeMapping.DATE, SqlTypeName.DATE, Date.class);
+ TYPEMAPPING.put(DataTypeMapping.INTEGER, SqlTypeName.INTEGER, Integer.class);
+ TYPEMAPPING.put(DataTypeMapping.INT, SqlTypeName.TIMESTAMP, String.class);
+ TYPEMAPPING.put(DataTypeMapping.TINYINT, SqlTypeName.TINYINT, Integer.class);
+ TYPEMAPPING.put(DataTypeMapping.SMALLINT, SqlTypeName.SMALLINT, Integer.class);
+ TYPEMAPPING.put(DataTypeMapping.BIGINT, SqlTypeName.BIGINT, Long.class);
+ TYPEMAPPING.put(DataTypeMapping.DECIMAL, SqlTypeName.DECIMAL, BigDecimal.class);
+ TYPEMAPPING.put(DataTypeMapping.NUMERIC, SqlTypeName.DECIMAL, Long.class);
+ TYPEMAPPING.put(DataTypeMapping.FLOAT, SqlTypeName.FLOAT, Float.class);
+ TYPEMAPPING.put(DataTypeMapping.REAL, SqlTypeName.REAL, Double.class);
+ TYPEMAPPING.put(DataTypeMapping.DOUBLE, SqlTypeName.DOUBLE, Double.class);
+ TYPEMAPPING.put(DataTypeMapping.TIME, SqlTypeName.TIME, Date.class);
+ TYPEMAPPING.put(DataTypeMapping.TIMESTAMP, SqlTypeName.TIMESTAMP, Long.class);
+ TYPEMAPPING.put(DataTypeMapping.ANY, SqlTypeName.ANY, String.class);
+ }
+
+ /**
+ * 根据名字获取,对应的java类型
+ */
+ public static Class getJavaClassByName(String name) {
+ Set<Table.Cell<String, SqlTypeName, Class>> table = TYPEMAPPING.cellSet();
+ for (Table.Cell<String, SqlTypeName, Class> it : table) {
+ if (it.getRowKey().equals(name)) {
+ return it.getValue();
+ }
+ }
+ return null;
+ }
+
+ public static SqlTypeName getSqlTypeByName(String name) {
+ for (Table.Cell<String, SqlTypeName, Class> it : TYPEMAPPING.cellSet()) {
+ if (it.getRowKey().equals(name)) {
+ return it.getColumnKey();
+ }
+ }
+ return null;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/Storage.java b/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/Storage.java
new file mode 100644
index 0000000..a5c7def
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/calcite/storage/Storage.java
@@ -0,0 +1,100 @@
+package com.mesalab.calcite.storage;
+
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import java.util.*;
+
+/**
+ * 用于模拟数据库结构及数据
+ */
+public class Storage {
+
+ public static Hashtable<String, DummyTable> _bag = new Hashtable<>();
+
+ public static Collection<DummyTable> getTables() {
+ return _bag.values();
+ }
+
+ public static DummyTable getTable(String tableName) {
+ return _bag.get(tableName);
+ }
+
+ public static class DummyTable {
+ private String name;
+ private List<DummyColumn> columns;
+ private List<List<Object>> datas = new ArrayList<>();
+
+ public DummyTable(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public List<DummyColumn> getColumns() {
+ return columns;
+ }
+
+ public DummyTable addColumn(DummyColumn dc) {
+ if (this.columns == null) {
+ this.columns = new ArrayList<>();
+ }
+ this.columns.add(dc);
+ return this;
+ }
+
+ public void setColumns(List<DummyColumn> columns) {
+ this.columns = columns;
+ }
+
+ public Object[] getData(int index) {
+ return this.datas.get(index).toArray();
+ }
+
+ public int getRowCount() {
+ return this.datas.size();
+ }
+
+ public void addRow(Object... objects) {
+ this.datas.add(Arrays.asList(objects));
+ }
+
+
+ }
+
+ public static class DummyColumn {
+ private String name;
+ private String type;
+
+ public DummyColumn(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Class getJavaClass() {
+ return DataTypeMapping.getJavaClassByName(this.type);
+ }
+
+ public SqlTypeName getSqlTypeName() {
+ return DataTypeMapping.getSqlTypeByName(this.type);
+ }
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResult.java b/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResult.java
new file mode 100644
index 0000000..5dea539
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResult.java
@@ -0,0 +1,54 @@
+package com.mesalab.common.base;
+
+import com.mesalab.common.enums.ResultStatusEnum;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * 响应结果
+ * 如果使用注解@JsonInclude(JsonInclude.Include.NON_NULL): 则会保证序列化json的时候,如果是null的对象,key也会消失
+ *
+ * @author dazzlzy
+ * @date 2018/3/21
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BaseResult<T> implements Serializable {
+
+ private Integer status;
+
+ private String code;
+
+ private String queryKey;
+
+ private boolean success;
+
+ private String message;
+
+ private Map<String, Object> statistics;
+
+ private String formatType;
+
+ private T meta;
+
+ private T data;
+
+
+ /**
+ * 判断是否是成功结果
+ * JsonIgnore使之不在json序列化结果当中
+ *
+ * @return 是否为成功结果
+ */
+ public boolean isSuccess() {
+ return ResultStatusEnum.SUCCESS.getCode() == this.status;
+ }
+
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResultGenerator.java b/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResultGenerator.java
new file mode 100644
index 0000000..57a51e4
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/base/BaseResultGenerator.java
@@ -0,0 +1,207 @@
+package com.mesalab.common.base;
+
+
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+
+import java.util.Map;
+
+/**
+ * BaseResult生成器
+ *
+ * @author dazzlzy
+ * @date 2018/4/1
+ */
+public class BaseResultGenerator {
+
+ /**
+ * 生成返回结果
+ *
+ * @param status 返回HTTP响应码
+ * @param code 返回业务编码
+ * @param message 返回消息
+ * @param data 返回数据
+ * @param formatType 返回数据格式 JSON/CSV
+ * @param <T> 返回数据类型
+ * @return 返回结果
+ */
+ public static <T> BaseResult<T> generate(final int status, final String code, final String message, T data, T meta, final Map<String, Object> statistics, final String formatType) {
+ return new BaseResult<>(status, code,null, false, message, statistics, formatType, meta, data);
+ }
+
+ /**
+ * 操作成功响应结果, 默认结果
+ *
+ * @return 操作成功的默认响应结果
+ */
+ public static <T> BaseResult<T> success() {
+ return new BaseResult<>(ResultStatusEnum.SUCCESS.getCode(), ResultCodeEnum.EXECUTE_SUCCESS.getCode(),
+ null, true, ResultCodeEnum.EXECUTE_SUCCESS.getMessage(), null, null, null, null);
+ }
+
+ /**
+ * 操作成功响应结果, 自定义数据及信息
+ *
+ * @param message 自定义信息
+ * @param data 自定义数据
+ * @param <T> 自定义数据类型
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> success(final String message, final T data) {
+ return new BaseResult<>(ResultStatusEnum.SUCCESS.getCode(), ResultCodeEnum.EXECUTE_SUCCESS.getCode(),
+ null, true, message, null, null, null, data);
+ }
+
+ /**
+ * 操作成功响应结果, 自定义数据及信息, 统计结果
+ *
+ * @param message 自定义信息
+ * @param data 自定义数据
+ * @param <T> 自定义数据类型
+ * @param statistics 统计结果
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> success(final String message, final T data, final Map<String, Object> statistics) {
+ return new BaseResult<>(ResultStatusEnum.SUCCESS.getCode(), ResultCodeEnum.EXECUTE_SUCCESS.getCode(),
+ null, true, message, statistics, null, null, data);
+ }
+
+ /**
+ * 操作成功响应结果,自定义数据,默认信息
+ *
+ * @param data 自定义数据
+ * @param <T> 自定义数据类型
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> success(final T data) {
+ return new BaseResult<>(ResultStatusEnum.SUCCESS.getCode(), ResultCodeEnum.EXECUTE_SUCCESS.getCode(), null, true,
+ ResultCodeEnum.EXECUTE_SUCCESS.getMessage(), null, null, null, data);
+ }
+
+ /**
+ * 操作成功响应结果,自定义信息,无数据
+ *
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> success4Message(final String message) {
+ return new BaseResult<>(ResultStatusEnum.SUCCESS.getCode(), ResultCodeEnum.EXECUTE_SUCCESS.getCode(),
+ null, true, message, null, null, null, null);
+ }
+
+ /**
+ * 操作失败响应结果, 默认结果
+ *
+ * @return 操作成功的默认响应结果
+ */
+ public static <T> BaseResult<T> failure() {
+ return new BaseResult<>(ResultStatusEnum.FAIL.getCode(),
+ ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, ResultCodeEnum.UNKNOW_ERROR.getMessage(), null, null, null, null);
+ }
+
+ /**
+ * 操作失败响应结果, 自定义错误编码及信息
+ *
+ * @param status HTTP状态码
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> failure(final int status, final String message) {
+ return new BaseResult<>(status, ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, message, null, null, null, null);
+ }
+
+ /**
+ * 操作失败响应结果, 自定义错误编码及信息
+ *
+ * @param status HTTP 状态码
+ * @param code 返回业务编码
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> failure(final int status, final String code, final String message) {
+ return new BaseResult<>(status, code, null, false, message, null, null, null, null);
+ }
+
+ /**
+ * 操作失败响应结果, 自定义错误编码及信息
+ *
+ * @param status HTTP 状态码
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> failure(final int status, final String message, T data) {
+ return new BaseResult<>(status, ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, message, null, null, null, data);
+ }
+
+ /**
+ * 操作失败响应结果,自定义错误编码
+ *
+ * @param resultStatusEnum 自定义错误编码枚举
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> failure(final ResultStatusEnum resultStatusEnum) {
+ return new BaseResult<>(resultStatusEnum.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, resultStatusEnum.getMessage(), null, null, null, null);
+ }
+
+ /**
+ * 操作失败响应结果,自定义信息
+ *
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> failure(final String message) {
+ return new BaseResult<>(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, message, null, null, null, null);
+ }
+
+ /**
+ * 异常响应结果, 默认结果
+ *
+ * @return 操作成功的默认响应结果
+ */
+ public static <T> BaseResult<T> error() {
+ return new BaseResult<>(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, ResultStatusEnum.SERVER_ERROR.getMessage(), null, null, null, null);
+ }
+
+ /**
+ * 异常响应结果, 自定义错误编码及信息
+ *
+ * @param code 自定义错误编码
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> error(final int code, final String message) {
+ return new BaseResult<>(code, ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, message, null, null, null, null);
+ }
+
+ /**
+ * 异常响应结果,自定义错误编码
+ *
+ * @param resultStatusEnum 自定义错误编码枚举
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> error(final ResultStatusEnum resultStatusEnum) {
+ return new BaseResult<>(resultStatusEnum.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, resultStatusEnum.getMessage(), null, null, null, null);
+ }
+
+ /**
+ * 业务异常响应结果
+ *
+ * @param be 业务异常
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> error(final BusinessException be) {
+ return new BaseResult<>(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, be.getErrorMessage(), null, null, null, null);
+ }
+
+ /**
+ * 异常响应结果,自定义信息
+ *
+ * @param message 自定义信息
+ * @return 响应结果
+ */
+ public static <T> BaseResult<T> error(final String message) {
+ return new BaseResult<>(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), null, false, message, null, null, null, null);
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java b/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java
new file mode 100644
index 0000000..aff97f9
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/base/SchemaBase.java
@@ -0,0 +1,31 @@
+package com.mesalab.common.base;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SchemaBase implements Serializable {
+
+ private String type;
+ private String name;
+ private String namespace;
+ private List<Map> fields;
+
+ public String getNamespace() {
+ return namespace = "com.zdjizhi";
+ }
+
+ public String getType() {
+ return type = "record";
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/BifangMysqlConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/BifangMysqlConfiguration.java
new file mode 100644
index 0000000..e7f71c0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/BifangMysqlConfiguration.java
@@ -0,0 +1,26 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Date: 2020-09-17 15:03
+ * @Author : liuyongqiang
+ * @ClassName : BifangMysqlConfiguration
+ * @Description : BifangMysql数据源配置
+ */
+@Data
+@Component
+public class BifangMysqlConfiguration {
+
+ @Value("${spring.datasource.url}")
+ private String url;
+
+ @Value("${spring.datasource.username}")
+ private String userName;
+
+ @Value("${spring.datasource.password}")
+ private String passWord;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java
new file mode 100644
index 0000000..fe684af
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseConfiguration.java
@@ -0,0 +1,34 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.qgw.model.api.ClickHouseHttpSource;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(ClickHouseProperties.class)
+public class ClickHouseConfiguration {
+
+ private final ClickHouseProperties clickhouseProperties;
+
+ @Autowired
+ public ClickHouseConfiguration(ClickHouseProperties clickhouseProperties) {
+ this.clickhouseProperties = clickhouseProperties;
+ }
+
+ @Bean(name="clickHouseHttpSource")
+ public ClickHouseHttpSource clickhouseHttpSource() {
+ ClickHouseHttpSource httpSource = new ClickHouseHttpSource();
+ httpSource.setUrl(StringUtil.substringAfter(clickhouseProperties.getUrl(), "//"));
+ httpSource.setDbName(clickhouseProperties.getDbname());
+ httpSource.setRealTimeAccount(clickhouseProperties.getRealTimeAccount());
+ httpSource.setLongTermAccount(clickhouseProperties.getLongTermAccount());
+
+ return httpSource;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseProperties.java
new file mode 100644
index 0000000..d7263f3
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ClickHouseProperties.java
@@ -0,0 +1,23 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "clickhouse")
+public class ClickHouseProperties {
+ private String url;
+ private String driverClassName;
+ private String dbname;
+
+ private DBAccount realTimeAccount = new DBAccount();
+
+ private DBAccount longTermAccount = new DBAccount();
+
+ @Data
+ public class DBAccount {
+ private String username;
+ private String password;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoConfiguration.java
new file mode 100644
index 0000000..03da75d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoConfiguration.java
@@ -0,0 +1,33 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.qgw.model.api.DruidIoHttpSource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(DruidIoProperties.class)
+public class DruidIoConfiguration {
+
+ private final DruidIoProperties druidIoProperties;
+
+ @Autowired
+ public DruidIoConfiguration(DruidIoProperties druidIoProperties) {
+ this.druidIoProperties = druidIoProperties;
+ }
+
+
+ @Bean(name="druidIoHttpSource")
+ public DruidIoHttpSource druidIoHttpSource() {
+ DruidIoHttpSource httpSource = new DruidIoHttpSource();
+ httpSource.setUrl(druidIoProperties.getUrl());
+ httpSource.setDbname(druidIoProperties.getDbname());
+ return httpSource;
+ }
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoProperties.java
new file mode 100644
index 0000000..ce996db
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/DruidIoProperties.java
@@ -0,0 +1,12 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "druid")
+public class DruidIoProperties {
+ private String url;
+ private String dbname;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineConfiguration.java
new file mode 100644
index 0000000..39267ef
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineConfiguration.java
@@ -0,0 +1,47 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.qgw.model.api.EngineConfigSource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(EngineProperties.class)
+public class EngineConfiguration {
+
+ private final EngineProperties engineProperties;
+
+ @Autowired
+ public EngineConfiguration(EngineProperties engineProperties) {
+ this.engineProperties = engineProperties;
+ }
+
+ @Bean(name="engineConfigSource")
+ public EngineConfigSource engineConfigSource() {
+ EngineConfigSource engineConfigSource = new EngineConfigSource();
+ engineConfigSource.setMaxCacheNum(engineProperties.getMaxCacheNum());
+ engineConfigSource.setDefaultResultNum(engineProperties.getDefaultResultNum());
+ return engineConfigSource;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineProperties.java
new file mode 100644
index 0000000..1120765
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/EngineProperties.java
@@ -0,0 +1,12 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@ConfigurationProperties(prefix = "engine")
+public class EngineProperties {
+ private int maxCacheNum;
+ private int defaultResultNum;
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseConfiguration.java
new file mode 100644
index 0000000..ca79aa0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseConfiguration.java
@@ -0,0 +1,63 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.qgw.model.api.HBaseAPISource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.ConnectionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(HBaseProperties.class)
+public class HBaseConfiguration {
+
+ private final HBaseProperties hBaseProperties;
+
+ @Autowired
+ public HBaseConfiguration(HBaseProperties hBaseProperties) {
+ this.hBaseProperties = hBaseProperties;
+ }
+
+ @Bean(name = "hBaseAPISource")
+ public HBaseAPISource hBaseHttpSource() {
+ HBaseAPISource apiSource = new HBaseAPISource();
+ apiSource.setZookeeperQuorum(hBaseProperties.getZookeeperQuorum());
+ apiSource.setZookeeperPropertyClientPort(hBaseProperties.getZookeeperPropertyClientPort());
+ apiSource.setZookeeperParent(hBaseProperties.getZookeeperZnodeParent());
+ apiSource.setClientIpcPoolSize(hBaseProperties.getClientIpcPoolSize());
+ apiSource.setRpcTimeout(hBaseProperties.getRpcTimeout());
+ apiSource.setDbName(hBaseProperties.getDbName());
+ apiSource.setTableName(hBaseProperties.getTableName());
+ apiSource.setColumnFamily(hBaseProperties.getColumnFamily());
+ apiSource.setColumnName(hBaseProperties.getColumnName());
+ return apiSource;
+ }
+
+ @Bean(name = "hbaseConnection")
+ public Connection getConnection() {
+ org.apache.hadoop.conf.Configuration conf = null;
+ Connection con = null;
+ if (conf == null) {
+ conf = org.apache.hadoop.hbase.HBaseConfiguration.create();
+ conf.set("hbase.zookeeper.quorum", hBaseProperties.getZookeeperQuorum());
+ conf.set("hbase.zookeeper.property.clientPort", hBaseProperties.getZookeeperPropertyClientPort());
+ conf.set("hbase.zookeeper.znode.parent", hBaseProperties.getZookeeperZnodeParent());
+ conf.set("hbase.rpc.timeout", hBaseProperties.getRpcTimeout());
+ conf.set("hbase.client.ipc.pool.size", hBaseProperties.getClientIpcPoolSize());
+ conf.set("hbase.client.ipc.pool.type", "ThreadLocalPool");
+ conf.set("zookeeper.recovery.retry.intervalmill", "200");
+ conf.set("zookeeper.recovery.retry", "3");
+ conf.set("hbase.client.retries.number", "3");
+ }
+ try {
+ con = ConnectionFactory.createConnection(conf);
+ } catch (Exception e) {
+ log.error("create connection error: ", e);
+ }
+ return con;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseProperties.java
new file mode 100644
index 0000000..9c6cb67
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/HBaseProperties.java
@@ -0,0 +1,18 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "hbase")
+public class HBaseProperties {
+ private String zookeeperQuorum;
+ private String zookeeperPropertyClientPort;
+ private String zookeeperZnodeParent;
+ private String dbName;
+ private String tableName;
+ private String columnFamily;
+ private String columnName;
+ private String clientIpcPoolSize;
+ private String rpcTimeout;
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminConfiguration.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminConfiguration.java
new file mode 100644
index 0000000..dbfe9e0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminConfiguration.java
@@ -0,0 +1,30 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.qgw.model.api.JobAdminHttpSource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(JobAdminProperties.class)
+public class JobAdminConfiguration {
+
+ private final JobAdminProperties jobAdminProperties;
+
+ @Autowired
+ public JobAdminConfiguration(JobAdminProperties jobAdminProperties) {
+ this.jobAdminProperties = jobAdminProperties;
+ }
+
+ @Bean(name = "jobAdminHttpSource")
+ public JobAdminHttpSource jobAdminHttpSource() {
+ JobAdminHttpSource httpSource = new JobAdminHttpSource();
+ httpSource.setUrl(jobAdminProperties.getUrl());
+ httpSource.setUserName(jobAdminProperties.getUserName());
+ httpSource.setPassword(jobAdminProperties.getPassword());
+ return httpSource;
+ }
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminProperties.java
new file mode 100644
index 0000000..98c20e9
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/JobAdminProperties.java
@@ -0,0 +1,16 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "xxl-job-admin")
+public class JobAdminProperties {
+
+ private String url;
+
+ private String userName;
+
+ private String password;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectAuthorProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectAuthorProperties.java
new file mode 100644
index 0000000..767e28d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectAuthorProperties.java
@@ -0,0 +1,20 @@
+package com.mesalab.common.configuration;
+
+import lombok.Data;
+
+/**
+ * 项目作者联系方式
+ *
+ * @author dazzlzy
+ * @date 2018/5/26
+ */
+@Data
+public class ProjectAuthorProperties {
+
+ private String name;
+
+ private String url;
+
+ private String email;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectProperties.java b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectProperties.java
new file mode 100644
index 0000000..84ac4ac
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/configuration/ProjectProperties.java
@@ -0,0 +1,107 @@
+package com.mesalab.common.configuration;
+
+import com.mesalab.common.enums.EnvironmentEnum;
+import com.mesalab.common.enums.EnvironmentGroupEnum;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 项目配置
+ *
+ * @author dazzlzy
+ * @date 2018/5/26
+ */
+@Data
+@Repository
+@ConfigurationProperties("project")
+public class ProjectProperties {
+
+ /**
+ * 工程名
+ */
+ private String name;
+
+ /**
+ * 版本
+ */
+ private String version;
+
+ /**
+ * 工程描述
+ */
+ private String description;
+
+ /**
+ * 项目组织标识
+ */
+ private String groupId;
+
+ /**
+ * 项目标识
+ */
+ private String artifactId;
+
+ /**
+ * 项目根目录
+ */
+ private String basedir;
+
+ /**
+ * 核心项目包
+ */
+ private String corePackage;
+
+ /**
+ * 业务项目包
+ */
+ private String servicePackage;
+
+ /**
+ * 当前环境值
+ */
+ private String[] env;
+
+ /**
+ * 项目作者
+ */
+ private ProjectAuthorProperties author;
+
+ /**
+ * 注入的spring环境上下文
+ */
+ private final Environment environment;
+
+ @Autowired
+ public ProjectProperties(Environment environment) {
+ this.environment = environment;
+ this.env = environment.getActiveProfiles();
+ }
+
+ /**
+ * 是否是生产环境
+ * 从运行环境中读取最后一个是否为生产环境
+ *
+ * @return boolean 是否为生产环境
+ */
+ public boolean isProduct() {
+ List<String> runtimeEnvs = new ArrayList<>();
+ for (String s : this.env) {
+ if (EnvironmentGroupEnum.isRuntime(s)) {
+ runtimeEnvs.add(s);
+ }
+ }
+ if (runtimeEnvs.size() == 0) {
+ return false;
+ }
+ //最后一个运行环境, 如果spring.profiles.active=dev, prod, mysql 则运行环境为dev, prod, 最后一个运行环境为prod,是生产环境
+ String env = runtimeEnvs.get(runtimeEnvs.size() - 1);
+ return EnvironmentEnum.PROD.getName().equals(env);
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/BooleanEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/BooleanEnum.java
new file mode 100644
index 0000000..bc5ee49
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/BooleanEnum.java
@@ -0,0 +1,30 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * boolean枚举,YES/NO
+ *
+ * @author dazzlzy
+ * @date 2018/5/7
+ */
+@Getter
+public enum BooleanEnum {
+
+ /**
+ * YES: 1
+ */
+ YES(1),
+
+ /**
+ * NO: 0
+ */
+ NO(0);
+
+ private int value;
+
+ BooleanEnum(int value) {
+ this.value = value;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/CookieEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/CookieEnum.java
new file mode 100644
index 0000000..898369b
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/CookieEnum.java
@@ -0,0 +1,23 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * Cookie枚举
+ *
+ * @author dazzlzy
+ * @date 2018/5/26
+ */
+@Getter
+public enum CookieEnum {
+ /**
+ * REMEMBER_ME: Cookie中存储的REMEMBER_ME
+ */
+ REMEMBER_ME("rememberMe"),;
+
+ private String value;
+
+ CookieEnum(String value) {
+ this.value = value;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/DBTypeEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/DBTypeEnum.java
new file mode 100644
index 0000000..418ef80
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/DBTypeEnum.java
@@ -0,0 +1,12 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum DBTypeEnum {
+ CLICKHOUSE("clickHouse"),
+ DRUID("druid"),
+ HBASE("hbase"),;
+ private String value;
+ DBTypeEnum(String value) {this.value = value;}
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentEnum.java
new file mode 100644
index 0000000..421fb63
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentEnum.java
@@ -0,0 +1,30 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * 运行环境枚举
+ *
+ * @author dazzlzy
+ * @date 2018/5/26
+ */
+@Getter
+public enum EnvironmentEnum {
+
+ /**
+ * 开发环境
+ */
+ DEV("dev"),
+ /**
+ * 生产环境
+ */
+ PROD("prod"),;
+
+ private String name;
+
+ EnvironmentEnum(String name) {
+ this.name = name;
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentGroupEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentGroupEnum.java
new file mode 100644
index 0000000..5e433e0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/EnvironmentGroupEnum.java
@@ -0,0 +1,45 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * 运行环境组枚举
+ *
+ * @author dazzlzy
+ * @date 2018/5/26
+ */
+@Getter
+public enum EnvironmentGroupEnum {
+
+ /**
+ * RUNTIME运行环境组:
+ * 1. DEV(开发环境)
+ * 2. PROD(生产环境)
+ */
+ RUNTIME(new EnvironmentEnum[]{EnvironmentEnum.DEV, EnvironmentEnum.PROD}),;
+
+ /**
+ * 运行环境
+ */
+ private EnvironmentEnum[] environments;
+
+ EnvironmentGroupEnum(EnvironmentEnum[] environments) {
+ this.environments = environments;
+ }
+
+ /**
+ * 是否是runtime运行环境组
+ *
+ * @param s 环境名
+ * @return boolean
+ */
+ public static boolean isRuntime(String s) {
+ EnvironmentEnum[] environmentEnums = RUNTIME.getEnvironments();
+ for (EnvironmentEnum environmentEnum : environmentEnums) {
+ if (environmentEnum.getName().equals(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/JobHandlerEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/JobHandlerEnum.java
new file mode 100644
index 0000000..1ef1d05
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/JobHandlerEnum.java
@@ -0,0 +1,21 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+
+@Getter
+public enum JobHandlerEnum {
+
+ DELETE_TRAFFIC_DATA_JOB_HANDLER("deleteTrafficDataJobHandler"),
+ DELETE_REPORT_AND_METRICS_DATA_JOB_HANDLER("deleteReportAndMetricsDataJobHandler"),
+ DELETE_FILES_JOB_HANDLER("deleteFilesJobHandler"),
+ DELETE_ALL_TRAFFIC_DATA_JOB_HANDLER("deleteAllTrafficDataJobHandler"),
+ DELETE_ALL_REPORT_AND_METRICS_DATA_JOB_HANDLER("deleteAllReportAndMetricsDataJobHandler"),
+ DELETE_ALL_FILES_JOB_HANDLER("deleteAllFilesJobHandler"),
+ ;
+ private String value;
+
+ JobHandlerEnum(String value) {
+ this.value = value;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryFormatEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryFormatEnum.java
new file mode 100644
index 0000000..741139c
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryFormatEnum.java
@@ -0,0 +1,11 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum QueryFormatEnum {
+ JSON("json"),
+ CSV("csv"),;
+ private String value;
+ QueryFormatEnum(String value) {this.value = value;}
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryOptionEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryOptionEnum.java
new file mode 100644
index 0000000..84a94af
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryOptionEnum.java
@@ -0,0 +1,14 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum QueryOptionEnum {
+ REAL_TIME("real-time"),
+ LONG_TERM("long-term"),
+ SYNTAX_CHECK("syntax-check");
+ private String value;
+ QueryOptionEnum(String value) {this.value = value;}
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryParamEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryParamEnum.java
new file mode 100644
index 0000000..b9718eb
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/QueryParamEnum.java
@@ -0,0 +1,12 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum QueryParamEnum {
+ QUERY("query"),
+ FORMAT("format"),
+ OPTION("option"),;
+ private String value;
+ QueryParamEnum(String value) {this.value = value;}
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultCodeEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultCodeEnum.java
new file mode 100644
index 0000000..c2dd16e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultCodeEnum.java
@@ -0,0 +1,30 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * BaseResult的业务状态码
+ *
+ * @author
+ * @date
+ */
+@Getter
+public enum ResultCodeEnum {
+
+ EXECUTE_SUCCESS("200666", "成功"),
+ PARAM_SYNTAX_ERROR("400001", "参数检查异常"),
+ SQL_SYNTAX_ERROR("400010", "SQL语句检查异常"),
+ SQL_EXECUTION_ERROR("500001", "SQL 执行异常"),
+ ENGINE_STATISTICS_ERROR("500010", "引擎计算异常"),
+ UNKNOW_ERROR("555999", "执行失败");
+
+
+
+ private String code;
+ private String message;
+
+ ResultCodeEnum(String code, String message) {
+ this.code = code;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultStatusEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultStatusEnum.java
new file mode 100644
index 0000000..dbd08eb
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/ResultStatusEnum.java
@@ -0,0 +1,33 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * BaseResult的http状态编码枚举
+ *
+ * @author
+ * @date 2018/3/21
+ */
+@Getter
+public enum ResultStatusEnum {
+ /**
+ * SUCCESS: 200 成功
+ * FAIL: 400 失败
+ * NOT_FOUND: 404 不存在
+ * SERVER_ERROR: 500 网络服务异常
+ */
+ SUCCESS(200, "成功"),
+ FAIL(400, "失败"),
+ NOT_FOUND(404, "不存在"),
+ REQ_FORBIDDEN(403, "重复请求"),
+ SERVER_ERROR(500, "服务异常");
+
+ private int code;
+
+ private String message;
+
+ ResultStatusEnum(int code, String message) {
+ this.code = code;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/enums/SessionEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/SessionEnum.java
new file mode 100644
index 0000000..e475ddc
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/enums/SessionEnum.java
@@ -0,0 +1,24 @@
+package com.mesalab.common.enums;
+
+import lombok.Getter;
+
+/**
+ * Session枚举
+ *
+ * @author zhaozhenyao
+ * @date 2018/5/10
+ */
+@Getter
+public enum SessionEnum {
+
+ /**
+ * CURRENT_USER: session中存储的当前用户
+ */
+ CURRENT_USER("CURRENT_USER"),;
+
+ private String value;
+
+ SessionEnum(String value) {
+ this.value = value;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/exception/BusinessException.java b/galaxy-query-engine/src/main/java/com/mesalab/common/exception/BusinessException.java
new file mode 100644
index 0000000..6cbb1ac
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/exception/BusinessException.java
@@ -0,0 +1,51 @@
+package com.mesalab.common.exception;
+
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import lombok.*;
+
+/**
+ * 业务异常
+ *
+ * @author dazzlzy
+ * @date 2018/3/22
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BusinessException extends RuntimeException {
+
+ /**
+ * 异常代码
+ */
+ @Builder.Default
+ private int errorStatus = ResultStatusEnum.SERVER_ERROR.getCode();
+
+ @Builder.Default
+ private String errorCode = ResultCodeEnum.UNKNOW_ERROR.getCode();
+
+
+ /**
+ * 异常信息
+ */
+ private String errorMessage;
+
+ public BusinessException(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+
+ public BusinessException(String errorMessage, Throwable e) {
+ super(errorMessage, e);
+ }
+
+ public BusinessException(int errorStatus, String errorCode, String errorMessage, Throwable e) {
+ super(errorMessage, e);
+ this.errorStatus = errorStatus;
+ this.errorCode = errorCode;
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ActiveRecordInit.java b/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ActiveRecordInit.java
new file mode 100644
index 0000000..ab8f595
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ActiveRecordInit.java
@@ -0,0 +1,33 @@
+package com.mesalab.common.plugin;
+
+import com.jfinal.plugin.druid.DruidPlugin;
+import com.mesalab.common.configuration.BifangMysqlConfiguration;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @Date: 2020-09-17 15:24
+ * @Author : liuyongqiang
+ * @ClassName : ActiveRecordInit
+ * @Description : ActiveRecordInit
+ */
+@Slf4j
+@Component
+public class ActiveRecordInit {
+
+ @Autowired
+ BifangMysqlConfiguration bmc;
+
+ @PostConstruct
+ public void initDialect() {
+ DruidPlugin dp = new DruidPlugin(bmc.getUrl(), bmc.getUserName(), bmc.getPassWord());
+ ArpStartPlugin arp = new ArpStartPlugin(dp);
+ arp.addSqlTemplate("sql-temelate.sql");
+ dp.start();
+ arp.start();
+ log.info("Initializing ActiveRecordPlugin Complete");
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ArpStartPlugin.java b/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ArpStartPlugin.java
new file mode 100644
index 0000000..8e0cfcf
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/plugin/ArpStartPlugin.java
@@ -0,0 +1,29 @@
+package com.mesalab.common.plugin;
+
+import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
+import com.jfinal.plugin.activerecord.IDataSourceProvider;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Date: 2020-10-09 16:09
+ * @Author : liuyongqiang
+ * @ClassName : ArpStartPlugin
+ * @Description : ArpStartPlugin
+ */
+@Slf4j
+public class ArpStartPlugin extends ActiveRecordPlugin {
+
+ public ArpStartPlugin(IDataSourceProvider dataSourceProvider) {
+ super(dataSourceProvider);
+ }
+
+ @Override
+ public boolean start() {
+ try {
+ super.start();
+ } catch (Exception e) {
+ log.error("ArpStartPlugin init error:{}", e.getMessage());
+ }
+ return true;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/support/IConvertor.java b/galaxy-query-engine/src/main/java/com/mesalab/common/support/IConvertor.java
new file mode 100644
index 0000000..fabccfc
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/support/IConvertor.java
@@ -0,0 +1,20 @@
+package com.mesalab.common.support;
+
+
+/**
+ * 转换器接口,可以将Source转换为Target
+ *
+ * @author dazzlzy
+ * @date 2018/5/9
+ */
+public interface IConvertor<Source, Target> {
+
+ /**
+ * 将Source转换为Target
+ *
+ * @param source 需要转换的对象
+ * @return 转换后的对象
+ */
+ Target convert(Source source);
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/BigDecimalUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/BigDecimalUtil.java
new file mode 100644
index 0000000..9ae7c38
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/BigDecimalUtil.java
@@ -0,0 +1,179 @@
+package com.mesalab.common.utils;
+
+import java.math.BigDecimal;
+
+/**
+ * 数字处理类,解决丢失精度问题
+ *
+ * @author dazzlzy
+ * @date 2018/3/15
+ */
+public class
+BigDecimalUtil {
+
+ /**
+ * 默认除法运算精度
+ */
+ private static final int DEFAULT_DIV_SCALE = 6;
+
+ private BigDecimalUtil() {
+ }
+
+ /**
+ * 提供精确的加法运算。
+ *
+ * @param v1 被加数
+ * @param v2 加数
+ * @return 两个参数的和
+ */
+ public static double add(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(Double.toString(v1));
+ BigDecimal b2 = new BigDecimal(Double.toString(v2));
+ return b1.add(b2).doubleValue();
+ }
+
+ /**
+ * 提供精确的减法运算。
+ *
+ * @param v1 被减数
+ * @param v2 减数
+ * @return 两个参数的差
+ */
+ public static double sub(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(Double.toString(v1));
+ BigDecimal b2 = new BigDecimal(Double.toString(v2));
+ return b1.subtract(b2).doubleValue();
+ }
+
+ /**
+ * 提供精确的乘法运算。
+ *
+ * @param v1 被乘数
+ * @param v2 乘数
+ * @return 两个参数的积
+ */
+ public static double mul(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(Double.toString(v1));
+ BigDecimal b2 = new BigDecimal(Double.toString(v2));
+ return b1.multiply(b2).doubleValue();
+ }
+
+ /**
+ * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
+ * 小数点以后10位,以后的数字四舍五入。
+ *
+ * @param v1 被除数
+ * @param v2 除数
+ * @return 两个参数的商
+ */
+ public static double div(double v1, double v2) {
+ return div(v1, v2, DEFAULT_DIV_SCALE);
+ }
+
+ /**
+ * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
+ * 定精度,以后的数字四舍五入。
+ *
+ * @param v1 被除数
+ * @param v2 除数
+ * @param scale 表示表示需要精确到小数点以后几位。
+ * @return 两个参数的商
+ */
+ public static double div(double v1, double v2, int scale) {
+ if (scale < 0) {
+ throw new IllegalArgumentException("The scale must be a positive integer or zero");
+ }
+ BigDecimal b1 = new BigDecimal(Double.toString(v1));
+ BigDecimal b2 = new BigDecimal(Double.toString(v2));
+ return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
+ }
+
+ /**
+ * 提供精确的小数位四舍五入处理。
+ *
+ * @param v 需要四舍五入的数字
+ * @param scale 小数点后保留几位
+ * @return 四舍五入后的结果
+ */
+ public static double round(double v, int scale) {
+ if (scale < 0) {
+ throw new IllegalArgumentException("The scale must be a positive integer or zero");
+ }
+ BigDecimal b = new BigDecimal(Double.toString(v));
+ BigDecimal one = new BigDecimal("1");
+ return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
+ }
+
+ /**
+ * 提供精确的类型转换(Float)
+ *
+ * @param v 需要被转换的数字
+ * @return 返回转换结果
+ */
+ public static float convertsToFloat(double v) {
+ BigDecimal b = new BigDecimal(v);
+ return b.floatValue();
+ }
+
+ /**
+ * 提供精确的类型转换(Int)不进行四舍五入
+ *
+ * @param v 需要被转换的数字
+ * @return 返回转换结果
+ */
+ public static int convertsToInt(double v) {
+ BigDecimal b = new BigDecimal(v);
+ return b.intValue();
+ }
+
+ /**
+ * 提供精确的类型转换(Long)
+ *
+ * @param v 需要被转换的数字
+ * @return 返回转换结果
+ */
+ public static long convertsToLong(double v) {
+ BigDecimal b = new BigDecimal(v);
+ return b.longValue();
+ }
+
+ /**
+ * 返回两个数中大的一个值
+ *
+ * @param v1 需要被对比的第一个数
+ * @param v2 需要被对比的第二个数
+ * @return 返回两个数中大的一个值
+ */
+ public static double returnMax(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(v1);
+ BigDecimal b2 = new BigDecimal(v2);
+ return b1.max(b2).doubleValue();
+ }
+
+ /**
+ * 返回两个数中小的一个值
+ *
+ * @param v1 需要被对比的第一个数
+ * @param v2 需要被对比的第二个数
+ * @return 返回两个数中小的一个值
+ */
+ public static double returnMin(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(v1);
+ BigDecimal b2 = new BigDecimal(v2);
+ return b1.min(b2).doubleValue();
+ }
+
+ /**
+ * 精确对比两个数字
+ *
+ * @param v1 需要被对比的第一个数
+ * @param v2 需要被对比的第二个数
+ * @return 如果两个数一样则返回0,如果第一个数比第二个数大则返回1,反之返回-1
+ */
+ public static int compareTo(double v1, double v2) {
+ BigDecimal b1 = new BigDecimal(v1);
+ BigDecimal b2 = new BigDecimal(v2);
+ return b1.compareTo(b2);
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java
new file mode 100644
index 0000000..43736f0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ConvertUtil.java
@@ -0,0 +1,350 @@
+package com.mesalab.common.utils;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.*;
+import com.mesalab.common.support.IConvertor;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.nutz.lang.Lang;
+import java.util.*;
+
+/**
+ * 转换器工具类
+ *
+ * @author dazzlzy
+ * @date 2018/5/9
+ */
+public class ConvertUtil {
+
+ public static final String GROUP_SEPRATOR = "|G|";
+
+ enum Fill {
+
+ NONE(""), NULL("NULL"), ZERO("0"), PREVIOUS("previous"), NEXT("next");
+
+ private final String value;
+
+ Fill(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ }
+
+
+ /**
+ * 将来源collection转换成目标list.
+ *
+ * @param sources 来源
+ * @param convertor 转换器
+ * @param ignoreNull 是否忽略空值
+ * @param duplicateRemoval 是否去除重复
+ * @param <Source> 来源
+ * @param <Target> 目标对象
+ * @return 转换后的List
+ */
+ public static <Source, Target> List<Target> convert(Collection<Source> sources, IConvertor<Source, Target> convertor,
+ boolean ignoreNull, boolean duplicateRemoval) {
+ // 返回目标值
+ Collection<Target> targets;
+
+ //去重使用HashSet,不去冲使用ArrayList
+ targets = duplicateRemoval ? new HashSet<>() : new ArrayList<>();
+
+ // 来源不为空
+ if (sources != null && sources.size() > 0) {
+ for (Source source : sources) {
+ Target target = convertor.convert(source);
+ // 不忽略空值或者目标不为空
+ if (!ignoreNull || target != null) {
+ // 添加目标
+ targets.add(convertor.convert(source));
+ }
+ }
+ }
+ // 转换成list
+ return Lang.collection2list(targets);
+ }
+
+ /**
+ * 将来源collection转换成目标list.
+ *
+ * @param sources 来源
+ * @param convertor 转换器
+ * @param <Source> 来源
+ * @param <Target> 目标对象
+ * @return 转换后的List
+ */
+ public static <Source, Target> List<Target> convert(Collection<Source> sources, IConvertor<Source, Target> convertor) {
+ return convert(sources, convertor, false, false);
+ }
+
+ /**
+ * 将来源按转换器的方式转换成Map<Key, Obj>的方式.
+ *
+ * @param sources 来源
+ * @param convertor 转换器
+ * @param <Key> 返回的Map的key的类型
+ * @param <Obj> 返回的Map的value的类型,即来源集合中的类型
+ * @return 转换后的对象类型
+ */
+ public static <Key, Obj> Map<Key, Obj> map(Collection<Obj> sources, IConvertor<Obj, Key> convertor) {
+ if (sources == null) {
+ return new HashMap<>(16);
+ }
+ Map<Key, Obj> mapping = new HashMap<>(sources.size());
+ // 来源不为空
+ if (sources.size() > 0) {
+ for (Obj obj : sources) {
+ Key key = convertor.convert(obj);
+ mapping.put(key, obj);
+ }
+ }
+ return mapping;
+ }
+
+ /**
+ * 将来源按转换器的方式转换成Map<Key,List<Obj>>的方式.
+ *
+ * @param sources 来源
+ * @param convertor 转换器
+ * @param <Key> 返回的Map的key的类型
+ * @param <Obj> 返回的Map的value的List包含类型
+ * @return 转换后的对象类型
+ */
+ public static <Key, Obj> Map<Key, List<Obj>> maplist(Collection<Obj> sources, IConvertor<Obj, Key> convertor) {
+ Map<Key, List<Obj>> mapping = new HashMap<>(16);
+ // 来源不为空
+ if (sources != null && sources.size() > 0) {
+ for (Obj obj : sources) {
+ Key key = convertor.convert(obj);
+ List<Obj> list = mapping.get(key);
+
+ if (list == null) {
+ mapping.put(key, Lang.list(obj));
+ } else {
+ list.add(obj);
+ }
+ }
+ }
+ return mapping;
+ }
+
+ /**
+ * 将时序特征的数据,转换成层级结构;
+ * 例如:Map<groupKey, timeseries Map>
+ * Map<timeGran,Metrics Map>
+ * Map<metric,value>
+ *
+ * @param sources
+ * @param groupLabel
+ * @param timeGranLabel
+ * @return
+ */
+ public static Map<String, Map<String, Map<String, Object>>> convertResultListToTimeseries(Collection<Object> sources, String groupLabel, String timeGranLabel) {
+
+
+ Map<String, Map<String, Map<String, Object>>> resultMap = Maps.newLinkedHashMap();
+
+ for (Object source : sources) {
+
+ Map<String, Object> sourceMap = ((Map<String, Object>) source);
+
+ String groupKey = null;
+ if (StringUtil.isBlank(groupLabel)) {
+ groupKey = "default";
+
+ } else {
+ for(String group : StringUtils.split(groupLabel, GROUP_SEPRATOR)) {
+ groupKey = Joiner.on(GROUP_SEPRATOR).skipNulls().join(groupKey, sourceMap.get(group));
+ sourceMap.remove(group);
+ }
+ }
+
+
+ String timeGran = sourceMap.get(timeGranLabel).toString();
+ sourceMap.remove(timeGranLabel);
+
+ Map groupMap = resultMap.get(groupKey);
+
+ if (StringUtil.isEmpty(groupMap)) {
+ groupMap = Maps.newTreeMap();
+ groupMap.put(timeGran, sourceMap);
+ resultMap.put(groupKey,groupMap);
+
+ } else {
+
+ groupMap.put(timeGran, sourceMap);
+ }
+
+
+ }
+
+ return resultMap;
+
+ }
+
+
+
+ public static List<Map<String, Object>> convertTimeseriesToList(Map<String, Map<String, Map<String, Object>>> target, String groupLabel, String timeGranLabel) {
+ List<Map<String, Object>> results = Lists.newArrayList();
+ String[] grouLabelArray;
+ String[] groupKeyArray;
+ for(String groupKey : target.keySet()) {
+
+ Map<String, Map<String, Object>> groupMap = target.get(groupKey);
+
+ for (Map.Entry<String, Map<String,Object>> entry: groupMap.entrySet()) {
+
+ Map<String, Object> resultMap = Maps.newLinkedHashMap();
+ resultMap.put(timeGranLabel, entry.getKey());
+ if (StringUtil.isNotBlank(groupLabel)) {
+ grouLabelArray = StringUtils.split(groupLabel, GROUP_SEPRATOR);
+ groupKeyArray = StringUtils.splitByWholeSeparatorPreserveAllTokens(groupKey, GROUP_SEPRATOR);
+ for (int i = 0; i < grouLabelArray.length; i++) {
+ resultMap.put(grouLabelArray[i], StringUtil.isBlank(groupKey) ? StringUtil.EMPTY : groupKeyArray[i]);
+ }
+
+ }
+ //metrics
+ resultMap.putAll(entry.getValue());
+ results.add(resultMap);
+
+ }
+ }
+
+ target.clear();
+
+ return results;
+ }
+
+
+
+
+
+ /**
+ * 时序数据补全操作
+ * @param sources TreeMap<timeGran, metricMap>
+ * @param dateList
+ * @param fill
+ * @return
+ */
+ public static Map<String, Map<String, Object>> completeTimeseries(TreeMap<String, Map<String, Object>> sources,
+ List<Date> dateList, String fill) {
+
+ Map<String, Object> defaultElement = Maps.newHashMap(sources.firstEntry().getValue());
+
+
+ if (fill.equalsIgnoreCase(Fill.ZERO.name())){
+ for(String key: defaultElement.keySet()){
+ defaultElement.put(key, Integer.valueOf(Fill.ZERO.getValue()));
+ }
+
+ } else if (fill.equalsIgnoreCase(Fill.NULL.name())){
+ for(String key: defaultElement.keySet()) {
+ defaultElement.put(key, Fill.NULL.value);
+ }
+ } else if (fill.equalsIgnoreCase(Fill.NONE.name())) {
+ for(String key: defaultElement.keySet()) {
+ defaultElement.put(key, Fill.NONE.value);
+ }
+ } else {
+ defaultElement.clear();
+ }
+
+ TreeMap<String, Map<String, Object>> target = Maps.newTreeMap(sources);
+
+ boolean isTimestamp = StringUtil.isNumeric(sources.firstKey());
+ for(Date date : dateList) {
+
+ String timeKey;
+ if (isTimestamp) {
+ timeKey = String.valueOf(date.getTime()/1000);
+ } else {
+ timeKey = DateUtils.getFormatDate(date, DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ }
+
+ Map<String, Object> metricsMap = sources.get(timeKey);
+ if (StringUtil.isEmpty(metricsMap)) {
+ target.put(timeKey, defaultElement);
+ }
+ }
+
+
+
+ if (StringUtil.isEmpty(defaultElement)) {
+
+ defaultElement = getDefaultElement(sources.get(sources.firstKey()));
+
+ for (String key : target.keySet()) {
+
+ if (StringUtil.isEmpty(target.get(key))) {
+
+ Map<String, Object> element= getPositionElement(target, key, fill);
+
+ if (StringUtil.isEmpty(element)) {
+ target.put(key, defaultElement);
+ } else {
+ target.put(key, element);
+ }
+
+
+ }
+
+
+ }
+
+ }
+
+
+ return target;
+ }
+
+
+
+
+
+ private static Map<String, Object> getPositionElement(TreeMap<String, Map<String, Object>> target,
+ String key, String fill) {
+ Map<String, Object> element = Maps.newHashMap();
+
+ if (fill.equalsIgnoreCase(Fill.PREVIOUS.name())) {
+ if (StringUtil.isNotEmpty(target.lowerEntry(key))) {
+ element = target.lowerEntry(key).getValue();
+ }
+
+
+ } else if (fill.equalsIgnoreCase(Fill.NEXT.name())) {
+ if (StringUtil.isNotEmpty(target.higherEntry(key))) {
+ element = target.higherEntry(key).getValue();
+ }
+
+
+ }
+ return element;
+ }
+
+
+
+ private static Map<String, Object> getDefaultElement(Map<String, Object> firstElement) {
+ Map<String, Object> element = Maps.newHashMap(firstElement);
+
+ for (String key : element.keySet()) {
+ element.put(key, Fill.NONE.getValue());
+ }
+
+ return element;
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java
new file mode 100644
index 0000000..5a26fb1
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/IPUtil.java
@@ -0,0 +1,84 @@
+package com.mesalab.common.utils;
+
+import com.zdjizhi.utils.IpLookup;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * IP工具类
+ *
+ * @author dazzlzy
+ * @date 2018/4/1
+ */
+public class IPUtil {
+
+ private static final String UNKNOWN = "unknown";
+ private static final String DEFAULT_SEPARATOR = ",";
+ private static final int DEFAULT_IP_LENGTH = 15;
+ private static IpLookup ipLookup = new IpLookup.Builder(true)
+ .loadDataFileV4("dat/ip_v4.mmdb")
+ .loadDataFileV6("dat/ip_v6.mmdb")
+ .loadDataFilePrivateV4("dat/ip_private_v4.mmdb")
+ .loadDataFilePrivateV4("dat/ip_private_v6.mmdb")
+ .loadAsnDataFileV4("dat/asn_v4.mmdb")
+ .loadAsnDataFileV6("dat/asn_v6.mmdb")
+ .build();
+
+ public static String getGeo(String ip) {
+ return ipLookup.latLngLookup(ip);
+ }
+
+ public static String getCityDetail(String ip) {
+ return ipLookup.cityLookupDetail(ip);
+ }
+
+ public static String getCountry(String ip) {
+ return ipLookup.countryLookup(ip);
+ }
+
+
+
+ /**
+ * 从http request中获取真实IP
+ *
+ * @param request HttpServletRequest
+ * @return 真实IP
+ */
+ public static String parseIP(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ // 代理IP
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ // 网宿cdn的真实ip
+ ip = request.getHeader("Cdn-Src-Ip");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ // 蓝讯cdn的真实ip
+ ip = request.getHeader("HTTP_CLIENT_IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ // 真实IP
+ ip = request.getRemoteAddr();
+ }
+ // 如果是多级代理,那么取第一个ip为客户端ip
+ if (ip != null && ip.length() > DEFAULT_IP_LENGTH && ip.contains(DEFAULT_SEPARATOR)) {
+ String[] ips = ip.split(DEFAULT_SEPARATOR);
+ for (String strIp : ips) {
+ if (!UNKNOWN.equalsIgnoreCase(strIp)) {
+ ip = strIp;
+ break;
+ }
+ }
+ }
+ return ip;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/JsonMapper.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/JsonMapper.java
new file mode 100644
index 0000000..41702e0
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/JsonMapper.java
@@ -0,0 +1,237 @@
+/**
+ * Copyright &copy; 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
+ */
+package com.mesalab.common.utils;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser.Feature;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.util.JSONPObject;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.TimeZone;
+
+
+/**
+ * 简单封装Jackson,实现JSON String<->Java Object的Mapper. 封装不同的输出风格,
+ * 使用不同的builder函数创建实例.
+ *
+ * @author
+ * @version
+ */
+public class JsonMapper extends ObjectMapper {
+
+ private static final long serialVersionUID = 1L;
+
+ private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
+
+ private static JsonMapper mapper;
+
+ public JsonMapper() {
+ this(Include.ALWAYS);
+ }
+
+ public JsonMapper(Include include) {
+ // 设置输出时包含属性的风格
+ if (include != null) {
+ this.setSerializationInclusion(include);
+ }
+ // 允许单引号、允许不带引号的字段名称
+ this.enableSimple();
+ // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
+ this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ // 空值
+ /*
+ * this.getSerializerProvider().setNullValueSerializer(new
+ * JsonSerializer<Object>(){
+ *
+ * @Override public void serialize(Object value, JsonGenerator jgen,
+ * SerializerProvider provider) throws IOException,
+ * JsonProcessingException { jgen.writeString(""); } });
+ */
+ this.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+ // 进行HTML解码。
+ this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>() {
+ @Override
+ public void serialize(String value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException {
+ jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
+ }
+ }));
+ // 设置时区
+ this.setTimeZone(TimeZone.getDefault());// getTimeZone("GMT+8:00")
+ }
+
+ /**
+ * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
+ */
+ public static JsonMapper getInstance() {
+ if (mapper == null) {
+ mapper = new JsonMapper();// .enableSimple();只输出非Null且非Empty
+ }
+ return mapper;
+ }
+
+ /**
+ * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
+ */
+ public static JsonMapper nonDefaultMapper() {
+ if (mapper == null) {
+ mapper = new JsonMapper(Include.NON_DEFAULT);
+ }
+ return mapper;
+ }
+
+ /**
+ * Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
+ */
+ public String toJson(Object object) {
+ try {
+ return this.writeValueAsString(object);
+ } catch (IOException e) {
+ logger.warn("write to json string error:" + object, e);
+ return null;
+ }
+ }
+
+ /**
+ * 反序列化POJO或简单Collection如List<String>.
+ *
+ * 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
+ *
+ * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
+ *
+ * @see #fromJson(String, JavaType)
+ */
+ public <T> T fromJson(String jsonString, Class<T> clazz) {
+ if (StringUtils.isEmpty(jsonString)) {
+ return null;
+ }
+ try {
+ return this.readValue(jsonString, clazz);
+ } catch (IOException e) {
+ logger.warn("parse json string error:" + jsonString, e);
+ return null;
+ }
+ }
+
+ /**
+ * 反序列化复杂Collection如List<Bean>, 先使用函數createCollectionType构造类型,然后调用本函数.
+ *
+ * @see #createCollectionType(Class, Class...)
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T fromJson(String jsonString, JavaType javaType) {
+ if (StringUtils.isEmpty(jsonString)) {
+ return null;
+ }
+ try {
+ return (T) this.readValue(jsonString, javaType);
+ } catch (IOException e) {
+ logger.warn("parse json string error:" + jsonString, e);
+ return null;
+ }
+ }
+
+ /**
+ * 構造泛型的Collection Type如: ArrayList<MyBean>,
+ * 则调用constructCollectionType(ArrayList.class,MyBean.class)
+ * HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
+ */
+ public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
+ return this.getTypeFactory().constructParametricType(collectionClass, elementClasses);
+ }
+
+ /**
+ * 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T update(String jsonString, T object) {
+ try {
+ return (T) this.readerForUpdating(object).readValue(jsonString);
+ } catch (JsonProcessingException e) {
+ logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
+ } catch (IOException e) {
+ logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
+ }
+ return null;
+ }
+
+ /**
+ * 輸出JSONP格式數據.
+ */
+ public String toJsonP(String functionName, Object object) {
+ return toJson(new JSONPObject(functionName, object));
+ }
+
+ /**
+ * 設定是否使用Enum的toString函數來讀寫Enum, 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
+ * 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
+ */
+ public JsonMapper enableEnumUseToString() {
+ this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+ this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ return this;
+ }
+
+
+ /**
+ * 允许单引号 允许不带引号的字段名称
+ */
+ public JsonMapper enableSimple() {
+ this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
+ this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+ return this;
+ }
+
+ /**
+ * 取出Mapper做进一步的设置或使用其他序列化API.
+ */
+ public ObjectMapper getMapper() {
+ return this;
+ }
+
+ /**
+ * 对象转换为JSON字符串
+ *
+ * @param object
+ * @return
+ */
+ public static String toJsonString(Object object) {
+ return JsonMapper.getInstance().toJson(object);
+ }
+
+ /**
+ * JSON字符串转换为对象
+ *
+ * @param jsonString
+ * @param clazz
+ * @return
+ */
+ public static Object fromJsonString(String jsonString, Class<?> clazz) {
+ return JsonMapper.getInstance().fromJson(jsonString, clazz);
+ }
+
+ /**
+ * JSON字符串转换为对象
+ *
+ * @param jsonString
+ * @param clazz
+ * @return
+ */
+ public static Object fromJsonList(String jsonString, Class<?> clazz) {
+ JavaType javaType = JsonMapper.getInstance().createCollectionType(ArrayList.class, clazz);
+ return JsonMapper.getInstance().fromJson(jsonString,javaType );
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/PropertiesFileUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/PropertiesFileUtil.java
new file mode 100644
index 0000000..ef8cf90
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/PropertiesFileUtil.java
@@ -0,0 +1,162 @@
+package com.mesalab.common.utils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * 资源文件读取工具
+ *
+ * @author dazzlzy
+ * @date 2018/4/4
+ */
+public class PropertiesFileUtil {
+
+ /**
+ * 当打开多个资源文件时,缓存资源文件
+ */
+ private static HashMap<String, PropertiesFileUtil> configMap = new HashMap<>();
+ /**
+ * 打开文件时间,判断超时使用
+ */
+ private Date loadTime;
+ /**
+ * 资源文件
+ */
+ private ResourceBundle resourceBundle;
+ /**
+ * 默认资源文件名称
+ */
+ private static final String NAME = "config";
+ /**
+ * 缓存时间
+ */
+ private static final Integer TIME_OUT = 60 * 1000;
+
+ /**
+ * 私有构造方法,创建单例
+ *
+ * @param name properties名
+ */
+ private PropertiesFileUtil(String name) {
+ this.loadTime = new Date();
+ this.resourceBundle = ResourceBundle.getBundle(name);
+ }
+
+ /**
+ * 获取单例对象
+ *
+ * @return 工具单例对象
+ */
+ public static synchronized PropertiesFileUtil getInstance() {
+ return getInstance(NAME);
+ }
+
+ /**
+ * 获取工具单例对象
+ *
+ * @param name properties名
+ * @return 工具单例对象
+ */
+ public static synchronized PropertiesFileUtil getInstance(String name) {
+ PropertiesFileUtil conf = configMap.get(name);
+ if (null == conf) {
+ conf = new PropertiesFileUtil(name);
+ configMap.put(name, conf);
+ }
+ // 判断是否打开的资源文件是否超时1分钟
+ if ((System.currentTimeMillis() - conf.getLoadTime().getTime()) > TIME_OUT) {
+ conf = new PropertiesFileUtil(name);
+ configMap.put(name, conf);
+ }
+ return conf;
+ }
+
+
+ /**
+ * 根据key读取value
+ *
+ * @param key 属性key
+ * @return 属性value
+ */
+ public String get(String key) {
+ try {
+ String value = resourceBundle.getString(key);
+ return value;
+ } catch (MissingResourceException e) {
+ return "";
+ }
+ }
+
+
+ /**
+ * 根据key读取value(整形)
+ *
+ * @param key 属性key
+ * @return 属性value(整形)
+ */
+ public Integer getInteger(String key) {
+ try {
+ String value = resourceBundle.getString(key);
+ return Integer.parseInt(value);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 根据key读取value(长整形)
+ *
+ * @param key 属性key
+ * @return 属性value(长整形)
+ */
+ public Long getLong(String key) {
+ try {
+ String value = resourceBundle.getString(key);
+ return Long.parseLong(value);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 根据key读取value(浮点)
+ *
+ * @param key 属性key
+ * @return 属性value(浮点)
+ */
+ public Double getDouble(String key) {
+ try {
+ String value = resourceBundle.getString(key);
+ return Double.parseDouble(value);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 根据key读取value(布尔)
+ *
+ * @param key 属性key
+ * @return 属性value(布尔值)
+ */
+ public boolean getBoolean(String key) {
+ try {
+ String value = resourceBundle.getString(key);
+ return "true".equals(value);
+ } catch (MissingResourceException e) {
+ return false;
+ }
+ }
+
+ /**
+ * 获取加载文件的时间
+ *
+ * @return 加载文件的时间
+ */
+ public Date getLoadTime() {
+ return loadTime;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java
new file mode 100644
index 0000000..07ee3d7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/QueryCacheUtils.java
@@ -0,0 +1,62 @@
+package com.mesalab.common.utils;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheStats;
+import com.zdjizhi.utils.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class QueryCacheUtils {
+
+ private static Cache<String,Object> cache;
+
+ private static final Logger log = LoggerFactory.getLogger(QueryCacheUtils.class);
+
+ static {
+ cache = CacheBuilder.newBuilder().maximumSize(100000)
+ .expireAfterWrite(5, TimeUnit.SECONDS)
+ .initialCapacity(10)
+ .recordStats()
+ .build();
+ }
+
+
+ public static Object get(String key){
+
+ return StringUtil.isNotBlank(key)?cache.getIfPresent(key):null;
+ }
+
+
+ public static void put(String key,Object value){
+ if(StringUtil.isNotBlank(key) && value != null){
+ cache.put(key,value);
+
+ }
+ }
+
+ public static void remove(String key){
+
+ if(StringUtil.isNotBlank(key)){
+ cache.invalidate(key);
+ }
+ }
+
+ public static void remove(List<String> keys){
+ if(StringUtil.isNotEmpty(keys)){
+ cache.invalidateAll(keys);
+ }
+
+ }
+
+ public static CacheStats getStats() {
+ return cache.stats();
+ }
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/RandomUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/RandomUtil.java
new file mode 100644
index 0000000..426a460
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/RandomUtil.java
@@ -0,0 +1,58 @@
+package com.mesalab.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Base64;
+import java.util.UUID;
+
+/**
+ * 随机数工具类
+ *
+ * @author dazzlzy
+ * @date 2018/5/19
+ */
+@Slf4j
+public class RandomUtil {
+
+ /**
+ * 获取默认位数(8位)的盐
+ *
+ * @return 8位的随机盐
+ */
+ public static String getSalt() {
+ return getSalt(12);
+ }
+
+ /**
+ * 获取随机盐
+ * 使用SecureRandom安全的伪随机数
+ *
+ * @param size 盐的位数
+ * @return 随机盐
+ */
+ public static String getSalt(int size) {
+ return RandomStringUtils.randomAlphanumeric(size);
+ }
+
+ /**
+ * 获取UUID
+ *
+ * @return UUID
+ */
+ public static String getUUID() {
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * 获取不带 `-` 的UUID
+ *
+ * @return UUID
+ */
+ public static String getShortUUID() {
+ return getUUID().replaceAll("-", "");
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java
new file mode 100644
index 0000000..c31c1ec
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/ReportCacheUtils.java
@@ -0,0 +1,83 @@
+package com.mesalab.common.utils;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.QueryFormatEnum;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.qgw.model.api.HBaseAPISource;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.*;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @author wangwei
+ * @version 1.0
+ * @date 2020/6/5 2:04 下午
+ */
+@Slf4j
+public class ReportCacheUtils {
+
+ private static HBaseAPISource hBaseAPISource = (HBaseAPISource) SpringContextUtil.getBean("hBaseAPISource");
+ private static Connection hbaseConnection = (Connection) SpringContextUtil.getBean("hbaseConnection");
+
+ public static BaseResult<Object> get(String id, String query) {
+ Result result = query(id, query);
+ byte[] value = result.getValue(Bytes.toBytes(hBaseAPISource.getColumnFamily()), Bytes.toBytes(hBaseAPISource.getColumnName()));
+ Map map = (Map) JsonMapper.fromJsonString(Bytes.toString(value), Map.class);
+ BaseResult baseResult;
+ if (StringUtil.isEmpty(map)) {
+ baseResult = BaseResultGenerator.failure("Results not exist");
+ } else {
+ baseResult = BaseResultGenerator.generate(Integer.parseInt(String.valueOf(map.get("status"))), ResultCodeEnum.EXECUTE_SUCCESS.getCode(), String.valueOf(map.get("message")),
+ map.get("data"), map.get("meta"), (Map<String, Object>) (map.get("statistics")), QueryFormatEnum.JSON.getValue());
+ }
+ return baseResult;
+ }
+
+ private static Result query(String id, String query) {
+ Table table = null;
+ Result result;
+ try {
+ table = hbaseConnection.getTable(TableName.valueOf((hBaseAPISource.getDbName() + ":" + hBaseAPISource.getTableName())));
+ Get get = new Get(Bytes.toBytes(getQueryId(id, query)));
+ get.addColumn(Bytes.toBytes(hBaseAPISource.getColumnFamily()), Bytes.toBytes(hBaseAPISource.getColumnName()));
+ result = table.get(get);
+ } catch (Exception e) {
+ log.error("get hbase error: {}", e);
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), "Get Hbase Error: ", e);
+ } finally {
+ closeTable(table);
+ }
+ return result;
+ }
+
+ /**
+ * 通过SQL生成查询唯一kEY
+ *
+ * @param sql
+ * @param resultId
+ * @return
+ */
+ public static String getQueryId(String resultId, String sql) {
+ return DigestUtils.md5Hex(resultId + sql.trim());
+ }
+
+
+ private static void closeTable(Table table) {
+ try {
+ if (table != null) {
+ table.close();
+ }
+ } catch (IOException e) {
+ log.error("hbase table close error: ", e);
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java
new file mode 100644
index 0000000..6feb2a3
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLFunctionUtil.java
@@ -0,0 +1,1409 @@
+package com.mesalab.common.utils;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Maps;
+import com.mesalab.common.enums.DBTypeEnum;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.qgw.model.api.ClickHouseHttpSource;
+import com.mesalab.qgw.model.api.DruidIoHttpSource;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.zdjizhi.utils.Encodes;
+import lombok.Data;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author wangwei
+ * @data 2019/8/1 10:13
+ */
+public class SQLFunctionUtil {
+ public static final String TIME_FLOOR_WITH_FILL = "TIME_FLOOR_WITH_FILL";
+ public static final String IP_TO_GEO = "IP_TO_GEO";
+ public static final String IP_TO_CITY = "IP_TO_CITY";
+ public static final String IP_TO_COUNTRY = "IP_TO_COUNTRY";
+
+ private static DruidIoHttpSource druidIoHttpSource = (DruidIoHttpSource) SpringContextUtil.getBean("druidIoHttpSource");
+ private static ClickHouseHttpSource clickHouseHttpSource = (ClickHouseHttpSource) SpringContextUtil.getBean("clickHouseHttpSource");
+ private static HttpClientService httpClientService = (HttpClientService) SpringContextUtil.getBean("httpClientService");
+ private static HttpConfig httpConfig = (HttpConfig) SpringContextUtil.getBean("httpConfig");
+
+ /**
+ * 自定义函数
+ */
+ public static Pattern pTimeFloorWithFill = Pattern.compile("\\b" + TIME_FLOOR_WITH_FILL + "\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pIpToGeo = Pattern.compile("\\b" + IP_TO_GEO + "\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pIpToCity = Pattern.compile("\\b" + IP_TO_CITY + "\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pIpToCountry = Pattern.compile("\\b" + IP_TO_COUNTRY + "\\(", Pattern.CASE_INSENSITIVE);
+
+ public static Pattern periodOfPT = Pattern.compile("PT(\\d+)(\\w+)", Pattern.CASE_INSENSITIVE);
+ public static Pattern periodOfP = Pattern.compile("P(\\d+)(\\w+)", Pattern.CASE_INSENSITIVE);
+ public static final HashMap<String, String> functions = Maps.newHashMap();
+
+ static {
+ functions.put(TIME_FLOOR_WITH_FILL, null);
+ functions.put(IP_TO_GEO, null);
+ functions.put(IP_TO_CITY, null);
+ functions.put(IP_TO_COUNTRY, null);
+ }
+
+ /**
+ * 标准函数
+ */
+ public static Pattern pDateFormat = Pattern.compile("\\W(FROM_UNIXTIME|DATE_FORMAT|STR_TO_DATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pGroupByFormat = Pattern.compile("(SELECT\\s+|GROUP\\s*BY\\s+|,\\s*)(FROM_UNIXTIME|DATE_FORMAT|STR_TO_DATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pDateRelative = Pattern.compile("\\W(ADDDATE|DATE_ADD|DATE_SUB|SUBDATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pIntervalNumUnit = Pattern.compile("INTERVAL(.*?)(YEAR|QUARTER|MONTH|WEEK|DAY|HOUR|MINUTE|SECOND)$", Pattern.CASE_INSENSITIVE);
+ public static Pattern pUnixTime = Pattern.compile("\\WUNIX_TIMESTAMP\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pDate = Pattern.compile("\\W(DATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pDateCalculateNum = Pattern.compile("\\(\\s*(DATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pUnitFuncGetNum = Pattern.compile("\\W(YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|SECOND|DAYOFYEAR|DAYOFMONTH|DAYOFWEEK)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pMarkDate = Pattern.compile("\\W(MAKEDATE)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pLastDateFunc = Pattern.compile("\\W(LAST_DAY)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ public static Pattern pCKTimeStamp = Pattern.compile("\\s+TIMESTAMP\\s+([^'])", Pattern.CASE_INSENSITIVE);
+ public static Pattern pNow = Pattern.compile("NOW\\(\\s*\\)", Pattern.CASE_INSENSITIVE);
+ public static Pattern pStrDateTime = Pattern.compile("(<|>|=|between|and)\\s*('\\d{4}-\\d{2}-\\d{2}\\s*\\d{2}:\\d{2}:\\d{2}')", Pattern.CASE_INSENSITIVE);
+ public static Pattern pMergeFunction = Pattern.compile("\\WDATE_FORMAT\\(FROM_UNIXTIME\\s*\\(\\s*FLOOR\\s*\\(\\s*UNIX_TIMESTAMP\\s*\\(", Pattern.CASE_INSENSITIVE);
+
+
+ /**
+ * 解析mysql函数替换为对应数据库类型函数
+ *
+ * @param sql 要解析的sql
+ * @param dbType 数据库类型
+ * @return
+ */
+ public static String generateDateFunction(String sql, String dbType) {
+ sql = translateUDF(sql, dbType);
+ sql = parseMergepFunction(sql, dbType);
+ sql = parseMarkDate(sql, dbType);
+ sql = parseDateCalculateNum(sql, dbType);
+ sql = parseLastDayFunc(sql, dbType);
+ sql = parseGroupByFormat(sql, dbType);
+ sql = parseDateFormat(sql, dbType);
+ sql = parseDateRelative(sql, dbType);
+ sql = parseUnixTime(sql, dbType);
+ sql = parseDate(sql, dbType);
+ sql = parseUnitFuncGetNum(sql, dbType);
+ sql = specialDisposeEnd(sql, dbType);
+ sql = replaceMark(sql);
+ return sql;
+ }
+
+ /**
+ * 转义自定义函数
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String translateUDF(String sql, String dbType) {
+ String resultSql = sql;
+ resultSql = translateByPattern(resultSql, dbType, pTimeFloorWithFill);
+ resultSql = translateByPattern(resultSql, dbType, pIpToGeo);
+ resultSql = translateByPattern(resultSql, dbType, pIpToCity);
+ resultSql = translateByPattern(resultSql, dbType, pIpToCountry);
+ return resultSql;
+ }
+
+ /**
+ * 查询数据源获取函数实际值
+ *
+ * @param query
+ * @param dbType
+ * @return
+ */
+ public static String getQueryValue(String query, String dbType) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ query = generateDateFunction("select " + query + " as actualValue", dbType);
+ query = Encodes.urlEncode(query);
+ Map<String, String> results = executeHttpGetOfCK(query);
+ Map<String, Object> maps = (Map<String, Object>) JsonMapper.fromJsonString(results.get("result"), Map.class);
+ List<Map<String, Object>> dates = (List<Map<String, Object>>) maps.get("data");
+ Map<String, Object> data = dates.get(0);
+ Object actualValue = data.get("actualValue");
+ return actualValue.toString();
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ query = generateDateFunction("select TIME_FORMAT(" + query + ", 'yyyy-MM-dd HH:mm:ss') as actualValue", dbType);
+ Map<String, String> results = executeHttpPostOfDruid(query);
+ List<Object> maps = (List<Object>) JsonMapper.fromJsonString(results.get("result"), Object.class);
+ Map<String, Object> data = (Map<String, Object>) maps.get(0);
+ Object actualValue = data.get("actualValue");
+ return actualValue.toString();
+ } else {
+ return query;
+ }
+ }
+
+ /**
+ * post查询druid
+ *
+ * @param query
+ * @return
+ */
+ public static Map<String, String> executeHttpPostOfDruid(String query) {
+ StringBuilder urlBuilder = new StringBuilder("http://").append(druidIoHttpSource.getUrl());
+ DruidQueryParam druidQueryParam = new DruidQueryParam();
+ druidQueryParam.setQuery(query);
+ druidQueryParam.getContext().put("skipEmptyBuckets", druidIoHttpSource.getSkipEmptyBuckets());
+ druidQueryParam.setResultFormat("object");
+ int socketTimeOut = httpConfig.getDruidSocketTimeOut();
+ Map<String, String> stringStringMap = httpClientService.httpPost(urlBuilder.toString(), JsonMapper.toJsonString(druidQueryParam), socketTimeOut);
+ return stringStringMap;
+
+ }
+
+ /**
+ * get查询clickHouse
+ *
+ * @param sql
+ * @return
+ */
+ private static Map<String, String> executeHttpGetOfCK(String sql) {
+ StringBuilder urlBuilder = new StringBuilder("http://")
+ .append(clickHouseHttpSource.getUrl()).append("/?");
+ StringBuilder queryparamBuilder = new StringBuilder("user=")
+ .append(clickHouseHttpSource.getRealTimeAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getRealTimeAccount().getPassword()).append("&")
+ .append("database=").append(clickHouseHttpSource.getDbName()).append("&")
+ .append("query=").append(sql)
+ .append(" FORMAT JSON;");
+ List<NameValuePair> values = URLEncodedUtils.parse(queryparamBuilder.toString(), Charset.forName("UTF-8"));
+ int socketTimeOut = httpConfig.getCkRealTimeAccountSocketTimeOut();
+ Map<String, String> stringStringMap = httpClientService.httpGet(urlBuilder.toString() + URLEncodedUtils.format(values, "utf-8"), socketTimeOut);
+ return stringStringMap;
+ }
+
+
+ /**
+ * 匹配连接函数: DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ private static String parseMergepFunction(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pMergeFunction.matcher(sql);
+ if (!matcher.find() || count++ >= 40) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = MergeFromUnixToTimeHavaMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+
+ /**
+ * 匹配范围:FROM_UNIXTIME(、DATE_FORMAT(、STR_TO_DATE(
+ *
+ * @param sql 需要解析的sql
+ * @param dbType
+ * @return
+ */
+ public static String parseDateFormat(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pDateFormat.matcher(sql);
+ if (!matcher.find() || count++ >= 40) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = dateFormatHavaMark(sqlParse, bracketsMatch[0], false, dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配格式化 FROM_UNIXTIME(、DATE_FORMAT(、STR_TO_DATE(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseGroupByFormat(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pGroupByFormat.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start();
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = dateFormatHavaMark(sqlParse, bracketsMatch[0], true, dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 SUBDATE(、SUBDATE(、SUBDATE(、ADDDATE(、DATE_SUB(、DATE_ADD(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseDateRelative(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pDateRelative.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, null, false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = dateRelativeHaveMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 UNIX_TIMESTAMP(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseUnixTime(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pUnixTime.matcher(sql);
+ if (!matcher.find() || count++ == 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, null, false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = parseUnixTimeHavaMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 DATE(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseDate(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pDate.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = parseDateHavaMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 YEAR(、QUARTER(、MONTH(、DAY(、HOUR(、MINUTE(、SECOND、DAYOFYEAR(、DAYOFMONTH(、DAYOFWEEK(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseUnitFuncGetNum(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pUnitFuncGetNum.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = parseUnitFuncGetNumHaveMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 pMarkDate(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseMarkDate(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pMarkDate.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = parseMarkDateHaveMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 LAST_DAY(
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseLastDayFunc(String sql, String dbType) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pLastDateFunc.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ return sql;
+ }
+ int start = matcher.start() + 1;
+ String sqlParse = sql.substring(start);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String str = parseLastDayFuncHaveMark(sqlParse, bracketsMatch[0], dbType);
+ sql = sql.substring(0, start) + str;
+ }
+ }
+
+ /**
+ * 匹配 涉及DATE()-、DATE()+
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String parseDateCalculateNum(String sql, String dbType) {
+ int count = 0;
+ String sqlTmp = "";
+ while (true) {
+ Matcher matcher = pDateCalculateNum.matcher(sql);
+ if (!matcher.find() || count++ >= 30) {
+ sql = sql.replace("##", "(");
+ return sql;
+ }
+ String sqlParse = sql.substring(matcher.start());
+ if (sqlTmp.equals(sqlParse)) {
+ sqlParse = "##" + sqlParse.substring(1);
+ sql = sql.substring(0, matcher.start()) + sqlParse;
+ continue;
+ }
+ sqlTmp = sqlParse;
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ String sqlParse2 = sql.substring(matcher.start() + 1);
+ int[] bracketsMatch2 = StringUtil.getBracketsMatch(sqlParse2, "(", false);
+ if (bracketsMatch2[0] >= 1) {
+ --bracketsMatch2[0];
+ }
+ String str = parseDateCalculateNumHaveMark(sqlParse, bracketsMatch[0], bracketsMatch2[0], dbType);
+ sql = sql.substring(0, matcher.start()) + str;
+ }
+ }
+
+
+ /**
+ * 替换连接函数: DATE_FOERMAT(FROM_UNIXTIME(UNIX_TIMESTAMP(...)
+ *
+ * @param sql
+ * @param num
+ * @param dbType
+ * @return
+ */
+ private static String MergeFromUnixToTimeHavaMark(String sql, int num, String dbType) {
+ Pattern p = Pattern.compile("DATE_FORMAT\\s*\\(\\s*FROM_UNIXTIME\\s*\\(\\s*FLOOR\\s*\\(\\s*UNIX_TIMESTAMP\\s*(\\((.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ StringBuffer sb = new StringBuffer();
+ Matcher m = p.matcher(sql);
+ if (m.find()) {
+ String group = m.group(1);
+ int[] bracketsMatch = StringUtil.getBracketsMatch(group, "(", false);
+ String param = group.substring(1, bracketsMatch[1]);
+ String var = group.substring(bracketsMatch[1] + 1);
+ var = var.replaceAll(" ", "");
+ String replaceValue = m.group(0);
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ switch (var) {
+ case "/60)*60),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "toStartOfMinute#[toDateTime#[" + param + "]]";
+ break;
+ case "/3600)*3600),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "toStartOfHour#[toDateTime#[" + param + "]]";
+ break;
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ if (param.matches("'\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}'")) {
+ param = "TIMESTAMP " + param;
+ }
+ switch (var) {
+ case "/30)*30),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_FLOOR#[" + param + ",'PT30S'],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/30)*30-30),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT30S'],'PT30S',-1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/30)*30+30),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT30S'],'PT30S',1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/60)*60),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_FLOOR#[" + param + ",'PT1M'],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/60)*60-60),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT1M'],'PT1M',-1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/60)*60+60),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT1M'],'PT1M',1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/300)*300),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_FLOOR#[" + param + ",'PT5M'],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/300)*300-300),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT5M'],'PT5M',-1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/300)*300+300),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT5M'],'PT5M',1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/3600)*3600),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_FLOOR#[" + param + ",'PT1H'],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/3600)*3600-3600),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT1H'],'PT1H',-1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ case "/3600)*3600+3600),'%Y-%m-%d%H:%i:%s'":
+ replaceValue = "TIME_FORMAT#[TIME_SHIFT#[TIME_FLOOR#[" + param + ",'PT1H'],'PT1H',1],'yyyy-MM-dd HH:mm:ss']";
+ break;
+ }
+ }
+ m.appendReplacement(sb, replaceValue);
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+
+ /**
+ * 替换 涉及DATE()-、DATE()+
+ *
+ * @param sqlParse
+ * @param num 括号总个数
+ * @param num2 date函数内括号数
+ * @param dbType
+ * @return
+ */
+ private static String parseDateCalculateNumHaveMark(String sqlParse, int num, int num2, String dbType) {
+ Pattern pDateCalculateNumParse = Pattern.compile("(DATE)\\s*\\((.*?(.*?\\).*?){" + num2 + "})\\)(.*?(.*?\\).*?){" + (num - num2 - 1) + "})\\)", Pattern.CASE_INSENSITIVE);
+ StringBuffer sb = new StringBuffer();
+ Matcher mDateCalculateNumParse = pDateCalculateNumParse.matcher(sqlParse);
+ if (mDateCalculateNumParse.find() && (mDateCalculateNumParse.group(4).trim().startsWith("+") || mDateCalculateNumParse.group(4).trim().startsWith("-"))) {
+ String group0 = mDateCalculateNumParse.group(0);
+ String group2 = mDateCalculateNumParse.group(2);
+ String group4 = mDateCalculateNumParse.group(4);
+ if (StringUtil.getBracketsMatch(group0.substring(0, group0.length() - 1), "(", true)[0] == num) {
+ String[] split = group4.split(",");
+ String replaceValue = "";
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ if (split.length == 1) {
+ replaceValue = "toStartOfDay#[toDateTime#[" + group2 + "]]+[" + group4 + "]*86400 )";
+ } else if (split.length == 2) {
+ replaceValue = "toStartOfDay#[toDateTime#[" + group2 + "]]+[" + split[0] + "]*86400 ," + split[1] + ")";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ if (split.length == 1) {
+ replaceValue = "TIME_SHIFT#[FLOOR#[ TIMESTAMP " + group2 + " to day],'P1D'," + group4 + "])";
+ } else if (split.length == 2) {
+ replaceValue = "TIME_SHIFT#[FLOOR#[ TIMESTAMP " + group2 + "to day],'P1D'," + split[0] + "]," + split[1] + ")";
+ }
+ }
+ mDateCalculateNumParse.appendReplacement(sb, replaceValue);
+ }
+ }
+ mDateCalculateNumParse.appendTail(sb);
+ return sb.toString();
+ }
+
+
+ /**
+ * 替换 LAST_DAY(date)
+ *
+ * @param sqlParse
+ * @param num 包含括号个数
+ * @param dbType
+ * @return
+ */
+ public static String parseLastDayFuncHaveMark(String sqlParse, int num, String dbType) {
+ Pattern pLastDayParse = Pattern.compile("(LAST_DAY)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ StringBuffer sb = new StringBuffer();
+ Matcher mLastDayParse = pLastDayParse.matcher(sqlParse);
+ if (mLastDayParse.find()) {
+ String replaceValue = lastDayRealize(mLastDayParse.group(1), mLastDayParse.group(2), dbType);
+ mLastDayParse.appendReplacement(sb, replaceValue);
+ }
+ mLastDayParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 实现替换:LAST_DAY(date)
+ *
+ * @param unit
+ * @param param
+ * @param dbType
+ * @return
+ */
+ private static String lastDayRealize(String unit, String param, String dbType) {
+ String replaceValue = null;
+ if ("LAST_DAY".equals(unit.toUpperCase())) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ replaceValue = "addDays#[addMonths#[toStartOfMonth#[toDateTime#[" + param + "]],1],-1]";
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ replaceValue = "TIME_SHIFT#[FLOOR#[TIME_SHIFT#[ TIMESTAMP " + param + ", 'P1M', 1] to month], 'P1D', -1]";
+ }
+ }
+ return replaceValue;
+ }
+
+ /**
+ * 替换:MAKEDATE(year,dayofyear)
+ *
+ * @param sqlParse
+ * @param num 函数参数包含括号的个数
+ * @param dbType
+ * @return
+ */
+ public static String parseMarkDateHaveMark(String sqlParse, int num, String dbType) {
+ Pattern pMarkDateParse = Pattern.compile("(MAKEDATE)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ StringBuffer sb = new StringBuffer();
+ Matcher mMarkDateParse = pMarkDateParse.matcher(sqlParse);
+ if (mMarkDateParse.find()) {
+ String replaceValue = markDateRealize(mMarkDateParse.group(1), mMarkDateParse.group(2), dbType);
+ mMarkDateParse.appendReplacement(sb, replaceValue);
+ }
+ mMarkDateParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 实现替换:MAKEDATE(year,dayofyear)
+ *
+ * @param func
+ * @param expr
+ * @param dbType
+ * @return
+ */
+ private static String markDateRealize(String func, String expr, String dbType) {
+ String replaceValue = null;
+ List<String> params = diviParam(expr, ",");
+ if ("MAKEDATE".equals(func.toUpperCase()) && params.size() == 2) {
+ Pattern pYearFunNum = Pattern.compile("(YEAR)\\s*\\(", Pattern.CASE_INSENSITIVE);
+ Matcher matcher = pYearFunNum.matcher(expr);
+ if (matcher.find() && "YEAR".equals(matcher.group(1).toUpperCase())) {
+ String temp = expr.substring(matcher.start());
+ int[] bracketsMatch = StringUtil.getBracketsMatch(temp, "(", false);
+ if (bracketsMatch[0] >= 1) {
+ --bracketsMatch[0];
+ }
+ Pattern pYear = Pattern.compile("^(.*?)(YEAR)\\s*\\((.*?(.*?\\).*?){" + bracketsMatch[0] + "})\\)(.*?)$", Pattern.CASE_INSENSITIVE);
+ Matcher mYear = pYear.matcher(params.get(0));
+ if (mYear.find()) {
+ String group1 = mYear.group(1);
+ String group5 = mYear.group(5);
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ if (group1 != null && !"".equals(group1.trim()) && group5 != null && !"".equals(group5.trim())) {
+ replaceValue = "toDateTime#[addDays#[addYears#[toStartOfYear#[toDateTime#[" + mYear.group(3) + "]]," + group1 + " " + group5 + "]," + params.get(1) + " -1 ]]";
+ } else if (group5 != null && !"".equals(group5.trim())) {
+ replaceValue = "toDateTime#[addDays#[addYears#[toStartOfYear#[toDateTime#[" + mYear.group(3) + "]]," + group5 + "]," + params.get(1) + " -1 ]]";
+ } else if (group1 != null && !"".equals(group1.trim())) {
+ replaceValue = "toDateTime#[addDays#[addYears#[toStartOfYear#[toDateTime#[" + mYear.group(3) + "]]," + group1 + "0 ]," + params.get(1) + " -1 ]]";
+ } else {
+ replaceValue = "toDateTime#[addDays#[toStartOfYear#[toDateTime#[" + mYear.group(3) + "]]," + params.get(1) + " -1 ]]";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ if (group1 != null && !"".equals(group1.trim()) && group5 != null && !"".equals(group5.trim())) {
+ replaceValue = "TIME_SHIFT#[TIME_SHIFT#[FLOOR#[ TIMESTAMP " + mYear.group(3) + " to year],'P1Y'," + group1 + " " + group5 + " ],'P1D'," + params.get(1) + " -1 ]";
+ } else if (group5 != null && !"".equals(group5.trim())) {
+ replaceValue = "TIME_SHIFT#[TIME_SHIFT#[FLOOR#[ TIMESTAMP " + mYear.group(3) + " to year],'P1Y'," + group5 + "],'P1D'," + params.get(1) + " -1 ]";
+ } else if (group1 != null && !"".equals(group1.trim())) {
+ replaceValue = "TIME_SHIFT#[TIME_SHIFT#[FLOOR#[ TIMESTAMP " + mYear.group(3) + " to year],'P1Y'," + group1 + "0 ],'P1D'," + params.get(1) + " -1 ]";
+ } else {
+ replaceValue = "TIME_SHIFT#[FLOOR#[ TIMESTAMP " + mYear.group(3) + " to year],'P1D'," + params.get(1) + "-1 ]";
+ }
+ }
+ }
+ }
+ }
+ return replaceValue;
+ }
+
+ /**
+ * 替换 YEAR(expr)、QUARTER(expr)、MONTH(expr)、DAY(expr)、HOUR(expr)、MINUTE(expr)、SECONDexpr)、DAYOFYEAR(expr)、DAYOFMONTH(expr)、DAYOFWEEK(expr)
+ *
+ * @param sqlParse
+ * @param num
+ * @param dbType
+ * @return
+ */
+ private static String parseUnitFuncGetNumHaveMark(String sqlParse, int num, String dbType) {
+ Pattern pUnitFuncParse = Pattern.compile("(YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|SECOND|DAYOFYEAR|DAYOFMONTH|DAYOFWEEK)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ StringBuffer sb = new StringBuffer();
+ Matcher mUnitFuncParse = pUnitFuncParse.matcher(sqlParse);
+ if (mUnitFuncParse.find()) {
+ String replaceValue = unitFuncGetNumRealize(mUnitFuncParse.group(1), mUnitFuncParse.group(2), dbType);
+ mUnitFuncParse.appendReplacement(sb, replaceValue);
+ }
+ mUnitFuncParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 实现替换:YEAR(expr)、QUARTER(expr)、MONTH(expr)、DAY(expr)、HOUR(expr)、MINUTE(expr)、SECONDexpr)、DAYOFYEAR(expr)、DAYOFMONTH(expr)、DAYOFWEEK(expr)
+ *
+ * @param unit
+ * @param expr
+ * @param dbType
+ * @return
+ */
+ private static String unitFuncGetNumRealize(String unit, String expr, String dbType) {
+ String replaceValue = null;
+ unit = unit.toUpperCase();
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ switch (unit) {
+ case "YEAR":
+ replaceValue = "toYear#[toDateTime#[" + expr + "]]";
+ break;
+ case "QUARTER":
+ replaceValue = "toQuarter#[toDateTime#[" + expr + "]]";
+ break;
+ case "MONTH":
+ replaceValue = "toMonth#[toDateTime#[" + expr + "]]";
+ break;
+ case "DAY":
+ replaceValue = "toDayOfMonth#[toDateTime#[" + expr + "]]";
+ break;
+ case "HOUR":
+ replaceValue = "toHour#[toDateTime#[" + expr + "]]";
+ break;
+ case "MINUTE":
+ replaceValue = "toMinute#[toDateTime#[" + expr + "]]";
+ break;
+ case "SECOND":
+ replaceValue = "toSecond#[toDateTime#[" + expr + "]]";
+ break;
+ case "DAYOFYEAR":
+ replaceValue = "toDayOfYear#[toDateTime#[" + expr + "]]";
+ break;
+ case "DAYOFMONTH":
+ replaceValue = "toDayOfMonth#[toDateTime#[" + expr + "]]";
+ break;
+ case "DAYOFWEEK":
+ replaceValue = "toDayOfWeek#[addDays#[toDateTime#[" + expr + "],1]]";
+ break;
+ default:
+ replaceValue = unit + "#[" + expr + "]";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ switch (unit) {
+ case "YEAR":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'YEAR' ]";
+ break;
+ case "QUARTER":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'QUARTER' ]";
+ break;
+ case "MONTH":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'MONTH' ]";
+ break;
+ case "DAY":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'DAY' ]";
+ break;
+ case "HOUR":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'HOUR' ]";
+ break;
+ case "MINUTE":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'MINUTE' ]";
+ break;
+ case "SECOND":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'SECOND' ]";
+ break;
+ case "DAYOFYEAR":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'DOY' ]";
+ break;
+ case "DAYOFMONTH":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'PT1M',0], 'DAY' ]";
+ break;
+ case "DAYOFWEEK":
+ replaceValue = "TIME_EXTRACT#[TIME_SHIFT#[ TIMESTAMP " + expr + ",'P1D',1], 'DOW' ]";
+ break;
+ default:
+ replaceValue = unit + "#[" + expr + "]";
+ }
+ }
+ return replaceValue;
+ }
+
+ /**
+ * 实现相对时间相关替换:
+ *
+ * @param params
+ * @param sign ADD相关为true,SUB相关为false;
+ * @param dbType
+ * @return
+ */
+ private static String dateRelative(List<String> params, Boolean sign, String dbType) {
+ String replaceValue = "";
+ if (params.size() == 2 && params.get(1).toUpperCase().contains("INTERVAL")) {
+ String param1 = params.get(0);
+ String param2 = params.get(1);
+ Matcher matcher = pIntervalNumUnit.matcher(param2);
+ if (matcher.find()) {
+ param2 = matcher.group(1);
+ if (!sign) {
+ param2 = "- #[" + param2 + "]";
+ }
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ switch (matcher.group(2).toUpperCase()) {
+ case "SECOND":
+ replaceValue = "toDateTime#[" + param1 + "]" + param2;
+ break;
+ case "MINUTE":
+ replaceValue = "toDateTime#[" + param1 + "]" + param2 + "*60";
+ break;
+ case "HOUR":
+ replaceValue = "toDateTime#[" + param1 + "]" + param2 + "*3600";
+ break;
+ case "DAY":
+ replaceValue = "toDateTime#[" + param1 + "]" + param2 + "*86400";
+ break;
+ case "WEEK":
+ replaceValue = "toDateTime#[" + param1 + "]" + param2 + "*604800";
+ break;
+ case "MONTH":
+ replaceValue = "addMonths#[toDateTime#[" + param1 + "] ," + param2 + "]";
+ break;
+ case "QUARTER":
+ replaceValue = "addQuarter#[toDateTime#[" + param1 + "]," + param2 + "]";
+ break;
+ case "YEAR":
+ replaceValue = "addYears#[toDateTime#[" + param1 + "]," + param2 + "]";
+ break;
+ default:
+ replaceValue = param1 + param2;
+ break;
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ switch (matcher.group(2).toUpperCase()) {
+ case "SECOND":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'PT1S'," + param2 + "]";
+ break;
+ case "MINUTE":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'PT1M'," + param2 + "]";
+ break;
+ case "HOUR":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'PT1H'," + param2 + "]";
+ break;
+ case "DAY":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1D'," + param2 + "]";
+ break;
+ case "WEEK":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1W'," + param2 + "]";
+ break;
+ case "MONTH":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1M'," + param2 + "]";
+ break;
+ case "QUARTER":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1M'," + param2 + "]";
+ break;
+ case "YEAR":
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1Y'," + param2 + "]";
+ break;
+ default:
+ replaceValue = param1 + param2;
+ break;
+ }
+ }
+ return replaceValue;
+ }
+ } else if (params.size() == 2) {
+ String param1 = params.get(0);
+ String param2 = params.get(1);
+ if (!sign) {
+ param2 = "- #[" + param2 + "]";
+ }
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ replaceValue = "addDays#[toDateTime#[" + param1 + "]," + param2 + "]";
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ replaceValue = "TIME_SHIFT#[ TIMESTAMP " + param1 + ",'P1D'," + param2 + "]";
+ }
+ }
+ return replaceValue;
+ }
+
+ /**
+ * 实现替换:FROM_UNIXTIME(unix_timestamp)、FROM_UNIXTIME(date,format)、DATE_FORMAT(date,format)、STR_TO_DATE(date,format)
+ *
+ * @param func
+ * @param param
+ * @param dbType
+ * @return
+ */
+ private static String dateFormatRealize(String func, String param, boolean bool, String dbType) {
+ List<String> params = diviParam(param, ",");
+ String param1 = params.get(0);
+ String replaceValue = null;
+ if ("FROM_UNIXTIME".equals(func.toUpperCase()) && params.size() == 1) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ replaceValue = "toDateTime#[" + param + "]";
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType) && !bool) {
+ replaceValue = "MILLIS_TO_TIMESTAMP#[ 1000 * [" + param + "]]";
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType) && bool) {
+ replaceValue = "TIME_FORMAT#[MILLIS_TO_TIMESTAMP#[ 1000 * [" + param + "]],'YYYY-MM-dd HH:mm:ss']";
+ }
+ } else if (func.contains("FROM_UNIXTIME") && DBTypeEnum.DRUID.getValue().equals(dbType) && "%Y-%m-%d %H:%i:%s".equals(params.get(1).replaceAll("\\'|\\\"", "").trim())) {
+ if (!bool) {
+ replaceValue = "MILLIS_TO_TIMESTAMP#[ 1000*[" + param1 + "]]";
+ } else if (bool) {
+ replaceValue = "TIME_FORMAT#[MILLIS_TO_TIMESTAMP#[ 1000 * [" + param + "]],'YYYY-MM-dd HH:mm:ss']";
+ }
+ } else {
+ String param2 = params.get(1).replaceAll("\\'|\\\"", "").trim();
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType) && bool) {
+ switch (param2) {
+ case "%Y-%m-%d %H:%i:%s":
+ replaceValue = "toDateTime#[" + param1 + "]";
+ break;
+ case "%Y-%m-%d %H:%i:00":
+ replaceValue = "toStartOfMinute#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-%d %H:00:00":
+ replaceValue = "toStartOfHour#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-%d 00:00:00":
+ replaceValue = "toStartOfDay#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-01 00:00:00":
+ replaceValue = "toDateTime#[toStartOfMonth#[toDateTime#[" + param1 + "]]]";
+ break;
+ case "%Y-01-01 00:00:00":
+ replaceValue = "toDateTime#[toStartOfYear#[toDateTime#[" + param1 + "]]]";
+ break;
+ case "%Y-%m-%d":
+ replaceValue = "formatDateTime#[toDateTime#[" + param1 + "], '%Y-%m-%d]";
+ break;
+ case "%Y-%m-01":
+ replaceValue = "formatDateTime#[toDateTime#[" + param1 + "], '%Y-%m-01]";
+ break;
+ case "%Y-01-01":
+ replaceValue = "formatDateTime#[toDateTime#[" + param1 + "], '%Y-01-01]";
+ break;
+ default:
+ replaceValue = "toDateTime#[" + param1 + "]";
+ }
+ } else if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType) && !bool) {
+ switch (param2) {
+ case "%Y-%m-%d %H:%i:%s":
+ replaceValue = "toDateTime#[" + param1 + "]";
+ break;
+ case "%Y-%m-%d %H:%i:00":
+ replaceValue = "toStartOfMinute#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-%d %H:00:00":
+ replaceValue = "toStartOfHour#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-%d 00:00:00":
+ replaceValue = "toStartOfDay#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-01 00:00:00":
+ replaceValue = "toDateTime#[toStartOfMonth#[toDateTime#[" + param1 + "]]]";
+ break;
+ case "%Y-01-01 00:00:00":
+ replaceValue = "toDateTime#[toStartOfYear#[toDateTime#[" + param1 + "]]]";
+ break;
+ case "%Y-%m-%d":
+ replaceValue = "toStartOfDay#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-%m-01":
+ replaceValue = "toStartOfMonth#[toDateTime#[" + param1 + "]]";
+ break;
+ case "%Y-01-01":
+ replaceValue = "toStartOfYear#[toDateTime#[" + param1 + "]]";
+ break;
+ default:
+ replaceValue = "toDateTime#[" + param1 + "]";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType) && bool) {
+ switch (param2) {
+ case "%Y-%m-%d %H:%i:%s":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd HH:mm:ss']";
+ break;
+ case "%Y-%m-%d %H:%i:00":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd HH:mm:00']";
+ break;
+ case "%Y-%m-%d %H:00:00":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd HH:00:00']";
+ break;
+ case "%Y-%m-%d 00:00:00":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd 00:00:00']";
+ break;
+ case "%Y-%m-01 00:00:00":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-01 00:00:00']";
+ break;
+ case "%Y-01-01 00:00:00":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-01-01 00:00:00']";
+ break;
+ case "%Y-%m-%d":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd']";
+ break;
+ case "%Y-%m-01":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-01']";
+ break;
+ case "%Y-01-01":
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-01-01']";
+ break;
+ default:
+ replaceValue = "TIME_FORMAT#[ TIMESTAMP " + param1 + ",'YYYY-MM-dd HH:mm:ss']";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType) && !bool) {
+ switch (param2) {
+ case "%Y-%m-%d %H:%i:%s":
+ replaceValue = " TIMESTAMP " + param1;
+ break;
+ case "%Y-%m-%d %H:%i:00":
+ replaceValue = "FLOOR#[ TIMESTAMP " + param1 + " to minute]";
+ break;
+ case "%Y-%m-%d %H:00:00":
+ replaceValue = "FLOOR#[ TIMESTAMP " + param1 + " to hour]";
+ break;
+ case "%Y-%m-%d 00:00:00":
+ replaceValue = "FLOOR#[ TIMESTAMP " + param1 + " to day]";
+ break;
+ case "%Y-%m-01 00:00:00":
+ replaceValue = "FLOOR#[ TIMESTAMP " + param1 + " to month]";
+ break;
+ case "%Y-01-01 00:00:00":
+ replaceValue = "FLOOR#[ TIMESTAMP " + param1 + " to year]";
+ break;
+ case "%Y-%m-%d":
+ replaceValue = "TIME_FLOOR#[ TIMESTAMP " + param1 + ",'P1D']";
+ break;
+ case "%Y-%m-01":
+ replaceValue = "TIME_FLOOR#[ TIMESTAMP " + param1 + ",'P1M']";
+ break;
+ case "%Y-01-01":
+ replaceValue = "TIME_FLOOR#[ TIMESTAMP " + param1 + ",'P1Y']";
+ break;
+ default:
+ replaceValue = " TIMESTAMP " + param1;
+ break;
+ }
+ }
+ }
+ return replaceValue;
+ }
+
+ /**
+ * 解析之后的sql处理
+ *
+ * @param sql
+ * @param dbType
+ * @return
+ */
+ public static String specialDisposeEnd(String sql, String dbType) {
+ if (sql == null) {
+ return sql;
+ }
+ StringBuffer sb = new StringBuffer();
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ Matcher mStrDateTime = pStrDateTime.matcher(sql);
+ while (mStrDateTime.find()) {
+ String innerValue = mStrDateTime.group(1) + " toDateTime#[" + mStrDateTime.group(2) + "]";
+ mStrDateTime.appendReplacement(sb, innerValue);
+ }
+ mStrDateTime.appendTail(sb);
+ sql = sb.toString();
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+
+ Matcher mNowFun = pNow.matcher(sql);
+ while (mNowFun.find()) {
+ String innerValue = "CURRENT_TIMESTAMP";
+ mNowFun.appendReplacement(sb, innerValue);
+ }
+ mNowFun.appendTail(sb);
+ sql = sb.toString();
+
+ Matcher mStrDateTime = pStrDateTime.matcher(sql);
+ sb = new StringBuffer();
+ while (mStrDateTime.find()) {
+ String innerValue = mStrDateTime.group(1) + " TIMESTAMP " + mStrDateTime.group(2);
+ mStrDateTime.appendReplacement(sb, innerValue);
+ }
+ mStrDateTime.appendTail(sb);
+ sql = sb.toString();
+
+
+ Matcher matcher = pCKTimeStamp.matcher(sql);
+ sb = new StringBuffer();
+ while (matcher.find()) {
+ if (matcher.groupCount() == 1) {
+ matcher.appendReplacement(sb, " " + matcher.group(1));
+ }
+ }
+ matcher.appendTail(sb);
+ sql = sb.toString();
+ }
+ return sql;
+ }
+
+ /**
+ * 替换解析时候加入的[、]、#
+ *
+ * @param sql
+ * @return
+ */
+ public static String replaceMark(String sql) {
+ sql = sql.replace("[", "(");
+ sql = sql.replace("]", ")");
+ sql = sql.replace("#", "");
+ return sql;
+ }
+
+ /**
+ * 替换:FROM_UNIXTIME(unix_timestamp)、FROM_UNIXTIME(date,format)、DATE_FORMAT(date,format)、STR_TO_DATE(date,format)
+ *
+ * @param sqlParse
+ * @param num 包含括号的个数
+ * @param bool 应用的分组中为true 条件范围中则为false
+ * @param dbType
+ * @return
+ */
+ public static String dateFormatHavaMark(String sqlParse, int num, boolean bool, String dbType) {
+ Pattern pDateFormatMark = Pattern.compile("(FROM_UNIXTIME|DATE_FORMAT|STR_TO_DATE)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ Matcher mDateFormatMark = pDateFormatMark.matcher(sqlParse);
+ StringBuffer sb = new StringBuffer();
+ if (mDateFormatMark.find()) {
+ String group2 = mDateFormatMark.group(2);
+ String replaceValue = group2;
+ if (StringUtil.getBracketsMatch(group2, "(", false)[0] >= 0) {
+ replaceValue = dateFormatRealize(mDateFormatMark.group(1), group2, bool, dbType);
+ }
+ mDateFormatMark.appendReplacement(sb, replaceValue);
+ }
+ mDateFormatMark.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 替换SUBDATE(expr,days)、SUBDATE(expr,days)、SUBDATE(date,INTERVAL expr dbType)、ADDDATE(date,INTERVAL expr dbType)、DATE_SUB(date,INTERVAL expr dbType)、DATE_ADD(date,INTERVAL expr dbType)
+ *
+ * @param sqlParse
+ * @param num 包含的括号个数
+ * @param dbType
+ * @return
+ */
+ public static String dateRelativeHaveMark(String sqlParse, int num, String dbType) {
+ Pattern pDateRelativeParse = Pattern.compile("(ADDDATE|DATE_ADD|SUBDATE|DATE_SUB)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ Matcher matcherParse = pDateRelativeParse.matcher(sqlParse);
+ String innerValue = "";
+ StringBuffer sb = new StringBuffer();
+ if (matcherParse.find()) {
+ Boolean sign = matcherParse.group(1).toUpperCase().contains("ADD");
+ if (StringUtil.getBracketsMatch(matcherParse.group(2), null, false)[0] >= 0) {
+ List<String> params = diviParam(matcherParse.group(2), ",");
+ innerValue = dateRelative(params, sign, dbType);
+ }
+ matcherParse.appendReplacement(sb, innerValue);
+ }
+ matcherParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 实现替换:UNIX_TIMESTAMP()、UNIX_TIMESTAMP(expr)
+ *
+ * @param sqlParse
+ * @param num 包含的括号个数
+ * @param dbType
+ * @return
+ */
+ public static String parseUnixTimeHavaMark(String sqlParse, int num, String dbType) {
+ Pattern pUnixTimeParse = Pattern.compile("(UNIX_TIMESTAMP)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ Matcher matcherParse = pUnixTimeParse.matcher(sqlParse);
+ StringBuffer sb = new StringBuffer();
+ String innerValue = null;
+ if (matcherParse.find()) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ if (matcherParse.group(2) == null || "".equals(matcherParse.group(2).trim())) {
+ innerValue = "toUnixTimestamp#[now#[]]";
+ } else {
+ innerValue = "toUnixTimestamp#[ " + matcherParse.group(2) + "]";
+ }
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ if (matcherParse.group(2) == null || "".equals(matcherParse.group(2).trim())) {
+ innerValue = "0.001 * TIMESTAMP_TO_MILLIS[CURRENT_TIMESTAMP]";
+ } else {
+ innerValue = "0.001 * TIMESTAMP_TO_MILLIS#[ TIMESTAMP " + matcherParse.group(2) + "]";
+ }
+ }
+ matcherParse.appendReplacement(sb, innerValue);
+ }
+ matcherParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 实现替换:DATE(expr)
+ *
+ * @param sqlParse
+ * @param num 包含的括号个数
+ * @param dbType
+ * @return
+ */
+ public static String parseDateHavaMark(String sqlParse, int num, String dbType) {
+ Pattern pDateParse = Pattern.compile("(DATE)\\s*\\((.*?(.*?\\).*?){" + num + "})\\)", Pattern.CASE_INSENSITIVE);
+ Matcher matcherParse = pDateParse.matcher(sqlParse);
+ StringBuffer sb = new StringBuffer();
+ String innerValue = null;
+ if (matcherParse.find()) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ innerValue = "toStartOfDay#[toDateTime#[" + matcherParse.group(2) + "]]";
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ innerValue = "TIME_FLOOR#[ TIMESTAMP " + matcherParse.group(2) + ",'P1D']";
+ }
+ matcherParse.appendReplacement(sb, innerValue);
+ }
+ matcherParse.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 获取函数参数
+ *
+ * @param str
+ * @param div 参数分隔符
+ * @return
+ */
+ public static List<String> diviParam(String str, String div) {
+ if (str == null) {
+ return null;
+ }
+ List<String> result = new ArrayList<>();
+ String[] split = str.split(div);
+ String resultTemp = "";
+ for (int i = 0; i < split.length; i++) {
+ resultTemp += split[i];
+ if (StringUtil.getBracketsMatch(resultTemp, "(", true)[0] >= 0
+ && StringUtil.getBracketsMatch(resultTemp, "[", true)[0] >= 0) {
+ result.add(resultTemp);
+ resultTemp = "";
+ continue;
+ }
+ resultTemp += div;
+ }
+ return result;
+ }
+
+
+ /**
+ * 公共,通过pattern匹配转义
+ *
+ * @param sql
+ * @param dbType
+ * @param pattern
+ * @return
+ */
+ private static String translateByPattern(String sql, String dbType, Pattern pattern) {
+ int count = 0;
+ while (true) {
+ Matcher matcher = pattern.matcher(sql);
+ if (!matcher.find() || count++ >= 40) {
+ return sql;
+ }
+ String sqlParse = sql.substring(matcher.start());
+ int[] bracketsMatch = StringUtil.getBracketsMatch(sqlParse, "(", false);
+
+ if (bracketsMatch[0] >= 1) {
+ int start = StringUtils.indexOf(sqlParse, "(");
+ Function function = new Function();
+ function.setName(sqlParse.substring(0, start));
+ int end = bracketsMatch[1];
+ List<String> strings = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(sqlParse.substring(start + 1, end));
+ StringBuffer sb = new StringBuffer();
+ for (String str : strings) {
+ sb.append(str);
+ int[] a = StringUtil.getBracketsMatch(sb.toString(), "(", true);
+ if (a[0] != -1) {
+ function.getParamsList().add(sb.toString());
+ sb = new StringBuffer();
+ continue;
+ } else {
+ sb.append(",");
+ }
+ }
+
+ String replace = translateFunction(function, dbType);
+ sql = sql.substring(0, matcher.start()) + replace + sql.substring(matcher.start() + 1 + end);
+ }
+ }
+ }
+
+ /**
+ * 转义函数
+ *
+ * @param fun
+ * @param dbType
+ * @return
+ */
+ private static String translateFunction(Function fun, String dbType) {
+ String function = null;
+ if (TIME_FLOOR_WITH_FILL.equals(fun.getName())) {
+ function = translateTimeFloorWithFill(fun, dbType);
+ } else if (IP_TO_GEO.equals(fun.getName())) {
+ function = translateIpToGeo(fun);
+ } else if (IP_TO_CITY.equals(fun.getName())) {
+ function = translateIpToCity(fun);
+ } else if (IP_TO_COUNTRY.equals(fun.getName())) {
+ function = translateIpToCountry(fun);
+ }
+ return function;
+ }
+
+ /**
+ * 转义IP_TO_GEO
+ *
+ * @param fun
+ * @return
+ */
+ private static String translateIpToCountry(Function fun) {
+ return fun.paramsList.get(0);
+ }
+
+ /**
+ * 转义IP_TO_CITY
+ *
+ * @param fun
+ * @return
+ */
+ private static String translateIpToCity(Function fun) {
+ return fun.paramsList.get(0);
+ }
+
+ /**
+ * 转义IP_TO_COUNTRY
+ *
+ * @param fun
+ * @return
+ */
+ private static String translateIpToGeo(Function fun) {
+ return fun.paramsList.get(0);
+ }
+
+ /**
+ * 转义time_floor_with_fill
+ *
+ * @param function
+ * @param dbType
+ * @return
+ */
+ private static String translateTimeFloorWithFill(Function function, String dbType) {
+ String timestamp = function.getParamsList().get(0);
+ String period = function.getParamsList().get(1);
+
+ Matcher matcherPT = periodOfPT.matcher(period);
+ if (matcherPT.find()) {
+ String num = matcherPT.group(1);
+ String unit = matcherPT.group(2);
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ String format = null;
+ if ("S".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s SECOND)))";
+ } else if ("M".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s MINUTE)))";
+ } else if ("H".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s HOUR)))";
+ }
+ return String.format(format, timestamp, num);
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ String format = "TIMESTAMP_TO_MILLIS(time_floor(%s * 1000,%s))/1000";
+ return String.format(format, timestamp, period);
+ }
+ }
+
+ Matcher matcherP = periodOfP.matcher(period);
+ if (matcherP.find()) {
+ String num = matcherP.group(1);
+ String unit = matcherP.group(2);
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ String format = null;
+ if ("D".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s DAY)))";
+ } else if ("W".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s WEEK)))";
+ } else if ("M".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s MONTH)))";
+ } else if ("Y".equalsIgnoreCase(unit)) {
+ format = "toUnixTimestamp(toDateTime(toStartOfInterval(toDateTime(%s),INTERVAL %s YEAR)))";
+ }
+ return String.format(format, timestamp, num);
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ String format = "TIMESTAMP_TO_MILLIS(time_floor(%s * 1000,%s))/1000";
+ return String.format(format, timestamp, period);
+ }
+ }
+ return function.toString();
+ }
+
+ @Data
+ static class Function {
+ private String name;
+ private List<String> paramsList = new ArrayList<>();
+ }
+
+ @Data
+ static class DruidQueryParam {
+ private String query;
+ private Map<String, String> context = Maps.newHashMap();
+ private String resultFormat;
+
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLHelper.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLHelper.java
new file mode 100644
index 0000000..8fff8da
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SQLHelper.java
@@ -0,0 +1,95 @@
+package com.mesalab.common.utils;
+
+import com.alibaba.druid.util.JdbcConstants;
+import com.mesalab.common.enums.DBTypeEnum;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.select.Limit;
+import net.sf.jsqlparser.statement.select.PlainSelect;
+import net.sf.jsqlparser.statement.select.Select;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Slf4j
+public class SQLHelper {
+
+ public static Pattern pOrder = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
+
+
+ /**
+ * 去除qlString的select子句。
+ *
+ * @param qlString
+ * @return
+ */
+ public static String removeSelect(String qlString) {
+ int beginPos = qlString.toLowerCase().indexOf("from");
+ return qlString.substring(beginPos);
+ }
+
+ /**
+ * 去除orderBy子句。
+ *
+ * @param sql
+ * @return
+ */
+ public static String removeOrders(String sql) {
+ Matcher m = pOrder.matcher(sql);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(sb, "");
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+
+ /**
+ * 为当前SQL最外层增加Limit限制
+ *
+ * @param sql 原始SQL语句
+ * @param offset 开始条数
+ * @param rowCount 每页显示多少纪录条数
+ * @return limit限制后SQL语句
+ */
+ public static String getLimitString(String sql, int offset, int rowCount) {
+ try {
+ Select selectStatement = (Select) CCJSqlParserUtil.parse(sql);
+ PlainSelect select = (PlainSelect) selectStatement.getSelectBody();
+ Limit limit = new Limit();
+ if (offset > 0) {
+ limit.setOffset(new LongValue(offset));
+ }
+ limit.setRowCount(new LongValue(rowCount));
+ select.setLimit(limit);
+ sql = String.valueOf(selectStatement.getSelectBody());
+ } catch (Exception e) {
+ log.error("Set limit error, SQL is:{} , Error Message is :{} ", sql, e);
+ }
+
+ return sql;
+ }
+
+
+ /**
+ * 获取当前数据库预定义的方言
+ *
+ * @param dbType
+ * @return
+ */
+ public static String getDialectDBType(String dbType) {
+ if (DBTypeEnum.CLICKHOUSE.getValue().equals(dbType)) {
+ return JdbcConstants.MYSQL;
+ } else if (DBTypeEnum.DRUID.getValue().equals(dbType)) {
+ return JdbcConstants.HIVE;
+ } else if (DBTypeEnum.HBASE.getValue().equals(dbType)) {
+ return JdbcConstants.MYSQL;
+ } else {
+ return null;
+ }
+
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SchemaCacheUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SchemaCacheUtils.java
new file mode 100644
index 0000000..91da3f5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SchemaCacheUtils.java
@@ -0,0 +1,62 @@
+package com.mesalab.common.utils;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.CacheStats;
+import com.google.common.cache.LoadingCache;
+import com.mesalab.qgw.service.MetadataService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.TimeUnit;
+
+public class SchemaCacheUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(QueryCacheUtils.class);
+ private static final MetadataService metadataService = (MetadataService) SpringContextUtil.getBean("metadataService");
+
+ private static LoadingCache<String, Object> loadingCache = CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterWrite(30, TimeUnit.MINUTES)
+ .recordStats()
+ .build(new CacheLoader<String, Object>() {
+ @Override
+ public Object load(String key) throws Exception{
+ Object value = metadataService.getAllSchema();
+ return value;
+ }
+
+ });
+
+ public static Object get(String key) {
+ try {
+ return loadingCache.get(key);
+ } catch(Exception e) {
+ log.error(" Schema Cache ,get key error ", e);
+ return null;
+ }
+ }
+
+
+ public static void put(String key, Object value) {
+ loadingCache.put(key, value);
+ }
+
+ public static void remove(String key) {
+ loadingCache.invalidate(key);
+ }
+
+
+ public static void removeAll() {
+ loadingCache.invalidateAll();
+ }
+
+ public static CacheStats getStats() {
+ return loadingCache.stats();
+ }
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SpringContextUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SpringContextUtil.java
new file mode 100644
index 0000000..d750356
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/SpringContextUtil.java
@@ -0,0 +1,95 @@
+package com.mesalab.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * Spring上下文工具类
+ *
+ * @author dazzlzy
+ * @date 2018/4/25
+ */
+@Component
+public class SpringContextUtil implements ApplicationContextAware {
+
+ private static ApplicationContext context = null;
+
+ private SpringContextUtil() {
+ super();
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ context = applicationContext;
+ }
+
+ /**
+ * 根据名称获取bean
+ *
+ * @param beanName bean的名字
+ * @return bean对象
+ */
+ public static Object getBean(String beanName) {
+ return context.getBean(beanName);
+ }
+
+ /**
+ * 根据bean名称获取指定类型bean
+ *
+ * @param beanName bean名称
+ * @param clazz 返回的bean类型,若类型不匹配,将抛出异常
+ */
+ public static <T> T getBean(String beanName, Class<T> clazz) {
+ return context.getBean(beanName, clazz);
+ }
+
+ /**
+ * 根据类型获取bean
+ *
+ * @param clazz bean类型
+ * @return 指定类型的bean
+ */
+ public static <T> T getBean(Class<T> clazz) {
+ T t = null;
+ Map<String, T> map = context.getBeansOfType(clazz);
+ for (Map.Entry<String, T> entry : map.entrySet()) {
+ t = entry.getValue();
+ }
+ return t;
+ }
+
+ /**
+ * 是否包含bean
+ *
+ * @param beanName bean名字
+ * @return boolean,是否包含指定名字的bean
+ */
+ public static boolean containsBean(String beanName) {
+ return context.containsBean(beanName);
+ }
+
+ /**
+ * 是否是单例
+ *
+ * @param beanName bean名字
+ * @return boolean, 是否是单例
+ */
+ public static boolean isSingleton(String beanName) {
+ return context.isSingleton(beanName);
+ }
+
+ /**
+ * bean的类型
+ *
+ * @param beanName bean名字
+ * @return bean的类型
+ */
+ public static Class getType(String beanName) {
+ return context.getType(beanName);
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/StringUtil.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/StringUtil.java
new file mode 100644
index 0000000..11a485e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/StringUtil.java
@@ -0,0 +1,284 @@
+package com.mesalab.common.utils;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang.StringUtils;
+
+import javax.management.RuntimeErrorException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String 工具类
+ *
+ * @author dazzlzy
+ * @date 2018/4/26
+ */
+public class StringUtil {
+
+ private static Pattern linePattern = Pattern.compile("_(\\w)");
+ private static Pattern humpPattern = Pattern.compile("[A-Z]");
+
+ /**
+ * 下划线转驼峰
+ *
+ * @param str 下划线字符串
+ * @return 驼峰字符串
+ */
+ public static String lineToHump(String str) {
+ if (null == str || "".equals(str)) {
+ return str;
+ }
+ str = str.toLowerCase();
+ Matcher matcher = linePattern.matcher(str);
+ StringBuffer sb = new StringBuffer();
+ while (matcher.find()) {
+ matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
+ }
+ matcher.appendTail(sb);
+
+ str = sb.toString();
+ str = str.substring(0, 1).toUpperCase() + str.substring(1);
+
+ return str;
+ }
+
+ /**
+ * 驼峰转下划线,效率比上面高
+ *
+ * @param str 驼峰字符串
+ * @return 下划线字符串
+ */
+ public static String humpToLine(String str) {
+ Matcher matcher = humpPattern.matcher(str);
+ StringBuffer sb = new StringBuffer();
+ while (matcher.find()) {
+ matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
+ }
+ matcher.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 驼峰转下划线(简单写法,效率低于{@link #humpToLine(String)})
+ *
+ * @param str 驼峰字符串
+ * @return 下划线字符串
+ */
+ public static String humpToLine2(String str) {
+ return str.replaceAll("[A-Z]", "_$0").toLowerCase();
+ }
+
+ /**
+ * 首字母转小写
+ *
+ * @param s 字符串
+ * @return 首字母小写的字符串
+ */
+ public static String toLowerCaseFirstOne(String s) {
+ if (StringUtils.isBlank(s)) {
+ return s;
+ }
+ if (Character.isLowerCase(s.charAt(0))) {
+ return s;
+ } else {
+ return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
+ }
+ }
+
+ /**
+ * 首字母转大写
+ *
+ * @param s 字符串
+ * @return 首字母大写的字符串
+ */
+ public static String toUpperCaseFirstOne(String s) {
+ if (StringUtils.isBlank(s)) {
+ return s;
+ }
+ if (Character.isUpperCase(s.charAt(0))) {
+ return s;
+ } else {
+ return (new StringBuffer()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
+ }
+ }
+
+ /**
+ * object转String
+ *
+ * @param object object
+ * @return String
+ */
+ public static String getString(Object object) {
+ return getString(object, "");
+ }
+
+ /**
+ * object转String,提供默认值
+ *
+ * @param object object
+ * @param defaultValue 默认值
+ * @return String
+ */
+ public static String getString(Object object, String defaultValue) {
+ if (null == object) {
+ return defaultValue;
+ }
+ try {
+ return object.toString();
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * object转int
+ *
+ * @param object object
+ * @return int
+ */
+ public static int getInt(Object object) {
+ return getInt(object, -1);
+ }
+
+ /**
+ * object转int,提供默认值
+ *
+ * @param object object
+ * @param defaultValue 默认值
+ * @return int
+ */
+ public static int getInt(Object object, Integer defaultValue) {
+ if (null == object) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(object.toString());
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * object转Boolean
+ *
+ * @param object object
+ * @return boolean
+ */
+ public static boolean getBoolean(Object object) {
+ return getBoolean(object, false);
+ }
+
+ /**
+ * object转boolean,提供默认值
+ *
+ * @param object object
+ * @param defaultValue 默认值
+ * @return boolean
+ */
+ public static boolean getBoolean(Object object, Boolean defaultValue) {
+ if (null == object) {
+ return defaultValue;
+ }
+ try {
+ return Boolean.parseBoolean(object.toString());
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+
+ /**
+ * 获取第一个括号对应右括号的索引以及包含括号的个数,向后匹配
+ * @param str
+ * @param bracketL 支持:( OR [ OR {
+ * @param bool 是否将传入的字符串全部匹配完成,若不需要则在匹配到第一个括号匹配完成时结束
+ * @return int[0]:匹配括号的个数,int[1]:第一个括号对应右括号的索引;若无匹配括号返回{0,-1};若有其中一个不成对则返回{-1,index}
+ */
+ public static int[] getBracketsMatch(String str, String bracketL, boolean bool) {
+ int[] result = {0, -1};
+ if (str == null) {
+ return result;
+ }
+ String bracketR = ")";
+ if (bracketL == null) {
+ bracketL = "(";
+ } else if (bracketL.equals("[")) {
+ bracketR = "]";
+ } else if (bracketL.equals("{")) {
+ bracketR = "}";
+ }
+ StringBuffer sb = new StringBuffer(str);
+ int countL = 0, countR = 0;
+ for (int a = 0; a < sb.length(); a++) {
+ if (sb.indexOf(bracketR) == a) {
+ ++countR;
+ sb.replace(a, a + 1, "$");
+ } else if (sb.indexOf(bracketL) == a) {
+ ++countL;
+ sb.replace(a, a + 1, "$");
+ }
+ if (countR > countL) {
+ result[0] = -1;
+ result[1] = -1;
+ return result;
+ }
+ result[0] = countL;
+ result[1] = a;
+ if (countL != 0 && (countL == countR) && !bool) {
+ return result;
+ }
+ }
+ if (countR != countL) {
+ result[0] = -1;
+ }
+ return result;
+ }
+
+ /**
+ * 获取最后一个括号对应左括号的索引以及包含括号的个数,向前匹配
+ * @param str
+ * @param bracketR 支持:) OR ] OR }
+ * @param bool 是否将传入的字符串全部匹配完成,若不需要则在匹配到第一个括号匹配完成时结束
+ * @return int[0]:匹配括号的个数,int[1]:第一个括号对应左括号的索引;若无匹配括号返回{0,-1};若有其中一个不成对则返回{-1,index}
+ */
+ public static int[] getBracketsMatchReverse(String str, String bracketR, boolean bool) {
+ int[] result = {0, -1};
+ if (str == null) {
+ return result;
+ }
+ StringBuffer sb = new StringBuffer(str);
+ String bracketL = "(";
+ if (bracketR == null) {
+ bracketR = ")";
+ } else if (bracketR.equals("]")) {
+ bracketL = "[";
+ } else if (bracketR.equals("}")) {
+ bracketL = "{";
+ }
+ int countL = 0, countR = 0;
+ for (int a = sb.length() - 1; a >= 0; a--) {
+ if (sb.indexOf(bracketR) == a) {
+ ++countR;
+ sb.replace(a, a + 1, "$");
+ } else if (sb.indexOf(bracketL) == a) {
+ ++countL;
+ sb.replace(a, a + 1, "$");
+ }
+ if (countL > countR) {
+ result[0] = -1;
+ result[1] = -1;
+ return result;
+ }
+ result[0] = countL;
+ result[1] = a;
+ if (countR != 0 && (countL == countR) && !bool) {
+ return result;
+ }
+ }
+ if (countR != countL) {
+ result[0] = -1;
+ }
+ return result;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java
new file mode 100644
index 0000000..4ca55b7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TableFinder.java
@@ -0,0 +1,786 @@
+package com.mesalab.common.utils;
+
+import com.mesalab.common.utils.SpringContextUtil;
+import com.mesalab.qgw.service.MetadataService;
+import com.zdjizhi.utils.StringUtil;
+import net.sf.jsqlparser.expression.*;
+import net.sf.jsqlparser.expression.operators.arithmetic.*;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
+import net.sf.jsqlparser.expression.operators.relational.*;
+import net.sf.jsqlparser.schema.Column;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.Block;
+import net.sf.jsqlparser.statement.Commit;
+import net.sf.jsqlparser.statement.DeclareStatement;
+import net.sf.jsqlparser.statement.DescribeStatement;
+import net.sf.jsqlparser.statement.ExplainStatement;
+import net.sf.jsqlparser.statement.SetStatement;
+import net.sf.jsqlparser.statement.ShowColumnsStatement;
+import net.sf.jsqlparser.statement.ShowStatement;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.StatementVisitor;
+import net.sf.jsqlparser.statement.Statements;
+import net.sf.jsqlparser.statement.UseStatement;
+import net.sf.jsqlparser.statement.alter.Alter;
+import net.sf.jsqlparser.statement.comment.Comment;
+import net.sf.jsqlparser.statement.create.index.CreateIndex;
+import net.sf.jsqlparser.statement.create.table.CreateTable;
+import net.sf.jsqlparser.statement.create.view.AlterView;
+import net.sf.jsqlparser.statement.create.view.CreateView;
+import net.sf.jsqlparser.statement.delete.Delete;
+import net.sf.jsqlparser.statement.drop.Drop;
+import net.sf.jsqlparser.statement.execute.Execute;
+import net.sf.jsqlparser.statement.insert.Insert;
+import net.sf.jsqlparser.statement.merge.Merge;
+import net.sf.jsqlparser.statement.replace.Replace;
+import net.sf.jsqlparser.statement.select.AllColumns;
+import net.sf.jsqlparser.statement.select.AllTableColumns;
+import net.sf.jsqlparser.statement.select.FromItemVisitor;
+import net.sf.jsqlparser.statement.select.Join;
+import net.sf.jsqlparser.statement.select.LateralSubSelect;
+import net.sf.jsqlparser.statement.select.ParenthesisFromItem;
+import net.sf.jsqlparser.statement.select.PlainSelect;
+import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.statement.select.SelectBody;
+import net.sf.jsqlparser.statement.select.SelectExpressionItem;
+import net.sf.jsqlparser.statement.select.SelectItem;
+import net.sf.jsqlparser.statement.select.SelectItemVisitor;
+import net.sf.jsqlparser.statement.select.SelectVisitor;
+import net.sf.jsqlparser.statement.select.SetOperationList;
+import net.sf.jsqlparser.statement.select.SubJoin;
+import net.sf.jsqlparser.statement.select.SubSelect;
+import net.sf.jsqlparser.statement.select.TableFunction;
+import net.sf.jsqlparser.statement.select.ValuesList;
+import net.sf.jsqlparser.statement.select.WithItem;
+import net.sf.jsqlparser.statement.truncate.Truncate;
+import net.sf.jsqlparser.statement.update.Update;
+import net.sf.jsqlparser.statement.upsert.Upsert;
+import net.sf.jsqlparser.statement.values.ValuesStatement;
+
+public class TableFinder implements SelectVisitor, FromItemVisitor, ExpressionVisitor, ItemsListVisitor, SelectItemVisitor, StatementVisitor {
+
+ private static MetadataService metadataService = (MetadataService) SpringContextUtil.getBean("metadataService");
+
+ private static final String NOT_SUPPORTED_YET = "Not supported yet.";
+ private boolean defaultAlias = false;
+
+ public void addSchemaName(Statement statement) {
+ statement.accept(this);
+ }
+
+ public void setDefaultAlias(boolean bool) {
+ this.defaultAlias = bool;
+ }
+
+ @Override
+ public void visit(Select select) {
+ if (select.getWithItemsList() != null) {
+ for (WithItem withItem : select.getWithItemsList()) {
+ withItem.accept(this);
+ }
+ }
+ select.getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(WithItem withItem) {
+ withItem.getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(PlainSelect plainSelect) {
+ if (plainSelect.getSelectItems() != null) {
+ for (SelectItem item : plainSelect.getSelectItems()) {
+ item.accept(this);
+ }
+ }
+
+ if (plainSelect.getFromItem() != null) {
+ plainSelect.getFromItem().accept(this);
+ }
+
+ if (plainSelect.getJoins() != null) {
+ for (Join join : plainSelect.getJoins()) {
+ join.getRightItem().accept(this);
+ }
+ }
+ if (plainSelect.getWhere() != null) {
+ plainSelect.getWhere().accept(this);
+ }
+
+ if (plainSelect.getHaving() != null) {
+ plainSelect.getHaving().accept(this);
+ }
+
+ if (plainSelect.getOracleHierarchical() != null) {
+ plainSelect.getOracleHierarchical().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Table tableName) {
+ //添加 schemaName
+ if (StringUtil.isBlank(tableName.getSchemaName())) {
+ tableName.setSchemaName(metadataService.getDBNameByTableName(tableName.getName()));
+ }
+ //添加 alias
+ if ((defaultAlias && (tableName.getAlias() == null))
+ || defaultAlias && (StringUtil.isBlank(tableName.getAlias().getName()))) {
+ Alias alias = new Alias(tableName.getName(), true);
+ tableName.setAlias(alias);
+ }
+ }
+
+ @Override
+ public void visit(SubSelect subSelect) {
+ if (subSelect.getWithItemsList() != null) {
+ for (WithItem withItem : subSelect.getWithItemsList()) {
+ withItem.accept(this);
+ }
+ }
+ subSelect.getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(Addition addition) {
+ visitBinaryExpression(addition);
+ }
+
+ @Override
+ public void visit(AndExpression andExpression) {
+ visitBinaryExpression(andExpression);
+ }
+
+ @Override
+ public void visit(Between between) {
+ between.getLeftExpression().accept(this);
+ between.getBetweenExpressionStart().accept(this);
+ between.getBetweenExpressionEnd().accept(this);
+ }
+
+ @Override
+ public void visit(Column tableColumn) {
+ if (tableColumn.getTable() != null && tableColumn.getTable().getName() != null) {
+ visit(tableColumn.getTable());
+ }
+ }
+
+ @Override
+ public void visit(Division division) {
+ visitBinaryExpression(division);
+ }
+
+ @Override
+ public void visit(IntegerDivision division) {
+ visitBinaryExpression(division);
+ }
+
+ @Override
+ public void visit(DoubleValue doubleValue) {
+ }
+
+ @Override
+ public void visit(EqualsTo equalsTo) {
+ visitBinaryExpression(equalsTo);
+ }
+
+ @Override
+ public void visit(Function function) {
+ ExpressionList exprList = function.getParameters();
+ if (exprList != null) {
+ visit(exprList);
+ }
+ }
+
+ @Override
+ public void visit(GreaterThan greaterThan) {
+ visitBinaryExpression(greaterThan);
+ }
+
+ @Override
+ public void visit(GreaterThanEquals greaterThanEquals) {
+ visitBinaryExpression(greaterThanEquals);
+ }
+
+ @Override
+ public void visit(InExpression inExpression) {
+ if (inExpression.getLeftExpression() != null) {
+ inExpression.getLeftExpression().accept(this);
+ } else if (inExpression.getLeftItemsList() != null) {
+ inExpression.getLeftItemsList().accept(this);
+ }
+ inExpression.getRightItemsList().accept(this);
+ }
+
+ @Override
+ public void visit(FullTextSearch fullTextSearch) {
+ }
+
+ @Override
+ public void visit(SignedExpression signedExpression) {
+ signedExpression.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(IsNullExpression isNullExpression) {
+ }
+
+ @Override
+ public void visit(IsBooleanExpression isBooleanExpression) {
+ }
+
+ @Override
+ public void visit(JdbcParameter jdbcParameter) {
+ }
+
+ @Override
+ public void visit(LikeExpression likeExpression) {
+ visitBinaryExpression(likeExpression);
+ }
+
+ @Override
+ public void visit(ExistsExpression existsExpression) {
+ existsExpression.getRightExpression().accept(this);
+ }
+
+ @Override
+ public void visit(LongValue longValue) {
+ }
+
+ @Override
+ public void visit(MinorThan minorThan) {
+ visitBinaryExpression(minorThan);
+ }
+
+ @Override
+ public void visit(MinorThanEquals minorThanEquals) {
+ visitBinaryExpression(minorThanEquals);
+ }
+
+ @Override
+ public void visit(Multiplication multiplication) {
+ visitBinaryExpression(multiplication);
+ }
+
+ @Override
+ public void visit(NotEqualsTo notEqualsTo) {
+ visitBinaryExpression(notEqualsTo);
+ }
+
+ @Override
+ public void visit(NullValue nullValue) {
+ }
+
+ @Override
+ public void visit(OrExpression orExpression) {
+ visitBinaryExpression(orExpression);
+ }
+
+ @Override
+ public void visit(Parenthesis parenthesis) {
+ parenthesis.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(StringValue stringValue) {
+ }
+
+ @Override
+ public void visit(Subtraction subtraction) {
+ visitBinaryExpression(subtraction);
+ }
+
+ @Override
+ public void visit(NotExpression notExpr) {
+ notExpr.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(BitwiseRightShift expr) {
+ visitBinaryExpression(expr);
+ }
+
+ @Override
+ public void visit(BitwiseLeftShift expr) {
+ visitBinaryExpression(expr);
+ }
+
+ public void visitBinaryExpression(BinaryExpression binaryExpression) {
+ binaryExpression.getLeftExpression().accept(this);
+ binaryExpression.getRightExpression().accept(this);
+ }
+
+ @Override
+ public void visit(ExpressionList expressionList) {
+ for (Expression expression : expressionList.getExpressions()) {
+ expression.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(NamedExpressionList namedExpressionList) {
+ for (Expression expression : namedExpressionList.getExpressions()) {
+ expression.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(DateValue dateValue) {
+ }
+
+ @Override
+ public void visit(TimestampValue timestampValue) {
+ }
+
+ @Override
+ public void visit(TimeValue timeValue) {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.jsqlparser.expression.ExpressionVisitor#visit(net.sf.jsqlparser.expression.CaseExpression)
+ */
+ @Override
+ public void visit(CaseExpression caseExpression) {
+ if (caseExpression.getSwitchExpression() != null) {
+ caseExpression.getSwitchExpression().accept(this);
+ }
+ if (caseExpression.getWhenClauses() != null) {
+ for (WhenClause when : caseExpression.getWhenClauses()) {
+ when.accept(this);
+ }
+ }
+ if (caseExpression.getElseExpression() != null) {
+ caseExpression.getElseExpression().accept(this);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.jsqlparser.expression.ExpressionVisitor#visit(net.sf.jsqlparser.expression.WhenClause)
+ */
+ @Override
+ public void visit(WhenClause whenClause) {
+ if (whenClause.getWhenExpression() != null) {
+ whenClause.getWhenExpression().accept(this);
+ }
+ if (whenClause.getThenExpression() != null) {
+ whenClause.getThenExpression().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(AllComparisonExpression allComparisonExpression) {
+ allComparisonExpression.getSubSelect().getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(AnyComparisonExpression anyComparisonExpression) {
+ anyComparisonExpression.getSubSelect().getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(SubJoin subjoin) {
+ subjoin.getLeft().accept(this);
+ for (Join join : subjoin.getJoinList()) {
+ join.getRightItem().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Concat concat) {
+ visitBinaryExpression(concat);
+ }
+
+ @Override
+ public void visit(Matches matches) {
+ visitBinaryExpression(matches);
+ }
+
+ @Override
+ public void visit(BitwiseAnd bitwiseAnd) {
+ visitBinaryExpression(bitwiseAnd);
+ }
+
+ @Override
+ public void visit(BitwiseOr bitwiseOr) {
+ visitBinaryExpression(bitwiseOr);
+ }
+
+ @Override
+ public void visit(BitwiseXor bitwiseXor) {
+ visitBinaryExpression(bitwiseXor);
+ }
+
+ @Override
+ public void visit(CastExpression cast) {
+ cast.getLeftExpression().accept(this);
+ }
+
+ @Override
+ public void visit(Modulo modulo) {
+ visitBinaryExpression(modulo);
+ }
+
+ @Override
+ public void visit(AnalyticExpression analytic) {
+ }
+
+ @Override
+ public void visit(SetOperationList list) {
+ for (SelectBody plainSelect : list.getSelects()) {
+ plainSelect.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(ExtractExpression eexpr) {
+ }
+
+ @Override
+ public void visit(LateralSubSelect lateralSubSelect) {
+ lateralSubSelect.getSubSelect().getSelectBody().accept(this);
+ }
+
+ @Override
+ public void visit(MultiExpressionList multiExprList) {
+ for (ExpressionList exprList : multiExprList.getExprList()) {
+ exprList.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(ValuesList valuesList) {
+ }
+
+
+ @Override
+ public void visit(IntervalExpression iexpr) {
+ }
+
+ @Override
+ public void visit(JdbcNamedParameter jdbcNamedParameter) {
+ }
+
+ @Override
+ public void visit(OracleHierarchicalExpression oexpr) {
+ if (oexpr.getStartExpression() != null) {
+ oexpr.getStartExpression().accept(this);
+ }
+
+ if (oexpr.getConnectExpression() != null) {
+ oexpr.getConnectExpression().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(RegExpMatchOperator rexpr) {
+ visitBinaryExpression(rexpr);
+ }
+
+ @Override
+ public void visit(RegExpMySQLOperator rexpr) {
+ visitBinaryExpression(rexpr);
+ }
+
+ @Override
+ public void visit(JsonExpression jsonExpr) {
+ }
+
+ @Override
+ public void visit(JsonOperator jsonExpr) {
+ }
+
+ @Override
+ public void visit(AllColumns allColumns) {
+ }
+
+ @Override
+ public void visit(AllTableColumns allTableColumns) {
+ }
+
+ @Override
+ public void visit(SelectExpressionItem item) {
+ item.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(UserVariable var) {
+ }
+
+ @Override
+ public void visit(NumericBind bind) {
+
+ }
+
+ @Override
+ public void visit(KeepExpression aexpr) {
+ }
+
+ @Override
+ public void visit(MySQLGroupConcat groupConcat) {
+ }
+
+ @Override
+ public void visit(ValueListExpression valueList) {
+ valueList.getExpressionList().accept(this);
+ }
+
+ @Override
+ public void visit(Delete delete) {
+ visit(delete.getTable());
+
+ if (delete.getJoins() != null) {
+ for (Join join : delete.getJoins()) {
+ join.getRightItem().accept(this);
+ }
+ }
+
+ if (delete.getWhere() != null) {
+ delete.getWhere().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Update update) {
+ visit(update.getTable());
+ if (update.getStartJoins() != null) {
+ for (Join join : update.getStartJoins()) {
+ join.getRightItem().accept(this);
+ }
+ }
+ if (update.getExpressions() != null) {
+ for (Expression expression : update.getExpressions()) {
+ expression.accept(this);
+ }
+ }
+
+ if (update.getFromItem() != null) {
+ update.getFromItem().accept(this);
+ }
+
+ if (update.getJoins() != null) {
+ for (Join join : update.getJoins()) {
+ join.getRightItem().accept(this);
+ }
+ }
+
+ if (update.getWhere() != null) {
+ update.getWhere().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Insert insert) {
+ visit(insert.getTable());
+ if (insert.getItemsList() != null) {
+ insert.getItemsList().accept(this);
+ }
+ if (insert.getSelect() != null) {
+ visit(insert.getSelect());
+ }
+ }
+
+ @Override
+ public void visit(Replace replace) {
+ visit(replace.getTable());
+ if (replace.getExpressions() != null) {
+ for (Expression expression : replace.getExpressions()) {
+ expression.accept(this);
+ }
+ }
+ if (replace.getItemsList() != null) {
+ replace.getItemsList().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Drop drop) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(Truncate truncate) {
+ visit(truncate.getTable());
+ }
+
+ @Override
+ public void visit(CreateIndex createIndex) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(CreateTable create) {
+ visit(create.getTable());
+ if (create.getSelect() != null) {
+ create.getSelect().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(CreateView createView) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(Alter alter) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(Statements stmts) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(Execute execute) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(SetStatement set) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(ShowColumnsStatement set) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(RowConstructor rowConstructor) {
+ for (Expression expr : rowConstructor.getExprList().getExpressions()) {
+ expr.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(HexValue hexValue) {
+
+ }
+
+ @Override
+ public void visit(Merge merge) {
+ visit(merge.getTable());
+ if (merge.getUsingTable() != null) {
+ merge.getUsingTable().accept(this);
+ } else if (merge.getUsingSelect() != null) {
+ merge.getUsingSelect().accept((FromItemVisitor) this);
+ }
+ }
+
+ @Override
+ public void visit(OracleHint hint) {
+ }
+
+ @Override
+ public void visit(TableFunction valuesList) {
+ }
+
+ @Override
+ public void visit(AlterView alterView) {
+ throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ }
+
+ @Override
+ public void visit(TimeKeyExpression timeKeyExpression) {
+ }
+
+ @Override
+ public void visit(DateTimeLiteralExpression literal) {
+
+ }
+
+ @Override
+ public void visit(Commit commit) {
+
+ }
+
+ @Override
+ public void visit(Upsert upsert) {
+ visit(upsert.getTable());
+ if (upsert.getItemsList() != null) {
+ upsert.getItemsList().accept(this);
+ }
+ if (upsert.getSelect() != null) {
+ visit(upsert.getSelect());
+ }
+ }
+
+ @Override
+ public void visit(UseStatement use) {
+ }
+
+ @Override
+ public void visit(ParenthesisFromItem parenthesis) {
+ parenthesis.getFromItem().accept(this);
+ }
+
+ @Override
+ public void visit(Block block) {
+ if (block.getStatements() != null) {
+ visit(block.getStatements());
+ }
+ }
+
+ @Override
+ public void visit(Comment comment) {
+ if (comment.getTable() != null) {
+ visit(comment.getTable());
+ }
+ if (comment.getColumn() != null) {
+ Table table = comment.getColumn().getTable();
+ if (table != null) {
+ visit(table);
+ }
+ }
+ }
+
+ @Override
+ public void visit(ValuesStatement values) {
+ for (Expression expr : values.getExpressions()) {
+ expr.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(DescribeStatement describe) {
+ describe.getTable().accept(this);
+ }
+
+ @Override
+ public void visit(ExplainStatement explain) {
+ explain.getStatement().accept(this);
+ }
+
+ @Override
+ public void visit(NextValExpression nextVal) {
+ }
+
+ @Override
+ public void visit(CollateExpression col) {
+ col.getLeftExpression().accept(this);
+ }
+
+ @Override
+ public void visit(ShowStatement aThis) {
+ }
+
+ @Override
+ public void visit(SimilarToExpression expr) {
+ visitBinaryExpression(expr);
+ }
+
+ @Override
+ public void visit(DeclareStatement aThis) {
+ }
+
+ @Override
+ public void visit(ArrayExpression array) {
+ array.getObjExpression().accept(this);
+ array.getIndexExpression().accept(this);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java
new file mode 100644
index 0000000..e09fbe5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/common/utils/TreeUtils.java
@@ -0,0 +1,100 @@
+package com.mesalab.common.utils;
+
+
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class TreeUtils {
+
+
+ /**
+ * 遍历树结构
+ * @param root 节点树
+ * @param getChildrenNode 获取当前节点的子节点列表;函数,接收当前节点对象
+ * @param behavior 当前节点操作函数;定义遍历当前节点的操作行为
+ * @param <T> 树的节点对象
+ */
+ public static <T> void traversalTree(List<T> root, Function<T, List<T>> getChildrenNode,
+ Consumer<T> behavior) {
+
+ Stack<T> stack = new Stack<>();
+ root.forEach(stack :: push);
+ while (!stack.isEmpty()) {
+ T o = stack.pop();
+ behavior.accept(o);
+ List<T> childrens = getChildrenNode.apply(o);
+ if (StringUtil.isNotEmpty(childrens)) {
+ childrens.forEach(stack :: push);
+ }
+ }
+
+ }
+
+ /**
+ * 平铺树结构
+ * @param root 节点树
+ * @param getChildrenNode 获取当前节点的子节点列表;函数,接收当前节点对象
+ * @param <T> 树的节点对象
+ * @return 平铺后的节点结构
+ */
+ public static <T> List<T> flatTree(List<T> root,
+ Function<T, List<T>> getChildrenNode) {
+ List<T> list = new ArrayList<>();
+ traversalTree(root, getChildrenNode, list :: add);
+ return list;
+ }
+
+
+
+
+
+ /**
+ * 聚合为树结构
+ * @param list 节点列表数据
+ * @param loadKey 节点的ID;函数,接收一个节点获取唯一ID
+ * @param loadParentKey 节点的父亲ID;函数,接收一个节点获取父亲ID
+ * @param write 节点Children写入函数;函数,接收当前节点和子节点列表,然后将子节点项写入当前节点。
+ * @param <T> 当前节点对象
+ * @param <R> 请求节点返回的属性信息
+ * @return 树结构列表
+ */
+ public static <T, R> List<T> mergeTree(List<T> list,
+ Function<T, R> loadKey,
+ Function<T, R> loadParentKey,
+ BiConsumer<T, List<T>> write) {
+ List<T> root = list.stream().filter(o -> StringUtil.isEmpty(loadParentKey.apply(o))).collect(Collectors.toList());
+ Stack<T> stack = new Stack<T>();
+ root.forEach(stack::push);
+ while (!stack.isEmpty()) {
+ T o = stack.pop();
+ R key = loadKey.apply(o);
+ List<T> childrens = list.stream().filter(k -> key.equals(loadParentKey.apply(k))).collect(Collectors.toList());
+ write.accept(o, childrens);
+ if (childrens.size() > 0) {
+ childrens.forEach(stack :: push);
+ }
+
+ }
+
+ return root;
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/engine/GalaxyQueryEngine.java b/galaxy-query-engine/src/main/java/com/mesalab/engine/GalaxyQueryEngine.java
deleted file mode 100644
index 8f80f11..0000000
--- a/galaxy-query-engine/src/main/java/com/mesalab/engine/GalaxyQueryEngine.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.mesalab.engine;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-
-@EnableDiscoveryClient
-@SpringBootApplication
-public class GalaxyQueryEngine {
-
- public static void main(String[] args) {
- SpringApplication.run(GalaxyQueryEngine.class);
- }
-}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLValidate.java b/galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLVerification.java
index 3d5cde7..5c8a0ab 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLValidate.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/engine/component/DSLVerification.java
@@ -28,7 +28,7 @@ import java.util.regex.Pattern;
* @Description : DSL格式校验
*/
@Component
-public class DSLValidate {
+public class DSLVerification {
public static Pattern periodOfPT = Pattern.compile("PT(\\d+)[SMH]", Pattern.CASE_INSENSITIVE);
public static Pattern periodOfP = Pattern.compile("P(\\d+)[DWMY]", Pattern.CASE_INSENSITIVE);
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/engine/controller/DslQueryController.java b/galaxy-query-engine/src/main/java/com/mesalab/engine/controller/DslQueryController.java
index 620073a..5b3ae64 100644
--- a/galaxy-query-engine/src/main/java/com/mesalab/engine/controller/DslQueryController.java
+++ b/galaxy-query-engine/src/main/java/com/mesalab/engine/controller/DslQueryController.java
@@ -5,7 +5,7 @@ import com.mesalab.engine.common.pojo.BaseResult;
import com.mesalab.engine.common.pojo.DSLObject;
import com.mesalab.engine.common.util.BaseResultUtil;
import com.mesalab.engine.component.DSLRouter;
-import com.mesalab.engine.component.DSLValidate;
+import com.mesalab.engine.component.DSLVerification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
@@ -28,13 +28,13 @@ public class DslQueryController {
protected DSLRouter dslRouter;
@Autowired
- protected DSLValidate dslValidate;
+ protected DSLVerification verification;
@PostMapping("query")
public BaseResult query(@RequestBody DSLObject dslObject) {
BaseResult baseResult;
try {
- dslValidate.executeValidate(dslObject);
+ verification.executeValidate(dslObject);
baseResult = dslRouter.executeRouter(dslObject);
} catch (BusinessException e) {
return BaseResultUtil.failure(
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/config/ArangoConfig.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/config/ArangoConfig.java
new file mode 100644
index 0000000..9dd84d7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/config/ArangoConfig.java
@@ -0,0 +1,39 @@
+package com.mesalab.knowledge.common.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @description: for http
+ * @author: zhq
+ * @create: 2020-07-07
+ **/
+@Data
+@Configuration
+public class ArangoConfig {
+
+ @Value("${arango.server}")
+ private String server;
+
+ @Value("${arango.database}")
+ private String database;
+
+ @Value("${arango.username}")
+ private String username;
+
+ @Value("${arango.password}")
+ private String password;
+
+ @Value("${arango.jwturl}")
+ private String jwturl;
+
+ @Value("${arango.queryurl}")
+ private String queryurl;
+
+ @Value("${arango.maxrows}")
+ private String maxrows;
+
+ private String jwt;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/Constant.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/Constant.java
new file mode 100644
index 0000000..9c776f8
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/Constant.java
@@ -0,0 +1,15 @@
+package com.mesalab.knowledge.common.utils;
+
+/**
+ * @description: for constant
+ * @author: zhq
+ * @create: 2020-07-22
+ **/
+public class Constant {
+ /**
+ * arango 相关常量
+ */
+ public static final String JWT = "jwt";
+ public static final String ARANGO_CACHE_JWT = "arango_jwt";
+ public static final String ARANGO_JWT_BEARER = "bearer ";//arango jwt固定前缀
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/HttpConfig.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/HttpConfig.java
new file mode 100644
index 0000000..c7a8acc
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/HttpConfig.java
@@ -0,0 +1,64 @@
+package com.mesalab.knowledge.common.utils;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+public class HttpConfig {
+ /**
+ * 最大连接数400
+ */
+ @Value("${http.pool.max.connection}")
+ private int maxConnectionNum;
+
+ /**
+ * 单路由最大连接数80
+ */
+ @Value("${http.pool.max.per.route}")
+ private int maxPerRoute;
+
+ /**
+ * 向服务端请求超时时间设置(单位:毫秒)
+ */
+ @Value("${http.pool.request.timeout}")
+ private int serverRequestTimeOut;
+
+ /**
+ * 向服务端连接超时时间设置(单位:毫秒)
+ */
+ @Value("${http.pool.connect.timeout}")
+ private int serverConnectTimeOut;
+
+ /**
+ * 服务端响应超时时间设置(单位:毫秒)
+ */
+ @Value("${http.pool.response.timeout}")
+ private int serverResponseTimeOut;
+
+ /**
+ * Druid查询请求响应时间
+ */
+ @Value("${druid.socketTimeOut}")
+ private int druidSocketTimeOut;
+
+ /**
+ * Arango查询请求响应时间
+ */
+ @Value("${arango.socketTimeOut}")
+ private int arangoSocketTimeOut;
+
+ /**
+ * ClickHouse长查询请求响应时间
+ */
+ @Value("${clickhouse.longTermAccount.socketTimeOut}")
+ private int ckLongTermAccountSocketTimeOut;
+
+ /**
+ * ClickHouse实时查询请求响应时间
+ */
+ @Value("${clickhouse.realTimeAccount.socketTimeOut}")
+ private int ckRealTimeAccountSocketTimeOut;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java
new file mode 100644
index 0000000..b09825d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/common/utils/JwtCache.java
@@ -0,0 +1,54 @@
+package com.mesalab.knowledge.common.utils;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheStats;
+import com.zdjizhi.utils.StringUtil;
+
+/**
+ * @description: for jwt cache
+ * @author: zhq
+ * @create: 2020-07-07
+ **/
+public class JwtCache {
+
+ private static Cache<String, Object> cache;
+
+ static {
+ cache = CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterWrite(20, TimeUnit.DAYS)
+ .recordStats()
+ .build();
+ }
+
+ public static Object get(String key) {
+ return StringUtil.isNotBlank(key) ? cache.getIfPresent(key) : null;
+ }
+
+ public static void put(String key, Object value) {
+ if (StringUtil.isNotBlank(key) && value != null) {
+ cache.put(key, value);
+ }
+ }
+
+ public static void remove(String key) {
+ if (StringUtil.isNotBlank(key)) {
+ cache.invalidate(key);
+ }
+
+ }
+
+ public static void remove(List<String> keys) {
+ if (StringUtil.isNotEmpty(keys)) {
+ cache.invalidateAll(keys);
+ }
+ }
+
+ public static CacheStats getStats() {
+ return cache.stats();
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java
new file mode 100644
index 0000000..d2fbcbf
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/controller/KnowledgeController.java
@@ -0,0 +1,46 @@
+package com.mesalab.knowledge.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.knowledge.enums.QueryTypeEnum;
+import com.mesalab.knowledge.service.KnowledgeService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.EnumUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@RestController
+@RequestMapping(value = "/knowledge")
+public class KnowledgeController {
+
+ @Autowired
+ KnowledgeService knowledgeService;
+
+ @GetMapping("/info")
+ public String info() {
+ return "You Konow, For Graph Search!";
+ }
+
+ /***
+ * @Description //TODO
+ * @Date 2020\7\16
+ * @Param [request, dSLObject]
+ * @return com.mesalab.common.base.BaseResult
+ **/
+ @PostMapping(value = "/v1/", produces = "application/json")
+ public BaseResult knowledgeQuery(HttpServletRequest request, @RequestBody Object object) {
+ if (EnumUtils.isValidEnum(QueryTypeEnum.class,StringUtil.upperCase(request.getQueryString()))) {
+ log.info("服务推荐接口, 参数: queryString is {},params is {}", request.getQueryString(), object);
+ return knowledgeService.query(object);
+ } else {
+ log.error("服务推荐接口, 错误:queryString is {},params is {}", request.getQueryString(), object);
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Not Support", null);
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/DSLObject.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/DSLObject.java
new file mode 100644
index 0000000..096bc5e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/DSLObject.java
@@ -0,0 +1,26 @@
+package com.mesalab.knowledge.entity;
+
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+@Data
+public class DSLObject implements Serializable {
+
+ private static final long serialVersionUID = 4506414702067122671L;
+ private Integer clientId;
+
+ private DSLQuery query;
+
+ @Data
+ public static class DSLQuery {
+
+ private String queryType;
+ private String dataSource;
+ private Parameters parameters;
+
+ }
+}
+
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java
new file mode 100644
index 0000000..3e44af1
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Match.java
@@ -0,0 +1,56 @@
+package com.mesalab.knowledge.entity;
+
+import com.google.common.base.CharMatcher;
+import com.mesalab.knowledge.enums.MatchEnum;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+import org.apache.commons.lang3.EnumUtils;
+import org.springframework.util.ObjectUtils;
+
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.function.Predicate;
+
+import static java.util.stream.Collectors.joining;
+
+/**
+ * @description: 查询单位字符串
+ * @author: zhq
+ * @create: 2020-07-02
+ **/
+@Data
+public class Match extends QueryExp {
+
+
+ public static String like(List<Match> matches, Predicate<Match> predicate) {
+
+ return ObjectUtils.isEmpty(matches) ?"": matches.stream().filter(m -> predicate.test(m)).map(m -> {
+
+ MatchEnum match = EnumUtils.getEnum(MatchEnum.class, StringUtil.upperCase(m.getType()));
+ return m.getFieldValues().stream().filter(mv -> mv != null).map(mv -> {
+ String matchExp = match.getMatchExp();
+ String value = String.valueOf(mv);
+ if (MatchEnum.REGEX.getType().equals(m.getType())) {
+ if (value.startsWith("$")) {
+ matchExp = MatchEnum.EXACTLY.getMatchExp();
+ value = CharMatcher.anyOf("$").trimLeadingFrom(value);
+ } else if (value.startsWith("*") && !value.endsWith("*")) {
+ matchExp = MatchEnum.SUFFIX.getMatchExp();
+ value = CharMatcher.anyOf("*").trimLeadingFrom(value);
+ } else if (value.endsWith("*") && !value.startsWith("*")) {
+ matchExp = MatchEnum.PREFIX.getMatchExp();
+ value = CharMatcher.anyOf("*").trimTrailingFrom(value);
+ } else if (value.startsWith("*") && value.endsWith("*")) {
+ matchExp = MatchEnum.SUBSTRING.getMatchExp();
+ value = CharMatcher.anyOf("*").trimFrom(value);
+ } else {
+ matchExp = MatchEnum.SUBSTRING.getMatchExp();
+ }
+ }
+ return MessageFormat.format(matchExp, value);
+ }).collect(joining(" or doc._key like ", " ( doc._key like ", ") "));
+
+ }).collect(joining(" and ", " filter ", " "));
+ }
+
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Parameters.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Parameters.java
new file mode 100644
index 0000000..f770c49
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Parameters.java
@@ -0,0 +1,22 @@
+package com.mesalab.knowledge.entity;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class Parameters {
+
+ private List<Match> match;
+
+ private List<Range> range;
+
+ private List<String> intervals;
+
+ private List<Sort> sort;
+
+ private String limit;
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/QueryExp.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/QueryExp.java
new file mode 100644
index 0000000..cbc5240
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/QueryExp.java
@@ -0,0 +1,18 @@
+package com.mesalab.knowledge.entity;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class QueryExp {
+
+ protected String type;
+ protected String fieldKey;
+ protected List<Object> fieldValues;
+
+ protected String operator;
+
+ protected String qlSegment;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Range.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Range.java
new file mode 100644
index 0000000..2ea4780
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Range.java
@@ -0,0 +1,13 @@
+package com.mesalab.knowledge.entity;
+
+import lombok.Data;
+
+/**
+ * @description: 查询单位范围
+ * @author: zhq
+ * @create: 2020-07-02
+ **/
+@Data
+public class Range extends QueryExp {
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Sort.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Sort.java
new file mode 100644
index 0000000..58b6503
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/Sort.java
@@ -0,0 +1,12 @@
+package com.mesalab.knowledge.entity;
+
+import lombok.Data;
+
+/**
+ * @description: 排序
+ * @author: zhq
+ * @create: 2020-07-03
+ **/
+@Data
+public class Sort extends QueryExp {
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseDocument.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseDocument.java
new file mode 100644
index 0000000..67ff17c
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseDocument.java
@@ -0,0 +1,49 @@
+/*
+ * DISCLAIMER
+ *
+ * Copyright 2016 ArangoDB GmbH, Cologne, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright holder is ArangoDB GmbH, Cologne, Germany
+ */
+
+package com.mesalab.knowledge.entity.arango;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Mark Vollmary
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BaseDocument implements Serializable {
+
+ private static final long serialVersionUID = -1824742667228719116L;
+
+ @JsonProperty(value = "_id")
+ protected String id;
+ @JsonProperty(value = "_key")
+ protected String key;
+ @JsonProperty(value = "_rev")
+ protected String revision;
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseEdgeDocument.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseEdgeDocument.java
new file mode 100644
index 0000000..fdd66d3
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/BaseEdgeDocument.java
@@ -0,0 +1,43 @@
+/*
+ * DISCLAIMER
+ *
+ * Copyright 2016 ArangoDB GmbH, Cologne, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright holder is ArangoDB GmbH, Cologne, Germany
+ */
+
+package com.mesalab.knowledge.entity.arango;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * @author Mark Vollmary
+ */
+@Data
+public class BaseEdgeDocument/* extends BaseDocument*/ {
+
+ private static final long serialVersionUID = 6904923804449368783L;
+
+ @JsonProperty(value = "_from")
+ private String from;
+
+ @JsonProperty(value = "_to")
+ private String to;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/IpLearningPath.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/IpLearningPath.java
new file mode 100644
index 0000000..d5af33e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/IpLearningPath.java
@@ -0,0 +1,84 @@
+package com.mesalab.knowledge.entity.arango;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.nutz.json.JsonField;
+
+import java.util.Date;
+import java.util.List;
+
+import static org.nutz.json.JsonFormat.Function.dateFormat;
+
+/**
+ * @description: for iplearning
+ * @author: zhq
+ * @create: 2020-07-15
+ **/
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class IpLearningPath {
+
+// private List<IpLearningVertices> vertices;
+
+ private List<IplearningEdges> edges;
+
+
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class IplearningEdges extends BaseEdgeDocument {
+
+ @JsonProperty(value = "FIRST_FOUND_TIME")
+ private Long firstFoundTime;
+
+ @JsonProperty(value = "LAST_FOUND_TIME")
+ private Long lastFoundTime;
+
+ @JsonProperty(value = "HTTP_CNT_RECENT")
+ private List<Long> httpCntRecent;
+
+ @JsonProperty(value = "HTTP_CNT_TOTAL")
+ private Long httpCntTotal;
+
+ @JsonProperty(value = "DNS_CNT_RECENT")
+ private List<Long> dnsCntRecent;
+
+ @JsonProperty(value = "DNS_CNT_TOTAL")
+ private Long dnsCntTotal;
+
+ @JsonProperty(value = "TLS_CNT_RECENT")
+ private List<Long> tlsCntRecent;
+
+ @JsonProperty(value = "TLS_CNT_TOTAL")
+ private Long tlsCntTotal;
+
+ @JsonProperty(value = "DIST_CIP_TS")
+ private List<Long> distCipTs;
+
+ @JsonProperty(value = "DIST_CIP")
+ private List<String> distCip;
+
+ }
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class IpLearningVertices {
+
+ @JsonProperty(value = "FQDN_NAME")
+ private String fqdnName;
+
+ @JsonProperty(value = "FIRST_FOUND_TIME")
+ private String firstFoundTime;
+
+ @JsonProperty(value = "LAST_FOUND_TIME")
+ private String lastFoundTime;
+
+ @JsonProperty(value = "IP")
+ private String ip;
+
+ @JsonProperty(value = "COMMON_LINK_INFO")
+ private String commonLinkInfo;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/SubscriberIdPath.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/SubscriberIdPath.java
new file mode 100644
index 0000000..d3d217c
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/entity/arango/SubscriberIdPath.java
@@ -0,0 +1,37 @@
+package com.mesalab.knowledge.entity.arango;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @description: for path
+ * @author: zhq
+ * @create: 2020-07-17
+ **/
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SubscriberIdPath {
+
+ private List<SubscriberIdVertices> vertices;
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class SubscriberIdVertices extends BaseDocument {
+
+ @JsonProperty(value = "SUBSCRIBER_ID")
+ private String fqdnName;
+
+ @JsonProperty(value = "FIRST_FOUND_TIME")
+ private String firstFoundTime;
+
+ @JsonProperty(value = "LAST_FOUND_TIME")
+ private String lastFoundTime;
+
+ @JsonProperty(value = "IP")
+ private String ip;
+
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/DataSourceEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/DataSourceEnum.java
new file mode 100644
index 0000000..dd11e86
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/DataSourceEnum.java
@@ -0,0 +1,24 @@
+package com.mesalab.knowledge.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @description: for datasource
+ * @author: zhq
+ * @create: 2020-07-06
+ **/
+@Getter
+@AllArgsConstructor
+public enum DataSourceEnum {
+
+
+ IP_LEARNING_VIEW("IP_LEARNING_VIEW"),
+
+ IP_VIEW("IP_VIEW"),
+
+ SUBSCRIBER_ID_VIEW("SUBSCRIBER_ID_VIEW");
+
+ private String view;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/MatchEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/MatchEnum.java
new file mode 100644
index 0000000..5134fac
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/MatchEnum.java
@@ -0,0 +1,45 @@
+package com.mesalab.knowledge.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 匹配查询
+ * <p>
+ * type:匹配方式,["exactly"|"prefix"|"suffix"|"substring"|"regex"]
+ * <p>
+ * exactly:完全匹配
+ * prefix:前缀匹配
+ * suffix:后缀匹配
+ * substring:子串匹配
+ * regex:正则符号匹配
+ * fieldKey:属性名称,
+ * <p>
+ * fieldValues:属性值
+ * <p>
+ * 注:当type=regex时
+ * <p>
+ * fieldValues值匹配方式符合下列规则,数组内多个值为“或”的关系
+ * <p>
+ * 匹配方式转义
+ * <p>
+ * 以*结尾,不以*或者$开始,无论关键字其他位置是否包含表示匹配方式的字符*和$,即表示左匹配(前缀匹配),例如aaaa*bbb$ccc*$*
+ * 以*开始,不以*结尾,无论关键字其他位置是否包含表示匹配方式的字符*和$,即表示右匹配(后缀匹配),例如*$*aaa*bbb$ccc
+ * 以*开始,以*结尾,无论关键字其他位置是否包含表示匹配方式的字符*和$,即表示子串匹配,例如*aaa$bbb*ccc*
+ * 不以*或者$开头,不以*结尾,无论关键字其他位置是否包含表示匹配方式的字符*和$,即表示子串匹配,例如aaa*bbb$ccc*$
+ * 以$开头,不以*结尾,无论关键字其他位置是否包含表示匹配方式的字符*和$,即表示完整匹配,例如$aaa*bbb$或者$aaa*$bbb
+ */
+@Getter
+@AllArgsConstructor
+public enum MatchEnum {
+
+ EXACTLY("exactly", "\"{0}\""),
+ PREFIX("prefix", "\"{0}%\""),
+ SUFFIX("suffix", "\"%{0}\""),
+ SUBSTRING("substring", "\"%{0}%\""),
+ REGEX("regex", "\"{0}\"");
+
+ private final String type;
+ private final String matchExp;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/QueryTypeEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/QueryTypeEnum.java
new file mode 100644
index 0000000..39c226e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/QueryTypeEnum.java
@@ -0,0 +1,23 @@
+package com.mesalab.knowledge.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @description: for queryType
+ * @author: zhq
+ * @create: 2020-07-16
+ **/
+@Getter
+@AllArgsConstructor
+public enum QueryTypeEnum {
+
+
+ IPLEARNING("iplearning"),
+ IPPOOL("ippool"),
+ SUBSCRIBERIDPOOL("subscriberidpool");
+
+
+ private final String type;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/RangeEnum.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/RangeEnum.java
new file mode 100644
index 0000000..09aa862
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/enums/RangeEnum.java
@@ -0,0 +1,46 @@
+package com.mesalab.knowledge.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 范围查询
+ * <p>
+ * type:["gt"|"lt"|"eq"|"ge"|"le"|"ne"]
+ * <p>
+ * gt: > 大于(greater than)
+ * lt: < 小于(less than)
+ * eq: = 等于(equal to)
+ * ge: >= 大于等于(greater than or equal)
+ * le: <= 小于等于(less than or equal)
+ * ne: != 不等于(not equal)
+ */
+@Getter
+@AllArgsConstructor
+public enum RangeEnum {
+
+
+ EQ("eq", "==", true),
+ NE("ne", "<>", true),
+ LT("lt", "<", false),
+ LE("le", "<=", false),
+ GT("gt", ">", false),
+ GE("ge", ">=", false);
+
+ private final String type;
+ private final String symbol;
+ private final boolean symmetric;
+
+
+ /**
+ * Returns if this operation is symmetric with respect to its parameters.
+ * More formally returns true if: A oper B is true if and only if B oper A is
+ * true.
+ *
+ * @return if this operation is symmetric with respect to its parameters
+ */
+ public boolean isSymmetric() {
+ return symmetric;
+ }
+
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java
new file mode 100644
index 0000000..20e7780
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/service/KnowledgeService.java
@@ -0,0 +1,163 @@
+package com.mesalab.knowledge.service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jackson.JsonLoader;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.core.report.ProcessingMessage;
+import com.github.fge.jsonschema.core.report.ProcessingReport;
+import com.github.fge.jsonschema.main.JsonSchema;
+import com.github.fge.jsonschema.main.JsonSchemaFactory;
+import com.google.common.base.Splitter;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.knowledge.entity.*;
+import com.mesalab.knowledge.enums.DataSourceEnum;
+import com.mesalab.knowledge.enums.MatchEnum;
+import com.mesalab.knowledge.enums.RangeEnum;
+import com.mesalab.knowledge.strategy.QueryProvider;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.JsonMapper;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.Validate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Objects.*;
+
+/**
+ * @description: for IP learning
+ * @author: zhq
+ * @create: 2020-07-06
+ **/
+@Slf4j
+@Service
+public class KnowledgeService {
+
+ @Value("${arango.maxrows}")
+ private String maxrows;//查询最大条数
+
+ @Autowired
+ Map<String, QueryProvider> provider = new ConcurrentHashMap<>();
+
+ public BaseResult query(Object object) {
+ //1.结构校验
+ validateJson(JsonMapper.toJsonString(object));
+ DSLObject dSLObject = (DSLObject) JsonMapper.fromJsonString(JsonMapper.toJsonString(object), DSLObject.class);
+ validate(dSLObject);
+ DSLObject.DSLQuery dslQeruy = dSLObject.getQuery();
+ //2.查询
+ Object result = provider.get(dslQeruy.getDataSource()).query(dslQeruy);
+ return BaseResultGenerator.success(result);
+
+ }
+
+ /**
+ * @return void
+ * @Author zhq
+ * @Description //TODO 参数校验
+ * @Date 2020\7\21 0021
+ * @Param [dslQuery]
+ **/
+ private void validate(DSLObject dSLObject) {
+ DSLObject.DSLQuery dslQuery = dSLObject.getQuery();
+ requireNonNull(dslQuery, "query is null");
+ Parameters parameters = dslQuery.getParameters();
+
+ requireNonNull(dslQuery.getDataSource(), "dataSource is null");
+ requireNonNull(EnumUtils.getEnum(DataSourceEnum.class,StringUtil.upperCase(dslQuery.getDataSource())), "dataSource no match");
+
+ if (isNull(parameters)) {
+ return;
+ }
+
+ List<Match> matchs = parameters.getMatch();
+ List<Range> ranges = parameters.getRange();
+ List<String> intervals = parameters.getIntervals();
+ List<Sort> sorts = parameters.getSort();
+ String limit = parameters.getLimit();
+ if (!ObjectUtils.isEmpty(matchs)) {
+ matchs.forEach(m -> {
+ Validate.isTrue(EnumUtils.isValidEnum(MatchEnum.class, StringUtil.upperCase(m.getType())), "match type is illegal");
+ //正则匹配方式 禁止 $xxx* 形式的value
+ if (MatchEnum.REGEX.getType().equals(m.getType())) {
+ m.getFieldValues().forEach(mv -> {
+ Validate.isTrue(!(String.valueOf(mv).startsWith("$") && String.valueOf(mv).endsWith("*")), "error in matching sign. begin with * and do not end with * for suffix matching, end with * and do not begin with $ or * for prefix matching, begin with $ and do not end with * for exactly matching, begin with * and end with * or no wildcard for substring matching");
+ });
+ }
+ });
+ }
+ if (!ObjectUtils.isEmpty(ranges)) {
+ ranges.forEach(r -> {
+ Validate.isTrue(EnumUtils.isValidEnum(RangeEnum.class, StringUtil.upperCase(r.getType())), "range type is illegal");
+ });
+ }
+ if (!ObjectUtils.isEmpty(sorts)) {
+ sorts.forEach(s -> {
+ Validate.isTrue("asc".equalsIgnoreCase(s.getType()) || "desc".equalsIgnoreCase(s.getType()), "sort type is illegal");
+ });
+ }
+ if (!ObjectUtils.isEmpty(intervals)) {
+ List<String> times = Splitter.on("/").splitToList(intervals.get(0));
+ Validate.notEmpty(times, "intervals should be [startTime/endTime],such as 2020-01-01 00:00:00/2020-02-02 00:00:00");
+ Validate.isTrue(times.size() == 2, "intervals should be [startTime/endTime],such as 2020-01-01 00:00:00/2020-02-02 00:00:00");
+ Validate.notBlank(times.get(0), "start time is null");
+ Validate.notBlank(times.get(1), "end time is null");
+ Date start = DateUtils.convertStringToDate(times.get(0), DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ Date end = DateUtils.convertStringToDate(times.get(1), DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ Validate.isTrue(start.before(end), "the end time must be after the start time");
+ }
+ if (nonNull(limit)) {
+ List<String> limits = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(limit);
+ Validate.notEmpty(limits, "limit is illegal");
+ Validate.isTrue(!(limit.contains(",") && limits.size() != 2), "limit is illegal");
+ for (String l : limits) {
+ Validate.isTrue(l.length() <= maxrows.length() && Integer.valueOf(maxrows) >= Integer.valueOf(l) && Integer.valueOf(l) > 0, "limit is greater than 0 and less than " + maxrows);
+ }
+ }
+ }
+
+ private void validateJson(String jsonString) {
+ JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
+ //通过jsonschemaFactory获取jsonnode对象
+ try {
+
+ JsonNode schemaNode = JsonLoader.fromResource("/dsl-validation.json");
+ //通过jsonstr字符串获取对应的jsonnode对象
+ JsonNode dataNode = JsonLoader.fromString(jsonString);
+ JsonSchema jsonSchema = factory.getJsonSchema(schemaNode);
+ //使用json-schema-validator中的jsonschema对象的validate方法对数据进行校验
+ //获取处理的报告信息
+ ProcessingReport processingReport = jsonSchema.validate(dataNode);
+ //获取完整的报告信息
+ Iterator<ProcessingMessage> iterator = processingReport.iterator();
+ StringBuffer sb = new StringBuffer();
+ while (iterator.hasNext()) {
+ ProcessingMessage next = iterator.next();
+ JsonNode jsonNode = next.asJson();
+ sb.append("pointer on ");
+ sb.append(jsonNode.get("instance").get("pointer"));
+ sb.append(", ");
+ sb.append(next.getMessage());
+ sb.append(". ");
+ }
+ //判断校验是否成功,如果为true成功
+ Validate.isTrue(processingReport.isSuccess(), sb.toString());
+ } catch (ProcessingException e) {
+ log.error(e.getMessage());
+ } catch (IOException e) {
+ log.error(e.getMessage());
+ }
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java
new file mode 100644
index 0000000..599910d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/BaseQueryProvider.java
@@ -0,0 +1,88 @@
+package com.mesalab.knowledge.strategy;
+
+import com.google.common.collect.ImmutableMap;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.knowledge.common.config.ArangoConfig;
+import com.mesalab.knowledge.common.utils.Constant;
+import com.mesalab.knowledge.common.utils.JwtCache;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.zdjizhi.utils.JsonMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @description: for base method
+ * @author: zhq
+ * @create: 2020-07-13
+ **/
+@Slf4j
+@Component
+public class BaseQueryProvider {
+
+ @Autowired
+ ArangoConfig arangoConfig;
+
+ @Autowired
+ HttpClientService httpClientService;
+
+ /**
+ * @return java.lang.String
+ * @Author zhq
+ * @Description 获取ArangoJwt
+ * @Date 2020\7\7 0007
+ **/
+ public String getJwt() {
+ Object jwt = JwtCache.get(Constant.ARANGO_CACHE_JWT);
+ if (Objects.nonNull(jwt)) {
+ return String.valueOf(jwt);
+ }
+ Map<String, String> params = new HashMap<>();
+ params.put("username", arangoConfig.getUsername());
+ params.put("password", arangoConfig.getPassword());
+ String res = httpClientService.httpPost(arangoConfig.getJwturl(), JsonMapper.toJsonString(params));
+ Map resMap = (Map) JsonMapper.fromJsonString(res, Map.class);
+ if (Objects.isNull(resMap.get(Constant.JWT))) {
+ throw new BusinessException("获取Arango jwt 失败");
+ }
+ jwt = Constant.ARANGO_JWT_BEARER + resMap.get(Constant.JWT);
+ JwtCache.put(Constant.ARANGO_CACHE_JWT, jwt);
+ return String.valueOf(jwt);
+ }
+
+ /***
+ * @Author zhq
+ * @Description //TODO
+ * @Date 2020\8\12 0012
+ * @Param [aql]
+ * @return java.lang.Object
+ **/
+ public Object queryArango(String aql) {
+ Map queryMap = ImmutableMap.of("query", aql);
+ Header header = new BasicHeader(HttpHeaders.AUTHORIZATION, getJwt());
+ String res = "";
+ try {
+ res = httpClientService.httpPost(arangoConfig.getQueryurl(), JsonMapper.toJsonString(queryMap), header);
+ } catch (BusinessException e) {
+ if (e.getErrorMessage() != null && e.getErrorMessage().contains("not authorized to execute this request")) {
+ //刷新jwt
+ JwtCache.remove(Constant.ARANGO_CACHE_JWT);
+ log.warn("arango jwt 失效后重置");
+ res = httpClientService.httpPost(arangoConfig.getQueryurl(), JsonMapper.toJsonString(queryMap), new BasicHeader(HttpHeaders.AUTHORIZATION, getJwt()));
+ } else {
+ log.error(e.getErrorMessage());
+ throw e;
+ }
+ }
+ Map jsonMap = (Map) JsonMapper.fromJsonString(res, Map.class);
+ Object result = jsonMap.get("result");
+ return result;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java
new file mode 100644
index 0000000..90ead32
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/FqdnProviderImpl.java
@@ -0,0 +1,191 @@
+package com.mesalab.knowledge.strategy;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mesalab.knowledge.entity.DSLObject;
+import com.mesalab.knowledge.entity.Match;
+import com.mesalab.knowledge.entity.Parameters;
+import com.mesalab.knowledge.entity.Range;
+import com.mesalab.knowledge.entity.arango.IpLearningPath;
+import com.mesalab.knowledge.enums.RangeEnum;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.StringUtil;
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.Validate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 根据fqdn查询ip的关系
+ */
+
+@Component("IP_LEARNING_VIEW")
+public class FqdnProviderImpl implements QueryProvider {
+
+ private static final String depthregex = "^[1-9]\\d*$"; //depth 取值范围大于0
+ private static final String SSL = "SSL";
+ private static final String TLS = "TLS";
+ private static final String HTTP = "HTTP";
+ private static final String DNS = "DNS";
+
+ @Value("${arango.maxrows}")
+ private String limit;//查询最大条数
+
+ @Autowired
+ BaseQueryProvider baseQueryProvider;
+
+ @Override
+ public Object query(DSLObject.DSLQuery dslQuery) {
+ Parameters parameters = dslQuery.getParameters();
+ //a.处理条件 b.需要的条件:fqdn_name 多个, depth, filter:last_found_time, dist_cip, http,ssl/tls,dns, limit
+ StringBuffer likeFilter = new StringBuffer();
+ StringBuffer intervalsb = new StringBuffer();
+ StringBuffer protocolsb = new StringBuffer();
+ StringBuffer distCiptsb = new StringBuffer();
+ if(!ObjectUtils.isEmpty(parameters)){
+ limit = ObjectUtils.isEmpty(parameters.getLimit()) ? limit : parameters.getLimit();
+ List<Match> matches = parameters.getMatch();
+ //1.构建查询语句 match like
+ likeFilter.append(Match.like(matches, (m) -> m != null && "FQDN_NAME".equals(m.getFieldKey()) && !ObjectUtils.isEmpty(m.getFieldValues())).replace(" doc._key like \"", " e._from like \"FQDN/"));
+
+ //2.构建查询语句 intervals 时间
+ List<String> intervals = parameters.getIntervals();
+ if(!ObjectUtils.isEmpty(intervals)){
+ String[] times = intervals.get(0).split("/");
+ intervalsb.append(" and e.LAST_FOUND_TIME >= ").append(DateUtils.convertStringToTimestamp(times[0], DateUtils.YYYY_MM_DD_HH24_MM_SS)).append(" and ").append("e.LAST_FOUND_TIME <").append(DateUtils.convertStringToTimestamp(times[1], DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ }
+
+ //3.构建查询语句 range depth ,protocols, limit
+ List<Range> ranges = parameters.getRange();
+
+ if(!ObjectUtils.isEmpty(ranges)){
+
+ for (Range r : ranges) {
+ //查询深度
+ if ("DEPTH".equals(r.getFieldKey())) {
+ Validate.notEmpty(r.getFieldValues(), "fieldValues of depth is null");
+ Validate.matchesPattern(String.valueOf(r.getFieldValues().get(0)), depthregex, "fieldValues of depth is illegal, you should type in an integer greater than 0");
+ } else if ("PROTOCOL".equals(r.getFieldKey())) {
+ List<String> protocols = Lists.newArrayList();
+ for (Object protocol : r.getFieldValues()) {
+ if (HTTP.equals(protocol)) {
+ protocols.add("e.HTTP_CNT_TOTAL > 0");
+ } else if (DNS.equals(protocol)) {
+ protocols.add("e.DNS_CNT_TOTAL > 0");
+ } else if (SSL.equals(protocol)||TLS.equals(protocol)) {
+ protocols.add("e.TLS_CNT_TOTAL > 0");
+ }
+ }
+ if (protocols.size() > 0) {
+ protocolsb.append(Joiner.on("").skipNulls().join(" and (", Joiner.on(" or ").skipNulls().join(protocols), ")"));
+ }
+ } else if ("UNIQ_CIP".equals(r.getFieldKey())) {
+ distCiptsb.append(" and count(e.DIST_CIP) ").append(EnumUtils.getEnum(RangeEnum.class, StringUtil.upperCase(r.getType())).getSymbol()).append(r.getFieldValues().get(0));
+ }
+
+ }
+ }
+ }
+
+ StringBuffer aqlsb = new StringBuffer("for e in R_LOCATE_FQDN2IP ");
+ aqlsb.append(ObjectUtils.isEmpty(likeFilter) ? "" : likeFilter);
+ aqlsb.append(" filter 1==1 ");
+ aqlsb.append(intervalsb);
+ aqlsb.append(distCiptsb);
+ aqlsb.append(protocolsb);
+
+ int pageRow = 0;
+ int offSet = 0;
+ int pageSize = 0;
+ List<String> limitList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(limit);
+ if(limitList.size()<2){
+ pageSize= pageRow = Integer.valueOf(limitList.get(0));
+ } else {
+ pageRow = Integer.valueOf(limitList.get(0)) + Integer.valueOf(limitList.get(1));
+ offSet = Integer.valueOf(limitList.get(0));
+ pageSize = Integer.valueOf(limitList.get(1));
+ }
+
+ List<IpLearningPath.IplearningEdges> ipEdgesList = getDistinctList(aqlsb, pageRow, offSet, pageSize);
+
+ return parseResult(ipEdgesList);
+
+ }
+ //循环查询 ,目的为了数量达到limit , 结果数据是否为limit , 1.当查询数量小于limit停止 2.当结果数量=limit停止
+ private List<IpLearningPath.IplearningEdges> getDistinctList(StringBuffer aqlsb ,int pageRow,int offSet, int pageSize){
+ pageRow = pageRow + offSet + pageSize;//每次多查一点点,去重
+ StringBuffer sb = new StringBuffer(aqlsb);
+ sb.append(" limit ").append(pageRow);
+ sb.append(" return distinct e ");
+
+ Object result = baseQueryProvider.queryArango(sb.toString());
+ List ipEdgesList = new ObjectMapper().convertValue(result, new TypeReference<List<IpLearningPath.IplearningEdges>>() {
+ });
+ List<IpLearningPath.IplearningEdges> edgesList = (List<IpLearningPath.IplearningEdges>) ipEdgesList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(IpLearningPath.IplearningEdges::getTo))), ArrayList::new));
+ if(ipEdgesList.size()<pageRow || edgesList.size()>= pageSize+offSet){
+ if(offSet > edgesList.size()){
+ return new ArrayList<>();
+ } else {
+ if(offSet + pageSize > edgesList.size()){
+ return edgesList.subList(offSet, edgesList.size());
+ }
+ return edgesList.subList(offSet, offSet + pageSize);
+ }
+ }
+ return getDistinctList( aqlsb , pageRow, offSet, pageSize);
+ }
+ /**
+ * @return java.lang.Object
+ * @Author zhq
+ * @Description //TODO 返回需要的结果集
+ * @Date 2020\7\15 0015
+ * @Param [IpLearningPath]
+ **/
+ private Object parseResult(List<IpLearningPath.IplearningEdges> edgesList) {
+
+ List<Object> list = Lists.newArrayList();
+ if(!ObjectUtils.isEmpty(edgesList)){
+ for (IpLearningPath.IplearningEdges edges : edgesList) {
+ Map<String, Object> map = Maps.newHashMap();
+ List<String> protocolsList = Lists.newArrayList();
+ map.put("FQDN_NAME", CharMatcher.anyOf("FQDN/").trimLeadingFrom(edges.getFrom()));
+ map.put("IP", CharMatcher.anyOf("IP/").trimLeadingFrom(edges.getTo()));
+ map.put("FIRST_FOUND_TIME", DateUtils.convertTimestampToString(edges.getFirstFoundTime(), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ map.put("LAST_FOUND_TIME", DateUtils.convertTimestampToString(edges.getLastFoundTime(), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ //协议 按 TLS_CNT_TOTAL>0,SESSION_RECENT按 *_CNT_RECENT和,SESSION_TOTAL按 *_CNT_TOTAL和
+ if (edges.getHttpCntTotal() > 0) {
+ protocolsList.add(HTTP);
+ }
+ if (edges.getTlsCntTotal() > 0) {
+ protocolsList.add(SSL);
+ }
+ if (edges.getDnsCntTotal() > 0) {
+ protocolsList.add(DNS);
+ }
+ map.put("PROTOCOL", Joiner.on(",").join(protocolsList));
+ map.put("SESSION_TOTAL", edges.getHttpCntTotal() + edges.getTlsCntTotal() + edges.getDnsCntTotal());
+ map.put("SESSION_RECENT", Stream.of(edges.getHttpCntRecent(), edges.getTlsCntRecent(), edges.getDnsCntRecent()).flatMap(Collection::stream).mapToLong(x -> x).sum());
+
+ //UNIQ_CIP_RECENT与UNIQ_CIP相同
+ map.put("UNIQ_CIP", edges.getDistCip()==null?0:edges.getDistCip().size());
+ map.put("UNIQ_CIP_RECENT", edges.getDistCip()==null?0:edges.getDistCip().size());
+
+ list.add(map);
+ }
+ }
+
+ return list;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java
new file mode 100644
index 0000000..765ff56
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/IpProviderImpl.java
@@ -0,0 +1,80 @@
+package com.mesalab.knowledge.strategy;
+
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.mesalab.knowledge.entity.DSLObject;
+import com.mesalab.knowledge.entity.Parameters;
+import com.mesalab.knowledge.entity.Sort;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @description: for ip search
+ * @author: zhq
+ * @create: 2020-07-17
+ **/
+@Component("IP_VIEW")
+public class IpProviderImpl implements QueryProvider {
+
+ @Value("${arango.maxrows}")
+ private String limit;//查询最大条数
+ @Autowired
+ BaseQueryProvider baseQueryProvider;
+
+ @Override
+ public Object query(DSLObject.DSLQuery dslQeruy) {
+ Parameters parameters = dslQeruy.getParameters();
+ StringBuffer aqlsb = new StringBuffer();
+ String sortAql = "";
+ //需要条件 时间,limit
+ if(!ObjectUtils.isEmpty(parameters)){
+ limit = ObjectUtils.isEmpty(parameters.getLimit()) ? limit : parameters.getLimit();
+ List<Sort> sorts = parameters.getSort();
+
+ if (Objects.nonNull(sorts)) {
+ sortAql = sorts.stream().map(x -> {
+ if ("BYTES_TOTAL".equals(x.getFieldKey())) {
+ return "(doc.CLIENT_BYTES_SUM+doc.SERVER_BYTES_SUM) " + x.getType();
+ } else if ("LAST_FOUND_TIME".equals(x.getFieldKey())) {
+ return "doc.LAST_FOUND_TIME " + x.getType();
+ }
+ return null;
+ }).filter(x -> StringUtil.isNotBlank(x)).collect(Collectors.joining(",", " ", " "));
+ }
+ }
+ aqlsb.append("for doc in IP ");
+ aqlsb.append(" filter doc.COMMON_LINK_INFO != '' ");
+ aqlsb.append(StringUtil.isBlank(sortAql) ? "" : " sort " + sortAql);
+ aqlsb.append(" limit ").append(limit);
+ aqlsb.append(" return distinct doc");
+ //1.查询
+ Object result = baseQueryProvider.queryArango(aqlsb.toString());
+ //2.解析结果
+ List<Map> resultList = new ObjectMapper().convertValue(result, new TypeReference<List<Map>>() {
+ });
+ return parseResult(resultList);
+
+ }
+
+ private Object parseResult(List<Map> resultList) {
+ for (Map ip : resultList) {
+ ip.remove("_key");
+ ip.remove("_id");
+ ip.remove("_rev");
+ ip.put("FIRST_FOUND_TIME", DateUtils.convertTimestampToString(Long.valueOf(String.valueOf(ip.get("FIRST_FOUND_TIME"))), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ ip.put("LAST_FOUND_TIME", DateUtils.convertTimestampToString(Long.valueOf(String.valueOf(ip.get("LAST_FOUND_TIME"))), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ ip.put("BYTES_TOTAL", Long.valueOf(String.valueOf(ip.get("CLIENT_BYTES_SUM"))) + Long.valueOf(String.valueOf(ip.get("SERVER_BYTES_SUM"))));
+ }
+ return resultList;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/QueryProvider.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/QueryProvider.java
new file mode 100644
index 0000000..902da66
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/QueryProvider.java
@@ -0,0 +1,12 @@
+package com.mesalab.knowledge.strategy;
+
+import com.mesalab.knowledge.entity.DSLObject;
+
+/**
+ * @Description: 提供查询结果
+ */
+public interface QueryProvider {
+
+ public Object query(DSLObject.DSLQuery dslQeruy);
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java
new file mode 100644
index 0000000..6370a2b
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/knowledge/strategy/SubscriberIdProviderImpl.java
@@ -0,0 +1,84 @@
+package com.mesalab.knowledge.strategy;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.CharMatcher;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mesalab.knowledge.entity.DSLObject;
+import com.mesalab.knowledge.entity.Match;
+import com.mesalab.knowledge.entity.Parameters;
+import com.zdjizhi.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @description:
+ * @author: zhq
+ * @create: 2020-07-17
+ **/
+@Component("SUBSCRIBER_ID_VIEW")
+public class SubscriberIdProviderImpl implements QueryProvider {
+
+ @Value("${arango.maxrows}")
+ private String limit;//查询最大条数
+
+ @Autowired
+ BaseQueryProvider baseQueryProvider;
+
+ @Override
+ public Object query(DSLObject.DSLQuery dslQeruy) {
+
+ //1.构建查询语句 match like
+ StringBuffer likeFilter = new StringBuffer();
+ Parameters parameters = dslQeruy.getParameters();
+ if(!ObjectUtils.isEmpty(parameters)){
+ likeFilter.append(Match.like(parameters.getMatch(), (m) -> m != null && "SUBSCRIBER_ID".equals(m.getFieldKey()) && !ObjectUtils.isEmpty(m.getFieldValues())));
+ limit = ObjectUtils.isEmpty(parameters.getLimit()) ? limit : parameters.getLimit();
+ }
+
+ StringBuffer aqlsb = new StringBuffer("for doc in SUBSCRIBER ");
+ aqlsb.append(ObjectUtils.isEmpty(likeFilter) ? "" : likeFilter);
+ aqlsb.append(" let maxTime = (let times = (for v,e,p in 1 outbound doc._id graph 'SUBSCRIBER_IP_GRAPH' return e.LAST_FOUND_TIME) return max(times)) ");
+ aqlsb.append(" for v,e,p in 1..1 outbound doc._id graph 'SUBSCRIBER_IP_GRAPH' ");
+ aqlsb.append(" filter e.LAST_FOUND_TIME == maxTime[0] ");
+ aqlsb.append(" limit ").append(limit);
+ aqlsb.append(" return distinct p ");
+
+ //1.查询
+ Object result = baseQueryProvider.queryArango(aqlsb.toString());
+ //2.解析结果
+ List<Map> resultList = new ObjectMapper().convertValue(result, new TypeReference<List<Map>>() {
+ });
+ return parseResult(resultList);
+
+ }
+
+ private Object parseResult(List<Map> resultList) {
+ List<Object> list = Lists.newArrayList();
+ for (Map<String, List<Map>> map : resultList) {
+ Map<String, Object> newMap = Maps.newHashMap();
+ Map subIdVertice = map.get("vertices").get(0);
+ if (Objects.isNull(subIdVertice)) {
+ continue;
+ }
+ newMap.put("SUBSCRIBER_ID", subIdVertice.get("_key"));
+ newMap.put("FIRST_FOUND_TIME", DateUtils.convertTimestampToString(Long.valueOf(String.valueOf(subIdVertice.get("FIRST_FOUND_TIME"))), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ newMap.put("LAST_FOUND_TIME", DateUtils.convertTimestampToString(Long.valueOf(String.valueOf(subIdVertice.get("LAST_FOUND_TIME"))), DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ Map ipEdges = map.get("edges").get(0);
+ if (Objects.isNull(ipEdges)||Objects.isNull(ipEdges.get("_to"))) {
+ newMap.put("IP", "");
+ } else {
+ newMap.put("IP", CharMatcher.anyOf("IP/").trimLeadingFrom(String.valueOf(ipEdges.get("_to"))));
+ }
+ list.add(newMap);
+ }
+ return list;
+ }
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/controller/NetworkMonitorController.java b/galaxy-query-engine/src/main/java/com/mesalab/network/controller/NetworkMonitorController.java
new file mode 100644
index 0000000..2bd44fd
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/controller/NetworkMonitorController.java
@@ -0,0 +1,44 @@
+package com.mesalab.network.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.network.dsl.DSLObject;
+import com.mesalab.network.dsl.DSLValidate;
+import com.mesalab.network.service.NetworkMonitorService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * @author wangwei
+ * @version 1.0
+ * @date 2020/6/30 10:38 上午
+ */
+@Slf4j
+@RestController
+@RequestMapping(value = "/")
+public class NetworkMonitorController {
+
+ @Autowired
+ private DSLValidate dslValidate;
+ @Autowired
+ private NetworkMonitorService networkMonitorService;
+ private static final String PROTOCOL = "protocol";
+
+ @PostMapping(value = "/traffic/v1/", produces = "application/json")
+ public BaseResult trafficDistribution(HttpServletRequest request, @Validated @RequestBody DSLObject dslObject) {
+ log.info("流量分布接口, 参数: queryString is {},params is {}", request.getQueryString(), dslObject);
+ dslValidate.executeValidate(dslObject);
+ if (PROTOCOL.equalsIgnoreCase(request.getQueryString())) {
+ return networkMonitorService.getTrafficDistributedInfo(dslObject);
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Support protocol only", null);
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLObject.java b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLObject.java
new file mode 100644
index 0000000..4bd98e4
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLObject.java
@@ -0,0 +1,40 @@
+package com.mesalab.network.dsl;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Date: 2020-09-18 09:48
+ * @Author : wangwei
+ * @ClassName : DSLObject
+ * @Description :
+ */
+@Data
+public class DSLObject implements Serializable {
+
+ private String clientId;
+ private QueryBean query;
+
+ @Data
+ public static class QueryBean {
+ private String queryType;
+ private String dataSource;
+ private Parameters parameters;
+
+ @Data
+ public static class Parameters {
+ private String granularity;
+ private List<MatchBean> match;
+ private List<String> intervals;
+
+ @Data
+ public static class MatchBean {
+ private String type;
+ private String fieldKey;
+ private List<String> fieldValues;
+ }
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLValidate.java b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLValidate.java
new file mode 100644
index 0000000..3f32eba
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/DSLValidate.java
@@ -0,0 +1,132 @@
+package com.mesalab.network.dsl;
+
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.knowledge.enums.MatchEnum;
+import com.zdjizhi.utils.StringUtil;
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.http.HttpStatus;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * @Date: 2020-09-17 18:10
+ * @Author : wangwei
+ * @ClassName : DSLValidate
+ * @Description : DSL格式校验
+ */
+@Component
+public class DSLValidate {
+
+ public static Pattern periodOfPT = Pattern.compile("PT(\\d+)[SMH]", Pattern.CASE_INSENSITIVE);
+ public static Pattern periodOfP = Pattern.compile("P(\\d+)[DWMY]", Pattern.CASE_INSENSITIVE);
+ public static Pattern strFormatDateTime = Pattern.compile("\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}", Pattern.CASE_INSENSITIVE);
+
+
+ public void executeValidate(DSLObject dslObject) throws BusinessException {
+ if (StringUtil.isEmpty(dslObject)) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(),
+ "DSLObject is invalid");
+ }
+ if (StringUtil.isEmpty(dslObject.getQuery())) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(),
+ "DSLObject.query is invalid");
+ }
+ DSLObject.QueryBean.Parameters parameters = dslObject.getQuery().getParameters();
+ if (StringUtil.isEmpty(parameters)) {
+ return;
+ }
+ if (!isValidGranularity(parameters.getGranularity())) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(),
+ "query.Granularity value is invalid");
+ }
+ if (!isValidMatch(parameters.getMatch())) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(),
+ "query.Match type is invalid");
+ }
+ if (!isValidIntervals(parameters.getIntervals())) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(),
+ "query.Intervals is invalid");
+ }
+ }
+
+ /**
+ * 时间粒度校验, 遵循ISO8601 durations 定义
+ *
+ * @param granularity
+ * @return
+ */
+ private boolean isValidGranularity(String granularity) {
+ if (StringUtil.isBlank(granularity)) {
+ return true;
+ }
+ if (periodOfP.matcher(granularity).find() || periodOfPT.matcher(granularity).find()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 校验match:
+ * 1.是否属于{@link MatchEnum}限定类型
+ * 2.不能以*开始、或$结尾
+ *
+ * @param matchList
+ * @return
+ */
+ private boolean isValidMatch(List<DSLObject.QueryBean.Parameters.MatchBean> matchList) {
+ if (CollectionUtils.isEmpty(matchList)) {
+ return true;
+ }
+ for (DSLObject.QueryBean.Parameters.MatchBean matchBean : matchList) {
+ Validate.isTrue(EnumUtils.isValidEnum(MatchEnum.class, StringUtil.upperCase(matchBean.getType())), "match type is illegal");
+ for (String fieldValue : matchBean.getFieldValues()) {
+ if (fieldValue.startsWith("*") || fieldValue.endsWith("$")) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Match fieldValues cannot startWith '*' or endWith '$'");
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 校验Interval:
+ * 1.目前只支持between类型: ["2020-01-01 00:00:00/2020-01-02 00:00:00"]
+ * 2.时间区间必须是 开始时间 < 结束时间
+ *
+ * @param intervals
+ */
+ private boolean isValidIntervals(List<String> intervals) {
+ if (CollectionUtils.isEmpty(intervals)) {
+ return true;
+ }
+ if (intervals.size() != 1) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Intervals param error");
+ }
+ String[] split = intervals.get(0).split("/");
+ if (split.length != 2) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Intervals param error");
+ }
+ for (String dateTimeStr : split) {
+ if (!strFormatDateTime.matcher(dateTimeStr).find()) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Time format should be: yyyy-MM-dd HH:mm:ss");
+ }
+ }
+ try {
+ DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
+ if (dateTimeFormatter.parseMillis(split[1]) < dateTimeFormatter.parseMillis(split[0])) {
+ throw new RuntimeException("Intervals value should be [start, end]");
+ }
+ } catch (Exception e) {
+ throw new BusinessException(HttpStatus.SC_BAD_REQUEST, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), e.getMessage());
+ }
+ return true;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/Parameter.java b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/Parameter.java
new file mode 100644
index 0000000..30a1a87
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/dsl/Parameter.java
@@ -0,0 +1,10 @@
+package com.mesalab.network.dsl;
+
+/**
+ * @author wangwei
+ * @description:
+ * @date 2020/9/18 6:31 下午
+ */
+public class Parameter {
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/service/NetworkMonitorService.java b/galaxy-query-engine/src/main/java/com/mesalab/network/service/NetworkMonitorService.java
new file mode 100644
index 0000000..6455a4d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/service/NetworkMonitorService.java
@@ -0,0 +1,17 @@
+package com.mesalab.network.service;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.network.dsl.DSLObject;
+
+/**
+ * @author wangwei
+ * @version 1.0
+ * @date 2020/6/30 4:20 下午
+ */
+
+
+public interface NetworkMonitorService {
+
+ BaseResult getTrafficDistributedInfo(DSLObject dslObject);
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/network/service/impl/NetworkMonitorServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/network/service/impl/NetworkMonitorServiceImpl.java
new file mode 100644
index 0000000..1792837
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/network/service/impl/NetworkMonitorServiceImpl.java
@@ -0,0 +1,402 @@
+package com.mesalab.network.service.impl;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.common.utils.TreeUtils;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.knowledge.enums.MatchEnum;
+import com.mesalab.network.dsl.DSLObject;
+import com.mesalab.network.service.NetworkMonitorService;
+import com.mesalab.qgw.model.protocol.ProtocolTree;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Nullable;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author wangwei
+ * @version 1.0
+ * @date 2020/6/30 4:24 下午
+ */
+@Slf4j
+@Service("networkMonitorService")
+public class NetworkMonitorServiceImpl implements NetworkMonitorService {
+ @Autowired
+ HttpClientService httpClientService;
+ @Autowired
+ HttpConfig httpConfig;
+ @Value("${server.port}")
+ private int serverPort;
+ private static String hostAddress;
+
+ private static final String PROTOCOL_NODE = "Protocols/";
+
+ static {
+ try {
+ hostAddress = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ log.error("get LocalHost error: ", e);
+ }
+ }
+
+ @Override
+ public BaseResult getTrafficDistributedInfo(DSLObject dslObject) {
+ BaseResult baseResult;
+ String sql;
+ if (QueryType.PROTOCOL_TREE_SUMMARY.getValue().equalsIgnoreCase(dslObject.getQuery().getQueryType())) {
+ sql = generateProtocolTreeSql(dslObject.getQuery());
+ baseResult = getResultProtocolTree(sql);
+ } else if (QueryType.PROTOCOL_DATA_RATE_SUMMARY.getValue().equalsIgnoreCase(dslObject.getQuery().getQueryType())) {
+ sql = generateProtocolDataRateSql(dslObject.getQuery());
+ baseResult = getProtocolDataRateSummary(sql);
+ } else if (QueryType.NETWORK_OVERVIEW_SUMMARY.getValue().equalsIgnoreCase(dslObject.getQuery().getQueryType())) {
+ sql = generateOverviewSummarySql(dslObject.getQuery());
+ Map<String, String> dataRateResult = executeQuery(sql);
+ String statSql = generateStatSql(dslObject.getQuery());
+ Map<String, String> statResult = executeQuery(statSql);
+ baseResult = buildNetworkOverviewResult(dataRateResult, statResult);
+ } else {
+ baseResult = BaseResultGenerator.failure(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "No match queryType");
+ }
+ if (!baseResult.isSuccess()) {
+ throw new BusinessException(baseResult.getStatus(), baseResult.getCode(), baseResult.getMessage(), null);
+ }
+ return baseResult;
+ }
+
+ private BaseResult buildNetworkOverviewResult(Map<String, String> dataRateResult, Map<String, String> currentSessionResult) {
+ BaseResult baseResult;
+ if (String.valueOf(HttpStatus.SC_OK).equals(currentSessionResult.get("status"))
+ && String.valueOf(HttpStatus.SC_OK).equals(dataRateResult.get("status"))) {
+ Map statDataResult = (Map) JsonMapper.fromJsonString(currentSessionResult.get("result"), Map.class);
+ List<Map> statData = (List<Map>) statDataResult.get("data");
+ Map summaryDataResult = (Map) JsonMapper.fromJsonString(dataRateResult.get("result"), Map.class);
+ List<Map> summaryData = (List<Map>) summaryDataResult.get("data");
+
+ Map<String, Object> data = new HashMap<>(16);
+ if (!statData.isEmpty()) {
+ data.putAll(statData.get(0));
+ }
+ if (statData.size() >= 2) {
+ data.put("current_sessions", statData.get(1).get("total_bytes"));
+ }
+ if (!summaryData.isEmpty()) {
+ data.putAll(summaryData.get(0));
+ }
+ long uniqClientIp = Long.parseLong(String.valueOf(data.get("uniq_client_ip") == null ? 0 : data.get("uniq_client_ip")));
+ long totalSessions = Long.parseLong(String.valueOf(data.get("total_sessions") == null ? 0 : data.get("total_sessions")));
+ long summaryTotalSessions = Long.parseLong(String.valueOf(data.get("summarySessions") == null ? 0 : data.get("summarySessions")));
+ long summaryTotalBytes = Long.parseLong(String.valueOf(data.get("summaryTotalBytes") == null ? 0 : data.get("summaryTotalBytes")));
+ long summaryTotalPackets = Long.parseLong(String.valueOf(data.get("summaryTotalPackets") == null ? 0 : data.get("summaryTotalPackets")));
+ long currentSessions = Long.parseLong(String.valueOf(data.get("current_sessions") == null ? 0 : data.get("current_sessions")));
+ long dataRate = Long.parseLong(String.valueOf(data.get("data_rate") == null ? 0 : data.get("data_rate")));
+ long totalBytes = Long.parseLong(String.valueOf(data.get("total_bytes") == null ? 0 : data.get("total_bytes")));
+ long totalUncategorizedBytes = Long.parseLong(String.valueOf(data.get("total_uncategorized_bytes") == null ? 0 : data.get("total_uncategorized_bytes")));
+ double totalUncategorizedPercent = summaryTotalBytes == 0 ? 0 : totalUncategorizedBytes * 1.0 / summaryTotalBytes;
+ long oneSidedConnections = Long.parseLong(String.valueOf(data.get("one_sided_connections") == null ? 0 : data.get("one_sided_connections")));
+ double oneSidedPercent = summaryTotalSessions == 0 ? 0 : oneSidedConnections * 1.0 / summaryTotalSessions;
+ long sequenceGapLossBytes = Long.parseLong(String.valueOf(data.get("sequence_gap_loss_bytes") == null ? 0 : data.get("sequence_gap_loss_bytes")));
+ double sequenceGapLossBytesPercent = summaryTotalBytes == 0 ? 0 : sequenceGapLossBytes * 1.0 / summaryTotalBytes;
+ long fragmentationPackets = Long.parseLong(String.valueOf(data.get("fragmentation_packets") == null ? 0 : data.get("fragmentation_packets")));
+ double fragmentationPacketsPercent = summaryTotalPackets == 0 ? 0 : fragmentationPackets * 1.0 / summaryTotalPackets;
+
+ List result = new ArrayList<>();
+ Map resultMap = new LinkedHashMap<>();
+ resultMap.put("uniq_client_ip", uniqClientIp);
+ resultMap.put("total_sessions", totalSessions);
+ resultMap.put("current_sessions", currentSessions);
+ resultMap.put("data_rate", dataRate);
+ resultMap.put("total_bytes", totalBytes);
+ resultMap.put("total_uncategorized_bytes", totalUncategorizedBytes);
+ resultMap.put("total_uncategorized_percent", Double.parseDouble(String.format("%.4f", totalUncategorizedPercent)));
+ resultMap.put("one_sided_connections", oneSidedConnections);
+ resultMap.put("one_sided_percent", Double.parseDouble(String.format("%.4f", oneSidedPercent)));
+ resultMap.put("sequence_gap_loss_bytes", sequenceGapLossBytes);
+ resultMap.put("sequence_gap_loss_percent", Double.parseDouble(String.format("%.4f", sequenceGapLossBytesPercent)));
+ resultMap.put("fragmentation_packets", fragmentationPackets);
+ resultMap.put("fragmentation_percent", Double.parseDouble(String.format("%.4f", fragmentationPacketsPercent)));
+ result.add(resultMap);
+
+ Map statistics = (Map) summaryDataResult.get("statistics");
+ Map statStatistics = (Map) statDataResult.get("statistics");
+ for (Object key : statistics.keySet()) {
+ if ("result_rows".equals(key.toString())) {
+ continue;
+ }
+ statistics.put(key, Long.parseLong(statistics.get(key).toString()) + Long.parseLong(statStatistics.get(key).toString()));
+ }
+
+ baseResult = BaseResultGenerator.success("ok", result, statistics);
+ } else {
+ baseResult = BaseResultGenerator.error("dataRate result: " + dataRateResult.toString() + ";\n currentSession result is: " + currentSessionResult);
+ }
+ return baseResult;
+ }
+
+ private BaseResult getProtocolDataRateSummary(String sql) {
+ BaseResult baseResult;
+ Map<String, String> result = executeQuery(sql);
+ if (String.valueOf(HttpStatus.SC_OK).equals(result.get("status"))) {
+ Map resultMap = (Map) JsonMapper.fromJsonString(result.get("result"), Map.class);
+ List<Map> data = (List<Map>) resultMap.get("data");
+ data.forEach(o -> {
+ String[] protocolIds = String.valueOf(o.get("type")).split("/");
+ String protocolId = protocolIds[protocolIds.length - 1];
+ o.put("type", protocolId);
+ });
+ baseResult = BaseResultGenerator.success("ok", data, (Map) resultMap.get("statistics"));
+ } else {
+ baseResult = BaseResultGenerator.error(result.get("result"));
+ }
+ return baseResult;
+ }
+
+ private BaseResult getResultProtocolTree(String sql) {
+ BaseResult baseResult;
+ Map<String, String> result = executeQuery(sql);
+ if (String.valueOf(HttpStatus.SC_OK).equals(result.get("status"))) {
+ Map resultMap = (Map) JsonMapper.fromJsonString(result.get("result"), Map.class);
+ List<ProtocolTree> listProtocol = getListProtocol(getProtocolTrees((List<Map>) resultMap.get("data")));
+ baseResult = BaseResultGenerator.success("ok", listProtocol, (Map) resultMap.get("statistics"));
+ } else {
+ baseResult = BaseResultGenerator.error(result.get("result"));
+ }
+ return baseResult;
+ }
+
+ private String generateStatSql(DSLObject.QueryBean queryParam) {
+ String whereOfTime = getWhereOfTime(queryParam.getParameters());
+ String whereOfExactly = getWhereOfExactly(queryParam.getParameters());
+ whereOfExactly = StringUtil.isBlank(whereOfExactly) ? "" : "AND " + whereOfExactly;
+ String[] intervals = getIntervals(queryParam.getParameters().getIntervals());
+ return String.format("(SELECT SUM(c2s_byte_num + s2c_byte_num) as total_bytes, SUM(sessions) as total_sessions, (SUM(c2s_byte_num + s2c_byte_num) * 8)/((TIMESTAMP_TO_MILLIS(TIMESTAMP '%s')-TIMESTAMP_TO_MILLIS(TIMESTAMP '%s'))/1000) AS data_rate " +
+ "FROM traffic_protocol_stat_log " +
+ "WHERE %s %s" +
+ "AND LENGTH(protocol_id) = LENGTH(REPLACE(protocol_id,'/','')) LIMIT 1) " +
+ "UNION ALL " +
+ "( SELECT SUM(sessions), 0, 0 " +
+ "FROM traffic_protocol_stat_log " +
+ "WHERE %s %s" +
+ "AND LENGTH(protocol_id) = LENGTH(REPLACE(protocol_id,'/','')) GROUP BY __time ORDER BY __time DESC LIMIT 1 ) ",
+ intervals[1], intervals[0], whereOfTime, whereOfExactly,
+ whereOfTime, whereOfExactly);
+ }
+
+ private String generateProtocolDataRateSql(DSLObject.QueryBean queryParam) {
+ String whereOfTime = getWhereOfTime(queryParam.getParameters());
+ String whereOfExactly = getWhereOfExactly(queryParam.getParameters());
+ whereOfExactly = StringUtil.isBlank(whereOfExactly) ? "" : "AND " + whereOfExactly;
+ String protocolStr = null;
+ List<DSLObject.QueryBean.Parameters.MatchBean> match = queryParam.getParameters().getMatch();
+ for (DSLObject.QueryBean.Parameters.MatchBean item : match) {
+ if (MatchEnum.PREFIX.getType().equals(item.getType())) {
+ String[] split = item.getFieldValues().get(0).split(",");
+ protocolStr = split[0].replaceFirst(PROTOCOL_NODE, "");
+ }
+ }
+ return String.format("(" +
+ "SELECT TIME_FORMAT(MILLIS_TO_TIMESTAMP( 1000 * TIME_FLOOR_WITH_FILL(TIMESTAMP_TO_MILLIS(__time)/1000, '%s', 'zero')), 'yyyy-MM-dd HH:mm:ss') as stat_time, protocol_id as type, sum(c2s_byte_num + s2c_byte_num) as bytes " +
+ "from %s " +
+ "where %s %s and protocol_id = '%s' " +
+ "group by TIME_FORMAT(MILLIS_TO_TIMESTAMP( 1000 * TIME_FLOOR_WITH_FILL(TIMESTAMP_TO_MILLIS(__time)/1000, '%s', 'zero')), 'yyyy-MM-dd HH:mm:ss'), protocol_id " +
+ "order by stat_time asc" +
+ ") " +
+ "union all " +
+ "(" +
+ "SELECT TIME_FORMAT(MILLIS_TO_TIMESTAMP( 1000 * TIME_FLOOR_WITH_FILL(TIMESTAMP_TO_MILLIS(__time)/1000, '%s', 'zero')), 'yyyy-MM-dd HH:mm:ss') as stat_time, protocol_id as type, sum(c2s_byte_num + s2c_byte_num) as bytes " +
+ "from %s " +
+ "where %s %s and protocol_id like CONCAT('%s','/%s') and LENGTH(protocol_id) = LENGTH(REPLACE(protocol_id,'/','')) + 1 + %s " +
+ "group by TIME_FORMAT(MILLIS_TO_TIMESTAMP( 1000 * TIME_FLOOR_WITH_FILL(TIMESTAMP_TO_MILLIS(__time)/1000, '%s', 'zero')), 'yyyy-MM-dd HH:mm:ss'), protocol_id " +
+ "order by stat_time asc) ",
+ queryParam.getParameters().getGranularity(), queryParam.getDataSource(), whereOfTime, whereOfExactly, protocolStr, queryParam.getParameters().getGranularity(),
+ queryParam.getParameters().getGranularity(), queryParam.getDataSource(), whereOfTime, whereOfExactly, protocolStr, "%",
+ protocolStr.length() - protocolStr.replaceAll("/", "").length(), queryParam.getParameters().getGranularity());
+
+ }
+
+ private String generateOverviewSummarySql(DSLObject.QueryBean queryParam) {
+ String whereOfTime = getWhereOfTime(queryParam.getParameters());
+ String whereOfExactly = getWhereOfExactly(queryParam.getParameters());
+
+ return String.format("SELECT APPROX_COUNT_DISTINCT_DS_HLL(ip_object) AS uniq_client_ip, " +
+ "SUM(one_sided_connections) AS one_sided_connections, " +
+ "SUM(uncategorized_bytes) AS total_uncategorized_bytes, " +
+ "SUM(fragmentation_packets) AS fragmentation_packets, " +
+ "SUM(sequence_gap_loss) AS sequence_gap_loss_bytes, " +
+ "SUM(s2c_byte_num+c2s_byte_num) AS summaryTotalBytes, " +
+ "SUM(s2c_pkt_num+c2s_pkt_num) AS summaryTotalPackets, " +
+ "SUM(sessions) AS summarySessions " +
+ "FROM %s " +
+ "WHERE %s" +
+ " %s LIMIT 1 ",
+ queryParam.getDataSource(), whereOfTime, StringUtil.isBlank(whereOfExactly) ? "" : "AND " + whereOfExactly);
+ }
+
+ private String getWhereOfTime(DSLObject.QueryBean.Parameters parameters) {
+ if (CollectionUtils.isEmpty(parameters.getIntervals())) {
+ return StringUtil.EMPTY;
+ }
+ StringBuffer whereOfTime = new StringBuffer();
+ String[] intervals = getIntervals(parameters.getIntervals());
+ whereOfTime.append("__time >= TIMESTAMP '").append(intervals[0]).append("' AND __time < TIMESTAMP '").append(intervals[1]).append("'");
+ return whereOfTime.toString();
+ }
+
+ private String[] getIntervals(List<String> intervals) {
+ return intervals.get(0).split("/");
+ }
+
+ private String getWhereOfExactly(DSLObject.QueryBean.Parameters parameters) {
+ if (CollectionUtils.isEmpty(parameters.getMatch())) {
+ return StringUtil.EMPTY;
+ }
+ StringBuffer whereOfExactly = new StringBuffer();
+ List<DSLObject.QueryBean.Parameters.MatchBean> match = parameters.getMatch();
+ for (DSLObject.QueryBean.Parameters.MatchBean item : match) {
+ if (MatchEnum.EXACTLY.getType().equals(item.getType()) && !CollectionUtils.isEmpty(item.getFieldValues())) {
+ whereOfExactly.append(item.getFieldKey()).append(" IN ('").append(String.join("','", item.getFieldValues())).append("')");
+ }
+ }
+ return whereOfExactly.toString();
+ }
+
+ private String generateProtocolTreeSql(DSLObject.QueryBean queryParam) {
+ String whereOfTime = getWhereOfTime(queryParam.getParameters());
+ String whereOfExactly = getWhereOfExactly(queryParam.getParameters());
+ whereOfExactly = StringUtil.isBlank(whereOfExactly) ? "" : "AND " + whereOfExactly;
+ return String.format("SELECT protocol_id, SUM(sessions) as sessions,SUM(c2s_byte_num) as c2s_byte_num, SUM(c2s_pkt_num) as c2s_pkt_num, SUM(s2c_byte_num) as s2c_byte_num, SUM(s2c_pkt_num) as s2c_pkt_num " +
+ "FROM %s " +
+ "WHERE %s %s" +
+ "GROUP BY protocol_id ",
+ queryParam.getDataSource(), whereOfTime, whereOfExactly);
+ }
+
+ private List<ProtocolTree> getProtocolTrees(List<Map> data) {
+ Iterable<ProtocolTree> resultConcat = Iterables.concat(new ArrayList<>());
+ for (Map datum : data) {
+ String s = JsonMapper.toJsonString(datum);
+ List<ProtocolTree> nodes = parserRawData(s);
+ resultConcat = Iterables.concat(resultConcat, nodes);
+ }
+ List<ProtocolTree> listNodes = Lists.newArrayList(resultConcat);
+ ProtocolTree root = new ProtocolTree("Protocols", "Protocols", null);
+ List<ProtocolTree> roots = listNodes.stream().filter(o -> StringUtil.isBlank(o.getParentId())).collect(Collectors.toList());
+ roots.forEach(item -> {
+ root.setSentBytes(root.getSentBytes() + item.getSentBytes());
+ root.setReceivedBytes(root.getReceivedBytes() + item.getReceivedBytes());
+ });
+
+ listNodes.forEach(item -> {
+ item.setId(PROTOCOL_NODE + item.getId());
+ });
+
+ listNodes.add(root);
+ return listNodes;
+ }
+
+ private Map<String, String> executeQuery(String sql) {
+ try {
+ sql = URLEncoder.encode(sql, "utf-8").replaceAll("\\+", "%20");
+ } catch (UnsupportedEncodingException e) {
+ hostAddress = "127.0.0.1";
+ log.error("sql Encode error: ", e);
+ }
+ String url = "http://" + hostAddress + ":" + serverPort + "/?query=";
+ int socketTimeOut = httpConfig.getServerResponseTimeOut();
+ return httpClientService.httpGet(url + sql, socketTimeOut);
+ }
+
+
+ private List<ProtocolTree> parserRawData(String jsonString) {
+ List<ProtocolTree> lists = Lists.newArrayList();
+ Map<String, Object> results = (Map<String, Object>) JsonMapper.fromJsonString(jsonString, Map.class);
+ long sessions = Long.parseLong(results.get("sessions").toString());
+ long sentBytes = Long.parseLong(results.get("c2s_byte_num").toString());
+ long receivedBytes = Long.parseLong(results.get("s2c_byte_num").toString());
+ long sentPackets = Long.parseLong(results.get("c2s_pkt_num").toString());
+ long receivedPackets = Long.parseLong(results.get("s2c_pkt_num").toString());
+ String protocolId = results.get("protocol_id").toString();
+ List<String> protocolList = Lists.newArrayList(protocolId.split("/"));
+ ProtocolTree protocolTree = new ProtocolTree(protocolId, protocolList.size() <= 0 ? null : protocolList.get(protocolList.size() - 1), null);
+ protocolTree.setSentBytes(sentBytes);
+ protocolTree.setReceivedBytes(receivedBytes);
+ protocolTree.getMetrics().put("sentPackets", sentPackets);
+ protocolTree.getMetrics().put("receivedPackets", receivedPackets);
+ protocolTree.getMetrics().put("sessions", sessions);
+ lists.add(protocolTree);
+ return lists;
+ }
+
+ private List<ProtocolTree> getListProtocol(List<ProtocolTree> listNodes) {
+ Map<String, List<ProtocolTree>> resultMap = listNodes.stream().collect(Collectors.groupingBy(ProtocolTree::getId));
+ Map<String, Object> mergeResultMap =
+ Maps.transformValues(resultMap, new com.google.common.base.Function<List<ProtocolTree>, Object>() {
+ @Nullable
+ @Override
+ public Object apply(@Nullable List<ProtocolTree> input) {
+ if (StringUtil.isEmpty(input)) {
+ return null;
+ }
+ if (input.size() == 1) {
+ return input.get(0);
+ }
+ ProtocolTree firstProtocolTree = input.get(0);
+ ProtocolTree mergeProtocolTree = new ProtocolTree(firstProtocolTree.getId(), firstProtocolTree.getName(),
+ firstProtocolTree.getParentId(), 0, 0);
+ mergeProtocolTree.setMetrics(Maps.newLinkedHashMap());
+
+ for (ProtocolTree protocolTree : input) {
+ mergeProtocolTree.setSentBytes(mergeProtocolTree.getSentBytes() + protocolTree.getSentBytes());
+ mergeProtocolTree.setReceivedBytes(mergeProtocolTree.getReceivedBytes() + protocolTree.getReceivedBytes());
+ for (String key : protocolTree.getMetrics().keySet()) {
+ if (StringUtil.isEmpty(mergeProtocolTree.getMetrics().get(key))) {
+ mergeProtocolTree.getMetrics().put(key, protocolTree.getMetrics().get(key));
+ } else {
+ long sumValue = Long.parseLong(mergeProtocolTree.getMetrics().get(key).toString())
+ + Long.parseLong(protocolTree.getMetrics().get(key).toString());
+ mergeProtocolTree.getMetrics().put(key, sumValue);
+ }
+ }
+
+ }
+
+ return mergeProtocolTree;
+ }
+ });
+ List<ProtocolTree> mergeNodes = new ArrayList(mergeResultMap.values());
+ return TreeUtils.mergeTree(mergeNodes, ProtocolTree::getId, ProtocolTree::getParentId, ProtocolTree::setChildrens);
+ }
+
+ enum QueryType {
+
+ PROTOCOL_TREE_SUMMARY("protocolTreeSummary"), PROTOCOL_DATA_RATE_SUMMARY("protocolDataRateSummary"), NETWORK_OVERVIEW_SUMMARY("networkOverviewSummary");
+ private final String value;
+
+ QueryType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/openapi/controller/OpenApiController.java b/galaxy-query-engine/src/main/java/com/mesalab/openapi/controller/OpenApiController.java
new file mode 100644
index 0000000..fa18975
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/openapi/controller/OpenApiController.java
@@ -0,0 +1,49 @@
+package com.mesalab.openapi.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.openapi.service.OpenApiService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Objects;
+
+/**
+ * @Date: 2020-09-18 10:58
+ * @Author : liuyongqiang
+ * @ClassName : OpenApiController
+ * @Description : OpenApiController
+ */
+@RestController
+@RequestMapping("open-api")
+public class OpenApiController {
+
+ @Autowired
+ OpenApiService openApiService;
+
+ /**
+ * @Description: APP字典列表
+ * @Author: liuyongqiang
+ * @Date: 2020/9/17 15:32
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ @GetMapping("appDicList")
+ public BaseResult appDicList() {
+ return openApiService.appDicList();
+ }
+
+ /**
+ * @param id: 报告ID
+ * @Description: 查询报告结构
+ * @Author: liuyongqiang
+ * @Date: 2020/10/16 17:46
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ @GetMapping("reportResults/{id}")
+ public BaseResult reportResults(@PathVariable(name = "id") Integer id) {
+ return openApiService.reportResults(id);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/OpenApiService.java b/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/OpenApiService.java
new file mode 100644
index 0000000..65866ed
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/OpenApiService.java
@@ -0,0 +1,29 @@
+package com.mesalab.openapi.service;
+
+import com.mesalab.common.base.BaseResult;
+
+/**
+ * @Date: 2020-09-18 10:58
+ * @Author : liuyongqiang
+ * @ClassName : OpenApiService
+ * @Description : OpenApiService
+ */
+public interface OpenApiService {
+
+ /**
+ * @Description: APP字典列表
+ * @Author: liuyongqiang
+ * @Date: 2020/9/17 15:31
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ BaseResult appDicList();
+
+ /**
+ * @param id: 报告ID
+ * @Description: 查询报告结果
+ * @Author: liuyongqiang
+ * @Date: 2020/10/16 17:45
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ BaseResult reportResults(Integer id);
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/impl/OpenApiServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/impl/OpenApiServiceImpl.java
new file mode 100644
index 0000000..665cf23
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/openapi/service/impl/OpenApiServiceImpl.java
@@ -0,0 +1,61 @@
+package com.mesalab.openapi.service.impl;
+
+import com.jfinal.plugin.activerecord.Db;
+import com.jfinal.plugin.activerecord.Record;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.utils.ReportCacheUtils;
+import com.mesalab.openapi.service.OpenApiService;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Date: 2020-09-18 11:00
+ * @Author : liuyongqiang
+ * @ClassName : OpenApiServiceImpl
+ * @Description : OpenApiServiceImpl
+ */
+@Service("openApiService")
+public class OpenApiServiceImpl implements OpenApiService {
+
+ /**
+ * @Description: APP字典列表
+ * @Author: liuyongqiang
+ * @Date: 2020/9/17 15:31
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ @Override
+ public BaseResult appDicList() {
+ List<?> list = Db.query(Db.getSql("appDicList"));
+ return BaseResultGenerator.success(list);
+ }
+
+ /**
+ * @param id: 报告ID
+ * @Description: 查询报告结果
+ * @Author: liuyongqiang
+ * @Date: 2020/10/16 17:45
+ * @return: com.mesalab.common.base.BaseResult
+ **/
+ @Override
+ public BaseResult reportResults(Integer id) {
+ List<Map<String, Object>> results = new ArrayList<>();
+ String sql = Db.getSql("reportResults");
+ List<Record> list = Db.find(sql, id);
+ if (CollectionUtils.isEmpty(list)) return BaseResultGenerator.success();
+
+ list.stream().forEach(record -> {
+ String querySql = record.get("query_sql");
+ int resultId = record.getInt("result_id");
+ String queryId = ReportCacheUtils.getQueryId(String.valueOf(resultId), querySql);
+ record.set("query_id", queryId);
+ results.add(record.getColumns());
+ });
+
+ return BaseResultGenerator.success(results);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java
new file mode 100644
index 0000000..0c9542b
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ApiController.java
@@ -0,0 +1,37 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.AuditLog;
+import com.mesalab.qgw.model.api.CachedSubmitCheck;
+import com.mesalab.qgw.service.ApiService;
+import com.zdjizhi.utils.JsonMapper;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@RestController
+@RequestMapping(value = "/")
+public class ApiController {
+
+ @Autowired
+ ApiService apiService;
+
+ @RequestMapping("/")
+ @AuditLog("QGW QUERY SERVICE")
+ @CachedSubmitCheck
+ public BaseResult querey(ApiParam apiParam) {
+
+ log.info("Quest Params:{}", JsonMapper.toJsonString(apiParam));
+
+ if (StringUtil.isBlank(apiParam.getQuery()))
+ return BaseResultGenerator.success4Message("ok");
+
+ return apiService.executeQuery(apiParam);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java
new file mode 100644
index 0000000..690e66a
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/AuditLogAspect.java
@@ -0,0 +1,113 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.utils.QueryCacheUtils;
+import com.mesalab.common.utils.IPUtil;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.AuditLog;
+import com.mesalab.qgw.model.api.AuditServiceLog;
+import com.zdjizhi.utils.StringUtil;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+
+@Aspect
+@Component
+public class AuditLogAspect {
+
+ ThreadLocal<Long> startTime = new ThreadLocal<>();
+ ThreadLocal<AuditServiceLog> log = new ThreadLocal<>();
+ private static final Logger logger= LoggerFactory.getLogger(AuditLogAspect.class);
+
+
+ @Pointcut("@annotation(com.mesalab.qgw.model.api.AuditLog)")
+ public void annotationPointCut(){}
+
+ @Before("annotationPointCut()")
+ public void doBefore(JoinPoint joinPoint) throws Throwable {
+ // 接收到请求,记录请求内容
+ startTime.set(System.currentTimeMillis());
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ HttpServletRequest request = attributes.getRequest();
+ String url = request.getRequestURL().toString();
+ String method = request.getMethod();
+ String remoteAddr = request.getRemoteAddr();
+ String clientIp = IPUtil.parseIP(request);
+
+ if("0.0.0.0".equals(clientIp) || "0:0:0:0:0:0:0:1".equals(clientIp) || "localhost".equals(clientIp) || "127.0.0.1".equals(clientIp)){
+ clientIp = "127.0.0.1";
+ }
+ String class_method = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
+ String param = Arrays.toString(joinPoint.getArgs());
+
+ MethodSignature sign = (MethodSignature)joinPoint.getSignature();
+ Method method2 = sign.getMethod();
+ AuditLog annotation = method2.getAnnotation(AuditLog.class);
+
+ AuditServiceLog auditServiceLog = new AuditServiceLog();
+ auditServiceLog.setUrl(url);
+ auditServiceLog.setMethod(method);
+ auditServiceLog.setRemoteAddr(remoteAddr);
+ auditServiceLog.setClientIp(clientIp);
+ auditServiceLog.setClassMethod(class_method);
+ if (logger.isDebugEnabled()) {
+ auditServiceLog.setParam(param);
+ }
+ auditServiceLog.setAnnotation(annotation.value());
+ auditServiceLog.setQueryKey(DigestUtils.md5Hex(StringUtil.isNotBlank(request.getQueryString()) ? request.getQueryString() : ""));
+
+ log.set(auditServiceLog);
+ }
+
+ @AfterThrowing(value = "annotationPointCut()", throwing = "exception")
+ public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
+ logger.error("Audit log [error]:" + joinPoint.getSignature().getName() + exception);
+
+ }
+
+
+ @After(value = "annotationPointCut()")
+ public void after(JoinPoint joinPoint) {
+ ApiParam param = (ApiParam) joinPoint.getArgs()[0];
+ log.get().setDbType(param.getDbType());
+
+ }
+
+
+
+
+ @AfterReturning(returning = "result", pointcut = "annotationPointCut()")
+ public void doAfterReturning(Object result) throws Throwable {
+
+ AuditServiceLog logAfter = log.get();
+ if (StringUtil.isNotEmpty(result) ) {
+ QueryCacheUtils.put(logAfter.getQueryKey(), result);
+ }
+
+ if(result instanceof BaseResult){
+ BaseResult baseResult = (BaseResult) result;
+ baseResult.setQueryKey(logAfter.getQueryKey());
+ }
+
+ Long exeTime = System.currentTimeMillis() - startTime.get();
+ logAfter.setExeTime(exeTime);
+
+ logger.info("Audit Log [completed]:" + JsonMapper.toJsonString(logAfter));
+
+ }
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ControllerFilter.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ControllerFilter.java
new file mode 100644
index 0000000..d4817f5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/ControllerFilter.java
@@ -0,0 +1,29 @@
+package com.mesalab.qgw.controller;
+
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+@Component
+@WebFilter(urlPatterns = "/*")
+public class ControllerFilter implements Filter {
+
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+
+ }
+
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ filterChain.doFilter(new RequestParamWrapper((HttpServletRequest) servletRequest), servletResponse);
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/GlobalExceptionHandler.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/GlobalExceptionHandler.java
new file mode 100644
index 0000000..cde2f8d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/GlobalExceptionHandler.java
@@ -0,0 +1,35 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.exception.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+
+ @ExceptionHandler(Exception.class)
+ public BaseResult handleException(Exception e) {
+ return BaseResultGenerator.failure(e.getMessage()); //自己需要实现的异常处理
+ }
+
+
+
+
+ @ExceptionHandler({BusinessException.class})
+ public BaseResult handleBusinessException(BusinessException e, HttpServletRequest request, HttpServletResponse response) {
+ response.setStatus(e.getErrorStatus());
+ log.error("Execute Query Error: {}", e.getMessage()+ ";" + (e.getCause() != null ? e.getCause().getMessage() : ""));
+ return BaseResultGenerator.failure(e.getErrorStatus(), e.getErrorCode(),
+ (e.getMessage() != null ? e.getMessage() : e.getErrorMessage()) + " " + (e.getCause() != null ? e.getCause().getMessage() : ""));//自己需要实现的异常处理
+ }
+
+
+ }
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java
new file mode 100644
index 0000000..bc2db36
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MetadataController.java
@@ -0,0 +1,32 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.qgw.service.MetadataService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@RestController
+@RequestMapping(value = "/metadata")
+public class MetadataController {
+
+ @Autowired
+ private MetadataService metadataService;
+
+
+ @RequestMapping("/schema/v1/{type}/{name}")
+ public BaseResult getSchema(@PathVariable String type, @PathVariable String name) {
+ log.debug("SCHEMA信息获取,参数为{} {}", type, name);
+
+ if (StringUtil.isBlank(type) || StringUtil.isBlank(name)) {
+
+ return BaseResultGenerator.success4Message("ok");
+ }
+ return metadataService.getSchemaInfo(type, name);
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MonitorController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MonitorController.java
new file mode 100644
index 0000000..f0d30f8
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/MonitorController.java
@@ -0,0 +1,40 @@
+package com.mesalab.qgw.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.*;
+
+/**
+ * @author wangwei
+ * @description:
+ * @date 2020/7/31 1:59 下午
+ */
+@Slf4j
+@RestController
+@RequestMapping(value = "/monitor")
+public class MonitorController {
+
+ @RequestMapping("/info")
+ public String config() {
+ String jsonStr = "";
+ try {
+ String pathRoot = new File("").getCanonicalPath();
+ File jsonFile = new File(pathRoot + "/config/version.json");
+ FileReader fileReader = new FileReader(jsonFile);
+ Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
+ int ch;
+ StringBuffer sb = new StringBuffer();
+ while ((ch = reader.read()) != -1) {
+ sb.append((char) ch);
+ }
+ fileReader.close();
+ reader.close();
+ jsonStr = sb.toString();
+ } catch (IOException e) {
+ log.error("get file error: ", e);
+ }
+ return jsonStr;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/RequestParamWrapper.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/RequestParamWrapper.java
new file mode 100644
index 0000000..3bd0698
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/RequestParamWrapper.java
@@ -0,0 +1,50 @@
+package com.mesalab.qgw.controller;
+
+
+
+import com.google.common.collect.Lists;
+import com.mesalab.common.enums.QueryParamEnum;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.nio.charset.Charset;
+import java.util.List;
+
+public class RequestParamWrapper extends HttpServletRequestWrapper {
+ private String queryString = null;
+ RequestParamWrapper(HttpServletRequest request) {
+ super(request);
+ queryString = request.getQueryString();
+
+ }
+
+
+ @Override
+ public String[] getParameterValues(String name) {
+ if (QueryParamEnum.QUERY.getValue().equals(name)) {
+
+ queryString = queryString.replaceAll("\\+", "%2B");
+
+ List<NameValuePair> values = URLEncodedUtils.parse(queryString, Charset.forName("UTF-8"));
+ List<String> valueList = Lists.newArrayList();
+ for (NameValuePair nameValuePair: values) {
+ if (nameValuePair.getName().equals(QueryParamEnum.QUERY.getValue())) {
+ valueList.add(nameValuePair.getValue());
+ }
+ }
+ String[] valueString = new String[valueList.size()];
+ valueList.toArray(valueString);
+ return valueString;
+ }
+ return super.getParameterValues(name);
+ }
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java
new file mode 100644
index 0000000..9a2e755
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/SystemController.java
@@ -0,0 +1,81 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.qgw.model.job.StorageDeletionInfo;
+import com.mesalab.qgw.service.SystemService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping(value = "/sys")
+public class SystemController {
+
+ @Autowired
+ private SystemService systemService;
+
+
+ @RequestMapping("/storage/quota")
+ public BaseResult storageQuota() {
+ log.debug("获取系统存储配额信息");
+ return systemService.getStorageQuota();
+ }
+
+ @RequestMapping("storage/daily-trend")
+ public BaseResult dailyTrendOfStorage(@RequestParam Map<String, Object> param) {
+ log.debug("获取系统存储配额信息");
+
+
+ String searchStartTime = StringUtil.stripToEmpty((String) param.get("start_time"));
+ String searchEndTime = StringUtil.stripToEmpty((String) param.get("end_time"));
+
+
+ return systemService.dailyTrendOfStorage(searchStartTime, searchEndTime);
+ }
+
+ @PostMapping(value = "storage/deletion")
+ public BaseResult storageDeletion(@RequestBody List<StorageDeletionInfo> list) {
+ log.info("数据配额设置, 参数: params is {}", list);
+
+ if (StringUtil.isEmpty(list)) {
+ return BaseResultGenerator.failure(ResultStatusEnum.FAIL.getCode(), "未获取到参数");
+ }
+ for (StorageDeletionInfo info : list) {
+ if (StringUtil.isBlank(info.getLogType()) || StringUtil.isBlank(String.valueOf(info.getMaxDays()))) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "参数校验: logType 与 maxDays 需同时填写", null);
+ }
+ if ("ALL".equalsIgnoreCase(info.getLogType()) && list.size() != 1) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "参数校验: logType存在ALL时, 不能与其它类型共存", null);
+ }
+ if (!(info.getMaxDays() >= 0 && info.getMaxDays() <= 2000)) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "参数校验: logType非All: maxDays 必须是数值且[0-2000]", null);
+ }
+ }
+ return systemService.deleteStorage(list);
+ }
+
+ @GetMapping(value = "storage/deletion")
+ public BaseResult storageDeletionStatus(StorageDeletionInfo storageDeletionInfo) {
+
+ log.info("数据配额设置状态, 参数: params is {}", storageDeletionInfo);
+ return systemService.getDeleteStorageStatus(storageDeletionInfo.getLogType());
+ }
+
+ @DeleteMapping(value = "engine/tasks/{queryId}")
+ public BaseResult killQuery(@PathVariable String queryId) {
+ log.info("停止查询, 参数: queryId is {}", queryId);
+ if (StringUtil.isBlank(queryId)) {
+ return BaseResultGenerator.success4Message("ok");
+ }
+ return systemService.deleteQueryTask(queryId);
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/TestController.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/TestController.java
new file mode 100644
index 0000000..dc73ae8
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/controller/TestController.java
@@ -0,0 +1,125 @@
+package com.mesalab.qgw.controller;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.configuration.ProjectProperties;
+import com.mesalab.qgw.service.impl.TestSqlServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 测试Controller
+ * 使用@RestController可以不需要使用@ResponseBody注解,方法会自动处理成json格式返回
+ *
+ * @author darnell
+ * @date 2019/5/13
+ */
+@Slf4j
+@RestController
+@RequestMapping(value = "test")
+public class TestController {
+
+ private final ProjectProperties projectProperties;
+
+ private final Environment environment;
+
+ @Autowired
+ TestSqlServiceImpl testSqlService;
+
+ @Autowired
+ public TestController(ProjectProperties projectProperties, Environment environment) {
+ this.projectProperties = projectProperties;
+ this.environment = environment;
+ }
+
+ /**
+ * 测试
+ * 使用@GetMapping相当于使用@RequestMapping(method={RequestMethod.GET})
+ *
+ * @return BaseResult
+ */
+ @GetMapping(value = "projectProperties")
+ public BaseResult projectProperties() {
+ log.info("Project Properties: {}", projectProperties);
+ //此处本意是将projectProperties返回至前端,但是projectProperties对象是由spring注入而来,其中包含过多的动态代理数据,
+ //使用lombok的@Data注解处理BaseResult时,数据过大,返回报错,因此只返回success
+ return BaseResultGenerator.success();
+ }
+
+ /**
+ * 获取项目环境值,获取的是Environment对象中的activeProfiles,String[]
+ *
+ * @return 返回当前项目的环境值
+ */
+ @GetMapping(value = "activeProfiles")
+ public BaseResult activeProfiles() {
+ String[] activeProfiles = environment.getActiveProfiles();
+ log.info("Active Profiles: {}", Arrays.toString(activeProfiles));
+ return BaseResultGenerator.success(activeProfiles);
+ }
+
+ /**
+ * 运行环境,将Environment.activeProfiles注入到projectProfiles中
+ *
+ * @return 返回当前项目的运行环境
+ */
+ @GetMapping(value = "env")
+ public BaseResult env() {
+ String[] env = projectProperties.getEnv();
+ log.info("Project env: {}", Arrays.toString(env));
+ return BaseResultGenerator.success(env);
+ }
+
+ /**
+ * 是否是生产环境
+ *
+ * @return 返回当前项目的运行环境
+ */
+ @GetMapping(value = "isProduct")
+ public BaseResult isProduct() {
+ boolean isProduct = projectProperties.isProduct();
+ String msg = "Current Environment is" + (isProduct ? "" : " not") + " product";
+ log.info(msg);
+ return BaseResultGenerator.success(msg);
+ }
+
+ /**
+ * 检查是否授权
+ *
+ * @return 检查授权
+ */
+ @GetMapping(value = "checkAuthc")
+ public BaseResult checkAuthc() {
+ return BaseResultGenerator.success();
+ }
+
+
+ /**
+ * 运行测试用例
+ *
+ * @return
+ */
+ @GetMapping(value = "runSql")
+ public BaseResult runSql() {
+ BaseResult result = testSqlService.runSql();
+ return result;
+ }
+
+ /**
+ * 校验schema
+ *
+ * @return
+ */
+ @GetMapping(value = "runSchema")
+ public BaseResult runSchema() {
+ BaseResult result = testSqlService.runSchema();
+ return result;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java
new file mode 100644
index 0000000..aac3bd2
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractDataSourceDialect.java
@@ -0,0 +1,80 @@
+package com.mesalab.qgw.dialect;
+
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.zdjizhi.utils.Encodes;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+import org.apache.calcite.rel.core.TableScan;
+
+import java.util.Optional;
+
+@Data
+public abstract class AbstractDataSourceDialect implements Dialect {
+
+ abstract void init();
+
+ /**
+ * SQL查询语句转换为方言所认知的查询语句。
+ * @param sql
+ * @return
+ */
+ abstract String convertQuery(String sql);
+
+ /**
+ * 基于RBO(rule-base optimizer)获取最优化的SQL
+ * @return
+ */
+ abstract String getBestQuery();
+
+ /**
+ * 获取原始SQL语句,不做规则转换,直接下推
+ * @return
+ */
+ abstract String getOriginQuery();
+
+ /**
+ * 获取用于语法检查的SQL,目标生成无Filter语句。
+ * @return
+ */
+ abstract String getSyntaxCheckQuery();
+
+ /**
+ * 解析并生成最终结果
+ * @param sql
+ * @param message
+ * @return
+ */
+ abstract BaseResult generateBaseResult(String sql, Optional<String> message);
+
+ @Override
+ final public BaseResult executeQuery() {
+
+ init();
+ String sql = convertQuery(getBestQuery());
+ return generateBaseResult(sql, Optional.of("OK"));
+ }
+
+ @Override
+ final public BaseResult executeSyntaxCheck() {
+ init();
+ String originSQL = getOriginQuery();
+ String sql = convertQuery(getSyntaxCheckQuery());
+ return generateBaseResult(sql, Optional.of(originSQL));
+ }
+
+ @Override
+ final public BaseResult executeAdministrativeQuery() {
+ init();
+ String sql = getOriginQuery();
+ return generateBaseResult(sql, Optional.of("OK"));
+ }
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java
new file mode 100644
index 0000000..eb39720
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/AbstractEngineDialect.java
@@ -0,0 +1,49 @@
+package com.mesalab.qgw.dialect;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+
+import java.util.Optional;
+
+@Data
+public abstract class AbstractEngineDialect implements Dialect {
+
+ abstract void init();
+
+ public boolean isExecute() {
+ return false;
+ }
+
+ abstract void executeUDF();
+
+ /**
+ * 解析并生成最终结果
+ * @return
+ */
+ abstract BaseResult generateBaseResult();
+
+
+ @Override
+ final public BaseResult executeQuery() {
+ init();
+ executeUDF();
+ return generateBaseResult();
+ }
+
+
+ @Override
+ final public BaseResult executeSyntaxCheck() {
+ return null;
+ }
+
+ @Override
+ final public BaseResult executeAdministrativeQuery() {
+ return null;
+ }
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java
new file mode 100644
index 0000000..419b1ac
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/ClickHouseDialect.java
@@ -0,0 +1,1016 @@
+package com.mesalab.qgw.dialect;
+
+
+import com.google.common.collect.Maps;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.*;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.*;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.qgw.model.api.*;
+import com.mesalab.qgw.service.MetadataService;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.mesalab.common.utils.TableFinder;
+import com.zdjizhi.utils.Encodes;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.Function;
+import net.sf.jsqlparser.expression.Parenthesis;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
+import net.sf.jsqlparser.expression.operators.relational.*;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.select.*;
+import org.apache.avro.Schema;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Slf4j
+public class ClickHouseDialect extends AbstractDataSourceDialect {
+ Pattern pGlobalIn = Pattern.compile("\\s+in\\s*\\(", Pattern.CASE_INSENSITIVE);
+ Pattern pUniq = Pattern.compile("count\\s*\\(\\s*distinct\\s*\\((.*?)\\)", Pattern.CASE_INSENSITIVE);
+ Pattern pUniqCombined = Pattern.compile("count\\s*\\(\\s*distinct\\s*\\((.*?)\\)", Pattern.CASE_INSENSITIVE);
+ Pattern pWhere = Pattern.compile("where\\s*", Pattern.CASE_INSENSITIVE);
+ Pattern pCount = Pattern.compile("\\bcount\\s*\\(", Pattern.CASE_INSENSITIVE);
+ Pattern pCount1 = Pattern.compile("count\\(\\s*1\\s*\\)", Pattern.CASE_INSENSITIVE);
+ private ClickHouseHttpSource clickHouseHttpSource = (ClickHouseHttpSource) SpringContextUtil.getBean("clickHouseHttpSource");
+ private HttpClientService httpClientService = (HttpClientService) SpringContextUtil.getBean("httpClientService");
+ private MetadataService metadataService = (MetadataService) SpringContextUtil.getBean("metadataService");
+ private EngineConfigSource engineConfigSource = (EngineConfigSource) SpringContextUtil.getBean("engineConfigSource");
+ private HttpConfig httpConfig = (HttpConfig) SpringContextUtil.getBean("httpConfig");
+ public ApiParam param;
+ public BaseResult baseResult;
+
+ public ClickHouseDialect(ApiParam param) {
+ this.param = param;
+ }
+
+
+ @Override
+ public void init() {
+ if (StringUtil.isNotEmpty(param.getDbQuerySource())) {
+ param.setSql(param.getDbQuerySource().getSqlBody());
+ } else {
+ param.setSql(param.getQuery());
+ }
+ baseResult = BaseResultGenerator.success();
+ }
+
+ @Override
+ public boolean supportsLimit() {
+ return true;
+ }
+
+
+ @Override
+ public String convertQuery(String sql) {
+ return new Converter(sql).
+ generateStandard().generateDateFunction().generateSqlEncode().build();
+ }
+
+ @Override
+ public String getBestQuery() {
+ return new Optimizer().generateQueryLimit().
+ generateSQL().generateUniq().generateSubquery().build();
+ }
+
+ @Override
+ public String getOriginQuery() {
+ return param.getQuery();
+ }
+
+ /**
+ * 获取语法检测sql
+ *
+ * @return
+ */
+ @Override
+ public String getSyntaxCheckQuery() {
+ String sql = param.getDbQuerySource().getSqlBody();
+ try {
+ sql = String.valueOf(parserAndUpdateSql(sql));
+ } catch (Exception e) {
+ log.error("syntax-check sql error {}, execute original sql: {}, error is: {} ",
+ sql, sql = param.getDbQuerySource().getSqlBody(), e.getMessage() == null ? e.getCause() : e.getMessage());
+ }
+ return sql;
+ }
+
+
+ class Converter {
+ String sql = null;
+
+ public Converter(String sql) {
+ this.sql = sql;
+ }
+
+ /**
+ * 兼容标准SQL语言(支持CK19.14.6.12 新特性):
+ * 1.集群模式子查询必须加库名、别名 (解决方法: 对sql统一处理添加库名、别名)
+ * 2.不支持 count(1) 需转为count(*)
+ *
+ * @return
+ */
+ public Converter generateStandard() {
+ sql = generateCount(sql);
+ try {
+ TableFinder tableFinder = new TableFinder();
+ Statement parse = CCJSqlParserUtil.parse(sql);
+ tableFinder.setDefaultAlias(true);
+ tableFinder.addSchemaName(parse);
+ sql = String.valueOf(parse);
+ } catch (JSQLParserException e) {
+ log.error("添加库名、别名异常: ", e);
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "添加库名、别名异常", e);
+ }
+ return this;
+ }
+
+ public Converter generateDateFunction() {
+ try {
+ sql = SQLFunctionUtil.generateDateFunction(sql, DBTypeEnum.CLICKHOUSE.getValue());
+ } catch (Exception ex) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "参数校验:SQL 日期函数解析错误", ex);
+ }
+
+ return this;
+ }
+
+ /**
+ * http GET sql 里特殊符号需要做encode编码
+ *
+ * @return
+ */
+ public Converter generateSqlEncode() {
+ sql = Encodes.urlEncode(sql);
+ return this;
+ }
+
+ public String build() {
+ return sql;
+ }
+
+ /**
+ * 集群不支持count(1) 需转成count(*)
+ *
+ * @param sql
+ * @return
+ */
+ private String generateCount(String sql) {
+ Matcher m = pCount1.matcher(sql);
+ StringBuffer sb = new StringBuffer();
+
+ while (m.find()) {
+ m.appendReplacement(sb, "count(*)");
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+ }
+
+
+ class Optimizer {
+ private Boolean subIndexValidFlag = true;
+ String sql = null;
+
+ /**
+ * 对SQL最内层的结果数据集进行限制
+ * 参见查询网关系统参数:engine.maxCacheNum
+ *
+ * @return
+ */
+ public Optimizer generateQueryLimit() {
+
+ setDefaultResultRows(StringUtil.isEmpty(param.getEngineQuerySource()) ? param.getDbQuerySource() : param.getEngineQuerySource(), engineConfigSource.getDefaultResultNum());
+
+ setMaxCacheResultRows(param.getDbQuerySource(), engineConfigSource.getMaxCacheNum());
+ return this;
+ }
+
+
+ private void setDefaultResultRows(SQLQuerySource sqlQuerySource, int defaultResultRows) {
+ if (StringUtil.isBlank(sqlQuerySource.getLimit())) {
+ sqlQuerySource.setSqlBody(sqlQuerySource.getSqlBody() + " limit " + defaultResultRows);
+ sqlQuerySource.setLimit(String.valueOf(defaultResultRows));
+ }
+
+ }
+
+ /**
+ * 设置最大缓存数据集
+ *
+ * @param sqlQuerySource
+ * @return
+ */
+ private void setMaxCacheResultRows(SQLQuerySource sqlQuerySource, int maxCacheResultRows) {
+ SQLQuerySource innerSqlQuerySource = sqlQuerySource;
+ while (StringUtil.isNotEmpty(innerSqlQuerySource.getSubSelect())) {
+ innerSqlQuerySource = innerSqlQuerySource.getSubSqlQuerySources().get(0);
+ }
+
+ if (!innerSqlQuerySource.isEnableLimit()) {
+ return;
+ }
+
+ String orginInnerSql = innerSqlQuerySource.getSqlBody();
+ String limitInnerSql = innerSqlQuerySource.getSqlBody();
+
+ if (StringUtil.isNotBlank(innerSqlQuerySource.getLimit())) {
+
+ String[] limits = innerSqlQuerySource.getLimit().split(",");
+
+ if (Integer.valueOf(limits[limits.length - 1]) > maxCacheResultRows) {
+ limits[limits.length - 1] = String.valueOf(maxCacheResultRows);
+
+ if (limits.length == 2) {
+ limitInnerSql = SQLHelper.getLimitString(limitInnerSql, Integer.valueOf(limits[0]), Integer.valueOf(limits[1]));
+ } else {
+ limitInnerSql = SQLHelper.getLimitString(limitInnerSql, 0, Integer.valueOf(limits[0]));
+ }
+
+ innerSqlQuerySource.setLimit(String.join(",", limits).toString());
+ innerSqlQuerySource.setSqlBody(limitInnerSql);
+
+ }
+
+ } else {
+ limitInnerSql = innerSqlQuerySource.getSqlBody() + " limit " + maxCacheResultRows;
+ innerSqlQuerySource.setLimit(String.valueOf(maxCacheResultRows));
+ innerSqlQuerySource.setSqlBody(limitInnerSql);
+
+ }
+
+ if (StringUtil.isNotEmpty(sqlQuerySource.getSubSqlQuerySources())) {
+ sqlQuerySource.setSqlBody(sqlQuerySource.getSqlBody().replace(orginInnerSql, limitInnerSql));
+ }
+
+ }
+
+ public Optimizer generateSQL() {
+ SQLQuerySource sqlQuerySource = param.getDbQuerySource();
+ sql = sqlQuerySource.getSqlBody();
+ return this;
+ }
+
+ /**
+ * count(distinct())转为uniq函数
+ *
+ * @return
+ */
+ public Optimizer generateUniq() {
+ Matcher m = pUniq.matcher(sql);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ if (m.groupCount() == 1) {
+ String replaceValue = m.group(1);
+ m.appendReplacement(sb, "uniq(" + replaceValue);
+
+ }
+ }
+ m.appendTail(sb);
+ sql = sb.toString();
+ return this;
+ }
+
+ /**
+ * IN 转换为 集群 Global IN 模式
+ *
+ * @return
+ */
+ public Optimizer generateGlobalIn() {
+ Matcher m = pGlobalIn.matcher(sql);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(sb, " global in (");
+ }
+
+ m.appendTail(sb);
+ sql = sb.toString();
+ return this;
+ }
+
+ /**
+ * count(distinct())转为uniqCombined函数
+ *
+ * @return
+ */
+ private Optimizer generateUniqCombined() {
+
+ Matcher m = pUniqCombined.matcher(sql);
+
+ StringBuffer sb = new StringBuffer();
+
+ while (m.find()) {
+
+ if (m.groupCount() == 1) {
+ String replaceValue = m.group(1);
+ m.appendReplacement(sb, "uniqCombined(" + replaceValue);
+
+ }
+ }
+ m.appendTail(sb);
+
+ sql = sb.toString();
+ return this;
+ }
+
+ /**
+ * 事件索引子查询,目的提高日志查询检索性能:
+ * 方式1.基于索引表
+ * 方式2.基于分区键
+ * 限制:
+ * 1. 仅适用一级普通查询,带where (无group by 统计)的查询
+ * 2. 不对count 统计进行生成
+ *
+ * @return
+ */
+ public Optimizer generateSubquery() {
+
+ if (StringUtil.isBlank(param.getDbQuerySource().getExpr())) {
+ return this;
+ }
+
+ if (StringUtil.isNotEmpty(param.getDbQuerySource().getGroupByElement())) {
+ return this;
+ }
+
+ if (pCount.matcher(param.getDbQuerySource().getSelectItems()).find()) {
+ return this;
+ }
+
+ String indexTable = getAvaliableIndexTable();
+ if (StringUtil.isNotBlank(indexTable)) {
+ sql = getSubqueryByIndexTable(indexTable);
+ } else {
+ sql = getSubqueryByPartitionKey(sql);
+ }
+ return this;
+ }
+
+
+ /**
+ * 设置索引表子查询参数: 索引表有效性、索引表表名
+ *
+ * @return
+ */
+ private String getAvaliableIndexTable() {
+ String indexTable = "";
+ String str = metadataService.getValueByKeyInSchemaDoc(param.getTableName(), "index_table");
+ String[] indexTables = StringUtil.split(str, ",");
+ if (StringUtil.isEmpty(indexTables)) {
+ return StringUtil.EMPTY;
+ }
+ for (String tempIndexTable : indexTables) {
+
+ String indexKey = metadataService.getValueByKeyInSchemaDoc(tempIndexTable, "index_key");
+ //判断一: where 是否包含索引键
+ if (!param.getDbQuerySource().getExpr().contains(indexKey)) {
+ continue;
+ }
+
+ BaseResult indexTableData = metadataService.getSchemaInfo("fields", tempIndexTable);
+ Schema indexTableSchema = new Schema.Parser().parse(JsonMapper.toJsonString(indexTableData.getData()));
+ //判断二: order by 元素是否都在索引表中
+ if (!isValidOfOrderElementsInSchema(indexTableSchema)) {
+ continue;
+ }
+
+ BaseResult masterTableData = metadataService.getSchemaInfo("fields", param.getTableName());
+ Schema masterTableSchema = new Schema.Parser().parse(JsonMapper.toJsonString(masterTableData.getData()));
+ //判断三: where 条件列是否都在索引表中
+ setValidityByWhereExpressionsInSchema(param.getDbQuerySource().getWhereExpression(), masterTableSchema, indexTableSchema);
+ if (getSubIndexValidFlag() && isExist(indexTableSchema.getFullName())) {
+ indexTable = indexTableSchema.getName();
+ break;
+ }
+ }
+ return indexTable;
+ }
+
+ /**
+ * 基于索引表方式添加子查询
+ *
+ * @param indexTable
+ * @return
+ */
+ private String getSubqueryByIndexTable(String indexTable) {
+
+ String primaryKey = metadataService.getValueByKeyInSchemaDoc(param.getTableName(), "primary_key");
+
+ StringBuffer subQuery = getSubquerySql(primaryKey, indexTable);
+ StringBuffer sb = new StringBuffer();
+ sb.append("select ").append(param.getDbQuerySource().getSelectItems()).append(" from ").append(param.getTableName()).append(" where ").append(primaryKey).append(" in ( ").append(subQuery).append(")");
+ if (StringUtil.isNotBlank(param.getDbQuerySource().getExpr())) {
+ sb.append(" and (").append(param.getDbQuerySource().getExpr()).append(")");
+ }
+ if (StringUtil.isNotBlank(param.getDbQuerySource().getOrderBy())) {
+ sb.append(" order by ").append(param.getDbQuerySource().getOrderBy());
+ }
+ if (StringUtil.isNotBlank(param.getDbQuerySource().getLimit())) {
+ sb.append(" limit ").append(param.getDbQuerySource().getLimit());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 基于分区键方式
+ *
+ * @param sql
+ * @return
+ */
+ private String getSubqueryByPartitionKey(String sql) {
+ String partitionKey = getPartitionKey(param.getTableName());
+ if (StringUtil.isBlank(partitionKey)) {
+ log.warn("Get Partition Key is Null.Focus in tableName {} schema", param.getTableName());
+ return sql;
+ } else {
+ StringBuffer subQuery = getSubquerySql(partitionKey, param.getTableName());
+ Matcher m = pWhere.matcher(sql);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(sb, "where " + partitionKey + " in ( " + subQuery + ") and ");
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+ }
+
+ /**
+ * 获取子sql
+ *
+ * @param columnName
+ * @param tableName
+ * @return
+ */
+ private StringBuffer getSubquerySql(String columnName, String tableName) {
+ StringBuffer subQuery = new StringBuffer();
+
+ subQuery.append("select " + columnName + " from ").append(tableName)
+ .append(" where ").append(param.getDbQuerySource().getExpr());
+
+ //order by中元素存在别名时做替换处理
+ List<OrderByElement> listOrderElement = param.getDbQuerySource().getListOrderElement();
+ if (StringUtil.isNotEmpty(listOrderElement)) {
+ String orderBy = param.getDbQuerySource().getOrderBy();
+ for (OrderByElement order : listOrderElement) {
+ String orderField = order.getExpression().toString();
+ if (orderField.startsWith("\"") && orderField.endsWith("\"")) {
+ orderField = orderField.substring(1, orderField.length() - 1);
+ }
+ String originalField = param.getDbQuerySource().getAliasFields().get(orderField);
+ if (StringUtil.isNotBlank(originalField)) {
+ orderBy = orderBy.replaceAll("(\"" + orderField + "\")|(\\b" + orderField + "\\b)", originalField);
+ }
+
+ }
+ subQuery.append(" order by ").append(orderBy);
+ }
+
+
+ if (StringUtil.isNotBlank(param.getDbQuerySource().getLimit())) {
+ String[] limits = param.getDbQuerySource().getLimit().split(",");
+ if (limits.length == 2) {
+ int rows = Integer.valueOf(limits[0].trim()) + Integer.valueOf(limits[1].trim());
+ subQuery.append(" limit ").append(rows);
+ } else {
+ subQuery.append(" limit ").append(param.getDbQuerySource().getLimit());
+ }
+
+ } else {
+ subQuery.append(" limit 0, " + engineConfigSource.getDefaultResultNum());
+ }
+ return subQuery;
+ }
+
+ /**
+ * 获取当前CK查询中的分区键,用于子查询优化操作;
+ * 若分区键被其它列当别名使用,返回空
+ *
+ * @return
+ */
+ private String getPartitionKey(String tableName) {
+ String partitionKey = metadataService.getPartitionKey(tableName);
+
+ if (StringUtil.isNotBlank(partitionKey)) {
+ String tempValue = param.getDbQuerySource().getAliasFields().get(partitionKey);
+ if (StringUtil.isNotBlank(tempValue)) {
+ if (tempValue.contains(partitionKey)) {
+ partitionKey = tempValue;
+ } else {
+ partitionKey = "";
+ }
+ }
+
+ }
+
+ return partitionKey;
+
+ }
+
+ /**
+ * 判断table是否在DB中
+ *
+ * @param tableName
+ * @return
+ */
+ private boolean isExist(String tableName) {
+ Map<String, String> result = executeHttpGet(String.format("select 1 from %s limit 1", tableName));
+ if (result.get("status") == null || Integer.parseInt(result.get("status")) != HttpStatus.SC_OK) {
+ log.info("DB中不存在该表: {}", tableName);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 判断order by 元素是否属于schema字段中
+ *
+ * @param schema
+ * @return
+ */
+ private boolean isValidOfOrderElementsInSchema(Schema schema) {
+ List<OrderByElement> listOrderElement = param.getDbQuerySource().getListOrderElement();
+ if (StringUtil.isEmpty(listOrderElement)) {
+ return true;
+ } else {
+ Map<String, String> aliasFields = param.getDbQuerySource().getAliasFields();
+ for (OrderByElement order : listOrderElement) {
+ String orderField = String.valueOf(order.getExpression());
+ if (orderField.startsWith("\"") && orderField.endsWith("\"")) {
+ orderField = orderField.substring(1, orderField.length() - 1);
+ }
+ String originalField = StringUtil.isBlank(aliasFields.get(orderField)) ? orderField : aliasFields.get(orderField);
+ Expression expression = parserException(originalField);
+ if (expression instanceof Function) {
+ if (!getValidityByFunctionParamsInSchema(schema, (Function) expression)) {
+ return false;
+ }
+ } else {
+ if (!isFieldOfSchema(schema, originalField)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * 判断schema中是否存在field列
+ *
+ * @param schema
+ * @param fieldName
+ * @return
+ */
+ private boolean isFieldOfSchema(Schema schema, String fieldName) {
+ Schema.Field field = schema.getField(fieldName);
+ if (StringUtil.isEmpty(field)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 判断where条件是否可以进行在索引表中的查询
+ *
+ * @param where
+ * @param masterTableSchema 主表
+ * @param indexTableSchema 索引表
+ */
+ private void setValidityByWhereExpressionsInSchema(Expression where, Schema masterTableSchema, Schema indexTableSchema) {
+
+ if (StringUtil.isEmpty(masterTableSchema) || StringUtil.isEmpty(indexTableSchema)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+
+ if (where instanceof InExpression) {
+ InExpression whereIn = (InExpression) where;
+ ItemsList rightItemsList = whereIn.getRightItemsList();
+ if (rightItemsList instanceof SubSelect) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ String left;
+ if (!StringUtil.isEmpty(whereIn.getLeftExpression())) {
+ left = String.valueOf(whereIn.getLeftExpression());
+ } else {
+ left = String.valueOf(whereIn.getLeftItemsList());
+ }
+ if (!isFieldOfSchema(masterTableSchema, left) || !isFieldOfSchema(indexTableSchema, left)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ } else if (where instanceof AndExpression) {
+ AndExpression whereAnd = (AndExpression) where;
+ Expression leftExpression = whereAnd.getLeftExpression();
+ Expression rightExpression = whereAnd.getRightExpression();
+ setValidityByWhereExpressionsInSchema(leftExpression, masterTableSchema, indexTableSchema);
+ setValidityByWhereExpressionsInSchema(rightExpression, masterTableSchema, indexTableSchema);
+ } else if (where instanceof OrExpression) {
+ OrExpression whereOr = (OrExpression) where;
+ Expression leftExpression = whereOr.getLeftExpression();
+ Expression rightExpression = whereOr.getRightExpression();
+ setValidityByWhereExpressionsInSchema(leftExpression, masterTableSchema, indexTableSchema);
+ setValidityByWhereExpressionsInSchema(rightExpression, masterTableSchema, indexTableSchema);
+ } else if (where instanceof ComparisonOperator) {
+ ComparisonOperator whereComparisonOperator = (ComparisonOperator) where;
+ setValidityByLRExpressionInSchema(masterTableSchema, indexTableSchema, whereComparisonOperator.getLeftExpression(), whereComparisonOperator.getRightExpression());
+ } else if (where instanceof LikeExpression) {
+ LikeExpression whereLike = (LikeExpression) where;
+ setValidityByLRExpressionInSchema(masterTableSchema, indexTableSchema, whereLike.getLeftExpression(), whereLike.getRightExpression());
+ } else if (where instanceof Function) {
+ Function function = (Function) where;
+ boolean bool = getValidityByFunctionParamsInSchema(indexTableSchema, function);
+ if (!bool) {
+ setSubIndexValidFlag(false);
+ }
+ } else if (where instanceof Parenthesis) {
+ Parenthesis whereExpressionParenthesis = (Parenthesis) where;
+ Expression expression = whereExpressionParenthesis.getExpression();
+ setValidityByWhereExpressionsInSchema(expression, masterTableSchema, indexTableSchema);
+ } else {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ }
+
+ private Expression parserException(String originalField) {
+ try {
+ return CCJSqlParserUtil.parseExpression(originalField);
+ } catch (JSQLParserException e) {
+ throw new BusinessException("parseExpression error: " + originalField);
+ }
+ }
+
+ /**
+ * 根据函数参数判断索引表查询是否有效: 只支持0或1(判断是否在schema中)个参数, 其它均设为无效
+ *
+ * @param schema
+ * @param function
+ */
+ private boolean getValidityByFunctionParamsInSchema(Schema schema, Function function) {
+ ExpressionList parameters = function.getParameters();
+ if (StringUtil.isEmpty(parameters)) {
+ return true;
+ } else {
+ List<Expression> expressions = parameters.getExpressions();
+ if (expressions.size() != 1) {
+ return false;
+ }
+ if (!isFieldOfSchema(schema, String.valueOf(expressions.get(0)))) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /**
+ * 根据左右表达式判断索引表查询是否有效
+ *
+ * @param masterTableSchema
+ * @param indexTableSchema
+ * @param leftExpression
+ * @param rightExpression
+ */
+ private void setValidityByLRExpressionInSchema(Schema masterTableSchema, Schema indexTableSchema, Expression leftExpression, Expression rightExpression) {
+ String leftStr = String.valueOf(leftExpression);
+ String rightStr = String.valueOf(rightExpression);
+ if (leftExpression instanceof Function && rightExpression instanceof Function) {
+ setValidityByFunAndFunInSchema(masterTableSchema, indexTableSchema, (Function) leftExpression, (Function) rightExpression);
+ } else if (!(leftExpression instanceof Function) && rightExpression instanceof Function) {
+ setValidityByFunctionAndStrInSchema(masterTableSchema, indexTableSchema, (Function) rightExpression, leftStr);
+ } else if (leftExpression instanceof Function && !(rightExpression instanceof Function)) {
+ setValidityByFunctionAndStrInSchema(masterTableSchema, indexTableSchema, (Function) leftExpression, rightStr);
+ } else {
+ setValidityBuStrAndStrInSchema(masterTableSchema, indexTableSchema, leftStr, rightStr);
+ }
+ }
+
+ /**
+ * 操作符左右两边都是非函数类型(转String)
+ *
+ * @param masterTableSchema
+ * @param indexTableSchema
+ * @param leftStr
+ * @param rightStr
+ */
+ private void setValidityBuStrAndStrInSchema(Schema masterTableSchema, Schema indexTableSchema, String leftStr, String rightStr) {
+ if (isFieldOfSchema(masterTableSchema, leftStr) && !isFieldOfSchema(indexTableSchema, leftStr)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ if (isFieldOfSchema(masterTableSchema, rightStr) && !isFieldOfSchema(indexTableSchema, rightStr)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ if (!isFieldOfSchema(masterTableSchema, leftStr) && !isFieldOfSchema(masterTableSchema, rightStr)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ }
+
+ /**
+ * 操作符左右两边都是函数
+ *
+ * @param masterTableSchema
+ * @param indexTableSchema
+ * @param leftExpression
+ * @param rightExpression
+ */
+ private void setValidityByFunAndFunInSchema(Schema masterTableSchema, Schema indexTableSchema, Function leftExpression, Function rightExpression) {
+ boolean validLeftInMaster = getValidityByFunctionParamsInSchema(masterTableSchema, leftExpression);
+ boolean validLeftInIndex = getValidityByFunctionParamsInSchema(indexTableSchema, leftExpression);
+ if (validLeftInMaster && !validLeftInIndex) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ boolean validRightInMaster = getValidityByFunctionParamsInSchema(masterTableSchema, rightExpression);
+ boolean validRightInIndex = getValidityByFunctionParamsInSchema(indexTableSchema, rightExpression);
+ if (validRightInMaster && !validRightInIndex) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ if (!validLeftInMaster && !validRightInMaster) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ }
+
+ /**
+ * 操作符左右一边是函数类型一边是非函数(转String)
+ *
+ * @param masterTableSchema
+ * @param indexTableSchema
+ * @param function
+ * @param str
+ */
+ private void setValidityByFunctionAndStrInSchema(Schema masterTableSchema, Schema indexTableSchema, Function function, String str) {
+ boolean validFunInMaster = getValidityByFunctionParamsInSchema(masterTableSchema, function);
+ boolean validFunInIndex = getValidityByFunctionParamsInSchema(indexTableSchema, function);
+ if (validFunInMaster && !validFunInIndex) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ if (isFieldOfSchema(masterTableSchema, str) && !isFieldOfSchema(indexTableSchema, str)) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ if (!isFieldOfSchema(masterTableSchema, str) && !validFunInMaster) {
+ setSubIndexValidFlag(false);
+ return;
+ }
+ }
+
+ private void setSubIndexValidFlag(Boolean subIndexValidFlag) {
+ this.subIndexValidFlag = subIndexValidFlag;
+ }
+
+ private Boolean getSubIndexValidFlag() {
+ return subIndexValidFlag;
+ }
+
+ public String build() {
+ return sql;
+ }
+
+
+ }
+
+
+ /**
+ * 执行SQL获取查询结果,此数据为数据库返回的原始结果。
+ * 主要目标统一封装BaseResult对象,便于后续对结果进行业务模型构建。
+ *
+ * @param sql
+ * @param message 携带消息
+ * @return
+ */
+ @Override
+ public BaseResult generateBaseResult(String sql, Optional<String> message) {
+
+ Map<String, String> results = executeHttpGet(sql);
+
+ if (results.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+
+ baseResult = BaseResultGenerator.generate(
+ Integer.valueOf(results.get("status")),
+ ResultCodeEnum.EXECUTE_SUCCESS.getCode(),
+ message.get(),
+ JsonMapper.fromJsonString(results.get("result"), Map.class),
+ null,
+ null,
+ QueryFormatEnum.JSON.getValue());
+ } else {
+ baseResult = BaseResultGenerator.generate(Integer.valueOf(results.get("status")), ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(), message.get(),
+ results.get("result"), null, null, param.getFormat());
+ }
+ return build();
+ }
+
+
+ private BaseResult build() {
+
+ Object dataObject = baseResult.getData();
+ if (baseResult.isSuccess()) {
+ if (StringUtil.isBlank(baseResult.getMessage())) {
+ baseResult.setMessage("ok");
+ }
+ Map<String, Object> resultMap = (Map<String, Object>) dataObject;
+ Map<String, Object> statisticMap = (Map<String, Object>) resultMap.get("statistics");
+ Map<String, Object> statistics = Maps.newLinkedHashMap();
+ statistics.put("elapsed", Math.round(Double.parseDouble(String.valueOf(statisticMap.get("elapsed"))) * 1000));
+ statistics.put("rows_read", statisticMap.get("rows_read"));
+ baseResult.setData(resultMap.get("data"));
+ baseResult.setMeta(resultMap.get("meta"));
+ baseResult.setStatistics(statistics);
+ } else if (baseResult.getStatus().equals(HttpStatus.SC_NOT_FOUND)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_NOT_FOUND,
+ ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), StringUtil.isEmpty(dataObject) ? "System Runtime Exception, Please contact Galaxy Data Platform Project manager" : String.valueOf(dataObject));
+ } else if (baseResult.getStatus().equals(HttpStatus.SC_INTERNAL_SERVER_ERROR)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(),
+ StringUtil.isEmpty(dataObject) ? "System Runtime Exception, Please contact Galaxy Data Platform Project manager" : String.valueOf(dataObject));
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(),
+ StringUtil.isEmpty(dataObject) ? "System Runtime Exception, Please contact Galaxy Data Platform Project manager " : String.valueOf(dataObject));
+ }
+ return baseResult;
+ }
+
+
+
+
+
+ /**
+ * 做数据集限制: 将最内层sql的表名, 替换成(select * from tableName limit XXX) as alias
+ * 涉及from 和 where中存在子查询
+ *
+ * @param sql
+ * @return
+ * @throws JSQLParserException
+ */
+ private SelectBody parserAndUpdateSql(String sql) throws JSQLParserException {
+ Statement parse = CCJSqlParserUtil.parse(sql);
+ if (parse instanceof Select) {
+ Select select = (Select) parse;
+ SelectBody selectBody = select.getSelectBody();
+ if (selectBody instanceof PlainSelect) {
+ PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
+ FromItem fromItem = plainSelect.getFromItem();
+ if (fromItem instanceof SubSelect) {
+ SubSelect subSelect = (SubSelect) plainSelect.getFromItem();
+ subSelect.setSelectBody(parserAndUpdateSql(subSelect.getSelectBody().toString()));
+ } else if (fromItem instanceof Table) {
+ Table table = (Table) fromItem;
+ plainSelect.setFromItem(generateDataSetSql(table.getName(), table.getAlias() != null ? table.getAlias().getName() : table.getName()));
+ }
+ parseWhereAndUpdate(plainSelect.getWhere());
+ return plainSelect;
+ } else if (selectBody instanceof SetOperationList) {
+ SetOperationList setOperationList = (SetOperationList) selectBody;
+ List<SelectBody> selects = setOperationList.getSelects();
+ for (int i = 0; i < selects.size(); i++) {
+ selects.set(i, parserAndUpdateSql(selects.get(i).toString()));
+ }
+ return setOperationList;
+ } else {
+ throw new BusinessException("Only support selectBody operation: PlainSelect or SetOperationList");
+ }
+ }
+ throw new BusinessException("Only support statement operation as select");
+ }
+
+ /**
+ * 将where中子查询语句表名更新为数据集形式,类同from中表的替换
+ *
+ * @param whereExpression
+ * @throws JSQLParserException
+ */
+ private void parseWhereAndUpdate(Expression whereExpression) throws JSQLParserException {
+ if (whereExpression instanceof ComparisonOperator) {
+ ComparisonOperator whereOperator = (ComparisonOperator) whereExpression;
+ Expression left = whereOperator.getLeftExpression();
+ setSelectBody(left);
+ Expression right = whereOperator.getRightExpression();
+ setSelectBody(right);
+ } else if (whereExpression instanceof InExpression) {
+ InExpression inExpression = (InExpression) whereExpression;
+ Expression leftExpression = inExpression.getLeftExpression();
+ setSelectBody(leftExpression);
+ ItemsList rightItemsList = inExpression.getRightItemsList();
+ if (rightItemsList instanceof SubSelect) {
+ SubSelect subSelect = (SubSelect) rightItemsList;
+ setSelectBody(subSelect);
+ }
+ } else if (whereExpression instanceof Between) {
+ Between whereBetween = (Between) whereExpression;
+ Expression betweenExpressionStart = whereBetween.getBetweenExpressionStart();
+ setSelectBody(betweenExpressionStart);
+ Expression betweenExpressionEnd = whereBetween.getBetweenExpressionEnd();
+ setSelectBody(betweenExpressionEnd);
+ } else if (whereExpression instanceof AndExpression) {
+ AndExpression whereAnd = (AndExpression) whereExpression;
+ parseWhereAndUpdate(whereAnd.getLeftExpression());
+ parseWhereAndUpdate(whereAnd.getRightExpression());
+ } else if (whereExpression instanceof OrExpression) {
+ OrExpression whereOr = (OrExpression) whereExpression;
+ parseWhereAndUpdate(whereOr.getLeftExpression());
+ parseWhereAndUpdate(whereOr.getRightExpression());
+ } else if (whereExpression instanceof Parenthesis) {
+ Parenthesis whereExpressionParenthesis = (Parenthesis) whereExpression;
+ Expression expression = whereExpressionParenthesis.getExpression();
+ parseWhereAndUpdate(expression);
+ }
+ }
+
+ private void setSelectBody(Expression expression) throws JSQLParserException {
+ if (expression instanceof SubSelect) {
+ SubSelect subSelect = (SubSelect) expression;
+ SelectBody selectBody = subSelect.getSelectBody();
+ subSelect.setSelectBody(parserAndUpdateSql(selectBody.toString()));
+ }
+ }
+
+ /**
+ * 生成数据集: 以FromItem对象形式的数据集表 sql,用来替换table
+ *
+ * @param tableName
+ * @param alias
+ * @return
+ * @throws JSQLParserException
+ */
+ private FromItem generateDataSetSql(String tableName, String alias) throws JSQLParserException {
+ String sql = String.format("SELECT 1 FROM (SELECT * FROM %s LIMIT %s ) as %s ",
+ tableName, 10000, alias);
+ Statement parse = CCJSqlParserUtil.parse(sql);
+ Select select = (Select) parse;
+ PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
+ return plainSelect.getFromItem();
+ }
+
+ /**
+ * ClickHouse Http Query Interface
+ *
+ * @param sql SQL语句
+ * @return
+ */
+ private Map<String, String> executeHttpGet(String sql) {
+ StringBuilder urlBuilder = new StringBuilder("http://")
+ .append(clickHouseHttpSource.getUrl()).append("/?");
+
+ ClickHouseHttpQuery clickHouseHttpQuery = buildHttpQueryParameter(sql);
+
+ log.info("DB Engine is :{}, Execute Http Query is: {}", DBTypeEnum.CLICKHOUSE.getValue(), urlBuilder.toString() +
+ Encodes.urlDecode(clickHouseHttpQuery.getQueryParameter()));
+
+ List<NameValuePair> values = URLEncodedUtils.parse(clickHouseHttpQuery.getQueryParameter(), Charset.forName("UTF-8"));
+
+ return httpClientService.httpGet(urlBuilder.toString() + URLEncodedUtils.format(values, "utf-8"), clickHouseHttpQuery.getSocketTimeOut());
+ }
+
+ private ClickHouseHttpQuery buildHttpQueryParameter(String sql) {
+ ClickHouseHttpQuery clickHouseHttpQuery = new ClickHouseHttpQuery();
+ StringBuilder queryParameterBuilder = new StringBuilder(1024);
+ String dbName = metadataService.getDBNameByTableName(param.getTableName());
+
+ if (dbName.equalsIgnoreCase(clickHouseHttpSource.getSystemDBName())) {
+ clickHouseHttpQuery.setSocketTimeOut(httpConfig.getCkLongTermAccountSocketTimeOut());
+ queryParameterBuilder.append("user=")
+ .append(clickHouseHttpSource.getLongTermAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getLongTermAccount().getPassword()).append("&")
+ .append("database=").append(dbName).append("&");
+ } else if (QueryOptionEnum.LONG_TERM.getValue().equalsIgnoreCase(param.getOption())) {
+ clickHouseHttpQuery.setSocketTimeOut(httpConfig.getCkLongTermAccountSocketTimeOut());
+ queryParameterBuilder.append("user=")
+ .append(clickHouseHttpSource.getLongTermAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getLongTermAccount().getPassword()).append("&")
+ .append("database=").append(dbName).append("&")
+ .append("query_id=").append(ReportCacheUtils.getQueryId(param.getResultId(), param.getQuery())).append("&");
+ } else {
+ clickHouseHttpQuery.setSocketTimeOut(httpConfig.getCkRealTimeAccountSocketTimeOut());
+ queryParameterBuilder.append("user=")
+ .append(clickHouseHttpSource.getRealTimeAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getRealTimeAccount().getPassword()).append("&")
+ .append("database=").append(dbName).append("&");
+ }
+
+ queryParameterBuilder.append("query=").append(sql).append(" FORMAT ").append(QueryFormatEnum.JSON.getValue().toUpperCase()).append(" ;");
+ clickHouseHttpQuery.setQueryParameter(queryParameterBuilder.toString());
+ return clickHouseHttpQuery;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/Dialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/Dialect.java
new file mode 100644
index 0000000..790e880
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/Dialect.java
@@ -0,0 +1,54 @@
+package com.mesalab.qgw.dialect;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+
+public interface Dialect {
+
+ /**
+ * 数据库本身是否支持分页当前的分页查询方式
+ * 如果数据库不支持的话,则不进行数据库分页
+ *
+ * @return true:支持当前的分页查询方式
+ */
+ boolean supportsLimit();
+
+ /**
+ * 执行SQL语法检查
+ * @return
+ */
+ BaseResult executeSyntaxCheck();
+
+ /**
+ * 执行查询操作
+ * @return
+ */
+ BaseResult executeQuery();
+
+
+ /**
+ * 执行数据库系统管理操作,包含 Show/Describe/Kill等
+ * @return
+ */
+
+ BaseResult executeAdministrativeQuery();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java
new file mode 100644
index 0000000..a33f12d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/DruidDialect.java
@@ -0,0 +1,425 @@
+package com.mesalab.qgw.dialect;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Maps;
+import com.mesalab.calcite.storage.DataTypeMapping;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.DBTypeEnum;
+import com.mesalab.common.enums.QueryFormatEnum;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.common.utils.SQLFunctionUtil;
+import com.mesalab.common.utils.SQLHelper;
+import com.mesalab.common.utils.SpringContextUtil;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.DruidIoHttpSource;
+import com.mesalab.qgw.model.api.EngineConfigSource;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.select.*;
+import org.apache.http.HttpStatus;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class DruidDialect extends AbstractDataSourceDialect {
+
+ private DruidIoHttpSource druidIoHttpSource = (DruidIoHttpSource) SpringContextUtil.getBean("druidIoHttpSource");
+ private HttpClientService httpClientService = (HttpClientService) SpringContextUtil.getBean("httpClientService");
+ private EngineConfigSource engineConfigSource = (EngineConfigSource) SpringContextUtil.getBean("engineConfigSource");
+ private HttpConfig httpConfig = (HttpConfig) SpringContextUtil.getBean("httpConfig");
+ private int pageOffset;
+ private Stopwatch watch = Stopwatch.createUnstarted();
+ public ApiParam param;
+ public BaseResult baseResult;
+
+ public DruidDialect(ApiParam param) {
+ this.param = param;
+ }
+
+ @Override
+ void init() {
+ if (StringUtil.isNotEmpty(param.getDbQuerySource())) {
+ param.setSql(param.getDbQuerySource().getSqlBody());
+ } else {
+ param.setSql(param.getQuery());
+ }
+ baseResult = BaseResultGenerator.success();
+ }
+
+
+
+ @Override
+ public boolean supportsLimit() {
+ return true;
+ }
+
+
+ @Override
+ public String convertQuery(String sql) {
+ return new Converter(sql).generateStandard().generateDateFunction().build();
+
+ }
+
+ @Override
+ public String getBestQuery() {
+
+ return new Optimizer().generateQueryLimit().generateSQL().build();
+
+ }
+
+ @Override
+ public String getOriginQuery() {
+ return param.getQuery();
+ }
+
+ /**
+ * 获取语法检测sql
+ *
+ * @return
+ */
+ @Override
+ public String getSyntaxCheckQuery() {
+ String sql = param.getDbQuerySource().getSqlBody();
+ try {
+ sql = String.valueOf(parserAndUpdateSql(sql));
+ } catch (Exception e) {
+ log.error("syntax-check sql error {}, execute original sql: {}, error is: {} ",
+ sql, sql = param.getDbQuerySource().getSqlBody(), e.getMessage() == null ? e.getCause() : e.getMessage());
+ }
+ return sql;
+ }
+
+
+
+ /*@Override
+ public BaseResult executeQuery() {
+
+ watch.start();
+ return generateBaseResult(convertQuery(findBestQuery()), Optional.of("OK")).build();
+
+ }
+
+ @Override
+ public BaseResult executeAdministrativeQuery() {
+ return generateBaseResult(param.getQuery(), Optional.of("OK")).build();
+ }
+
+ @Override
+ public BaseResult executeSyntaxCheck() {
+ String query = convertQuery(getSyntaxCheckSql());
+
+ log.info("option=syntax-check: original sql: {}, after transformation(return message) info: {}", param.getQuery(), query);
+
+ return generateBaseResult(query, Optional.of(query)).build();
+
+ }*/
+
+
+ /**
+ * Druid Http Query Interface
+ *
+ * @param sql SQL语句
+ * @return
+ */
+ private Map<String, String> executeHttpPost(String sql) {
+ StringBuilder urlBuilder = new StringBuilder("http://").append(druidIoHttpSource.getUrl());
+ DruidQueryParam druidQueryParam = new DruidQueryParam();
+ druidQueryParam.setQuery(sql);
+ druidQueryParam.getContext().put("skipEmptyBuckets", druidIoHttpSource.getSkipEmptyBuckets());
+ druidQueryParam.setResultFormat("object");
+
+ log.info("DB Engine is :{}, Execute Query is: {}", DBTypeEnum.DRUID.getValue(), JsonMapper.toJsonString(druidQueryParam));
+ int socketTimeOut = httpConfig.getDruidSocketTimeOut();
+ return httpClientService.httpPost(urlBuilder.toString(), JsonMapper.toJsonString(druidQueryParam), socketTimeOut);
+ }
+
+ @Override
+ public BaseResult generateBaseResult(String sql, Optional<String> message) {
+ watch.start();
+
+ Map<String, String> results = executeHttpPost(sql);
+
+ if (results.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ baseResult = BaseResultGenerator.generate(Integer.valueOf(results.get("status")), ResultCodeEnum.EXECUTE_SUCCESS.getCode(), message.get(),
+ (List<Object>) JsonMapper.fromJsonString(results.get("result"), Object.class), null, null, QueryFormatEnum.JSON.getValue());
+ } else {
+ baseResult = BaseResultGenerator.generate(Integer.valueOf(results.get("status")), ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(), results.get("message"),
+ results.get("result"), null, null, param.getFormat());
+ }
+
+ return build();
+ }
+
+
+ private BaseResult build() {
+
+ Object dataObject = baseResult.getData();
+
+ if (baseResult.isSuccess()) {
+ if (StringUtil.isBlank(baseResult.getMessage())) {
+ baseResult.setMessage("ok");
+ }
+ List<Object> allResults = (List<Object>) dataObject;
+ if (pageOffset > 0 && StringUtil.isNotEmpty(allResults)) {
+ if (pageOffset >= allResults.size()) {
+ allResults = new ArrayList<>();
+ } else {
+ allResults = allResults.subList(pageOffset, allResults.size());
+ }
+ }
+ Map<String, Object> statistics = Maps.newLinkedHashMap();
+ statistics.put("elapsed", watch.elapsed(TimeUnit.MILLISECONDS));
+ statistics.put("rows_read", allResults.size());
+ baseResult.setData(allResults);
+ baseResult.setMeta(getMeta(allResults));
+ baseResult.setStatistics(statistics);
+ } else if (baseResult.getStatus().equals(HttpStatus.SC_NOT_FOUND)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_NOT_FOUND, ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(),
+ StringUtil.isEmpty(dataObject) ? "System Runtime Exception,Please contact Galaxy Data Platform Project manager. " : String.valueOf(dataObject));
+ } else if (baseResult.getStatus().equals(HttpStatus.SC_INTERNAL_SERVER_ERROR)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(),
+ StringUtil.isEmpty(dataObject) ? "System Runtime Exception,Please contact Galaxy Data Platform Project manager. " : String.valueOf(dataObject));
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, ResultCodeEnum.SQL_EXECUTION_ERROR.getCode(),
+ StringUtil.isEmpty(dataObject) ? "System Runtime Exception,Please contact Galaxy Data Platform Project manager. " : String.valueOf(dataObject));
+ }
+ return baseResult;
+ }
+
+
+
+
+ /**
+ * 做时间范围条件过滤: 去除原有最内层条件, 重新添加时间范围
+ *
+ * @param sql
+ * @return
+ * @throws JSQLParserException
+ */
+ private SelectBody parserAndUpdateSql(String sql) throws JSQLParserException {
+ Statement parse = CCJSqlParserUtil.parse(sql);
+ if (parse instanceof Select) {
+ Select select = (Select) parse;
+ SelectBody selectBody = select.getSelectBody();
+ if (selectBody instanceof PlainSelect) {
+ PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
+ FromItem fromItem = plainSelect.getFromItem();
+ if (fromItem instanceof SubSelect) {
+ SubSelect subSelect = (SubSelect) plainSelect.getFromItem();
+ subSelect.setSelectBody(parserAndUpdateSql(subSelect.getSelectBody().toString()));
+ } else if (fromItem instanceof Table) {
+ plainSelect.setWhere(generateDataSetSql());
+ return plainSelect;
+ }
+ return plainSelect;
+ } else if (selectBody instanceof SetOperationList) {
+ SetOperationList setOperationList = (SetOperationList) selectBody;
+ List<SelectBody> selects = setOperationList.getSelects();
+ for (int i = 0; i < selects.size(); i++) {
+ selects.set(i, parserAndUpdateSql(selects.get(i).toString()));
+ }
+ return setOperationList;
+ } else {
+ throw new BusinessException("Only support selectBody operation: PlainSelect or SetOperationList");
+ }
+ }
+ throw new BusinessException("Only support statement operation as select");
+ }
+
+
+ /**
+ * 生成where条件: 以Expression对象形式
+ *
+ * @return
+ * @throws JSQLParserException
+ */
+ private Expression generateDataSetSql() throws JSQLParserException {
+ String sql = String.format("SELECT * FROM tableName WHERE %s >= CURRENT_TIMESTAMP - INTERVAL '%s' HOUR ", param.getDbQuerySource().getPartitionKey(), 12);
+ Statement parse = CCJSqlParserUtil.parse(sql);
+ Select select = (Select) parse;
+ PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
+ return plainSelect.getWhere();
+ }
+
+ private List getMeta(List<Object> results) {
+ List meta = new ArrayList<Map<String, String>>();
+ if (results.size() > 0) {
+ Map<String, Object> map = (Map) results.get(0);
+ for (String key : map.keySet()) {
+ Object value = map.get(key);
+ Map<String, String> temp = new HashMap<>();
+ temp.put("name", key);
+ if (value instanceof Integer) {
+ temp.put("type", DataTypeMapping.BIGINT);
+ } else if (value instanceof Double) {
+ temp.put("type", DataTypeMapping.DOUBLE);
+ } else {
+ temp.put("type", DataTypeMapping.VARCHAR);
+ }
+ meta.add(temp);
+ }
+ }
+ return meta;
+ }
+
+ class Converter {
+ String sql = null;
+
+ public Converter(String sql) {
+ this.sql = sql;
+ }
+
+ /**
+ * SQL转换为DRUID语法格式
+ * 1. 不支持limit offset,rows 转为 limit rows
+ *
+ * @return
+ */
+ public Converter generateStandard() {
+ SQLQuerySource dbQuerySource = param.getDbQuerySource();
+ if (StringUtil.isNotBlank(dbQuerySource.getLimit()) &&
+ dbQuerySource.getLimit().split(",").length >= 2) {
+
+ String[] limits = dbQuerySource.getLimit().trim().split(",");
+ int offset = Integer.valueOf(limits[0].trim());
+ int rowNum = Integer.valueOf(limits[1].trim());
+ pageOffset = offset;
+ sql = SQLHelper.getLimitString(dbQuerySource.getSqlBody(), 0, (offset + rowNum));
+ }
+ return this;
+ }
+
+
+ public Converter generateDateFunction() {
+
+ try {
+ sql = SQLFunctionUtil.generateDateFunction(sql, DBTypeEnum.DRUID.getValue());
+ } catch (Exception ex) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "参数校验:SQL 日期函数解析错误", ex);
+ }
+
+ return this;
+ }
+
+
+ public String build() {
+ return sql;
+ }
+ }
+
+
+ class Optimizer {
+ String sql = null;
+
+ /**
+ * 对SQL最内层的结果数据集进行限制
+ * 参见查询网关系统参数:engine.maxCacheNum
+ *
+ * @return
+ */
+ public Optimizer generateQueryLimit() {
+
+ setDefaultResultRows(StringUtil.isEmpty(param.getEngineQuerySource()) ? param.getDbQuerySource() : param.getEngineQuerySource(), engineConfigSource.getDefaultResultNum());
+
+ setMaxCacheResultRows(param.getDbQuerySource(), engineConfigSource.getMaxCacheNum());
+
+
+ return this;
+ }
+
+
+ private void setDefaultResultRows(SQLQuerySource sqlQuerySource, int defaultResultRows) {
+ if (StringUtil.isBlank(sqlQuerySource.getLimit())) {
+ sqlQuerySource.setSqlBody(sqlQuerySource.getSqlBody() + " limit " + defaultResultRows);
+ sqlQuerySource.setLimit(String.valueOf(defaultResultRows));
+ }
+
+ }
+
+ /**
+ * 设置最大缓存数据集
+ *
+ * @param sqlQuerySource
+ * @return
+ */
+ private void setMaxCacheResultRows(SQLQuerySource sqlQuerySource, int maxCacheResultRows) {
+ SQLQuerySource innerSqlQuerySource = sqlQuerySource;
+ while (StringUtil.isNotEmpty(innerSqlQuerySource.getSubSelect())) {
+ innerSqlQuerySource = innerSqlQuerySource.getSubSqlQuerySources().get(0);
+ }
+
+ if (!innerSqlQuerySource.isEnableLimit()) {
+ return;
+ }
+
+ String orginInnerSql = innerSqlQuerySource.getSqlBody();
+
+ String limitInnerSql = innerSqlQuerySource.getSqlBody();
+ if (StringUtil.isNotBlank(innerSqlQuerySource.getLimit())) {
+
+ String[] limits = innerSqlQuerySource.getLimit().split(",");
+
+ if (Integer.valueOf(limits[limits.length - 1]) > maxCacheResultRows) {
+ limits[limits.length - 1] = String.valueOf(maxCacheResultRows);
+
+ if (limits.length == 2) {
+ limitInnerSql = SQLHelper.getLimitString(limitInnerSql, Integer.valueOf(limits[0]), Integer.valueOf(limits[1]));
+ } else {
+ limitInnerSql = SQLHelper.getLimitString(limitInnerSql, 0, Integer.valueOf(limits[0]));
+ }
+
+ innerSqlQuerySource.setLimit(String.join(",", limits).toString());
+ innerSqlQuerySource.setSqlBody(limitInnerSql);
+
+ }
+
+ } else {
+ limitInnerSql = innerSqlQuerySource.getSqlBody() + " limit " + maxCacheResultRows;
+ innerSqlQuerySource.setLimit(String.valueOf(maxCacheResultRows));
+ innerSqlQuerySource.setSqlBody(limitInnerSql);
+
+ }
+
+ if (StringUtil.isNotEmpty(sqlQuerySource.getSubSqlQuerySources())) {
+ sqlQuerySource.setSqlBody(sqlQuerySource.getSqlBody().replace(orginInnerSql, limitInnerSql));
+ }
+
+ }
+
+ public Optimizer generateSQL() {
+ SQLQuerySource sqlQuerySource = param.getDbQuerySource();
+ sql = sqlQuerySource.getSqlBody();
+ return this;
+ }
+
+ public String build() {
+ return sql;
+ }
+
+
+ }
+
+
+ @Data
+ class DruidQueryParam {
+ private String query;
+ private Map<String, String> context = Maps.newHashMap();
+ private String resultFormat;
+
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java
new file mode 100644
index 0000000..fe3649f
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/dialect/FederationDialect.java
@@ -0,0 +1,151 @@
+package com.mesalab.qgw.dialect;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+import com.mesalab.calcite.CalciteMemoryUtils;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.enums.QueryFormatEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.mesalab.qgw.model.api.udf.UDF;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+
+
+import javax.annotation.Nullable;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 联邦查询-基于Calcite支持多源联合查询
+ */
+@Slf4j
+public class FederationDialect extends AbstractEngineDialect{
+ private Stopwatch watch = Stopwatch.createUnstarted();
+ public ApiParam param;
+ public BaseResult baseResult;
+
+ public FederationDialect(ApiParam param, BaseResult result) {
+ this.param = param;
+ this.baseResult = result;
+ }
+ @Override
+ public void init() {
+ if (StringUtil.isNotEmpty(param.getEngineQuerySource())) {
+ param.setQuery(param.getEngineQuerySource().getSqlBody());
+ }
+ }
+
+
+ @Override
+ public boolean supportsLimit() {
+ return false;
+ }
+
+
+
+ @Override
+ public boolean isExecute() {
+ return baseResult.isSuccess() ? true : false ;
+ }
+
+
+ @Override
+ public BaseResult generateBaseResult() {
+ try {
+ if (!isExecute()) {
+ return baseResult;
+ }
+
+ watch.start();
+ if (StringUtil.isNotEmpty(param.getEngineQuerySource())) {
+ SQLQuerySource sqlQuerySource = param.getEngineQuerySource();
+ Map resultMap = CalciteMemoryUtils.executeMemoryQuery(sqlQuerySource.getTableName(),
+ (List<Map<String, String>>) baseResult.getMeta(),
+ (List<Map<String, Object>>) baseResult.getData(), param.getQuery());
+ baseResult.setData(resultMap.get("data"));
+ baseResult.setMeta(resultMap.get("meta"));
+ }
+ log.debug("Calcite execute time :" + watch.elapsed().toMillis()/1000 + "s");
+
+ } catch (Exception ex) {
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(),
+ ResultCodeEnum.ENGINE_STATISTICS_ERROR.getCode(), "Engine execute memory-query error:", ex);
+ }
+ return build();
+ }
+
+
+
+ private BaseResult build() {
+
+ long executeTime = watch.elapsed(TimeUnit.MILLISECONDS);
+ Map<String, Object> statisticMap = (Map<String, Object>) baseResult.getStatistics();
+ statisticMap.put("elapsed", Long.parseLong(String.valueOf(statisticMap.get("elapsed"))) + executeTime);
+ if (StringUtil.isEmpty(baseResult.getData())) {
+ statisticMap.put("result_size", 0);
+ statisticMap.put("result_rows", 0);
+ } else {
+ statisticMap.put("result_size", JsonMapper.toJsonString(baseResult.getData()).getBytes().length);
+ statisticMap.put("result_rows", ((List) baseResult.getData()).size());
+ }
+
+ if (param.getFormat().equalsIgnoreCase(QueryFormatEnum.CSV.getValue())) {
+ convertJsonToCSV();
+ }
+ baseResult.setFormatType(param.getFormat());
+
+ log.debug("Execute build Time : {}", watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0);
+ return baseResult;
+ }
+
+ @Override
+ public void executeUDF() {
+ if (isExecute()) {
+ SQLQuerySource sqlQuerySource = param.getDbQuerySource();
+ Set<UDF> udfSet = sqlQuerySource.getUdfSet();
+ for (UDF udf : udfSet) {
+ List<Map<String, String>> targetResult = (List<Map<String, String>>) udf.execute(sqlQuerySource,
+ (List<Object>) baseResult.getData());
+ baseResult.setData(targetResult);
+ }
+ }
+
+ }
+
+
+ private void convertJsonToCSV() {
+
+ List<String> results = Lists.transform( (List<Map<String, Object>>) baseResult.getData(), new Function<Map<String, Object>, String>() {
+
+ @Override
+ public String apply(@Nullable Map<String, Object> input) {
+ return Joiner.on(",").useForNull("").join(input.values());
+ }
+ });
+
+ List<Object> metas = Lists.transform((List<Map<String, Object>>) baseResult.getMeta(), new Function<Map<String, Object>, Object>() {
+
+ @Override
+ public Object apply(@Nullable Map<String, Object> input) {
+ return input.get("name");
+ }
+ });
+
+ baseResult.setData(Joiner.on("\n").useForNull("").join(results));
+ baseResult.setMeta(Joiner.on(",").useForNull("").join(metas));
+ }
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java
new file mode 100644
index 0000000..9e5582f
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/interceptor/QuerySubmitInterceptor.java
@@ -0,0 +1,90 @@
+package com.mesalab.qgw.interceptor;
+
+import com.google.common.cache.CacheStats;
+import com.mesalab.common.utils.QueryCacheUtils;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.qgw.model.api.CachedSubmitCheck;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+@Slf4j
+public class QuerySubmitInterceptor extends HandlerInterceptorAdapter {
+
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+
+ if (handler instanceof HandlerMethod) {
+
+ HandlerMethod handlerMethod = (HandlerMethod) handler;
+
+ CachedSubmitCheck submitCheck = handlerMethod.getMethodAnnotation(CachedSubmitCheck.class);
+
+ if (submitCheck == null || StringUtil.isBlank(request.getQueryString())) {
+ return true;
+ }
+
+ String clientId = this.getClientId();
+ String queryKey = DigestUtils.md5Hex(request.getQueryString());
+
+
+ log.debug("Query Submit Check,ClientId:{}, QueryKey:{}", clientId, DigestUtils.md5Hex(queryKey));
+ Object result = QueryCacheUtils.get(queryKey);
+ if (StringUtil.isNotEmpty(result)) {
+
+ CacheStats stats = QueryCacheUtils.getStats();
+ log.info(" Query Repeat Submit Stat,QEQ_count:{},HIT_count:{},HIT_rate:{}, MISS_count:{}",
+ stats.requestCount(), stats.hitCount(), stats.hitRate(), stats.missCount());
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/json;charset=UTF-8");
+ response.getWriter().write(JsonMapper.toJsonString(result));
+ return false;
+
+ }
+ }
+ return true;
+ }
+
+
+
+ private UserMethodKey getUserMethodKey(String clientId, String queryString) {
+
+ UserMethodKey k = new UserMethodKey();
+ k.setClientId(clientId);
+ k.setQueryString(queryString);
+ return k;
+ }
+
+ private String getClientId() {
+
+ return RequestContextHolder.getRequestAttributes().getSessionId();
+
+ }
+
+
+
+
+ @Data
+ private static class UserMethodKey {
+ private String clientId;
+ private String queryString;
+
+ @Override
+ public String toString() {
+ return DigestUtils.md5Hex(clientId + queryString);
+ }
+ }
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java
new file mode 100644
index 0000000..14c6341
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ApiParam.java
@@ -0,0 +1,42 @@
+package com.mesalab.qgw.model.api;
+
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.nutz.json.JsonIgnore;
+
+import java.io.Serializable;
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ApiParam implements Serializable {
+
+ private String query;
+ private String option;
+ private String format;
+ private String schema;
+ private String tableName;
+ private String dbType;// 数据库类型
+ private String dialectDBType; //方言数据库类型,用于SQL格式解析校验
+ private String reportId;//离线统计报告唯一ID
+ private String resultId;//离线统计报告结果ID
+
+ private String sql;//当前执行的SQL
+
+ private SQLQuerySource engineQuerySource; //网关引擎处理SQL对象
+
+ private SQLQuerySource dbQuerySource; //下沉数据源引擎的SQL对象
+
+
+ public String getResultId() {
+
+ return StringUtil.isNotBlank(reportId) ? reportId : resultId;
+ }
+
+ public void setResultId(String resultId) {
+ this.resultId = resultId;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditLog.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditLog.java
new file mode 100644
index 0000000..c602b3b
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditLog.java
@@ -0,0 +1,14 @@
+package com.mesalab.qgw.model.api;
+
+
+import java.lang.annotation.*;
+
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AuditLog {
+
+ String value();
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditServiceLog.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditServiceLog.java
new file mode 100644
index 0000000..914c106
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/AuditServiceLog.java
@@ -0,0 +1,34 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+
+@Data
+public class AuditServiceLog {
+
+ private String annotation;
+
+ private String clientIp;
+
+ private long exeTime;
+
+ private String remoteAddr;
+
+ private String param;
+
+ private String url;
+
+ private String method;
+
+ private String classMethod;
+
+ private String queryKey;
+
+ private String dbType;
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/CachedSubmitCheck.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/CachedSubmitCheck.java
new file mode 100644
index 0000000..97ab332
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/CachedSubmitCheck.java
@@ -0,0 +1,11 @@
+package com.mesalab.qgw.model.api;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface CachedSubmitCheck {
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpQuery.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpQuery.java
new file mode 100644
index 0000000..fd18f4e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpQuery.java
@@ -0,0 +1,17 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+/**
+ * @Date: 2020-09-22 10:45
+ * @Author : liuyongqiang
+ * @ClassName : ClickHouseHttpQuery
+ * @Description : ClickHouseHttpQuery
+ */
+@Data
+public class ClickHouseHttpQuery {
+ //查询参数
+ private String queryParameter;
+ //响应超时时间
+ private int socketTimeOut;
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpSource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpSource.java
new file mode 100644
index 0000000..3cb53cf
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/ClickHouseHttpSource.java
@@ -0,0 +1,24 @@
+package com.mesalab.qgw.model.api;
+
+import com.mesalab.common.configuration.ClickHouseProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+@Data
+public class ClickHouseHttpSource implements Serializable {
+
+ private String url;
+
+ private String dbName;
+
+ private ClickHouseProperties.DBAccount realTimeAccount ;
+
+ private ClickHouseProperties.DBAccount longTermAccount;
+
+ private int enableHttpCompression = 1;
+
+ private String systemDBName = "system";
+
+ private long socketTimeout;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/DruidIoHttpSource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/DruidIoHttpSource.java
new file mode 100644
index 0000000..ca16454
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/DruidIoHttpSource.java
@@ -0,0 +1,12 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DruidIoHttpSource implements Serializable {
+ private String url;
+ private String dbname;
+ private String skipEmptyBuckets = "true";
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/EngineConfigSource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/EngineConfigSource.java
new file mode 100644
index 0000000..417373d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/EngineConfigSource.java
@@ -0,0 +1,13 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class EngineConfigSource implements Serializable {
+
+ private int maxCacheNum;
+ private int defaultResultNum;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/HBaseAPISource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/HBaseAPISource.java
new file mode 100644
index 0000000..9cf45ab
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/HBaseAPISource.java
@@ -0,0 +1,20 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+@Data
+public class HBaseAPISource implements Serializable {
+
+ private String zookeeperQuorum;
+ private String zookeeperPropertyClientPort;
+ private String zookeeperParent;
+ private String dbName;
+ private String tableName;
+ private String columnFamily;
+ private String columnName;
+ private String clientRetriesNumber;
+ private String clientIpcPoolSize;
+ private String rpcTimeout;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/JobAdminHttpSource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/JobAdminHttpSource.java
new file mode 100644
index 0000000..15301a3
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/JobAdminHttpSource.java
@@ -0,0 +1,16 @@
+package com.mesalab.qgw.model.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class JobAdminHttpSource implements Serializable {
+
+ private String url;
+
+ private String userName;
+
+ private String password;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java
new file mode 100644
index 0000000..3ea2dd9
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/SQLQuerySource.java
@@ -0,0 +1,94 @@
+package com.mesalab.qgw.model.api;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.mesalab.qgw.model.api.udf.UDF;
+import com.mesalab.qgw.service.impl.ApiServiceImpl;
+import com.zdjizhi.utils.StringUtil;
+import lombok.Data;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.statement.select.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * SQL Parser properties
+ */
+@Data
+public class SQLQuerySource {
+
+ private String sqlBody;
+ private String tableName;
+ private String partitionKey;/** 分区键,多用于检索查询首要过滤列;例如timestamp **/
+ private String fromItem;
+ private String selectItems;
+ private String expr;
+ private String orderBy;
+ private String limit;
+ private SubSelect subSelect;
+ private Expression whereExpression; /** where 对象 **/
+ private GroupByElement groupByElement;
+ private List<OrderByElement> listOrderElement;
+ private Map<String, String> aliasFields= Maps.newHashMap();/** k=alias,v=column **/
+ private Set<UDF> udfSet = Sets.newHashSet();
+ private Map<String, String> groupDimension = Maps.newHashMap();
+ private List<SQLQuerySource> subSqlQuerySources = Lists.newArrayList();
+ private boolean isEnableLimit;
+
+
+ public boolean isEnableLimit() {
+ if (StringUtil.isNotBlank(limit) && limit.equalsIgnoreCase(ApiServiceImpl.UNVALID_LIMIT_DESC)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+
+
+
+ public Map<String, String> getGroupDimension() {
+ if (groupByElement == null) {
+ return null;
+ }
+ for (Expression groupByExpression : groupByElement.getGroupByExpressions()) {
+
+ String groupBy = groupByExpression.toString();
+ if (groupBy.startsWith("\"") && groupBy.endsWith("\"")) {
+ groupBy = groupBy.substring(1, groupBy.length() - 1);
+ }
+ if (StringUtil.isNotBlank(aliasFields.get(groupBy))) {
+ groupDimension.put(groupBy, aliasFields.get(groupBy));
+ } else {
+ //非别名,确定实际的别名
+ for (String key : aliasFields.keySet()) {
+ if (aliasFields.get(key).equalsIgnoreCase(groupBy)) {
+ groupDimension.put(key, groupBy);
+ break;
+ }
+ }
+ }
+
+ }
+ return groupDimension;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java
new file mode 100644
index 0000000..99b07f7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_CITY.java
@@ -0,0 +1,59 @@
+package com.mesalab.qgw.model.api.udf;
+
+import com.google.common.collect.Lists;
+import com.mesalab.common.utils.IPUtil;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.StringValue;
+
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class IP_TO_CITY implements UDF{
+ private String name;
+ private String address;
+
+
+ public IP_TO_CITY(UDFElements udfElements) {
+ this.name = udfElements.getName();
+ this.address = udfElements.getParams().get(0).toString();
+ }
+
+ @Override
+ public Object execute(SQLQuerySource sqlQuerySource, List<Object> results) {
+ List<Map<String, Object>> targetResult = Lists.newArrayList();
+ String addressLabel = StringUtil.EMPTY;
+ try {
+ for (String alias : sqlQuerySource.getAliasFields().keySet()) {
+ if (sqlQuerySource.getAliasFields().get(alias).contains(address) &&
+ sqlQuerySource.getAliasFields().get(alias).contains(name) ) {
+ addressLabel = alias;
+ break;
+ }
+ }
+
+ for (Object source: results) {
+ Map<String, Object> sourceMap = ((Map<String, Object>) source);
+ if (sourceMap.containsKey(addressLabel)) {
+ sourceMap.put(addressLabel, IPUtil.getCityDetail(sourceMap.get(addressLabel).toString()));
+ }
+ targetResult.add(sourceMap);
+ }
+
+ } catch (Exception e) {
+ log.error("execute IP_TO_CITY ERROR: " + e);
+ }
+
+ return targetResult;
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java
new file mode 100644
index 0000000..d57f5ee
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_COUNTRY.java
@@ -0,0 +1,59 @@
+package com.mesalab.qgw.model.api.udf;
+
+import com.google.common.collect.Lists;
+import com.mesalab.common.utils.IPUtil;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.StringValue;
+
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class IP_TO_COUNTRY implements UDF{
+ private String name;
+ private String address;
+
+
+ public IP_TO_COUNTRY(UDFElements udfElements) {
+ this.name = udfElements.getName();
+ this.address = udfElements.getParams().get(0).toString();
+ }
+
+ @Override
+ public Object execute(SQLQuerySource sqlQuerySource, List<Object> results) {
+ List<Map<String, Object>> targetResult = Lists.newArrayList();
+ String addressLabel = StringUtil.EMPTY;
+ try {
+ for (String alias : sqlQuerySource.getAliasFields().keySet()) {
+ if (sqlQuerySource.getAliasFields().get(alias).contains(address) &&
+ sqlQuerySource.getAliasFields().get(alias).contains(name) ) {
+ addressLabel = alias;
+ break;
+ }
+ }
+ for (Object source: results) {
+ Map<String, Object> sourceMap = ((Map<String, Object>) source);
+ if (sourceMap.containsKey(addressLabel)) {
+ sourceMap.put(addressLabel, IPUtil.getCountry(sourceMap.get(addressLabel).toString()));
+ }
+ targetResult.add(sourceMap);
+ }
+
+ } catch (Exception e) {
+ log.error("execute IP_TO_COUNTRY ERROR: " + e);
+ }
+
+ return targetResult;
+ }
+
+
+}
+ \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java
new file mode 100644
index 0000000..bc49146
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/IP_TO_GEO.java
@@ -0,0 +1,63 @@
+package com.mesalab.qgw.model.api.udf;
+
+import com.google.common.collect.Lists;
+import com.mesalab.common.utils.IPUtil;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.zdjizhi.utils.IpLookup;
+import com.zdjizhi.utils.JsonMapper;
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.StringValue;
+
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class IP_TO_GEO implements UDF{
+ private String name;
+ private String address;
+
+
+ public IP_TO_GEO(UDFElements udfElements) {
+ this.name = udfElements.getName();
+ this.address = udfElements.getParams().get(0).toString();
+ }
+
+ @Override
+ public Object execute(SQLQuerySource sqlQuerySource, List<Object> results) {
+ List<Map<String, Object>> targetResult = Lists.newArrayList();
+ String addressLabel = StringUtil.EMPTY;
+ try {
+
+ for (String alias : sqlQuerySource.getAliasFields().keySet()) {
+ if (sqlQuerySource.getAliasFields().get(alias).contains(address) &&
+ sqlQuerySource.getAliasFields().get(alias).contains(name) ) {
+ addressLabel = alias;
+ break;
+ }
+ }
+
+
+ for (Object source: results) {
+ Map<String, Object> sourceMap = ((Map<String, Object>) source);
+ if (sourceMap.containsKey(addressLabel)) {
+ sourceMap.put(addressLabel, IPUtil.getGeo(sourceMap.get(addressLabel).toString()));
+ }
+ targetResult.add(sourceMap);
+ }
+
+ } catch (Exception e) {
+ log.error("execute IP_TO_GEO ERROR: " + e);
+ }
+
+ return targetResult;
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java
new file mode 100644
index 0000000..bf2e2d6
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/TIME_FLOOR_WITH_FILL.java
@@ -0,0 +1,276 @@
+package com.mesalab.qgw.model.api.udf;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.ConvertUtil;
+import com.mesalab.common.utils.SQLFunctionUtil;
+import com.mesalab.common.utils.SpringContextUtil;
+import com.mesalab.qgw.model.api.EngineConfigSource;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.mesalab.qgw.service.MetadataService;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.Parenthesis;
+import net.sf.jsqlparser.expression.StringValue;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
+import net.sf.jsqlparser.expression.operators.relational.Between;
+import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.*;
+
+@Slf4j
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TIME_FLOOR_WITH_FILL implements UDF{
+
+ @Autowired
+ private MetadataService metadataService = (MetadataService) SpringContextUtil.getBean("metadataService");
+ private EngineConfigSource engineConfigSource = (EngineConfigSource) SpringContextUtil.getBean("engineConfigSource");
+ private String name;
+ private String timestamp;
+ private String period;
+ private String fill;
+
+ public TIME_FLOOR_WITH_FILL(UDFElements udfElements) {
+ this.name = udfElements.getName();
+
+ this.timestamp = udfElements.getParams().get(0).toString();
+ this.period = ((StringValue) udfElements.getParams().get(1)).getValue();
+ if (udfElements.getParams().size() >= 3) {
+ this.fill = ((StringValue) udfElements.getParams().get(2)).getValue();
+ }
+ }
+
+
+ @Override
+ public Object execute(SQLQuerySource sqlQuerySource, List<Object> results) {
+ List<Map<String, Object>> targetResult = null;
+ String groupLabel= null;
+ String timeGranLabel = null;
+
+ try {
+ Map<String, String> groupDimension = sqlQuerySource.getGroupDimension();
+ if (results.isEmpty() || StringUtil.isBlank(fill) || StringUtil.isEmpty(groupDimension)) {
+ return results;
+ }
+ for (String groupKey: groupDimension.keySet()) {
+ if (groupDimension.get(groupKey).contains(name) &&
+ groupDimension.get(groupKey).contains(timestamp)) {
+ timeGranLabel = groupKey;
+ } else {
+ groupLabel = Joiner.on(ConvertUtil.GROUP_SEPRATOR).skipNulls().join(groupKey, groupLabel);
+ }
+
+ }
+
+ WhereTimeRange whereTimeRange = getWhereTimeRange(sqlQuerySource);
+ Date benchmarkDate = getBenchmarkDate((Map<String,Object>) results.get(0), timeGranLabel);
+
+
+ List<Date> dateRangeList = Lists.newArrayList();
+
+ if (StringUtil.isNotBlank(whereTimeRange.getStart())) {
+
+ if (StringUtil.isBlank(whereTimeRange.getEnd())) {
+ whereTimeRange.setEnd(DateUtils.getCurrentDate(DateUtils.YYYY_MM_DD_HH24_MM_SS));
+ }
+
+ List<Date> leftDateRange = DateUtils.getLeftDateRange(benchmarkDate,
+ DateUtils.convertStringToDate((whereTimeRange.getStart()), DateUtils.YYYY_MM_DD_HH24_MM_SS), period);
+ List<Date> rightDateRange = DateUtils.getRightDateRange(benchmarkDate,
+ DateUtils.convertStringToDate((whereTimeRange.getEnd()), DateUtils.YYYY_MM_DD_HH24_MM_SS), period);
+
+ Collections.reverse(leftDateRange);
+ dateRangeList = Lists.newArrayList(Iterables.concat(leftDateRange, rightDateRange));
+
+ } else {
+ log.warn("SQL中时间条件不完整[startTime:{} - endTime:{}],补全功能无效!", whereTimeRange.getStart(), whereTimeRange.getEnd());
+ return results;
+ }
+
+ if (dateRangeList.size() >= 2) {
+ dateRangeList = dateRangeList.subList(1, dateRangeList.size() - 1);
+ }
+ if (dateRangeList.size() == 0) {
+ return results;
+ }
+
+ int maxSeriesNum = engineConfigSource.getMaxCacheNum() / dateRangeList.size();
+ if (maxSeriesNum == 0) {
+ log.warn("初始时间范围超出系统设置,无法进行补全[getMaxCacheNum:{} - dateRangeNum:{}],补全功能无效!", engineConfigSource.getMaxCacheNum(), dateRangeList.size());
+ return results;
+ }
+
+
+ Map<String, Map<String, Map<String, Object>>> targetTimeseriesMap = ConvertUtil.convertResultListToTimeseries(results,
+ groupLabel, timeGranLabel);
+
+ int actualSeriesNum = maxSeriesNum > targetTimeseriesMap.size() ? targetTimeseriesMap.size() : maxSeriesNum;
+
+ if (actualSeriesNum > 0) {
+
+ Map<String, Map<String, Map<String, Object>>> limitTimeseriesMap = Maps.newLinkedHashMap();
+ int i = 1;
+ for (Map.Entry<String, Map<String, Map<String, Object>>> entry: targetTimeseriesMap.entrySet()) {
+ limitTimeseriesMap.put(entry.getKey(), entry.getValue());
+ if (++i > actualSeriesNum) {
+ break;
+ }
+
+ }
+ targetTimeseriesMap.clear();
+ targetTimeseriesMap.putAll(limitTimeseriesMap);
+ }
+
+ if(StringUtil.isNotEmpty(dateRangeList)){
+
+ for (String key : targetTimeseriesMap.keySet()) {
+ targetTimeseriesMap.put(key,ConvertUtil.completeTimeseries((TreeMap<String, Map<String, Object>>) targetTimeseriesMap.get(key), dateRangeList, fill.toString()));
+ }
+ }
+
+ targetResult = ConvertUtil.convertTimeseriesToList(targetTimeseriesMap, groupLabel, timeGranLabel);
+
+ } catch (Exception e) {
+ log.error("Parser function : TIME_FLOOR_WITH_FILL error : " + e);
+ }
+
+ return targetResult;
+ }
+
+
+ /**
+ * 获取基准时间
+ * @param firstElement
+ * @param timeGranLabel
+ * @return
+ */
+ private Date getBenchmarkDate(Map<String, Object> firstElement, String timeGranLabel) {
+ Date benchmarkDate = null;
+ try {
+ Object benchmarkDateObject = firstElement.get(timeGranLabel);
+
+ if (StringUtil.isNumeric(benchmarkDateObject.toString())) {
+ benchmarkDate = new DateTime(Long.valueOf(benchmarkDateObject.toString())*1000).toDate();
+ } else {
+ benchmarkDate = DateUtils.convertStringToDate(benchmarkDateObject.toString(), DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ }
+ } catch (Exception ex) {
+ log.error("Get BenchmarkDate Error ", ex);
+
+ }
+
+ return benchmarkDate;
+ }
+
+ /**
+ * 获取where查询时间范围
+ * @param sqlQuerySource
+ * @return
+ */
+ private WhereTimeRange getWhereTimeRange(SQLQuerySource sqlQuerySource) {
+ String partitionKey = sqlQuerySource.getPartitionKey();
+ Expression whereExpression = sqlQuerySource.getWhereExpression();
+ String dbType = metadataService.getDBTypeByTableName(sqlQuerySource.getTableName());
+ WhereTimeRange whereTimeRange = new WhereTimeRange();
+ try {
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, whereExpression, partitionKey, dbType);
+ } catch (Exception e) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(),
+ ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "解析where表达式,获取数据的时间范围异常", e);
+ }
+ return whereTimeRange;
+ }
+
+ /**
+ * 解析where表达式并设置数据的时间范围
+ * @param whereTimeRange
+ * @param whereExpression
+ * @param partitionKey
+ * @param dbType
+ */
+ private void parserWhereExpressionForWhereTimeRange(WhereTimeRange whereTimeRange, Expression whereExpression, String partitionKey, String dbType) {
+ if (StringUtil.isEmpty(whereExpression) || StringUtil.isBlank(partitionKey)) {
+ return;
+ }
+ if (whereExpression instanceof ComparisonOperator) {
+ ComparisonOperator whereOperator = (ComparisonOperator) whereExpression;
+ String operator = whereOperator.getStringExpression();
+ Expression left = whereOperator.getLeftExpression();
+ Expression right = whereOperator.getRightExpression();
+ if (partitionKey.equals(left.toString())) {
+ String query;
+ if (right instanceof StringValue) {
+ query = ((StringValue) right).getValue();
+ } else if (right instanceof LongValue) {
+ query = right.toString();
+ } else {
+ query = SQLFunctionUtil.getQueryValue(right.toString(), dbType);
+ }
+ if (operator.contains("<")) {
+ whereTimeRange.setEnd(query);
+ } else if (operator.contains(">")) {
+ whereTimeRange.setStart(query);
+ }
+ } else if (partitionKey.equals(right.toString())) {
+ String query;
+ if (left instanceof StringValue) {
+ query = ((StringValue) right).getValue();
+ } else if (left instanceof LongValue) {
+ query = left.toString();
+ } else {
+ query = SQLFunctionUtil.getQueryValue(left.toString(), dbType);
+ }
+ if (operator.contains("<")) {
+ whereTimeRange.setStart(query);
+ } else if (operator.contains(">")) {
+ whereTimeRange.setEnd(query);
+ }
+ }
+ } else if (whereExpression instanceof Between) {
+ Between whereBetween = (Between) whereExpression;
+ Expression leftExpression = whereBetween.getLeftExpression();
+ if (partitionKey.equals(leftExpression.toString())) {
+ whereTimeRange.setStart(whereBetween.getBetweenExpressionStart().toString());
+ whereTimeRange.setEnd(whereBetween.getBetweenExpressionEnd().toString());
+ }
+ } else if (whereExpression instanceof AndExpression) {
+ AndExpression whereAnd = (AndExpression) whereExpression;
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, whereAnd.getLeftExpression(), partitionKey, dbType);
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, whereAnd.getRightExpression(), partitionKey, dbType);
+ } else if (whereExpression instanceof OrExpression) {
+ OrExpression whereOr = (OrExpression) whereExpression;
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, whereOr.getLeftExpression(), partitionKey, dbType);
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, whereOr.getRightExpression(), partitionKey, dbType);
+ } else if (whereExpression instanceof Parenthesis) {
+ Parenthesis whereExpressionParenthesis = (Parenthesis) whereExpression;
+ Expression expression = whereExpressionParenthesis.getExpression();
+ parserWhereExpressionForWhereTimeRange(whereTimeRange, expression, partitionKey, dbType);
+ }
+ }
+
+ @Data
+ private class WhereTimeRange {
+ private String start;
+ private String end;
+
+
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDF.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDF.java
new file mode 100644
index 0000000..2ce754d
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDF.java
@@ -0,0 +1,10 @@
+package com.mesalab.qgw.model.api.udf;
+
+import com.mesalab.qgw.model.api.SQLQuerySource;
+
+import java.util.List;
+
+public interface UDF {
+
+ Object execute(SQLQuerySource sqlQuerySource, List<Object> results);
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDFElements.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDFElements.java
new file mode 100644
index 0000000..1a3e588
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/api/udf/UDFElements.java
@@ -0,0 +1,16 @@
+package com.mesalab.qgw.model.api.udf;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.sf.jsqlparser.expression.Expression;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class UDFElements {
+ private String name;
+ private List<Expression> params;
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/ExecutorParam.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/ExecutorParam.java
new file mode 100644
index 0000000..a442261
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/ExecutorParam.java
@@ -0,0 +1,9 @@
+package com.mesalab.qgw.model.job;
+
+import lombok.Data;
+
+@Data
+public class ExecutorParam {
+
+ private int maxdays;
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/StorageDeletionInfo.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/StorageDeletionInfo.java
new file mode 100644
index 0000000..11e84e7
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/StorageDeletionInfo.java
@@ -0,0 +1,16 @@
+package com.mesalab.qgw.model.job;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class StorageDeletionInfo {
+
+ private String logType;
+ private Integer maxDays;
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/XxlJobInfo.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/XxlJobInfo.java
new file mode 100644
index 0000000..5115208
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/job/XxlJobInfo.java
@@ -0,0 +1,30 @@
+package com.mesalab.qgw.model.job;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.objenesis.instantiator.annotations.Instantiator;
+
+import java.util.Date;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class XxlJobInfo {
+
+ private int id; // 主键ID
+
+ private int jobGroup; // 执行器主键ID
+ private String jobCron; // 任务执行CRON表达式
+ private String jobDesc;
+ private String author; // 负责人
+ private String alarmEmail; // 报警邮件
+
+ private String executorRouteStrategy; // 执行器路由策略
+ private String executorHandler; // 执行器,任务Handler名称
+ private String executorParam; // 执行器,任务参数
+ private String executorBlockStrategy; // 阻塞处理策略
+ private String childJobId; // 子任务ID,多个逗号分隔
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java
new file mode 100644
index 0000000..d917798
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/model/protocol/ProtocolTree.java
@@ -0,0 +1,69 @@
+package com.mesalab.qgw.model.protocol;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.zdjizhi.utils.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProtocolTree {
+ private String id;
+ private String name;
+ private String parentId;
+ private List<ProtocolTree> childrens = Lists.newArrayList();
+ private Map<String, Object> metrics = Maps.newLinkedHashMap();
+ private long sentBytes;
+ private long receivedBytes;
+ private static final String HIERARCCY_FLAG = "/";
+
+
+
+ public ProtocolTree(String id, String name, String parentId) {
+ this.id = id;
+ this.name = name;
+ this.parentId = parentId;
+ }
+
+ public ProtocolTree(String id, String name, String parentId, long sentBytes, long receivedBytes) {
+ this.id = id;
+ this.name = name;
+ this.parentId = parentId;
+ this.sentBytes = sentBytes;
+ this.receivedBytes = receivedBytes;
+ }
+
+
+ public String getParentId() {
+ return id.lastIndexOf(HIERARCCY_FLAG) > 0 ?
+ id.substring(0, id.lastIndexOf(HIERARCCY_FLAG)) : null;
+ }
+
+ public void setParentId(String parentId) {
+ this.parentId = parentId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProtocolTree that = (ProtocolTree) o;
+ return Objects.equals(id, that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name);
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java
new file mode 100644
index 0000000..042d503
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ArangoHealthIndicator.java
@@ -0,0 +1,78 @@
+package com.mesalab.qgw.monitor;
+
+import com.mesalab.common.configuration.HBaseProperties;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.knowledge.common.config.ArangoConfig;
+import com.mesalab.knowledge.common.utils.Constant;
+import com.mesalab.knowledge.common.utils.JwtCache;
+import com.mesalab.knowledge.strategy.QueryProvider;
+import com.mesalab.qgw.service.impl.HttpClientService;
+import com.zdjizhi.utils.JsonMapper;
+import com.zdjizhi.utils.StringUtil;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.http.HttpStatus;
+import org.apache.http.message.BasicHeader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+@Component
+public class ArangoHealthIndicator extends AbstractHealthIndicator {
+
+ @Autowired
+ private ArangoConfig arangoConfig;
+ @Autowired
+ HttpClientService httpClientService;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+
+ try {
+ Object jwt = JwtCache.get(Constant.ARANGO_CACHE_JWT);
+ if (StringUtil.isEmpty(jwt)) {
+ Map<String, String> params = new HashMap<>();
+ params.put("username", arangoConfig.getUsername());
+ params.put("password", arangoConfig.getPassword());
+ String res = httpClientService.httpPost(arangoConfig.getJwturl(), JsonMapper.toJsonString(params));
+ Map resMap = (Map) JsonMapper.fromJsonString(res, Map.class);
+ if (StringUtil.isEmpty(resMap) || StringUtil.isEmpty(resMap.get(Constant.JWT))) {
+ builder.down()
+ .withDetail("app", "Arango")
+ .withDetail("message", "获取Arango jwt 失败: " + arangoConfig.getServer());
+ return;
+ } else {
+ jwt = Constant.ARANGO_JWT_BEARER + resMap.get(Constant.JWT);
+ JwtCache.put(Constant.ARANGO_CACHE_JWT, jwt);
+ }
+ }
+ String result = httpClientService.httpPost(arangoConfig.getServer() + "/_db/" + arangoConfig.getDatabase() + "/_api/version", null, new BasicHeader(HttpHeaders.AUTHORIZATION, String.valueOf(jwt)));
+ Map map = (Map) JsonMapper.fromJsonString(result, Map.class);
+ if (StringUtil.isEmpty(map) || StringUtil.isEmpty(map.get("version"))) {
+ builder.down()
+ .withDetail("app", "Arango")
+ .withDetail("message", "连接Arango 失败: " + result);
+ } else {
+ builder.up()
+ .withDetail("app", "Arango")
+ .withDetail("url", arangoConfig.getServer())
+ .withDetail("message", "ok");
+ }
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "Arango")
+ .withDetail("message", "连接Arango 失败");
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ClickHouseHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ClickHouseHealthIndicator.java
new file mode 100644
index 0000000..60a2847
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/ClickHouseHealthIndicator.java
@@ -0,0 +1,59 @@
+package com.mesalab.qgw.monitor;
+import com.mesalab.qgw.model.api.ClickHouseHttpSource;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+@Component
+public class ClickHouseHealthIndicator extends AbstractHealthIndicator {
+
+
+ public RestTemplate restTemplate = new RestTemplate();
+ @Autowired
+ private ClickHouseHttpSource clickHouseHttpSource;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+ clickHouseHttpSource.getRealTimeAccount();
+ StringBuilder urlBuilder = new StringBuilder("http://")
+ .append(clickHouseHttpSource.getUrl()).append("/?");
+ StringBuilder queryParamBuilder = new StringBuilder("user=")
+ .append(clickHouseHttpSource.getRealTimeAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getRealTimeAccount().getPassword()).append("&")
+ .append("database=").append(clickHouseHttpSource.getDbName()).append("&")
+ .append("query=").append("select version()")
+ .append(" FORMAT JSON ;");
+ String url = urlBuilder.toString() + queryParamBuilder.toString();
+
+ try {
+ ResponseEntity responseEntity = restTemplate.getForEntity(url, Map.class);
+
+ if (responseEntity.getStatusCodeValue() == HttpStatus.SC_OK) {
+ builder.up()
+ .withDetail("app", "ClickHouse")
+ .withDetail("url", clickHouseHttpSource.getUrl())
+ .withDetail("message", "ok");
+ } else {
+ builder.down()
+ .withDetail("app", "ClickHouse")
+ .withDetail("message", "error, status code " + responseEntity.getStatusCodeValue());
+
+
+ }
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "ClickHouse")
+ .withDetail("message", e.getMessage());
+
+ }
+
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/DruidHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/DruidHealthIndicator.java
new file mode 100644
index 0000000..8e322f5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/DruidHealthIndicator.java
@@ -0,0 +1,74 @@
+package com.mesalab.qgw.monitor;
+import com.google.common.collect.Maps;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.qgw.model.api.DruidIoHttpSource;
+import lombok.Data;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+@Component
+public class DruidHealthIndicator extends AbstractHealthIndicator {
+
+
+ public RestTemplate restTemplate = new RestTemplate();
+ @Autowired
+ private DruidIoHttpSource druidIoHttpSource;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+
+ StringBuilder urlBuilder = new StringBuilder("http://") .append(druidIoHttpSource.getUrl());
+ DruidHealthIndicator.DruidQueryParam druidQueryParam = new DruidHealthIndicator.DruidQueryParam();
+
+ druidQueryParam.setQuery("select count(*) from sys.servers ");
+ druidQueryParam.getContext().put("skipEmptyBuckets", druidIoHttpSource.getSkipEmptyBuckets());
+ druidQueryParam.setResultFormat("object");
+ try {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ HttpEntity request = new HttpEntity(JsonMapper.toJsonString(druidQueryParam), headers);
+ ResponseEntity responseEntity = restTemplate.postForEntity(urlBuilder.toString(), request, Object.class);
+
+ if (responseEntity.getStatusCodeValue() == HttpStatus.SC_OK) {
+ builder.up()
+ .withDetail("app", "Druid")
+ .withDetail("url", druidIoHttpSource.getUrl())
+ .withDetail("message", "ok");
+ } else {
+ builder.down()
+ .withDetail("app", "Druid")
+ .withDetail("message", "error, status code " + responseEntity.getStatusCodeValue());
+
+ }
+
+
+
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "Druid")
+ .withDetail("message", e.getMessage());
+
+ }
+
+ }
+
+ @Data
+ class DruidQueryParam {
+ private String query;
+ private Map<String, String> context = Maps.newHashMap();
+ private String resultFormat;
+
+ }
+
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/HbaseHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/HbaseHealthIndicator.java
new file mode 100644
index 0000000..2e699fa
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/HbaseHealthIndicator.java
@@ -0,0 +1,50 @@
+package com.mesalab.qgw.monitor;
+
+import com.mesalab.common.configuration.HBaseProperties;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.Connection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+
+@Component
+public class HbaseHealthIndicator extends AbstractHealthIndicator {
+
+ public RestTemplate restTemplate = new RestTemplate();
+ @Autowired
+ private HBaseProperties hBaseProperties;
+ @Autowired
+ private Connection hbaseConnection;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+
+ try {
+ boolean connectionSuccess;
+ Admin admin = hbaseConnection.getAdmin();
+ connectionSuccess = admin.tableExists(TableName.valueOf((hBaseProperties.getDbName() + ":" + hBaseProperties.getTableName())));
+
+ if (connectionSuccess) {
+ builder.up()
+ .withDetail("app", "Hbase")
+ .withDetail("url", hBaseProperties.getZookeeperQuorum() + ":" + hBaseProperties.getZookeeperPropertyClientPort())
+ .withDetail("message", "ok");
+ } else {
+ builder.down()
+ .withDetail("app", "Hbase")
+ .withDetail("message", "error");
+
+
+ }
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "Hbase")
+ .withDetail("message", e.getMessage());
+ }
+
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/JobAdminHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/JobAdminHealthIndicator.java
new file mode 100644
index 0000000..059645e
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/JobAdminHealthIndicator.java
@@ -0,0 +1,65 @@
+package com.mesalab.qgw.monitor;
+import com.mesalab.qgw.model.api.JobAdminHttpSource;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class JobAdminHealthIndicator extends AbstractHealthIndicator {
+
+
+ public RestTemplate restTemplate = new RestTemplate();
+ @Autowired
+ private JobAdminHttpSource jobAdminHttpSource;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
+ map.add("userName", jobAdminHttpSource.getUserName());
+ map.add("password", jobAdminHttpSource.getPassword());
+
+ HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
+
+ try {
+ ResponseEntity responseEntity = restTemplate.postForEntity(jobAdminHttpSource.getUrl() + "/login?", request, Map.class);
+ if (responseEntity.getStatusCodeValue() == HttpStatus.SC_OK) {
+ Map body = (HashMap) responseEntity.getBody();
+ int code = Integer.parseInt(String.valueOf(body.get("code")));
+ if (code == HttpStatus.SC_OK) {
+ builder.up()
+ .withDetail("app", "xxl-job-admin")
+ .withDetail("url", jobAdminHttpSource.getUrl())
+ .withDetail("message", "ok");
+ } else {
+ builder.down()
+ .withDetail("app", "xxl-job-admin")
+ .withDetail("message", body.get("msg") + ", status code " + code);
+ }
+ } else {
+ builder.down()
+ .withDetail("app", "xxl-job-admin")
+ .withDetail("message", "error, status code " + responseEntity.getStatusCodeValue());
+ }
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "xxl-job-admin")
+ .withDetail("message", e.getMessage());
+
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/MariaDBHealthIndicator.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/MariaDBHealthIndicator.java
new file mode 100644
index 0000000..831061a
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/monitor/MariaDBHealthIndicator.java
@@ -0,0 +1,45 @@
+package com.mesalab.qgw.monitor;
+
+import com.jfinal.plugin.activerecord.Db;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * @author wangwei
+ * @description:
+ * @date 2020/10/23 11:32 上午
+ */
+@Component
+public class MariaDBHealthIndicator extends AbstractHealthIndicator {
+
+ @Value("${spring.datasource.url}")
+ private String url;
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) {
+ try {
+ List<Object> query = Db.query("select 1");
+ if (!CollectionUtils.isEmpty(query) && 1 == Long.parseLong(String.valueOf(query.get(0)))) {
+ builder.up()
+ .withDetail("app", "MariaDB")
+ .withDetail("url", url)
+ .withDetail("message", "ok");
+ } else {
+ builder.down()
+ .withDetail("app", "MariaDB")
+ .withDetail("url", url)
+ .withDetail("message", "error, " + query);
+ }
+ } catch (Exception e) {
+ builder.down()
+ .withDetail("app", "MariaDB")
+ .withDetail("url", url)
+ .withDetail("message", "error, " + e.getMessage());
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/ApiService.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/ApiService.java
new file mode 100644
index 0000000..546d3ae
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/ApiService.java
@@ -0,0 +1,10 @@
+package com.mesalab.qgw.service;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.qgw.model.api.ApiParam;
+
+public interface ApiService {
+
+ BaseResult executeQuery(ApiParam param);
+
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/MetadataService.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/MetadataService.java
new file mode 100644
index 0000000..16181e9
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/MetadataService.java
@@ -0,0 +1,57 @@
+package com.mesalab.qgw.service;
+
+
+import com.mesalab.common.base.BaseResult;
+import org.apache.avro.Schema;
+
+import java.util.Map;
+
+public interface MetadataService {
+
+ /**
+ * 查询schema信息
+ * @param type
+ * @param name
+ * @return
+ */
+ BaseResult getSchemaInfo(String type, String name);
+
+ /**
+ * 根据表名获取partitionKey
+ * @param tableName
+ * @return
+ */
+ String getPartitionKey(String tableName);
+
+ /**
+ * Schema Doc中: 通过key获取value
+ * @param tableName
+ * @param key
+ * @return
+ */
+ String getValueByKeyInSchemaDoc(String tableName, String key);
+
+ /**
+ * 通过数据源,获取所属数据库类型
+ * @param tableName
+ * @return
+ */
+ String getDBTypeByTableName(String tableName);
+
+
+ /**
+ * 通过数据源,获取所对应数据库名称
+ * @param tableName
+ * @return
+ */
+ String getDBNameByTableName(String tableName);
+
+
+
+ /**
+ * 获取所有已注册schema
+ * @return
+ */
+ Map<String, Schema> getAllSchema();
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/SystemService.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/SystemService.java
new file mode 100644
index 0000000..aaeb49a
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/SystemService.java
@@ -0,0 +1,44 @@
+package com.mesalab.qgw.service;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.qgw.model.job.StorageDeletionInfo;
+
+import java.util.List;
+
+public interface SystemService {
+
+ /**
+ * 系统存储配额
+ * @return
+ */
+ BaseResult getStorageQuota();
+
+ /**
+ * 获取每天日志存储变化
+ * @param searchStartTime
+ * @param searchEndTime
+ * @return
+ */
+ BaseResult dailyTrendOfStorage(String searchStartTime, String searchEndTime);
+
+ /**
+ * 数据配额设置
+ * @param list
+ * @return
+ */
+ BaseResult deleteStorage(List<StorageDeletionInfo> list);
+
+ /**
+ * 数据配额设置状态
+ * @param logType
+ * @return
+ */
+ BaseResult getDeleteStorageStatus(String logType);
+
+ /**
+ * 终止查询任务
+ * @param queryId
+ * @return
+ */
+ BaseResult deleteQueryTask(String queryId);
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java
new file mode 100644
index 0000000..b191734
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/ApiServiceImpl.java
@@ -0,0 +1,815 @@
+package com.mesalab.qgw.service.impl;
+
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.SQLLimit;
+import com.alibaba.druid.sql.ast.SQLOrderBy;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
+import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
+import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
+import com.alibaba.druid.sql.ast.statement.*;
+import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
+import com.alibaba.druid.stat.TableStat;
+import com.alibaba.druid.util.JdbcConstants;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.base.SchemaBase;
+import com.mesalab.common.configuration.ClickHouseProperties;
+import com.mesalab.common.configuration.DruidIoProperties;
+import com.mesalab.common.enums.*;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.ReportCacheUtils;
+import com.mesalab.common.utils.SQLFunctionUtil;
+import com.mesalab.common.utils.SQLHelper;
+import com.mesalab.qgw.dialect.Dialect;
+import com.mesalab.qgw.dialect.FederationDialect;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.SQLQuerySource;
+import com.mesalab.qgw.model.api.udf.UDF;
+import com.mesalab.qgw.model.api.udf.UDFElements;
+import com.mesalab.qgw.service.ApiService;
+import com.mesalab.qgw.service.MetadataService;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.BinaryExpression;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.Function;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.DescribeStatement;
+import net.sf.jsqlparser.statement.ShowStatement;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.select.*;
+import net.sf.jsqlparser.util.TablesNamesFinder;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.lang.reflect.Constructor;
+import java.util.*;
+
+@Slf4j
+@Service("apiService")
+public class ApiServiceImpl implements ApiService {
+
+ @Autowired
+ private ClickHouseProperties clickHouseProperties;
+ @Autowired
+ private DruidIoProperties druidIoProperties;
+ @Autowired
+ private MetadataService metadataServiceTemp;
+
+ private static MetadataService metadataService;
+
+ @PostConstruct
+ private void initMetadataService() {
+ metadataService = this.metadataServiceTemp;
+ }
+
+ public static final int MAX_PARSER_LEVEL = 5;
+
+ public static final String UNVALID_LIMIT_DESC = "NO LIMIT";
+
+
+ @Override
+ public BaseResult executeQuery(ApiParam param) {
+ if (StringUtil.isBlank(param.getQuery())) {
+ return BaseResultGenerator.success4Message("ok");
+ }
+ Statement statement;
+ try {
+ statement = CCJSqlParserUtil.parse(param.getQuery());
+ } catch (Exception e) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:", e.getCause());
+ }
+
+ BaseResult baseResult;
+ if (statement instanceof Select) {
+ baseResult = executeSelectStatement(param);
+ } else if (statement instanceof DescribeStatement) {
+ DescribeStatement describeStatement = (DescribeStatement) statement;
+ baseResult = executeDescStatement(param, describeStatement);
+ } else if (statement instanceof ShowStatement) {
+ ShowStatement showStatement = (ShowStatement) statement;
+ baseResult = executeShowStatement(param, showStatement);
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(),
+ "SQL Syntax Error: Only support statement operations for select, show and describe.", null);
+ }
+ return baseResult;
+ }
+
+
+ private BaseResult executeSelectStatement(ApiParam param) {
+
+ BaseResult baseResult = null;
+
+ if (QueryOptionEnum.LONG_TERM.getValue().equalsIgnoreCase(param.getOption())) {
+ baseResult = ReportCacheUtils.get(param.getResultId(), param.getQuery());
+ if (baseResult.isSuccess()) {
+ return baseResult;
+ } else {
+ log.warn("Long-Term Results not exist, execute real-time query: resultID-{}, sql-{}",
+ param.getResultId(), StringUtil.strip(param.getQuery()) );
+
+ }
+
+ }
+
+ Dialect dbDialect = parserSQL(param);
+
+ if (param.getOption().equalsIgnoreCase(QueryOptionEnum.SYNTAX_CHECK.getValue())) {
+ baseResult = dbDialect.executeSyntaxCheck();
+ } else {
+ baseResult = dbDialect.executeQuery();
+ }
+ baseResult = new FederationDialect(param, baseResult).executeQuery();
+ if (!baseResult.isSuccess()) {
+ throw new BusinessException(baseResult.getStatus(), baseResult.getCode(), baseResult.getMessage(), null);
+ }
+
+ return baseResult;
+ }
+
+ private Dialect parserSQL(ApiParam param) {
+ param.setTableName(validateAndGetTableName(param));
+ return parserAndGetDialect(param);
+ }
+
+
+ private Dialect parserAndGetDialect(ApiParam param) {
+ Dialect dialect = null;
+ String dbType = metadataService.getDBTypeByTableName(param.getTableName());
+ if (DBTypeEnum.CLICKHOUSE.getValue().equalsIgnoreCase(dbType)) {
+ param.setDbType(DBTypeEnum.CLICKHOUSE.getValue());
+ } else if (DBTypeEnum.DRUID.getValue().equalsIgnoreCase(dbType)) {
+ param.setDbType(DBTypeEnum.DRUID.getValue());
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), param.getTableName() + " 表未在平台注册,请联系数据平台负责人", null);
+ }
+ param.setDialectDBType(SQLHelper.getDialectDBType(param.getDbType()));
+ convertQueryRecursive(param, parserSQLByAst(param.getQuery()));
+ dialect = getDialect(param);
+ return dialect;
+ }
+
+ private Dialect getDialect(ApiParam param) {
+ Dialect dialect;
+ try {
+ Class dialectClazz = Class.forName("com.mesalab.qgw.dialect." +
+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, param.getDbType())+"Dialect");
+ Constructor constructor = dialectClazz.getConstructor(ApiParam.class);
+
+ dialect = (Dialect) constructor.newInstance(param);
+
+ } catch (Exception e) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "方言转换实例异常!", e);
+ }
+
+ return dialect;
+ }
+
+
+
+ /**
+ * 对请求参数进行验证
+ * @param param
+ * query:查询语句,统一小写
+ * format:输出格式,默认为JSON
+ * option:查询选项,默认为real-time
+ */
+ private String validateAndGetTableName(ApiParam param) {
+
+ if (StringUtil.isBlank(param.getQuery())) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Param Syntax Error:The SQL must be exists.", null);
+ }
+
+ if (StringUtil.isNotBlank(param.getOption())) {
+ if (!param.getOption().equalsIgnoreCase(QueryOptionEnum.REAL_TIME.getValue()) &&
+ !param.getOption().equalsIgnoreCase(QueryOptionEnum.LONG_TERM.getValue()) &&
+ !param.getOption().equalsIgnoreCase(QueryOptionEnum.SYNTAX_CHECK.getValue())) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Param Syntax Error:The option must be real-time or long-term or syntax-check. ", null);
+ }
+ if (param.getOption().equalsIgnoreCase(QueryOptionEnum.LONG_TERM.getValue())) {
+ if (StringUtil.isBlank(param.getReportId()) && StringUtil.isBlank(param.getResultId())) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Param Syntax Error:The option=long-term,must be reportId or resultId.", null);
+ }
+ }
+ } else {
+ param.setOption(QueryOptionEnum.REAL_TIME.getValue());
+ }
+
+
+ if (StringUtil.isNotBlank(param.getFormat())) {
+ if (!param.getFormat().equalsIgnoreCase(QueryFormatEnum.JSON.getValue())
+ && !param.getFormat().equalsIgnoreCase(QueryFormatEnum.CSV.getValue())) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Param Syntax Error: The format must be json or csv.", null);
+ }
+ } else {
+ param.setFormat(QueryFormatEnum.JSON.getValue());
+ }
+
+ return getTableName(param.getQuery());
+ }
+
+
+ private String getTableName(String sql) {
+
+ String tableName = "";
+ try {
+ Statement statement = CCJSqlParserUtil.parse(sql);
+ if (statement instanceof Select) {
+ Select selectStatement = (Select) statement;
+ TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
+ List<String> tableList = tablesNamesFinder.getTableList(selectStatement);
+ if (StringUtil.isNotEmpty(tableList)) {
+ tableName = tableList.get(0);
+ int i = tableName.lastIndexOf(".");
+ tableName = i < 0 ? tableName : tableName.substring(i + 1);
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error: Get Table Name Error." );
+ }
+
+
+ } else {
+ log.warn("Not support DML Parser");
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error, Not support DML Parser." );
+ }
+
+ } catch (Exception e) {
+
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "SQL Syntax Error: ", ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), e.getCause());
+ }
+
+ return tableName;
+ }
+
+
+
+ /**
+ * Visitor 模式解析SQL
+ * @param sql
+ */
+ @Deprecated
+ private String getTableNameFromDruid(String sql) {
+ String tableName = "";
+ try {
+
+ List<SQLStatement> statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
+ SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.MYSQL);
+ SQLStatement statement = statementList.get(0);
+ statement.accept(statVisitor);
+ Map<TableStat.Name, TableStat> tables = statVisitor.getTables();
+
+ if (tables.keySet().size() > 0) {
+ TableStat.Name name = Iterables.getFirst(tables.keySet(), null);
+ tableName = name.getName();
+ }
+
+ } catch (Exception e) {
+ log.error("sqlParser error: ", e);
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:", e);
+ }
+ return tableName;
+ }
+
+ /**
+ * 递归解析SQLQuerySource ,拆分为数据库执行SQL与引擎执行的SQL source
+ * @param sqlQuerySource SQL解析对象
+ */
+ public static void convertQueryRecursive(ApiParam param, SQLQuerySource sqlQuerySource) {
+ SQLQuerySource engineQuerySource = null;
+ SQLQuerySource dbQuerySource = null;
+
+ SQLQuerySource indexUpSqlQuerySource = null;
+ SQLQuerySource indexSqlQuerySource = sqlQuerySource;
+ for (int i = 0; i < MAX_PARSER_LEVEL; i++) {
+ if (indexSqlQuerySource.getUdfSet().size() > 0) {
+ dbQuerySource = indexSqlQuerySource;
+ break;
+ }
+ if (StringUtil.isEmpty(indexSqlQuerySource.getSubSelect())) {
+ dbQuerySource = sqlQuerySource;
+ indexUpSqlQuerySource = null;
+ break;
+ } else {
+ indexUpSqlQuerySource = indexSqlQuerySource;
+ indexSqlQuerySource = indexSqlQuerySource.getSubSqlQuerySources().get(0);
+ if (indexSqlQuerySource.getUdfSet().size() > 0) {
+ dbQuerySource = indexSqlQuerySource;
+ break;
+ }
+ }
+ }
+
+ if (StringUtil.isNotEmpty(indexUpSqlQuerySource)) {
+ engineQuerySource = new SQLQuerySource();
+ String tableName = StringUtil.isEmpty(indexUpSqlQuerySource.getSubSelect().getAlias()) ? indexUpSqlQuerySource.getTableName() : indexUpSqlQuerySource.getSubSelect().getAlias().getName();
+ String replace = sqlQuerySource.getSqlBody().replace(indexUpSqlQuerySource.getSubSelect().toString(), tableName);
+ engineQuerySource.setSqlBody(replace);
+ engineQuerySource.setTableName(tableName);
+ engineQuerySource.setLimit(sqlQuerySource.getLimit());
+ }
+
+ param.setDbQuerySource(dbQuerySource);
+ param.setEngineQuerySource(engineQuerySource);
+ }
+
+
+
+
+
+ /**
+ *
+ * 解析SQL
+ * @param sql
+ * @return
+ */
+ public static SQLQuerySource parserSQLByAst(String sql) {
+
+
+ SQLQuerySource sqlQuerySource = new SQLQuerySource();
+ try {
+
+ Statement statement = CCJSqlParserUtil.parse(sql);
+ if (statement instanceof Select) {
+ Select selectStatement = (Select) statement;
+ sqlQuerySource.setSqlBody(String.valueOf(selectStatement.getSelectBody()));
+ TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
+ List<String> tableList = tablesNamesFinder.getTableList(selectStatement);
+
+ if (StringUtil.isNotEmpty(tableList)) {
+ String tableName = tableList.get(0);
+ int i = tableName.lastIndexOf(".");
+ tableName = i < 0 ? tableName : tableName.substring(i + 1);
+ sqlQuerySource.setTableName(tableName);
+ sqlQuerySource.setPartitionKey(metadataService.getPartitionKey(tableName));
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error: Can't find table name." );
+ }
+
+
+
+ SelectBody body = selectStatement.getSelectBody();
+
+
+ if (body instanceof PlainSelect) { //单条查询
+
+ PlainSelect select = (PlainSelect) body;
+
+ FromItem fromItem = select.getFromItem();
+ if (fromItem != null) {
+ sqlQuerySource.setFromItem(fromItem.toString());
+ }
+
+ Expression where = select.getWhere();
+
+ if (where != null) {
+ sqlQuerySource.setExpr(where.toString());
+ sqlQuerySource.setWhereExpression(where);
+ }
+
+ List<SelectItem> selectItemsList = select.getSelectItems();
+
+ if (StringUtil.isNotEmpty(selectItemsList)) {
+ String selectItemsString = Joiner.on(",").join(selectItemsList);
+ sqlQuerySource.setSelectItems(selectItemsString);
+
+ }
+
+ for (SelectItem item: selectItemsList) {
+ if (item instanceof SelectExpressionItem) {
+ SelectExpressionItem expressionItem = ((SelectExpressionItem)item);
+ if (StringUtil.isNotEmpty(expressionItem.getAlias())) {
+ String aliasName = expressionItem.getAlias().getName();
+ if (aliasName.startsWith("\"") && aliasName.endsWith("\"")) {
+ aliasName = aliasName.substring(1, aliasName.length() - 1);
+ }
+ sqlQuerySource.getAliasFields().put(aliasName, expressionItem.getExpression().toString());
+ } else {
+ sqlQuerySource.getAliasFields().put(expressionItem.getExpression().toString(), expressionItem.getExpression().toString());
+ }
+ addUDFSet(sqlQuerySource.getUdfSet(), expressionItem.getExpression());//伪代码:后期需要在SQLQuerySource where对象中提取
+
+ }
+ }
+
+ GroupByElement groupBy;
+ if (StringUtil.isNotEmpty(groupBy = select.getGroupBy())) {
+ sqlQuerySource.setGroupByElement(groupBy);
+ }
+
+ List<OrderByElement> orderByList = select.getOrderByElements();
+ if (StringUtil.isNotEmpty(orderByList)) {
+ String orderByString = Joiner.on(",").join(orderByList);
+ sqlQuerySource.setOrderBy(orderByString);
+ sqlQuerySource.setListOrderElement(orderByList);
+ }
+
+
+
+ FromItem subItem = select.getFromItem();
+
+ if (subItem instanceof SubSelect) {
+ SubSelect subSelect = (SubSelect) subItem;
+ log.debug("存在子查询为: {}", subSelect);
+ sqlQuerySource.setSubSelect(subSelect);
+ sqlQuerySource.getSubSqlQuerySources().add(0, parserSQLByAst(String.valueOf(subSelect.getSelectBody())));
+ }
+
+
+ Limit limit = select.getLimit();
+
+
+ if (limit != null) {
+
+ if (StringUtil.isNotEmpty(limit.getOffset())) {
+ sqlQuerySource.setLimit(StringUtil.setDefaultIfEmpty(limit.getOffset() , 0)+ "," + limit.getRowCount());
+ } else {
+ sqlQuerySource.setLimit(String.valueOf(limit.getRowCount()));
+ }
+ }
+
+
+ } else if (body instanceof SetOperationList) { // 连接查询
+ SetOperationList setOperationList = (SetOperationList) body;
+ List<SelectBody> selects = setOperationList.getSelects();
+ //暂时只解析第一个结构,不接受不相同的where
+ if(StringUtil.isNotEmpty(selects)) {
+ SQLQuerySource parseSql = parserSQLByAst(selects.get(0).toString());
+ sqlQuerySource.setUdfSet(parseSql.getUdfSet());
+ sqlQuerySource.setWhereExpression(parseSql.getWhereExpression());
+ sqlQuerySource.setGroupByElement(parseSql.getGroupByElement());
+ sqlQuerySource.setAliasFields(parseSql.getAliasFields());
+ }
+ sqlQuerySource.setLimit(UNVALID_LIMIT_DESC);
+ } else { //其它暂不支持
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:Only support statement operation as select.");
+ }
+
+
+
+ } else {
+ log.warn("Not support DML Parser");
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error: Only support statement operation as select." );
+ }
+
+
+
+ } catch (Exception e) {
+ log.error("sqlParser error: ", e);
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:", e);
+
+ }
+
+ return sqlQuerySource;
+ }
+
+
+ /**
+ * 自定义函数封装
+ *
+ * @param udfSet
+ * @param expr
+ */
+ private static void addUDFSet(Set<UDF> udfSet, Expression expr) {
+ parserExpressionForFun(udfSet, expr);
+ }
+
+ private static void parserExpressionForFun(Set<UDF> udfSet, Expression expr) {
+ if (expr instanceof Function) {
+ Function fun = (Function) expr;
+ if (SQLFunctionUtil.functions.keySet().contains(fun.getName().toUpperCase())) {
+ List<Expression> expressions = fun.getParameters().getExpressions();
+ UDF udf = getUDF(fun, expressions);
+ udfSet.add(udf);
+ }
+ if (fun.getParameters() == null) {
+ return;
+ }
+ for (Expression expression : fun.getParameters().getExpressions()) {
+ parserExpressionForFun(udfSet, expression);
+ }
+ } else if (expr instanceof BinaryExpression) {
+ BinaryExpression binary = (BinaryExpression) expr;
+ Expression leftExpression = binary.getLeftExpression();
+ parserExpressionForFun(udfSet, leftExpression);
+ Expression rightExpression = binary.getRightExpression();
+ parserExpressionForFun(udfSet, rightExpression);
+ }
+ }
+
+ /**
+ * 获取自定义函数类
+ * @param fun
+ * @param expressions
+ * @return
+ */
+ private static UDF getUDF(Function fun, List<Expression> expressions) {
+ UDF udf;
+ String funName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, fun.getName());
+ try {
+ Class dialectClazz = Class.forName("com.mesalab.qgw.model.api.udf." + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, fun.getName().toUpperCase()));
+ Constructor constructor = dialectClazz.getConstructor(UDFElements.class);
+ UDFElements udfElements = new UDFElements(funName, expressions);
+ udf = (UDF) constructor.newInstance(udfElements);
+ } catch (Exception e) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "自定义函数转换实例异常!", e);
+ }
+ return udf;
+ }
+
+
+
+ /**
+ * 对SQL语句进行预先解析,为语法树结构
+ * @param sql
+ * @return
+ */
+ @Deprecated
+ private SQLQuerySource parserSQLByAst(String sql, String dialectDbType) {
+
+ SQLQuerySource sqlQuerySource = new SQLQuerySource();
+ try {
+ List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dialectDbType);
+ if (statementList.size() > 0) {
+ SQLStatement statement = statementList.get(0);
+ if (statement instanceof SQLSelectStatement) {
+ SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) statement;
+ SQLSelectQuery sqlSelectQuery = sqlSelectStatement.getSelect().getQuery();
+ // 非union的查询语句
+ if (sqlSelectQuery instanceof SQLSelectQueryBlock) {
+ SQLSelectQueryBlock sqlSelectQueryBlock = (SQLSelectQueryBlock) sqlSelectQuery;
+ // 获取字段列表
+ List<SQLSelectItem> selectItems = sqlSelectQueryBlock.getSelectList();
+ sqlQuerySource.setSelectItems( Arrays.toString(selectItems.toArray()));
+
+ // 获取表
+ SQLTableSource table = sqlSelectQueryBlock.getFrom();
+ // 普通单表
+ if (table instanceof SQLExprTableSource) {
+ sqlQuerySource.setTableName(((SQLExprTableSource) table).getName().getSimpleName());
+ // join多表
+ } else if (table instanceof SQLJoinTableSource) {
+ SQLTableSource sqlSubTableSource = ((SQLJoinTableSource)table).getLeft();
+ sqlQuerySource.setTableName(((SQLExprTableSource) sqlSubTableSource).getName().getSimpleName());
+ // 子查询作为表
+ } else if (table instanceof SQLSubqueryTableSource) {
+ SQLSelectQuery sqlSubSelectQuery = ((SQLSubqueryTableSource)table).getSelect().getQuery();
+ sqlQuerySource.setTableName(getMultiSqlTableName(sqlSubSelectQuery));
+ }
+ // 获取where条件
+ SQLExpr where = sqlSelectQueryBlock.getWhere();
+
+ // 如果是二元表达式
+ if (where instanceof SQLBinaryOpExpr) {
+ SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) where;
+ SQLExpr left = sqlBinaryOpExpr.getLeft();
+ SQLBinaryOperator operator = sqlBinaryOpExpr.getOperator();
+ SQLExpr right = sqlBinaryOpExpr.getRight();
+ sqlQuerySource.setExpr(left.toString() + operator.name() + right.toString());
+ // 如果是子查询
+ } else if (where instanceof SQLInSubQueryExpr) {
+ SQLInSubQueryExpr sqlInSubQueryExpr = (SQLInSubQueryExpr) where;
+
+ }
+
+
+ // 获取分组
+ SQLSelectGroupByClause groupBy = sqlSelectQueryBlock.getGroupBy();
+
+ // 获取排序
+ SQLOrderBy orderBy = sqlSelectQueryBlock.getOrderBy();
+
+ // 获取分页
+ SQLLimit limit = sqlSelectQueryBlock.getLimit();
+
+ if (limit != null) {
+ if (StringUtil.isNotEmpty(limit.getOffset())) {
+ sqlQuerySource.setLimit(StringUtil.setDefaultIfEmpty(limit.getOffset() , 0)+ "," + limit.getRowCount());
+ } else {
+ sqlQuerySource.setLimit(String.valueOf(limit.getRowCount()));
+ }
+ }
+
+
+ // union的查询语句
+ } else if (sqlSelectQuery instanceof SQLUnionQuery) {
+ SQLUnionQuery sqlUnionQuery = (SQLUnionQuery) sqlSelectQuery;
+ sqlQuerySource.setTableName(getMultiSqlTableName(sqlUnionQuery.getRight()));
+ sqlQuerySource.setLimit(UNVALID_LIMIT_DESC);
+ }
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:Only support statement operation as select.");
+ }
+
+
+
+ }
+ } catch (Exception e) {
+ log.error("sqlParser error: ", e);
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:", e);
+
+ }
+
+
+ return sqlQuerySource;
+ }
+
+
+ private String getMultiSqlTableName(SQLSelectQuery sqlSubSelectQuery) {
+ SQLTableSource subTable = ((SQLSelectQueryBlock) sqlSubSelectQuery).getFrom();
+ if (subTable instanceof SQLExprTableSource) {
+ return ((SQLExprTableSource) subTable).getName().getSimpleName();
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), "SQL Syntax Error:Multi-level nested subqueries are not supported yet.");
+ }
+ }
+
+
+
+ /**
+ * 执行describe语句
+ * @param param
+ * @param statement
+ * @return
+ */
+ private BaseResult executeDescStatement(ApiParam param, DescribeStatement statement) {
+ String tableName = statement == null ? param.getTableName() : statement.getTable().getName();
+ param.setTableName(tableName);
+ String dbType = metadataService.getDBTypeByTableName(param.getTableName());
+
+ if (DBTypeEnum.CLICKHOUSE.getValue().equalsIgnoreCase(dbType)) {
+ param.setDbType(DBTypeEnum.CLICKHOUSE.getValue());
+ param.setDialectDBType(DBTypeEnum.CLICKHOUSE.getValue());
+ } else if (DBTypeEnum.DRUID.getValue().equalsIgnoreCase(dbType)) {
+ param.setDbType(DBTypeEnum.DRUID.getValue());
+ param.setDialectDBType(DBTypeEnum.DRUID.getValue());
+ param.setQuery("SELECT COLUMN_NAME as name, DATA_TYPE as type FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + tableName + "'");
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), ResultCodeEnum.SQL_SYNTAX_ERROR.getCode(), param.getTableName() + " 表未在平台注册,请联系数据平台负责人", null);
+ }
+
+ param.setFormat(QueryFormatEnum.JSON.getValue());
+ SQLQuerySource dbQuerySource = new SQLQuerySource();
+ dbQuerySource.setSqlBody(param.getQuery());
+ param.setDbQuerySource(dbQuerySource);
+ Dialect dialect = getDialect(param);
+ BaseResult baseResult = dataEncapsulationOfSchema(dialect.executeAdministrativeQuery(), param);
+
+ if (!baseResult.isSuccess()) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "describe table error, please check tableName", null);
+ }
+ return baseResult;
+ }
+
+ /**
+ * 执行show语句
+ * @param param
+ * @param showStatement
+ * @return
+ */
+ private BaseResult executeShowStatement(ApiParam param, ShowStatement showStatement) {
+
+ if (showStatement != null && !"tables".equalsIgnoreCase(showStatement.getName())) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "SQL Syntax Error:不支持Show tables 之外的操作", null);
+ }
+ if (clickHouseProperties.getDbname().equalsIgnoreCase(param.getSchema())) {
+ param.setDbType(DBTypeEnum.CLICKHOUSE.getValue());
+ param.setDialectDBType(DBTypeEnum.CLICKHOUSE.getValue());
+ } else if (druidIoProperties.getDbname().equalsIgnoreCase(param.getSchema())) {
+ param.setDbType(DBTypeEnum.DRUID.getValue());
+ param.setDialectDBType(DBTypeEnum.DRUID.getValue());
+ param.setQuery("SELECT TABLE_NAME AS name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'TABLE'");
+ } else if (StringUtil.isBlank(param.getSchema())) {
+ BaseResult result = getAllTables();
+ return result;
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema name error", null);
+ }
+ param.setFormat(QueryFormatEnum.JSON.getValue());
+
+ Dialect dialect = getDialect(param);
+ BaseResult result = dialect.executeAdministrativeQuery();
+ if (result.getStatus() == null || result.getStatus() != HttpStatus.SC_OK) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), result.getMessage(), null);
+ }
+ List tables = (ArrayList) result.getData();
+ List<String> list = new ArrayList<>();
+ Iterator iterator = tables.iterator();
+ while (iterator.hasNext()) {
+ Map<String, String> next = (Map) iterator.next();
+ list.add(next.get("name"));
+ }
+ return tablesResultEncapsulation(list, param.getSchema());
+ }
+
+ /**
+ * 获取所有表信息
+ * @return
+ */
+ private BaseResult getAllTables() {
+ //查ck
+ ApiParam temp = new ApiParam();
+ temp.setQuery("show tables");
+ temp.setSchema(clickHouseProperties.getDbname());
+ BaseResult ck = new BaseResult();
+ try {
+ ck = executeShowStatement(temp, null);
+ }catch (Exception e){
+ log.info("tables: 查询clickhouse异常", e);
+ }
+
+ //查druid
+ BaseResult druid = new BaseResult();
+ temp = new ApiParam();
+ temp.setSchema(druidIoProperties.getDbname());
+ try {
+ druid = executeShowStatement(temp, null);
+ }catch (Exception e){
+ log.info("tables: 查询druid 异常", e);
+ }
+ //合并结果
+ Map<String, Object> date = new LinkedHashMap<>();
+ List symbols = new ArrayList<>();
+ String dbName = "";
+ date.put("type", "enum");
+ if(ck.getStatus() != null && ck.getStatus() == HttpStatus.SC_OK){
+ Map ckDate = (Map)ck.getData();
+ dbName += (String) ckDate.get("name");
+ symbols.addAll((List)ckDate.get("symbols"));
+ }
+ if(druid.getStatus() != null && druid.getStatus() == HttpStatus.SC_OK){
+ Map druidDate = (Map)druid.getData();
+ if(!"".equals(dbName)){
+ dbName += ",";
+ }
+ dbName += (String) druidDate.get("name");
+ symbols.addAll((List)druidDate.get("symbols"));
+ }
+ date.put("name", dbName);
+ date.put("symbols", symbols);
+ if(ck.getStatus() == HttpStatus.SC_OK){
+ ck.setData(date);
+ return ck;
+ }else if(druid.getStatus() == HttpStatus.SC_OK){
+ druid.setData(date);
+ return druid;
+ }else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "查询所有tables异常", null);
+ }
+ }
+
+
+ /**
+ * 表描述信息结果封装
+ *
+ * @param result
+ * @param param
+ * @return
+ */
+ public BaseResult dataEncapsulationOfSchema(BaseResult result, ApiParam param) {
+ SchemaBase schema = new SchemaBase();
+ schema.setName(param.getTableName());
+ List<Map> fields = new ArrayList<>();
+ HashMap<String, Object> map = new HashMap<>();
+ List<Map> list = (List<Map>) result.getData();
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ Map<String, String> next = (Map) iterator.next();
+ map = new HashMap<>();
+ map.put("name", next.get("name"));
+ map.put("type", next.get("type"));
+ fields.add(map);
+ }
+ schema.setFields(fields);
+ result.setData(schema);
+ return result;
+ }
+
+ /**
+ * 库中包含表表名查询结果处理
+ *
+ * @param tables
+ * @return
+ */
+ private BaseResult tablesResultEncapsulation(List tables, String database) {
+ List<String> list = new ArrayList<>();
+ Map<String, Object> date = new LinkedHashMap<>();
+ date.put("type", "enum");
+ date.put("name", database);
+ Iterator iterator = tables.iterator();
+ while (iterator.hasNext()){
+ list.add(String.valueOf(iterator.next()));
+ date.put("symbols", list);
+ }
+ BaseResult<Map> baseResult = BaseResultGenerator.success("ok", null);
+ baseResult.setData(date);
+ return baseResult;
+ }
+
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java
new file mode 100644
index 0000000..6e21a2f
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/HttpClientService.java
@@ -0,0 +1,427 @@
+package com.mesalab.qgw.service.impl;
+
+import com.google.common.collect.Maps;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.*;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicHeaderElementIterator;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class HttpClientService {
+
+ @Autowired
+ HttpConfig httpConfig;
+
+ //全局连接池对象
+ private PoolingHttpClientConnectionManager connectionManager;
+
+ /**
+ * 初始化连接池信息
+ */
+ @PostConstruct
+ public void initConnectionManager() {
+ if (connectionManager == null) {
+ connectionManager = new PoolingHttpClientConnectionManager();
+ // 整个连接池最大连接数
+ connectionManager.setMaxTotal(httpConfig.getMaxConnectionNum());
+ // 每路由最大连接数,默认值是2
+ connectionManager.setDefaultMaxPerRoute(httpConfig.getMaxPerRoute());
+ }
+ log.info("Initializing PoolingHttpClientConnectionManager Complete");
+ }
+
+ /**
+ * 获取Http客户端连接对象
+ *
+ * @param socketTimeOut 响应超时时间
+ * @return Http客户端连接对象
+ */
+ public CloseableHttpClient getHttpClient(int socketTimeOut) {
+ // 创建Http请求配置参数
+ RequestConfig requestConfig = RequestConfig.custom()
+ // 获取连接超时时间
+ .setConnectionRequestTimeout(httpConfig.getServerRequestTimeOut())
+ // 请求超时时间
+ .setConnectTimeout(httpConfig.getServerConnectTimeOut())
+ // 响应超时时间
+ .setSocketTimeout(socketTimeOut)
+ .build();
+
+ /**
+ * 测出超时重试机制为了防止超时不生效而设置
+ * 如果直接放回false,不重试
+ * 这里会根据情况进行判断是否重试
+ */
+ HttpRequestRetryHandler retry = (exception, executionCount, context) -> {
+ if (executionCount >= 3) {// 如果已经重试了3次,就放弃
+ return false;
+ }
+ if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
+ return true;
+ }
+ if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
+ return false;
+ }
+ if (exception instanceof InterruptedIOException) {// 超时
+ return true;
+ }
+ if (exception instanceof UnknownHostException) {// 目标服务器不可达
+ return false;
+ }
+ if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
+ return false;
+ }
+ if (exception instanceof SSLException) {// ssl握手异常
+ return false;
+ }
+ HttpClientContext clientContext = HttpClientContext.adapt(context);
+ HttpRequest request = clientContext.getRequest();
+ // 如果请求是幂等的,就再次尝试
+ if (!(request instanceof HttpEntityEnclosingRequest)) {
+ return true;
+ }
+ return false;
+ };
+
+
+ ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
+ HeaderElementIterator it = new BasicHeaderElementIterator
+ (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
+ while (it.hasNext()) {
+ HeaderElement he = it.nextElement();
+ String param = he.getName();
+ String value = he.getValue();
+ if (value != null && param.equalsIgnoreCase("timeout")) {
+ return Long.parseLong(value) * 1000;
+ }
+ }
+ return 60 * 1000;//如果没有约定,则默认定义时长为60s
+ };
+
+ // 创建httpClient
+ return HttpClients.custom()
+ // 把请求相关的超时信息设置到连接客户端
+ .setDefaultRequestConfig(requestConfig)
+ // 把请求重试设置到连接客户端
+ .setRetryHandler(retry)
+ .setKeepAliveStrategy(myStrategy)
+ // 配置连接池管理对象
+ .setConnectionManager(connectionManager)
+ .build();
+ }
+
+
+ /**
+ * @param url:请求地址
+ * @param socketTimeout: 响应超时时间
+ **/
+ public Map<String, String> httpGet(String url, int socketTimeout) {
+ Map<String, String> resultMap = Maps.newHashMap();
+ // 创建GET请求对象
+ CloseableHttpResponse response = null;
+ try {
+ HttpGet httpGet = new HttpGet(url);
+ // 执行请求
+ response = getHttpClient(socketTimeout).execute(httpGet);
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ // 获取响应信息
+ resultMap.put("status", String.valueOf(response.getStatusLine().getStatusCode()));
+ resultMap.put("result", EntityUtils.toString(entity, "UTF-8"));
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_BAD_GATEWAY));
+ resultMap.put("message", e.getMessage());
+ } catch (Exception e) {
+ log.error("其它错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR));
+ resultMap.put("message", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consumeQuietly(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return resultMap;
+ }
+
+ /**
+ * @param url:请求地址
+ * @param headers: Headers
+ * @param socketTimeOut: 响应超时时间
+ * @return: java.util.Map<java.lang.String, java.lang.String>
+ **/
+ public Map<String, String> httpGet(String url, Map<String, String> headers, int socketTimeOut) {
+ Map<String, String> resultMap = Maps.newHashMap();
+ // 创建GET请求对象
+ CloseableHttpResponse response = null;
+ try {
+ HttpGet httpGet = new HttpGet(url);
+ for (String key : headers.keySet()) {
+ httpGet.setHeader(key, headers.get(key));
+ }
+ // 执行请求
+ response = getHttpClient(socketTimeOut).execute(httpGet);
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ // 获取响应信息
+ resultMap.put("status", String.valueOf(response.getStatusLine().getStatusCode()));
+ resultMap.put("result", EntityUtils.toString(entity, "UTF-8"));
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_BAD_GATEWAY));
+ resultMap.put("message", e.getMessage());
+ } catch (Exception e) {
+ log.error("其它错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR));
+ resultMap.put("message", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consumeQuietly(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return resultMap;
+ }
+
+ /**
+ * @param url:请求地址
+ * @param jsonString:请求参数
+ * @param socketTimeOut:响应超时时间
+ **/
+ public Map<String, String> httpPost(String url, String jsonString, int socketTimeOut) {
+ Map<String, String> resultMap = Maps.newHashMap();
+ // 创建GET请求对象
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setEntity(new ByteArrayEntity(jsonString.getBytes("utf-8")));
+ response = getHttpClient(socketTimeOut).execute(httpPost);
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ // 获取响应信息
+ resultMap.put("status", String.valueOf(response.getStatusLine().getStatusCode()));
+ resultMap.put("result", EntityUtils.toString(entity, "UTF-8"));
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_SERVICE_UNAVAILABLE));
+ resultMap.put("message", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_BAD_GATEWAY));
+ resultMap.put("message", e.getMessage());
+ } catch (Exception e) {
+ log.error("其它错误: {}", e.getMessage());
+ resultMap.put("status", String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR));
+ resultMap.put("message", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consumeQuietly(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return resultMap;
+ }
+
+ /**
+ * @param url:请求地址
+ * @param headers: Headers
+ * @param socketTimeOut: 响应超时时间
+ **/
+ public Map<String, String> getHttpPostResponseHeads(String url, Map<String, String> headers, int socketTimeOut) {
+ CloseableHttpResponse response = null;
+ HashMap<String, String> map = Maps.newHashMap();
+ try {
+ HttpPost httpPost = new HttpPost(url);
+ for (Object k : headers.keySet()) {
+ httpPost.setHeader(k.toString(), headers.get(k).toString());
+ }
+ response = getHttpClient(socketTimeOut).execute(httpPost);
+ Header[] Headers = response.getAllHeaders();
+ for (Header h : Headers) {
+ map.put(h.getName().toUpperCase(), h.getValue());
+ }
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consumeQuietly(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return map;
+ }
+
+ /**
+ * @param url:请求地址
+ **/
+ public String httpGet(String url) {
+ String msg = "-1";
+ // 获取客户端连接对象
+ CloseableHttpClient httpClient = getHttpClient(httpConfig.getArangoSocketTimeOut());
+ CloseableHttpResponse response = null;
+ try {
+ URL ul = new URL(url);
+ URI uri = new URI(ul.getProtocol(), null, ul.getHost(), ul.getPort(), ul.getPath(), ul.getQuery(), null);
+ log.info("http get uri {}", uri);
+ // 创建GET请求对象
+ HttpGet httpGet = new HttpGet(uri);
+ // 执行请求
+ response = httpClient.execute(httpGet);
+ int statusCode = response.getStatusLine().getStatusCode();
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ // 获取响应信息
+ msg = EntityUtils.toString(entity, "UTF-8");
+ if (statusCode != HttpStatus.SC_OK) {
+ throw new BusinessException("Http get content is :" + msg);
+ }
+ } catch (URISyntaxException e) {
+ log.error("URI 转换错误: {}", e.getMessage());
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consume(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return msg;
+ }
+
+ /**
+ * @param url: 请求地址
+ * @param requestBody: 请求参数
+ * @param headers: Header
+ **/
+ public String httpPost(String url, String requestBody, Header... headers) {
+ String msg = "-1";
+ // 获取客户端连接对象
+ CloseableHttpClient httpClient = getHttpClient(httpConfig.getArangoSocketTimeOut());
+ // 创建POST请求对象
+ CloseableHttpResponse response = null;
+ try {
+ URL ul = new URL(url);
+ URI uri = new URI(ul.getProtocol(), null, ul.getHost(), ul.getPort(), ul.getPath(), ul.getQuery(), null);
+ log.debug("http post uri:{}, http post body:{}", uri, requestBody);
+ HttpPost httpPost = new HttpPost(uri);
+ httpPost.setHeader("Content-Type", "application/json");
+ if (StringUtil.isNotEmpty(headers)) {
+ for (Header h : headers) {
+ httpPost.addHeader(h);
+ }
+ }
+ if (StringUtil.isNotBlank(requestBody)) {
+ httpPost.setEntity(new ByteArrayEntity(requestBody.getBytes("utf-8")));
+ }
+ response = httpClient.execute(httpPost);
+ int statusCode = response.getStatusLine().getStatusCode();
+ // 获取响应实体
+ HttpEntity entity = response.getEntity();
+ // 获取响应信息
+ msg = EntityUtils.toString(entity, "UTF-8");
+ if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {
+ throw new BusinessException(msg);
+ }
+ } catch (URISyntaxException e) {
+ log.error("URI 转换错误: {}", e.getMessage());
+ } catch (ClientProtocolException e) {
+ log.error("协议错误: {}", e.getMessage());
+ } catch (ParseException e) {
+ log.error("解析错误: {}", e.getMessage());
+ } catch (IOException e) {
+ log.error("IO错误: {}", e.getMessage());
+ } finally {
+ if (null != response) {
+ try {
+ EntityUtils.consumeQuietly(response.getEntity());
+ response.close();
+ } catch (IOException e) {
+ log.error("释放链接错误: {}", e.getMessage());
+ }
+ }
+ }
+ return msg;
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java
new file mode 100644
index 0000000..11e1ca8
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/MetadataServiceImpl.java
@@ -0,0 +1,218 @@
+package com.mesalab.qgw.service.impl;
+
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.configuration.ClickHouseProperties;
+import com.mesalab.common.configuration.DruidIoProperties;
+import com.mesalab.common.enums.ResultCodeEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.enums.DBTypeEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.SchemaCacheUtils;
+import com.mesalab.qgw.service.MetadataService;
+import com.zdjizhi.utils.JsonMapper;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.avro.Schema;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.*;
+
+@Slf4j
+@Service("metadataService")
+public class MetadataServiceImpl implements MetadataService {
+
+ private static final String METADATA_SCHEMA_KEY = "metadata:schema";
+
+ @Autowired
+ ClickHouseProperties clickHouseProperties;
+ @Autowired
+ DruidIoProperties druidIoProperties;
+
+ @Override
+ public BaseResult getSchemaInfo(String type, String name) {
+ if ("tables".equals(type)) {
+ List<String> tables = getTablesName(name);
+ return encapsulationTablesResult(tables, name);
+ } else if ("fields".equals(type)) {
+ return BaseResultGenerator.success("ok", parseAndGetSchemaMap(name));
+ } else {
+ return BaseResultGenerator.failure(HttpStatus.SC_NOT_FOUND, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Not found, check url please");
+ }
+ }
+
+ private List<String> getTablesName(String dbName) {
+ List<String> tables = new ArrayList<>();
+ Map<String, Schema> map = (Map<String, Schema>) SchemaCacheUtils.get(METADATA_SCHEMA_KEY);
+ map.values().forEach(schema -> {
+ Optional.ofNullable(schema).ifPresent(o -> {
+ if (dbName.equalsIgnoreCase(schema.getNamespace())) {
+ tables.add(schema.getName());
+ }
+ });
+ });
+ return tables;
+ }
+
+ private Map parseAndGetSchemaMap(String tableName) {
+ Schema schema = getSchemaByName(tableName);
+ if (StringUtil.isEmpty(schema)) {
+ throw new BusinessException(HttpStatus.SC_NOT_FOUND, ResultCodeEnum.PARAM_SYNTAX_ERROR.getCode(), "Unregister In Schema: " + tableName, null);
+ }
+ Map resultMap = (Map) JsonMapper.fromJsonString(String.valueOf(schema), Map.class);
+ Map schemaDoc = (Map) JsonMapper.fromJsonString(schema.getDoc(), Map.class);
+ if (StringUtil.isEmpty(schemaDoc) && StringUtil.isNotEmpty(schema.getDoc())) {
+ log.error("{} schema's doc isn't jsonString and won't convert: {}", tableName, schema.getDoc());
+ }
+ if (StringUtil.isNotEmpty(schemaDoc)) {
+ resultMap.put("doc", schemaDoc);
+ }
+ List<Map> fields = (List<Map>) resultMap.get("fields");
+ Map mapDoc;
+ for (Map next : fields) {
+ mapDoc = (Map) JsonMapper.fromJsonString(String.valueOf(next.get("doc")), Map.class);
+ if (StringUtil.isNotEmpty(mapDoc)) {
+ next.put("doc", mapDoc);
+ }
+ if (StringUtil.isEmpty(mapDoc) && !StringUtil.isEmpty(next.get("doc"))) {
+ log.error("{} field's doc isn't jsonString and won't convert: {}", next.get("name"), next.get("doc"));
+ }
+ }
+ return resultMap;
+ }
+
+ private Schema getSchemaByName(String tableName) {
+ Map<String, Schema> schemas = (Map<String, Schema>) SchemaCacheUtils.get(METADATA_SCHEMA_KEY);
+ return schemas.get(tableName);
+ }
+
+ /**
+ * 封装库中元数据信息
+ *
+ * @param tables
+ * @return
+ */
+ private BaseResult encapsulationTablesResult(List tables, String database) {
+ Map<String, Object> date = new LinkedHashMap<>();
+ date.put("type", "enum");
+ date.put("name", database);
+ date.put("symbols", tables);
+ BaseResult<Map> baseResult = BaseResultGenerator.success("ok", date);
+ return baseResult;
+ }
+
+
+ /**
+ * 读取fileDir目录下的文件(.avsc)
+ *
+ * @param fileDir
+ * @return
+ */
+ private Map<String, Schema> getSchemasByDirs(File fileDir) {
+ Map<String, Schema> result = new HashMap<>();
+ List<File> files = recurseDirs(fileDir, ".avsc");
+ for (File item : files) {
+ try {
+ Schema schema = new Schema.Parser().parse(item);
+ result.put(schema.getName(), schema);
+ } catch (Exception e) {
+ log.error("File: {}, Schema Parser Error: {}", item.getPath(), e);
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * 遍历读取startDir文件夹目录下所有以regex结尾的文件
+ *
+ * @param startDir
+ * @param regex
+ * @return
+ */
+ private List<File> recurseDirs(File startDir, String regex) {
+ List<File> result = new ArrayList<>();
+ Optional.ofNullable(startDir.listFiles()).ifPresent(o -> {
+ for (File item : o) {
+ if (item.isDirectory()) {
+ result.addAll(recurseDirs(item, regex));
+ } else {
+ if (item.getName().endsWith(regex)) {
+ result.add(item);
+ }
+ }
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public String getPartitionKey(String tableName) {
+ String partitionKey = StringUtil.EMPTY;
+ try {
+ Schema schema = getSchemaByName(tableName);
+ Map doc = (Map) JsonMapper.fromJsonString(schema.getDoc(), Map.class);
+ if (StringUtil.isNotEmpty(doc)) {
+ Object partition_key = doc.get("partition_key");
+ partitionKey = StringUtil.isEmpty(partition_key) ? StringUtil.EMPTY : partition_key.toString();
+ }
+ } catch (Exception e) {
+ log.error("Get Partition key Error ", e);
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), "Get Partition key Error: " + e.getMessage());
+ }
+ return partitionKey;
+ }
+
+ @Override
+ public String getValueByKeyInSchemaDoc(String tableName, String key) {
+ Schema schema = getSchemaByName(tableName);
+ Map doc = (Map) JsonMapper.fromJsonString(schema.getDoc(), Map.class);
+ if (StringUtil.isNotEmpty(doc)) {
+ Object value = doc.get(key);
+ if (value instanceof Map) {
+ return JsonMapper.toJsonString(value);
+ } else {
+ return StringUtil.isEmpty(value) ? StringUtil.EMPTY : value.toString();
+ }
+ }
+ return StringUtil.EMPTY;
+ }
+
+ @Override
+ public String getDBTypeByTableName(String tableName) {
+ Schema schema = getSchemaByName(tableName);
+ if (StringUtil.isEmpty(schema)) {
+ return StringUtil.EMPTY;
+ }
+ if (clickHouseProperties.getDbname().equalsIgnoreCase(schema.getNamespace())
+ || "system".equalsIgnoreCase(schema.getNamespace())) {
+ return DBTypeEnum.CLICKHOUSE.getValue();
+ }
+ if (druidIoProperties.getDbname().equalsIgnoreCase(schema.getNamespace())) {
+ return DBTypeEnum.DRUID.getValue();
+ }
+ return StringUtil.EMPTY;
+ }
+
+ @Override
+ public String getDBNameByTableName(String tableName) {
+ Schema schema = getSchemaByName(tableName);
+ return StringUtil.isNotEmpty(schema) ? schema.getNamespace() : clickHouseProperties.getDbname() ;
+ }
+
+
+ @Override
+ public Map<String, Schema> getAllSchema() {
+ try {
+ String pathRoot = new File("").getCanonicalPath();
+ File fileDir = new File(pathRoot + "/config/avro");
+ return getSchemasByDirs(fileDir);
+ } catch (Exception e) {
+ log.error("Get Schema Error {}", e.getMessage());
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), ResultCodeEnum.UNKNOW_ERROR.getCode(), "Get Schema Error:", e);
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java
new file mode 100644
index 0000000..a36c0f5
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/SystemServiceImpl.java
@@ -0,0 +1,491 @@
+package com.mesalab.qgw.service.impl;
+
+import com.google.common.collect.Maps;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.enums.JobHandlerEnum;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.qgw.model.api.ApiParam;
+import com.mesalab.qgw.model.api.ClickHouseHttpSource;
+import com.mesalab.qgw.model.api.JobAdminHttpSource;
+import com.mesalab.qgw.model.job.ExecutorParam;
+import com.mesalab.qgw.model.job.StorageDeletionInfo;
+import com.mesalab.qgw.model.job.XxlJobInfo;
+import com.mesalab.qgw.service.ApiService;
+import com.mesalab.qgw.service.SystemService;
+import com.zdjizhi.utils.DateUtils;
+import com.zdjizhi.utils.Encodes;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cglib.beans.BeanMap;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
+import java.util.*;
+
+@Slf4j
+@Service("systemService")
+public class SystemServiceImpl implements SystemService {
+
+
+ @Autowired
+ private ApiService apiService;
+ @Autowired
+ private JobAdminHttpSource jobAdminHttpSource;
+ @Autowired
+ private HttpClientService httpClientService;
+ @Autowired
+ private ClickHouseHttpSource clickHouseHttpSource;
+ @Autowired
+ HttpConfig httpConfig;
+
+ private Map<String, String> headers = Maps.newHashMap();
+
+ @Override
+ public BaseResult getStorageQuota() {
+
+ //封装sql进行查询:Analytic Logs、Files、Traffic Logs
+ ApiParam param = new ApiParam();
+ param.setQuery("(select log_type, used_size, max_size, TIME_FORMAT(MILLIS_TO_TIMESTAMP(1000 * last_storage),'YYYY-MM-dd') as first_storage from sys_storage_log where log_type = 'Report and Metrics' ORDER BY __time desc limit 1)\n" +
+ "UNION ALL\n" +
+ "(select log_type, used_size, max_size, TIME_FORMAT(MILLIS_TO_TIMESTAMP(1000 * last_storage),'YYYY-MM-dd') as first_storage from sys_storage_log where log_type = 'Files' ORDER BY __time desc limit 1)\n" +
+ "UNION ALL\n" +
+ "(select log_type, used_size, max_size,TIME_FORMAT(MILLIS_TO_TIMESTAMP(1000 * last_storage),'YYYY-MM-dd') as first_storage from sys_storage_log where log_type = 'Traffic Logs' ORDER BY __time desc limit 1)");
+ BaseResult result = apiService.executeQuery(param);
+ return result;
+ }
+
+ @Override
+ public BaseResult dailyTrendOfStorage(String searchStartTime, String searchEndTime) {
+
+ Date currentDate = DateUtils.convertStringToDate(DateUtils.getCurrentDate(), DateUtils.YYYY_MM_DD);
+
+ if (StringUtil.isBlank(searchStartTime) && StringUtil.isBlank(searchEndTime)) {
+ searchStartTime = DateUtils.getFormatDate(DateUtils.getSomeDate(currentDate, -7), DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ searchEndTime = DateUtils.getFormatDate(currentDate, DateUtils.YYYY_MM_DD_HH24_MM_SS);
+ }
+
+ if (StringUtil.isNotBlank(searchStartTime) && StringUtil.isNotBlank(searchEndTime)) {
+ ApiParam param = new ApiParam();
+ String sql = String.format("select TIME_FORMAT(__time,'YYYY-MM-dd') as stat_time,log_type as type, sum(aggregate_size) as used_size from sys_storage_log where __time >= '%s' and __time < '%s' group by TIME_FORMAT(__time,'YYYY-MM-dd'), log_type", searchStartTime, searchEndTime);
+ param.setQuery(sql);
+ return apiService.executeQuery(param);
+ } else {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "参数校验:start_time 与 end_time 需同时填写", null);
+ }
+ }
+
+ @Override
+ public BaseResult deleteStorage(List<StorageDeletionInfo> list) {
+
+ if (!logTypeIsAvaliable(list)) {
+ return BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "匹配失败, 请检查日志类型!");
+ }
+
+ preProcessOfLogType(list);
+
+ if (jobIsBusy(list)) {
+ return BaseResultGenerator.failure(HttpStatus.SC_LOCKED, "任务繁忙中, 请稍后尝试!");
+ }
+
+ BaseResult baseResult = null;
+ for (StorageDeletionInfo info : list) {
+ baseResult = executeDeleteStorageJob(info);
+ }
+ return baseResult;
+ }
+
+ @Override
+ public BaseResult getDeleteStorageStatus(String logType) {
+ setCookie();
+ List list = new ArrayList<>();
+ if (StringUtil.isBlank(logType)) {
+
+ StorageDeletionInfo trafficInfo = getStorageDeletionInfoByHandler(LogType.TRAFFIC_LOGS.getValue(), JobHandlerEnum.DELETE_TRAFFIC_DATA_JOB_HANDLER.getValue());
+ list.add(trafficInfo);
+
+ StorageDeletionInfo reportInfo = getStorageDeletionInfoByHandler(LogType.REPORT_AND_METRICS.getValue(), JobHandlerEnum.DELETE_REPORT_AND_METRICS_DATA_JOB_HANDLER.getValue());
+ list.add(reportInfo);
+
+ StorageDeletionInfo fileInfo = getStorageDeletionInfoByHandler(LogType.FILES.getValue(), JobHandlerEnum.DELETE_FILES_JOB_HANDLER.getValue());
+ list.add(fileInfo);
+ } else if (LogType.TRAFFIC_LOGS.getValue().equalsIgnoreCase(logType)) {
+ StorageDeletionInfo trafficInfo = getStorageDeletionInfoByHandler(logType, JobHandlerEnum.DELETE_TRAFFIC_DATA_JOB_HANDLER.getValue());
+ list.add(trafficInfo);
+ } else if (LogType.REPORT_AND_METRICS.getValue().equalsIgnoreCase(logType)) {
+ StorageDeletionInfo reportInfo = getStorageDeletionInfoByHandler(logType, JobHandlerEnum.DELETE_REPORT_AND_METRICS_DATA_JOB_HANDLER.getValue());
+ list.add(reportInfo);
+ } else if (LogType.FILES.getValue().equalsIgnoreCase(logType)) {
+ StorageDeletionInfo reportInfo = getStorageDeletionInfoByHandler(logType, JobHandlerEnum.DELETE_FILES_JOB_HANDLER.getValue());
+ list.add(reportInfo);
+ } else {
+ return BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "没有匹配的日志类型: " + logType);
+ }
+ return BaseResultGenerator.success("ok", list);
+ }
+
+ @Override
+ public BaseResult deleteQueryTask(String queryId) {
+ String executeSql = "kill query where query_id = '" + queryId + "'";
+ StringBuilder urlBuilder = new StringBuilder("http://")
+ .append(clickHouseHttpSource.getUrl()).append("/?");
+ StringBuilder queryParamBuilder = new StringBuilder("user=")
+ .append(clickHouseHttpSource.getLongTermAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getLongTermAccount().getPassword()).append("&")
+ .append("database=").append(clickHouseHttpSource.getDbName()).append("&")
+ .append("query=").append(executeSql)
+ .append(" FORMAT ").append("JSON").append(" ;");
+
+ List<NameValuePair> values = URLEncodedUtils.parse(queryParamBuilder.toString(), Charset.forName("UTF-8"));
+
+ Map<String, String> map = httpClientService.httpGet(urlBuilder.toString() + URLEncodedUtils.format(values, "utf-8"), 0);
+ if (map.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ return BaseResultGenerator.success4Message("ok");
+ } else {
+ return BaseResultGenerator.failure(Integer.parseInt(map.get("status")), map.get("result"));
+ }
+ }
+
+
+ private boolean logTypeIsAvaliable(List<StorageDeletionInfo> list) {
+
+ List<LogType> logTypes = Arrays.asList(LogType.values());
+ List<String> logType = new ArrayList<>();
+ for (LogType type : logTypes) {
+ logType.add(type.getValue().toUpperCase());
+ }
+ for (StorageDeletionInfo info : list) {
+ if (!logType.contains(info.getLogType().toUpperCase())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private List<StorageDeletionInfo> preProcessOfLogType(List<StorageDeletionInfo> list) {
+ if (list.size() == 1 && LogType.ALL.getValue().equalsIgnoreCase(list.get(0).getLogType())) {
+ Integer maxDays = list.get(0).getMaxDays();
+
+ list.clear();
+ list.add(new StorageDeletionInfo(LogType.TRAFFIC_LOGS.getValue(), maxDays));
+ list.add(new StorageDeletionInfo(LogType.REPORT_AND_METRICS.getValue(), maxDays));
+ list.add(new StorageDeletionInfo(LogType.FILES.getValue(), maxDays));
+ }
+ return list;
+ }
+
+ private boolean jobIsBusy(List<StorageDeletionInfo> list) {
+ setCookie();
+ for (StorageDeletionInfo info : list) {
+
+ String handler = getDeletePartHandlerByLogType(info.getLogType());
+ if (jobIsBusyByHandler(handler)) {
+ return true;
+ }
+ handler = getDeleteAllHandlerByLogType(info.getLogType());
+ if (jobIsBusyByHandler(handler)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean jobIsBusyByHandler(String handler) {
+ Map dataByHandler = getDataByHandler(handler);
+ String id = String.valueOf(dataByHandler.get("id"));
+ BaseResult result = queryJobStatusByJobId(Integer.parseInt(id));
+ if (result.getStatus().equals(HttpStatus.SC_LOCKED)) {
+ return true;
+ } else if (!result.getStatus().equals(HttpStatus.SC_OK)) {
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), "获取任务状态异常: " + result.getMessage(), null);
+ }
+ return false;
+ }
+
+
+ /**
+ * 执行日志删除任务: 调用调度任务任务
+ *
+ * @param info
+ * @return
+ */
+ private BaseResult executeDeleteStorageJob(StorageDeletionInfo info) {
+
+ BaseResult baseResult;
+ String jobHandler;
+ String logType = info.getLogType();
+ ExecutorParam executorParam = new ExecutorParam();
+ if (0 == info.getMaxDays()) {
+ jobHandler = getDeleteAllHandlerByLogType(logType);
+ Map dataByHandler = getDataByHandler(jobHandler);
+
+ StorageDeletionInfo storageDeletionInfoByHandler = getStorageDeletionInfoByHandler(logType, getDeletePartHandlerByLogType(logType));
+ executorParam.setMaxdays(storageDeletionInfoByHandler.getMaxDays());
+
+ XxlJobInfo xxlJobInfo = setXxlJobInfoParam(dataByHandler, executorParam);
+ baseResult = executeTriggerAndUpdate(xxlJobInfo);
+ } else {
+ jobHandler = getDeletePartHandlerByLogType(info.getLogType());
+ executorParam.setMaxdays(info.getMaxDays());
+ Map dataByHandler = getDataByHandler(jobHandler);
+ XxlJobInfo xxlJobInfo = setXxlJobInfoParam(dataByHandler, executorParam);
+ baseResult = executeTriggerAndUpdate(xxlJobInfo);
+ }
+ if (!baseResult.getStatus().equals(HttpStatus.SC_OK)) {
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), "调度任务数据配额设置任务执行失败", null);
+ }
+ return baseResult;
+ }
+
+ private String getDeleteAllHandlerByLogType(String logType) {
+ String jobHandler = StringUtil.EMPTY;
+ if (LogType.TRAFFIC_LOGS.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_ALL_TRAFFIC_DATA_JOB_HANDLER.getValue();
+ } else if (LogType.REPORT_AND_METRICS.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_ALL_REPORT_AND_METRICS_DATA_JOB_HANDLER.getValue();
+ } else if (LogType.FILES.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_ALL_FILES_JOB_HANDLER.getValue();
+ }
+ return jobHandler;
+ }
+
+ private String getDeletePartHandlerByLogType(String logType) {
+ String jobHandler = StringUtil.EMPTY;
+ if (LogType.TRAFFIC_LOGS.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_TRAFFIC_DATA_JOB_HANDLER.getValue();
+ } else if (LogType.REPORT_AND_METRICS.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_REPORT_AND_METRICS_DATA_JOB_HANDLER.getValue();
+ } else if (LogType.FILES.getValue().equalsIgnoreCase(logType)) {
+ jobHandler = JobHandlerEnum.DELETE_FILES_JOB_HANDLER.getValue();
+ }
+ return jobHandler;
+ }
+
+ /**
+ * 通过handler获取数据配额设置状态
+ *
+ * @param logType
+ * @param jobHandlerValue
+ * @return
+ */
+ private StorageDeletionInfo getStorageDeletionInfoByHandler(String logType, String jobHandlerValue) {
+ StorageDeletionInfo storageDeletionInfo = new StorageDeletionInfo();
+ Map trafficDate = getDataByHandler(jobHandlerValue);
+ XxlJobInfo xxlJobInfo = mapToBean(trafficDate, XxlJobInfo.class);
+ Map executorParam = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(xxlJobInfo.getExecutorParam(), Map.class);
+ Object maxDays = executorParam.get("maxdays");
+ storageDeletionInfo.setLogType(logType);
+ storageDeletionInfo.setMaxDays(Integer.parseInt(String.valueOf(maxDays)));
+ return storageDeletionInfo;
+ }
+
+ /**
+ * 触发执行器并更新任务
+ *
+ * @param xxlJobInfo
+ * @return
+ */
+ private BaseResult executeTriggerAndUpdate(XxlJobInfo xxlJobInfo) {
+ BaseResult baseResult;
+ BaseResult resultExecute = executeManageJob("trigger", xxlJobInfo);
+ if (resultExecute.getStatus().equals(HttpStatus.SC_OK)) {
+ BaseResult resultUpdate = executeManageJob("update", xxlJobInfo);
+ if (resultUpdate.getStatus().equals(HttpStatus.SC_OK)) {
+ baseResult = BaseResultGenerator.success("ok", null);
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "更新任务失败: " + xxlJobInfo.getExecutorHandler());
+ }
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "执行任务失败: " + xxlJobInfo.getExecutorHandler());
+ }
+ return baseResult;
+ }
+
+ /**
+ * 查询任务状态
+ *
+ * @param jobId
+ * @return
+ */
+ private BaseResult queryJobStatusByJobId(int jobId) {
+ BaseResult baseResult = null;
+ StringBuilder url = new StringBuilder(jobAdminHttpSource.getUrl()).append("/jobinfo/jobBeat?jobId=").append(jobId);
+ Map<String, String> resultMap = httpClientService.httpGet(url.toString(), headers, httpConfig.getServerResponseTimeOut());
+ log.info("请求调度任务jobBeat接口" + url);
+ baseResult = resultEncapsulationOfJob(resultMap);
+ return baseResult;
+ }
+
+ /**
+ * 执行调度任务结果封装
+ *
+ * @param resultMap
+ * @return
+ */
+ private BaseResult resultEncapsulationOfJob(Map<String, String> resultMap) {
+ BaseResult baseResult;
+ if (StringUtil.isEmpty(resultMap)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "服务繁忙,请联系调度平台方!");
+ } else {
+ if (resultMap.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ Map result = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(resultMap.get("result")), Map.class);
+ if (result.get("code").equals(HttpStatus.SC_OK)) {
+ baseResult = BaseResultGenerator.success("ok", null);
+ } else if (result.get("code").equals(HttpStatus.SC_LOCKED)) {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_LOCKED, "Clear Task is Running.");
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, String.valueOf(result.get("msg")));
+ }
+ } else {
+ baseResult = BaseResultGenerator.failure(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Clear Task Failed.");
+ }
+ }
+ return baseResult;
+ }
+
+
+ /**
+ * 执行调度平台任务更新
+ *
+ * @param executeType
+ * @param xxlJobInfo
+ * @return
+ */
+ private BaseResult executeManageJob(String executeType, XxlJobInfo xxlJobInfo) {
+ BaseResult baseResult = null;
+ String params = getUrlParamsByMap(getObjectToMap(xxlJobInfo));
+ String url = String.format("%s/jobinfo/%s/?%s", jobAdminHttpSource.getUrl(), executeType, params);
+ Map<String, String> resultMap = httpClientService.httpGet(url, headers, httpConfig.getServerResponseTimeOut());
+ log.info("请求调度任务" + executeType + "接口" + url);
+ baseResult = resultEncapsulationOfJob(resultMap);
+ return baseResult;
+ }
+
+
+ /**
+ * 获取调度平台Cookie
+ *
+ * @return
+ */
+ public void setCookie() {
+ StringBuilder url = new StringBuilder(jobAdminHttpSource.getUrl());
+ headers.put("Content-Type", "application/json");
+ String urlParamsByMap = getUrlParamsByMap(getObjectToMap(jobAdminHttpSource));
+ int socketTimeOut = httpConfig.getServerResponseTimeOut();
+ Map httpPostResponseHeads = httpClientService.getHttpPostResponseHeads(url + "/login?" + urlParamsByMap, headers, socketTimeOut);
+ String cookie = String.valueOf(httpPostResponseHeads.get("SET-COOKIE"));
+ headers.put("Cookie", cookie);
+ }
+
+ /**
+ * 通过handler Value获取jobInfo数据
+ *
+ * @param handlerValue
+ * @return
+ */
+ private Map getDataByHandler(String handlerValue) {
+ StringBuilder url = new StringBuilder(jobAdminHttpSource.getUrl()).
+ append("/jobinfo/pageList?jobGroup=-1&triggerStatus=-1&executorHandler=").
+ append(handlerValue);
+ Map<String, String> resultPageList = httpClientService.httpGet(url.toString(), headers, httpConfig.getServerResponseTimeOut());
+ log.info("请求调度任务pageList接口 " + url);
+ if (StringUtil.isNotEmpty(resultPageList) && resultPageList.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ Map<String, Object> maps = (Map<String, Object>) JsonMapper.fromJsonString(resultPageList.get("result"), Map.class);
+ if (StringUtil.isEmpty(maps)) {
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), "获取或封装结果异常: " + resultPageList, null);
+ }
+ List<Map> data = (List) maps.get("data");
+ if (data.size() >= 1) {
+ return data.get(0);
+ } else {
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), "调度任务无匹配executorHandler(" + handlerValue + ")的任务信息", null);
+ }
+ }
+ throw new BusinessException(ResultStatusEnum.SERVER_ERROR.getCode(), "获取调度任务异常: " + resultPageList, null);
+ }
+
+ /**
+ * 更新jobInfo
+ *
+ * @param data
+ * @param executorParam
+ * @return
+ */
+ private XxlJobInfo setXxlJobInfoParam(Map data, ExecutorParam executorParam) {
+ XxlJobInfo xxlJobInfo = mapToBean(data, XxlJobInfo.class);
+ xxlJobInfo.setExecutorParam(JsonMapper.toJsonString(executorParam));
+ return xxlJobInfo;
+ }
+
+ public static String getUrlParamsByMap(Map<String, Object> map) {
+ if (map == null) {
+ return "";
+ }
+ StringBuffer sb = new StringBuffer();
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ sb.append(entry.getKey() + "=" + Encodes.urlEncode(String.valueOf(entry.getValue())));
+ sb.append("&");
+ }
+ String s = sb.toString();
+ if (s.endsWith("&")) {
+ s = StringUtil.substringBeforeLast(s, "&");
+ }
+ return s;
+ }
+
+ public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
+ T bean = null;
+ try {
+ bean = clazz.newInstance();
+ } catch (InstantiationException e) {
+ log.error("Instantiation Exception: ", e);
+ } catch (IllegalAccessException e) {
+ log.error("Illegal Access Exception: ", e);
+ }
+ BeanMap beanMap = BeanMap.create(bean);
+ beanMap.putAll(map);
+ return bean;
+ }
+
+ public static Map<String, Object> getObjectToMap(Object obj) {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ Class<?> clazz = obj.getClass();
+ for (Field field : clazz.getDeclaredFields()) {
+ field.setAccessible(true);
+ String fieldName = field.getName();
+ Object value = null;
+ try {
+ value = field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.error("Illegal Access Exception: ", e);
+ }
+ if (value == null) {
+ value = "";
+ }
+ map.put(fieldName, value);
+ }
+ return map;
+ }
+
+
+ enum LogType {
+ TRAFFIC_LOGS("Traffic Logs"), REPORT_AND_METRICS("Report and Metrics"), FILES("Files"), ALL("ALL");
+ private final String value;
+
+ LogType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java
new file mode 100644
index 0000000..478214c
--- /dev/null
+++ b/galaxy-query-engine/src/main/java/com/mesalab/qgw/service/impl/TestSqlServiceImpl.java
@@ -0,0 +1,617 @@
+package com.mesalab.qgw.service.impl;
+
+
+import com.google.common.collect.Maps;
+import com.mesalab.common.base.BaseResult;
+import com.mesalab.common.base.BaseResultGenerator;
+import com.mesalab.common.configuration.ClickHouseProperties;
+import com.mesalab.common.configuration.DruidIoProperties;
+import com.mesalab.common.enums.ResultStatusEnum;
+import com.mesalab.common.exception.BusinessException;
+import com.mesalab.common.utils.JsonMapper;
+import com.mesalab.common.utils.SchemaCacheUtils;
+import com.mesalab.knowledge.common.utils.HttpConfig;
+import com.mesalab.qgw.model.api.ClickHouseHttpSource;
+import com.zdjizhi.utils.Encodes;
+import com.zdjizhi.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.avro.JsonProperties;
+import org.apache.avro.Schema;
+import org.apache.avro.data.Json;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+@Service
+public class TestSqlServiceImpl {
+
+ @Autowired
+ HttpClientService httpClientService;
+ @Autowired
+ private ClickHouseProperties clickHouseProperties;
+ @Autowired
+ public ApiServiceImpl apiServiceImpl;
+ @Autowired
+ public DruidIoProperties druidIoProperties;
+ @Autowired
+ public ClickHouseHttpSource clickHouseHttpSource;
+ @Autowired
+ HttpConfig httpConfig;
+ @Value("${server.port}")
+ private int serverPort;
+ private List errorDate;
+
+
+ /**
+ * 运行测试用例
+ *
+ * @return
+ */
+ public BaseResult runSql() {
+ long start = System.currentTimeMillis();
+ List list = ckSql();
+ List listDruid = druidSql();
+ list.addAll(listDruid);
+ Map<String, String> resultTemp = null;
+ BaseResult result = null;
+ List<Object> data = new ArrayList<>();
+ int countSuccess = 0;
+ SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
+ SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date date = new Date(System.currentTimeMillis());
+ String hostAddress = null;
+ try {
+ hostAddress = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ hostAddress = "127.0.0.1";
+ log.error("获取服务器IP异常", e);
+ }
+ for (int i = 0; i < list.size(); i++) {
+ String sql = String.valueOf(list.get(i));
+ try {
+ sql = sql.replaceAll("\\$start_time", "'" + format1.format(date) + "'");
+ sql = sql.replaceAll("\\$end_time", "'" + format2.format(date) + "'");
+ sql = URLEncoder.encode(sql, "utf-8").replaceAll("\\+", "%20");
+ } catch (Exception e) {
+ log.error("测试用例sql编码错误", e);
+ }
+ resultTemp = httpClientService.httpGet("http://" + hostAddress + ":" + serverPort + "/?query=" + sql, httpConfig.getServerResponseTimeOut());
+ if (resultTemp.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ resultTemp.remove("result");
+ countSuccess++;
+ } else {
+ try {
+ resultTemp.put("query", URLDecoder.decode(sql, "UTF-8"));
+ } catch (Exception e) {
+ log.error("sql查询结果处理异常", e);
+ }
+ }
+ data.add(resultTemp);
+ }
+
+ Collections.sort(data, new Comparator<Object>() {
+
+ @Override
+ public int compare(Object o1, Object o2) {
+ Map<String, Object> oneMap = (Map<String, Object>) o1;
+ Map<String, Object> twoMap = (Map<String, Object>) o2;
+ return Integer.valueOf(twoMap.get("status").toString()).compareTo(Integer.valueOf(oneMap.get("status").toString()));
+ }
+ });
+ long cost = System.currentTimeMillis() - start;
+ HashMap<String, Object> statistics = new HashMap<>();
+ statistics.put("elapsed", String.format("%.2f", (double) cost / 1000));
+ statistics.put("total", list.size());
+ statistics.put("success", countSuccess);
+ String message = countSuccess == list.size() ? "ok" : "error";
+ result = BaseResultGenerator.success(message, data, statistics);
+ return result;
+ }
+
+ /**
+ * 运行schema校验
+ *
+ * @return
+ */
+ public BaseResult runSchema() {
+ SchemaCacheUtils.removeAll();
+ long start = System.currentTimeMillis();
+ errorDate = new ArrayList();
+ checkCKSchema("/config/avro/clickhouse");
+ checkDruidSchema("/config/avro/druid");
+ checkSchema("/config/avro/clickhouse");
+ checkSchema("/config/avro/druid");
+ long cost = System.currentTimeMillis() - start;
+ HashMap<String, Object> statistics = new HashMap<>();
+ statistics.put("elapsed", String.format("%.2f", (double) cost / 1000));
+ String message = errorDate.size() == 0 ? "ok" : "error";
+ return BaseResultGenerator.success(message, errorDate, statistics);
+ }
+
+
+ public List ckSql() {
+ List<String> list = new ArrayList<>();
+ list.add("select toDateTime(common_recv_time) as common_recv_time,common_subscriber_id, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, ssl_sni, ssl_version from security_event_log where common_recv_time >= toDateTime($start_time) and common_recv_time< toDateTime($end_time) and common_client_ip like '49.7%' order by common_recv_time desc limit 0,20");
+ list.add("select FROM_UNIXTIME(common_recv_time) as common_recv_time,common_subscriber_id, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, ssl_sni, ssl_version from security_event_log where common_recv_time >= UNIX_TIMESTAMP($start_time) and common_recv_time< UNIX_TIMESTAMP($end_time) and common_client_ip like '49.7%' order by common_recv_time desc limit 0,20");
+ list.add("select toDateTime(common_recv_time) as common_recv_time,common_subscriber_id, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, http_host,http_url,http_user_agent from proxy_event_log where common_recv_time >= toDateTime($start_time) and common_recv_time< toDateTime($end_time) and http_host like '%joy.cn%' order by common_recv_time desc limit 0,20");
+ list.add("select FROM_UNIXTIME(common_recv_time) as common_recv_time,common_subscriber_id, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, http_host,http_url,http_user_agent from proxy_event_log where common_recv_time >= UNIX_TIMESTAMP($start_time) and common_recv_time< UNIX_TIMESTAMP($end_time) and http_host like '%joy.cn%' order by common_recv_time desc limit 0,20");
+ list.add("select toDateTime(common_recv_time) as common_recv_time, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, radius_framed_ip, radius_account from radius_record_log where common_recv_time >= toDateTime($start_time) and common_recv_time< toDateTime($start_time) and radius_account='T1yRd' order by common_recv_time desc limit 0,20");
+ list.add("select FROM_UNIXTIME(common_recv_time) as common_recv_time,common_subscriber_id, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, http_host,http_url,http_user_agent from proxy_event_log where common_recv_time >= UNIX_TIMESTAMP($start_time) and common_recv_time< UNIX_TIMESTAMP($end_time) and http_host like '%joy.cn%' order by common_recv_time desc limit 0,20");
+ list.add("select toDateTime(common_recv_time) as common_recv_time, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, radius_framed_ip, radius_account from radius_record_log where common_recv_time >= toDateTime($start_time) and common_recv_time< toDateTime($start_time) and radius_account='T1yRd' order by common_recv_time desc limit 0,20");
+ list.add("select FROM_UNIXTIME(common_recv_time) as common_recv_time, common_address_type, common_l4_protocol, common_client_ip, common_server_ip, common_server_port, radius_framed_ip, radius_account from radius_record_log where common_recv_time >= UNIX_TIMESTAMP($start_time) and common_recv_time< UNIX_TIMESTAMP($end_time) and radius_account='T1yRd' order by common_recv_time desc limit 0,20");
+ list.add("select FROM_UNIXTIME(common_recv_time) as common_recv_time,common_log_id,common_policy_id,common_subscriber_id,common_client_ip,common_client_port,common_l4_protocol,common_address_type,common_server_ip,common_server_port,common_action,common_direction,common_sled_ip,common_client_location,common_client_asn,common_server_location,common_server_asn,common_c2s_pkt_num,common_s2c_pkt_num,common_c2s_byte_num,common_s2c_byte_num,common_schema_type,common_sub_action,common_device_id, FROM_UNIXTIME(common_start_time) as common_start_time, FROM_UNIXTIME(common_end_time) as common_end_time,common_establish_latency_ms,common_con_duration_ms,common_stream_dir,common_stream_trace_id,http_url,http_host,http_domain,http_request_body,http_response_body,http_cookie,http_referer,http_user_agent,http_content_length,http_content_type,http_set_cookie,http_version,http_response_lantency_ms,http_action_file_size,http_session_duration_ms,mail_protocol_type,mail_account,mail_from_cmd,mail_to_cmd,mail_from,mail_to,mail_cc,mail_bcc,mail_subject,mail_attachment_name,mail_eml_file,dns_message_id,dns_qr,dns_opcode,dns_aa,dns_tc,dns_rd,dns_ra,dns_rcode,dns_qdcount,dns_ancount,dns_nscount,dns_arcount,dns_qname,dns_qtype,dns_qclass,dns_cname,dns_sub,dns_rr,ssl_sni,ssl_san,ssl_cn,ssl_pinningst,ssl_intercept_state,ssl_server_side_latency,ssl_client_side_latency,ssl_server_side_version,ssl_client_side_version,ssl_cert_verify,ssl_error,quic_version,quic_sni,quic_user_agent,ftp_account,ftp_url,ftp_content from security_event_log where common_recv_time >= $start_time and common_recv_time < $end_time and common_log_id in ( 289451559826124800 , 332 ) and ( common_server_ip like '192.168%' ) order by common_recv_time desc limit 100000");
+
+ list.add("select count(1) from connection_record_log");
+ list.add("select count(*) from connection_record_log");
+ list.add("select * from " + clickHouseProperties.getDbname() + ".connection_record_log limit 1");
+ //二次查询
+ list.add("select * from (select FROM_UNIXTIME(TIME_FLOOR_WITH_FILL(common_recv_time,'PT5M','zero')) as stat_time from connection_record_log where common_recv_time >= toDateTime($start_time) and common_recv_time< toDateTime($end_time) group by stat_time order by stat_time asc)");
+
+ //Radius 用户分析
+ //1. radius账户申请客户端IP变化
+ list.add("select framed_ip, arraySlice(groupUniqArray(concat(toString(event_timestamp),':', if(acct_status_type=1,'start','stop'))),1,100000) as timeseries \n" +
+ "from radius_onff_log where event_timestamp >=toDateTime($start_time) and event_timestamp <toDateTime($end_time) and account='admin' group by framed_ip");
+ list.add("select framed_ip, arraySlice(groupUniqArray(concat(toString(event_timestamp),':', if(acct_status_type=1,'start','stop'))),1,100000) as timeseries \n" +
+ "from radius_onff_log where event_timestamp >=$start_time and event_timestamp < $end_time and account='admin' group by framed_ip");
+ //2. 用户IP承载用户变化
+ list.add("select account, arraySlice(groupUniqArray(concat(toString(event_timestamp),':', if(acct_status_type=1,'start','stop'))),1,100000) as timeseries \n" +
+ "from radius_onff_log where event_timestamp >= $start_time and event_timestamp < $end_time and framed_ip='127.0.0.1' group by account");
+ list.add("select account, arraySlice(groupUniqArray(concat(toString(event_timestamp),':', if(acct_status_type=1,'start','stop'))),1,100000) as timeseries \n" +
+ "from radius_onff_log where event_timestamp >= $start_time and event_timestamp < $end_time and framed_ip='127.0.0.1' group by account");
+ //自定义报告API
+ //一. 预置Internal Hosts 报告
+ list.add("select common_client_ip, count(*) as sessions from connection_record_log where common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($end_time)) group by common_client_ip order by sessions desc limit 0,100");
+ //二. 预置External Hosts 报告
+ list.add("select common_server_ip, count(*) as sessions from connection_record_log where common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($start_time)) group by common_server_ip order by sessions desc limit 0,100");
+ //三. 预置Domains报告
+ list.add("select http_domain AS domain,SUM(coalesce(common_c2s_byte_num, 0)) AS sent_bytes,SUM(coalesce(common_s2c_byte_num, 0)) AS received_bytes,SUM(coalesce(common_c2s_byte_num, 0)+coalesce(common_s2c_byte_num, 0)) AS bytes FROM connection_record_log WHERE common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and notEmpty(domain) GROUP BY domain ORDER BY bytes DESC LIMIT 100");
+ list.add("select toDateTime(intDiv(toUInt32(toDateTime(toDateTime(common_recv_time))), 300)*300) as stat_time, http_domain, uniq (common_client_ip) as nums from connection_record_log where common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and http_domain in (select http_domain from connection_record_log where common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and notEmpty(http_domain) group by http_domain order by SUM(coalesce(common_c2s_byte_num, 0)+coalesce(common_s2c_byte_num, 0)) desc limit 10 ) group by toDateTime(intDiv(toUInt32(toDateTime(toDateTime(common_recv_time))), 300)*300), http_domain order by stat_time asc limit 500\n");
+ list.add("SELECT http_host as host, SUM(coalesce(common_c2s_byte_num, 0)) AS sent_bytes,SUM(coalesce(common_s2c_byte_num, 0)) AS received_bytes,SUM(coalesce(common_c2s_byte_num, 0)+coalesce(common_s2c_byte_num, 0)) AS bytes FROM connection_record_log WHERE common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($start_time)) and notEmpty(http_host) GROUP BY host ORDER BY bytes DESC " +
+ "union all " +
+ "SELECT 'totals' as host, SUM(coalesce(common_c2s_byte_num, 0)) AS sent_bytes, SUM(coalesce(common_s2c_byte_num, 0)) AS received_bytes, SUM(coalesce(common_c2s_byte_num, 0)+coalesce(common_s2c_byte_num, 0)) AS bytes from connection_record_log where common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($start_time)) and notEmpty(http_host)");
+ //四. 预置HTTP/HTTPS URLS报告
+ list.add("SELECT http_url AS url,count(*) AS sessions FROM proxy_event_log WHERE common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and notEmpty(http_url) GROUP BY url ORDER BY sessions DESC LIMIT 100");
+ list.add("select toDateTime(intDiv(toUInt32(toDateTime(toDateTime(common_recv_time))), 300)*300) as stat_time, http_url, count(distinct(common_client_ip)) as nums from proxy_event_log where common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and http_url IN (select http_url from proxy_event_log where common_recv_time >= toStartOfDay(toDateTime($start_time))-86400 AND common_recv_time < toStartOfDay(toDateTime($start_time)) and notEmpty(http_url) group by http_url order by count(*) desc limit 10 )group by toDateTime(intDiv(toUInt32(toDateTime(toDateTime(common_recv_time))), 300)*300), http_url order by stat_time asc limit 500");
+ list.add("select common_subscriber_id as user, count(*) as sessions from connection_record_log where common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($start_time)) and notEmpty(user) group by common_subscriber_id order by sessions desc limit 0,100");
+ list.add("SELECT common_subscriber_id as user,SUM(coalesce(common_c2s_byte_num, 0)) AS sent_bytes,SUM(coalesce(common_s2c_byte_num, 0)) AS received_bytes,SUM(coalesce(common_c2s_byte_num, 0)+coalesce(common_s2c_byte_num, 0)) AS bytes FROM connection_record_log WHERE common_recv_time>= toStartOfDay(toDateTime($start_time))-604800 and common_recv_time< toStartOfDay(toDateTime($start_time)) and notEmpty(user) GROUP BY user ORDER BY bytes DESC LIMIT 100");
+
+ //RADIUS账户总计
+ list.add("select count(distinct(framed_ip)) as active_ip_num , sum(acct_session_time) as online_duration from (select any(framed_ip) as framed_ip ,max(acct_session_time) as acct_session_time from radius_onff_log where account='000jS' and event_timestamp >= $start_time and event_timestamp < $end_time group by acct_session_id)");
+ //RADIUS账户IP详情
+ list.add("select distinct(framed_ip) as framed_ip from radius_onff_log where account='000iS' and event_timestamp >= $start_time and event_timestamp < $end_time");
+ //RADIUS账户访问详情
+ list.add("select max(if(acct_status_type=1,event_timestamp,0)) as start_time,max(if(acct_status_type=2,event_timestamp,0)) as end_time, any(framed_ip) as ip,max(acct_session_time) as online_duration from radius_onff_log where account='000jS' and event_timestamp >= $start_time and event_timestamp < $end_time group by acct_session_id order by start_time desc limit 200");
+ //自定义函数测试
+ list.add("SELECT policy_id, APPROX_COUNT_DISTINCT_DS_HLL(isp) as num FROM proxy_event_hits_log where __time >= '2020-04-05 00:00:00' and __time < '2020-05-05 00:00:00' and policy_id=0 group by policy_id");
+ list.add("select TIME_FLOOR_WITH_FILL(common_recv_time,'PT5M','previous') as stat_time from connection_record_log where common_recv_time > $start_time and common_recv_time < $end_time group by stat_time");
+
+ return list;
+ }
+
+ public List druidSql() {
+ List<String> list = new ArrayList<>();
+ //安全策略命中统计
+ //1. 某策略命中计数
+ list.add("select policy_id, sum(hits) as hits from security_event_hits_log where __time >$start_time and __time <$end_time and policy_id=40 group by policy_id");
+ list.add("select policy_id, sum(hits) as hits from security_event_hits_log where __time >$start_time and __time <$end_time and policy_id in (9,10,88,45) group by policy_id");
+ //2. 某策略命中计数趋势
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as start_time, sum(hits) as hits from security_event_hits_log where __time >= TIMESTAMP $start_time and __time < TIMESTAMP $end_time and policy_id=10 group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') limit 100");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as start_time, sum(hits) as hits from security_event_hits_log where __time >= $start_time and __time < $end_time and policy_id=10 group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') limit 100");
+ //3. 某策略命中时间(首次和最近一次)
+ list.add("select policy_id,TIME_FORMAT(min(__time) ,'yyyy-MM-dd HH:mm:ss') as first_used, TIME_FORMAT(max(__time) ,'yyyy-MM-dd HH:mm:ss') as last_used from security_event_hits_log where policy_id in (100,101 ,105, 102) group by policy_id");
+ list.add("select policy_id, DATE_FORMAT(min(__time) ,'%Y-%m-%d %H:%i:%s') as first_used, DATE_FORMAT(max(__time) ,'%Y-%m-%d %H:%i:%s') as last_used from security_event_hits_log where policy_id in (100,101 ,105, 102) group by policy_id");
+ //4. TopN 命中策略
+ list.add("select policy_id, action, sum(hits) as hits from security_event_hits_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by policy_id, action order by hits desc limit 200");
+ list.add("select policy_id, action, sum(hits) as hits from security_event_hits_log where __time >=$start_time and __time <$end_time group by policy_id, action order by hits desc limit 200");
+ //二、 代理策略命中统计
+ //1. 某策略命中计数
+ list.add("select policy_id, sum(hits) as hits from proxy_event_hits_log where __time >=$start_time and __time <$end_time and policy_id=100 group by policy_id");
+ list.add("select policy_id, sum(hits) as hits from proxy_event_hits_log where __time >=$start_time and __time <$end_time and policy_id=100 group by policy_id");
+ //2. 某策略命中趋势
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as start_time, sum(hits) as hits from proxy_event_hits_log where __time >= TIMESTAMP $start_time and __time <TIMESTAMP $end_time and policy_id=100 group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') limit 101");
+ list.add("select FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300) as start_time, sum(hits) as hits from proxy_event_hits_log where __time >= $start_time and __time < $end_time and policy_id=100 group by FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300) limit 101");
+ //3.某策略命中时间(首次和最近一次
+ list.add("select policy_id,TIME_FORMAT(min(__time) ,'yyyy-MM-dd HH:mm:ss') as first_used, TIME_FORMAT(max(__time) ,'yyyy-MM-dd HH:mm:ss') as last_used from proxy_event_hits_log where policy_id in (100,101,102,105) group by policy_id");
+ list.add("select policy_id, DATE_FORMAT(min(__time) ,'%Y-%m-%d %H:%i:%s') as first_used, DATE_FORMAT(max(__time) ,'%Y-%m-%d %H:%i:%s') as last_used from proxy_event_hits_log where policy_id in (100,101,102,105) group by policy_id");
+ //4. TopN 命中策略
+ list.add("select policy_id, sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by policy_id, sub_action order by hits desc limit 200");
+ list.add("select policy_id, sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >=$start_time and __time <$end_time group by policy_id, sub_action order by hits desc limit 200");
+ //5. Proxy 操纵动作命中计数
+ list.add("select sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >= TIMESTAMP $start_time and __time < TIMESTAMP $end_time group by sub_action");
+ list.add("select sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >= $start_time and __time < $end_time group by sub_action");
+ //6. Proxy 操纵动作命中趋势
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as start_time, sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') , sub_action limit 100");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as start_time, sub_action as action, sum(hits) as hits from proxy_event_hits_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s'), sub_action limit 100");
+ //7. Proxy Pinning TIMESTAMP 计数
+ list.add("SELECT sum(not_pinning_num) AS sessions, 'notPinningNum' AS type FROM traffic_metrics_log WHERE __time >= $start_time AND __time < $end_time UNION ALL SELECT sum(pinning_num) AS sessions, 'pinningNum' AS type FROM traffic_metrics_log WHERE __time >= $start_time AND __time < $end_time UNION ALL SELECT sum(maybe_pinning_num) AS sessions, 'maybePinningNum' AS type FROM traffic_metrics_log WHERE __time >= $start_time AND __time < $end_time");
+ //8.Proxy Pinning计数趋势
+ list.add("SELECT TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') AS statisticTime, sum(pinning_num) AS sessions FROM traffic_metrics_log WHERE __time >= $start_time AND __time < $end_time GROUP BY TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') LIMIT 100");
+ list.add("SELECT TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') AS statisticTime, sum(not_pinning_num) AS sessions FROM traffic_metrics_log WHERE __time>= $start_time AND __time < $end_time GROUP BY TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') LIMIT 100");
+ list.add("SELECT TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') AS statisticTime, sum(maybe_pinning_num) AS sessions FROM traffic_metrics_log WHERE __time >= $start_time AND __time < $end_time GROUP BY TIME_FORMAT( MILLIS_TO_TIMESTAMP( 1000 * (TIMESTAMP_TO_MILLIS(time_floor(0.001 * TIMESTAMP_TO_MILLIS( __time) * 1000,'PT300S'))/1000)),'YYYY-MM-dd HH:mm:ss') LIMIT 100");
+ //三、 Traffics-带宽统计
+ //1. Traffic IN/OUT 计数
+ //Bytes
+ list.add("select sum(total_in_bytes) as traffic_in_bytes, sum(total_out_bytes) as traffic_out_bytes from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time");
+ list.add("select sum(total_in_bytes) as traffic_in_bytes, sum(total_out_bytes) as traffic_out_bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //Packets
+ list.add("select sum(total_in_packets) as traffic_in_packets, sum(total_out_packets) as traffic_out_packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time");
+ list.add("select sum(total_in_packets) as traffic_in_packets, sum(total_out_packets) as traffic_out_packets from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //Sessions
+ list.add("select sum(new_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time");
+ list.add("select sum(new_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //2. Traffic IN/OUT 带宽趋势
+ //Bytes
+ list.add("select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_in_bytes' as type, sum(total_in_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_out_bytes' as type, sum(total_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_in_bytes' as type, sum(total_in_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_out_bytes' as type, sum(total_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')");
+ //Packets
+ list.add("select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_in_packets' as type, sum(total_in_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_out_packets' as type, sum(total_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_in_packets' as type, sum(total_in_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_out_packets' as type, sum(total_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')");
+ //Packets
+ list.add("select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_in_packets' as type, sum(total_in_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'traffic_out_packets' as type, sum(total_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_in_packets' as type, sum(total_in_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'traffic_out_packets' as type, sum(total_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')");
+ //Sessions
+ list.add("select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'new_conn_num' as type, sum(new_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'new_conn_num' as type, sum(new_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')");
+ //四、 Traffics-计数统计
+ //1. 新建与活跃链接计数
+ list.add("select sum(new_conn_num) as new_conn_num, sum(established_conn_num) as established_conn_num from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time");
+ list.add("select sum(new_conn_num) as new_conn_num, sum(established_conn_num) as established_conn_num from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //2.新建与活跃链接计数趋势
+ list.add("select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'new_conn_num' as type, sum(new_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time < TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'established_conn_num' as type, sum(established_conn_num) as sessions from traffic_metrics_log where __time >= TIMESTAMP $start_time and __time < TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT30S'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'new_conn_num' as type, sum(new_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s') as stat_time, 'established_conn_num' as type, sum(established_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/30)*30),'%Y-%m-%d %H:%i:%s')");
+ //3. 安全策略动作计数
+ //Bytes
+ list.add("select sum(default_in_bytes+default_out_bytes) as default_bytes, sum(allow_in_bytes+allow_out_bytes) as allow_bytes, sum(deny_in_bytes+deny_out_bytes) as deny_bytes, sum(monitor_in_bytes+monitor_out_bytes) as monitor_bytes, sum(intercept_in_bytes+intercept_out_bytes) as intercept_bytes from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time < TIMESTAMP $end_time");
+ list.add("select sum(default_in_bytes+default_out_bytes) as default_bytes, sum(allow_in_bytes+allow_out_bytes) as allow_bytes, sum(deny_in_bytes+deny_out_bytes) as deny_bytes, sum(monitor_in_bytes+monitor_out_bytes) as monitor_bytes, sum(intercept_in_bytes+intercept_out_bytes) as intercept_bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //Packets
+ list.add("select sum(default_in_packets+default_out_packets) as default_packets, sum(allow_in_packets+allow_in_packets) as allow_packets, sum(deny_in_packets+deny_out_packets) as deny_packets, sum(monitor_in_packets+monitor_out_packets) as monitor_packets, sum(intercept_in_packets+intercept_out_packets) as intercept_packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time\n");
+ list.add("select sum(default_in_packets+default_out_packets) as default_packets, sum(allow_in_packets+allow_in_packets) as allow_packets, sum(deny_in_packets+deny_out_packets) as deny_packets, sum(monitor_in_packets+monitor_out_packets) as monitor_packets, sum(intercept_in_packets+intercept_out_packets) as intercept_packets from traffic_metrics_log where __time >= $start_time and __time < $end_time\n");
+ //Sessions
+ list.add("select sum(default_conn_num) as default_sessions, sum(allow_conn_num) as allow_sessions, sum(deny_conn_num) as deny_sessions, sum(monitor_conn_num) as monitor_sessions, sum(intercept_conn_num) as intercept_sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time");
+ list.add("select sum(default_conn_num) as default_sessions, sum(allow_conn_num) as allow_sessions, sum(deny_conn_num) as deny_sessions, sum(monitor_conn_num) as monitor_sessions, sum(intercept_conn_num) as intercept_sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time");
+ //4. 安全策略动作趋势
+ //Bytes
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'default_bytes' as type, sum(default_in_bytes+default_out_bytes) as bytes from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'allow_bytes' as type, sum(allow_in_bytes+allow_out_bytes) as bytes from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'deny_bytes' as type, sum(deny_in_bytes+deny_out_bytes) as bytes from traffic_metrics_log where __time >= TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') \n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'monitor_bytes' as type, sum(monitor_in_bytes+monitor_out_bytes) as bytes from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'intercept_bytes' as type, sum(intercept_in_bytes+intercept_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'default_bytes' as type, sum(default_in_bytes+default_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'allow_bytes' as type, sum(allow_in_bytes+allow_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'deny_bytes' as type, sum(deny_in_bytes+deny_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') \n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'monitor_bytes' as type, sum(monitor_in_bytes+monitor_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'intercept_bytes' as type, sum(intercept_in_bytes+intercept_out_bytes) as bytes from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')");
+ //packets
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'default_packets' as type, sum(default_in_packets+default_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'allow_packets' as type, sum(allow_in_packets+allow_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'deny_packets' as type, sum(deny_in_packets+deny_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') \n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'monitor_packets' as type, sum(monitor_in_packets+monitor_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'intercept_packets' as type, sum(intercept_in_packets+intercept_out_packets) as packets from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'default_packets' as type, sum(default_in_packets+default_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'allow_packets' as type, sum(allow_in_packets+allow_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'deny_packets' as type, sum(deny_in_packets+deny_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') \n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'monitor_packets' as type, sum(monitor_in_packets+monitor_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'intercept_packets' as type, sum(intercept_in_packets+intercept_out_packets) as packets from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')");
+ //sessions
+ list.add("select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'default_conn_num' as type, sum(default_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'allow_conn_num' as type, sum(allow_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'deny_conn_num' as type, sum(deny_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') \n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'monitor_conn_num' as type, sum(monitor_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')\n" +
+ "union all\n" +
+ "select TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss') as stat_time, 'intercept_conn_num' as type, sum(intercept_conn_num) as sessions from traffic_metrics_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by TIME_FORMAT(time_floor(__time,'PT5M'),'yyyy-MM-dd HH:mm:ss')");
+ list.add("select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'default_conn_num' as type, sum(default_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'allow_conn_num' as type, sum(allow_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'deny_conn_num' as type, sum(deny_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') \n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'monitor_conn_num' as type, sum(monitor_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')\n" +
+ "union all\n" +
+ "select DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s') as stat_time, 'intercept_conn_num' as type, sum(intercept_conn_num) as sessions from traffic_metrics_log where __time >= $start_time and __time < $end_time group by DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(__time)/300)*300),'%Y-%m-%d %H:%i:%s')");
+ //五. Traffics-TOPN统计
+ //1. TopN 源IP
+ list.add("select source as client_ip, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_internal_host_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time and order_by=source group by source order by source desc limit 100");
+ list.add("select source as client_ip, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_internal_host_log where __time >= $start_time and __time < $end_time and order_by=source group by source order by source desc limit 100");
+ //2. TopN 目的IP
+ list.add("select destination as server_ip, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_external_host_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time and order_by=destination group by destination order by destination desc limit 100");
+ list.add("select destination as server_ip, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_external_host_log where __time >= $start_time and __time < $end_time and order_by=destination group by destination order by destination desc limit 100");
+ //3. TopN 域名
+ list.add("select domain, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_website_domain_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time and order_by=domain group by domain order by domain desc limit 200");
+ list.add("select domain, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_website_domain_log where __time >= $start_time and __time < $end_time and order_by=domain group by domain order by domain desc limit 200");
+ //4.TopN 用户
+ list.add("select subscriber_id, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_user_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time and order_by=subscriber_id group by subscriber_id order by subscriber_id desc limit 200");
+ list.add("select subscriber_id, sum(session_num) as sessions, sum(c2s_byte_num) as sent_bytes, sum(s2c_byte_num) as received_bytes, sum(c2s_byte_num + s2c_byte_num) as bytes, sum(c2s_pkt_num) as sent_packets ,sum(s2c_pkt_num) as received_packets, sum(c2s_pkt_num+s2c_pkt_num) as packets from top_user_log where __time >= $start_time and __time < $end_time and order_by=subscriber_id group by subscriber_id order by subscriber_id desc limit 200");
+ //六、命中URL统计
+ list.add("select url,sum(session_num) as hits from top_urls_log where __time >=TIMESTAMP $start_time and __time <TIMESTAMP $end_time group by url order by hits desc limit 100");
+ list.add("select url,sum(session_num) as hits from top_urls_log where __time >= $start_time and __time < $end_time group by url order by hits desc limit 100");
+
+ //劫持客户端数量
+ list.add("SELECT policy_id, APPROX_COUNT_DISTINCT_DS_HLL(isp) as num FROM proxy_event_hits_log where __time >= $start_time and __time < $end_time and policy_id=0 group by policy_id");
+
+ return list;
+ }
+
+
+ /**
+ * 查询clickhouse数据库
+ *
+ * @param query
+ * @return
+ */
+ private List queryCKDynamic(String query) {
+ StringBuilder urlBuilder = new StringBuilder("http://")
+ .append(clickHouseHttpSource.getUrl()).append("/?");
+ StringBuilder queryparamBuilder = new StringBuilder("user=")
+ .append(clickHouseHttpSource.getRealTimeAccount().getUsername()).append("&")
+ .append("password=").append(clickHouseHttpSource.getRealTimeAccount().getPassword()).append("&")
+ .append("database=")
+ .append(clickHouseHttpSource.getDbName()).append("&")
+ .append("query=").append(query)
+ .append(" FORMAT JSON;");
+
+ log.info("Query Session and Events Query : {}", urlBuilder.toString() + Encodes.urlDecode(queryparamBuilder.toString()));
+ List<NameValuePair> values = URLEncodedUtils.parse(queryparamBuilder.toString(), Charset.forName("UTF-8"));
+ String s = urlBuilder.toString() + URLEncodedUtils.format(values, "utf-8");
+ Map<String, String> resultMap = httpClientService.httpGet(s, httpConfig.getCkRealTimeAccountSocketTimeOut());
+ List result = new ArrayList<>();
+ if (resultMap.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ Map<String, Object> maps = (Map<String, Object>) JsonMapper.fromJsonString(resultMap.get("result"), Map.class);
+ List data = (List) maps.get("data");
+ Iterator iterator = data.iterator();
+ while (iterator.hasNext()) {
+ Map next = (Map) iterator.next();
+ result.add(String.valueOf(next.get("name")));
+ }
+ return result;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * 查询druid数据库
+ *
+ * @param query
+ * @return
+ */
+ private List queryDruidDynamic(String query) {
+ //headers
+ HttpHeaders requestHeaders = new HttpHeaders();
+ requestHeaders.setContentType(MediaType.APPLICATION_JSON);
+ //body
+ Map<String, Object> params = Maps.newHashMap();
+ params.put("query", query);
+ int socketTimeOut = httpConfig.getDruidSocketTimeOut();
+ Map<String, String> resultMap = httpClientService.httpPost("http://" + druidIoProperties.getUrl(), JsonMapper.toJsonString(params), socketTimeOut);
+ if (resultMap.get("status").equals(String.valueOf(HttpStatus.SC_OK))) {
+ List<String> list = new ArrayList<>();
+ String result = resultMap.get("result");
+ List body = (List) Json.parseJson(result);
+ Iterator iterator = body.iterator();
+ while (iterator.hasNext()) {
+ Map next = (Map) iterator.next();
+ String name = String.valueOf(next.get("name"));
+ list.add(name);
+ }
+ return list;
+ }
+ return null;
+ }
+
+
+ private void checkDruidSchema(String path) {
+ Map<String, JsonProperties> druidSchemaInfo = getSchemaInfo(path);
+ Set<String> name = druidSchemaInfo.keySet();
+ Iterator<String> iterator = name.iterator();
+ while (iterator.hasNext()) {//遍历表,以Avro为基础
+ String tableName = iterator.next();
+ Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(druidSchemaInfo.get(tableName)), Map.class);
+ if (resultMap == null) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
+ }
+ //查数据库
+ List resultSql = queryDruidDynamic("SELECT COLUMN_NAME as name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + tableName + "'");
+
+ List resultAvro = new ArrayList();
+
+ //schema为基础
+ List<Map> fields = (List<Map>) resultMap.get("fields");//遍历列
+ Iterator<Map> fieldsAvro = fields.iterator();
+ while (fieldsAvro.hasNext()) {
+ Map next = fieldsAvro.next();
+ resultAvro.add(String.valueOf(next.get("name")));
+ boolean b = resultSql.contains(next.get("name"));
+ if (!b) {
+ String str = String.format("%s.avro中注册多余:%s", tableName, next.get("name"));
+ errorDate.add(str);
+ }
+ }
+
+ //Schema为基础
+ Iterator iteratorSql = resultSql.iterator();
+ while (iteratorSql.hasNext()) {
+ String next = String.valueOf(iteratorSql.next());
+ boolean b = resultAvro.contains(next);
+ if (!b) {
+ String str = String.format("%s.avro中注册缺少:%s", tableName, next);
+ errorDate.add(str);
+ }
+ }
+ }
+ }
+
+
+ private void checkCKSchema(String path) {
+ Map<String, JsonProperties> ckSchemaInfo = getSchemaInfo(path);
+ Set<String> name = ckSchemaInfo.keySet();
+ Iterator<String> iterator = name.iterator();
+ while (iterator.hasNext()) {//遍历表,以Avro为基础
+ String tableName = iterator.next();
+ Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(ckSchemaInfo.get(tableName)), Map.class);
+ if (resultMap == null) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
+ }
+ //查数据库
+ List resultSql = queryCKDynamic("describe " + tableName);
+ if (StringUtil.isEmpty(resultSql)) {
+ String str = String.format("avro中注册多余:%s.avsc", tableName);
+ errorDate.add(str);
+ continue;
+ }
+
+ List resultAvro = new ArrayList();
+
+ //avro为基础
+ List<Map> fields = (List<Map>) resultMap.get("fields");//遍历列
+ Iterator<Map> fieldsAvro = fields.iterator();
+ while (fieldsAvro.hasNext()) {
+ Map next = fieldsAvro.next();
+ resultAvro.add(String.valueOf(next.get("name")));
+ boolean b = resultSql.contains(next.get("name"));
+ if (!b) {
+ String str = String.format("%s.avro中注册多余:%s", tableName, next.get("name"));
+ errorDate.add(str);
+ }
+ }
+
+ //db为基础
+ Iterator iteratorSql = resultSql.iterator();
+ while (iteratorSql.hasNext()) {
+ String next = String.valueOf(iteratorSql.next());
+ boolean b = resultAvro.contains(next);
+ if (!b) {
+ String str = String.format("%s.avro中注册缺少:%s", tableName, next);
+ errorDate.add(str);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 获取avro文件
+ *
+ * @param path
+ * @return
+ */
+ private Map<String, JsonProperties> getSchemaInfo(String path) {
+ Map<String, JsonProperties> schema = new HashMap<>();
+ String pathRoot = null;
+ try {
+ pathRoot = new File("").getCanonicalPath();
+ File file = new File(pathRoot + path);
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ if (!f.getName().toLowerCase().endsWith(".avsc")) {
+ continue;
+ }
+ try {
+ Schema ckSchema = new Schema.Parser().parse(new File(f.getPath()));
+ schema.put(ckSchema.getName(), ckSchema);
+ } catch (Exception ex) {
+ log.error("遍历" + path + "路径下文件失败: " + f.getName(), ex);
+ String str = String.format("%s读取文件失败:%s", path, f.getName());
+ errorDate.add(str);
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error("获取 项目路径/{}失败", path);
+ String str = String.format("获取项目路径%s失败", path);
+ errorDate.add(str);
+ }
+ return schema;
+ }
+
+
+ /**
+ * 核对avro文件
+ *
+ * @param path 路径
+ */
+ private void checkSchema(String path) {
+ Map<String, JsonProperties> ckeckSchemaInfo = getSchemaInfo(path);
+ Set<String> name = ckeckSchemaInfo.keySet();
+ Iterator<String> iterator = name.iterator();
+ while (iterator.hasNext()) {//遍历表
+ String tableName = iterator.next();
+ Map resultMap = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(ckeckSchemaInfo.get(tableName)), Map.class);
+ if (resultMap == null) {
+ throw new BusinessException(ResultStatusEnum.FAIL.getCode(), "schema未注册此表: " + tableName, null);
+ }
+ List<Map> fields = (List<Map>) resultMap.get("fields");//遍历列
+ Iterator<Map> fieldsIterator = fields.iterator();
+ Map mapDoc = null;
+ while (fieldsIterator.hasNext()) {
+ Map next = fieldsIterator.next();
+ try {
+ mapDoc = (Map) com.zdjizhi.utils.JsonMapper.fromJsonString(String.valueOf(next.get("doc")), Map.class);
+ } catch (Exception ex) {
+ log.error("该字段的 doc 为非JSON字符串,不需类型转换");
+ String str = String.format("%s.avro中doc非json格式字段%s", tableName, next.get("name"));
+ errorDate.add(str);
+ }
+ if (mapDoc != null) {
+ next.put("doc", mapDoc);
+ }
+ if (StringUtil.isEmpty(mapDoc) && !StringUtil.isEmpty(next.get("doc"))) {
+ log.error("该字段的 doc 为非JSON字符串,不需类型转换");
+ String str = String.format("%s.avro中doc非json格式字段%s", tableName, next.get("name"));
+ errorDate.add(str);
+ }
+ }
+ }
+ }
+}
diff --git a/galaxy-query-engine/src/main/resources/dsl-validation.json b/galaxy-query-engine/src/main/resources/dsl-validation.json
new file mode 100644
index 0000000..f54eb05
--- /dev/null
+++ b/galaxy-query-engine/src/main/resources/dsl-validation.json
@@ -0,0 +1,231 @@
+{
+ "title": "服务推荐",
+ "description": "查询",
+ "type": "object",
+ "properties": {
+ "clientId": {
+ "description": "唯一标识符",
+ "maximum": 2147483647,
+ "minimum": -2147483648,
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "query": {
+ "description": "查询条件",
+ "type": "object",
+ "required": [
+ "dataSource"
+ ],
+ "properties": {
+ "queryType": {
+ "description": "查询类型",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "dataSource": {
+ "description": "查询数据源",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "parameters": {
+ "description": "查询参数",
+ "type": "object",
+ "properties": {
+ "match": {
+ "description": "模糊查询参数",
+ "type": "array",
+ "items": [
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "fieldKey",
+ "fieldValues"
+ ],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "查询字段",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldValues": {
+ "description": "查询参数",
+ "type": "array",
+ "items": {
+ "maxLength": 65535,
+ "type": "string"
+ }
+ }
+ }
+ }
+ ],
+ "additionalItems": {
+ "type": "object",
+ "required": [
+ "type",
+ "fieldKey",
+ "fieldValues"
+ ],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "查询字段",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldValues": {
+ "description": "查询参数",
+ "type": "array",
+ "items": {
+ "maxLength": 65535,
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "range": {
+ "description": "范围查询参数",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "fieldKey",
+ "fieldValues"
+ ],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "查询字段",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldValues": {
+ "description": "查询参数",
+ "type": "array",
+ "items": {
+ "maximum": 2147483647,
+ "minimum": -2147483648,
+ "maxLength": 65535,
+ "type": [
+ "integer",
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ "additionalItems": {
+ "type": "object",
+ "required": [
+ "type",
+ "fieldKey",
+ "fieldValues"
+ ],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "查询字段",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldValues": {
+ "description": "查询参数",
+ "type": "array",
+ "items": {
+ "maximum": 2147483647,
+ "minimum": -2147483648,
+ "maxLength": 65535,
+ "type": [
+ "integer",
+ "string"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "intervals": {
+ "description": "查询时间",
+ "type": "array",
+ "items": {
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "additionalItems": {
+ "maxLength": 65535,
+ "type": "string"
+ }
+ },
+ "sort": {
+ "description": "排序",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["type","fieldKey"],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "排序字段",
+ "maxLength": 65535,
+ "type": "string"
+ }
+ }
+ },
+ "additionalItems": {
+ "type": "object",
+ "required": ["type","fieldKey"],
+ "properties": {
+ "type": {
+ "description": "匹配符号",
+ "maxLength": 65535,
+ "type": "string"
+ },
+ "fieldKey": {
+ "description": "排序字段",
+ "maxLength": 65535,
+ "type": "string"
+ }
+ }
+ }
+ },
+ "limit": {
+ "description": "查询条数",
+ "maxLength": 65535,
+ "maximum": 2147483647,
+ "minimum": 0,
+ "type": [
+ "integer",
+ "string"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/galaxy-query-engine/src/main/resources/sql-temelate.sql b/galaxy-query-engine/src/main/resources/sql-temelate.sql
new file mode 100644
index 0000000..f3c2ca5
--- /dev/null
+++ b/galaxy-query-engine/src/main/resources/sql-temelate.sql
@@ -0,0 +1,7 @@
+#sql("appDicList")
+ select app_id,app_name from app_id_dict
+#end
+
+#sql("reportResults")
+ select * from report_result where job_id = ? and status !=2 order by op_time desc
+#end \ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0d9c241..1a72e60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,25 +57,32 @@
<avro.version>1.9.1</avro.version>
<nutz.version>1.r.65</nutz.version>
<guava.version>23.0</guava.version>
+ <log4j.version>2.10.0</log4j.version>
<hutool.version>5.4.0</hutool.version>
<lombok.version>1.18.6</lombok.version>
<zdjizhi.version>1.0.4</zdjizhi.version>
+ <jakarta.version>3.0.0</jakarta.version>
<commonsio.version>2.2</commonsio.version>
<joda.time.version>2.6</joda.time.version>
- <jakarta.version>3.0.0</jakarta.version>
+ <jsqlparser.version>3.0</jsqlparser.version>
<jsqlparser.version>3.0</jsqlparser.version>
<google.gson.version>2.8.6</google.gson.version>
+ <docker.registry>192.168.40.153</docker.registry>
+ <docker.registry.port>9080</docker.registry.port>
<json.schema.version>2.2.10</json.schema.version>
+ <docker.image.prefix>galaxy</docker.image.prefix>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<commons.lang3.version>3.5</commons.lang3.version>
+ <hbase.client.version>2.2.3</hbase.client.version>
<calcite.core.version>1.22.0</calcite.core.version>
- <spring.cloud.version>Finchley.RELEASE</spring.cloud.version>
+ <active.record.version>4.9.01</active.record.version>
+ <starter.druid.version>1.1.22</starter.druid.version>
+ <apache.calcite.version>1.22.0</apache.calcite.version>
<spring.boot.version>2.0.2.RELEASE</spring.boot.version>
+ <mysql.connector.version>8.0.18</mysql.connector.version>
+ <spring.cloud.version>Finchley.RELEASE</spring.cloud.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <docker.registry>192.168.40.153</docker.registry>
- <docker.registry.port>9080</docker.registry.port>
- <docker.image.prefix>galaxy</docker.image.prefix>
</properties>
<dependencyManagement>