diff options
| author | liuyongqiang <[email protected]> | 2020-12-01 11:02:11 +0800 |
|---|---|---|
| committer | liuyongqiang <[email protected]> | 2020-12-01 11:02:11 +0800 |
| commit | 5b530df5105912d48c091a796290e995885a1913 (patch) | |
| tree | c00116d948ed7d6dbebdf65384e9e7746879e77a | |
| parent | ee38423b7d67b004dffd7c11ec8286577c0334fd (diff) | |
galaxy-qgw-service工程迁移完成
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 Binary files differnew file mode 100644 index 0000000..4508ea2 --- /dev/null +++ b/galaxy-query-engine/dat/asn_v4.mmdb diff --git a/galaxy-query-engine/dat/asn_v6.mmdb b/galaxy-query-engine/dat/asn_v6.mmdb Binary files differnew file mode 100644 index 0000000..a779312 --- /dev/null +++ b/galaxy-query-engine/dat/asn_v6.mmdb diff --git a/galaxy-query-engine/dat/ip_private_v4.mmdb b/galaxy-query-engine/dat/ip_private_v4.mmdb Binary files differnew file mode 100644 index 0000000..445f2aa --- /dev/null +++ b/galaxy-query-engine/dat/ip_private_v4.mmdb diff --git a/galaxy-query-engine/dat/ip_private_v6.mmdb b/galaxy-query-engine/dat/ip_private_v6.mmdb Binary files differnew file mode 100644 index 0000000..cf82ebe --- /dev/null +++ b/galaxy-query-engine/dat/ip_private_v6.mmdb diff --git a/galaxy-query-engine/dat/ip_v4.mmdb b/galaxy-query-engine/dat/ip_v4.mmdb Binary files differnew file mode 100644 index 0000000..842cce9 --- /dev/null +++ b/galaxy-query-engine/dat/ip_v4.mmdb diff --git a/galaxy-query-engine/dat/ip_v6.mmdb b/galaxy-query-engine/dat/ip_v6.mmdb Binary files differnew file mode 100644 index 0000000..cf82ebe --- /dev/null +++ b/galaxy-query-engine/dat/ip_v6.mmdb 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 © 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 @@ -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> |
