diff --git a/src/.vuepress/sidebar/V2.0.x/en-Table.ts b/src/.vuepress/sidebar/V2.0.x/en-Table.ts index b563a84e6..630f48597 100644 --- a/src/.vuepress/sidebar/V2.0.x/en-Table.ts +++ b/src/.vuepress/sidebar/V2.0.x/en-Table.ts @@ -99,7 +99,7 @@ export const enSidebar = { text: 'Security Permissions', collapsible: true, children: [ - { text: 'Authority Management', link: 'Authority-Management' }, + { text: 'Authority Management', link: 'Authority-Management_apache' }, ], }, { @@ -126,20 +126,20 @@ export const enSidebar = { collapsible: true, prefix: 'Tools-System/', children: [ - { text: 'CLI', link: 'CLI' }, + { text: 'CLI', link: 'CLI_apache' }, { text: 'Monitor Tool', link: 'Monitor-Tool_apache' }, { text: 'Benchmark Tool', link: 'Benchmark' }, { text: 'Cluster Management Tool', link: 'Maintenance-Tool_apache' }, { text: 'Data Import & Export', collapsible: true, children: [ - { text: 'Data Import', link: 'Data-Import-Tool' }, - { text: 'Data Export', link: 'Data-Export-Tool' }, + { text: 'Data Import', link: 'Data-Import-Tool_apache' }, + { text: 'Data Export', link: 'Data-Export-Tool_apache' }, ], }, { text: 'Schema Import & Export', collapsible: true, children: [ - { text: 'Schema Import', link: 'Schema-Import-Tool' }, - { text: 'Schema Export', link: 'Schema-Export-Tool' }, + { text: 'Schema Import', link: 'Schema-Import-Tool_apache' }, + { text: 'Schema Export', link: 'Schema-Export-Tool_apache' }, ], }, ], @@ -150,10 +150,10 @@ export const enSidebar = { prefix: 'API/', children: [ { text: 'Java Native API', link: 'Programming-Java-Native-API_apache' }, - { text: 'Python Native API', link: 'Programming-Python-Native-API' }, - { text: 'C++ Native API', link: 'Programming-Cpp-Native-API' }, - { text: 'GO Native API', link: 'Programming-Go-Native-API' }, - { text: 'C# Native API', link: 'Programming-CSharp-Native-API' }, + { text: 'Python Native API', link: 'Programming-Python-Native-API_apache' }, + { text: 'C++ Native API', link: 'Programming-Cpp-Native-API_apache' }, + { text: 'GO Native API', link: 'Programming-Go-Native-API_apache' }, + { text: 'C# Native API', link: 'Programming-CSharp-Native-API_apache' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT Protocol', link: 'Programming-MQTT' }, { text: 'RESTAPI V1 ', link: 'RestAPI-V1' }, diff --git a/src/.vuepress/sidebar/V2.0.x/en-Tree.ts b/src/.vuepress/sidebar/V2.0.x/en-Tree.ts index 0576d8841..42df7c020 100644 --- a/src/.vuepress/sidebar/V2.0.x/en-Tree.ts +++ b/src/.vuepress/sidebar/V2.0.x/en-Tree.ts @@ -81,8 +81,8 @@ export const enSidebar = { text: 'Data Modeling', link: 'Operate-Metadata_apache', }, - { text: 'Write Data', link: 'Write-Data' }, - { text: 'Query Data', link: 'Query-Data' }, + { text: 'Write Data', link: 'Write-Data_apache' }, + { text: 'Query Data', link: 'Query-Data_apache' }, { text: 'Delete Data', collapsible: true, @@ -99,7 +99,7 @@ export const enSidebar = { prefix: 'User-Manual/', children: [ { text: 'Data Sync', link: 'Data-Sync_apache' }, - { text: 'Data Subscription', link: 'Data-subscription' }, + { text: 'Data Subscription', link: 'Data-subscription_apache' }, { text: 'Stream Computing', collapsible: true, @@ -113,7 +113,7 @@ export const enSidebar = { { text: 'Security Permissions', collapsible: true, - children: [{ text: 'Permission Management', link: 'Authority-Management' }], + children: [{ text: 'Permission Management', link: 'Authority-Management_apache' }], }, { text: 'System Maintenance', @@ -146,14 +146,14 @@ export const enSidebar = { { text: 'Cluster Management Tool', link: 'Maintenance-Tool_apache' }, { text: 'Data Import & Export', collapsible: true, children: [ - { text: 'Data Import', link: 'Data-Import-Tool' }, - { text: 'Data Export', link: 'Data-Export-Tool' }, + { text: 'Data Import', link: 'Data-Import-Tool_apache' }, + { text: 'Data Export', link: 'Data-Export-Tool_apache' }, ], }, { text: 'Schema Import & Export', collapsible: true, children: [ - { text: 'Schema Import', link: 'Schema-Import-Tool' }, - { text: 'Schema Export', link: 'Schema-Export-Tool' }, + { text: 'Schema Import', link: 'Schema-Import-Tool_apache' }, + { text: 'Schema Export', link: 'Schema-Export-Tool_apache' }, ], }, { text: 'Full Backup Tool', link: 'Backup-Tool' }, @@ -167,24 +167,24 @@ export const enSidebar = { children: [ { text: 'Java Native Interface', collapsible: true, children: [ - { text: 'Java Native API', link: 'Programming-Java-Native-API' }, - { text: 'Data Subscription API', link: 'Programming-Data-Subscription' }, + { text: 'Java Native API', link: 'Programming-Java-Native-API_apache' }, + { text: 'Data Subscription API', link: 'Programming-Data-Subscription_apache' }, ], }, - { text: 'Python Native API', link: 'Programming-Python-Native-API' }, + { text: 'Python Native API', link: 'Programming-Python-Native-API_apache' }, { text: 'C++ Native API', link: 'Programming-Cpp-Native-API' }, { text: 'Go Native API', link: 'Programming-Go-Native-API' }, { text: 'C# Native API', link: 'Programming-CSharp-Native-API' }, { text: 'Node.js Native API', link: 'Programming-NodeJS-Native-API' }, { text: 'Rust Native API', link: 'Programming-Rust-Native-API' }, - { text: 'JDBC', link: 'Programming-JDBC' }, + { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT Protocol', link: 'Programming-MQTT' }, { text: 'REST API', collapsible: true, children: [ - { text: 'V1 (Not Recommend)', link: 'RestServiceV1' }, - { text: 'V2', link: 'RestServiceV2' }, + { text: 'V1 (Not Recommend)', link: 'RestServiceV1_apache' }, + { text: 'V2', link: 'RestServiceV2_apache' }, ], }, ], @@ -251,7 +251,7 @@ export const enSidebar = { children: [ { text: 'Identifiers', link: 'Syntax-Rule' }, { text: 'Keywords', link: 'Keywords' }, - { text: 'SQL Manual', link: 'SQL-Manual' }, + { text: 'SQL Manual', link: 'SQL-Manual_apache' }, { text: 'Functions and Operators', collapsible: true, diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts index 63378b2f4..48c58a8d5 100644 --- a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts +++ b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts @@ -91,7 +91,7 @@ export const zhSidebar = { { text: '安全权限', collapsible: true, - children: [{ text: '权限管理', link: 'Authority-Management' }], + children: [{ text: '权限管理', link: 'Authority-Management_apache' }], }, { text: '系统运维', @@ -117,19 +117,19 @@ export const zhSidebar = { collapsible: true, prefix: 'Tools-System/', children: [ - { text: '命令行工具', link: 'CLI' }, + { text: '命令行工具', link: 'CLI_apache' }, { text: '监控工具', link: 'Monitor-Tool_apache' }, { text: '集群管理工具', link: 'Maintenance-Tool_apache' }, { text: '数据导入导出', collapsible: true, children: [ - { text: '数据导入', link: 'Data-Import-Tool' }, - { text: '数据导出', link: 'Data-Export-Tool' }, + { text: '数据导入', link: 'Data-Import-Tool_apache' }, + { text: '数据导出', link: 'Data-Export-Tool_apache' }, ], }, { text: '元数据导入导出', collapsible: true, children: [ - { text: '元数据导入', link: 'Schema-Import-Tool' }, - { text: '元数据导出', link: 'Schema-Export-Tool' }, + { text: '元数据导入', link: 'Schema-Import-Tool_apache' }, + { text: '元数据导出', link: 'Schema-Export-Tool_apache' }, ], }, ], @@ -140,10 +140,10 @@ export const zhSidebar = { prefix: 'API/', children: [ { text: 'Java原生接口', link: 'Programming-Java-Native-API_apache' }, - { text: 'Python原生接口', link: 'Programming-Python-Native-API' }, - { text: 'C++原生接口', link: 'Programming-Cpp-Native-API' }, - { text: 'GO原生接口', link: 'Programming-Go-Native-API' }, - { text: 'C#原生接口', link: 'Programming-CSharp-Native-API' }, + { text: 'Python原生接口', link: 'Programming-Python-Native-API_apache' }, + { text: 'C++原生接口', link: 'Programming-Cpp-Native-API_apache' }, + { text: 'GO原生接口', link: 'Programming-Go-Native-API_apache' }, + { text: 'C#原生接口', link: 'Programming-CSharp-Native-API_apache' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT协议', link: 'Programming-MQTT' }, { text: 'RESTAPI V1 ', link: 'RestServiceV1' }, diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts b/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts index 850ce3442..589b77c98 100644 --- a/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts +++ b/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts @@ -69,8 +69,8 @@ export const zhSidebar = { prefix: 'Basic-Concept/', children: [ { text: '测点管理', link: 'Operate-Metadata_apache' }, - { text: '数据写入', link: 'Write-Data' }, - { text: '数据查询', link: 'Query-Data' }, + { text: '数据写入', link: 'Write-Data_apache' }, + { text: '数据查询', link: 'Query-Data_apache' }, { text: '数据删除', collapsible: true, @@ -87,7 +87,7 @@ export const zhSidebar = { prefix: 'User-Manual/', children: [ { text: '数据同步', link: 'Data-Sync_apache' }, - { text: '数据订阅', link: 'Data-subscription' }, + { text: '数据订阅', link: 'Data-subscription_apache' }, { text: '流计算', collapsible: true, @@ -101,7 +101,7 @@ export const zhSidebar = { { text: '安全权限', collapsible: true, - children: [{ text: '权限管理', link: 'Authority-Management' }], + children: [{ text: '权限管理', link: 'Authority-Management_apache' }], }, { text: '系统运维', @@ -134,14 +134,14 @@ export const zhSidebar = { { text: '集群管理工具', link: 'Maintenance-Tool_apache' }, { text: '数据导入导出', collapsible: true, children: [ - { text: '数据导入', link: 'Data-Import-Tool' }, - { text: '数据导出', link: 'Data-Export-Tool' }, + { text: '数据导入', link: 'Data-Import-Tool_apache' }, + { text: '数据导出', link: 'Data-Export-Tool_apache' }, ], }, { text: '元数据导入导出', collapsible: true, children: [ - { text: '元数据导入', link: 'Schema-Import-Tool' }, - { text: '元数据导出', link: 'Schema-Export-Tool' }, + { text: '元数据导入', link: 'Schema-Import-Tool_apache' }, + { text: '元数据导出', link: 'Schema-Export-Tool_apache' }, ], }, { text: '全量备份工具', link: 'Backup-Tool' }, @@ -155,24 +155,24 @@ export const zhSidebar = { children: [ { text: 'Java原生接口', collapsible: true, children: [ - { text: 'Java原生API', link: 'Programming-Java-Native-API' }, - { text: '数据订阅API', link: 'Programming-Data-Subscription' }, + { text: 'Java原生API', link: 'Programming-Java-Native-API_apache' }, + { text: '数据订阅API', link: 'Programming-Data-Subscription_apache' }, ], }, - { text: 'Python原生接口', link: 'Programming-Python-Native-API' }, + { text: 'Python原生接口', link: 'Programming-Python-Native-API_apache' }, { text: 'C++原生接口', link: 'Programming-Cpp-Native-API' }, { text: 'Go原生接口', link: 'Programming-Go-Native-API' }, { text: 'C#原生接口', link: 'Programming-CSharp-Native-API' }, { text: 'Node.js原生接口', link: 'Programming-NodeJS-Native-API' }, { text: 'Rust原生接口', link: 'Programming-Rust-Native-API' }, - { text: 'JDBC', link: 'Programming-JDBC' }, + { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT协议', link: 'Programming-MQTT' }, { text: 'REST API', collapsible: true, children: [ - { text: 'V1 (不推荐)', link: 'RestServiceV1' }, - { text: 'V2', link: 'RestServiceV2' }, + { text: 'V1 (不推荐)', link: 'RestServiceV1_apache' }, + { text: 'V2', link: 'RestServiceV2_apache' }, ], }, ], diff --git a/src/.vuepress/sidebar_timecho/V2.0.x/en-Table.ts b/src/.vuepress/sidebar_timecho/V2.0.x/en-Table.ts index 247a7c120..497a26ce7 100644 --- a/src/.vuepress/sidebar_timecho/V2.0.x/en-Table.ts +++ b/src/.vuepress/sidebar_timecho/V2.0.x/en-Table.ts @@ -103,7 +103,7 @@ export const enSidebar = { text: 'Security Permissions', collapsible: true, children: [ - { text: 'Authority Management', link: 'Authority-Management' }, + { text: 'Authority Management', link: 'Authority-Management_timecho' }, ], }, { text: 'Tiered Storage', link: 'Tiered-Storage_timecho' }, @@ -131,20 +131,20 @@ export const enSidebar = { collapsible: true, prefix: 'Tools-System/', children: [ - { text: 'CLI', link: 'CLI' }, + { text: 'CLI', link: 'CLI_timecho' }, { text: 'Monitor Tool', link: 'Monitor-Tool_timecho' }, { text: 'Benchmark Tool', link: 'Benchmark' }, { text: 'Cluster Management Tool', link: 'Maintenance-Tool_timecho' }, { text: 'Data Import & Export', collapsible: true, children: [ - { text: 'Data Import', link: 'Data-Import-Tool' }, - { text: 'Data Export', link: 'Data-Export-Tool' }, + { text: 'Data Import', link: 'Data-Import-Tool_timecho' }, + { text: 'Data Export', link: 'Data-Export-Tool_timecho' }, ], }, { text: 'Schema Import & Export', collapsible: true, children: [ - { text: 'Schema Import', link: 'Schema-Import-Tool' }, - { text: 'Schema Export', link: 'Schema-Export-Tool' }, + { text: 'Schema Import', link: 'Schema-Import-Tool_timecho' }, + { text: 'Schema Export', link: 'Schema-Export-Tool_timecho' }, ], }, ], @@ -155,10 +155,10 @@ export const enSidebar = { prefix: 'API/', children: [ { text: 'Java Native API', link: 'Programming-Java-Native-API_timecho' }, - { text: 'Python Native API', link: 'Programming-Python-Native-API' }, - { text: 'C++ Native API', link: 'Programming-Cpp-Native-API' }, - { text: 'GO Native API', link: 'Programming-Go-Native-API' }, - { text: 'C# Native API', link: 'Programming-CSharp-Native-API' }, + { text: 'Python Native API', link: 'Programming-Python-Native-API_timecho' }, + { text: 'C++ Native API', link: 'Programming-Cpp-Native-API_timecho' }, + { text: 'GO Native API', link: 'Programming-Go-Native-API_timecho' }, + { text: 'C# Native API', link: 'Programming-CSharp-Native-API_timecho' }, { text: 'JDBC', link: 'Programming-JDBC_timecho' }, /* { text: 'MQTT Protocol', link: 'Programming-MQTT' }, */ { text: 'RESTAPI V1 ', link: 'RestAPI-V1' }, diff --git a/src/.vuepress/sidebar_timecho/V2.0.x/en-Tree.ts b/src/.vuepress/sidebar_timecho/V2.0.x/en-Tree.ts index 475853632..fb647d196 100644 --- a/src/.vuepress/sidebar_timecho/V2.0.x/en-Tree.ts +++ b/src/.vuepress/sidebar_timecho/V2.0.x/en-Tree.ts @@ -90,8 +90,8 @@ export const enSidebar = { text: 'Data Modeling', link: 'Operate-Metadata_timecho', }, - { text: 'Write Data', link: 'Write-Data' }, - { text: 'Query Data', link: 'Query-Data' }, + { text: 'Write Data', link: 'Write-Data_timecho' }, + { text: 'Query Data', link: 'Query-Data_timecho' }, { text: 'Delete Data', collapsible: true, @@ -108,7 +108,7 @@ export const enSidebar = { prefix: 'User-Manual/', children: [ { text: 'Data Sync', link: 'Data-Sync_timecho' }, - { text: 'Data Subscription', link: 'Data-subscription' }, + { text: 'Data Subscription', link: 'Data-subscription_timecho' }, { text: 'Stream Computing', collapsible: true, @@ -125,7 +125,7 @@ export const enSidebar = { text: 'Security Permissions', collapsible: true, children: [ - { text: 'Permission Management', link: 'Authority-Management' }, + { text: 'Permission Management', link: 'Authority-Management_timecho' }, { text: 'White List', link: 'White-List_timecho' }, { text: 'Security Audit', link: 'Audit-Log_timecho' }, ], @@ -162,14 +162,14 @@ export const enSidebar = { { text: 'Cluster Management Tool', link: 'Maintenance-Tool_timecho' }, { text: 'Data Import & Export', collapsible: true, children: [ - { text: 'Data Import', link: 'Data-Import-Tool' }, - { text: 'Data Export', link: 'Data-Export-Tool' }, + { text: 'Data Import', link: 'Data-Import-Tool_timecho' }, + { text: 'Data Export', link: 'Data-Export-Tool_timecho' }, ], }, { text: 'Schema Import & Export', collapsible: true, children: [ - { text: 'Schema Import', link: 'Schema-Import-Tool' }, - { text: 'Schema Export', link: 'Schema-Export-Tool' }, + { text: 'Schema Import', link: 'Schema-Import-Tool_timecho' }, + { text: 'Schema Export', link: 'Schema-Export-Tool_timecho' }, ], }, { text: 'Full Backup Tool', link: 'Backup-Tool' }, @@ -183,25 +183,25 @@ export const enSidebar = { children: [ { text: 'Java Native Interface', collapsible: true, children: [ - { text: 'Java Native API', link: 'Programming-Java-Native-API' }, - { text: 'Data Subscription API', link: 'Programming-Data-Subscription' }, + { text: 'Java Native API', link: 'Programming-Java-Native-API_timecho' }, + { text: 'Data Subscription API', link: 'Programming-Data-Subscription_timecho' }, ], }, - { text: 'Python Native API', link: 'Programming-Python-Native-API' }, + { text: 'Python Native API', link: 'Programming-Python-Native-API_timecho' }, { text: 'C++ Native API', link: 'Programming-Cpp-Native-API' }, { text: 'Go Native API', link: 'Programming-Go-Native-API' }, { text: 'C# Native API', link: 'Programming-CSharp-Native-API' }, { text: 'Node.js Native API', link: 'Programming-NodeJS-Native-API' }, { text: 'Rust Native API', link: 'Programming-Rust-Native-API' }, - { text: 'JDBC', link: 'Programming-JDBC' }, + { text: 'JDBC', link: 'Programming-JDBC_timecho' }, /* { text: 'MQTT Protocol', link: 'Programming-MQTT' }, */ { text: 'OPC UA Protocol', link: 'Programming-OPC-UA_timecho' }, { text: 'REST API', collapsible: true, children: [ - { text: 'V1 (Not Recommend)', link: 'RestServiceV1' }, - { text: 'V2', link: 'RestServiceV2' }, + { text: 'V1 (Not Recommend)', link: 'RestServiceV1_timecho' }, + { text: 'V2', link: 'RestServiceV2_timecho' }, ], }, ], @@ -269,7 +269,7 @@ export const enSidebar = { children: [ { text: 'Identifiers', link: 'Syntax-Rule' }, { text: 'Keywords', link: 'Keywords' }, - { text: 'SQL Manual', link: 'SQL-Manual' }, + { text: 'SQL Manual', link: 'SQL-Manual_timecho' }, { text: 'Functions and Operators', collapsible: true, diff --git a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts index 2cda499e2..5b22eb6d2 100644 --- a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts +++ b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts @@ -93,7 +93,7 @@ export const zhSidebar = { { text: '安全权限', collapsible: true, - children: [{ text: '权限管理', link: 'Authority-Management' }], + children: [{ text: '权限管理', link: 'Authority-Management_timecho' }], }, { text: '多级存储', link: 'Tiered-Storage_timecho' }, { @@ -120,20 +120,20 @@ export const zhSidebar = { collapsible: true, prefix: 'Tools-System/', children: [ - { text: '命令行工具', link: 'CLI' }, + { text: '命令行工具', link: 'CLI_timecho' }, { text: '监控工具', link: 'Monitor-Tool_timecho' }, { text: '测试工具', link: 'Benchmark' }, { text: '集群管理工具', link: 'Maintenance-Tool_timecho' }, { text: '数据导入导出', collapsible: true, children: [ - { text: '数据导入', link: 'Data-Import-Tool' }, - { text: '数据导出', link: 'Data-Export-Tool' }, + { text: '数据导入', link: 'Data-Import-Tool_timecho' }, + { text: '数据导出', link: 'Data-Export-Tool_timecho' }, ], }, { text: '元数据导入导出', collapsible: true, children: [ - { text: '元数据导入', link: 'Schema-Import-Tool' }, - { text: '元数据导出', link: 'Schema-Export-Tool' }, + { text: '元数据导入', link: 'Schema-Import-Tool_timecho' }, + { text: '元数据导出', link: 'Schema-Export-Tool_timecho' }, ], }, ], @@ -144,10 +144,10 @@ export const zhSidebar = { prefix: 'API/', children: [ { text: 'Java原生接口', link: 'Programming-Java-Native-API_timecho' }, - { text: 'Python原生接口', link: 'Programming-Python-Native-API' }, - { text: 'C++原生接口', link: 'Programming-Cpp-Native-API' }, - { text: 'GO原生接口', link: 'Programming-Go-Native-API' }, - { text: 'C#原生接口', link: 'Programming-CSharp-Native-API' }, + { text: 'Python原生接口', link: 'Programming-Python-Native-API_timecho' }, + { text: 'C++原生接口', link: 'Programming-Cpp-Native-API_timecho' }, + { text: 'GO原生接口', link: 'Programming-Go-Native-API_timecho' }, + { text: 'C#原生接口', link: 'Programming-CSharp-Native-API_timecho' }, { text: 'JDBC', link: 'Programming-JDBC_timecho' }, /* { text: 'MQTT协议', link: 'Programming-MQTT' }, */ { text: 'RESTAPI V1 ', link: 'RestServiceV1' }, diff --git a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Tree.ts b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Tree.ts index f886d5c78..8c179edd5 100644 --- a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Tree.ts +++ b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Tree.ts @@ -72,8 +72,8 @@ export const zhSidebar = { prefix: 'Basic-Concept/', children: [ { text: '测点管理', link: 'Operate-Metadata_timecho' }, - { text: '数据写入', link: 'Write-Data' }, - { text: '数据查询', link: 'Query-Data' }, + { text: '数据写入', link: 'Write-Data_timecho' }, + { text: '数据查询', link: 'Query-Data_timecho' }, { text: '数据删除', collapsible: true, @@ -90,7 +90,7 @@ export const zhSidebar = { prefix: 'User-Manual/', children: [ { text: '数据同步', link: 'Data-Sync_timecho' }, - { text: '数据订阅', link: 'Data-subscription' }, + { text: '数据订阅', link: 'Data-subscription_timecho' }, { text: '流计算', collapsible: true, @@ -107,7 +107,7 @@ export const zhSidebar = { text: '安全权限', collapsible: true, children: [ - { text: '权限管理', link: 'Authority-Management' }, + { text: '权限管理', link: 'Authority-Management_timecho' }, { text: '白名单', link: 'White-List_timecho' }, { text: '安全审计', link: 'Audit-Log_timecho' }, ], @@ -144,14 +144,14 @@ export const zhSidebar = { { text: '集群管理工具', link: 'Maintenance-Tool_timecho' }, { text: '数据导入导出', collapsible: true, children: [ - { text: '数据导入', link: 'Data-Import-Tool' }, - { text: '数据导出', link: 'Data-Export-Tool' }, + { text: '数据导入', link: 'Data-Import-Tool_timecho' }, + { text: '数据导出', link: 'Data-Export-Tool_timecho' }, ], }, { text: '元数据导入导出', collapsible: true, children: [ - { text: '元数据导入', link: 'Schema-Import-Tool' }, - { text: '元数据导出', link: 'Schema-Export-Tool' }, + { text: '元数据导入', link: 'Schema-Import-Tool_timecho' }, + { text: '元数据导出', link: 'Schema-Export-Tool_timecho' }, ], }, { text: '全量备份工具', link: 'Backup-Tool' }, @@ -165,25 +165,25 @@ export const zhSidebar = { children: [ { text: 'Java原生接口', collapsible: true, children: [ - { text: 'Java原生API', link: 'Programming-Java-Native-API' }, - { text: '数据订阅API', link: 'Programming-Data-Subscription' }, + { text: 'Java原生API', link: 'Programming-Java-Native-API_timecho' }, + { text: '数据订阅API', link: 'Programming-Data-Subscription_timecho' }, ], }, - { text: 'Python原生接口', link: 'Programming-Python-Native-API' }, + { text: 'Python原生接口', link: 'Programming-Python-Native-API_timecho' }, { text: 'C++原生接口', link: 'Programming-Cpp-Native-API' }, { text: 'Go原生接口', link: 'Programming-Go-Native-API' }, { text: 'C#原生接口', link: 'Programming-CSharp-Native-API' }, { text: 'Node.js原生接口', link: 'Programming-NodeJS-Native-API' }, { text: 'Rust', link: 'Programming-Rust-Native-API' }, - { text: 'JDBC', link: 'Programming-JDBC' }, + { text: 'JDBC', link: 'Programming-JDBC_timecho' }, /* { text: 'MQTT协议', link: 'Programming-MQTT' }, */ { text: 'OPC UA协议', link: 'Programming-OPC-UA_timecho' }, { text: 'REST API', collapsible: true, children: [ - { text: 'V1 (不推荐)', link: 'RestServiceV1' }, - { text: 'V2', link: 'RestServiceV2' }, + { text: 'V1 (不推荐)', link: 'RestServiceV1_timecho' }, + { text: 'V2', link: 'RestServiceV2_timecho' }, ], }, ], diff --git a/src/UserGuide/Master/Table/API/Programming-CSharp-Native-API.md b/src/UserGuide/Master/Table/API/Programming-CSharp-Native-API_apache.md similarity index 100% rename from src/UserGuide/Master/Table/API/Programming-CSharp-Native-API.md rename to src/UserGuide/Master/Table/API/Programming-CSharp-Native-API_apache.md diff --git a/src/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md b/src/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md new file mode 100644 index 000000000..fc89b0c2d --- /dev/null +++ b/src/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md @@ -0,0 +1,402 @@ + +# C# Native API + +## 1. Feature Overview + +IoTDB provides a C# native client driver and corresponding connection pool, offering object-oriented interfaces that allow direct assembly of time-series objects for writing without SQL construction. It is recommended to use the connection pool for multi-threaded parallel database operations. + +## 2. Usage Instructions + +**Environment Requirements:** + +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 + +**Dependency Installation:** + +It supports installation using tools such as NuGet Package Manager or .NET CLI. Taking .NET CLI as an example: + +If using .NET 5.0 or a later version of the SDK, enter the following command to install the latest NuGet package: + +```Plain +dotnet add package Apache.IoTDB +``` + +## 3. Read/Write Operations + +### 3.1 TableSessionPool + +#### 3.1.1 Functional Description + +The `TableSessionPool` defines basic operations for interacting with IoTDB, supporting data insertion, query execution, and session closure. It also serves as a connection pool to efficiently reuse connections and properly release resources when unused. This interface defines how to acquire sessions from the pool and how to close the pool. + +#### 3.1.2 Method List + +Below are the methods defined in `TableSessionPool` with detailed descriptions: + +| Method | Description | Parameters | Return Type | +| ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |-----------------------------------------------------------------------------------------------------------| ---------------------------- | +| `Open(bool enableRpcCompression)` | Opens a session connection with custom `enableRpcCompression` | `enableRpcCompression`: Whether to enable `RpcCompression` (requires server-side configuration alignment) | `Task` | +| `Open()` | Opens a session connection without enabling `RpcCompression` | None | `Task` | +| `InsertAsync(Tablet tablet)` | Inserts a `Tablet` object containing time-series data into the database | `tablet`: The Tablet object to insert | `Task` | +| `ExecuteNonQueryStatementAsync(string sql)` | Executes a non-query SQL statement (e.g., DDL/DML commands) | `sql`: The SQL statement to execute | `Task` | +| `ExecuteQueryStatementAsync(string sql)` | Executes a query SQL statement and returns a `SessionDataSet` with results | `sql`: The SQL query to execute | `Task` | +| `ExecuteQueryStatementAsync(string sql, long timeoutInMs)` | Executes a query SQL statement with a timeout (milliseconds) | `sql`: The SQL query to execute
`timeoutInMs`: Query timeout in milliseconds | `Task` | +| `Close()` | Closes the session and releases held resources | None | `Task` | + +#### 3.1.3 Interface Examples + +```C# +public async Task Open(bool enableRpcCompression, CancellationToken cancellationToken = default) + + public async Task Open(CancellationToken cancellationToken = default) + + public async Task InsertAsync(Tablet tablet) + + public async Task ExecuteNonQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql, long timeoutInMs) + + public async Task Close() +``` + +### 3.2 TableSessionPool.Builder + +#### 3.2.1 Functional Description + +The `TableSessionPool.Builder` class configures and creates instances of `TableSessionPool`, allowing developers to set connection parameters, session settings, and pooling behaviors. + +#### 3.2.2 Configuration Options + +Below are the available configuration options for `TableSessionPool.Builder` and their defaults: + +| ​**Configuration Method** | ​**Description** | ​**Default Value** | +| --------------------------------------------- | -------------------------------------------------------------------------------- |---------------------------------------------------| +| `SetHost(string host)` | Sets the IoTDB node host | `localhost` | +| `SetPort(int port)` | Sets the IoTDB node port | `6667` | +| `SetNodeUrls(List nodeUrls)` | Sets IoTDB cluster node URLs (overrides `SetHost`/`SetPort` when used) | Not set | +| `SetUsername(string username)` | Sets the connection username | `"root"` | +| `SetPassword(string password)` | Sets the connection password | `"TimechoDB@2021"` //before V2.0.6 it is root | +| `SetFetchSize(int fetchSize)` | Sets the fetch size for query results | `1024` | +| `SetZoneId(string zoneId)` | Sets the timezone ZoneID | `UTC+08:00` | +| `SetPoolSize(int poolSize)` | Sets the maximum number of sessions in the connection pool | `8` | +| `SetEnableRpcCompression(bool enable)` | Enables/disables RPC compression | `false` | +| `SetConnectionTimeoutInMs(int timeout)` | Sets the connection timeout in milliseconds | `500` | +| `SetDatabase(string database)` | Sets the target database name | `""` | + +#### 3.2.3 Interface Examples + +```c# +public Builder SetHost(string host) + { + _host = host; + return this; + } + + public Builder SetPort(int port) + { + _port = port; + return this; + } + + public Builder SetUsername(string username) + { + _username = username; + return this; + } + + public Builder SetPassword(string password) + { + _password = password; + return this; + } + + public Builder SetFetchSize(int fetchSize) + { + _fetchSize = fetchSize; + return this; + } + + public Builder SetZoneId(string zoneId) + { + _zoneId = zoneId; + return this; + } + + public Builder SetPoolSize(int poolSize) + { + _poolSize = poolSize; + return this; + } + + public Builder SetEnableRpcCompression(bool enableRpcCompression) + { + _enableRpcCompression = enableRpcCompression; + return this; + } + + public Builder SetConnectionTimeoutInMs(int timeout) + { + _connectionTimeoutInMs = timeout; + return this; + } + + public Builder SetNodeUrls(List nodeUrls) + { + _nodeUrls = nodeUrls; + return this; + } + + protected internal Builder SetSqlDialect(string sqlDialect) + { + _sqlDialect = sqlDialect; + return this; + } + + public Builder SetDatabase(string database) + { + _database = database; + return this; + } + + public Builder() + { + _host = "localhost"; + _port = 6667; + _username = "root"; + _password = "TimechoDB@2021"; //before V2.0.6 it is root + _fetchSize = 1024; + _zoneId = "UTC+08:00"; + _poolSize = 8; + _enableRpcCompression = false; + _connectionTimeoutInMs = 500; + _sqlDialect = IoTDBConstant.TABLE_SQL_DIALECT; + _database = ""; + } + + public TableSessionPool Build() + { + SessionPool sessionPool; + // if nodeUrls is not empty, use nodeUrls to create session pool + if (_nodeUrls.Count > 0) + { + sessionPool = new SessionPool(_nodeUrls, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + else + { + sessionPool = new SessionPool(_host, _port, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + return new TableSessionPool(sessionPool); + } +``` + +## 4. Example + +Complete example : [samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs](https://github.com/apache/iotdb-client-csharp/blob/main/samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs) + +```c# +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Apache.IoTDB.DataStructure; + +namespace Apache.IoTDB.Samples; + +public class TableSessionPoolTest +{ + private readonly SessionPoolTest sessionPoolTest; + + public TableSessionPoolTest(SessionPoolTest sessionPoolTest) + { + this.sessionPoolTest = sessionPoolTest; + } + + public async Task Test() + { + await TestCleanup(); + + await TestSelectAndInsert(); + await TestUseDatabase(); + // await TestCleanup(); + } + + + public async Task TestSelectAndInsert() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test2"); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // or use full qualified table name + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table test1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + // show tables by specifying another database + // using SHOW tables FROM + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES FROM test1"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + var tableName = "testTable1"; + List columnNames = + new List { + "region_id", + "plant_id", + "device_id", + "model", + "temperature", + "humidity" }; + List dataTypes = + new List{ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.FLOAT, + TSDataType.DOUBLE}; + List columnCategories = + new List{ + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.ATTRIBUTE, + ColumnCategory.FIELD, + ColumnCategory.FIELD}; + var values = new List> { }; + var timestamps = new List { }; + for (long timestamp = 0; timestamp < 100; timestamp++) + { + timestamps.Add(timestamp); + values.Add(new List { "1", "5", "3", "A", 1.23F + timestamp, 111.1 + timestamp }); + } + var tablet = new Tablet(tableName, columnNames, columnCategories, dataTypes, values, timestamps); + + await tableSessionPool.InsertAsync(tablet); + + + res = await tableSessionPool.ExecuteQueryStatementAsync("select * from testTable1 " + + "where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + + public async Task TestUseDatabase() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetDatabase("test1") + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // show tables from current database + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + public async Task TestCleanup() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test2"); + + await tableSessionPool.Close(); + } +} +``` diff --git a/src/UserGuide/Master/Table/API/Programming-Cpp-Native-API.md b/src/UserGuide/Master/Table/API/Programming-Cpp-Native-API_apache.md similarity index 100% rename from src/UserGuide/Master/Table/API/Programming-Cpp-Native-API.md rename to src/UserGuide/Master/Table/API/Programming-Cpp-Native-API_apache.md diff --git a/src/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md b/src/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md new file mode 100644 index 000000000..22c41a533 --- /dev/null +++ b/src/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md @@ -0,0 +1,250 @@ + + +# C++ Native API + +## 1. Dependencies + +- Java 8+ +- Flex +- Bison 2.7+ +- Boost 1.56+ +- OpenSSL 1.0+ +- GCC 5.5.0+ + +## 2. Installation + +### 2.1 Install Required Dependencies + +- **MAC** + 1. Install Bison: + + Use the following brew command to install the Bison version: + ```shell + brew install bison + ``` + + 2. Install Boost: Make sure to install the latest version of Boost. + + ```shell + brew install boost + ``` + + 3. Check OpenSSL: Make sure the OpenSSL library is installed. The default OpenSSL header file path is "/usr/local/opt/openssl/include". + + If you encounter errors related to OpenSSL not being found during compilation, try adding `-Dopenssl.include.dir=""`. + +- **Ubuntu 16.04+ or Other Debian-based Systems** + + Use the following commands to install dependencies: + + ```shell + sudo apt-get update + sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-dev + ``` + +- **CentOS 7.7+/Fedora/Rocky Linux or Other Red Hat-based Systems** + + Use the yum command to install dependencies: + + ```shell + sudo yum update + sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel + ``` + +- **Windows** + + 1. Set Up the Build Environment + - Install MS Visual Studio (version 2019+ recommended): Make sure to select Visual Studio C/C++ IDE and compiler (supporting CMake, Clang, MinGW) during installation. + - Download and install [CMake](https://cmake.org/download/). + + 2. Download and Install Flex, Bison + - Download [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/). + - After downloading, rename the executables to flex.exe and bison.exe to ensure they can be found during compilation, and add the directory of these executables to the PATH environment variable. + + 3. Install Boost Library + - Download [Boost](https://www.boost.org/users/download/). + - Compile Boost locally: Run `bootstrap.bat` and `b2.exe` in sequence. + - Add the Boost installation directory to the PATH environment variable, e.g., `C:\Program Files (x86)\boost_1_78_0`. + + 4. Install OpenSSL + - Download and install [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html). + - Add the include directory under the installation directory to the PATH environment variable. + +### 2.2 Compilation + +Clone the source code from git: +```shell +git clone https://github.com/apache/iotdb.git +``` + +The default main branch is the master branch. If you want to use a specific release version, switch to that branch (e.g., version 1.3.2): +```shell +git checkout rc/1.3.2 +``` + +Run Maven to compile in the IoTDB root directory: + +- Mac or Linux with glibc version >= 2.32 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- Linux with glibc version >= 2.31 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT + ``` + +- Linux with glibc version >= 2.17 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT + ``` + +- Windows using Visual Studio 2022 + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- Windows using Visual Studio 2019 + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 16 2019" -Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT + ``` + - If you haven't added the Boost library path to the PATH environment variable, you need to add the relevant parameters to the compile command, e.g., `-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"`. + +After successful compilation, the packaged library files will be located in `iotdb-client/client-cpp/target`, and you can find the compiled example program under `example/client-cpp-example/target`. + +### 2.3 Compilation Q&A + +Q: What are the requirements for the environment on Linux? + +A: +- The known minimum version requirement for glibc (x86_64 version) is 2.17, and the minimum version for GCC is 5.5. +- The known minimum version requirement for glibc (ARM version) is 2.31, and the minimum version for GCC is 10.2. +- If the above requirements are not met, you can try compiling Thrift locally: + - Download the code from https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift. + - Run `./mvnw clean install`. + - Go back to the IoTDB code directory and run `./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp`. + +Q: How to resolve the `undefined reference to '_libc_single_thread'` error during Linux compilation? + +A: +- This issue is caused by the precompiled Thrift dependencies requiring a higher version of glibc. +- You can try adding `-Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT` or `-Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT` to the Maven compile command. + +Q: What if I need to compile using Visual Studio 2017 or earlier on Windows? + +A: +- You can try compiling Thrift locally before compiling the client: + - Download the code from https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift. + - Run `.\mvnw.cmd clean install`. + - Go back to the IoTDB code directory and run `.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 15 2017"`. + +## 3. Usage + +### 3.1 TableSession Class + +All operations in the C++ client are performed through the TableSession class. Below are the method descriptions defined in the TableSession interface. + +#### 3.1.1 Method List + +1. `insert(Tablet& tablet, bool sorted = false)`: Inserts a Tablet object containing time series data into the database. The sorted parameter indicates whether the rows in the tablet are already sorted by time. +2. `executeNonQueryStatement(string& sql)`: Executes non-query SQL statements, such as DDL (Data Definition Language) or DML (Data Manipulation Language) commands. +3. `executeQueryStatement(string& sql)`: Executes query SQL statements and returns a SessionDataSet object containing the query results. The optional timeoutInMs parameter indicates the timeout return time. +4. `open(bool enableRPCCompression = false)`: Opens the connection and determines whether to enable RPC compression (client state must match server state, disabled by default). +5. `close()`: Closes the connection. + +#### 3.1.2 Interface Display + +```cpp +class TableSession { +private: + Session* session; +public: + TableSession(Session* session) { + this->session = session; + } + void insert(Tablet& tablet, bool sorted = false); + void executeNonQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql, int64_t timeoutInMs); + string getDatabase(); //Get the currently selected database, can be replaced by executeNonQueryStatement + void open(bool enableRPCCompression = false); + void close(); +}; +``` + +### 3.2 TableSessionBuilder Class + +The TableSessionBuilder class is a builder used to configure and create instances of the TableSession class. Through it, you can conveniently set connection parameters, query parameters, and other settings when creating instances. + +#### 3.2.1 Usage Example + +```cpp +//Set connection IP, port, username, password +//The order of settings is arbitrary, just ensure build() is called last, the created instance is connected by default through open() +session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //before V2.0.6 it is root + ->build(); +``` + +#### 3.2.2 Configurable Parameter List + +| **Parameter Name** | **Description** | **Default Value** | +| :---: | :---: |:-------------------------------------------:| +| host | Set the connected node IP | "127.0.0.1" ("localhost") | +| rpcPort | Set the connected node port | 6667 | +| username | Set the connection username | "root" | +| password | Set the connection password | "TimechoDB@2021" //before V2.0.6 it is root | +| zoneId | Set the ZoneId related to timezone | "" | +| fetchSize | Set the query result fetch size | 10000 | +| database | Set the target database name | "" | + +## 4. Examples + +The sample code of using these interfaces is in: + +- `example/client-cpp-example/src/TableSessionExample.cpp`: [TableSessionExample](https://github.com/apache/iotdb/tree/rc/2.0.1/example/client-cpp-example/src/TableSessionExample.cpp) + +If the compilation finishes successfully, the example project will be placed under `example/client-cpp-example/target` + +## 5. FAQ + +### 5.1 on Mac + +If errors occur when compiling thrift source code, try to downgrade your xcode-commandline from 12 to 11.5 + +see https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087 + + +### 5.2 on Windows + +When Building Thrift and downloading packages via "wget", a possible annoying issue may occur with +error message looks like: +```shell +Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser +``` +Possible fixes: +- Try to delete the ".m2\repository\\.cache\" directory and try again. +- Add "\true\" configuration to the download-maven-plugin maven phase that complains this error. + diff --git a/src/UserGuide/Master/Table/API/Programming-Go-Native-API.md b/src/UserGuide/Master/Table/API/Programming-Go-Native-API_apache.md similarity index 100% rename from src/UserGuide/Master/Table/API/Programming-Go-Native-API.md rename to src/UserGuide/Master/Table/API/Programming-Go-Native-API_apache.md diff --git a/src/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md b/src/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md new file mode 100644 index 000000000..c0d6afb8c --- /dev/null +++ b/src/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md @@ -0,0 +1,571 @@ + + +# Go Native API + +The Git repository for the Go Native API client is located [here](https://github.com/apache/iotdb-client-go/) + +## 1. Usage +### 1.1 Dependencies + +* golang >= 1.13 +* make >= 3.0 +* curl >= 7.1.1 +* thrift 0.15.0 +* Linux、Macos or other unix-like systems +* Windows+bash (WSL、cygwin、Git Bash) + +### 1.2 Installation + +* go mod + +```sh +export GO111MODULE=on +export GOPROXY=https://goproxy.io + +mkdir session_example && cd session_example + +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +go mod init session_example +go run session_example.go +``` + +* GOPATH + +```sh +# get thrift 0.15.0 +go get github.com/apache/thrift +cd $GOPATH/src/github.com/apache/thrift +git checkout 0.15.0 + +mkdir -p $GOPATH/src/iotdb-client-go-example/session_example +cd $GOPATH/src/iotdb-client-go-example/session_example +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go +go run session_example.go +``` + +## 2. ITableSession Interface +### 2.1 Description + +Defines core operations for interacting with IoTDB tables, including data insertion, query execution, and session closure. Not thread-safe. + +### 2.2 Method List + +| **Method Name** | **Description** | **Parameters** | **Return Value** | **Return Error** | +| -------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| `Insert(tablet *Tablet)` | Inserts a`Tablet`containing time-series data into the database.| `tablet`: A pointer to a Tablet containing time-series data to be inserted. | A pointer to TSStatus indicating the execution result. | An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `xecuteNonQueryStatement(sql string)`| Executes non-query SQL statements such as DDL or DML commands. | `sql`: The SQL statement to execute.| A pointer to TSStatus indicating the execution result.| An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `ExecuteQueryStatement (sql string, timeoutInMs *int64)` | Executes a query SQL statement with a specified timeout in milliseconds. | `sql`: The SQL query statement.`timeoutInMs`: Query timeout in milliseconds. | A pointer to SessionDataSet containing the query results. | An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `Close()` | Closes the session and releases resources. | None | None | An error if there is an issue with closing the IoTDB connection. | + +### 2.3 Interface Definition +1. ITableSession + +```go +// ITableSession defines an interface for interacting with IoTDB tables. +// It supports operations such as data insertion, executing queries, and closing the session. +// Implementations of this interface are expected to manage connections and ensure +// proper resource cleanup. +// +// Each method may return an error to indicate issues such as connection errors +// or execution failures. +// +// Since this interface includes a Close method, it is recommended to use +// defer to ensure the session is properly closed. +type ITableSession interface { + + // Insert inserts a Tablet into the database. + // + // Parameters: + // - tablet: A pointer to a Tablet containing time-series data to be inserted. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + Insert(tablet *Tablet) (r *common.TSStatus, err error) + + // ExecuteNonQueryStatement executes a non-query SQL statement, such as a DDL or DML command. + // + // Parameters: + // - sql: The SQL statement to execute. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err error) + + // ExecuteQueryStatement executes a query SQL statement and returns the result set. + // + // Parameters: + // - sql: The SQL query statement to execute. + // - timeoutInMs: A pointer to the timeout duration in milliseconds for the query execution. + // + // Returns: + // - result: A pointer to SessionDataSet containing the query results. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteQueryStatement(sql string, timeoutInMs *int64) (*SessionDataSet, error) + + // Close closes the session, releasing any held resources. + // + // Returns: + // - err: An error if there is an issue with closing the IoTDB connection. + Close() (err error) +} +``` + +2. Constructing a TableSession + +* There’s no need to manually set the `sqlDialect` field in the `Config`structs. This is automatically handled by the corresponding `NewSession` function during initialization. Simply use the appropriate constructor based on your use case (single-node or cluster). + +```Go +type Config struct { + Host string + Port string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Version Version + Database string +} + +type ClusterConfig struct { + NodeUrls []string //ip:port + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Database string +} + +// NewTableSession creates a new TableSession instance using the provided configuration. +// +// Parameters: +// - config: The configuration for the session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// - connectionTimeoutInMs: The timeout in milliseconds for establishing a connection. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewTableSession(config *Config, enableRPCCompression bool, connectionTimeoutInMs int) (ITableSession, error) + +// NewClusterTableSession creates a new TableSession instance for a cluster setup. +// +// Parameters: +// - clusterConfig: The configuration for the cluster session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewClusterTableSession(clusterConfig *ClusterConfig, enableRPCCompression bool) (ITableSession, error) +``` + +> Note: +> +> When creating a `TableSession` via `NewTableSession` or `NewClusterTableSession`, the connection is already established; no additional `Open` operation is required. + +### 2.4 Example + +```go +package main + +import ( + "flag" + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "math/rand" + "strconv" + "time" +) + +func main() { + flag.Parse() + config := &client.Config{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_session", + } + session, err := client.NewTableSession(config, false, 0) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + checkError(session.ExecuteNonQueryStatement("create database test_db")) + checkError(session.ExecuteNonQueryStatement("use test_db")) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + insertRelationalTablet(session) + showTables(session) + query(session) +} + +func getTextValueFromDataSet(dataSet *client.SessionDataSet, columnName string) string { + if dataSet.IsNull(columnName) { + return "null" + } else { + return dataSet.GetText(columnName) + } +} + +func insertRelationalTablet(session client.ITableSession) { + tablet, err := client.NewRelationalTablet("t1", []*client.MeasurementSchema{ + { + Measurement: "id1", + DataType: client.STRING, + }, + { + Measurement: "id2", + DataType: client.STRING, + }, + { + Measurement: "s1", + DataType: client.TEXT, + }, + { + Measurement: "s2", + DataType: client.TEXT, + }, + }, []client.ColumnCategory{client.TAG, client.TAG, client.FIELD, client.FIELD}, 1024) + if err != nil { + log.Fatal("Failed to create relational tablet {}", err) + } + ts := time.Now().UTC().UnixNano() / 1000000 + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_"+strconv.Itoa(row), 0, row) + tablet.SetValueAt("id2_field_"+strconv.Itoa(row), 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) + + tablet.Reset() + + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_1", 0, row) + tablet.SetValueAt("id2_field_1", 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + + nullValueColumn := rand.Intn(4) + tablet.SetValueAt(nil, nullValueColumn, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) +} + +func showTables(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("tableName is", dataSet.GetText("TableName")) + } +} + +func query(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("select * from t1", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("%v %v %v %v", getTextValueFromDataSet(dataSet, "id1"), getTextValueFromDataSet(dataSet, "id2"), getTextValueFromDataSet(dataSet, "s1"), getTextValueFromDataSet(dataSet, "s2")) + } +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + +## 3. TableSessionPool Interface +### 3.1 Description + +Manages a pool of `ITableSession` instances for efficient connection reuse and resource cleanup. + +### 3.2 Method List + +| **Method Name** | **Description** | **Return Value** | **Return Error** | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------- | ------------------------------------------- | +| `GetSession()` | Acquires a session from the pool for database interaction. | A usable ITableSession instance for interacting with IoTDB. | An error if a session cannot be acquired. | +| `Close()` | Closes the session pool and releases resources.。 | None | None | + +### 3.3 Interface Definition +1. TableSessionPool + +```Go +// TableSessionPool manages a pool of ITableSession instances, enabling efficient +// reuse and management of resources. It provides methods to acquire a session +// from the pool and to close the pool, releasing all held resources. +// +// This implementation ensures proper lifecycle management of sessions, +// including efficient reuse and cleanup of resources. + +// GetSession acquires an ITableSession instance from the pool. +// +// Returns: +// - A usable ITableSession instance for interacting with IoTDB. +// - An error if a session cannot be acquired. +func (spool *TableSessionPool) GetSession() (ITableSession, error) { + return spool.sessionPool.getTableSession() +} + +// Close closes the TableSessionPool, releasing all held resources. +// Once closed, no further sessions can be acquired from the pool. +func (spool *TableSessionPool) Close() +``` + +2. Constructing a TableSessionPool + +```Go +type PoolConfig struct { + Host string + Port string + NodeUrls []string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + Database string + sqlDialect string +} + +// NewTableSessionPool creates a new TableSessionPool with the specified configuration. +// +// Parameters: +// - conf: PoolConfig defining the configuration for the pool. +// - maxSize: The maximum number of sessions the pool can hold. +// - connectionTimeoutInMs: Timeout for establishing a connection in milliseconds. +// - waitToGetSessionTimeoutInMs: Timeout for waiting to acquire a session in milliseconds. +// - enableCompression: A boolean indicating whether to enable compression. +// +// Returns: +// - A TableSessionPool instance. +func NewTableSessionPool(conf *PoolConfig, maxSize, connectionTimeoutInMs, waitToGetSessionTimeoutInMs int, + enableCompression bool) TableSessionPool +``` + +> Note: +> +> * If a `Database` is specified when creating the `TableSessionPool`, all sessions acquired from the pool will automatically use this database. There is no need to explicitly set the database during operations. +> * Automatic State Reset: If a session temporarily switches to another database using `USE DATABASE` during usage, the session will automatically revert to the original database specified in the pool when closed and returned to the pool. + +### 3.4 Example + +```go +package main + +import ( + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "strconv" + "sync" + "sync/atomic" + "time" +) + +func main() { + sessionPoolWithSpecificDatabaseExample() + sessionPoolWithoutSpecificDatabaseExample() + putBackToSessionPoolExample() +} + +func putBackToSessionPoolExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 4000, false) + defer sessionPool.Close() + + num := 4 + successGetSessionNum := int32(0) + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database "+dbName+"because ", err) + return + } + atomic.AddInt32(&successGetSessionNum, 1) + defer func() { + time.Sleep(6 * time.Second) + // put back to session pool + session.Close() + }() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table table_of_" + dbName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() + log.Println("success num is", successGetSessionNum) + + log.Println("All session's database have been reset.") + // the using database will automatically reset to session pool's database after the session closed + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to get session because ", err) + } + defer session.Close() + timeout := int64(3000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Println("table is", dataSet.GetText("TableName")) + } + }() + } + wg.Wait() +} + +func sessionPoolWithSpecificDatabaseExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + tableName := "t" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create table "+tableName+"because ", err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create table " + tableName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func sessionPoolWithoutSpecificDatabaseExample() { + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database ", dbName, err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + diff --git a/src/UserGuide/Master/Table/API/Programming-JDBC_timecho.md b/src/UserGuide/Master/Table/API/Programming-JDBC_timecho.md index 188e0721b..5ef239cc9 100644 --- a/src/UserGuide/Master/Table/API/Programming-JDBC_timecho.md +++ b/src/UserGuide/Master/Table/API/Programming-JDBC_timecho.md @@ -72,7 +72,7 @@ Add the following dependency to your Maven `pom.xml` file: String url = "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table"; ``` -You can find the full example code at [GitHub Repository](https://github.com/apache/iotdb/blob/master/example/jdbc/src/main/java/org/apache/iotdb/TableModelJDBCExample.java). +You can find the full example code at [GitHub Repository](https://github.com/apache/iotdb/blob/rc/2.0.1/example/jdbc/src/main/java/org/apache/iotdb/TableModelJDBCExample.java). Here is an excerpt of the sample code: @@ -120,7 +120,7 @@ public class TableModelJDBCExample { // don't specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "TimechoDB@2021"); //before V2.0.6 it is root Statement statement = connection.createStatement()) { statement.execute("CREATE DATABASE test1"); @@ -161,7 +161,7 @@ public class TableModelJDBCExample { // specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "TimechoDB@2021"); //before V2.0.6 it is root Statement statement = connection.createStatement()) { // show tables from current database test1 try (ResultSet resultSet = statement.executeQuery("SHOW TABLES")) { diff --git a/src/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md b/src/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md index ea4532116..c04b18e80 100644 --- a/src/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md +++ b/src/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md @@ -138,10 +138,10 @@ The `TableSessionBuilder` class is a builder for configuring and creating instan #### 3.2.2 Parameter Configuration | **Parameter** | **Description** | **Default Value** | -|-----------------------------------------------------| ------------------------------------------------------------ | ------------------------------------------------- | +|-----------------------------------------------------| ------------------------------------------------------------ |---------------------------------------------------| | nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("``localhost:6667``")` | | username(String username) | Sets the username for the connection. | `"root"` | -| password(String password) | Sets the password for the connection. | `"root"` | +| password(String password) | Sets the password for the connection. | `"TimechoDB@2021"` //before V2.0.6 it is root | | database(String database) | Sets the target database name. | `null` | | queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000` (1 minute) | | fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | @@ -202,7 +202,7 @@ public class TableSessionBuilder { * * @param password the password. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //before V2.0.6 it is root */ public TableSessionBuilder password(String password); @@ -397,28 +397,28 @@ The `TableSessionPoolBuilder` class is a builder for configuring and creating `I #### 4.2.2 Parameter Configuration -| **Parameter** | **Description** | **Default Value** | -|---------------------------------------------------------------| ------------------------------------------------------------ | --------------------------------------------- | -| nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("localhost:6667")` | -| maxSize(int maxSize) | Sets the maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `5` | -| user(String user) | Sets the username for the connection. | `"root"` | -| password(String password) | Sets the password for the connection. | `"root"` | -| database(String database) | Sets the target database name. | `"root"` | -| queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000`(1 minute) | -| fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | -| zoneId(ZoneId zoneId) | Sets the timezone-related `ZoneId`. | `ZoneId.systemDefault()` | -| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | Sets the timeout duration (in milliseconds) for acquiring a session from the pool. | `30000`(30 seconds) | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | Sets the default buffer size for the Thrift client (in bytes). | `1024`(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | Sets the maximum frame size for the Thrift client (in bytes). | `64 * 1024 * 1024`(64MB) | -| enableCompression(boolean enableCompression) | Enables or disables compression for the connection. | `false` | -| enableRedirection(boolean enableRedirection) | Enables or disables redirection for cluster nodes. | `true` | -| connectionTimeoutInMs(int connectionTimeoutInMs) | Sets the connection timeout in milliseconds. | `10000` (10 seconds) | -| enableAutoFetch(boolean enableAutoFetch) | Enables or disables automatic fetching of available DataNodes. | `true` | -| maxRetryCount(int maxRetryCount) | Sets the maximum number of connection retry attempts. | `60` | -| retryIntervalInMs(long retryIntervalInMs) | Sets the interval between retry attempts (in milliseconds). | `500` (500 milliseconds) | -| useSSL(boolean useSSL) | Enables or disables SSL for secure connections. | `false` | -| trustStore(String keyStore) | Sets the path to the trust store for SSL connections. | `null` | -| trustStorePwd(String keyStorePwd) | Sets the password for the SSL trust store. | `null` | +| **Parameter** | **Description** | **Default Value** | +|---------------------------------------------------------------| ------------------------------------------------------------ |------------------------------------------------| +| nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("localhost:6667")` | +| maxSize(int maxSize) | Sets the maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `5` | +| user(String user) | Sets the username for the connection. | `"root"` | +| password(String password) | Sets the password for the connection. | `"TimechoDB@2021"` //before V2.0.6 it is root | +| database(String database) | Sets the target database name. | `"root"` | +| queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000`(1 minute) | +| fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | +| zoneId(ZoneId zoneId) | Sets the timezone-related `ZoneId`. | `ZoneId.systemDefault()` | +| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | Sets the timeout duration (in milliseconds) for acquiring a session from the pool. | `30000`(30 seconds) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | Sets the default buffer size for the Thrift client (in bytes). | `1024`(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | Sets the maximum frame size for the Thrift client (in bytes). | `64 * 1024 * 1024`(64MB) | +| enableCompression(boolean enableCompression) | Enables or disables compression for the connection. | `false` | +| enableRedirection(boolean enableRedirection) | Enables or disables redirection for cluster nodes. | `true` | +| connectionTimeoutInMs(int connectionTimeoutInMs) | Sets the connection timeout in milliseconds. | `10000` (10 seconds) | +| enableAutoFetch(boolean enableAutoFetch) | Enables or disables automatic fetching of available DataNodes. | `true` | +| maxRetryCount(int maxRetryCount) | Sets the maximum number of connection retry attempts. | `60` | +| retryIntervalInMs(long retryIntervalInMs) | Sets the interval between retry attempts (in milliseconds). | `500` (500 milliseconds) | +| useSSL(boolean useSSL) | Enables or disables SSL for secure connections. | `false` | +| trustStore(String keyStore) | Sets the path to the trust store for SSL connections. | `null` | +| trustStorePwd(String keyStorePwd) | Sets the password for the SSL trust store. | `null` | #### 4.2.3 Sample Code @@ -472,7 +472,7 @@ public class TableSessionPoolBuilder { * * @param password the password. * @return the current {@link TableSessionPoolBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //before V2.0.6 it is root */ public TableSessionPoolBuilder password(String password); @@ -679,7 +679,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021") //before V2.0.6 it is root .maxSize(1) .build(); @@ -780,7 +780,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021")//before V2.0.6 it is root .maxSize(1) .database("test1") .build(); diff --git a/src/UserGuide/latest-Table/API/Programming-Python-Native-API.md b/src/UserGuide/Master/Table/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/UserGuide/latest-Table/API/Programming-Python-Native-API.md rename to src/UserGuide/Master/Table/API/Programming-Python-Native-API_apache.md diff --git a/src/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md b/src/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..7e2fb95e5 --- /dev/null +++ b/src/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,543 @@ + +# Python Native API + +IoTDB provides a Python native client driver and a session pool management mechanism. These tools allow developers to interact with IoTDB in a programmatic and efficient manner. Using the Python API, developers can encapsulate time-series data into objects (e.g., `Tablet`, `NumpyTablet`) and insert them into the database directly, without the need to manually construct SQL statements. For multi-threaded operations, the `TableSessionPool` is recommended to optimize resource utilization and enhance performance. + +## 1. Prerequisites + +To use the IoTDB Python API, install the required package using pip: + +```shell +pip3 install apache-iotdb>=2.0 +``` + +## 2. Read and Write Operations + +### 2.1 TableSession + +`TableSession` is a core class in IoTDB, enabling users to interact with the IoTDB database. It provides methods to execute SQL statements, insert data, and manage database sessions. + +#### Method Overview + +| **Method Name** | **Descripton** | **Parameter Type** | **Return Type** | +| --------------------------- | ----------------------------------------------------- | ------------------------------------ | ---------------- | +| insert | Inserts data into the database. | tablet: `Union[Tablet, NumpyTablet]` | None | +| execute_non_query_statement | Executes non-query SQL statements like DDL/DML. | sql: `str` | None | +| execute_query_statement | Executes a query SQL statement and retrieves results. | sql: `str` | `SessionDataSet` | +| close | Closes the session and releases resources. | None | None | + +#### Sample Code + +```Python +class TableSession(object): +def insert(self, tablet: Union[Tablet, NumpyTablet]): + """ + Insert data into the database. + + Parameters: + tablet (Tablet | NumpyTablet): The tablet containing the data to be inserted. + Accepts either a `Tablet` or `NumpyTablet`. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_non_query_statement(self, sql: str): + """ + Execute a non-query SQL statement. + + Parameters: + sql (str): The SQL statement to execute. Typically used for commands + such as INSERT, DELETE, or UPDATE. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_query_statement(self, sql: str, timeout_in_ms: int = 0) -> "SessionDataSet": + """ + Execute a query SQL statement and return the result set. + + Parameters: + sql (str): The SQL query to execute. + timeout_in_ms (int, optional): Timeout for the query in milliseconds. Defaults to 0, + which means no timeout. + + Returns: + SessionDataSet: The result set of the query. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def close(self): + """ + Close the session and release resources. + + Raises: + IoTDBConnectionException: If there is an issue closing the connection. + """ + pass +``` + +### 2.2 TableSessionConfig + +`TableSessionConfig` is a configuration class that sets parameters for creating a `TableSession` instance, defining essential settings for connecting to the IoTDB database. + +#### Parameter Configuration + +| **Parameter** | **Description** | **Type** | **Default Value** | +| ------------------ | ------------------------------------- | -------- |-----------------------------------------------| +| node_urls | List of database node URLs. | `list` | `["localhost:6667"]` | +| username | Username for the database connection. | `str` | `"root"` | +| password | Password for the database connection. | `str` | `"TimechoDB@2021"`,before V2.0.6 it is root | +| database | Target database to connect to. | `str` | `None` | +| fetch_size | Number of rows to fetch per query. | `int` | `5000` | +| time_zone | Default session time zone. | `str` | `Session.DEFAULT_ZONE_ID` | +| enable_compression | Enable data compression. | `bool` | `False` | + +#### Sample Code + +```Python +class TableSessionConfig(object): + """ + Configuration class for a TableSession. + + This class defines various parameters for connecting to and interacting + with the IoTDB tables. + """ + + def __init__( + self, + node_urls: list = None, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_compression: bool = False, + ): + """ + Initialize a TableSessionConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to ["localhost:6667"]. + username (str, optional): The username for the database connection. + Defaults to "root". + password (str, optional): The password for the database connection. + Defaults to "TimechoDB@2021",before V2.0.6 it is root + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session. + Defaults to Session.DEFAULT_ZONE_ID. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + """ +``` + +**Note:** After using a `TableSession`, make sure to call the `close` method to release resources. + +## 3. Session Pool + +### 3.1 TableSessionPool + +`TableSessionPool` is a session pool management class designed for creating and managing `TableSession` instances. It provides functionality to retrieve sessions from the pool and close the pool when it is no longer needed. + +#### Method Overview + +| **Method Name** | **Description** | **Return Type** | **Exceptions** | +| --------------- | ------------------------------------------------------ | --------------- | -------------- | +| get_session | Retrieves a new `TableSession` instance from the pool. | `TableSession` | None | +| close | Closes the session pool and releases all resources. | None | None | + +#### Sample Code + +```Python +def get_session(self) -> TableSession: + """ + Retrieve a new TableSession instance. + + Returns: + TableSession: A new session object configured with the session pool. + + Notes: + The session is initialized with the underlying session pool for managing + connections. Ensure proper usage of the session's lifecycle. + """ + +def close(self): + """ + Close the session pool and release all resources. + + This method closes the underlying session pool, ensuring that all + resources associated with it are properly released. + + Notes: + After calling this method, the session pool cannot be used to retrieve + new sessions, and any attempt to do so may raise an exception. + """ +``` + +### 3.2 TableSessionPoolConfig + +`TableSessionPoolConfig` is a configuration class used to define parameters for initializing and managing a `TableSessionPool` instance. It specifies the settings needed for efficient session pool management in IoTDB. + +#### Parameter Configuration + +| **Paramater** | **Description** | **Type** | **Default Value** | +| ------------------ | ------------------------------------------------------------ | -------- | -------------------------- | +| node_urls | List of IoTDB cluster node URLs. | `list` | None | +| max_pool_size | Maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `int` | `5` | +| username | Username for the connection. | `str` | `Session.DEFAULT_USER` | +| password | Password for the connection. | `str` | `Session.DEFAULT_PASSWORD` | +| database | Target database to connect to. | `str` | None | +| fetch_size | Fetch size for query results | `int` | `5000` | +| time_zone | Timezone-related `ZoneId` | `str` | `Session.DEFAULT_ZONE_ID` | +| enable_redirection | Whether to enable redirection. | `bool` | `False` | +| enable_compression | Whether to enable data compression. | `bool` | `False` | +| wait_timeout_in_ms | Sets the connection timeout in milliseconds. | `int` | `10000` | +| max_retry | Maximum number of connection retry attempts. | `int` | `3` | + +#### Sample Code + +```Python +class TableSessionPoolConfig(object): + """ + Configuration class for a TableSessionPool. + + This class defines the parameters required to initialize and manage + a session pool for interacting with the IoTDB database. + """ + def __init__( + self, + node_urls: list = None, + max_pool_size: int = 5, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_redirection: bool = False, + enable_compression: bool = False, + wait_timeout_in_ms: int = 10000, + max_retry: int = 3, + ): + """ + Initialize a TableSessionPoolConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to None. + max_pool_size (int, optional): The maximum number of sessions in the pool. + Defaults to 5. + username (str, optional): The username for the database connection. + Defaults to Session.DEFAULT_USER. + password (str, optional): The password for the database connection. + Defaults to Session.DEFAULT_PASSWORD. + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session pool. + Defaults to Session.DEFAULT_ZONE_ID. + enable_redirection (bool, optional): Whether to enable redirection. + Defaults to False. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + wait_timeout_in_ms (int, optional): The maximum time (in milliseconds) to wait for a session + to become available. Defaults to 10000. + max_retry (int, optional): The maximum number of retry attempts for operations. Defaults to 3. + + """ +``` + +**Notes:** + +- Ensure that `TableSession` instances retrieved from the `TableSessionPool` are properly closed after use. +- After closing the `TableSessionPool`, it will no longer be possible to retrieve new sessions. + +### 3.3 SSL Connection + +#### 3.3.1 Server Certificate Configuration + +In the `conf/iotdb-system.properties` configuration file, locate or add the following configuration items: + +``` +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 Configure Python Client Certificate + +- Set `use_ssl` to True to enable SSL. +- Specify the client certificate path using the `ca_certs` parameter. + +``` +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**Example Code: Using SSL to Connect to IoTDB** + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021",before V2.0.6 it is root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. Sample Code + +**Session** Example: You can find the full example code at [Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_example.py). + +**Session Pool** Example: You can find the full example code at [SessionPool Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_pool_example.py). + +Here is an excerpt of the sample code: + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +import threading + +import numpy as np + +from iotdb.table_session_pool import TableSessionPool, TableSessionPoolConfig +from iotdb.utils.IoTDBConstants import TSDataType +from iotdb.utils.NumpyTablet import NumpyTablet +from iotdb.utils.Tablet import ColumnType, Tablet + + +def prepare_data(): + print("create database") + # Get a session from the pool + session = session_pool.get_session() + session.execute_non_query_statement("CREATE DATABASE IF NOT EXISTS db1") + session.execute_non_query_statement('USE "db1"') + session.execute_non_query_statement( + "CREATE TABLE table0 (id1 string id, attr1 string attribute, " + + "m1 double " + + "field)" + ) + session.execute_non_query_statement( + "CREATE TABLE table1 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + + print("now the tables are:") + # show result + res = session.execute_query_statement("SHOW TABLES") + while res.has_next(): + print(res.next()) + + session.close() + + +def insert_data(num: int): + print("insert data for table" + str(num)) + # Get a session from the pool + session = session_pool.get_session() + column_names = [ + "id1", + "attr1", + "m1", + ] + data_types = [ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.DOUBLE, + ] + column_types = [ColumnType.TAG, ColumnType.ATTRIBUTE, ColumnType.FIELD] + timestamps = [] + values = [] + for row in range(15): + timestamps.append(row) + values.append(["id:" + str(row), "attr:" + str(row), row * 1.0]) + tablet = Tablet( + "table" + str(num), column_names, data_types, values, timestamps, column_types + ) + session.insert(tablet) + session.execute_non_query_statement("FLush") + + np_timestamps = np.arange(15, 30, dtype=np.dtype(">i8")) + np_values = [ + np.array(["id:{}".format(i) for i in range(15, 30)]), + np.array(["attr:{}".format(i) for i in range(15, 30)]), + np.linspace(15.0, 29.0, num=15, dtype=TSDataType.DOUBLE.np_dtype()), + ] + + np_tablet = NumpyTablet( + "table" + str(num), + column_names, + data_types, + np_values, + np_timestamps, + column_types=column_types, + ) + session.insert(np_tablet) + session.close() + + +def query_data(): + # Get a session from the pool + session = session_pool.get_session() + + print("get data from table0") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + print("get data from table1") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + session.close() + + +def delete_data(): + session = session_pool.get_session() + session.execute_non_query_statement("drop database db1") + print("data has been deleted. now the databases are:") + res = session.execute_query_statement("show databases") + while res.has_next(): + print(res.next()) + session.close() + + +# Create a session pool +username = "root" +password = "TimechoDB@2021",before V2.0.6 it is root +node_urls = ["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"] +fetch_size = 1024 +database = "db1" +max_pool_size = 5 +wait_timeout_in_ms = 3000 +config = TableSessionPoolConfig( + node_urls=node_urls, + username=username, + password=password, + database=database, + max_pool_size=max_pool_size, + fetch_size=fetch_size, + wait_timeout_in_ms=wait_timeout_in_ms, +) +session_pool = TableSessionPool(config) + +prepare_data() + +insert_thread1 = threading.Thread(target=insert_data, args=(0,)) +insert_thread2 = threading.Thread(target=insert_data, args=(1,)) + +insert_thread1.start() +insert_thread2.start() + +insert_thread1.join() +insert_thread2.join() + +query_data() +delete_data() +session_pool.close() +print("example is finished!") +``` + diff --git a/src/UserGuide/Master/Table/QuickStart/QuickStart_apache.md b/src/UserGuide/Master/Table/QuickStart/QuickStart_apache.md index 7f057a3a0..04d64e104 100644 --- a/src/UserGuide/Master/Table/QuickStart/QuickStart_apache.md +++ b/src/UserGuide/Master/Table/QuickStart/QuickStart_apache.md @@ -67,7 +67,7 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Data Synchronization: [Data Sync](../User-Manual/Data-Sync_apache.md) -6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_apache.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_apache.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. +6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_apache.md)、[Python Native API](../API/Programming-Python-Native-API_apache)、[JDBC](../API/Programming-JDBC_apache.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. ## 3. Want to learn more technical details? diff --git a/src/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md b/src/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md index 39fc660d0..a8c89a2dc 100644 --- a/src/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md +++ b/src/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md @@ -74,7 +74,7 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Data Synchronization: [Data Sync](../User-Manual/Data-Sync_timecho.md) -6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_timecho.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_timecho.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. +6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_timecho.md)、[Python Native API](../API/Programming-Python-Native-API_timecho)、[JDBC](../API/Programming-JDBC_timecho.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. ## 3. What other convenient tools are available? diff --git a/src/UserGuide/latest-Table/Tools-System/CLI.md b/src/UserGuide/Master/Table/Tools-System/CLI_apache.md similarity index 70% rename from src/UserGuide/latest-Table/Tools-System/CLI.md rename to src/UserGuide/Master/Table/Tools-System/CLI_apache.md index c8ae8cb21..f2128b7ef 100644 --- a/src/UserGuide/latest-Table/Tools-System/CLI.md +++ b/src/UserGuide/Master/Table/Tools-System/CLI_apache.md @@ -47,26 +47,27 @@ Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect tab # V2.0.4.x and later versions Shell> sbin\windows\start-cli.bat -sql_dialect table #or +# V2.0.4.x and later versions Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table ``` **Parameter Explanation** -| **Parameter** | **Type** | **Required** | **Description** | **Example** | -| -------------------------- | -------- | ------------ | ------------------------------------------------------------ | ------------------- | -| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | -| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | -| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | -| -pw `` | string | No | The password to connect to the IoTDB server. (Default: root) | -pw root | -| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | -| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | -| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | +| **Parameter** | **Type** | **Required** | **Description** | **Example** | +| -------------------------- | -------- | ------------ |-----------------------------------------------------------------------------------| ------------------- | +| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | +| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | +| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | +| -pw `` | string | No | The password to connect to the IoTDB server. (Default: root) | -pw root | +| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | +| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | +| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | | -disableISO8601 | Flag | No | If set, timestamps will be displayed as numeric values instead of ISO8601 format. | -disableISO8601 | -| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | -| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | -| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | -| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | -| -help | Flag | No | Displays help information for the CLI tool. | -help | +| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | +| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | +| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | +| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | +| -help | Flag | No | Displays help information for the CLI tool. | -help | The figure below indicates a successful startup: diff --git a/src/UserGuide/Master/Table/Tools-System/CLI_timecho.md b/src/UserGuide/Master/Table/Tools-System/CLI_timecho.md new file mode 100644 index 000000000..c2d2fde6e --- /dev/null +++ b/src/UserGuide/Master/Table/Tools-System/CLI_timecho.md @@ -0,0 +1,109 @@ + +# CLI + +The IoTDB Command Line Interface (CLI) tool allows users to interact with the IoTDB server. Before using the CLI tool to connect to IoTDB, ensure that the IoTDB service is running correctly. This document explains how to launch the CLI and its related parameters. + +In this manual, `$IOTDB_HOME` represents the installation directory of IoTDB. + +## 1. CLI Launch + +The CLI client script is located in the `$IOTDB_HOME/sbin` directory. The common commands to start the CLI tool are as follows: + +#### **Linux** **MacOS** + +```Bash +Shell> bash sbin/start-cli.sh -sql_dialect table +#or +# Before version V2.0.6.x +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x and later versions +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +#### **Windows** + +```Bash +# Before version V2.0.4.x +Shell> sbin\start-cli.bat -sql_dialect table +#or +Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table + +# V2.0.4.x and later versions +Shell> sbin\windows\start-cli.bat -sql_dialect table +#or +# V2.0.4.x and later versions, before version V2.0.6.x +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x and later versions +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +**Parameter Explanation** + +| **Parameter** | **Type** | **Required** | **Description** | **Example** | +| -------------------------- | -------- | ------------ |---------------------------------------------------------------------------------------------------| ------------------- | +| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | +| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | +| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | +| -pw `` | string | No | The password to connect to the IoTDB server. (Default: `TimechoDB@2021`,before V2.0.6 it is root) | -pw root | +| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | +| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | +| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | +| -disableISO8601 | Flag | No | If set, timestamps will be displayed as numeric values instead of ISO8601 format. | -disableISO8601 | +| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | +| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | +| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | +| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | +| -help | Flag | No | Displays help information for the CLI tool. | -help | + +The figure below indicates a successful startup: + +![](/img/Cli-01.png) + + +## 2. Example Commands + +### 2.1 **Create a Database** + +```Java +create database test +``` + +![](/img/Cli-02.png) + + +### 2.2 **Show Databases** +```Java +show databases +``` + +![](/img/Cli-03.png) + + +## 3. CLI Exit + +To exit the CLI and terminate the session, type`quit`or`exit`. + +### 3.1 Additional Notes and Shortcuts + +1. **Navigate Command History:** Use the up and down arrow keys. +2. **Auto-Complete Commands:** Use the right arrow key. +3. **Interrupt Command Execution:** Press `CTRL+C`. diff --git a/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md b/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md new file mode 100644 index 000000000..d66c1a284 --- /dev/null +++ b/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md @@ -0,0 +1,166 @@ +# Data Export + +## 1. Function Overview +The data export tool `export-data.sh/bat` is located in the `tools` directory and can export query results from specified SQL statements into CSV, SQL, or TsFile (open-source time-series file format) formats. Its specific functionalities are as follows: + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVexport-data.sh/batPlain text format for storing structured data. Must follow the CSV format specified below.
SQLFile containing custom SQL statements.
TsFileOpen-source time-series file format.
+ + +## 2. Detailed Features +### 2.1 Common Parameters +| Short | Full Parameter | Description | Required | Default | +| ---------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------- |----------------------------------------------| +| `-ft` | `--file_type` | Export file type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | +| `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | +| `-u` | `--username` | Username for authentication. | No | `root` | +| `-pw` | `--password` | Password for authentication. | No | `root` | +| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | +| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| - | +| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | +| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | +|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | +| `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | +| `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | +| `-q` | `--query` | SQL query command to execute. | No | - | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (ms). | No | `-1` (Range: -1~Long max=9223372036854775807) | +| `-help` | `--help` | Display help information. | No | - | + +### 2.2 CSV Format +#### 2.2.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table + [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |------------------------------------------| +| `-dt` | `--datatype` | Whether to include data types in the CSV file header (`true` or `false`). | No | `false` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -db database1 -q "select * from table1" + +# Error Example +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -q "select * from table1" +Parse error: Missing required option: db +``` +## 2.3 SQL Format +#### 2.3.1 Command +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------- | +| `-aligned` | `--use_aligned` | Whether to export as aligned SQL format (`true` or `false`). | No | `true` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.3.3 Examples +```Shell +# Valid Example +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -db database1 -start_time 1 + +# Error Example +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -start_time 1 +Parse error: Missing required option: db +``` + +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 TsFile-Specific Parameters + +* None + +#### 2.4.3 Examples + +```Shell +# Valid Example +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -db database1 -start_time 0 + +# Error Example +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -start_time 0 +Parse error: Missing required option: db +``` diff --git a/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md b/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md similarity index 97% rename from src/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md rename to src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md index 921cc3783..f23293445 100644 --- a/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md +++ b/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md @@ -34,12 +34,12 @@ The data export tool `export-data.sh/bat` is located in the `tools` directory an | `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | | `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | | `-u` | `--username` | Username for authentication. | No | `root` | -| `-pw` | `--password` | Password for authentication. | No | `root` | -| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | -| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| -| -| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | -| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | -|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | +| `-pw` | `--password` | Password for authentication. | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | +| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| - | +| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | +| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | +|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | | `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | | `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | | `-q` | `--query` | SQL query command to execute. | No | - | diff --git a/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md b/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md new file mode 100644 index 000000000..6d04bef39 --- /dev/null +++ b/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md @@ -0,0 +1,321 @@ +# Data Import + +## 1. Functional Overview + +IoTDB supports three methods for data import: +- Data Import Tool: Use the `import-data.sh/bat` script in the `tools` directory to manually import CSV, SQL, or TsFile (open-source time-series file format) data into IoTDB. +- `TsFile` Auto-Loading Feature +- Load `TsFile` SQL + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVimport-data.sh/batCan be used for single or batch import of CSV files into IoTDB
SQLCan be used for single or batch import of SQL files into IoTDB
TsFileCan be used for single or batch import of TsFile files into IoTDB
TsFile Auto-Loading FeatureCan automatically monitor a specified directory for newly generated TsFiles and load them into IoTDB
Load SQLCan be used for single or batch import of TsFile files into IoTDB
+ +## 2. Data Import Tool +### 2.1 Common Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |---------------------------------------------| +| `-ft` | `--file_type` | File type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | +| `-p` | `--port` | IoTDB server port. | No | `6667` | +| `-u` | `--username` | Username. | No | `root` | +| `-pw` | `--password` | Password. | No | `root` | +| +|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | +|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | +|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | +| +| `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | +| `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | +| `-tz` | `--timezone` | Timezone (e.g., `+08:00`, `-01:00`). | No | System default | +| `-help` | `--help` | Display help (general or format-specific: `-help csv`). | No | - | + +### 2.2 CSV Format + +#### 2.2.1 Command +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------------- |----------------------------------------------------------| ---------- |-----------------| +| `-fd` | `--fail_dir` | Directory to save failed files. | No | YOUR_CSV_FILE_PATH | +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-aligned` | `--use_aligned` | Import as aligned time series. | No | `false` | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-ti` | `--type_infer` | Type mapping (e.g., `BOOLEAN=text,INT=long`). | No | - | +| `-tp` | `--timestamp_precision` | Timestamp precision: `ms`, `us`, `ns`. | No | `ms` | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_0.csv -db database1 -table table1 + +# Error Example +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -table table1 +Parse error: Missing required option: db + +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -db database1 -table table5 +There are no tables or the target table table5 does not exist +``` + +#### 2.2.4 Import Notes + +1. CSV Import Specifications + +- Special Character Escaping Rules: If a text-type field contains special characters (e.g., commas `,`), they must be escaped using a backslash (`\`). +- Supported Time Formats: `yyyy-MM-dd'T'HH:mm:ss`, `yyyy-MM-dd HH:mm:ss`, or `yyyy-MM-dd'T'HH:mm:ss.SSSZ`. +- Timestamp Column Requirement: The timestamp column must be the first column in the data file. + +2. CSV File Example + +```sql +time,region,device,model,temperature,humidity +1970-01-01T08:00:00.001+08:00,"SH","101","F",90.0,35.2 +1970-01-01T08:00:00.002+08:00,"SH","101","F",90.0,34.8 +``` + + +### 2.3 SQL Format + +#### 2.3.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| -------------- | ------------------------------- | -------------------------------------------------------------------- | ---------- | ------------------ | +| `-fd` | `--fail_dir` | Directory to save failed files. | No |YOUR_CSV_FILE_PATH| +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | + +#### 2.3.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump0_0.sql -db database1 + +# Error Example +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump1_1.sql -db database1 +Source file or directory ./sql/dump1_1.sql does not exist + +# When the ​target table exists but metadata is incompatible or ​data is malformed, the system will generate a .failed file and log error details. +# Log Example +Fail to insert measurements '[column.name]' caused by [data type is not consistent, input '[column.value]', registered '[column.DataType]'] +``` +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` +#### 2.4.2 TsFile-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ----------- | ----------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------- | --------------------------- | +| `-os` | `--on_success` | Action for successful files:
`none`: Do not delete the file.
`mv`: Move the successful file to the target directory.
`cp`:Create a hard link (copy) of the successful file to the target directory.
`delete`:Delete the file. | ​**Yes** | - | +| `-sd` | `--success_dir` | Target directory for `mv`/`cp` actions on success. Required if `-os` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/success` | +| `-of` | `--on_fail` | Action for failed files:
`none`:Skip the file.
`mv`:Move the failed file to the target directory.
`cp`:Create a hard link (copy) of the failed file to the target directory.
`delete`:Delete the file.. | ​**Yes** | - | +| `-fd` | `--fail_dir` | Target directory for `mv`/`cp` actions on failure. Required if `-of` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/fail` | +| `-tp` | `--timestamp_precision` | TsFile timestamp precision: `ms`, `us`, `ns`.
For non-remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The system will manually verify if the timestamp precision matches the server. If it does not match, an error will be returned.
​For remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The Pipe system will automatically verify if the timestamp precision matches. If it does not match, a Pipe error will be returned. | No | `ms` | + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 -os none -of none + +# Error Example +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 +Parse error: Missing required options: os, of +``` + +## 3. TsFile Auto-Loading + +This feature enables IoTDB to automatically monitor a specified directory for new TsFiles and load them into the database without manual intervention. + +![](/img/Data-import2.png) + +### 3.1 Configuration + +Add the following parameters to `iotdb-system.properties` (template: `iotdb-system.properties.template`): + +| Parameter | Description | Value Range | Required | Default | Hot-Load? | +| ---------------------------------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------| ---------- | ----------------------------- | ----------------------- | +| `load_active_listening_enable` | Enable auto-loading. | `true`/`false` | Optional | `true` | Yes | +| `load_active_listening_dirs` | Directories to monitor (subdirectories included). Multiple paths separated by commas.
Note: In the table model, the directory name where the file is located will be used as the database. | String | Optional | `ext/load/pending` | Yes | +| `load_active_listening_fail_dir` | Directory to store failed TsFiles. Only can set one. | String | Optional | `ext/load/failed` | Yes | +| `load_active_listening_max_thread_num` | Maximum Threads for TsFile Loading Tasks:The default value for this parameter, when commented out, is max(1, CPU cores / 2). If the value set by the user falls outside the range [1, CPU cores / 2], it will be reset to the default value of max(1, CPU cores / 2). | `1` to `Long.MAX_VALUE` | Optional | `max(1, CPU_CORES / 2)` | No (restart required) | +| `load_active_listening_check_interval_seconds` | Active Listening Polling Interval (in seconds):The active listening feature for TsFiles is implemented through polling the target directory. This configuration specifies the time interval between two consecutive checks of the `load_active_listening_dirs`. After each check, the next check will be performed after `load_active_listening_check_interval_seconds` seconds. If the polling interval set by the user is less than 1, it will be reset to the default value of 5 seconds. | `1` to `Long.MAX_VALUE` | Optional | `5` | No (restart required) | + +### 3.2 Examples + +```bash +load_active_listening_dir/ +├─sensors/ +│ ├─temperature/ +│ │ └─temperature-table.TSFILE + +``` + +- Table model TsFile + - `temperature-table.TSFILE`: will be imported into the `temperature` database (because it is located in the `sensors/temperature/` directory) + + +### 3.3 Notes + +1. ​​**Mods Files**​: If TsFiles have associated `.mods` files, move `.mods` files to the monitored directory ​**before** their corresponding TsFiles. Ensure `.mods` and TsFiles are in the same directory. +2. ​​**Restricted Directories**​: Do NOT set Pipe receiver directories, data directories, or other system paths as monitored directories. +3. ​​**Directory Conflicts**​: Ensure `load_active_listening_fail_dir` does not overlap with `load_active_listening_dirs` or its subdirectories. +4. ​​**Permissions**​: The monitored directory must have write permissions. Files are deleted after successful loading; insufficient permissions may cause duplicate loading. + + +## 4. Load SQL + +IoTDB supports importing one or multiple TsFile files containing time series into another running IoTDB instance directly via SQL execution through the CLI. + +### 4.1 Command + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` : The path to a TsFile or a folder containing multiple TsFiles. +* ``: Optional parameters, as described below. + +| Key | Key Description | Value Type | Value Range | Value is Required | Default Value | +|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|--------------------------------|-------------------|----------------------------| +| `database-level` | When the database corresponding to the TsFile does not exist, the database hierarchy level can be specified via the ` database-level` parameter. The default is the level set in `iotdb-common.properties`. For example, setting level=1 means the prefix path of level 1 in all time series in the TsFile will be used as the database. | Integer | `[1: Integer.MAX_VALUE]` | No | 1 | +| `on-success` | Action for successfully loaded TsFiles: `delete` (delete the TsFile after successful import) or `none` (retain the TsFile in the source folder). | String | `delete / none` | No | delete | +| `model` | Specifies whether the TsFile uses the `table` model or `tree` model. | String | `tree / table` | No | Aligns with `-sql_dialect` | +| `database-name` | Table model only: Target database for import. Automatically created if it does not exist. The database-name must not include the `root.` prefix (an error will occur if included). | String | `-` | No | null | +| `convert-on-type-mismatch` | Whether to perform type conversion during loading if data types in the TsFile mismatch the target schema. | Boolean | `true / false` | No | true | +| `verify` | Whether to validate the schema before loading the TsFile. | Boolean | `true / false` | No | true | +| `tablet-conversion-threshold` | Size threshold (in bytes) for converting TsFiles into tablet format during loading. Default: `-1` (no conversion for any TsFile). | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | No | -1 | +| `async` | Whether to enable asynchronous loading. If enabled, TsFiles are moved to an active-load directory and loaded into the `database-name` asynchronously. | Boolean | `true / false` | No | false | + +### 4.2 Example + +```SQL +-- Create target database: database2 +IoTDB> create database database2 +Msg: The statement is executed successfully. + +IoTDB> use database2 +Msg: The statement is executed successfully. + +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ ++---------+-------+------+-------+ +Empty set. + +-- Import tsfile by excuting load sql +IoTDB:database2> load '/home/dump0.tsfile' with ( 'on-success'='none', 'database-name'='database2') +Msg: The statement is executed successfully. + +-- Verify whether the import was successful +IoTDB:database2> select * from table2 ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +| time|region|plant_id|device_id|temperature|humidity|status| arrival_time| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +|2024-11-30T00:00:00.000+08:00| 上海| 3002| 101| 90.0| 35.2| true| null| +|2024-11-29T00:00:00.000+08:00| 上海| 3001| 101| 85.0| 35.1| null|2024-11-29T10:00:13.000+08:00| +|2024-11-27T00:00:00.000+08:00| 北京| 1001| 101| 85.0| 35.1| true|2024-11-27T16:37:01.000+08:00| +|2024-11-29T11:00:00.000+08:00| 上海| 3002| 100| null| 45.1| true| null| +|2024-11-28T08:00:00.000+08:00| 上海| 3001| 100| 85.0| 35.2| false|2024-11-28T08:00:09.000+08:00| +|2024-11-26T13:37:00.000+08:00| 北京| 1001| 100| 90.0| 35.1| true|2024-11-26T13:37:34.000+08:00| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +``` diff --git a/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md b/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md similarity index 98% rename from src/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md rename to src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md index c7d63735a..abbb26abf 100644 --- a/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md +++ b/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md @@ -46,11 +46,11 @@ IoTDB supports three methods for data import: | `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | | `-p` | `--port` | IoTDB server port. | No | `6667` | | `-u` | `--username` | Username. | No | `root` | -| `-pw` | `--password` | Password. | No | `root` | +| `-pw` | `--password` | Password. | No | `TimechoDB@2021`(Before V2.0.6 it is root) | | -|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | -|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | -|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | +|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | +|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | +|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | | | `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | | `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | diff --git a/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md b/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md new file mode 100644 index 000000000..ff7583917 --- /dev/null +++ b/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md @@ -0,0 +1,108 @@ + + +# Schema Export + +## 1. Overview + +The schema export tool `export-schema.sh/bat` is located in the `tools` directory. It can export schema from a specified database in IoTDB to a script file. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |---------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 Examples + +Export schema from `database1` to `/home`: + +```Bash +./export-schema.sh -sql_dialect table -t /home/ -db database1 +``` + +Output `dump_database1.sql`: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` diff --git a/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md b/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md similarity index 93% rename from src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md rename to src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md index f278576e4..885433f89 100644 --- a/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md +++ b/src/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md @@ -29,21 +29,21 @@ The schema export tool `export-schema.sh/bat` is located in the `tools` director ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------- | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | -| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | -| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | -| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | -| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | -| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | | `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md b/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md similarity index 89% rename from src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md rename to src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md index cca314db4..6c2057422 100644 --- a/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md +++ b/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md @@ -29,19 +29,19 @@ The schema import tool `import-schema.sh/bat` is located in `tools` directory. ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- | ------------------------------------------------ | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database for import | Yes | - | -| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | -| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | -| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | | `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md b/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md new file mode 100644 index 000000000..0dd8688ff --- /dev/null +++ b/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md @@ -0,0 +1,163 @@ + + +# Schema Import + +## 1. Overview + +The schema import tool `import-schema.sh/bat` is located in `tools` directory. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# Before version V2.0.4.x +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x and later versions +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 Examples + +Import `dump_database1.sql` from `/home` into `database2`, + +```sql +-- File content (dump_database1.sql): +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` + +Executing the command: + +```Bash +./import-schema.sh -sql_dialect table -s /home/dump_database1.sql -db database2 + +# If database2 doesn't exist +The target database database2 does not exist + +# If database2 exists +Import completely! +``` + +Verification: + +```Bash +# Before import +IoTDB:database2> show tables ++---------+-------+ +|TableName|TTL(ms)| ++---------+-------+ ++---------+-------+ +Empty set. + +# After import +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ +| table2| INF| USING| null| +| table1| INF| USING| null| ++---------+-------+------+-------+ + +IoTDB:database2> desc table1 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ + +IoTDB:database2> desc table2 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ +``` diff --git a/src/UserGuide/Master/Table/User-Manual/Authority-Management.md b/src/UserGuide/Master/Table/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/UserGuide/Master/Table/User-Manual/Authority-Management.md rename to src/UserGuide/Master/Table/User-Manual/Authority-Management_apache.md diff --git a/src/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md b/src/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..9672bc363 --- /dev/null +++ b/src/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,493 @@ + + +# Authority Management + +IoTDB provides permission management functionality to implement fine-grained access control for data and cluster systems, ensuring data and system security. This document introduces the basic concepts, user definitions, permission management, authentication logic, and functional use cases of the permission module in IoTDB's table model. + +## 1. Basic Concepts + +### 1.1 User + +A **user** is a legitimate database user. Each user is associated with a unique username and authenticated via a password. Before accessing the database, a user must provide valid credentials (a username and password that exist in the database). + +### 1.2 Permission + +A database supports multiple operations, but not all users can perform every operation. If a user is authorized to execute a specific operation, they are said to have the **permission** for that operation. + +### 1.3 Role + +A **role** is a collection of permissions, identified by a unique role name. Roles typically correspond to real-world identities (e.g., "traffic dispatcher"), where a single identity may encompass multiple users. Users sharing the same real-world identity often require the same set of permissions, and roles abstract this grouping for unified management. + +### 1.4 Default User and Role + +Upon initialization, IoTDB includes a default user: + +* ​**Username**​: `root` +* ​**Default password**​: `TimechoDB@2021` //before V2.0.6 it is root + +The `root` user is the ​**administrator**​, inherently possessing all permissions. This user cannot be granted or revoked permissions and cannot be deleted. The database maintains only one administrator user. Newly created users or roles start with **no permissions** by default. + +## 2. Permission List + +In IoTDB's table model, there are two main types of permissions: Global Permissions and Data Permissions . + +### 2.1 Global Permissions + +Global permissions include user management and role management. + +The following table describes the types of global permissions: + +| Permission Name | Description | +| ----------------- |----------------------------------------------------------------------------------------------------------------------------------| +| MANAGE\_USER | - Create users
- Delete users
- Modify user passwords
- View user permission details
- List all users | +| MANAGE\_ROLE | - Create roles
- Delete roles
- View role permission details
- Grant/revoke roles to/from users
- List all roles | + +### 2.2 Data Permissions + +Data permissions consist of permission types and permission scopes. + +* Permission Types: + * CREATE: Permission to create resources + * DROP: Permission to delete resources + * ALTER: Permission to modify definitions + * SELECT: Permission to query data + * INSERT: Permission to insert/update data + * DELETE: Permission to delete data +* Permission Scopes: + * ANY: System-wide (affects all databases and tables) + * DATABASE: Database-wide (affects the specified database and its tables) + * TABLE: Table-specific (affects only the specified table) +* Scope Enforcement Logic: + +When performing table-level operations, the system matches user permissions with data permission scopes hierarchically. Example: If a user attempts to write data to `DATABASE1.TABLE1`, the system checks for write permissions in this order: 1. `ANY` scope → 2. `DATABASE1` scope → 3. `DATABASE1.TABLE1` scope. The check stops at the first successful match or fails if no permissions are found. + +* Permission Type-Scope-Effect Matrix + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Permission TypeScope(Hierarchy)Effect
CREATEANYCreate any table/database
DATABASECreate tables in the specified database; create a database with the specified name
TABLECreate a table with the specified name
DROPANYDelete any table/database
DATABASEDelete the specified database or its tables
TABLEDelete the specified table
ALTERANYModify definitions of any table/database
DATABASEModify definitions of the specified database or its tables
TABLEModify the definition of the specified table
SELECTANYQuery data from any table in any database
DATABASEQuery data from any table in the specified database
TABLEQuery data from the specified table
INSERTANYInsert/update data in any table
DATABASEInsert/update data in any table within the specified database
TABLEInsert/update data in the specified table
DELETEANYDelete data from any table
DATABASEDelete data from tables within the specified database
TABLEDelete data from the specified table
+ +## 3. User and Role Management + +1. Create User (Requires `MANAGE_USER` Permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +Constraints: + +* Username: 4-32 characters (letters, numbers, special chars: `!@#$%^&*()_+-=`). Cannot duplicate the admin (`root`) username. +* Password: 4-32 characters (letters, numbers, special chars). Stored as SHA-256 hash by default. + +2. Modify Password + +Users can modify their own passwords. Modifying others' passwords requires `MANAGE_USER`. + +```SQL +ALTER USER SET PASSWORD +eg: ALTER USER tempuser SET PASSWORD 'newpwd' +``` + +3. Delete User (Requires `MANAGE_USER`) + +```SQL +DROP USER +eg: DROP USER user1 +``` + +4. Create Role (Requires `MANAGE_ROLE`) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +Constraints: + +* Role Name: 4-32 characters (letters, numbers, special chars). Cannot duplicate the admin role name. + +5. Delete Role (Requires `MANAGE_ROLE`) + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +6. Assign Role to User (Requires `MANAGE_ROLE`) + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +7. Revoke Role from User (Requires `MANAGE_ROLE`) + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +8. List All Users (Requires `MANAGE_USER`) + +```SQL +LIST USER +``` + +9. List All Roles (Requires `MANAGE_ROLE`) + +```SQL +LIST ROLE +``` + +10. List Users in a Role (Requires `MANAGE_USER`) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +11. List Roles of a User + +* Users can list their own permissions. +* Listing others' permissions requires `MANAGE_USER`. + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +12. List User Permissions + +* Users can list their own permissions. +* Listing others' permissions requires `MANAGE_USER`. + +```SQL +LIST PRIVILEGES OF USER +eg: LIST PRIVILEGES OF USER tempuser +``` + +13. List Role Permissions + +* Users can list permissions of roles they have. +* Listing other roles' permissions requires `MANAGE_ROLE`. + +```SQL +LIST PRIVILEGES OF ROLE +eg: LIST PRIVILEGES OF ROLE actor +``` + +## 4. Permission Management + +IoTDB supports granting and revoking permissions through the following three methods: + +* Direct assignment/revocation by a super administrator +* Assignment/revocation by users with the `GRANT OPTION` privilege +* Assignment/revocation via roles (managed by super administrators or users with `MANAGE_ROLE` permissions) + +In the IoTDB Table Model, the following principles apply when granting or revoking permissions: + +* **Global permissions** can be granted/revoked without specifying a scope. +* **Data permissions** require specifying both the permission type and permission scope. When revoking, only the explicitly defined scope is affected, regardless of hierarchical inclusion relationships. +* Preemptive permission planning is allowed—permissions can be granted for databases or tables that do not yet exist. +* Repeated granting/revoking of permissions is permitted. +* `WITH GRANT OPTION`: Allows users to manage permissions within the granted scope. Users with this option can grant or revoke permissions for other users in the same scope. + +### 4.1 Granting Permissions + +1. Grant a user the permission to manage users + +```SQL +GRANT MANAGE_USER TO USER +eg: GRANT MANAGE_USER TO USER TEST_USER +``` + +2. Grant a user the permission to create databases and tables within the database, and allow them to manage permissions in that scope + +```SQL +GRANT CREATE ON DATABASE TO USER WITH GRANT OPTION +eg: GRANT CREATE ON DATABASE TESTDB TO USER TEST_USER WITH GRANT OPTION +``` + +3. Grant a role the permission to query a database + +```SQL +GRANT SELECT ON DATABASE TO ROLE +eg: GRANT SELECT ON DATABASE TESTDB TO ROLE TEST_ROLE +``` + +4. Grant a user the permission to query a table + +```SQL +GRANT SELECT ON . TO USER +eg: GRANT SELECT ON TESTDB.TESTTABLE TO USER TEST_USER +``` + +5. Grant a role the permission to query all databases and tables + +```SQL +GRANT SELECT ON ANY TO ROLE +eg: GRANT SELECT ON ANY TO ROLE TEST_ROLE +``` + +6. ALL Syntax Sugar: ALL represents all permissions within a given scope, allowing flexible permission granting. + +```sql +GRANT ALL TO USER TESTUSER +-- Grants all possible permissions to the user, including global permissions and all data permissions under ANY scope. + +GRANT ALL ON ANY TO USER TESTUSER +-- Grants all data permissions under the ANY scope. After execution, the user will have all data permissions across all databases. + +GRANT ALL ON DATABASE TESTDB TO USER TESTUSER +-- Grants all data permissions within the specified database. After execution, the user will have all data permissions on that database. + +GRANT ALL ON TABLE TESTTABLE TO USER TESTUSER +-- Grants all data permissions on the specified table. After execution, the user will have all data permissions on that table. +``` + +### 4.2 Revoking Permissions + +1. Revoke a user's permission to manage users + +```SQL +REVOKE MANAGE_USER FROM USER +eg: REVOKE MANAGE_USER FROM USER TEST_USER +``` + +2. Revoke a user's permission to create databases and tables within the database + +```SQL +REVOKE CREATE ON DATABASE FROM USER +eg: REVOKE CREATE ON DATABASE TEST_DB FROM USER TEST_USER +``` + +3. Revoke a user's permission to query a table + +```SQL +REVOKE SELECT ON . FROM USER +eg: REVOKE SELECT ON TESTDB.TESTTABLE FROM USER TEST_USER +``` + +4. Revoke a user's permission to query all databases and tables + +```SQL +REVOKE SELECT ON ANY FROM USER +eg: REVOKE SELECT ON ANY FROM USER TEST_USER +``` + +5. ALL Syntax Sugar: ALL represents all permissions within a given scope, allowing flexible permission revocation. + +```sql +REVOKE ALL FROM USER TESTUSER +-- Revokes all global permissions and all data permissions under ANY scope. + +REVOKE ALL ON ANY FROM USER TESTUSER +-- Revokes all data permissions under the ANY scope, without affecting DB or TABLE-level permissions. + +REVOKE ALL ON DATABASE TESTDB FROM USER TESTUSER +-- Revokes all data permissions on the specified database, without affecting TABLE-level permissions. + +REVOKE ALL ON TABLE TESTDB FROM USER TESTUSER +-- Revokes all data permissions on the specified table. +``` + +### 4.3 Viewing User Permissions + +Each user has an access control list that identifies all the permissions they have been granted. You can use the `LIST PRIVILEGES OF USER ` statement to view the permission information of a specific user or role. The output format is as follows: + +| ROLE | SCOPE | PRIVIVLEGE | WITH GRANT OPTION | +|--------------|---------| -------------- |-------------------| +| | DB1.TB1 | SELECT | FALSE | +| | | MANAGE\_ROLE | TRUE | +| ROLE1 | DB2.TB2 | UPDATE | TRUE | +| ROLE1 | DB3.\* | DELETE | FALSE | +| ROLE1 | \*.\* | UPDATE | TRUE | + +* ​**ROLE column**​: If empty, it indicates the user's own permissions. If not empty, it means the permission is derived from a granted role. +* ​**SCOPE column**​: Represents the permission scope of the user/role. Table-level permissions are denoted as `DB.TABLE`, database-level permissions as `DB.*`, and ANY-level permissions as `*.*`. +* ​**PRIVILEGE column**​: Lists the specific permission types. +* ​**WITH GRANT OPTION column**​: If `TRUE`, it means the user can grant their own permissions to others. +* A user or role can have permissions in both the tree model and the table model, but the system will only display the permissions relevant to the currently connected model. Permissions under the other model will not be shown. + +## 5. Example + +Using the content from the [Sample Data](../Reference/Sample-Data.md) as an example, the data in the two tables may belong to the **bj** and **sh** data centers, respectively. To prevent each center from accessing the other's database data, we need to implement permission isolation at the data center level. + +### 5.1 Creating Users + +Use `CREATE USER ` to create users. For example, the **root** user with all permissions can create two user roles for the **ln** and **sgcc** groups, named **bj\_write\_user** and ​**sh\_write\_user**​, both with the password ​**write\_pwd**​. The SQL statements are: + +```SQL +CREATE USER bj_write_user 'write_pwd' +CREATE USER sh_write_user 'write_pwd' +``` + +To display the users, use the following SQL statement: + +```Plain +LIST USER +``` + +The result will show the two newly created users, as follows: + +```sql ++-------------+ +| User| ++-------------+ +|bj_write_user| +| root| +|sh_write_user| ++-------------+ +``` + +### 5.2 Granting User Permissions + +Although the two users have been created, they do not yet have any permissions and thus cannot perform database operations. For example, if the **bj\_write\_user** attempts to write data to ​**table1**​, the SQL statement would be: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +``` + +The system will deny the operation and display an error: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: database is not specified +IoTDB> use database1 +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: DATABASE database1 +``` + +The **root** user can grant **bj\_write\_user** write permissions for **table1** using the `GRANT ON TO USER ` statement, for example: + +```sql +GRANT INSERT ON database1.table1 TO USER bj_write_user +``` + +After granting permissions, **bj\_write\_user** can successfully write data: + +```SQL +IoTDB> use database1 +Msg: The statement is executed successfully. +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: The statement is executed successfully. +``` + +### 5.3 Revoking User Permissions + +After granting permissions, the **root** user can revoke them using the `REVOKE ON FROM USER ` statement. For example: + +```sql +REVOKE INSERT ON database1.table1 FROM USER bj_write_user +REVOKE INSERT ON database1.table2 FROM USER sh_write_user +``` + +Once permissions are revoked, **bj\_write\_user** will no longer have write access to ​**table1**​: + +```sql +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: No permissions for this operation, please add privilege INSERT ON database1.table1 +``` diff --git a/src/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md b/src/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md index 00e64f82d..e90d9dcbe 100644 --- a/src/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md +++ b/src/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md @@ -580,53 +580,53 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------| :------- | :------------ | -| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------| :------- |:---------------------------------------------| +| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | #### iotdb-air-gap-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- | :------------ | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| air-gap.handshake-timeout-ms | The timeout duration for the handshake requests when the sender and receiver attempt to establish a connection for the first time, in milliseconds. | Integer | No | 5000 | +| **Parameter** | **Description** | Value Range | Required | Default Value | +| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| air-gap.handshake-timeout-ms | The timeout duration for the handshake requests when the sender and receiver attempt to establish a connection for the first time, in milliseconds. | Integer | No | 5000 | #### iotdb-thrift-ssl-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------| :------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------|:---------------------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | #### write-back-sink @@ -645,5 +645,5 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink.opcua.security.dir | Directory for OPC UA's keys and certificates | String: Path, supports absolute and relative directories | No | Opc_security folder``in the conf directory of the DataNode related to iotdb
If there is no conf directory for iotdb (such as launching DataNode in IDEA), it will be the iotdb_opc_Security folder``in the user's home directory | | sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | No | true | | sink.user | User for OPC UA, specified in the configuration | String | No | root | -| sink.password | Password for OPC UA, specified in the configuration | String | No | root | +| sink.password | Password for OPC UA, specified in the configuration | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | | sink.opcua.placeholder | A placeholder string used to substitute for null mapping paths when the value of the ID column is null | String | Optional | "null" | diff --git a/src/UserGuide/Master/Tree/API/Programming-Data-Subscription.md b/src/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/API/Programming-Data-Subscription.md rename to src/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md index 7019f1b51..91e21cb83 100644 --- a/src/UserGuide/Master/Tree/API/Programming-Data-Subscription.md +++ b/src/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md @@ -21,7 +21,7 @@ # Data Subscription API -IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription.md) +IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription_apache) ## 1. Core Steps @@ -33,7 +33,7 @@ IoTDB provides powerful data subscription functionality, allowing users to acces ## 2. Detailed Steps -This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API.md#_3-native-interface-description) +This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API_apache#_3-native-interface-description) ### 2.1 Create a Maven project diff --git a/src/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md b/src/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md new file mode 100644 index 000000000..c49e12d6e --- /dev/null +++ b/src/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md @@ -0,0 +1,259 @@ + + + + +# Data Subscription API + +IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription_timecho) + +## 1. Core Steps + +1. Create Topic: Create a Topic that includes the measurement points you wish to subscribe to. +2. Subscribe to Topic: Before a consumer subscribes to a topic, the topic must have been created, otherwise the subscription will fail. Consumers under the same consumer group will evenly distribute the data. +3. Consume Data: Only by explicitly subscribing to a specific topic will you receive data from that topic. +4. Unsubscribe: When a consumer is closed, it will exit the corresponding consumer group and cancel all existing subscriptions. + + +## 2. Detailed Steps + +This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API_timecho#_3-native-interface-description) + + +### 2.1 Create a Maven project + +Create a Maven project and import the following dependencies(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 Code Example + +#### 2.2.1 Topic operations + +```java +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.SubscriptionSession; +import org.apache.iotdb.session.subscription.model.Topic; + +public class DataConsumerExample { + + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + try (SubscriptionSession session = new SubscriptionSession("127.0.0.1", 6667, "root", "TimechoDB@2021", 67108864)) { //Before V2.0.6.x the default password is root + // 1. open session + session.open(); + + // 2. create a topic of all data + Properties sessionConfig = new Properties(); + sessionConfig.put(TopicConstant.PATH_KEY, "root.**"); + + session.createTopic("allData", sessionConfig); + + // 3. show all topics + Set topics = session.getTopics(); + System.out.println(topics); + + // 4. show a specific topic + Optional allData = session.getTopic("allData"); + System.out.println(allData.get()); + } + } +} +``` + +#### 2.2.2 Data Consume + +##### Scenario-1: Subscribing to newly added real-time data in IoTDB (for scenarios such as dashboard or configuration display) + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessageType; +import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.tsfile.read.common.RowRecord; + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + + // 5. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //Before V2.0.6.x the default password is root + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + final short messageType = message.getMessageType(); + if (SubscriptionMessageType.isValidatedMessageType(messageType)) { + for (final SubscriptionSessionDataSet dataSet : message.getSessionDataSetsHandler()) { + while (dataSet.hasNext()) { + final RowRecord record = dataSet.next(); + System.out.println(record); + } + } + } + } + } + } + } +} + + +``` + +##### Scenario-2: Subscribing to newly added TsFiles (for scenarios such as regular data backup) + +Prerequisite: The format of the topic to be consumed must be of the TsfileHandler type. For example:`create topic topic_all_tsfile with ('path'='root.**','format'='TsFileHandler')` + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; + + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + // 1. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + // 2. Specify the consumption type as the tsfile type + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //Before V2.0.6.x the default password is root + consumerConfig.put(ConsumerConstant.FILE_SAVE_DIR_KEY, "/Users/iotdb/Downloads"); + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all_tsfile"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + message.getTsFileHandler().copyFile("/Users/iotdb/Downloads/1.tsfile"); + } + } + } + } +} +``` + + + + +## 3. Java Native API Description + +### 3.1 Parameter List + +The consumer-related parameters can be set through the Properties parameter object. The specific parameters are as follows: + +#### SubscriptionConsumer + + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :---------------------- |:-------------------------------------------------------------------------------------| :----------------------------------------------------------- | +| host | optional: 127.0.0.1 | `String`: The RPC host of a DataNode in IoTDB | +| port | optional: 6667 | `Integer`: The RPC port of a DataNode in IoTDB | +| node-urls | optional: 127.0.0.1:6667 | `List`: The RPC addresses of all DataNodes in IoTDB, which can be multiple; either host:port or node-urls can be filled. If both host:port and node-urls are filled, the **union** of host:port and node-urls will be taken to form a new node-urls for application | +| username | optional: root | `String`: The username of the DataNode in IoTDB | +| password | optional: TimechoDB@2021 //Before V2.0.6.x the default password is root | `String`: The password of the DataNode in IoTDB | +| groupId | optional | `String`: consumer group id,if not specified, it will be randomly assigned (a new consumer group),ensuring that the consumer group id of different consumer groups are all different | +| consumerId | optional | `String`: consumer client id,if not specified, it will be randomly assigned,ensuring that each consumer client id in the same consumer group is different | +| heartbeatIntervalMs | optional: 30000 (min: 1000) | `Long`: The interval at which the consumer sends periodic heartbeat requests to the IoTDB DataNode | +| endpointsSyncIntervalMs | optional: 120000 (min: 5000) | `Long`: The interval at which the consumer detects the expansion or contraction of IoTDB cluster nodes and adjusts the subscription connection | +| fileSaveDir | optional: Paths.get(System.getProperty("user.dir"), "iotdb-subscription").toString() | `String`: The temporary directory path where the consumer stores the subscribed TsFile files | +| fileSaveFsync | optional: false | `Boolean`: Whether the consumer actively calls fsync during the subscription of TsFiles | + +Special configurations in `SubscriptionPushConsumer` : + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| ackStrategy | optional: `ACKStrategy.AFTER_CONSUME` | The acknowledgment mechanism for consumption progress includes the following options: `ACKStrategy.BEFORE_CONSUME`(the consumer submits the consumption progress immediately upon receiving the data, before `onReceive` )`ACKStrategy.AFTER_CONSUME`(the consumer submits the consumption progress after consuming the data, after `onReceive` ) | +| consumeListener | optional | The callback function for consuming data, which needs to implement the `ConsumeListener` interface, defining the processing logic for consuming `SessionDataSetsHandler` and `TsFileHandler` formatted data | +| autoPollIntervalMs | optional: 5000 (min: 500) | Long: The time interval at which the consumer automatically pulls data, in **ms** | +| autoPollTimeoutMs | optional: 10000 (min: 1000) | Long: The timeout duration for the consumer to pull data each time, in **ms** | + +Special configurations in `SubscriptionPullConsumer` : + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| autoCommit | optional: true | Boolean: Whether to automatically commit the consumption progress. If this parameter is set to false, the `commit` method needs to be called manually to submit the consumption progress | +| autoCommitInterval | optional: 5000 (min: 500) | Long: The time interval for automatically committing the consumption progress, in **ms** .This parameter only takes effect when the `autoCommit` parameter is set to true | + + +### 3.2 Function List + +#### Data subscription + +##### SubscriptionPullConsumer + +| **Function name** | **Description** | **Parameter** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | Opens the consumer connection and starts message consumption. If `autoCommit` is enabled, it will start the automatic commit worker. | None | +| `close()` | Closes the consumer connection. If `autoCommit` is enabled, it will commit all uncommitted messages before closing. | None | +| `poll(final Duration timeout)` | Pulls messages with a specified timeout. | `timeout` : The timeout duration. | +| `poll(final long timeoutMs)` | Pulls messages with a specified timeout in milliseconds. | `timeoutMs` : The timeout duration in milliseconds. | +| `poll(final Set topicNames, final Duration timeout)` | Pulls messages from specified topics with a specified timeout. | `topicNames` : The set of topics to pull messages from. `timeout`: The timeout duration。 | +| `poll(final Set topicNames, final long timeoutMs)` | Pulls messages from specified topics with a specified timeout in milliseconds. | `topicNames` : The set of topics to pull messages from.`timeoutMs`: The timeout duration in milliseconds. | +| `commitSync(final SubscriptionMessage message)` | Synchronously commits a single message. | `message` : The message object to be committed. | +| `commitSync(final Iterable messages)` | Synchronously commits multiple messages. | `messages` : The collection of message objects to be committed. | +| `commitAsync(final SubscriptionMessage message)` | Asynchronously commits a single message. | `message` : The message object to be committed. | +| `commitAsync(final Iterable messages)` | Asynchronously commits multiple messages. | `messages` : The collection of message objects to be committed. | +| `commitAsync(final SubscriptionMessage message, final AsyncCommitCallback callback)` | Asynchronously commits a single message with a specified callback. | `message` : The message object to be committed. `callback` : The callback function to be executed after asynchronous commit. | +| `commitAsync(final Iterable messages, final AsyncCommitCallback callback)` | Asynchronously commits multiple messages with a specified callback. | `messages` : The collection of message objects to be committed.`callback` : The callback function to be executed after asynchronous commit. | + +##### SubscriptionPushConsumer + +| **Function name** | **Description** | **Parameter** | +| -------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | Opens the consumer connection, starts message consumption, and submits the automatic polling worker. | None | +| `close()` | Closes the consumer connection and stops message consumption. | None | +| `toString()` | Returns the core configuration information of the consumer object. | None | +| `coreReportMessage()` | Obtains the key-value representation of the consumer's core configuration. | None | +| `allReportMessage()` | Obtains the key-value representation of all the consumer's configurations. | None | +| `buildPushConsumer()` | Builds a `SubscriptionPushConsumer` instance through the `Builder` | None | +| `ackStrategy(final AckStrategy ackStrategy)` | Configures the message acknowledgment strategy for the consumer. | `ackStrategy`: The specified message acknowledgment strategy. | +| `consumeListener(final ConsumeListener consumeListener)` | Configures the message consumption logic for the consumer. | `consumeListener`: The processing logic when the consumer receives messages. | +| `autoPollIntervalMs(final long autoPollIntervalMs)` | Configures the interval for automatic polling. | `autoPollIntervalMs` : The interval for automatic polling, in milliseconds. | +| `autoPollTimeoutMs(final long autoPollTimeoutMs)` | Configures the timeout for automatic polling.间。 | `autoPollTimeoutMs`: The timeout for automatic polling, in milliseconds. | \ No newline at end of file diff --git a/src/UserGuide/latest/API/Programming-JDBC.md b/src/UserGuide/Master/Tree/API/Programming-JDBC_apache.md similarity index 99% rename from src/UserGuide/latest/API/Programming-JDBC.md rename to src/UserGuide/Master/Tree/API/Programming-JDBC_apache.md index 232e62ef4..1a2902672 100644 --- a/src/UserGuide/latest/API/Programming-JDBC.md +++ b/src/UserGuide/Master/Tree/API/Programming-JDBC_apache.md @@ -22,7 +22,7 @@ # JDBC **Note**: The current JDBC implementation is only for connecting with third-party tools. We do not recommend using JDBC (when executing insert statements) as it cannot provide high-performance writing. For queries, we recommend using JDBC. -PLEASE USE [Java Native API](./Programming-Java-Native-API.md) INSTEAD* +PLEASE USE [Java Native API](./Programming-Java-Native-API_apache) INSTEAD* ## 1. Dependencies diff --git a/src/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md b/src/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md new file mode 100644 index 000000000..782d7e9ab --- /dev/null +++ b/src/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md @@ -0,0 +1,295 @@ + + +# JDBC + +**Note**: The current JDBC implementation is only for connecting with third-party tools. We do not recommend using JDBC (when executing insert statements) as it cannot provide high-performance writing. For queries, we recommend using JDBC. +PLEASE USE [Java Native API](./Programming-Java-Native-API_timecho) INSTEAD* + +## 1. Dependencies + +* JDK >= 1.8+ +* Maven >= 3.9+ + +## 2. Installation + +In root directory: + +```shell +mvn clean install -pl iotdb-client/jdbc -am -DskipTests +``` + +## 3. Use IoTDB JDBC with Maven + +```xml + + + org.apache.iotdb + iotdb-jdbc + 1.3.1 + + +``` + +## 4. Coding Examples + +This chapter provides an example of how to open a database connection, execute an SQL query, and display the results. + +It requires including the packages containing the JDBC classes needed for database programming. + +**NOTE: For faster insertion, the insertTablet() in Session is recommended.** + +```java +import java.sql.*; +import org.apache.iotdb.jdbc.IoTDBSQLException; + +public class JDBCExample { + /** + * Before executing a SQL statement with a Statement object, you need to create a Statement object using the createStatement() method of the Connection object. + * After creating a Statement object, you can use its execute() method to execute a SQL statement + * Finally, remember to close the 'statement' and 'connection' objects by using their close() method + * For statements with query results, we can use the getResultSet() method of the Statement object to get the result set. + */ + public static void main(String[] args) throws SQLException { + Connection connection = getConnection(); + if (connection == null) { + System.out.println("get connection defeat"); + return; + } + Statement statement = connection.createStatement(); + //Create database + try { + statement.execute("CREATE DATABASE root.demo"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + + + //SHOW DATABASES + statement.execute("SHOW DATABASES"); + outputResult(statement.getResultSet()); + + //Create time series + //Different data type has different encoding methods. Here use INT32 as an example + try { + statement.execute("CREATE TIMESERIES root.demo.s0 WITH DATATYPE=INT32,ENCODING=RLE;"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + //Show time series + statement.execute("SHOW TIMESERIES root.demo"); + outputResult(statement.getResultSet()); + //Show devices + statement.execute("SHOW DEVICES"); + outputResult(statement.getResultSet()); + //Count time series + statement.execute("COUNT TIMESERIES root"); + outputResult(statement.getResultSet()); + //Count nodes at the given level + statement.execute("COUNT NODES root LEVEL=3"); + outputResult(statement.getResultSet()); + //Count timeseries group by each node at the given level + statement.execute("COUNT TIMESERIES root GROUP BY LEVEL=3"); + outputResult(statement.getResultSet()); + + + //Execute insert statements in batch + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(1,1);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(1,1);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(2,15);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(2,17);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) values(4,12);"); + statement.executeBatch(); + statement.clearBatch(); + + //Full query statement + String sql = "SELECT * FROM root.demo"; + ResultSet resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Exact query statement + sql = "SELECT s0 FROM root.demo WHERE time = 4;"; + resultSet= statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Time range query + sql = "SELECT s0 FROM root.demo WHERE time >= 2 AND time < 5;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Aggregate query + sql = "SELECT COUNT(s0) FROM root.demo;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Delete time series + statement.execute("DELETE timeseries root.demo.s0"); + + //close connection + statement.close(); + connection.close(); + } + + public static Connection getConnection() { + // JDBC driver name and database URL + String driver = "org.apache.iotdb.jdbc.IoTDBDriver"; + String url = "jdbc:iotdb://127.0.0.1:6667/"; + // set rpc compress mode + // String url = "jdbc:iotdb://127.0.0.1:6667?rpc_compress=true"; + + // Database credentials + String username = "root"; + String password = "TimechoDB@2021"; //Before V2.0.6.x the default password is root + + Connection connection = null; + try { + Class.forName(driver); + connection = DriverManager.getConnection(url, username, password); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return connection; + } + + /** + * This is an example of outputting the results in the ResultSet + */ + private static void outputResult(ResultSet resultSet) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print(resultSet.getString(i)); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` + +The parameter `version` can be used in the url: +````java +String url = "jdbc:iotdb://127.0.0.1:6667?version=V_1_0"; +```` +The parameter `version` represents the SQL semantic version used by the client, which is used in order to be compatible with the SQL semantics of `0.12` when upgrading to `0.13`. +The possible values are: `V_0_12`, `V_0_13`, `V_1_0`. + +In addition, IoTDB provides additional interfaces in JDBC for users to read and write the database using different character sets (e.g., GB18030) in the connection. +The default character set for IoTDB is UTF-8. When users want to use a character set other than UTF-8, they need to specify the charset property in the JDBC connection. For example: +1. Create a connection using the GB18030 charset: +```java +DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root +``` +2. When executing SQL with the `IoTDBStatement` interface, the SQL can be provided as a `byte[]` array, and it will be parsed into a string according to the specified charset. +```java +public boolean execute(byte[] sql) throws SQLException; +``` +3. When outputting query results, the `getBytes` method of `ResultSet` can be used to get `byte[]`, which will be encoded using the charset specified in the connection. +```java +System.out.print(resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); +``` +Here is a complete example: +```java +public class JDBCCharsetExample { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCCharsetExample.class); + + public static void main(String[] args) throws Exception { + Class.forName("org.apache.iotdb.jdbc.IoTDBDriver"); + + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + + final String insertSQLWithGB18030 = + "insert into root.测试(timestamp, 维语, 彝语, 繁体, 蒙文, 简体, 标点符号, 藏语) values(1, 'ئۇيغۇر تىلى', 'ꆈꌠꉙ', \"繁體\", 'ᠮᠣᠩᠭᠣᠯ ᠬᠡᠯᠡ', '简体', '——?!', \"བོད་སྐད།\");"; + final byte[] insertSQLWithGB18030Bytes = insertSQLWithGB18030.getBytes("GB18030"); + statement.execute(insertSQLWithGB18030Bytes); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + + outputResult("GB18030"); + outputResult("UTF-8"); + outputResult("UTF-16"); + outputResult("GBK"); + outputResult("ISO-8859-1"); + } + + private static void outputResult(String charset) throws SQLException { + System.out.println("[Charset: " + charset + "]"); + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=" + charset, "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + outputResult(statement.executeQuery("select ** from root"), Charset.forName(charset)); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + } + + private static void outputResult(ResultSet resultSet, Charset charset) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print( + resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/API/Programming-Java-Native-API.md b/src/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/API/Programming-Java-Native-API.md rename to src/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md index b191fe317..0f0778b7c 100644 --- a/src/UserGuide/Master/Tree/API/Programming-Java-Native-API.md +++ b/src/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md @@ -32,7 +32,7 @@ In the native API of IoTDB, the `Session` is the core interface for interacting ## 2. Detailed Steps -This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API.md#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/master/example/session/src/main/java/org/apache/iotdb) +This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API_apache#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) ### 2.1 Create a Maven Project diff --git a/src/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md b/src/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md new file mode 100644 index 000000000..dd8c3663b --- /dev/null +++ b/src/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md @@ -0,0 +1,498 @@ + + +# Java Native API + +In the native API of IoTDB, the `Session` is the core interface for interacting with the database. It integrates a rich set of methods that support data writing, querying, and metadata operations. By instantiating a `Session`, you can establish a connection to the IoTDB server and perform various database operations within the environment constructed by this connection. The `Session` is not thread-safe and should not be called simultaneously by multiple threads. + +`SessionPool` is a connection pool for `Session`, and it is recommended to use `SessionPool` for programming. In scenarios with multi-threaded concurrency, `SessionPool` can manage and allocate connection resources effectively, thereby improving system performance and resource utilization efficiency. + +## 1. Overview of Steps + +1. Create a Connection Pool Instance: Initialize a SessionPool object to manage multiple Session instances. +2. Perform Operations: Directly obtain a Session instance from the SessionPool and execute database operations, without the need to open and close connections each time. +3. Close Connection Pool Resources: When database operations are no longer needed, close the SessionPool to release all related resources. + + +## 2. Detailed Steps + +This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API_timecho#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) + +### 2.1 Create a Maven Project + +Create a Maven project and add the following dependencies to the pom.xml file (JDK >= 1.8, Maven >= 3.6): + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 Creating a Connection Pool Instance + + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.session.pool.SessionPool; + +public class IoTDBSessionPoolExample { + private static SessionPool sessionPool; + + public static void main(String[] args) { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root " + .maxSize(3) + .build(); + } +} +``` + +### 2.3 Performing Database Operations + +#### 2.3.1 Data Insertion + +In industrial scenarios, data insertion can be categorized into the following types: inserting multiple rows of data, and inserting multiple rows of data for a single device. Below, we introduce the insertion interfaces for different scenarios. + +##### Multi-Row Data Insertion Interface + +Interface Description: Supports inserting multiple rows of data at once, where each row corresponds to multiple measurement values for a device at a specific timestamp. + + +Interface List: + +| **Interface Name** | **Function Description** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Inserts multiple rows of data, suitable for scenarios where measurements are independently collected. | + +Code Example: + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertRecordsExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + public static void insertRecordsExample() throws IoTDBConnectionException, StatementExecutionException { + String deviceId = "root.sg1.d1"; + List measurements = new ArrayList<>(); + measurements.add("s1"); + measurements.add("s2"); + measurements.add("s3"); + List deviceIds = new ArrayList<>(); + List> measurementsList = new ArrayList<>(); + List> valuesList = new ArrayList<>(); + List timestamps = new ArrayList<>(); + List> typesList = new ArrayList<>(); + + for (long time = 0; time < 500; time++) { + List values = new ArrayList<>(); + List types = new ArrayList<>(); + values.add(1L); + values.add(2L); + values.add(3L); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + + deviceIds.add(deviceId); + measurementsList.add(measurements); + valuesList.add(values); + typesList.add(types); + timestamps.add(time); + if (time != 0 && time % 100 == 0) { + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + deviceIds.clear(); + measurementsList.clear(); + valuesList.clear(); + typesList.clear(); + timestamps.clear(); + } + } + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +##### Single-Device Multi-Row Data Insertion Interface + +Interface Description: Supports inserting multiple rows of data for a single device at once, where each row corresponds to multiple measurement values for a specific timestamp. + +Interface List: + +| **Interface Name** | **Function Description** | +| ----------------------------- | ------------------------------------------------------------ | +| `insertTablet(Tablet tablet)` | Inserts multiple rows of data for a single device, suitable for scenarios where measurements are independently collected. | + +Code Example: + +```java +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.write.record.Tablet; +import org.apache.tsfile.write.schema.IMeasurementSchema; +import org.apache.tsfile.write.schema.MeasurementSchema; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertTabletExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + //nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + private static void insertTabletExample() throws IoTDBConnectionException, StatementExecutionException { + /* + * A Tablet example: + * device1 + * time s1, s2, s3 + * 1, 1, 1, 1 + * 2, 2, 2, 2 + * 3, 3, 3, 3 + */ + // The schema of measurements of one device + // only measurementId and data type in MeasurementSchema take effects in Tablet + List schemaList = new ArrayList<>(); + schemaList.add(new MeasurementSchema("s1", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s2", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s3", TSDataType.INT64)); + + Tablet tablet = new Tablet("root.sg.d1",schemaList,100); + + // Method 1 to add tablet data + long timestamp = System.currentTimeMillis(); + + Random random = new Random(); + for (long row = 0; row < 100; row++) { + int rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, timestamp); + for (int s = 0; s < 3; s++) { + long value = random.nextLong(); + tablet.addValue(schemaList.get(s).getMeasurementName(), rowIndex, value); + } + if (tablet.getRowSize() == tablet.getMaxRowNumber()) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + timestamp++; + } + if (tablet.getRowSize() != 0) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +#### 2.3.2 SQL Operations + +SQL operations are divided into two categories: queries and non-queries. The corresponding interfaces are executeQuery and executeNonQuery. The difference between them is that the former executes specific query statements and returns a result set, while the latter performs insert, delete, and update operations and does not return a result set. + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.isession.pool.SessionDataSetWrapper; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. executes a non-query SQL statement, such as a DDL or DML command. + executeQueryExample(); + // 3. executes a query SQL statement and returns the result set. + executeNonQueryExample(); + // 4. close SessionPool + closeSessionPool(); + } + + private static void executeNonQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. create a nonAligned time series + sessionPool.executeNonQueryStatement("create timeseries root.test.d1.s1 with dataType = int32"); + // 2. set ttl + sessionPool.executeNonQueryStatement("set TTL to root.test.** 10000"); + // 3. delete time series + sessionPool.executeNonQueryStatement("delete timeseries root.test.d1.s1"); + } + + private static void executeQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. execute normal query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select s1 from root.sg1.d1 limit 10")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + // 2. execute aggregate query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select count(s1) from root.sg1.d1 group by ([0, 40), 5ms) ")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +### 3. Native Interface Description + +#### 3.1 Parameter List + +The Session class has the following fields, which can be set through the constructor or the Session.Builder method: + +| **Field Name** | **Type** | **Description** | +| -------------------------------- | ----------------------------------- | ------------------------------------------------------------ | +| `nodeUrls` | `List` | List of URLs for database nodes, supporting multiple node connections | +| `username` | `String` | Username | +| `password` | `String` | Password | +| `fetchSize` | `int` | Default batch size for query results | +| `useSSL` | `boolean` | Whether to enable SSL | +| `trustStore` | `String` | Path to the trust store | +| `trustStorePwd` | `String` | Password for the trust store | +| `queryTimeoutInMs` | `long` | Query timeout in milliseconds | +| `enableRPCCompression` | `boolean` | Whether to enable RPC compression | +| `connectionTimeoutInMs` | `int` | Connection timeout in milliseconds | +| `zoneId` | `ZoneId` | Time zone setting for the session | +| `thriftDefaultBufferSize` | `int` | Default buffer size for Thrift Thrift | +| `thriftMaxFrameSize` | `int` | Maximum frame size for Thrift Thrift | +| `defaultEndPoint` | `TEndPoint` | Default database endpoint information | +| `defaultSessionConnection` | `SessionConnection` | Default session connection object | +| `isClosed` | `boolean` | Whether the current session is closed | +| `enableRedirection` | `boolean` | Whether to enable redirection | +| `enableRecordsAutoConvertTablet` | `boolean` | Whether to enable the function of recording the automatic transfer to Tablet | +| `deviceIdToEndpoint` | `Map` | Mapping of device IDs to database endpoints | +| `endPointToSessionConnection` | `Map` | Mapping of database endpoints to session connections | +| `executorService` | `ScheduledExecutorService` | Thread pool for periodically updating the node list | +| `availableNodes` | `INodeSupplier` | Supplier of available nodes | +| `enableQueryRedirection` | `boolean` | Whether to enable query redirection | +| `version` | `Version` | Client version number, used for compatibility judgment with the server | +| `enableAutoFetch` | `boolean` | Whether to enable automatic fetching | +| `maxRetryCount` | `int` | Maximum number of retries | +| `retryIntervalInMs` | `long` | Retry interval in milliseconds | + + + +#### 3.2 Interface list + +##### 3.2.1 Metadata Management + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------ | +| `createDatabase(String database)` | Create a database | `database`: The name of the database to be created | +| `deleteDatabase(String database)` | Delete a specified database | `database`: The name of the database to be deleted | +| `deleteDatabases(List databases)` | Batch delete databases | `databases`: A list of database names to be deleted | +| `createTimeseries(String path, TSDataType dataType, TSEncoding encoding, CompressionType compressor)` | Create a single time series | `path`: The path of the time series,`dataType`: The data type,`encoding`: The encoding type,`compressor`: The compression type | +| `createAlignedTimeseries(...)` | Create aligned time series | Device ID, list of measurement points, list of data types, list of encodings, list of compression types | +| `createMultiTimeseries(...)` | Batch create time series | Multiple paths, data types, encodings, compression types, properties, tags, aliases, etc. | +| `deleteTimeseries(String path)` | Delete a time series | `path`: The path of the time series to be deleted | +| `deleteTimeseries(List paths)` | Batch delete time series | `paths`: A list of time series paths to be deleted | +| `setSchemaTemplate(String templateName, String prefixPath)` | Set a schema template | `templateName`: The name of template,`prefixPath`: The path where the template is applied | +| `createSchemaTemplate(Template template)` | Create a schema template | `template`: The template object | +| `dropSchemaTemplate(String templateName)` | Delete a schema template | `templateName`: The name of template to be deleted | +| `addAlignedMeasurementsInTemplate(...)` | Add aligned measurements to a template | Template name, list of measurement paths, data type, encoding type, compression type | +| `addUnalignedMeasurementsInTemplate(...)` | Add unaligned measurements to a template | Same as above | +| `deleteNodeInTemplate(String templateName, String path)` | Delete a node in a template | `templateName`: The name of template,`path`: The path to be deleted | +| `countMeasurementsInTemplate(String name)` | Count the number of measurements in a template | `name`: The name of template | +| `isMeasurementInTemplate(String templateName, String path)` | Check if a measurement exists in a template | `templateName`: The name of template,`path`: The path of the measurement | +| `isPathExistInTemplate(String templateName, String path)` | Check if a path exists in a template | same as above | +| `showMeasurementsInTemplate(String templateName)` | Show measurements in a template | `templateName`: The name of template | +| `showMeasurementsInTemplate(String templateName, String pattern)` | Show measurements in a template by pattern | `templateName`: The name of template,`pattern`: The matching pattern | +| `showAllTemplates()` | Show all templates | No parameters | +| `showPathsTemplateSetOn(String templateName)` | Show paths where a template is set | `templateName`: The name of the template | +| `showPathsTemplateUsingOn(String templateName)` | Show actual paths using a template | Same as above上 | +| `unsetSchemaTemplate(String prefixPath, String templateName)` | Unset the template setting for a path | `prefixPath`: The path,`templateName`: The name of template | + + +##### 3.2.2 Data Insertion + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `insertRecord(String deviceId, long time, List measurements, List types, Object... values)` | Insert a single record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`types`: List of data types,`values`: List of values | +| `insertRecord(String deviceId, long time, List measurements, List values)` | Insert a single record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`values`: List of values | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | Insert multiple records | `deviceIds`: List of device IDs,`times`: List of timestamps,`measurementsList`: List of timestamps,`valuesList`: List of lists of values | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple records | Same as above,plus `typesList`: List of lists of data types | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`typesList`: List of lists of types,`valuesList`: List of lists of values | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | Insert sorted multiple records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | Insert string-formatted records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | Insert sorted string-formatted records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted序 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List types, List values)` | Insert a single aligned record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`types`: List of types,`values`: List of values | +| `insertAlignedRecord(String deviceId, long time, List measurements, List values)` | Insert a single string-formatted aligned record | `deviceId`: Device ID`time`: Timestamp,`measurements`: List of measurement points,`values`: List of values | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | Insert multiple aligned records | `deviceIds`: List of device IDs,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple aligned records | Same as above, plus `typesList`: List of lists of data types | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple aligned records for a single device | Same as above | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | Insert sorted multiple aligned records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | Insert string-formatted aligned records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | Insert sorted string-formatted aligned records for a single device | Same as above, plus w `haveSorted`: whether the data is already sorted | +| `insertTablet(Tablet tablet)` | Insert a single Tablet data | `tablet`: The Tablet data to be inserted | +| `insertTablet(Tablet tablet, boolean sorted)` | Insert a sorted Tablet data | Same as above, plus `sorted`: whether the data is already sorted | +| `insertAlignedTablet(Tablet tablet)` | Insert an aligned Tablet data | `tablet`: The Tablet data to be inserted | +| `insertAlignedTablet(Tablet tablet, boolean sorted)` | Insert a sorted aligned Tablet data | Same as above, plus `sorted`: whether the data is already sorted | +| `insertTablets(Map tablets)` | Insert multiple Tablet data in batch | `tablets`: Mapping from device IDs to Tablet data | +| `insertTablets(Map tablets, boolean sorted)` | Insert sorted multiple Tablet data in batch | Same as above, plus `sorted`: whether the data is already sorted | +| `insertAlignedTablets(Map tablets)` | Insert multiple aligned Tablet data in batch | `tablets`: Mapping from device IDs to Tablet data | +| `insertAlignedTablets(Map tablets, boolean sorted)` | Insert sorted multiple aligned Tablet data in batch | Same as above, plus `sorted`: whether the data is already sorted | + +##### 3.2.3 Data Deletion + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------- | +| `deleteTimeseries(String path)` | Delete a single time series | `path`: The path of the time series | +| `deleteTimeseries(List paths)` | Batch delete time series | `paths`: A list of time series paths | +| `deleteData(String path, long endTime)` | Delete historical data for a specified path | `path`: The path,`endTime`: The end timestamp | +| `deleteData(List paths, long endTime)` | Batch delete historical data for specified paths | `paths`: A list of paths,`endTime`: The end timestamp | +| `deleteData(List paths, long startTime, long endTime)` | Delete historical data within a time range for specified paths | Same as above, plus `startTime`: The start timestamp | + + +##### 3.2.4 Data Query + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | -------------------------------------------------------- | ------------------------------------------------------------ | +| `executeQueryStatement(String sql)` | Execute a query statement | `sql`: The query SQL statement | +| `executeQueryStatement(String sql, long timeoutInMs)` | Execute a query statement with timeout | `sql`: The query SQL statement, `timeoutInMs`: The query timeout (in milliseconds), default to the server configuration, which is 60s. | +| `executeRawDataQuery(List paths, long startTime, long endTime)` | Query raw data for specified paths | paths: A list of query paths, `startTime`: The start timestamp, `endTime`: The end timestamp | +| `executeRawDataQuery(List paths, long startTime, long endTime, long timeOut)` | Query raw data for specified paths (with timeout) | Same as above, plus `timeOut`: The timeout time | +| `executeLastDataQuery(List paths)` | Query the latest data | `paths`: A list of query paths | +| `executeLastDataQuery(List paths, long lastTime)` | Query the latest data at a specified time | `paths`: A list of query paths, `lastTime`: The specified timestamp | +| `executeLastDataQuery(List paths, long lastTime, long timeOut)` | Query the latest data at a specified time (with timeout) | Same as above, plus `timeOut`: The timeout time | +| `executeLastDataQueryForOneDevice(String db, String device, List sensors, boolean isLegalPathNodes)` | Query the latest data for a single device | `db`: The database name, `device`: The device name, `sensors`: A list of sensors, `isLegalPathNodes`: Whether the path nodes are legal | +| `executeAggregationQuery(List paths, List aggregations)` | Execute an aggregation query | `paths`: A list of query paths, `aggregations`: A list of aggregation types | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime)` | Execute an aggregation query with a time range | Same as above, plus `startTime`: The start timestamp, `endTime`:` The end timestamp | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval)` | Execute an aggregation query with a time interval | Same as above, plus `interval`: The time interval | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval, long slidingStep)` | Execute a sliding window aggregation query | Same as above, plus `slidingStep`: The sliding step | +| `fetchAllConnections()` | Get information of all active connections | No parameters | + +##### 3.2.5 System Status and Backup + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| -------------------------- | ----------------------------------------- | ------------------------------------------ | +| `getBackupConfiguration()` | Get backup configuration information | No parameters | +| `fetchAllConnections()` | Get information of all active connections | No parameters | +| `getSystemStatus()` | Get the system status | Deprecated, returns `SystemStatus.NORMAL` | \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md b/src/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md index fe330fa9f..a638f0f6d 100644 --- a/src/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md +++ b/src/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md @@ -80,23 +80,23 @@ create pipe p1 'sink.opcua.tcp.port' = '12686', 'sink.opcua.https.port' = '8443', 'sink.user' = 'root', - 'sink.password' = 'root', + 'sink.password' = 'TimechoDB@2021', //Before V2.0.6.x the default password is root 'sink.opcua.security.dir' = '...' ) ``` ### 2.2 Parameters -| key | value | value range | required or not | default value | -| :------------------------------ | :----------------------------------------------------------- | :------------------------------------- | :------- | :------------- | -| sink | OPC UA SINK | String: opc-ua-sink | Required | | -| sink.opcua.model | OPC UA model used | String: client-server / pub-sub | Optional | pub-sub | -| sink.opcua.tcp.port | OPC UA's TCP port | Integer: [0, 65536] | Optional | 12686 | -| sink.opcua.https.port | OPC UA's HTTPS port | Integer: [0, 65536] | Optional | 8443 | +| key | value | value range | required or not | default value | +| :------------------------------ | :----------------------------------------------------------- | :------------------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| sink | OPC UA SINK | String: opc-ua-sink | Required | | +| sink.opcua.model | OPC UA model used | String: client-server / pub-sub | Optional | pub-sub | +| sink.opcua.tcp.port | OPC UA's TCP port | Integer: [0, 65536] | Optional | 12686 | +| sink.opcua.https.port | OPC UA's HTTPS port | Integer: [0, 65536] | Optional | 8443 | | sink.opcua.security.dir | Directory for OPC UA's keys and certificates | String: Path, supports absolute and relative directories | Optional | Opc_security folder/in the conf directory of the DataNode related to iotdb
If there is no conf directory for iotdb (such as launching DataNode in IDEA), it will be the iotdb_opc_Security folder/in the user's home directory | -| sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | Optional | true | -| sink.user | User for OPC UA, specified in the configuration | String | Optional | root | -| sink.password | Password for OPC UA, specified in the configuration | String | Optional | root | +| sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | Optional | true | +| sink.user | User for OPC UA, specified in the configuration | String | Optional | root | +| sink.password | Password for OPC UA, specified in the configuration | String | Optional | TimechoDB@2021 //Before V2.0.6.x the default password is root | ### 2.3 Example @@ -104,7 +104,7 @@ create pipe p1 create pipe p1 with sink ('sink' = 'opc-ua-sink', 'sink.user' = 'root', - 'sink.password' = 'root'); + 'sink.password' = 'TimechoDB@2021' //Before V2.0.6.x the default password is root start pipe p1; ``` @@ -178,7 +178,7 @@ insert into root.test.db(time, s2) values(now(), 2) #### Preparation Work -The code is located in the [opc-ua-sink package](https://github.com/apache/iotdb/tree/master/example/pipe-opc-ua-sink/src/main/java/org/apache/iotdb/opcua) under the iotdb-example package. +The code is located in the [opc-ua-sink package](https://github.com/apache/iotdb/tree/rc/2.0.1/example/pipe-opc-ua-sink/src/main/java/org/apache/iotdb/opcua)under the iotdb-example package. The code includes: diff --git a/src/UserGuide/Master/Tree/API/Programming-Python-Native-API.md b/src/UserGuide/Master/Tree/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/UserGuide/Master/Tree/API/Programming-Python-Native-API.md rename to src/UserGuide/Master/Tree/API/Programming-Python-Native-API_apache.md diff --git a/src/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md b/src/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..8df2a7996 --- /dev/null +++ b/src/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,826 @@ + + +# Python Native API + +## 1. Requirements + +You have to install thrift (>=0.13) before using the package. + + + +## 2. How to use (Example) + +First, download the package: `pip3 install apache-iotdb>=2.0` + +You can get an example of using the package to read and write data at here:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_example.py) + +An example of aligned timeseries: [Aligned Timeseries Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_aligned_timeseries_example.py) + +(you need to add `import iotdb` in the head of the file) + +Or: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + +## 3. Initialization + +* Initialize a Session + +```python +session = Session( + ip="127.0.0.1", + port="6667", + user="root", + password="TimechoDB@2021", //Before V2.0.6.x the default password is root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* Initialize a Session to connect multiple nodes + +```python +session = Session.init_from_node_urls( + node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], + user="root", + password="TimechoDB@2021", //Before V2.0.6.x the default password is root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* Open a session, with a parameter to specify whether to enable RPC compression + +```python +session.open(enable_rpc_compression=False) +``` + +Notice: this RPC compression status of client must comply with that of IoTDB server + +* Close a Session + +```python +session.close() +``` + +## 4. Managing Session through SessionPool + +Utilizing SessionPool to manage sessions eliminates the need to worry about session reuse. When the number of session connections reaches the maximum capacity of the pool, requests for acquiring a session will be blocked, and you can set the blocking wait time through parameters. After using a session, it should be returned to the SessionPool using the `putBack` method for proper management. + +### 4.1 Create SessionPool + +```python +pool_config = PoolConfig(host=ip,port=port, user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 + +# # Create the connection pool +session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) +``` +### 4.2 Create a SessionPool using distributed nodes. +```python +pool_config = PoolConfig(node_urls=node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 +``` +### 4.3 Acquiring a session through SessionPool and manually calling PutBack after use + +```python +session = session_pool.get_session() +session.set_storage_group(STORAGE_GROUP_NAME) +session.create_time_series( + TIMESERIES_PATH, TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.SNAPPY +) +# After usage, return the session using putBack +session_pool.put_back(session) +# When closing the sessionPool, all managed sessions will be closed as well +session_pool.close() +``` +### 4.4 SSL Connection + +#### 4.4.1 Server Certificate Configuration + +In the `conf/iotdb-system.properties` configuration file, locate or add the following configuration items: + +```Java +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 4.4.2 Configure Python Client Certificate + +- Set `use_ssl` to True to enable SSL. +- Specify the client certificate path using the `ca_certs` parameter. + +```Java +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**Example Code: Using SSL to Connect to IoTDB** + +```Java +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 5. Data Definition Interface (DDL Interface) + +### 5.1 Database Management + +* CREATE DATABASE + +```python +session.set_storage_group(group_name) +``` + +* Delete one or several databases + +```python +session.delete_storage_group(group_name) +session.delete_storage_groups(group_name_lst) +``` +### 5.2 Timeseries Management + +* Create one or multiple timeseries + +```python +session.create_time_series(ts_path, data_type, encoding, compressor, + props=None, tags=None, attributes=None, alias=None) + +session.create_multi_time_series( + ts_path_lst, data_type_lst, encoding_lst, compressor_lst, + props_lst=None, tags_lst=None, attributes_lst=None, alias_lst=None +) +``` + +* Create aligned timeseries + +```python +session.create_aligned_time_series( + device_id, measurements_lst, data_type_lst, encoding_lst, compressor_lst +) +``` + +Attention: Alias of measurements are **not supported** currently. + +* Delete one or several timeseries + +```python +session.delete_time_series(paths_list) +``` + +* Check whether the specific timeseries exists + +```python +session.check_time_series_exists(path) +``` + +## 6. Data Manipulation Interface (DML Interface) + +### 6.1 Insert + +It is recommended to use insertTablet to help improve write efficiency. + +* Insert a Tablet,which is multiple rows of a device, each row has the same measurements + * **Better Write Performance** + * **Support null values**: fill the null value with any value, and then mark the null value via BitMap (from v0.13) + + +We have two implementations of Tablet in Python API. + +* Normal Tablet + +```python +values_ = [ + [False, 10, 11, 1.1, 10011.1, "test01"], + [True, 100, 11111, 1.25, 101.0, "test02"], + [False, 100, 1, 188.1, 688.25, "test03"], + [True, 0, 0, 0, 6.25, "test04"], +] +timestamps_ = [1, 2, 3, 4] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) + +values_ = [ + [None, 10, 11, 1.1, 10011.1, "test01"], + [True, None, 11111, 1.25, 101.0, "test02"], + [False, 100, None, 188.1, 688.25, "test03"], + [True, 0, 0, 0, None, None], +] +timestamps_ = [16, 17, 18, 19] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) +``` +* Numpy Tablet + +Comparing with Tablet, Numpy Tablet is using [numpy.ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) to record data. +With less memory footprint and time cost of serialization, the insert performance will be better. + +**Notice** +1. time and numerical value columns in Tablet is ndarray +2. recommended to use the specific dtypes to each ndarray, see the example below + (if not, the default dtypes are also ok). + +```python +import numpy as np +data_types_ = [ + TSDataType.BOOLEAN, + TSDataType.INT32, + TSDataType.INT64, + TSDataType.FLOAT, + TSDataType.DOUBLE, + TSDataType.TEXT, +] +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([1, 2, 3, 4], TSDataType.INT64.np_dtype()) +np_tablet_ = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_ +) +session.insert_tablet(np_tablet_) + +# insert one numpy tablet with None into the database. +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([98, 99, 100, 101], TSDataType.INT64.np_dtype()) +np_bitmaps_ = [] +for i in range(len(measurements_)): + np_bitmaps_.append(BitMap(len(np_timestamps_))) +np_bitmaps_[0].mark(0) +np_bitmaps_[1].mark(1) +np_bitmaps_[2].mark(2) +np_bitmaps_[4].mark(3) +np_bitmaps_[5].mark(3) +np_tablet_with_none = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_, np_bitmaps_ +) +session.insert_tablet(np_tablet_with_none) +``` + +* Insert multiple Tablets + +```python +session.insert_tablets(tablet_lst) +``` + +* Insert a Record + +```python +session.insert_record(device_id, timestamp, measurements_, data_types_, values_) +``` + +* Insert multiple Records + +```python +session.insert_records( + device_ids_, time_list_, measurements_list_, data_type_list_, values_list_ +) +``` + +* Insert multiple Records that belong to the same device. + With type info the server has no need to do type inference, which leads a better performance + + +```python +session.insert_records_of_one_device(device_id, time_list, measurements_list, data_types_list, values_list) +``` + +### 6.2 Insert with type inference + +When the data is of String type, we can use the following interface to perform type inference based on the value of the value itself. For example, if value is "true" , it can be automatically inferred to be a boolean type. If value is "3.2" , it can be automatically inferred as a flout type. Without type information, server has to do type inference, which may cost some time. + +* Insert a Record, which contains multiple measurement value of a device at a timestamp + +```python +session.insert_str_record(device_id, timestamp, measurements, string_values) +``` + +### 6.3 Insert of Aligned Timeseries + +The Insert of aligned timeseries uses interfaces like insert_aligned_XXX, and others are similar to the above interfaces: + +* insert_aligned_record +* insert_aligned_records +* insert_aligned_records_of_one_device +* insert_aligned_tablet +* insert_aligned_tablets + + +## 7. IoTDB-SQL Interface + +* Execute query statement + +```python +session.execute_query_statement(sql) +``` + +* Execute non query statement + +```python +session.execute_non_query_statement(sql) +``` + +* Execute statement + +```python +session.execute_statement(sql) +``` + +## 8. Schema Template +### 8.1 Create Schema Template +The step for creating a metadata template is as follows +1. Create the template class +2. Adding MeasurementNode +3. Execute create schema template function + +```python +template = Template(name=template_name, share_time=True) + +m_node_x = MeasurementNode("x", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_y = MeasurementNode("y", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_z = MeasurementNode("z", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) + +template.add_template(m_node_x) +template.add_template(m_node_y) +template.add_template(m_node_z) + +session.create_schema_template(template) +``` +### 8.2 Modify Schema Template measurements +Modify measurements in a template, the template must be already created. These are functions that add or delete some measurement nodes. +* add node in template +```python +session.add_measurements_in_template(template_name, measurements_path, data_types, encodings, compressors, is_aligned) +``` + +* delete node in template +```python +session.delete_node_in_template(template_name, path) +``` + +### 8.3 Set Schema Template +```python +session.set_schema_template(template_name, prefix_path) +``` + +### 8.4 Uset Schema Template +```python +session.unset_schema_template(template_name, prefix_path) +``` + +### 8.5 Show Schema Template +* Show all schema templates +```python +session.show_all_templates() +``` +* Count all measurements in templates +```python +session.count_measurements_in_template(template_name) +``` + +* Judge whether the path is measurement or not in templates, This measurement must be in the template +```python +session.count_measurements_in_template(template_name, path) +``` + +* Judge whether the path is exist or not in templates, This path may not belong to the template +```python +session.is_path_exist_in_template(template_name, path) +``` + +* Show nodes under in schema template +```python +session.show_measurements_in_template(template_name) +``` + +* Show the path prefix where a schema template is set +```python +session.show_paths_template_set_on(template_name) +``` + +* Show the path prefix where a schema template is used (i.e. the time series has been created) +```python +session.show_paths_template_using_on(template_name) +``` + +### 8.6 Drop Schema Template +Delete an existing metadata template,dropping an already set template is not supported +```python +session.drop_schema_template("template_python") +``` + + +## 9. Pandas Support + +To easily transform a query result to a [Pandas Dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) +the SessionDataSet has a method `.todf()` which consumes the dataset and transforms it to a pandas dataframe. + +Example: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +result = session.execute_query_statement("SELECT * FROM root.*") + +# Transform to Pandas Dataset +df = result.todf() + +session.close() + +# Now you can work with the dataframe +df = ... +``` + + +## 10. IoTDB Testcontainer + +The Test Support is based on the lib `testcontainers` (https://testcontainers-python.readthedocs.io/en/latest/index.html) which you need to install in your project if you want to use the feature. + +To start (and stop) an IoTDB Database in a Docker container simply do: +```python +class MyTestCase(unittest.TestCase): + + def test_something(self): + with IoTDBContainer() as c: + session = Session("localhost", c.get_exposed_port(6667), "root", "TimechoDB@2021") //Before V2.0.6.x the default password is root + session.open(False) + result = session.execute_query_statement("SHOW TIMESERIES") + print(result) + session.close() +``` + +by default it will load the image `apache/iotdb:latest`, if you want a specific version just pass it like e.g. `IoTDBContainer("apache/iotdb:0.12.0")` to get version `0.12.0` running. + +## 11. IoTDB DBAPI + +IoTDB DBAPI implements the Python DB API 2.0 specification (https://peps.python.org/pep-0249/), which defines a common +interface for accessing databases in Python. + +### 11.1 Examples ++ Initialization + +The initialized parameters are consistent with the session part (except for the sqlalchemy_mode). +```python +from iotdb.dbapi import connect + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +conn = connect(ip, port_, username_, password_,fetch_size=1024,zone_id="UTC+8",sqlalchemy_mode=False) +cursor = conn.cursor() +``` ++ simple SQL statement execution +```python +cursor.execute("SELECT ** FROM root") +for row in cursor.fetchall(): + print(row) +``` + ++ execute SQL with parameter + +IoTDB DBAPI supports pyformat style parameters +```python +cursor.execute("SELECT ** FROM root WHERE time < %(time)s",{"time":"2017-11-01T00:08:00.000"}) +for row in cursor.fetchall(): + print(row) +``` + ++ execute SQL with parameter sequences +```python +seq_of_parameters = [ + {"timestamp": 1, "temperature": 1}, + {"timestamp": 2, "temperature": 2}, + {"timestamp": 3, "temperature": 3}, + {"timestamp": 4, "temperature": 4}, + {"timestamp": 5, "temperature": 5}, +] +sql = "insert into root.cursor(timestamp,temperature) values(%(timestamp)s,%(temperature)s)" +cursor.executemany(sql,seq_of_parameters) +``` + ++ close the connection and cursor +```python +cursor.close() +conn.close() +``` + +## 12. IoTDB SQLAlchemy Dialect (Experimental) +The SQLAlchemy dialect of IoTDB is written to adapt to Apache Superset. +This part is still being improved. +Please do not use it in the production environment! +### 12.1 Mapping of the metadata +The data model used by SQLAlchemy is a relational data model, which describes the relationships between different entities through tables. +While the data model of IoTDB is a hierarchical data model, which organizes the data through a tree structure. +In order to adapt IoTDB to the dialect of SQLAlchemy, the original data model in IoTDB needs to be reorganized. +Converting the data model of IoTDB into the data model of SQLAlchemy. + +The metadata in the IoTDB are: + +1. Database +2. Path +3. Entity +4. Measurement + +The metadata in the SQLAlchemy are: +1. Schema +2. Table +3. Column + +The mapping relationship between them is: + +| The metadata in the SQLAlchemy | The metadata in the IoTDB | +| -------------------- | -------------------------------------------- | +| Schema | Database | +| Table | Path ( from database to entity ) + Entity | +| Column | Measurement | + +The following figure shows the relationship between the two more intuitively: + +![sqlalchemy-to-iotdb](/img/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true) + +### 12.2 Data type mapping +| data type in IoTDB | data type in SQLAlchemy | +|--------------------|-------------------------| +| BOOLEAN | Boolean | +| INT32 | Integer | +| INT64 | BigInteger | +| FLOAT | Float | +| DOUBLE | Float | +| TEXT | Text | +| LONG | BigInteger | + +### 12.3 Example + ++ execute statement + +```python +from sqlalchemy import create_engine + +engine = create_engine("iotdb://root:root@127.0.0.1:6667") +connect = engine.connect() +result = connect.execute("SELECT ** FROM root") +for row in result.fetchall(): + print(row) +``` + ++ ORM (now only simple queries are supported) + +```python +from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +metadata = MetaData( + schema='root.factory' +) +Base = declarative_base(metadata=metadata) + + +class Device(Base): + __tablename__ = "room2.device1" + Time = Column(BigInteger, primary_key=True) + temperature = Column(Float) + status = Column(Float) + + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //Before V2.0.6.x the default password is root + +DbSession = sessionmaker(bind=engine) +session = DbSession() + +res = session.query(Device.status).filter(Device.temperature > 1) + +for row in res: + print(row) +``` + + +## 13. Developers + +### 13.1 Introduction + +This is an example of how to connect to IoTDB with python, using the thrift rpc interfaces. Things are almost the same on Windows or Linux, but pay attention to the difference like path separator. + + + +### 13.2 Prerequisites + +Python3.7 or later is preferred. + +You have to install Thrift (0.11.0 or later) to compile our thrift file into python code. Below is the official tutorial of installation, eventually, you should have a thrift executable. + +``` +http://thrift.apache.org/docs/install/ +``` + +Before starting you need to install `requirements_dev.txt` in your python environment, e.g. by calling +```shell +pip install -r requirements_dev.txt +``` + + + +### 13.3 Compile the thrift library and Debug + +In the root of IoTDB's source code folder, run `mvn clean generate-sources -pl iotdb-client/client-py -am`. + +This will automatically delete and repopulate the folder `iotdb/thrift` with the generated thrift files. +This folder is ignored from git and should **never be pushed to git!** + +**Notice** Do not upload `iotdb/thrift` to the git repo. + + + + +### 13.4 Session Client & Example + +We packed up the Thrift interface in `client-py/src/iotdb/Session.py` (similar with its Java counterpart), also provided an example file `client-py/src/SessionExample.py` of how to use the session module. please read it carefully. + + +Or, another simple example: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + + + +### 13.5 Tests + +Please add your custom tests in `tests` folder. + +To run all defined tests just type `pytest .` in the root folder. + +**Notice** Some tests need docker to be started on your system as a test instance is started in a docker container using [testcontainers](https://testcontainers-python.readthedocs.io/en/latest/index.html). + + + +### 13.6 Futher Tools + +[black](https://pypi.org/project/black/) and [flake8](https://pypi.org/project/flake8/) are installed for autoformatting and linting. +Both can be run by `black .` or `flake8 .` respectively. + + + +## 14. Releasing + +To do a release just ensure that you have the right set of generated thrift files. +Then run linting and auto-formatting. +Then, ensure that all tests work (via `pytest .`). +Then you are good to go to do a release! + + + +### 14.1 Preparing your environment + +First, install all necessary dev dependencies via `pip install -r requirements_dev.txt`. + + + +### 14.2 Doing the Release + +There is a convenient script `release.sh` to do all steps for a release. +Namely, these are + +* Remove all transient directories from last release (if exists) +* (Re-)generate all generated sources via mvn +* Run Linting (flake8) +* Run Tests via pytest +* Build +* Release to pypi + diff --git a/src/UserGuide/Master/Tree/API/RestServiceV1.md b/src/UserGuide/Master/Tree/API/RestServiceV1_apache.md similarity index 100% rename from src/UserGuide/Master/Tree/API/RestServiceV1.md rename to src/UserGuide/Master/Tree/API/RestServiceV1_apache.md diff --git a/src/UserGuide/Master/Tree/API/RestServiceV1_timecho.md b/src/UserGuide/Master/Tree/API/RestServiceV1_timecho.md new file mode 100644 index 000000000..a10bacce8 --- /dev/null +++ b/src/UserGuide/Master/Tree/API/RestServiceV1_timecho.md @@ -0,0 +1,924 @@ + + +# REST API V1(Not Recommend) +IoTDB's RESTful services can be used for query, write, and management operations, using the OpenAPI standard to define interfaces and generate frameworks. + +## 1. Enable RESTful Services + +RESTful services are disabled by default. + + Find the `conf/conf/iotdb-system.properties` file under the IoTDB installation directory and set `enable_rest_service` to `true` to enable the module. + + ```properties + enable_rest_service=true + ``` + +## 2. Authentication +Except the liveness probe API `/ping`, RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`. + +The username used in the following examples is: `root`, and password is: `TimechoDB@2021` //Before V2.0.6.x the default password is root. + +And the authorization header is + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- If a user authorized with incorrect username or password, the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- If the `Authorization` header is missing,the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. Interface + +### 3.1 ping + +The `/ping` API can be used for service liveness probing. + +Request method: `GET` + +Request path: `http://ip:port/ping` + +The user name used in the example is: root, password: root + +Example request: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +Response status codes: + +- `200`: The service is alive. +- `503`: The service cannot accept any requests now. + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +|code | integer | status code | +| message | string | message | + +Sample response: + +- With HTTP status code `200`: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- With HTTP status code `503`: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` can be accessed without authorization. + +### 3.2 query + +The query interface can be used to handle data queries and metadata queries. + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/query` + +Parameter Description: + +| parameter name | parameter type | required | parameter description | +|----------------| -------------- | -------- | ------------------------------------------------------------ | +| sql | string | yes | | +| rowLimit | integer | no | The maximum number of rows in the result set that can be returned by a query.
If this parameter is not set, the `rest_query_default_row_size_limit` of the configuration file will be used as the default value.
When the number of rows in the returned result set exceeds the limit, the status code `411` will be returned. | + +Response parameters: + +| parameter name | parameter type | parameter description | +|----------------| -------------- | ------------------------------------------------------------ | +| expressions | array | Array of result set column names for data query, `null` for metadata query | +| columnNames | array | Array of column names for metadata query result set, `null` for data query | +| timestamps | array | Timestamp column, `null` for metadata query | +| values | array | A two-dimensional array, the first dimension has the same length as the result set column name array, and the second dimension array represents a column of the result set | + +**Examples:** + +Tip: Statements like `select * from root.xx.**` are not recommended because those statements may cause OOM. + +**Expression query** + + ```shell + curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v1/query + ```` +Response instance + ```json + { + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] + } + ``` + +**Show child paths** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +**Show child nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +**Show all ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +**Show ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +**Show functions** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +**Show timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Show latest timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Count timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Count nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Show devices** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**Show devices with database** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**List user** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +**Aggregation** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +**Group by level** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +**Group by** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +**Last** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +**Disable align** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +**Align by device** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +**Select into** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/nonQuery` + +Parameter Description: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| sql | string | query content | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v1/nonQuery +``` + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/insertTablet` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:---------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements | array | yes | The name of the measuring point | +| dataTypes | array | yes | The data type | +| values | array | yes | Value columns, the values in each column can be `null` | +| isAligned | boolean | yes | Whether to align the timeseries | +| deviceId | string | yes | Device name | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"dataTypes":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"isAligned":false,"deviceId":"root.sg27"}' http://127.0.0.1:18080/rest/v1/insertTablet +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +## 4. Configuration + +The configuration is located in 'iotdb-system.properties'. + +* Set 'enable_rest_service' to 'true' to enable the module, and 'false' to disable the module. By default, this value is' false '. + +```properties +enable_rest_service=true +``` + +* This parameter is valid only when 'enable_REST_service =true'. Set 'rest_service_port' to a number (1025 to 65535) to customize the REST service socket port. By default, the value is 18080. + +```properties +rest_service_port=18080 +``` + +* Set 'enable_swagger' to 'true' to display rest service interface information through swagger, and 'false' to do not display the rest service interface information through the swagger. By default, this value is' false '. + +```properties +enable_swagger=false +``` + +* The maximum number of rows in the result set that can be returned by a query. When the number of rows in the returned result set exceeds the limit, the status code `411` is returned. + +````properties +rest_query_default_row_size_limit=10000 +```` + +* Expiration time for caching customer login information (used to speed up user authentication, in seconds, 8 hours by default) + +```properties +cache_expire=28800 +``` + + +* Maximum number of users stored in the cache (default: 100) + +```properties +cache_max_num=100 +``` + +* Initial cache size (default: 10) + +```properties +cache_init_num=10 +``` + +* REST Service whether to enable SSL configuration, set 'enable_https' to' true 'to enable the module, and set' false 'to disable the module. By default, this value is' false '. + +```properties +enable_https=false +``` + +* keyStore location path (optional) + +```properties +key_store_path= +``` + + +* keyStore password (optional) + +```properties +key_store_pwd= +``` + + +* trustStore location path (optional) + +```properties +trust_store_path= +``` + +* trustStore password (optional) + +```properties +trust_store_pwd= +``` + + +* SSL timeout period, in seconds + +```properties +idle_timeout=5000 +``` diff --git a/src/UserGuide/Master/Tree/API/RestServiceV2.md b/src/UserGuide/Master/Tree/API/RestServiceV2_apache.md similarity index 100% rename from src/UserGuide/Master/Tree/API/RestServiceV2.md rename to src/UserGuide/Master/Tree/API/RestServiceV2_apache.md diff --git a/src/UserGuide/Master/Tree/API/RestServiceV2_timecho.md b/src/UserGuide/Master/Tree/API/RestServiceV2_timecho.md new file mode 100644 index 000000000..43173a3dc --- /dev/null +++ b/src/UserGuide/Master/Tree/API/RestServiceV2_timecho.md @@ -0,0 +1,964 @@ + + +# REST API V2 +IoTDB's RESTful services can be used for query, write, and management operations, using the OpenAPI standard to define interfaces and generate frameworks. + +## 1. Enable RESTful Services + +RESTful services are disabled by default. + + Find the `conf/iotdb-system.properties` file under the IoTDB installation directory and set `enable_rest_service` to `true` to enable the module. + + ```properties + enable_rest_service=true + ``` + +## 2. Authentication +Except the liveness probe API `/ping`, RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`. + +The username used in the following examples is: `root`, and password is: `TimechoDB@2021` //Before V2.0.6.x the default password is root. + +And the authorization header is + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- If a user authorized with incorrect username or password, the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- If the `Authorization` header is missing,the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. Interface + +### 3.1 ping + +The `/ping` API can be used for service liveness probing. + +Request method: `GET` + +Request path: `http://ip:port/ping` + +The user name used in the example is: root, password: root + +Example request: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +Response status codes: + +- `200`: The service is alive. +- `503`: The service cannot accept any requests now. + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +|code | integer | status code | +| message | string | message | + +Sample response: + +- With HTTP status code `200`: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- With HTTP status code `503`: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` can be accessed without authorization. + +### 3.2 query + +The query interface can be used to handle data queries and metadata queries. + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/query` + +Parameter Description: + +| parameter name | parameter type | required | parameter description | +|----------------| -------------- | -------- | ------------------------------------------------------------ | +| sql | string | yes | | +| row_limit | integer | no | The maximum number of rows in the result set that can be returned by a query.
If this parameter is not set, the `rest_query_default_row_size_limit` of the configuration file will be used as the default value.
When the number of rows in the returned result set exceeds the limit, the status code `411` will be returned. | + +Response parameters: + +| parameter name | parameter type | parameter description | +|----------------| -------------- | ------------------------------------------------------------ | +| expressions | array | Array of result set column names for data query, `null` for metadata query | +| column_names | array | Array of column names for metadata query result set, `null` for data query | +| timestamps | array | Timestamp column, `null` for metadata query | +| values | array | A two-dimensional array, the first dimension has the same length as the result set column name array, and the second dimension array represents a column of the result set | + +**Examples:** + +Tip: Statements like `select * from root.xx.**` are not recommended because those statements may cause OOM. + +**Expression query** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v2/query +```` + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +**Show child paths** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +**Show child nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +**Show all ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +**Show ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +**Show functions** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +**Show timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Show latest timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Count timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Count nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Show devices** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**Show devices with database** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**List user** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +**Aggregation** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +**Group by level** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +**Group by** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +**Last** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +**Disable align** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +**Align by device** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +**Select into** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/nonQuery` + +Parameter Description: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| sql | string | query content | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v2/nonQuery +``` + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/insertTablet` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:---------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements | array | yes | The name of the measuring point | +| data_types | array | yes | The data type | +| values | array | yes | Value columns, the values in each column can be `null` | +| is_aligned | boolean | yes | Whether to align the timeseries | +| device | string | yes | Device name | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"data_types":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"is_aligned":false,"device":"root.sg27"}' http://127.0.0.1:18080/rest/v2/insertTablet +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +### 3.5 insertRecords + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/insertRecords` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:------------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements_list | array | yes | The name of the measuring point | +| data_types_list | array | yes | The data type | +| values_list | array | yes | Value columns, the values in each column can be `null` | +| devices | string | yes | Device name | +| is_aligned | boolean | yes | Whether to align the timeseries | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232113960,1635232151960,1635232143960,1635232143960],"measurements_list":[["s33","s44"],["s55","s66"],["s77","s88"],["s771","s881"]],"data_types_list":[["INT32","INT64"],["FLOAT","DOUBLE"],["FLOAT","DOUBLE"],["BOOLEAN","TEXT"]],"values_list":[[1,11],[2.1,2],[4,6],[false,"cccccc"]],"is_aligned":false,"devices":["root.s1","root.s1","root.s1","root.s3"]}' http://127.0.0.1:18080/rest/v2/insertRecords +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. Configuration + +The configuration is located in 'iotdb-system.properties'. + +* Set 'enable_rest_service' to 'true' to enable the module, and 'false' to disable the module. By default, this value is' false '. + +```properties +enable_rest_service=true +``` + +* This parameter is valid only when 'enable_REST_service =true'. Set 'rest_service_port' to a number (1025 to 65535) to customize the REST service socket port. By default, the value is 18080. + +```properties +rest_service_port=18080 +``` + +* Set 'enable_swagger' to 'true' to display rest service interface information through swagger, and 'false' to do not display the rest service interface information through the swagger. By default, this value is' false '. + +```properties +enable_swagger=false +``` + +* The maximum number of rows in the result set that can be returned by a query. When the number of rows in the returned result set exceeds the limit, the status code `411` is returned. + +````properties +rest_query_default_row_size_limit=10000 +```` + +* Expiration time for caching customer login information (used to speed up user authentication, in seconds, 8 hours by default) + +```properties +cache_expire=28800 +``` + + +* Maximum number of users stored in the cache (default: 100) + +```properties +cache_max_num=100 +``` + +* Initial cache size (default: 10) + +```properties +cache_init_num=10 +``` + +* REST Service whether to enable SSL configuration, set 'enable_https' to' true 'to enable the module, and set' false 'to disable the module. By default, this value is' false '. + +```properties +enable_https=false +``` + +* keyStore location path (optional) + +```properties +key_store_path= +``` + + +* keyStore password (optional) + +```properties +key_store_pwd= +``` + + +* trustStore location path (optional) + +```properties +trust_store_path= +``` + +* trustStore password (optional) + +```properties +trust_store_pwd= +``` + + +* SSL timeout period, in seconds + +```properties +idle_timeout=5000 +``` diff --git a/src/UserGuide/Master/Tree/Background-knowledge/Data-Type.md b/src/UserGuide/Master/Tree/Background-knowledge/Data-Type.md index 2fbb63040..ebd76e579 100644 --- a/src/UserGuide/Master/Tree/Background-knowledge/Data-Type.md +++ b/src/UserGuide/Master/Tree/Background-knowledge/Data-Type.md @@ -40,7 +40,7 @@ The difference between STRING and TEXT types is that STRING type has more statis ### 1.1 Float Precision -The time series of **FLOAT** and **DOUBLE** type can specify (MAX\_POINT\_NUMBER, see [this page](../SQL-Manual/SQL-Manual.md) for more information on how to specify), which is the number of digits after the decimal point of the floating point number, if the encoding method is [RLE](../Technical-Insider/Encoding-and-Compression.md) or [TS\_2DIFF](../Technical-Insider/Encoding-and-Compression.md). If MAX\_POINT\_NUMBER is not specified, the system will use [float\_precision](../Reference/DataNode-Config-Manual.md) in the configuration file `iotdb-system.properties`. +The time series of **FLOAT** and **DOUBLE** type can specify (MAX\_POINT\_NUMBER, see [this page](../SQL-Manual/SQL-Manual_timecho) for more information on how to specify), which is the number of digits after the decimal point of the floating point number, if the encoding method is [RLE](../Technical-Insider/Encoding-and-Compression.md) or [TS\_2DIFF](../Technical-Insider/Encoding-and-Compression.md). If MAX\_POINT\_NUMBER is not specified, the system will use [float\_precision](../Reference/DataNode-Config-Manual.md) in the configuration file `iotdb-system.properties`. ```sql CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=FLOAT, ENCODING=RLE, 'MAX_POINT_NUMBER'='2'; diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Delete-Data.md b/src/UserGuide/Master/Tree/Basic-Concept/Delete-Data.md index 2fa82332c..8c4d883c4 100644 --- a/src/UserGuide/Master/Tree/Basic-Concept/Delete-Data.md +++ b/src/UserGuide/Master/Tree/Basic-Concept/Delete-Data.md @@ -20,9 +20,9 @@ --> # Delete Data -Users can delete data that meet the deletion condition in the specified timeseries by using the [DELETE statement](../SQL-Manual/SQL-Manual.md#delete-data). When deleting data, users can select one or more timeseries paths, prefix paths, or paths with star to delete data within a certain time interval. +Users can delete data that meet the deletion condition in the specified timeseries by using the DELETE statement. When deleting data, users can select one or more timeseries paths, prefix paths, or paths with star to delete data within a certain time interval. -In a JAVA programming environment, you can use the [Java JDBC](../API/Programming-JDBC.md) to execute single or batch UPDATE statements. +In a JAVA programming environment, you can use the Java JDBC to execute single or batch UPDATE statements. ## 1. Delete Single Timeseries diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_apache.md b/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_apache.md index 7d590ad24..d4c6e51dd 100644 --- a/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_apache.md +++ b/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_apache.md @@ -57,7 +57,7 @@ Besides, if deploy on Windows system, the LayerName is case-insensitive, which m ### 1.2 Show Databases -After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual.md) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual.md) to view the databases. The SQL statements are as follows: +After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual_apache) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual_apache) to view the databases. The SQL statements are as follows: ``` IoTDB> SHOW DATABASES diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_timecho.md b/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_timecho.md index 94598c1c0..8d8740b97 100644 --- a/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_timecho.md +++ b/src/UserGuide/Master/Tree/Basic-Concept/Operate-Metadata_timecho.md @@ -57,7 +57,7 @@ Besides, if deploy on Windows system, the LayerName is case-insensitive, which m ### 1.2 Show Databases -After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual.md) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual.md) to view the databases. The SQL statements are as follows: +After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual_timecho) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual_timecho) to view the databases. The SQL statements are as follows: ``` IoTDB> SHOW DATABASES diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Query-Data.md b/src/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/Basic-Concept/Query-Data.md rename to src/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md index f020821f0..7a0b65600 100644 --- a/src/UserGuide/Master/Tree/Basic-Concept/Query-Data.md +++ b/src/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md @@ -277,7 +277,7 @@ Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C+ - Execute the query statement in the SQL command line terminal: start the SQL command line terminal, and directly enter the query statement to execute, see [SQL command line terminal](../Tools-System/CLI.md). -- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC.md) for details. +- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC_apache) for details. - Execute query statements in native APIs such as JAVA / C++ / Python / Go. For details, please refer to the relevant documentation in the Application Programming Interface chapter. The interface prototype is as follows: @@ -285,7 +285,7 @@ Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C+ SessionDataSet executeQueryStatement(String sql) ```` -- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1.md) or [HTTP API V2](../API/RestServiceV2.md) for details. +- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1_apache) or [HTTP API V2](../API/RestServiceV2_apache) for details. #### Efficient execution interfaces @@ -440,6 +440,7 @@ Total line number = 1 It costs 0.021s ``` + ## 3. `WHERE` CLAUSE In IoTDB query statements, two filter conditions, **time filter** and **value filter**, are supported. @@ -3015,7 +3016,7 @@ The user must have the following permissions to execute a query write-back state * All `WRITE_SCHEMA` permissions for the source series in the `select` clause. * All `WRITE_DATA` permissions for the target series in the `into` clause. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_apache). ### 10.4 Configurable Properties diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md b/src/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md new file mode 100644 index 000000000..6e4b8135c --- /dev/null +++ b/src/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md @@ -0,0 +1,3023 @@ + +# Query Data +## 1. OVERVIEW + +### 1.1 Syntax Definition + +In IoTDB, `SELECT` statement is used to retrieve data from one or more selected time series. Here is the syntax definition of `SELECT` statement: + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... ) | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires that the status and temperature sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.018s +``` + +#### Select Multiple Columns of Data for the Same Device According to Multiple Time Intervals + +IoTDB supports specifying multiple time interval conditions in a query. Users can combine time interval conditions at will according to their needs. For example, the SQL statement is: + +```sql +select status,temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature"; the statement specifies two different time intervals, namely "2017-11-01T00:05:00.000 to 2017-11-01T00:12:00.000" and "2017-11-01T16:35:00.000 to 2017-11-01T16:37:00.000". The SQL statement requires that the values of selected timeseries satisfying any time interval be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| +|2017-11-01T16:35:00.000+08:00| true| 23.44| +|2017-11-01T16:36:00.000+08:00| false| 21.98| +|2017-11-01T16:37:00.000+08:00| false| 21.93| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 9 +It costs 0.018s +``` + + +#### Choose Multiple Columns of Data for Different Devices According to Multiple Time Intervals + +The system supports the selection of data in any column in a query, i.e., the selected columns can come from different devices. For example, the SQL statement is: + +```sql +select wf01.wt01.status,wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +which means: + +The selected timeseries are "the power supply status of ln group wf01 plant wt01 device" and "the hardware version of ln group wf02 plant wt02 device"; the statement specifies two different time intervals, namely "2017-11-01T00:05:00.000 to 2017-11-01T00:12:00.000" and "2017-11-01T16:35:00.000 to 2017-11-01T16:37:00.000". The SQL statement requires that the values of selected timeseries satisfying any time interval be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+--------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf02.wt02.hardware| ++-----------------------------+------------------------+--------------------------+ +|2017-11-01T00:06:00.000+08:00| false| v1| +|2017-11-01T00:07:00.000+08:00| false| v1| +|2017-11-01T00:08:00.000+08:00| false| v1| +|2017-11-01T00:09:00.000+08:00| false| v1| +|2017-11-01T00:10:00.000+08:00| true| v2| +|2017-11-01T00:11:00.000+08:00| false| v1| +|2017-11-01T16:35:00.000+08:00| true| v2| +|2017-11-01T16:36:00.000+08:00| false| v1| +|2017-11-01T16:37:00.000+08:00| false| v1| ++-----------------------------+------------------------+--------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### Order By Time Query + +IoTDB supports the 'order by time' statement since 0.11, it's used to display results in descending order by time. +For example, the SQL statement is: + +```sql +select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-07T23:59:00.000+08:00| v1| false| 21.07| false| +|2017-11-07T23:58:00.000+08:00| v1| false| 22.93| false| +|2017-11-07T23:57:00.000+08:00| v2| true| 24.39| true| +|2017-11-07T23:56:00.000+08:00| v2| true| 24.44| true| +|2017-11-07T23:55:00.000+08:00| v2| true| 25.9| true| +|2017-11-07T23:54:00.000+08:00| v1| false| 22.52| false| +|2017-11-07T23:53:00.000+08:00| v2| true| 24.58| true| +|2017-11-07T23:52:00.000+08:00| v1| false| 20.18| false| +|2017-11-07T23:51:00.000+08:00| v1| false| 22.24| false| +|2017-11-07T23:50:00.000+08:00| v2| true| 23.7| true| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.016s +``` + +### 1.4 Execution Interface + +In IoTDB, there are two ways to execute data query: + +- Execute queries using IoTDB-SQL. +- Efficient execution interfaces for common queries, including time-series raw data query, last query, and aggregation query. + +#### Execute queries using IoTDB-SQL + +Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C++ / Python / Go and other native APIs, and RESTful APIs. + +- Execute the query statement in the SQL command line terminal: start the SQL command line terminal, and directly enter the query statement to execute, see [SQL command line terminal](../Tools-System/CLI.md). + +- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC_timecho) for details. + +- Execute query statements in native APIs such as JAVA / C++ / Python / Go. For details, please refer to the relevant documentation in the Application Programming Interface chapter. The interface prototype is as follows: + + ````java + SessionDataSet executeQueryStatement(String sql) + ```` + +- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1_timecho) or [HTTP API V2](../API/RestServiceV2_timecho) for details. + +#### Efficient execution interfaces + +The native APIs provide efficient execution interfaces for commonly used queries, which can save time-consuming operations such as SQL parsing. include: + +* Time-series raw data query with time range: + - The specified query time range is a left-closed right-open interval, including the start time but excluding the end time. + +```java +SessionDataSet executeRawDataQuery(List paths, long startTime, long endTime); +``` + +* Last query: + - Query the last data, whose timestamp is greater than or equal LastTime. + +```java +SessionDataSet executeLastDataQuery(List paths, long LastTime); +``` + +* Aggregation query: + - Support specified query time range: The specified query time range is a left-closed right-open interval, including the start time but not the end time. + - Support GROUP BY TIME. + +```java +SessionDataSet executeAggregationQuery(List paths, List aggregations); + +SessionDataSet executeAggregationQuery( + List paths, List aggregations, long startTime, long endTime); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval, + long slidingStep); +``` + +## 2. `SELECT` CLAUSE +The `SELECT` clause specifies the output of the query, consisting of several `selectExpr`. Each `selectExpr` defines one or more columns in the query result. For select expression details, see document [Operator-and-Expression](../SQL-Manual/Operator-and-Expression.md). + +- Example 1: + +```sql +select temperature from root.ln.wf01.wt01 +``` + +- Example 2: + +```sql +select status, temperature from root.ln.wf01.wt01 +``` + +### 2.1 Last Query + +The last query is a special type of query in Apache IoTDB. It returns the data point with the largest timestamp of the specified time series. In other word, it returns the latest state of a time series. This feature is especially important in IoT data analysis scenarios. To meet the performance requirement of real-time device monitoring systems, Apache IoTDB caches the latest values of all time series to achieve microsecond read latency. + +The last query is to return the most recent data point of the given timeseries in a three column format. + +The SQL syntax is defined as: + +```sql +select last [COMMA ]* from < PrefixPath > [COMMA < PrefixPath >]* [ORDER BY TIMESERIES (DESC | ASC)?] +``` + +which means: Query and return the last data points of timeseries prefixPath.path. + +- Only time filter is supported in \. Any other filters given in the \ will give an exception. When the cached most recent data point does not satisfy the criterion specified by the filter, IoTDB will have to get the result from the external storage, which may cause a decrease in performance. + +- The result will be returned in a four column table format. + + ``` + | Time | timeseries | value | dataType | + ``` + + **Note:** The `value` colum will always return the value as `string` and thus also has `TSDataType.TEXT`. Therefore, the column `dataType` is returned also which contains the _real_ type how the value should be interpreted. + +- We can use `TIME/TIMESERIES/VALUE/DATATYPE (DESC | ASC)` to specify that the result set is sorted in descending/ascending order based on a particular column. When the value column contains multiple types of data, the sorting is based on the string representation of the values. + +**Example 1:** get the last point of root.ln.wf01.wt01.status: + +``` +IoTDB> select last status from root.ln.wf01.wt01 ++-----------------------------+------------------------+-----+--------+ +| Time| timeseries|value|dataType| ++-----------------------------+------------------------+-----+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.status|false| BOOLEAN| ++-----------------------------+------------------------+-----+--------+ +Total line number = 1 +It costs 0.000s +``` + +**Example 2:** get the last status and temperature points of root.ln.wf01.wt01, whose timestamp larger or equal to 2017-11-07T23:50:00。 + +``` +IoTDB> select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 3:** get the last points of all sensor in root.ln.wf01.wt01, and order the result by the timeseries column in descending order + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by timeseries desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 4:** get the last points of all sensor in root.ln.wf01.wt01, and order the result by the dataType column in descending order + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by dataType desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Note:** The requirement to query the latest data point with other filtering conditions can be implemented through function composition. For example: + +``` +IoTDB> select max_time(*), last_value(*) from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 and status = false align by device ++-----------------+---------------------+----------------+-----------------------+------------------+ +| Device|max_time(temperature)|max_time(status)|last_value(temperature)|last_value(status)| ++-----------------+---------------------+----------------+-----------------------+------------------+ +|root.ln.wf01.wt01| 1510077540000| 1510077540000| 21.067368| false| ++-----------------+---------------------+----------------+-----------------------+------------------+ +Total line number = 1 +It costs 0.021s +``` + + +## 3. `WHERE` CLAUSE + +In IoTDB query statements, two filter conditions, **time filter** and **value filter**, are supported. + +The supported operators are as follows: + +- Comparison operators: greater than (`>`), greater than or equal ( `>=`), equal ( `=` or `==`), not equal ( `!=` or `<>`), less than or equal ( `<=`), less than ( `<`). +- Logical operators: and ( `AND` or `&` or `&&`), or ( `OR` or `|` or `||`), not ( `NOT` or `!`). +- Range contains operator: contains ( `IN` ). +- String matches operator: `LIKE`, `REGEXP`. + +### 3.1 Time Filter + +Use time filters to filter data for a specific time range. For supported formats of timestamps, please refer to [Timestamp](../Background-knowledge/Data-Type.md) . + +An example is as follows: + +1. Select data with timestamp greater than 2022-01-01T00:05:00.000: + + ```sql + select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; + ```` + +2. Select data with timestamp equal to 2022-01-01T00:05:00.000: + + ```sql + select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; + ```` + +3. Select the data in the time interval [2017-11-01T00:05:00.000, 2017-11-01T00:12:00.000): + + ```sql + select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; + ```` + +Note: In the above example, `time` can also be written as `timestamp`. + +### 3.2 Value Filter + +Use value filters to filter data whose data values meet certain criteria. **Allow** to use a time series not selected in the select clause as a value filter. + +An example is as follows: + +1. Select data with a value greater than 36.5: + + ```sql + select temperature from root.sg1.d1 where temperature > 36.5; + ```` + +2. Select data with value equal to true: + + ```sql + select status from root.sg1.d1 where status = true; + ```` + +3. Select data for the interval [36.5,40] or not: + + ```sql + select temperature from root.sg1.d1 where temperature between 36.5 and 40; + ```` + + ```sql + select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + ```` + +4. Select data with values within a specific range: + + ```sql + select code from root.sg1.d1 where code in ('200', '300', '400', '500'); + ```` + +5. Select data with values outside a certain range: + + ```sql + select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); + ```` + +6. Select data with values is null: + + ```sql + select code from root.sg1.d1 where temperature is null; + ```` + +7. Select data with values is not null: + + ```sql + select code from root.sg1.d1 where temperature is not null; + ```` + +### 3.3 Fuzzy Query + +Fuzzy query is divided into Like statement and Regexp statement, both of which can support fuzzy matching of TEXT type data. + +Like statement: + +#### Fuzzy matching using `Like` + +In the value filter condition, for TEXT type data, use `Like` and `Regexp` operators to perform fuzzy matching on data. + +**Matching rules:** + +- The percentage (`%`) wildcard matches any string of zero or more characters. +- The underscore (`_`) wildcard matches any single character. + +**Example 1:** Query data containing `'cc'` in `value` under `root.sg.d1`. + +``` +IoTDB> select * from root.sg.d1 where value like '%cc%' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 2:** Query data that consists of 3 characters and the second character is `'b'` in `value` under `root.sg.d1`. + +``` +IoTDB> select * from root.sg.device where value like '_b_' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:02.000+08:00| abc| ++-----------------------------+----------------+ +Total line number = 1 +It costs 0.002s +``` + +#### Fuzzy matching using `Regexp` + +The filter conditions that need to be passed in are regular expressions in the Java standard library style. + +**Examples of common regular matching:** + +``` +All characters with a length of 3-20: ^.{3,20}$ +Uppercase english characters: ^[A-Z]+$ +Numbers and English characters: ^[A-Za-z0-9]+$ +Beginning with a: ^a.* +``` + +**Example 1:** Query a string composed of 26 English characters for the value under root.sg.d1 + +``` +IoTDB> select * from root.sg.d1 where value regexp '^[A-Za-z]+$' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 2:** Query root.sg.d1 where the value value is a string composed of 26 lowercase English characters and the time is greater than 100 + +``` +IoTDB> select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +## 4. `GROUP BY` CLAUSE + +IoTDB supports using `GROUP BY` clause to aggregate the time series by segment and group. + +Segmented aggregation refers to segmenting data in the row direction according to the time dimension, aiming at the time relationship between different data points in the same time series, and obtaining an aggregated value for each segment. Currently only **group by time**、**group by variation**、**group by condition**、**group by session** and **group by count** is supported, and more segmentation methods will be supported in the future. + +Group aggregation refers to grouping the potential business attributes of time series for different time series. Each group contains several time series, and each group gets an aggregated value. Support **group by path level** and **group by tag** two grouping methods. + +### 4.1 Aggregate By Segment + +#### Aggregate By Time + +Aggregate by time is a typical query method for time series data. Data is collected at high frequency and needs to be aggregated and calculated at certain time intervals. For example, to calculate the daily average temperature, the sequence of temperature needs to be segmented by day, and then calculated. average value. + +Aggregate by time refers to a query method that uses a lower frequency than the time frequency of data collection, and is a special case of segmented aggregation. For example, the frequency of data collection is one second. If you want to display the data in one minute, you need to use time aggregagtion. + +This section mainly introduces the related examples of time aggregation, using the `GROUP BY` clause. IoTDB supports partitioning result sets according to time interval and customized sliding step. And by default results are sorted by time in ascending order. + +The GROUP BY statement provides users with three types of specified parameters: + +* Parameter 1: The display window on the time axis +* Parameter 2: Time interval for dividing the time axis(should be positive) +* Parameter 3: Time sliding step (optional and defaults to equal the time interval if not set) + +The actual meanings of the three types of parameters are shown in Figure below. +Among them, the parameter 3 is optional. + +
+
+ + +There are three typical examples of frequency reduction aggregation: + +##### Aggregate By Time without Specifying the Sliding Step Length + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` + +which means: + +Since the sliding step length is not specified, the `GROUP BY` statement by default set the sliding step the same as the time interval which is `1d`. + +The fist parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2017-11-07T23:00:00). + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1d) as time interval and startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [0,1d), [1d, 2d), [2d, 3d), etc. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-11-01T00:00:00, 2017-11-07 T23:00:00]), and map these data to the previously segmented time axis (in this case there are mapped data in every 1-day period from 2017-11-01T00:00:00 to 2017-11-07T23:00:00:00). + +Since there is data for each time period in the result range to be displayed, the execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 1440| 26.0| +|2017-11-02T00:00:00.000+08:00| 1440| 26.0| +|2017-11-03T00:00:00.000+08:00| 1440| 25.99| +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.024s +``` + +##### Aggregate By Time Specifying the Sliding Step Length + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +which means: + +Since the user specifies the sliding step parameter as 1d, the `GROUP BY` statement will move the time interval `1 day` long instead of `3 hours` as default. + +That means we want to fetch all the data of 00:00:00 to 02:59:59 every day from 2017-11-01 to 2017-11-07. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2017-11-07T23:00:00). + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (3h) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-11-01T00:00:00, 2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00), [2017-11-03T00:00:00, 2017-11-03T03:00:00), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-11-01T00:00:00, 2017-11-07T23:00:00]), and map these data to the previously segmented time axis (in this case there are mapped data in every 3-hour period for each day from 2017-11-01T00:00:00 to 2017-11-07T23:00:00:00). + +Since there is data for each time period in the result range to be displayed, the execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-02T00:00:00.000+08:00| 180| 25.98| +|2017-11-03T00:00:00.000+08:00| 180| 25.96| +|2017-11-04T00:00:00.000+08:00| 180| 25.96| +|2017-11-05T00:00:00.000+08:00| 180| 26.0| +|2017-11-06T00:00:00.000+08:00| 180| 25.85| +|2017-11-07T00:00:00.000+08:00| 180| 25.99| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.006s +``` + +The sliding step can be smaller than the interval, in which case there is overlapping time between the aggregation windows (similar to a sliding window). + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-01 10:00:00), 4h, 2h); +``` + +The execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-01T02:00:00.000+08:00| 180| 25.98| +|2017-11-01T04:00:00.000+08:00| 180| 25.96| +|2017-11-01T06:00:00.000+08:00| 180| 25.96| +|2017-11-01T08:00:00.000+08:00| 180| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 5 +It costs 0.006s +``` + +##### Aggregate by Natural Month + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +which means: + +Since the user specifies the sliding step parameter as `2mo`, the `GROUP BY` statement will move the time interval `2 months` long instead of `1 month` as default. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2019-11-07T23:00:00). + +The start time is 2017-11-01T00:00:00. The sliding step will increment monthly based on the start date, and the 1st day of the month will be used as the time interval's start time. + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1mo) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-11-01T00:00:00, 2017-12-01T00:00:00), [2018-02-01T00:00:00, 2018-03-01T00:00:00), [2018-05-03T00:00:00, 2018-06-01T00:00:00)), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of (2017-11-01T00:00:00, 2019-11-07T23:00:00], and map these data to the previously segmented time axis (in this case there are mapped data of the first month in every two month period from 2017-11-01T00:00:00 to 2019-11-07T23:00:00). + +The SQL execution result is: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-01T00:00:00.000+08:00| 259| +|2018-01-01T00:00:00.000+08:00| 250| +|2018-03-01T00:00:00.000+08:00| 259| +|2018-05-01T00:00:00.000+08:00| 251| +|2018-07-01T00:00:00.000+08:00| 242| +|2018-09-01T00:00:00.000+08:00| 225| +|2018-11-01T00:00:00.000+08:00| 216| +|2019-01-01T00:00:00.000+08:00| 207| +|2019-03-01T00:00:00.000+08:00| 216| +|2019-05-01T00:00:00.000+08:00| 207| +|2019-07-01T00:00:00.000+08:00| 199| +|2019-09-01T00:00:00.000+08:00| 181| +|2019-11-01T00:00:00.000+08:00| 60| ++-----------------------------+-------------------------------+ +``` + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +which means: + +Since the user specifies the sliding step parameter as `2mo`, the `GROUP BY` statement will move the time interval `2 months` long instead of `1 month` as default. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-10-31T00:00:00, 2019-11-07T23:00:00). + +Different from the previous example, the start time is set to 2017-10-31T00:00:00. The sliding step will increment monthly based on the start date, and the 31st day of the month meaning the last day of the month will be used as the time interval's start time. If the start time is set to the 30th date, the sliding step will use the 30th or the last day of the month. + +The start time is 2017-10-31T00:00:00. The sliding step will increment monthly based on the start time, and the 1st day of the month will be used as the time interval's start time. + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1mo) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-10-31T00:00:00, 2017-11-31T00:00:00), [2018-02-31T00:00:00, 2018-03-31T00:00:00), [2018-05-31T00:00:00, 2018-06-31T00:00:00), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-10-31T00:00:00, 2019-11-07T23:00:00) and map these data to the previously segmented time axis (in this case there are mapped data of the first month in every two month period from 2017-10-31T00:00:00 to 2019-11-07T23:00:00). + +The SQL execution result is: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-10-31T00:00:00.000+08:00| 251| +|2017-12-31T00:00:00.000+08:00| 250| +|2018-02-28T00:00:00.000+08:00| 259| +|2018-04-30T00:00:00.000+08:00| 250| +|2018-06-30T00:00:00.000+08:00| 242| +|2018-08-31T00:00:00.000+08:00| 225| +|2018-10-31T00:00:00.000+08:00| 216| +|2018-12-31T00:00:00.000+08:00| 208| +|2019-02-28T00:00:00.000+08:00| 216| +|2019-04-30T00:00:00.000+08:00| 208| +|2019-06-30T00:00:00.000+08:00| 199| +|2019-08-31T00:00:00.000+08:00| 181| +|2019-10-31T00:00:00.000+08:00| 69| ++-----------------------------+-------------------------------+ +``` + +##### Left Open And Right Close Range + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +In this sql, the time interval is left open and right close, so we won't include the value of timestamp 2017-11-01T00:00:00 and instead we will include the value of timestamp 2017-11-07T23:00:00. + +We will get the result like following: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### Aggregation By Variation + +IoTDB supports grouping by continuous stable values through the `GROUP BY VARIATION` statement. + +Group-By-Variation wil set the first point in group as the base point, +then if the difference between the new data and base point is small than or equal to delta, +the data point will be grouped together and execute aggregation query (The calculation of difference and the meaning of delte are introduced below). The groups won't overlap and there is no fixed start time and end time. +The syntax of clause is as follows: + +```sql +group by variation(controlExpression[,delta][,ignoreNull=true/false]) +``` + +The different parameters mean: + +* controlExpression + +The value that is used to calculate difference. It can be any columns or the expression of them. + +* delta + +The threshold that is used when grouping. The difference of controlExpression between the first data point and new data point should less than or equal to delta. +When delta is zero, all the continuous data with equal expression value will be grouped into the same group. + +* ignoreNull + +Used to specify how to deal with the data when the value of controlExpression is null. When ignoreNull is false, null will be treated as a new value and when ignoreNull is true, the data point will be directly skipped. + +The supported return types of controlExpression and how to deal with null value when ignoreNull is false are shown in the following table: + +| delta | Return Type Supported By controlExpression | The Handling of null when ignoreNull is False | +| -------- | ------------------------------------------ | ------------------------------------------------------------ | +| delta!=0 | INT32、INT64、FLOAT、DOUBLE | If the processing group doesn't contains null, null value should be treated as infinity/infinitesimal and will end current group.
Continuous null values are treated as stable values and assigned to the same group. | +| delta=0 | TEXT、BINARY、INT32、INT64、FLOAT、DOUBLE | Null is treated as a new value in a new group and continuous nulls belong to the same group. | + +groupByVariation + +##### Precautions for Use + +1. The result of controlExpression should be a unique value. If multiple columns appear after using wildcard stitching, an error will be reported. +2. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +3. Each device is grouped separately when used with `ALIGN BY DEVICE`. +4. Delta is zero and ignoreNull is true by default. +5. Currently `GROUP BY VARIATION` is not supported with `GROUP BY LEVEL`. + +Using the raw data below, several examples of `GROUP BY VARIAITON` queries will be given. + +``` ++-----------------------------+-------+-------+-------+--------+-------+-------+ +| Time| s1| s2| s3| s4| s5| s6| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +|1970-01-01T08:00:00.000+08:00| 4.5| 9.0| 0.0| 45.0| 9.0| 8.25| +|1970-01-01T08:00:00.010+08:00| null| 19.0| 10.0| 145.0| 19.0| 8.25| +|1970-01-01T08:00:00.020+08:00| 24.5| 29.0| null| 245.0| 29.0| null| +|1970-01-01T08:00:00.030+08:00| 34.5| null| 30.0| 345.0| null| null| +|1970-01-01T08:00:00.040+08:00| 44.5| 49.0| 40.0| 445.0| 49.0| 8.25| +|1970-01-01T08:00:00.050+08:00| null| 59.0| 50.0| 545.0| 59.0| 6.25| +|1970-01-01T08:00:00.060+08:00| 64.5| 69.0| 60.0| 645.0| 69.0| null| +|1970-01-01T08:00:00.070+08:00| 74.5| 79.0| null| null| 79.0| 3.25| +|1970-01-01T08:00:00.080+08:00| 84.5| 89.0| 80.0| 845.0| 89.0| 3.25| +|1970-01-01T08:00:00.090+08:00| 94.5| 99.0| 90.0| 945.0| 99.0| 3.25| +|1970-01-01T08:00:00.150+08:00| 66.5| 77.0| 90.0| 945.0| 99.0| 9.25| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +``` + +##### delta = 0 + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +``` + +Get the result below which ignores the row with null value in `s6`. + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.040+08:00| 24.5| 3| 50.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +when ignoreNull is false, the row with null value in `s6` will be considered. + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +``` + +Get the following result. + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.020+08:00|1970-01-01T08:00:00.030+08:00| 29.5| 1| 30.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.040+08:00| 44.5| 1| 40.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.060+08:00|1970-01-01T08:00:00.060+08:00| 64.5| 1| 60.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +##### delta !=0 + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.050+08:00| 24.5| 4| 100.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.050+08:00| 44.5| 2| 90.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.080+08:00| 79.5| 2| 80.0| +|1970-01-01T08:00:00.090+08:00|1970-01-01T08:00:00.150+08:00| 80.5| 2| 180.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +#### Aggregation By Condition + +When you need to filter the data according to a specific condition and group the continuous ones for an aggregation query. +`GROUP BY CONDITION` is suitable for you.The rows which don't meet the given condition will be simply ignored because they don't belong to any group. +Its syntax is defined below: + +```sql +group by condition(predict,[keep>/>=/=/<=/<]threshold,[,ignoreNull=true/false]) +``` + +* predict + +Any legal expression return the type of boolean for filtering in grouping. + +* [keep>/>=/=/<=/<]threshold + +Keep expression is used to specify the number of continuous rows that meet the `predict` condition to form a group. Only the number of rows in group satisfy the keep condition, the result of group will be output. +Keep expression consists of a 'keep' string and a threshold of type `long` or a single 'long' type data. + +* ignoreNull=true/false + +Used to specify how to handle data rows that encounter null predict, skip the row when it's true and end current group when it's false. + +##### Precautions for Use + +1. keep condition is required in the query, but you can omit the 'keep' string and given a `long` number which defaults to 'keep=long number' condition. +2. IgnoreNull defaults to true. +3. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +4. Each device is grouped separately when used with `ALIGN BY DEVICE`. +5. Currently `GROUP BY CONDITION` is not supported with `GROUP BY LEVEL`. + +For the following raw data, several query examples are given below: + +``` ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +| Time|root.sg.beijing.car01.soc|root.sg.beijing.car01.charging_status|root.sg.beijing.car01.vehicle_status| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| 1| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| 1| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +``` + +The sql statement to query data with at least two continuous row shown below: + +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=true) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 10| 5| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` + +When ignoreNull is false, the null value will be treated as a row that doesn't meet the condition. + +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=false) +``` + +Get the result below, the original group is split. + +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 7| 3| 36.0| +|1970-01-01T08:00:00.009+08:00| 10| 2| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` + +#### Aggregation By Session + +`GROUP BY SESSION` can be used to group data according to the interval of the time. Data with a time interval less than or equal to the given threshold will be assigned to the same group. +For example, in industrial scenarios, devices don't always run continuously, `GROUP BY SESSION` will group the data generated by each access session of the device. +Its syntax is defined as follows: + +```sql +group by session(timeInterval) +``` + +* timeInterval + +A given interval threshold to create a new group of data when the difference between the time of data is greater than the threshold. + +The figure below is a grouping diagram under `GROUP BY SESSION`. + +groupBySession + +##### Precautions for Use + +1. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +2. Each device is grouped separately when used with `ALIGN BY DEVICE`. +3. Currently `GROUP BY SESSION` is not supported with `GROUP BY LEVEL`. + +For the raw data below, a few query examples are given: + +``` ++-----------------------------+-----------------+-----------+--------+------+ +| Time| Device|temperature|hardware|status| ++-----------------------------+-----------------+-----------+--------+------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01| 35.7| 11| false| +|1970-01-01T08:00:02.000+08:00|root.ln.wf02.wt01| 35.8| 22| true| +|1970-01-01T08:00:03.000+08:00|root.ln.wf02.wt01| 35.4| 33| false| +|1970-01-01T08:00:04.000+08:00|root.ln.wf02.wt01| 36.4| 44| false| +|1970-01-01T08:00:05.000+08:00|root.ln.wf02.wt01| 36.8| 55| false| +|1970-01-01T08:00:10.000+08:00|root.ln.wf02.wt01| 36.8| 110| false| +|1970-01-01T08:00:20.000+08:00|root.ln.wf02.wt01| 37.8| 220| true| +|1970-01-01T08:00:30.000+08:00|root.ln.wf02.wt01| 37.5| 330| false| +|1970-01-01T08:00:40.000+08:00|root.ln.wf02.wt01| 37.4| 440| false| +|1970-01-01T08:00:50.000+08:00|root.ln.wf02.wt01| 37.9| 550| false| +|1970-01-01T08:01:40.000+08:00|root.ln.wf02.wt01| 38.0| 110| false| +|1970-01-01T08:02:30.000+08:00|root.ln.wf02.wt01| 38.8| 220| true| +|1970-01-01T08:03:20.000+08:00|root.ln.wf02.wt01| 38.6| 330| false| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01| 38.4| 440| false| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01| 38.3| 550| false| +|1970-01-01T08:06:40.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:07:50.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:08:00.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01| 38.2| 110| false| +|1970-01-02T08:08:02.000+08:00|root.ln.wf02.wt01| 37.5| 220| true| +|1970-01-02T08:08:03.000+08:00|root.ln.wf02.wt01| 37.4| 330| false| +|1970-01-02T08:08:04.000+08:00|root.ln.wf02.wt01| 36.8| 440| false| +|1970-01-02T08:08:05.000+08:00|root.ln.wf02.wt01| 37.4| 550| false| ++-----------------------------+-----------------+-----------+--------+------+ +``` + +TimeInterval can be set by different time units, the sql is shown below: + +```sql +select __endTime,count(*) from root.** group by session(1d) +``` + +Get the result: + +``` ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time| __endTime|count(root.ln.wf02.wt01.temperature)|count(root.ln.wf02.wt01.hardware)|count(root.ln.wf02.wt01.status)| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|1970-01-01T08:00:01.000+08:00|1970-01-01T08:08:00.000+08:00| 15| 18| 15| +|1970-01-02T08:08:01.000+08:00|1970-01-02T08:08:05.000+08:00| 5| 5| 5| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` + +It can be also used with `HAVING` and `ALIGN BY DEVICE` clauses. + +```sql +select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` + +Get the result below: + +``` ++-----------------------------+-----------------+-----------------------------+-------------+ +| Time| Device| __endTime|sum(hardware)| ++-----------------------------+-----------------+-----------------------------+-------------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01|1970-01-01T08:03:20.000+08:00| 2475.0| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:04:20.000+08:00| 440.0| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:05:20.000+08:00| 550.0| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01|1970-01-02T08:08:05.000+08:00| 1650.0| ++-----------------------------+-----------------+-----------------------------+-------------+ +``` + +#### Aggregation By Count + +`GROUP BY COUNT`can aggregate the data points according to the number of points. It can group fixed number of continuous data points together for aggregation query. +Its syntax is defined as follows: + +```sql +group by count(controlExpression, size[,ignoreNull=true/false]) +``` + +* controlExpression + +The object to count during processing, it can be any column or an expression of columns. + +* size + +The number of data points in a group, a number of `size` continuous points will be divided to the same group. + +* ignoreNull=true/false + +Whether to ignore the data points with null in `controlExpression`, when ignoreNull is true, data points with the `controlExpression` of null will be skipped during counting. + +##### Precautions for Use + +1. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +2. Each device is grouped separately when used with `ALIGN BY DEVICE`. +3. Currently `GROUP BY SESSION` is not supported with `GROUP BY LEVEL`. +4. When the final number of data points in a group is less than `size`, the result of the group will not be output. + +For the data below, some examples will be given. + +``` ++-----------------------------+-----------+-----------------------+ +| Time|root.sg.soc|root.sg.charging_status| ++-----------------------------+-----------+-----------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| ++-----------------------------+-----------+-----------------------+ +``` + +The sql is shown below + +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +``` + +Get the result below, in the second group from 1970-01-01T08:00:00.006+08:00 to 1970-01-01T08:00:00.010+08:00. There are only four points included which is less than `size`. So it won't be output. + +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` + +When `ignoreNull=false` is used to take null value into account. There will be two groups with 5 points in the resultSet, which is shown as follows: + +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` + +Get the results: + +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| +|1970-01-01T08:00:00.006+08:00|1970-01-01T08:00:00.010+08:00| 24.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` + +### 4.2 Aggregate By Group + +#### Aggregation By Level + +Aggregation by level statement is used to group the query result whose name is the same at the given level. + +- Keyword `LEVEL` is used to specify the level that need to be grouped. By convention, `level=0` represents *root* level. +- All aggregation functions are supported. When using five aggregations: sum, avg, min_value, max_value and extreme, please make sure all the aggregated series have exactly the same data type. Otherwise, it will generate a syntax error. + +**Example 1:** there are multiple series named `status` under different databases, like "root.ln.wf01.wt01.status", "root.ln.wf02.wt02.status", and "root.sgcc.wf03.wt01.status". If you need to count the number of data points of the `status` sequence under different databases, use the following query: + +```sql +select count(status) from root.** group by level = 1 +``` + +Result: + +``` ++-------------------------+---------------------------+ +|count(root.ln.*.*.status)|count(root.sgcc.*.*.status)| ++-------------------------+---------------------------+ +| 20160| 10080| ++-------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 2:** If you need to count the number of data points under different devices, you can specify level = 3, + +```sql +select count(status) from root.** group by level = 3 +``` + +Result: + +``` ++---------------------------+---------------------------+ +|count(root.*.*.wt01.status)|count(root.*.*.wt02.status)| ++---------------------------+---------------------------+ +| 20160| 10080| ++---------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 3:** Attention,the devices named `wt01` under databases `ln` and `sgcc` are grouped together, since they are regarded as devices with the same name. If you need to further count the number of data points in different devices under different databases, you can use the following query: + +```sql +select count(status) from root.** group by level = 1, 3 +``` + +Result: + +``` ++----------------------------+----------------------------+------------------------------+ +|count(root.ln.*.wt01.status)|count(root.ln.*.wt02.status)|count(root.sgcc.*.wt01.status)| ++----------------------------+----------------------------+------------------------------+ +| 10080| 10080| 10080| ++----------------------------+----------------------------+------------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 4:** Assuming that you want to query the maximum value of temperature sensor under all time series, you can use the following query statement: + +```sql +select max_value(temperature) from root.** group by level = 0 +``` + +Result: + +``` ++---------------------------------+ +|max_value(root.*.*.*.temperature)| ++---------------------------------+ +| 26.0| ++---------------------------------+ +Total line number = 1 +It costs 0.013s +``` + +**Example 5:** The above queries are for a certain sensor. In particular, **if you want to query the total data points owned by all sensors at a certain level**, you need to explicitly specify `*` is selected. + +```sql +select count(*) from root.ln.** group by level = 2 +``` + +Result: + +``` ++----------------------+----------------------+ +|count(root.*.wf01.*.*)|count(root.*.wf02.*.*)| ++----------------------+----------------------+ +| 20160| 20160| ++----------------------+----------------------+ +Total line number = 1 +It costs 0.013s +``` + +##### Aggregate By Time with Level Clause + +Level could be defined to show count the number of points of each node at the given level in current Metadata Tree. + +This could be used to query the number of points under each device. + +The SQL statement is: + +Get time aggregation by level. + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +``` + +Result: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.006s +``` + +Time aggregation with sliding step and by level. + +```sql +select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +Result: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| +|2017-11-02T00:00:00.000+08:00| 180| +|2017-11-03T00:00:00.000+08:00| 180| +|2017-11-04T00:00:00.000+08:00| 180| +|2017-11-05T00:00:00.000+08:00| 180| +|2017-11-06T00:00:00.000+08:00| 180| +|2017-11-07T00:00:00.000+08:00| 180| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### Aggregation By Tags + +IotDB allows you to do aggregation query with the tags defined in timeseries through `GROUP BY TAGS` clause as well. + +Firstly, we can put these example data into IoTDB, which will be used in the following feature introduction. + +These are the temperature data of the workshops, which belongs to the factory `factory1` and locates in different cities. The time range is `[1000, 10000)`. + +The device node of the timeseries path is the ID of the device. The information of city and workshop are modelled in the tags `city` and `workshop`. +The devices `d1` and `d2` belong to the workshop `d1` in `Beijing`. +`d3` and `d4` belong to the workshop `w2` in `Beijing`. +`d5` and `d6` belong to the workshop `w1` in `Shanghai`. +`d7` belongs to the workshop `w2` in `Shanghai`. +`d8` and `d9` are under maintenance, and don't belong to any workshops, so they have no tags. + + +```SQL +CREATE DATABASE root.factory1; +create timeseries root.factory1.d1.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d2.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d3.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d4.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d5.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d6.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d7.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w2); +create timeseries root.factory1.d8.temperature with datatype=FLOAT; +create timeseries root.factory1.d9.temperature with datatype=FLOAT; + +insert into root.factory1.d1(time, temperature) values(1000, 104.0); +insert into root.factory1.d1(time, temperature) values(3000, 104.2); +insert into root.factory1.d1(time, temperature) values(5000, 103.3); +insert into root.factory1.d1(time, temperature) values(7000, 104.1); + +insert into root.factory1.d2(time, temperature) values(1000, 104.4); +insert into root.factory1.d2(time, temperature) values(3000, 103.7); +insert into root.factory1.d2(time, temperature) values(5000, 103.3); +insert into root.factory1.d2(time, temperature) values(7000, 102.9); + +insert into root.factory1.d3(time, temperature) values(1000, 103.9); +insert into root.factory1.d3(time, temperature) values(3000, 103.8); +insert into root.factory1.d3(time, temperature) values(5000, 102.7); +insert into root.factory1.d3(time, temperature) values(7000, 106.9); + +insert into root.factory1.d4(time, temperature) values(1000, 103.9); +insert into root.factory1.d4(time, temperature) values(5000, 102.7); +insert into root.factory1.d4(time, temperature) values(7000, 106.9); + +insert into root.factory1.d5(time, temperature) values(1000, 112.9); +insert into root.factory1.d5(time, temperature) values(7000, 113.0); + +insert into root.factory1.d6(time, temperature) values(1000, 113.9); +insert into root.factory1.d6(time, temperature) values(3000, 113.3); +insert into root.factory1.d6(time, temperature) values(5000, 112.7); +insert into root.factory1.d6(time, temperature) values(7000, 112.3); + +insert into root.factory1.d7(time, temperature) values(1000, 101.2); +insert into root.factory1.d7(time, temperature) values(3000, 99.3); +insert into root.factory1.d7(time, temperature) values(5000, 100.1); +insert into root.factory1.d7(time, temperature) values(7000, 99.8); + +insert into root.factory1.d8(time, temperature) values(1000, 50.0); +insert into root.factory1.d8(time, temperature) values(3000, 52.1); +insert into root.factory1.d8(time, temperature) values(5000, 50.1); +insert into root.factory1.d8(time, temperature) values(7000, 50.5); + +insert into root.factory1.d9(time, temperature) values(1000, 50.3); +insert into root.factory1.d9(time, temperature) values(3000, 52.1); +``` + +##### Aggregation query by one single tag + +If the user wants to know the average temperature of each workshop, he can query like this + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +The query will calculate the average of the temperatures of those timeseries which have the same tag value of the key `city`. +The results are + +``` ++--------+------------------+ +| city| avg(temperature)| ++--------+------------------+ +| Beijing|104.04666697184244| +|Shanghai|107.85000076293946| +| NULL| 50.84999910990397| ++--------+------------------+ +Total line number = 3 +It costs 0.231s +``` + +From the results we can see that the differences between aggregation by tags query and aggregation by time or level query are: + +1. Aggregation query by tags will no longer remove wildcard to raw timeseries, but do the aggregation through the data of multiple timeseries, which have the same tag value. +2. Except for the aggregate result column, the result set contains the key-value column of the grouped tag. The column name is the tag key, and the values in the column are tag values which present in the searched timeseries. + If some searched timeseries doesn't have the grouped tag, a `NULL` value in the key-value column of the grouped tag will be presented, which means the aggregation of all the timeseries lacking the tagged key. + +##### Aggregation query by multiple tags + +Except for the aggregation query by one single tag, aggregation query by multiple tags in a particular order is allowed as well. + +For example, a user wants to know the average temperature of the devices in each workshop. +As the workshop names may be same in different city, it's not correct to aggregated by the tag `workshop` directly. +So the aggregation by the tag `city` should be done first, and then by the tag `workshop`. + +SQL + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +The results + +``` ++--------+--------+------------------+ +| city|workshop| avg(temperature)| ++--------+--------+------------------+ +| NULL| NULL| 50.84999910990397| +|Shanghai| w1|113.01666768391927| +| Beijing| w2| 104.4000004359654| +|Shanghai| w2|100.10000038146973| +| Beijing| w1|103.73750019073486| ++--------+--------+------------------+ +Total line number = 5 +It costs 0.027s +``` + +We can see that in a multiple tags aggregation query, the result set will output the key-value columns of all the grouped tag keys, which have the same order with the one in `GROUP BY TAGS`. + +##### Downsampling Aggregation by tags based on Time Window + +Downsampling aggregation by time window is one of the most popular features in a time series database. IoTDB supports to do aggregation query by tags based on time window. + +For example, a user wants to know the average temperature of the devices in each workshop, in every 5 seconds, in the range of time `[1000, 10000)`. + +SQL + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +The results + +``` ++-----------------------------+--------+--------+------------------+ +| Time| city|workshop| avg(temperature)| ++-----------------------------+--------+--------+------------------+ +|1970-01-01T08:00:01.000+08:00| NULL| NULL| 50.91999893188476| +|1970-01-01T08:00:01.000+08:00|Shanghai| w1|113.20000076293945| +|1970-01-01T08:00:01.000+08:00| Beijing| w2| 103.4| +|1970-01-01T08:00:01.000+08:00|Shanghai| w2| 100.1999994913737| +|1970-01-01T08:00:01.000+08:00| Beijing| w1|103.81666692097981| +|1970-01-01T08:00:06.000+08:00| NULL| NULL| 50.5| +|1970-01-01T08:00:06.000+08:00|Shanghai| w1| 112.6500015258789| +|1970-01-01T08:00:06.000+08:00| Beijing| w2| 106.9000015258789| +|1970-01-01T08:00:06.000+08:00|Shanghai| w2| 99.80000305175781| +|1970-01-01T08:00:06.000+08:00| Beijing| w1| 103.5| ++-----------------------------+--------+--------+------------------+ +``` + +Comparing to the pure tag aggregations, this kind of aggregation will divide the data according to the time window specification firstly, and do the aggregation query by the multiple tags in each time window secondly. +The result set will also contain a time column, which have the same meaning with the time column of the result in downsampling aggregation query by time window. + +##### Limitation of Aggregation by Tags + +As this feature is still under development, some queries have not been completed yet and will be supported in the future. + +> 1. Temporarily not support `HAVING` clause to filter the results. +> 2. Temporarily not support ordering by tag values. +> 3. Temporarily not support `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`. +> 4. Temporarily not support `ALIGN BY DEVICE`. +> 5. Temporarily not support expressions as aggregation function parameter,e.g. `count(s+1)`. +> 6. Not support the value filter, which stands the same with the `GROUP BY LEVEL` query. + +## 5. `HAVING` CLAUSE + +If you want to filter the results of aggregate queries, +you can use the `HAVING` clause after the `GROUP BY` clause. + +> NOTE: +> +> 1.The expression in HAVING clause must consist of aggregate values; the original sequence cannot appear alone. +> The following usages are incorrect: +> +> ```sql +> select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 +> select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 +> ``` +> +> 2.When filtering the `GROUP BY LEVEL` result, the PATH in `SELECT` and `HAVING` can only have one node. +> The following usages are incorrect: +> +> ```sql +> select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 +> select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 +> ``` + +Here are a few examples of using the 'HAVING' clause to filter aggregate results. + +Aggregation result 1: + +``` ++-----------------------------+---------------------+---------------------+ +| Time|count(root.test.*.s1)|count(root.test.*.s2)| ++-----------------------------+---------------------+---------------------+ +|1970-01-01T08:00:00.001+08:00| 4| 4| +|1970-01-01T08:00:00.003+08:00| 1| 0| +|1970-01-01T08:00:00.005+08:00| 2| 4| +|1970-01-01T08:00:00.007+08:00| 3| 2| +|1970-01-01T08:00:00.009+08:00| 4| 4| ++-----------------------------+---------------------+---------------------+ +``` + +Aggregation result filtering query 1: + +```sql + select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 1 +``` + +Filtering result 1: + +``` ++-----------------------------+---------------------+ +| Time|count(root.test.*.s1)| ++-----------------------------+---------------------+ +|1970-01-01T08:00:00.001+08:00| 4| +|1970-01-01T08:00:00.005+08:00| 2| +|1970-01-01T08:00:00.009+08:00| 4| ++-----------------------------+---------------------+ +``` + +Aggregation result 2: + +``` ++-----------------------------+-------------+---------+---------+ +| Time| Device|count(s1)|count(s2)| ++-----------------------------+-------------+---------+---------+ +|1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.003+08:00|root.test.sg1| 1| 0| +|1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.007+08:00|root.test.sg1| 2| 1| +|1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| +|1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| +|1970-01-01T08:00:00.003+08:00|root.test.sg2| 0| 0| +|1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| +|1970-01-01T08:00:00.007+08:00|root.test.sg2| 1| 1| +|1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| ++-----------------------------+-------------+---------+---------+ +``` + +Aggregation result filtering query 2: + +```sql + select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device +``` + +Filtering result 2: + +``` ++-----------------------------+-------------+---------+---------+ +| Time| Device|count(s1)|count(s2)| ++-----------------------------+-------------+---------+---------+ +|1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| +|1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| +|1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| +|1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| ++-----------------------------+-------------+---------+---------+ +``` + +## 6. `FILL` CLAUSE + +### 6.1 Introduction + +When executing some queries, there may be no data for some columns in some rows, and data in these locations will be null, but this kind of null value is not conducive to data visualization and analysis, and the null value needs to be filled. + +In IoTDB, users can use the FILL clause to specify the fill mode when data is missing. Fill null value allows the user to fill any query result with null values according to a specific method, such as taking the previous value that is not null, or linear interpolation. The query result after filling the null value can better reflect the data distribution, which is beneficial for users to perform data analysis. + +### 6.2 Syntax Definition + +**The following is the syntax definition of the `FILL` clause:** + +```sql +FILL '(' PREVIOUS | LINEAR | constant ')' +``` + +**Note:** + +- We can specify only one fill method in the `FILL` clause, and this method applies to all columns of the result set. +- Null value fill is not compatible with version 0.13 and previous syntax (`FILL(([(, , )?])+)`) is not supported anymore. + +### 6.3 Fill Methods + +**IoTDB supports the following three fill methods:** + +- `PREVIOUS`: Fill with the previous non-null value of the column. +- `LINEAR`: Fill the column with a linear interpolation of the previous non-null value and the next non-null value of the column. +- Constant: Fill with the specified constant. + +**Following table lists the data types and supported fill methods.** + +| Data Type | Supported Fill Methods | +| :-------- | :---------------------- | +| boolean | previous, value | +| int32 | previous, linear, value | +| int64 | previous, linear, value | +| float | previous, linear, value | +| double | previous, linear, value | +| text | previous, value | + +**Note:** For columns whose data type does not support specifying the fill method, we neither fill it nor throw exception, just keep it as it is. + +**For examples:** + +If we don't use any fill methods: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000; +``` + +the original result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### `PREVIOUS` Fill + +**For null values in the query result set, fill with the previous non-null value of the column.** + +**Note:** If the first value of this column is null, we will keep first value as null and won't fill it until we meet first non-null value + +For example, with `PREVIOUS` fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 21.93| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| false| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +**While using `FILL(PREVIOUS)`, you can specify a time interval. If the interval between the timestamp of the current null value and the timestamp of the previous non-null value exceeds the specified time interval, no filling will be performed.** + +> 1. In the case of FILL(LINEAR) and FILL(CONSTANT), if the second parameter is specified, an exception will be thrown +> 2. The interval parameter only supports integers + For example, the raw data looks like this: + +```sql +select s1 from root.db.d1 +``` +``` ++-----------------------------+-------------+ +| Time|root.db.d1.s1| ++-----------------------------+-------------+ +|2023-11-08T16:41:50.008+08:00| 1.0| ++-----------------------------+-------------+ +|2023-11-08T16:46:50.011+08:00| 2.0| ++-----------------------------+-------------+ +|2023-11-08T16:48:50.011+08:00| 3.0| ++-----------------------------+-------------+ +``` + +We want to group the data by 1 min time interval: + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| null| ++-----------------------------+------------------+ +``` + +After grouping, we want to fill the null value: + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +we also don't want the null value to be filled if it keeps null for 2 min. + +```sql +select avg(s1) +from root.db.d1 +group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS, 2m); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +#### `LINEAR` Fill + +**For null values in the query result set, fill the column with a linear interpolation of the previous non-null value and the next non-null value of the column.** + +**Note:** + +- If all the values before current value are null or all the values after current value are null, we will keep current value as null and won't fill it. +- If the column's data type is boolean/text, we neither fill it nor throw exception, just keep it as it is. + +Here we give an example of filling null values using the linear method. The SQL statement is as follows: + +For example, with `LINEAR` fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 22.08| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### Constant Fill + +**For null values in the query result set, fill with the specified constant.** + +**Note:** + +- When using the ValueFill, IoTDB neither fill the query result if the data type is different from the input constant nor throw exception, just keep it as it is. + + | Constant Value Data Type | Support Data Type | + | :----------------------- | :-------------------------------------- | + | `BOOLEAN` | `BOOLEAN` `TEXT` | + | `INT64` | `INT32` `INT64` `FLOAT` `DOUBLE` `TEXT` | + | `DOUBLE` | `FLOAT` `DOUBLE` `TEXT` | + | `TEXT` | `TEXT` | + +- If constant value is larger than Integer.MAX_VALUE, IoTDB neither fill the query result if the data type is int32 nor throw exception, just keep it as it is. + +For example, with `FLOAT` constant fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 2.0| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +For example, with `BOOLEAN` constant fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| true| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +## 7. `LIMIT` and `SLIMIT` CLAUSES (PAGINATION) + +When the query result set has a large amount of data, it is not conducive to display on one page. You can use the `LIMIT/SLIMIT` clause and the `OFFSET/SOFFSET` clause to control paging. + +- The `LIMIT` and `SLIMIT` clauses are used to control the number of rows and columns of query results. +- The `OFFSET` and `SOFFSET` clauses are used to control the starting position of the result display. + +### 7.1 Row Control over Query Results + +By using LIMIT and OFFSET clauses, users control the query results in a row-related manner. We demonstrate how to use LIMIT and OFFSET clauses through the following examples. + +* Example 1: basic LIMIT clause + +The SQL statement is: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 10 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires the first 10 rows of the query result. + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:00:00.000+08:00| true| 25.96| +|2017-11-01T00:01:00.000+08:00| true| 24.36| +|2017-11-01T00:02:00.000+08:00| false| 20.09| +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 10 +It costs 0.000s +``` + +* Example 2: LIMIT clause with OFFSET + +The SQL statement is: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires rows 3 to 7 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.342s +``` + +* Example 3: LIMIT clause combined with WHERE clause + +The SQL statement is: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2024-07-07T00:05:00.000 and time< 2024-07-12T00:12:00.000 limit 5 offset 3 +``` + +which means: + +The selected equipment is the ln group wf01 factory wt01 equipment; The selected time series are "state" and "temperature". The SQL statement requires the return of the status and temperature sensor values between the time "2024-07-07T00:05:00.000" and "2024-07-12T00:12:00.0000" on lines 3 to 7 (the first line is numbered as line 0). + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2024-07-09T17:32:11.943+08:00| true| 24.941973| +|2024-07-09T17:32:12.944+08:00| true| 20.05108| +|2024-07-09T17:32:13.945+08:00| true| 20.541632| +|2024-07-09T17:32:14.945+08:00| null| 23.09016| +|2024-07-09T17:32:14.946+08:00| true| null| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.070s +``` + +* Example 4: LIMIT clause combined with GROUP BY clause + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 5 offset 3 +``` + +which means: + +The SQL statement clause requires rows 3 to 7 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 4 +It costs 0.016s +``` + +### 7.2 Column Control over Query Results + +By using SLIMIT and SOFFSET clauses, users can control the query results in a column-related manner. We will demonstrate how to use SLIMIT and SOFFSET clauses through the following examples. + +* Example 1: basic SLIMIT clause + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is the first column under this device, i.e., the power supply status. The SQL statement requires the status sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The result is shown below: + +``` ++-----------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.temperature| ++-----------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| 20.71| +|2017-11-01T00:07:00.000+08:00| 21.45| +|2017-11-01T00:08:00.000+08:00| 22.58| +|2017-11-01T00:09:00.000+08:00| 20.98| +|2017-11-01T00:10:00.000+08:00| 25.52| +|2017-11-01T00:11:00.000+08:00| 22.91| ++-----------------------------+-----------------------------+ +Total line number = 6 +It costs 0.000s +``` + +* Example 2: SLIMIT clause with SOFFSET + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is the second column under this device, i.e., the temperature. The SQL statement requires the temperature sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The result is shown below: + +``` ++-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.status| ++-----------------------------+------------------------+ +|2017-11-01T00:06:00.000+08:00| false| +|2017-11-01T00:07:00.000+08:00| false| +|2017-11-01T00:08:00.000+08:00| false| +|2017-11-01T00:09:00.000+08:00| false| +|2017-11-01T00:10:00.000+08:00| true| +|2017-11-01T00:11:00.000+08:00| false| ++-----------------------------+------------------------+ +Total line number = 6 +It costs 0.003s +``` + +* Example 3: SLIMIT clause combined with GROUP BY clause + +The SQL statement is: + +```sql +select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +The result is shown below: + +``` ++-----------------------------+-----------------------------------+ +| Time|max_value(root.ln.wf01.wt01.status)| ++-----------------------------+-----------------------------------+ +|2017-11-01T00:00:00.000+08:00| true| +|2017-11-02T00:00:00.000+08:00| true| +|2017-11-03T00:00:00.000+08:00| true| +|2017-11-04T00:00:00.000+08:00| true| +|2017-11-05T00:00:00.000+08:00| true| +|2017-11-06T00:00:00.000+08:00| true| +|2017-11-07T00:00:00.000+08:00| true| ++-----------------------------+-----------------------------------+ +Total line number = 7 +It costs 0.000s +``` + +### 7.3 Row and Column Control over Query Results + +In addition to row or column control over query results, IoTDB allows users to control both rows and columns of query results. Here is a complete example with both LIMIT clauses and SLIMIT clauses. + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is columns 0 to 1 under this device (with the first column numbered as column 0). The SQL statement clause requires rows 100 to 109 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+-----------------------------+------------------------+ +|2017-11-01T01:40:00.000+08:00| 21.19| false| +|2017-11-01T01:41:00.000+08:00| 22.79| false| +|2017-11-01T01:42:00.000+08:00| 22.98| false| +|2017-11-01T01:43:00.000+08:00| 21.52| false| +|2017-11-01T01:44:00.000+08:00| 23.45| true| +|2017-11-01T01:45:00.000+08:00| 24.06| true| +|2017-11-01T01:46:00.000+08:00| 22.6| false| +|2017-11-01T01:47:00.000+08:00| 23.78| true| +|2017-11-01T01:48:00.000+08:00| 24.72| true| +|2017-11-01T01:49:00.000+08:00| 24.68| true| ++-----------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.009s +``` + +### 7.4 Error Handling + +If the parameter N/SN of LIMIT/SLIMIT exceeds the size of the result set, IoTDB returns all the results as expected. For example, the query result of the original SQL statement consists of six rows, and we select the first 100 rows through the LIMIT clause: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 100 +``` + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.005s +``` + +If the parameter N/SN of LIMIT/SLIMIT clause exceeds the allowable maximum value (N/SN is of type int64), the system prompts errors. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 9223372036854775808 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 416: Out of range. LIMIT : N should be Int64. +``` + +If the parameter N/SN of LIMIT/SLIMIT clause is not a positive intege, the system prompts errors. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 13.1 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 401: line 1:129 mismatched input '.' expecting {, ';'} +``` + +If the parameter OFFSET of LIMIT clause exceeds the size of the result set, IoTDB will return an empty result set. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 2 offset 6 +``` + +The result is shown below: + +``` ++----+------------------------+-----------------------------+ +|Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++----+------------------------+-----------------------------+ ++----+------------------------+-----------------------------+ +Empty set. +It costs 0.005s +``` + +If the parameter SOFFSET of SLIMIT clause is not smaller than the number of available timeseries, the system prompts errors. For example, executing the following SQL statement: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 2 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 411: Meet error in query process: The value of SOFFSET (2) is equal to or exceeds the number of sequences (2) that can actually be returned. +``` + +## 8. `ORDER BY` CLAUSE + +### 8.1 Order by in ALIGN BY TIME mode + +The result set of IoTDB is in ALIGN BY TIME mode by default and `ORDER BY TIME` clause can also be used to specify the ordering of timestamp. The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` + +Results: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-01T00:01:00.000+08:00| v2| true| 24.36| true| +|2017-11-01T00:00:00.000+08:00| v2| true| 25.96| true| +|1970-01-01T08:00:00.002+08:00| v2| false| null| null| +|1970-01-01T08:00:00.001+08:00| v1| true| null| null| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +``` + +### 8.2 Order by in ALIGN BY DEVICE mode + +When querying in ALIGN BY DEVICE mode, `ORDER BY` clause can be used to specify the ordering of result set. + +ALIGN BY DEVICE mode supports four kinds of clauses with two sort keys which are `Device` and `Time`. + +1. ``ORDER BY DEVICE``: sort by the alphabetical order of the device name. The devices with the same column names will be clustered in a group view. + +2. ``ORDER BY TIME``: sort by the timestamp, the data points from different devices will be shuffled according to the timestamp. + +3. ``ORDER BY DEVICE,TIME``: sort by the alphabetical order of the device name. The data points with the same device name will be sorted by timestamp. + +4. ``ORDER BY TIME,DEVICE``: sort by timestamp. The data points with the same time will be sorted by the alphabetical order of the device name. + +> To make the result set more legible, when `ORDER BY` clause is not used, default settings will be provided. +> The default ordering clause is `ORDER BY DEVICE,TIME` and the default ordering is `ASC`. + +When `Device` is the main sort key, the result set is sorted by device name first, then by timestamp in the group with the same device name, the SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +When `Time` is the main sort key, the result set is sorted by timestamp first, then by device name in data points with the same timestamp. The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +When `ORDER BY` clause is not used, sort in default way, the SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +The result below indicates `ORDER BY DEVICE ASC,TIME ASC` is the clause in default situation. +`ASC` can be omitted because it's the default ordering. + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +Besides,`ALIGN BY DEVICE` and `ORDER BY` clauses can be used with aggregate query,the SQL statement is: + +```sql +select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` + +The result shows below: + +``` ++-----------------------------+-----------------+---------------+-------------+------------------+ +| Time| Device|count(hardware)|count(status)|count(temperature)| ++-----------------------------+-----------------+---------------+-------------+------------------+ +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| 1| 1| +|2017-11-01T00:02:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:03:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| 1| 1| null| +|2017-11-01T00:02:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| +|2017-11-01T00:03:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| ++-----------------------------+-----------------+---------------+-------------+------------------+ +``` + +### 8.3 Order by arbitrary expressions + +In addition to the predefined keywords "Time" and "Device" in IoTDB, `ORDER BY` can also be used to sort by any expressions. + +When sorting, `ASC` or `DESC` can be used to specify the sorting order, and `NULLS` syntax is supported to specify the priority of NULL values in the sorting. By default, `NULLS FIRST` places NULL values at the top of the result, and `NULLS LAST` ensures that NULL values appear at the end of the result. If not specified in the clause, the default order is ASC with NULLS LAST. + +Here are several examples of queries for sorting arbitrary expressions using the following data: + +``` ++-----------------------------+-------------+-------+-------+--------+-------+ +| Time| Device| base| score| bonus| total| ++-----------------------------+-------------+-------+-------+--------+-------+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0| 107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0| 105.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0| 103.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00| root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.020+08:00| root.three| 8| null| 22.5| 30.5| +|1970-01-01T08:00:00.030+08:00| root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0| 104.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0| 102.0| ++-----------------------------+-------------+-------+-------+--------+-------+ +``` + +When you need to sort the results based on the base score score, you can use the following SQL: + +```Sql +select score from root.** order by score desc align by device +``` + +This will give you the following results: + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +If you want to sort the results based on the total score, you can use an expression in the `ORDER BY` clause to perform the calculation: + +```Sql +select score,total from root.one order by base+score+bonus desc +``` + +This SQL is equivalent to: + +```Sql +select score,total from root.one order by total desc +``` + +Here are the results: + +``` ++-----------------------------+--------------+--------------+ +| Time|root.one.score|root.one.total| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.000+08:00| 50.0| 107.0| +|1970-01-02T08:00:00.000+08:00| 50.0| 105.0| +|1970-01-03T08:00:00.000+08:00| 50.0| 103.0| ++-----------------------------+--------------+--------------+ +``` + +If you want to sort the results based on the total score and, in case of tied scores, sort by score, base, bonus, and submission time in descending order, you can specify multiple layers of sorting using multiple expressions: + +```Sql +select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +``` + +Here are the results: + +``` ++-----------------------------+----------+----+-----+-----+-----+ +| Time| Device|base|score|bonus|total| ++-----------------------------+----------+----+-----+-----+-----+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0|107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0|105.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0|104.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0|103.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0|102.0| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.000+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00|root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.030+08:00|root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.020+08:00|root.three| 8| null| 22.5| 30.5| ++-----------------------------+----------+----+-----+-----+-----+ +``` + +In the `ORDER BY` clause, you can also use aggregate query expressions. For example: + +```Sql +select min_value(total) from root.** order by min_value(total) asc align by device +``` + +This will give you the following results: + +``` ++----------+----------------+ +| Device|min_value(total)| ++----------+----------------+ +|root.three| 30.5| +| root.two| 33.0| +| root.four| 85.0| +| root.five| 102.0| +| root.one| 103.0| ++----------+----------------+ +``` + +When specifying multiple columns in the query, the unsorted columns will change order along with the rows and sorted columns. The order of rows when the sorting columns are the same may vary depending on the specific implementation (no fixed order). For example: + +```Sql +select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +``` + +This will give you the following results: +· + +``` ++----------+----------------+---------------+ +| Device|min_value(total)|max_value(base)| ++----------+----------------+---------------+ +| root.one| 103.0| 12| +| root.five| 102.0| 7| +| root.four| 85.0| 9| +| root.two| 33.0| 9| +|root.three| 30.5| 9| ++----------+----------------+---------------+ +``` + +You can use both `ORDER BY DEVICE,TIME` and `ORDER BY EXPRESSION` together. For example: + +```Sql +select score from root.** order by device asc, score desc, time asc align by device +``` + +This will give you the following results: + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +## 9. `ALIGN BY` CLAUSE + +In addition, IoTDB supports another result set format: `ALIGN BY DEVICE`. + +### 9.1 Align by Device + +The `ALIGN BY DEVICE` indicates that the deviceId is considered as a column. Therefore, there are totally limited columns in the dataset. + +> NOTE: +> +> 1.You can see the result of 'align by device' as one relational table, `Time + Device` is the primary key of this Table. +> +> 2.The result is order by `Device` firstly, and then by `Time` order. + +The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+-----------+------+--------+ +| Time| Device|temperature|status|hardware| ++-----------------------------+-----------------+-----------+------+--------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| 25.96| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| 24.36| true| null| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| null| true| v1| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| null| false| v2| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| null| true| v2| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| null| true| v2| ++-----------------------------+-----------------+-----------+------+--------+ +Total line number = 6 +It costs 0.012s +``` + +### 9.2 Ordering in ALIGN BY DEVICE + +ALIGN BY DEVICE mode arranges according to the device first, and sort each device in ascending order according to the timestamp. The ordering and priority can be adjusted through `ORDER BY` clause. + +## 10. `INTO` CLAUSE (QUERY WRITE-BACK) + +The `SELECT INTO` statement copies data from query result set into target time series. + +The application scenarios are as follows: + +- **Implement IoTDB internal ETL**: ETL the original data and write a new time series. +- **Query result storage**: Persistently store the query results, which acts like a materialized view. +- **Non-aligned time series to aligned time series**: Rewrite non-aligned time series into another aligned time series. + +### 10.1 SQL Syntax + +#### Syntax Definition + +**The following is the syntax definition of the `select` statement:** + +```sql +selectIntoStatement +: SELECT + resultColumn [, resultColumn] ... + INTO intoItem [, intoItem] ... + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY groupByTimeClause, groupByLevelClause] + [FILL {PREVIOUS | LINEAR | constant}] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] +; + +intoItem +: [ALIGNED] intoDevicePath '(' intoMeasurementName [',' intoMeasurementName]* ')' + ; +``` + +#### `INTO` Clause + +The `INTO` clause consists of several `intoItem`. + +Each `intoItem` consists of a target device and a list of target measurements (similar to the `INTO` clause in an `INSERT` statement). + +Each target measurement and device form a target time series, and an `intoItem` contains a series of time series. For example: `root.sg_copy.d1(s1, s2)` specifies two target time series `root.sg_copy.d1.s1` and `root.sg_copy.d1.s2`. + +The target time series specified by the `INTO` clause must correspond one-to-one with the columns of the query result set. The specific rules are as follows: + +- **Align by time** (default): The number of target time series contained in all `intoItem` must be consistent with the number of columns in the query result set (except the time column) and correspond one-to-one in the order from left to right in the header. +- **Align by device** (using `ALIGN BY DEVICE`): the number of target devices specified in all `intoItem` is the same as the number of devices queried (i.e., the number of devices matched by the path pattern in the `FROM` clause), and One-to-one correspondence according to the output order of the result set device. +
The number of measurements specified for each target device should be consistent with the number of columns in the query result set (except for the time and device columns). It should be in one-to-one correspondence from left to right in the header. + +For examples: + +- **Example 1** (aligned by time) + +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; ++--------------+-------------------+--------+ +| source column| target timeseries| written| ++--------------+-------------------+--------+ +| root.sg.d1.s1| root.sg_copy.d1.t1| 8000| ++--------------+-------------------+--------+ +| root.sg.d2.s1| root.sg_copy.d2.t1| 10000| ++--------------+-------------------+--------+ +| root.sg.d1.s2| root.sg_copy.d2.t2| 12000| ++--------------+-------------------+--------+ +| root.sg.d2.s2| root.sg_copy.d1.t2| 10000| ++--------------+-------------------+--------+ +Total line number = 4 +It costs 0.725s +``` + +This statement writes the query results of the four time series under the `root.sg` database to the four specified time series under the `root.sg_copy` database. Note that `root.sg_copy.d2(t1, t2)` can also be written as `root.sg_copy.d2(t1), root.sg_copy.d2(t2)`. + +We can see that the writing of the `INTO` clause is very flexible as long as the combined target time series is not repeated and corresponds to the query result column one-to-one. + +> In the result set displayed by `CLI`, the meaning of each column is as follows: +> +> - The `source column` column represents the column name of the query result. +> - `target timeseries` represents the target time series for the corresponding column to write. +> - `written` indicates the amount of data expected to be written. + + +- **Example 2** (aligned by time) + +```shell +IoTDB> select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); ++--------------------------------------+-------------------------+--------+ +| source column| target timeseries| written| ++--------------------------------------+-------------------------+--------+ +| count(root.sg.d1.s1 + root.sg.d1.s2)| root.agg.count.s1_add_s2| 10| ++--------------------------------------+-------------------------+--------+ +| last_value(root.sg.d1.s2)| root.agg.last_value.s2| 10| ++--------------------------------------+-------------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +This statement stores the results of an aggregated query into the specified time series. + +- **Example 3** (aligned by device) + +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+-------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s1| root.sg_copy.d1.t1| 8000| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s2| root.sg_copy.d1.t2| 11000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s1| root.sg_copy.d2.t1| 12000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s2| root.sg_copy.d2.t2| 9000| ++--------------+--------------+-------------------+--------+ +Total line number = 4 +It costs 0.625s +``` + +This statement also writes the query results of the four time series under the `root.sg` database to the four specified time series under the `root.sg_copy` database. However, in ALIGN BY DEVICE, the number of `intoItem` must be the same as the number of queried devices, and each queried device corresponds to one `intoItem`. + +> When aligning the query by device, the result set displayed by `CLI` has one more column, the `source device` column indicating the queried device. + +- **Example 4** (aligned by device) + +```shell +IoTDB> select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+------------------------+--------+ +| root.sg.d1| s1 + s2| root.expr.add.d1s1_d1s2| 10000| ++--------------+--------------+------------------------+--------+ +| root.sg.d2| s1 + s2| root.expr.add.d2s1_d2s2| 10000| ++--------------+--------------+------------------------+--------+ +Total line number = 2 +It costs 0.532s +``` + +This statement stores the result of evaluating an expression into the specified time series. + +#### Using variable placeholders + +In particular, We can use variable placeholders to describe the correspondence between the target and query time series, simplifying the statement. The following two variable placeholders are currently supported: + +- Suffix duplication character `::`: Copy the suffix (or measurement) of the query device, indicating that from this layer to the last layer (or measurement) of the device, the node name (or measurement) of the target device corresponds to the queried device The node name (or measurement) is the same. +- Single-level node matcher `${i}`: Indicates that the current level node name of the target sequence is the same as the i-th level node name of the query sequence. For example, for the path `root.sg1.d1.s1`, `${1}` means `sg1`, `${2}` means `d1`, and `${3}` means `s1`. + +When using variable placeholders, there must be no ambiguity in the correspondence between `intoItem` and the columns of the query result set. The specific cases are classified as follows: + +##### ALIGN BY TIME (default) + +> Note: The variable placeholder **can only describe the correspondence between time series**. If the query includes aggregation and expression calculation, the columns in the query result cannot correspond to a time series, so neither the target device nor the measurement can use variable placeholders. + +###### (1) The target device does not use variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** + +1. In each `intoItem`, the length of the list of physical quantities must be 1.
(If the length can be greater than 1, e.g. `root.sg1.d1(::, s1)`, it is not possible to determine which columns match `::`) +2. The number of `intoItem` is 1, or the same as the number of columns in the query result set.
(When the length of each target measurement list is 1, if there is only one `intoItem`, it means that all the query sequences are written to the same device; if the number of `intoItem` is consistent with the query sequence, it is expressed as each query time series specifies a target device; if `intoItem` is greater than one and less than the number of query sequences, it cannot be a one-to-one correspondence with the query sequence) + +**Matching method:** Each query time series specifies the target device, and the target measurement is generated from the variable placeholder. + +**Example:** + +```sql +select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; +```` + +This statement is equivalent to: + +```sql +select s1, s2 +into root.sg_copy.d1(s1), root.sg_copy.d2(s1), root.sg_copy.d1(s2), root.sg_copy.d2(s2) +from root.sg.d1, root.sg.d2; +```` + +As you can see, the statement is not very simplified in this case. + +###### (2) The target device uses variable placeholders & the target measurement list does not use variable placeholders + +**Limitations:** The number of target measurements in all `intoItem` is the same as the number of columns in the query result set. + +**Matching method:** The target measurement is specified for each query time series, and the target device is generated according to the target device placeholder of the `intoItem` where the corresponding target measurement is located. + +**Example:** + +```sql +select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; +```` + +###### (3) The target device uses variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** There is only one `intoItem`, and the length of the list of measurement list is 1. + +**Matching method:** Each query time series can get a target time series according to the variable placeholder. + +**Example:** + +```sql +select * into root.sg_bk.::(::) from root.sg.**; +```` + +Write the query results of all time series under `root.sg` to `root.sg_bk`, the device name suffix and measurement remain unchanged. + +##### ALIGN BY DEVICE + +> Note: The variable placeholder **can only describe the correspondence between time series**. If the query includes aggregation and expression calculation, the columns in the query result cannot correspond to a specific physical quantity, so the target measurement cannot use variable placeholders. + +###### (1) The target device does not use variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** In each `intoItem`, if the list of measurement uses variable placeholders, the length of the list must be 1. + +**Matching method:** Each query time series specifies the target device, and the target measurement is generated from the variable placeholder. + +**Example:** + +```sql +select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; +```` + +###### (2) The target device uses variable placeholders & the target measurement list does not use variable placeholders + +**Limitations:** There is only one `intoItem`. (If there are multiple `intoItem` with placeholders, we will not know which source devices each `intoItem` needs to match) + +**Matching method:** Each query device obtains a target device according to the variable placeholder, and the target measurement written in each column of the result set under each device is specified by the target measurement list. + +**Example:** + +```sql +select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; +```` + +###### (3) The target device uses variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** There is only one `intoItem` and the length of the target measurement list is 1. + +**Matching method:** Each query time series can get a target time series according to the variable placeholder. + +**Example:** + +```sql +select * into ::(backup_${4}) from root.sg.** align by device; +```` + +Write the query result of each time series in `root.sg` to the same device, and add `backup_` before the measurement. + +#### Specify the target time series as the aligned time series + +We can use the `ALIGNED` keyword to specify the target device for writing to be aligned, and each `intoItem` can be set independently. + +**Example:** + +```sql +select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` + +This statement specifies that `root.sg_copy.d1` is an unaligned device and `root.sg_copy.d2` is an aligned device. + +#### Unsupported query clauses + +- `SLIMIT`, `SOFFSET`: The query columns are uncertain, so they are not supported. +- `LAST`, `GROUP BY TAGS`, `DISABLE ALIGN`: The table structure is inconsistent with the writing structure, so it is not supported. + +#### Other points to note + +- For general aggregation queries, the timestamp is meaningless, and the convention is to use 0 to store. +- When the target time-series exists, the data type of the source column and the target time-series must be compatible. About data type compatibility, see the document [Data Type](../Background-knowledge/Data-Type.md#Data Type Compatibility). +- When the target time series does not exist, the system automatically creates it (including the database). +- When the queried time series does not exist, or the queried sequence does not have data, the target time series will not be created automatically. + +### 10.2 Application examples + +#### Implement IoTDB internal ETL + +ETL the original data and write a new time series. + +```shell +IOTDB > SELECT preprocess_udf(s1, s2) INTO ::(preprocessed_s1, preprocessed_s2) FROM root.sg.* ALIGN BY DEIVCE; ++--------------+-------------------+---------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s1)| root.sg.d1.preprocessed_s1| 8000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s2)| root.sg.d1.preprocessed_s2| 10000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s1)| root.sg.d2.preprocessed_s1| 11000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s2)| root.sg.d2.preprocessed_s2| 9000| ++--------------+-------------------+---------------------------+--------+ +``` + +#### Query result storage + +Persistently store the query results, which acts like a materialized view. + +```shell +IOTDB > SELECT count(s1), last_value(s1) INTO root.sg.agg_${2}(count_s1, last_value_s1) FROM root.sg1.d1 GROUP BY ([0, 10000), 10ms); ++--------------------------+-----------------------------+--------+ +| source column| target timeseries| written| ++--------------------------+-----------------------------+--------+ +| count(root.sg.d1.s1)| root.sg.agg_d1.count_s1| 1000| ++--------------------------+-----------------------------+--------+ +| last_value(root.sg.d1.s2)| root.sg.agg_d1.last_value_s2| 1000| ++--------------------------+-----------------------------+--------+ +Total line number = 2 +It costs 0.115s +``` + +#### Non-aligned time series to aligned time series + +Rewrite non-aligned time series into another aligned time series. + +**Note:** It is recommended to use the `LIMIT & OFFSET` clause or the `WHERE` clause (time filter) to batch data to prevent excessive data volume in a single operation. + +```shell +IOTDB > SELECT s1, s2 INTO ALIGNED root.sg1.aligned_d(s1, s2) FROM root.sg1.non_aligned_d WHERE time >= 0 and time < 10000; ++--------------------------+----------------------+--------+ +| source column| target timeseries| written| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s1| root.sg1.aligned_d.s1| 10000| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s2| root.sg1.aligned_d.s2| 10000| ++--------------------------+----------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +### 10.3 User Permission Management + +The user must have the following permissions to execute a query write-back statement: + +* All `WRITE_SCHEMA` permissions for the source series in the `select` clause. +* All `WRITE_DATA` permissions for the target series in the `into` clause. + +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_timecho). + +### 10.4 Configurable Properties + +* `select_into_insert_tablet_plan_row_limit`: The maximum number of rows can be processed in one insert-tablet-plan when executing select-into statements. 10000 by default. diff --git a/src/UserGuide/latest/Basic-Concept/Write-Data.md b/src/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md similarity index 89% rename from src/UserGuide/latest/Basic-Concept/Write-Data.md rename to src/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md index 5709e15da..35ebef8b5 100644 --- a/src/UserGuide/latest/Basic-Concept/Write-Data.md +++ b/src/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md @@ -23,15 +23,15 @@ # Write Data ## 1. CLI INSERT -IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC.md) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual.md). +IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC_apache) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache). -NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) for real-time data import in the scenario. +NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) for real-time data import in the scenario. Writing a repeat timestamp covers the original timestamp data, which can be regarded as updated data. ### 1.1 Use of INSERT Statements -The [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). +The [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). In the scenario of this section, take two timeseries `root.ln.wf02.wt02.status` and `root.ln.wf02.wt02.hardware` as an example, and their data types are BOOLEAN and TEXT, respectively. @@ -122,12 +122,12 @@ The Native API ( Session ) is the most widely used series of APIs of IoTDB, incl #### Java -Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API.md). -then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API.md#insert) +Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API_apache). +then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API_apache#insert) #### Python -Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API.md#insert) +Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API_apache#insert) #### C++ @@ -139,7 +139,7 @@ Refer to [Go Native API](../API/Programming-Go-Native-API.md) ## 3. REST API WRITE -Refer to [insertTablet (v1)](../API/RestServiceV1.md#inserttablet) or [insertTablet (v2)](../API/RestServiceV2.md#inserttablet) +Refer to [insertTablet (v1)](../API/RestServiceV1_apache#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_apache#inserttablet) Example: @@ -185,11 +185,11 @@ In different scenarios, the IoTDB provides a variety of methods for importing da ### 5.1 TsFile Batch Load -TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool.md). +TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool_apache). ### 5.2 CSV Batch Load -CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool.md). +CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool_apache). ## 6. SCHEMALESS WRITING In IoT scenarios, the types and quantities of devices may dynamically increase or decrease over time, and different devices may generate data with varying fields (e.g., temperature, humidity, status codes). Additionally, businesses often require rapid deployment and flexible integration of new devices without cumbersome predefined processes. Therefore, unlike traditional time-series databases that typically require predefining data models, IoTDB supports schema-less writing, where the database automatically identifies and registers the necessary metadata during data writing, enabling automatic modeling. diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md b/src/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md new file mode 100644 index 000000000..380ab5037 --- /dev/null +++ b/src/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md @@ -0,0 +1,200 @@ + + + +# Write Data +## 1. CLI INSERT + +IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC_timecho) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho). + +NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) for real-time data import in the scenario. + +Writing a repeat timestamp covers the original timestamp data, which can be regarded as updated data. + +### 1.1 Use of INSERT Statements + +The [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). + +In the scenario of this section, take two timeseries `root.ln.wf02.wt02.status` and `root.ln.wf02.wt02.hardware` as an example, and their data types are BOOLEAN and TEXT, respectively. + +The sample code for single column data insertion is as follows: + +``` +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +The above example code inserts the long integer timestamp and the value "true" into the timeseries `root.ln.wf02.wt02.status` and inserts the long integer timestamp and the value "v1" into the timeseries `root.ln.wf02.wt02.hardware`. When the execution is successful, cost time is shown to indicate that the data insertion has been completed. + +> Note: In IoTDB, TEXT type data can be represented by single and double quotation marks. The insertion statement above uses double quotation marks for TEXT type data. The following example will use single quotation marks for TEXT type data. + +The INSERT statement can also support the insertion of multi-column data at the same time point. The sample code of inserting the values of the two timeseries at the same time point '2' is as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (2, false, 'v2') +``` + +In addition, The INSERT statement support insert multi-rows at once. The sample code of inserting two rows as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +After inserting the data, we can simply query the inserted data using the SELECT statement: + +```sql +IoTDB > select * from root.ln.wf02.wt02 where time < 5 +``` + +The result is shown below. The query result shows that the insertion statements of single column and multi column data are performed correctly. + +``` ++-----------------------------+--------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status| ++-----------------------------+--------------------------+------------------------+ +|1970-01-01T08:00:00.001+08:00| v1| true| +|1970-01-01T08:00:00.002+08:00| v2| false| +|1970-01-01T08:00:00.003+08:00| v3| false| +|1970-01-01T08:00:00.004+08:00| v4| true| ++-----------------------------+--------------------------+------------------------+ +Total line number = 4 +It costs 0.004s +``` + +In addition, we can omit the timestamp column, and the system will use the current system timestamp as the timestamp of the data point. The sample code is as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` + +**Note:** Timestamps must be specified when inserting multiple rows of data in a SQL. + +### 1.2 Insert Data Into Aligned Timeseries + +To insert data into a group of aligned time series, we only need to add the `ALIGNED` keyword in SQL, and others are similar. + +The sample code is as follows: + +```sql +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +The result is shown below. The query result shows that the insertion statements are performed correctly. + +``` ++-----------------------------+--------------+--------------+ +| Time|root.sg1.d1.s1|root.sg1.d1.s2| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.001+08:00| 1| 1.0| +|1970-01-01T08:00:00.002+08:00| 2| 2.0| +|1970-01-01T08:00:00.003+08:00| 3| 3.0| ++-----------------------------+--------------+--------------+ +Total line number = 3 +It costs 0.004s +``` + +## 2. NATIVE API WRITE + +The Native API ( Session ) is the most widely used series of APIs of IoTDB, including multiple APIs, adapted to different data collection scenarios, with high performance and multi-language support. + +### 2.1 Multi-language API write + +#### Java + +Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API_timecho). +then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API_timecho#insert) + +#### Python + +Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API_timecho#insert) + +#### C++ + +Refer to [ C++ Data Manipulation Interface (DML) ](../API/Programming-Cpp-Native-API.md#insert) + +#### Go + +Refer to [Go Native API](../API/Programming-Go-Native-API.md) + +## 3. REST API WRITE + +Refer to [insertTablet (v1)](../API/RestServiceV1_timecho#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_timecho#inserttablet) + +Example: + +```JSON +{ +      "timestamps": [ +            1, +            2, +            3 +      ], +      "measurements": [ +            "temperature", +            "status" +      ], +      "data_types": [ +            "FLOAT", +            "BOOLEAN" +      ], +      "values": [ +            [ +                  1.1, +                  2.2, +                  3.3 +            ], +            [ +                  false, +                  true, +                  true +            ] +      ], +      "is_aligned": false, +      "device": "root.ln.wf01.wt01" +} +``` + +## 4. MQTT WRITE + +Refer to [Built-in MQTT Service](../API/Programming-MQTT.md#built-in-mqtt-service) + +## 5. BATCH DATA LOAD + +In different scenarios, the IoTDB provides a variety of methods for importing data in batches. This section describes the two most common methods for importing data in CSV format and TsFile format. + +### 5.1 TsFile Batch Load + +TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool_timecho). + +### 5.2 CSV Batch Load + +CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool_timecho). + +## 6. SCHEMALESS WRITING +In IoT scenarios, the types and quantities of devices may dynamically increase or decrease over time, and different devices may generate data with varying fields (e.g., temperature, humidity, status codes). Additionally, businesses often require rapid deployment and flexible integration of new devices without cumbersome predefined processes. Therefore, unlike traditional time-series databases that typically require predefining data models, IoTDB supports schema-less writing, where the database automatically identifies and registers the necessary metadata during data writing, enabling automatic modeling. + +Users can either use CLI `INSERT` statements or native APIs to write data in real-time, either in batches or row-by-row, for single or multiple devices. Alternatively, they can import historical data in formats such as CSV or TsFile using import tools, during which metadata like time series, data types, and compression encoding methods are automatically created. + + + diff --git a/src/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md b/src/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md index ea209fa53..131c0b882 100644 --- a/src/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md +++ b/src/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md @@ -53,9 +53,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Introduction to SQL syntax[SQL syntax](../Basic-Concept/Operate-Metadata_apache.md) -2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data) +2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data_apache) -3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data.md) +3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data_apache) 4. Other advanced features: In addition to common functions such as writing and querying in databases, IoTDB also supports "Data Synchronisation、Stream Framework、Database Administration " and other functions, specific usage methods can be found in the specific document: @@ -63,9 +63,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Stream Framework: [Stream Framework](../User-Manual/Streaming_apache.md) - - Authority Management:[Authority Management](../User-Manual/Authority-Management.md) + - Authority Management:[Authority Management](../User-Manual/Authority-Management_apache) -5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports [Java Native API](../API/Programming-Java-Native-API.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[C++ Native API](../API/Programming-Cpp-Native-API.md) ,For more API, please refer to the official website 【API】 and other chapters +5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports [Java Native API](../API/Programming-Java-Native-API_apache)、[Python Native API](../API/Programming-Python-Native-API_apache)、[C++ Native API](../API/Programming-Cpp-Native-API.md) ,For more API, please refer to the official website 【API】 and other chapters ## 3. What other convenient tools are available? @@ -73,9 +73,9 @@ In addition to its rich features, IoTDB also has a comprehensive range of tools - Benchmark Tool: IoT benchmark is a time series database benchmark testing tool developed based on Java and big data environments, developed and open sourced by the School of Software at Tsinghua University. It supports multiple writing and querying methods, can store test information and results for further query or analysis, and supports integration with Tableau to visualize test results. For specific usage instructions, please refer to: [Benchmark Tool](../Tools-System/Benchmark.md) - - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool.md) + - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool_apache) - - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool.md) + - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool_apache) ## 4. Want to Learn More About the Technical Details? diff --git a/src/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md b/src/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md index 47b6e7d76..89e04adc7 100644 --- a/src/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md +++ b/src/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md @@ -60,9 +60,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Introduction to SQL syntax[SQL syntax](../Basic-Concept/Operate-Metadata_timecho.md) -2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data) +2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data_timecho) -3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data.md) +3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data_timecho) 4. Other advanced features: In addition to common functions such as writing and querying in databases, IoTDB also supports "Data Synchronisation、Stream Framework、Security Management、Database Administration、AI Capability"and other functions, specific usage methods can be found in the specific document: @@ -72,11 +72,11 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Security Management: [Security Management](../User-Manual/White-List_timecho.md) - - Database Administration: [Database Administration](../User-Manual/Authority-Management.md) + - Database Administration: [Database Administration](../User-Manual/Authority-Management_timecho) - AI Capability :[AI Capability](../AI-capability/AINode_timecho.md) -5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports[ Java Native API](../API/Programming-Java-Native-API.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[C++ Native API](../API/Programming-Cpp-Native-API.md)、[Go Native API](../API/Programming-Go-Native-API.md), For more API, please refer to the official website 【API】 and other chapters +5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports[ Java Native API](../API/Programming-Java-Native-API_timecho)、[Python Native API](../API/Programming-Python-Native-API_timecho)、[C++ Native API](../API/Programming-Cpp-Native-API.md)、[Go Native API](../API/Programming-Go-Native-API.md), For more API, please refer to the official website 【API】 and other chapters ## 3. What other convenient tools are available? @@ -88,9 +88,9 @@ In addition to its rich features, IoTDB also has a comprehensive range of tools - Benchmark Tool: IoT benchmark is a time series database benchmark testing tool developed based on Java and big data environments, developed and open sourced by the School of Software at Tsinghua University. It supports multiple writing and querying methods, can store test information and results for further query or analysis, and supports integration with Tableau to visualize test results. For specific usage instructions, please refer to: [Benchmark Tool](../Tools-System/Benchmark.md) - - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool.md) + - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool_timecho) - - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool.md) + - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool_timecho) ## 4. Want to Learn More About the Technical Details? diff --git a/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual.md b/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual.md rename to src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_apache.md index 194ef0ccd..fccf82926 100644 --- a/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual.md +++ b/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_apache.md @@ -409,7 +409,7 @@ IoTDB> count devices root.ln.** ### 5.1 Insert Data -For more details, see document [Write-Data](../Basic-Concept/Write-Data). +For more details, see document [Write-Data](../Basic-Concept/Write-Data_apache). #### Use of INSERT Statements @@ -444,7 +444,7 @@ IoTDB > select * from root.sg1.d1 ### 5.2 Load External TsFile Tool -For more details, see document [Data Import](../Tools-System/Data-Import-Tool.md). +For more details, see document [Data Import](../Tools-System/Data-Import-Tool_apache). #### Load with SQL @@ -471,7 +471,7 @@ For more details, see document [Data Import](../Tools-System/Data-Import-Tool.md ## 6. DELETE DATA -For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data). +For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data_apache). ### 6.1 Delete Single Timeseries @@ -508,7 +508,7 @@ IoTDB > DELETE PARTITION root.ln 0,1,2 ## 7. QUERY DATA -For more details, see document [Query-Data](../Basic-Concept/Query-Data.md). +For more details, see document [Query-Data](../Basic-Concept/Query-Data_apache). ```sql SELECT [LAST] selectExpr [, selectExpr] ... diff --git a/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_timecho.md b/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_timecho.md new file mode 100644 index 000000000..a46f271c3 --- /dev/null +++ b/src/UserGuide/Master/Tree/SQL-Manual/SQL-Manual_timecho.md @@ -0,0 +1,1759 @@ + + +# SQL Manual + +## 1. DATABASE MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 1.1 Create Database + +```sql +IoTDB > create database root.ln +IoTDB > create database root.sgcc +``` + +### 1.2 Show Databases + +```sql +IoTDB> SHOW DATABASES +IoTDB> SHOW DATABASES root.** +``` + +### 1.3 Delete Database + +```sql +IoTDB > DELETE DATABASE root.ln +IoTDB > DELETE DATABASE root.sgcc +// delete all data, all timeseries and all databases +IoTDB > DELETE DATABASE root.** +``` + +### 1.4 Count Databases + +```sql +IoTDB> count databases +IoTDB> count databases root.* +IoTDB> count databases root.sgcc.* +IoTDB> count databases root.sgcc +``` + +### 1.5 Setting up heterogeneous databases (Advanced operations) + +#### Set heterogeneous parameters when creating a Database + +```sql +CREATE DATABASE root.db WITH SCHEMA_REPLICATION_FACTOR=1, DATA_REPLICATION_FACTOR=3, SCHEMA_REGION_GROUP_NUM=1, DATA_REGION_GROUP_NUM=2; +``` + +#### Adjust heterogeneous parameters at run time + +```sql +ALTER DATABASE root.db WITH SCHEMA_REGION_GROUP_NUM=1, DATA_REGION_GROUP_NUM=2; +``` + +#### Show heterogeneous databases + +```sql +SHOW DATABASES DETAILS +``` + +### 1.6 TTL + +#### Set TTL + +```sql +IoTDB> set ttl to root.ln 3600000 +IoTDB> set ttl to root.sgcc.** 3600000 +IoTDB> set ttl to root.** 3600000 +``` + +#### Unset TTL + +```sql +IoTDB> unset ttl from root.ln +IoTDB> unset ttl from root.sgcc.** +IoTDB> unset ttl from root.** +``` + +#### Show TTL + +```sql +IoTDB> SHOW ALL TTL +IoTDB> SHOW TTL ON StorageGroupNames +IoTDB> SHOW DEVICES +``` + +## 2. DEVICE TEMPLATE + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +![img](/img/%E6%A8%A1%E6%9D%BF.png) + + + + + +![img](/img/templateEN.jpg) + +### 2.1 Create Device Template + +**Example 1:** Create a template containing two non-aligned timeseires + +```shell +IoTDB> create device template t1 (temperature FLOAT, status BOOLEAN) +``` + +**Example 2:** Create a template containing a group of aligned timeseires + +```shell +IoTDB> create device template t2 aligned (lat FLOAT, lon FLOAT) +``` + +The` lat` and `lon` measurements are aligned. + +### 2.2 Set Device Template + +```sql +IoTDB> set device template t1 to root.sg1.d1 +``` + +### 2.3 Activate Device Template + +```sql +IoTDB> set device template t1 to root.sg1.d1 +IoTDB> set device template t2 to root.sg1.d2 +IoTDB> create timeseries using device template on root.sg1.d1 +IoTDB> create timeseries using device template on root.sg1.d2 +``` + +### 2.4 Show Device Template + +```sql +IoTDB> show device templates +IoTDB> show nodes in device template t1 +IoTDB> show paths set device template t1 +IoTDB> show paths using device template t1 +``` + +### 2.5 Deactivate Device Template + +```sql +IoTDB> delete timeseries of device template t1 from root.sg1.d1 +IoTDB> deactivate device template t1 from root.sg1.d1 +IoTDB> delete timeseries of device template t1 from root.sg1.*, root.sg2.* +IoTDB> deactivate device template t1 from root.sg1.*, root.sg2.* +``` + +### 2.6 Unset Device Template + +```sql +IoTDB> unset device template t1 from root.sg1.d1 +``` + +### 2.7 Drop Device Template + +```sql +IoTDB> drop device template t1 +``` + +### 2.8 Alter Device Template + +```sql +IoTDB> alter device template t1 add (speed FLOAT) +``` + +## 3. TIMESERIES MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 3.1 Create Timeseries + +```sql +IoTDB > create timeseries root.ln.wf01.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.ln.wf01.wt01.temperature with datatype=FLOAT +IoTDB > create timeseries root.ln.wf02.wt02.hardware with datatype=TEXT +IoTDB > create timeseries root.ln.wf02.wt02.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.temperature with datatype=FLOAT +``` + +- From v0.13, you can use a simplified version of the SQL statements to create timeseries: + +```sql +IoTDB > create timeseries root.ln.wf01.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.ln.wf01.wt01.temperature with datatype=FLOAT +IoTDB > create timeseries root.ln.wf02.wt02.hardware with datatype=TEXT +IoTDB > create timeseries root.ln.wf02.wt02.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.temperature with datatype=FLOAT +``` + +- Notice that when in the CREATE TIMESERIES statement the encoding method conflicts with the data type, the system gives the corresponding error prompt as shown below: + +```sql +IoTDB > create timeseries root.ln.wf02.wt02.status WITH DATATYPE=BOOLEAN +error: encoding TS_2DIFF does not support BOOLEAN +``` + +### 3.2 Create Aligned Timeseries + +```sql +IoTDB> CREATE ALIGNED TIMESERIES root.ln.wf01.GPS(latitude FLOAT , longitude FLOAT) +``` + +### 3.3 Delete Timeseries + +```sql +IoTDB> delete timeseries root.ln.wf01.wt01.status +IoTDB> delete timeseries root.ln.wf01.wt01.temperature, root.ln.wf02.wt02.hardware +IoTDB> delete timeseries root.ln.wf02.* +IoTDB> drop timeseries root.ln.wf02.* +``` + +### 3.4 Show Timeseries + +```sql +IoTDB> show timeseries root.** +IoTDB> show timeseries root.ln.** +IoTDB> show timeseries root.ln.** limit 10 offset 10 +IoTDB> show timeseries root.ln.** where timeseries contains 'wf01.wt' +IoTDB> show timeseries root.ln.** where dataType=FLOAT +``` + +### 3.5 Count Timeseries + +```sql +IoTDB > COUNT TIMESERIES root.** +IoTDB > COUNT TIMESERIES root.ln.** +IoTDB > COUNT TIMESERIES root.ln.*.*.status +IoTDB > COUNT TIMESERIES root.ln.wf01.wt01.status +IoTDB > COUNT TIMESERIES root.** WHERE TIMESERIES contains 'sgcc' +IoTDB > COUNT TIMESERIES root.** WHERE DATATYPE = INT64 +IoTDB > COUNT TIMESERIES root.** WHERE TAGS(unit) contains 'c' +IoTDB > COUNT TIMESERIES root.** WHERE TAGS(unit) = 'c' +IoTDB > COUNT TIMESERIES root.** WHERE TIMESERIES contains 'sgcc' group by level = 1 +IoTDB > COUNT TIMESERIES root.** GROUP BY LEVEL=1 +IoTDB > COUNT TIMESERIES root.ln.** GROUP BY LEVEL=2 +IoTDB > COUNT TIMESERIES root.ln.wf01.* GROUP BY LEVEL=2 +``` + +### 3.6 Tag and Attribute Management + +```sql +create timeseries root.turbine.d1.s1(temprature) with datatype=FLOAT tags(tag1=v1, tag2=v2) attributes(attr1=v1, attr2=v2) +``` + +* Rename the tag/attribute key + +```SQL +ALTER timeseries root.turbine.d1.s1 RENAME tag1 TO newTag1 +``` + +* Reset the tag/attribute value + +```SQL +ALTER timeseries root.turbine.d1.s1 SET newTag1=newV1, attr1=newV1 +``` + +* Delete the existing tag/attribute + +```SQL +ALTER timeseries root.turbine.d1.s1 DROP tag1, tag2 +``` + +* Add new tags + +```SQL +ALTER timeseries root.turbine.d1.s1 ADD TAGS tag3=v3, tag4=v4 +``` + +* Add new attributes + +```SQL +ALTER timeseries root.turbine.d1.s1 ADD ATTRIBUTES attr3=v3, attr4=v4 +``` + +* Upsert alias, tags and attributes + +> add alias or a new key-value if the alias or key doesn't exist, otherwise, update the old one with new value. + +```SQL +ALTER timeseries root.turbine.d1.s1 UPSERT ALIAS=newAlias TAGS(tag3=v3, tag4=v4) ATTRIBUTES(attr3=v3, attr4=v4) +``` + +* Show timeseries using tags. Use TAGS(tagKey) to identify the tags used as filter key + +```SQL +SHOW TIMESERIES (<`PathPattern`>)? timeseriesWhereClause +``` + +returns all the timeseries information that satisfy the where condition and match the pathPattern. SQL statements are as follows: + +```SQL +ALTER timeseries root.ln.wf02.wt02.hardware ADD TAGS unit=c +ALTER timeseries root.ln.wf02.wt02.status ADD TAGS description=test1 +show timeseries root.ln.** where TAGS(unit)='c' +show timeseries root.ln.** where TAGS(description) contains 'test1' +``` + +- count timeseries using tags + +```SQL +COUNT TIMESERIES (<`PathPattern`>)? timeseriesWhereClause +COUNT TIMESERIES (<`PathPattern`>)? timeseriesWhereClause GROUP BY LEVEL= +``` + +returns all the number of timeseries that satisfy the where condition and match the pathPattern. SQL statements are as follows: + +```SQL +count timeseries +count timeseries root.** where TAGS(unit)='c' +count timeseries root.** where TAGS(unit)='c' group by level = 2 +``` + +create aligned timeseries + +```SQL +create aligned timeseries root.sg1.d1(s1 INT32 tags(tag1=v1, tag2=v2) attributes(attr1=v1, attr2=v2), s2 DOUBLE tags(tag3=v3, tag4=v4) attributes(attr3=v3, attr4=v4)) +``` + +The execution result is as follows: + +```SQL +IoTDB> show timeseries ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +| timeseries|alias| database|dataType|encoding|compression| tags| attributes|deadband|deadband parameters| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +|root.sg1.d1.s1| null| root.sg1| INT32| RLE| SNAPPY|{"tag1":"v1","tag2":"v2"}|{"attr2":"v2","attr1":"v1"}| null| null| +|root.sg1.d1.s2| null| root.sg1| DOUBLE| GORILLA| SNAPPY|{"tag4":"v4","tag3":"v3"}|{"attr4":"v4","attr3":"v3"}| null| null| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +``` + +Support query: + +```SQL +IoTDB> show timeseries where TAGS(tag1)='v1' ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +| timeseries|alias| database|dataType|encoding|compression| tags| attributes|deadband|deadband parameters| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +|root.sg1.d1.s1| null| root.sg1| INT32| RLE| SNAPPY|{"tag1":"v1","tag2":"v2"}|{"attr2":"v2","attr1":"v1"}| null| null| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +``` + +The above operations are supported for timeseries tag, attribute updates, etc. + +## 4. NODE MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 4.1 Show Child Paths + +```SQL +SHOW CHILD PATHS pathPattern +``` + +### 4.2 Show Child Nodes + +```SQL +SHOW CHILD NODES pathPattern +``` + +### 4.3 Count Nodes + +```SQL +IoTDB > COUNT NODES root.** LEVEL=2 +IoTDB > COUNT NODES root.ln.** LEVEL=2 +IoTDB > COUNT NODES root.ln.wf01.** LEVEL=3 +IoTDB > COUNT NODES root.**.temperature LEVEL=3 +``` + +### 4.4 Show Devices + +```SQL +IoTDB> show devices +IoTDB> show devices root.ln.** +IoTDB> show devices root.ln.** where device contains 't' +IoTDB> show devices with database +IoTDB> show devices root.ln.** with database +``` + +### 4.5 Count Devices + +```SQL +IoTDB> show devices +IoTDB> count devices +IoTDB> count devices root.ln.** +``` + +## 5. INSERT & LOAD DATA + +### 5.1 Insert Data + +For more details, see document [Write-Data](../Basic-Concept/Write-Data_timecho). + +#### Use of INSERT Statements + +- Insert Single Timeseries + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +- Insert Multiple Timeseries + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (2, false, 'v2') +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +- Use the Current System Timestamp as the Timestamp of the Data Point + +```SQL +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` + +#### Insert Data Into Aligned Timeseries + +```SQL +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +### 5.2 Load External TsFile Tool + +For more details, see document [Data Import](../Tools-System/Data-Import-Tool_timecho). + +#### Load with SQL + +1. Load a single tsfile by specifying a file path (absolute path). + +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile'` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' sglevel=1` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' onSuccess=delete` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' sglevel=1 onSuccess=delete` + + +2. Load a batch of files by specifying a folder path (absolute path). + +- `load '/Users/Desktop/data'` +- `load '/Users/Desktop/data' sglevel=1` +- `load '/Users/Desktop/data' onSuccess=delete` +- `load '/Users/Desktop/data' sglevel=1 onSuccess=delete` + +#### Load with Script + +``` +./load-rewrite.bat -f D:\IoTDB\data -h 192.168.0.101 -p 6667 -u root -pw root +``` + +## 6. DELETE DATA + +For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data_timecho). + +### 6.1 Delete Single Timeseries + +```sql +IoTDB > delete from root.ln.wf02.wt02.status where time<=2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.status where time>=2017-01-01T00:00:00 and time<=2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.status where time < 10 +IoTDB > delete from root.ln.wf02.wt02.status where time <= 10 +IoTDB > delete from root.ln.wf02.wt02.status where time < 20 and time > 10 +IoTDB > delete from root.ln.wf02.wt02.status where time <= 20 and time >= 10 +IoTDB > delete from root.ln.wf02.wt02.status where time > 20 +IoTDB > delete from root.ln.wf02.wt02.status where time >= 20 +IoTDB > delete from root.ln.wf02.wt02.status where time = 20 +IoTDB > delete from root.ln.wf02.wt02.status where time > 4 or time < 0 +Msg: 303: Check metadata error: For delete statement, where clause can only contain atomic +expressions like : time > XXX, time <= XXX, or two atomic expressions connected by 'AND' +IoTDB > delete from root.ln.wf02.wt02.status +``` + +### 6.2 Delete Multiple Timeseries + +```sql +IoTDB > delete from root.ln.wf02.wt02 where time <= 2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.* where time <= 2017-11-01T16:26:00; +IoTDB> delete from root.ln.wf03.wt02.status where time < now() +Msg: The statement is executed successfully. +``` + +### 6.3 Delete Time Partition (experimental) + +```sql +IoTDB > DELETE PARTITION root.ln 0,1,2 +``` + +## 7. QUERY DATA + +For more details, see document [Query-Data](../Basic-Concept/Query-Data_timecho). + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... ) | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ select temperature from root.ln.wf01.wt01 where time < 2017-11-01T00:08:00.000 +``` + +#### Select Multiple Columns of Data Based on a Time Interval + +```sql +IoTDB > select status, temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +#### Select Multiple Columns of Data for the Same Device According to Multiple Time Intervals + +```sql +IoTDB > select status,temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +#### Choose Multiple Columns of Data for Different Devices According to Multiple Time Intervals + +```sql +IoTDB > select wf01.wt01.status,wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +#### Order By Time Query + +```sql +IoTDB > select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +### 7.2 `SELECT` CLAUSE + +#### Use Alias + +```sql +IoTDB > select s1 as temperature, s2 as speed from root.ln.wf01.wt01; +``` + +#### Nested Expressions + +##### Nested Expressions with Time Series Query + +```sql +IoTDB > select a, + b, + ((a + 1) * 2 - 1) % 2 + 1.5, + sin(a + sin(a + sin(b))), + -(a + b) * (sin(a + b) * sin(a + b) + cos(a + b) * cos(a + b)) + 1 +from root.sg1; + +IoTDB > select (a + b) * 2 + sin(a) from root.sg + +IoTDB > select (a + *) / 2 from root.sg1 + +IoTDB > select (a + b) * 3 from root.sg, root.ln +``` + +##### Nested Expressions query with aggregations + +```sql +IoTDB > select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) +from root.ln.wf01.wt01; + +IoTDB > select avg(*), + (avg(*) + 1) * 3 / 2 -1 +from root.sg1 + +IoTDB > select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) as custom_sum +from root.ln.wf01.wt01 +GROUP BY([10, 90), 10ms); +``` + +#### Last Query + +```sql +IoTDB > select last status from root.ln.wf01.wt01 +IoTDB > select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 +IoTDB > select last * from root.ln.wf01.wt01 order by timeseries desc; +IoTDB > select last * from root.ln.wf01.wt01 order by dataType desc; +``` + +### 7.3 `WHERE` CLAUSE + +#### Time Filter + +```sql +IoTDB > select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; +IoTDB > select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; +IoTDB > select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +#### Value Filter + +```sql +IoTDB > select temperature from root.sg1.d1 where temperature > 36.5; +IoTDB > select status from root.sg1.d1 where status = true; +IoTDB > select temperature from root.sg1.d1 where temperature between 36.5 and 40; +IoTDB > select temperature from root.sg1.d1 where temperature not between 36.5 and 40; +IoTDB > select code from root.sg1.d1 where code in ('200', '300', '400', '500'); +IoTDB > select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); +IoTDB > select code from root.sg1.d1 where temperature is null; +IoTDB > select code from root.sg1.d1 where temperature is not null; +``` + +#### Fuzzy Query + +- Fuzzy matching using `Like` + +```sql +IoTDB > select * from root.sg.d1 where value like '%cc%' +IoTDB > select * from root.sg.device where value like '_b_' +``` + +- Fuzzy matching using `Regexp` + +```sql +IoTDB > select * from root.sg.d1 where value regexp '^[A-Za-z]+$' +IoTDB > select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 +``` + +### 7.4 `GROUP BY` CLAUSE + +- Aggregate By Time without Specifying the Sliding Step Length + +```sql +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` + +- Aggregate By Time Specifying the Sliding Step Length + +```sql +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +- Aggregate by Natural Month + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +IoTDB > select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +- Left Open And Right Close Range + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +- Aggregation By Variation + +```sql +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` + +- Aggregation By Condition + +```sql +IoTDB > select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=true) +IoTDB > select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=false) +``` + +- Aggregation By Session + +```sql +IoTDB > select __endTime,count(*) from root.** group by session(1d) +IoTDB > select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` + +- Aggregation By Count + +```sql +IoTDB > select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +IoTDB > select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` + +- Aggregation By Level + +```sql +IoTDB > select count(status) from root.** group by level = 1 +IoTDB > select count(status) from root.** group by level = 3 +IoTDB > select count(status) from root.** group by level = 1, 3 +IoTDB > select max_value(temperature) from root.** group by level = 0 +IoTDB > select count(*) from root.ln.** group by level = 2 +``` + +- Aggregate By Time with Level Clause + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +IoTDB > select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +- Aggregation query by one single tag + +```sql +IoTDB > SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +- Aggregation query by multiple tags + +```sql +IoTDB > SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +- Downsampling Aggregation by tags based on Time Window + +```sql +IoTDB > SELECT avg(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +### 7.5 `HAVING` CLAUSE + +Correct: + +```sql +IoTDB > select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 1 +IoTDB > select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device +``` + +Incorrect: + +```sql +IoTDB > select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 +IoTDB > select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 +IoTDB > select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 +IoTDB > select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 +``` + +### 7.6 `FILL` CLAUSE + +#### `PREVIOUS` Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +#### `PREVIOUS` FILL and specify the fill timeout threshold +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous, 2m); +``` + +#### `LINEAR` Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +#### Constant Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +### 7.7 `LIMIT` and `SLIMIT` CLAUSES (PAGINATION) + +#### Row Control over Query Results + +```sql +IoTDB > select status, temperature from root.ln.wf01.wt01 limit 10 +IoTDB > select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +IoTDB > select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time< 2017-11-01T00:12:00.000 limit 2 offset 3 +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 5 offset 3 +``` + +#### Column Control over Query Results + +```sql +IoTDB > select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +IoTDB > select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +IoTDB > select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +#### Row and Column Control over Query Results + +```sql +IoTDB > select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +### 7.8 `ORDER BY` CLAUSE + +#### Order by in ALIGN BY TIME mode + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` + +#### Order by in ALIGN BY DEVICE mode + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +IoTDB > select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` + +#### Order by arbitrary expressions + +```sql +IoTDB > select score from root.** order by score desc align by device +IoTDB > select score,total from root.one order by base+score+bonus desc +IoTDB > select score,total from root.one order by total desc +IoTDB > select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +IoTDB > select min_value(total) from root.** order by min_value(total) asc align by device +IoTDB > select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +IoTDB > select score from root.** order by device asc, score desc, time asc align by device +``` + +### 7.9 `ALIGN BY` CLAUSE + +#### Align by Device + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +### 7.10 `INTO` CLAUSE (QUERY WRITE-BACK) + +```sql +IoTDB > select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; +IoTDB > select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); +IoTDB > select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +IoTDB > select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; +``` + +- Using variable placeholders: + +```sql +IoTDB > select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; + +IoTDB > select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; + +IoTDB > select * into root.sg_bk.::(::) from root.sg.**; + +IoTDB > select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; + +IoTDB > select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; + +IoTDB > select * into ::(backup_${4}) from root.sg.** align by device; + +IoTDB > select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` + +## 8. Maintennance +Generate the corresponding query plan: +``` +explain select s1,s2 from root.sg.d1 +``` +Execute the corresponding SQL, analyze the execution and output: +``` +explain analyze select s1,s2 from root.sg.d1 order by s1 +``` +## 9. OPERATOR + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md). + +### 9.1 Arithmetic Operators + +For details and examples, see the document [Arithmetic Operators and Functions](./Operator-and-Expression.md#arithmetic-operators). + +```sql +select s1, - s1, s2, + s2, s1 + s2, s1 - s2, s1 * s2, s1 / s2, s1 % s2 from root.sg.d1 +``` + +### 9.2 Comparison Operators + +For details and examples, see the document [Comparison Operators and Functions](./Operator-and-Expression.md#comparison-operators). + +```sql +# Basic comparison operators +select a, b, a > 10, a <= b, !(a <= b), a > 10 && a > b from root.test; + +# `BETWEEN ... AND ...` operator +select temperature from root.sg1.d1 where temperature between 36.5 and 40; +select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + +# Fuzzy matching operator: Use `Like` for fuzzy matching +select * from root.sg.d1 where value like '%cc%' +select * from root.sg.device where value like '_b_' + +# Fuzzy matching operator: Use `Regexp` for fuzzy matching +select * from root.sg.d1 where value regexp '^[A-Za-z]+$' +select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 +select b, b like '1%', b regexp '[0-2]' from root.test; + +# `IS NULL` operator +select code from root.sg1.d1 where temperature is null; +select code from root.sg1.d1 where temperature is not null; + +# `IN` operator +select code from root.sg1.d1 where code in ('200', '300', '400', '500'); +select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); +select a, a in (1, 2) from root.test; +``` + +### 9.3 Logical Operators + +For details and examples, see the document [Logical Operators](./Operator-and-Expression.md#logical-operators). + +```sql +select a, b, a > 10, a <= b, !(a <= b), a > 10 && a > b from root.test; +``` + +## 10. BUILT-IN FUNCTIONS + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md#built-in-functions). + +### 10.1 Aggregate Functions + +For details and examples, see the document [Aggregate Functions](./Operator-and-Expression.md#aggregate-functions). + +```sql +select count(status) from root.ln.wf01.wt01; + +select count_if(s1=0 & s2=0, 3), count_if(s1=1 & s2=0, 3) from root.db.d1; +select count_if(s1=0 & s2=0, 3, 'ignoreNull'='false'), count_if(s1=1 & s2=0, 3, 'ignoreNull'='false') from root.db.d1; + +select time_duration(s1) from root.db.d1; +``` + +### 10.2 Arithmetic Functions + +For details and examples, see the document [Arithmetic Operators and Functions](./Operator-and-Expression.md#arithmetic-functions). + +```sql +select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000; +select s4,round(s4),round(s4,2),round(s4,-1) from root.sg1.d1; +``` + +### 10.3 Comparison Functions + +For details and examples, see the document [Comparison Operators and Functions](./Operator-and-Expression.md#comparison-functions). + +```sql +select ts, on_off(ts, 'threshold'='2') from root.test; +select ts, in_range(ts, 'lower'='2', 'upper'='3.1') from root.test; +``` + +### 10.4 String Processing Functions + +For details and examples, see the document [String Processing](./Operator-and-Expression.md#string-processing-functions). + +```sql +select s1, string_contains(s1, 's'='warn') from root.sg1.d4; +select s1, string_matches(s1, 'regex'='[^\\s]+37229') from root.sg1.d4; +select s1, length(s1) from root.sg1.d1 +select s1, locate(s1, "target"="1") from root.sg1.d1 +select s1, locate(s1, "target"="1", "reverse"="true") from root.sg1.d1 +select s1, startswith(s1, "target"="1") from root.sg1.d1 +select s1, endswith(s1, "target"="1") from root.sg1.d1 +select s1, s2, concat(s1, s2, "target1"="IoT", "target2"="DB") from root.sg1.d1 +select s1, s2, concat(s1, s2, "target1"="IoT", "target2"="DB", "series_behind"="true") from root.sg1.d1 +select s1, substring(s1 from 1 for 2) from root.sg1.d1 +select s1, replace(s1, 'es', 'tt') from root.sg1.d1 +select s1, upper(s1) from root.sg1.d1 +select s1, lower(s1) from root.sg1.d1 +select s3, trim(s3) from root.sg1.d1 +select s1, s2, strcmp(s1, s2) from root.sg1.d1 +select strreplace(s1, "target"=",", "replace"="/", "limit"="2") from root.test.d1 +select strreplace(s1, "target"=",", "replace"="/", "limit"="1", "offset"="1", "reverse"="true") from root.test.d1 +select regexmatch(s1, "regex"="\d+\.\d+\.\d+\.\d+", "group"="0") from root.test.d1 +select regexreplace(s1, "regex"="192\.168\.0\.(\d+)", "replace"="cluster-$1", "limit"="1") from root.test.d1 +select regexsplit(s1, "regex"=",", "index"="-1") from root.test.d1 +select regexsplit(s1, "regex"=",", "index"="3") from root.test.d1 +``` + +### 10.5 Data Type Conversion Function + +For details and examples, see the document [Data Type Conversion Function](./Operator-and-Expression.md#data-type-conversion-function). + +```sql +SELECT cast(s1 as INT32) from root.sg +``` + +### 10.6 Constant Timeseries Generating Functions + +For details and examples, see the document [Constant Timeseries Generating Functions](./Operator-and-Expression.md#constant-timeseries-generating-functions). + +```sql +select s1, s2, const(s1, 'value'='1024', 'type'='INT64'), pi(s2), e(s1, s2) from root.sg1.d1; +``` + +### 10.7 Selector Functions + +For details and examples, see the document [Selector Functions](./Operator-and-Expression.md#selector-functions). + +```sql +select s1, top_k(s1, 'k'='2'), bottom_k(s1, 'k'='2') from root.sg1.d2 where time > 2020-12-10T20:36:15.530+08:00; +``` + +### 10.8 Continuous Interval Functions + +For details and examples, see the document [Continuous Interval Functions](./Operator-and-Expression.md#continuous-interval-functions). + +```sql +select s1, zero_count(s1), non_zero_count(s2), zero_duration(s3), non_zero_duration(s4) from root.sg.d2; +``` + +### 10.9 Variation Trend Calculation Functions + +For details and examples, see the document [Variation Trend Calculation Functions](./Operator-and-Expression.md#variation-trend-calculation-functions). + +```sql +select s1, time_difference(s1), difference(s1), non_negative_difference(s1), derivative(s1), non_negative_derivative(s1) from root.sg1.d1 limit 5 offset 1000; + +SELECT DIFF(s1), DIFF(s2) from root.test; +SELECT DIFF(s1, 'ignoreNull'='false'), DIFF(s2, 'ignoreNull'='false') from root.test; +``` + +### 10.10 Sample Functions + +For details and examples, see the document [Sample Functions](./Operator-and-Expression.md#sample-functions). + +```sql +select equal_size_bucket_random_sample(temperature,'proportion'='0.1') as random_sample from root.ln.wf01.wt01; +select equal_size_bucket_agg_sample(temperature, 'type'='avg','proportion'='0.1') as agg_avg, equal_size_bucket_agg_sample(temperature, 'type'='max','proportion'='0.1') as agg_max, equal_size_bucket_agg_sample(temperature,'type'='min','proportion'='0.1') as agg_min, equal_size_bucket_agg_sample(temperature, 'type'='sum','proportion'='0.1') as agg_sum, equal_size_bucket_agg_sample(temperature, 'type'='extreme','proportion'='0.1') as agg_extreme, equal_size_bucket_agg_sample(temperature, 'type'='variance','proportion'='0.1') as agg_variance from root.ln.wf01.wt01; +select equal_size_bucket_m4_sample(temperature, 'proportion'='0.1') as M4_sample from root.ln.wf01.wt01; +select equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='avg', 'number'='2') as outlier_avg_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='stendis', 'number'='2') as outlier_stendis_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='cos', 'number'='2') as outlier_cos_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='prenextdis', 'number'='2') as outlier_prenextdis_sample from root.ln.wf01.wt01; + +select M4(s1,'timeInterval'='25','displayWindowBegin'='0','displayWindowEnd'='100') from root.vehicle.d1 +select M4(s1,'windowSize'='10') from root.vehicle.d1 +``` + +### 10.11 Change Points Function + +For details and examples, see the document [Time-Series](./Operator-and-Expression.md#change-points-function). + +```sql +select change_points(s1), change_points(s2), change_points(s3), change_points(s4), change_points(s5), change_points(s6) from root.testChangePoints.d1 +``` + +## 11. DATA QUALITY FUNCTION LIBRARY + +For more details, see document [Operator-and-Expression](../SQL-Manual/UDF-Libraries.md). + +### 11.1 Data Quality + +For details and examples, see the document [Data-Quality](../SQL-Manual/UDF-Libraries.md#data-quality). + +```sql +# Completeness +select completeness(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select completeness(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Consistency +select consistency(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select consistency(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Timeliness +select timeliness(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select timeliness(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Validity +select Validity(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select Validity(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Accuracy +select Accuracy(t1,t2,t3,m1,m2,m3) from root.test +``` + +### 11.2 Data Profiling + +For details and examples, see the document [Data-Profiling](../SQL-Manual/UDF-Libraries.md#data-profiling). + +```sql +# ACF +select acf(s1) from root.test.d1 where time <= 2020-01-01 00:00:05 + +# Distinct +select distinct(s2) from root.test.d2 + +# Histogram +select histogram(s1,"min"="1","max"="20","count"="10") from root.test.d1 + +# Integral +select integral(s1) from root.test.d1 where time <= 2020-01-01 00:00:10 +select integral(s1, "unit"="1m") from root.test.d1 where time <= 2020-01-01 00:00:10 + +# IntegralAvg +select integralavg(s1) from root.test.d1 where time <= 2020-01-01 00:00:10 + +# Mad +select mad(s0) from root.test +select mad(s0, "error"="0.01") from root.test + +# Median +select median(s0, "error"="0.01") from root.test + +# MinMax +select minmax(s1) from root.test + +# Mode +select mode(s2) from root.test.d2 + +# MvAvg +select mvavg(s1, "window"="3") from root.test + +# PACF +select pacf(s1, "lag"="5") from root.test + +# Percentile +select percentile(s0, "rank"="0.2", "error"="0.01") from root.test + +# Quantile +select quantile(s0, "rank"="0.2", "K"="800") from root.test + +# Period +select period(s1) from root.test.d3 + +# QLB +select QLB(s1) from root.test.d1 + +# Resample +select resample(s1,'every'='5m','interp'='linear') from root.test.d1 +select resample(s1,'every'='30m','aggr'='first') from root.test.d1 +select resample(s1,'every'='30m','start'='2021-03-06 15:00:00') from root.test.d1 + +# Sample +select sample(s1,'method'='reservoir','k'='5') from root.test.d1 +select sample(s1,'method'='isometric','k'='5') from root.test.d1 + +# Segment +select segment(s1, "error"="0.1") from root.test + +# Skew +select skew(s1) from root.test.d1 + +# Spline +select spline(s1, "points"="151") from root.test + +# Spread +select spread(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 + +# Stddev +select stddev(s1) from root.test.d1 + +# ZScore +select zscore(s1) from root.test +``` + +### 11.3 Anomaly Detection + +For details and examples, see the document [Anomaly-Detection](../SQL-Manual/UDF-Libraries.md#anomaly-detection). + +```sql +# IQR +select iqr(s1) from root.test + +# KSigma +select ksigma(s1,"k"="1.0") from root.test.d1 where time <= 2020-01-01 00:00:30 + +# LOF +select lof(s1,s2) from root.test.d1 where time<1000 +select lof(s1, "method"="series") from root.test.d1 where time<1000 + +# MissDetect +select missdetect(s2,'minlen'='10') from root.test.d2 + +# Range +select range(s1,"lower_bound"="101.0","upper_bound"="125.0") from root.test.d1 where time <= 2020-01-01 00:00:30 + +# TwoSidedFilter +select TwoSidedFilter(s0, 'len'='5', 'threshold'='0.3') from root.test + +# Outlier +select outlier(s1,"r"="5.0","k"="4","w"="10","s"="5") from root.test + +# MasterTrain +select MasterTrain(lo,la,m_lo,m_la,'p'='3','eta'='1.0') from root.test + +# MasterDetect +select MasterDetect(lo,la,m_lo,m_la,model,'output_type'='repair','p'='3','k'='3','eta'='1.0') from root.test +select MasterDetect(lo,la,m_lo,m_la,model,'output_type'='anomaly','p'='3','k'='3','eta'='1.0') from root.test +``` + +### 11.4 Frequency Domain + +For details and examples, see the document [Frequency-Domain](../SQL-Manual/UDF-Libraries.md#frequency-domain-analysis). + +```sql +# Conv +select conv(s1,s2) from root.test.d2 + +# Deconv +select deconv(s3,s2) from root.test.d2 +select deconv(s3,s2,'result'='remainder') from root.test.d2 + +# DWT +select dwt(s1,"method"="haar") from root.test.d1 + +# FFT +select fft(s1) from root.test.d1 +select fft(s1, 'result'='real', 'compress'='0.99'), fft(s1, 'result'='imag','compress'='0.99') from root.test.d1 + +# HighPass +select highpass(s1,'wpass'='0.45') from root.test.d1 + +# IFFT +select ifft(re, im, 'interval'='1m', 'start'='2021-01-01 00:00:00') from root.test.d1 + +# LowPass +select lowpass(s1,'wpass'='0.45') from root.test.d1 + +# Envelope +select envelope(s1) from root.test.d1 +``` + +### 11.5 Data Matching + +For details and examples, see the document [Data-Matching](../SQL-Manual/UDF-Libraries.md#data-matching). + +```sql +# Cov +select cov(s1,s2) from root.test.d2 + +# DTW +select dtw(s1,s2) from root.test.d2 + +# Pearson +select pearson(s1,s2) from root.test.d2 + +# PtnSym +select ptnsym(s4, 'window'='5', 'threshold'='0') from root.test.d1 + +# XCorr +select xcorr(s1, s2) from root.test.d1 where time <= 2020-01-01 00:00:05 +``` + +### 11.6 Data Repairing + +For details and examples, see the document [Data-Repairing](../SQL-Manual/UDF-Libraries.md#data-repairing). + +```sql +# TimestampRepair +select timestamprepair(s1,'interval'='10000') from root.test.d2 +select timestamprepair(s1) from root.test.d2 + +# ValueFill +select valuefill(s1) from root.test.d2 +select valuefill(s1,"method"="previous") from root.test.d2 + +# ValueRepair +select valuerepair(s1) from root.test.d2 +select valuerepair(s1,'method'='LsGreedy') from root.test.d2 + +# MasterRepair +select MasterRepair(t1,t2,t3,m1,m2,m3) from root.test + +# SeasonalRepair +select seasonalrepair(s1,'period'=3,'k'=2) from root.test.d2 +select seasonalrepair(s1,'method'='improved','period'=3) from root.test.d2 +``` + +### 11.7 Series Discovery + +For details and examples, see the document [Series-Discovery](../SQL-Manual/UDF-Libraries.md#series-discovery). + +```sql +# ConsecutiveSequences +select consecutivesequences(s1,s2,'gap'='5m') from root.test.d1 +select consecutivesequences(s1,s2) from root.test.d1 + +# ConsecutiveWindows +select consecutivewindows(s1,s2,'length'='10m') from root.test.d1 +``` + +### 11.8 Machine Learning + +For details and examples, see the document [Machine-Learning](../SQL-Manual/UDF-Libraries.md#machine-learning). + +```sql +# AR +select ar(s0,"p"="2") from root.test.d0 + +# Representation +select representation(s0,"tb"="3","vb"="2") from root.test.d0 + +# RM +select rm(s0, s1,"tb"="3","vb"="2") from root.test.d0 +``` + +## 12. LAMBDA EXPRESSION + +For details and examples, see the document [Lambda](../SQL-Manual/UDF-Libraries.md#lambda-expression). + +```sql +select jexl(temperature, 'expr'='x -> {x + x}') as jexl1, jexl(temperature, 'expr'='x -> {x * 3}') as jexl2, jexl(temperature, 'expr'='x -> {x * x}') as jexl3, jexl(temperature, 'expr'='x -> {multiply(x, 100)}') as jexl4, jexl(temperature, st, 'expr'='(x, y) -> {x + y}') as jexl5, jexl(temperature, st, str, 'expr'='(x, y, z) -> {x + y + z}') as jexl6 from root.ln.wf01.wt01;``` +``` + +## 13. CONDITIONAL EXPRESSION + +For details and examples, see the document [Conditional Expressions](../SQL-Manual/UDF-Libraries.md#conditional-expressions). + +```sql +select T, P, case +when 1000=1050 then "bad temperature" +when P<=1000000 or P>=1100000 then "bad pressure" +end as `result` +from root.test1 + +select str, case +when str like "%cc%" then "has cc" +when str like "%dd%" then "has dd" +else "no cc and dd" end as `result` +from root.test2 + +select +count(case when x<=1 then 1 end) as `(-∞,1]`, +count(case when 1 +[RESAMPLE + [EVERY ] + [BOUNDARY ] + [RANGE [, end_time_offset]] +] +[TIMEOUT POLICY BLOCKED|DISCARD] +BEGIN + SELECT CLAUSE + INTO CLAUSE + FROM CLAUSE + [WHERE CLAUSE] + [GROUP BY([, ]) [, level = ]] + [HAVING CLAUSE] + [FILL ({PREVIOUS | LINEAR | constant} (, interval=DURATION_LITERAL)?)] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] +END +``` + +### 15.1 Configuring execution intervals + +```sql +CREATE CONTINUOUS QUERY cq1 +RESAMPLE EVERY 20s +BEGIN +SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) +END +``` + +### 15.2 Configuring time range for resampling + +```sql +CREATE CONTINUOUS QUERY cq2 +RESAMPLE RANGE 40s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) +END +``` + +### 15.3 Configuring execution intervals and CQ time ranges + +```sql +CREATE CONTINUOUS QUERY cq3 +RESAMPLE EVERY 20s RANGE 40s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) + FILL(100.0) +END +``` + +### 15.4 Configuring end_time_offset for CQ time range + +```sql +CREATE CONTINUOUS QUERY cq4 +RESAMPLE EVERY 20s RANGE 40s, 20s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) + FILL(100.0) +END +``` + +### 15.5 CQ without group by clause + +```sql +CREATE CONTINUOUS QUERY cq5 +RESAMPLE EVERY 20s +BEGIN + SELECT temperature + 1 + INTO root.precalculated_sg.::(temperature) + FROM root.ln.*.* + align by device +END +``` + +### 15.6 CQ Management + +#### Listing continuous queries + +```sql +SHOW (CONTINUOUS QUERIES | CQS) +``` + +#### Dropping continuous queries + +```sql +DROP (CONTINUOUS QUERY | CQ) +``` + +#### Altering continuous queries + +CQs can't be altered once they're created. To change a CQ, you must `DROP` and re`CREATE` it with the updated settings. + +## 16. USER-DEFINED FUNCTION (UDF) + +For more details, see document [Operator-and-Expression](../SQL-Manual/UDF-Libraries.md). + +### 16.1 UDF Registration + +```sql +CREATE FUNCTION AS (USING URI URI-STRING)? +``` + +### 16.2 UDF Deregistration + +```sql +DROP FUNCTION +``` + +### 16.3 UDF Queries + +```sql +SELECT example(*) from root.sg.d1 +SELECT example(s1, *) from root.sg.d1 +SELECT example(*, *) from root.sg.d1 + +SELECT example(s1, 'key1'='value1', 'key2'='value2'), example(*, 'key3'='value3') FROM root.sg.d1; +SELECT example(s1, s2, 'key1'='value1', 'key2'='value2') FROM root.sg.d1; + +SELECT s1, s2, example(s1, s2) FROM root.sg.d1; +SELECT *, example(*) FROM root.sg.d1 DISABLE ALIGN; +SELECT s1 * example(* / s1 + s2) FROM root.sg.d1; +SELECT s1, s2, s1 + example(s1, s2), s1 - example(s1 + example(s1, s2) / s2) FROM root.sg.d1; +``` + +### 16.4 Show All Registered UDFs + +```sql +SHOW FUNCTIONS +``` + +## 17. ADMINISTRATION MANAGEMENT + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md). + +### 17.1 SQL Statements + +- Create user (Requires MANAGE_USER permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- Delete user (Requires MANAGE_USER permission) + +```sql +DROP USER +eg: DROP USER user1 +``` + +- Create role (Requires MANAGE_ROLE permission) + +```sql +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- Delete role (Requires MANAGE_ROLE permission) + +```sql +DROP ROLE +eg: DROP ROLE role1 +``` + +- Grant role to user (Requires MANAGE_ROLE permission) + +```sql +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- Revoke role from user(Requires MANAGE_ROLE permission) + +```sql +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- List all user (Requires MANAGE_USER permission) + +```sql +LIST USER +``` + +- List all role (Requires MANAGE_ROLE permission) + +```sql +LIST ROLE +``` + +- List all users granted specific role.(Requires MANAGE_USER permission) + +```sql +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- List all role granted to specific user. + +```sql +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- List all privileges of user + +```sql +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; +``` + +- List all privileges of role + +```sql +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- Modify password + +```sql +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 17.2 Authorization and Deauthorization + + +```sql +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +```sql +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + + +#### Delete Time Partition (experimental) + +``` +Eg: IoTDB > DELETE PARTITION root.ln 0,1,2 +``` + +#### Continuous Query,CQ + +``` +Eg: IoTDB > CREATE CONTINUOUS QUERY cq1 BEGIN SELECT max_value(temperature) INTO temperature_max FROM root.ln.*.* GROUP BY time(10s) END +``` + +#### Maintenance Command + +- FLUSH + +``` +Eg: IoTDB > flush +``` + +- MERGE + +``` +Eg: IoTDB > MERGE +Eg: IoTDB > FULL MERGE +``` + +- CLEAR CACHE + +```sql +Eg: IoTDB > CLEAR CACHE +``` + +- START REPAIR DATA + +```sql +Eg: IoTDB > START REPAIR DATA +``` + +- STOP REPAIR DATA + +```sql +Eg: IoTDB > STOP REPAIR DATA +``` + +- SET SYSTEM TO READONLY / WRITABLE + +``` +Eg: IoTDB > SET SYSTEM TO READONLY / WRITABLE +``` + +- Query abort + +``` +Eg: IoTDB > KILL QUERY 1 +``` \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/Technical-Insider/Encoding-and-Compression.md b/src/UserGuide/Master/Tree/Technical-Insider/Encoding-and-Compression.md index b71925665..f70a704d5 100644 --- a/src/UserGuide/Master/Tree/Technical-Insider/Encoding-and-Compression.md +++ b/src/UserGuide/Master/Tree/Technical-Insider/Encoding-and-Compression.md @@ -119,7 +119,7 @@ IoTDB allows you to specify the compression method of the column when creating a * LZMA2 -The specified syntax for compression is detailed in [Create Timeseries Statement](../SQL-Manual/SQL-Manual.md). +The specified syntax for compression is detailed in [Create Timeseries Statement](../SQL-Manual/SQL-Manual_timecho). ### 2.2 Compression Ratio Statistics diff --git a/src/UserGuide/Master/Tree/Tools-System/CLI_apache.md b/src/UserGuide/Master/Tree/Tools-System/CLI_apache.md index 5261ff35a..758846624 100644 --- a/src/UserGuide/Master/Tree/Tools-System/CLI_apache.md +++ b/src/UserGuide/Master/Tree/Tools-System/CLI_apache.md @@ -60,10 +60,10 @@ Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root The Windows system startup commands are as follows: ```shell -# Before version V2.0.4.x +# Before version V2.0.4 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x and later versions +# V2.0.4 and later versions Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root ``` diff --git a/src/UserGuide/Master/Tree/Tools-System/CLI_timecho.md b/src/UserGuide/Master/Tree/Tools-System/CLI_timecho.md index d2bf58f53..3a3807cb1 100644 --- a/src/UserGuide/Master/Tree/Tools-System/CLI_timecho.md +++ b/src/UserGuide/Master/Tree/Tools-System/CLI_timecho.md @@ -29,7 +29,7 @@ IoTDB provides Cli/shell tools for users to interact with IoTDB server in comman ## 1. Running Cli After installation, there is a default user in IoTDB: `root`, and the -default password is `root`. Users can use this username to try IoTDB Cli/Shell tool. The cli startup script is the `start-cli` file under the \$IOTDB\_HOME/bin folder. When starting the script, you need to specify the IP and PORT. (Make sure the IoTDB cluster is running properly when you use Cli/Shell tool to connect to it.) +default password is `TimechoDB@2021`(Before V2.0.6 it is `root`). Users can use this username to try IoTDB Cli/Shell tool. The cli startup script is the `start-cli` file under the \$IOTDB\_HOME/bin folder. When starting the script, you need to specify the IP and PORT. (Make sure the IoTDB cluster is running properly when you use Cli/Shell tool to connect to it.) Here is an example where the cluster is started locally and the user has not changed the running port. The default rpc port is 6667
@@ -40,7 +40,11 @@ You also can set your own environment variable at the front of the start script The Linux and MacOS system startup commands are as follows: ```shell +# Before version V2.0.6.x Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x and later versions +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` The Windows system startup commands are as follows: @@ -49,8 +53,11 @@ The Windows system startup commands are as follows: # Before version V2.0.4.x Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x and later versions +# V2.0.4.x and later versions, before version V2.0.6.x Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x and later versions +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` After operating these commands, the cli can be started successfully. The successful status will be as follows: diff --git a/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md b/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md similarity index 98% rename from src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md rename to src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md index 5601f3b8a..af564f3ec 100644 --- a/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md +++ b/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md @@ -79,7 +79,7 @@ The data export tool, export-data.sh (Unix/OS X) or export-data.bat (Windows), l # Error Example > tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ## 2.3 SQL Format #### 2.3.1 Command @@ -118,7 +118,7 @@ Parse error: Missing required option: t # Error Example > tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.4 TsFile Format @@ -153,5 +153,5 @@ Parse error: Missing required option: t # Error Example > tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` diff --git a/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md b/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..21366ef6b --- /dev/null +++ b/src/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,163 @@ +# Data Export + +## 1. Overview +The data export tool, export-data.sh (Unix/OS X) or export-data.bat (Windows), located in the tools directory, allows users to export query results from specified SQL statements into CSV, SQL, or TsFile (open-source time-series file format) formats. The specific functionalities are as follows: + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVexport-data.sh/batPlain text format for storing structured data. Must follow the CSV format specified below.
SQLFile containing custom SQL statements.
TsFileOpen-source time-series file format.
+ + +## 2. Detailed Functionality +### 2.1 Common Parameters +| Short | Full Parameter | Description | Required | Default | +| ---------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------- |------------------------------------------------| +| `-ft` | `--file_type` | Export file type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | +| `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | +| `-u` | `--username` | Username for authentication. | No | `root` | +| `-pw` | `--password` | Password for authentication. | No | `TimechoDB@2021`(Before V2.0.6 it is `root` ) | +| `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | +| `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | +| `-q` | `--query` | SQL query command to execute. | No | - | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (ms). | No | `-1` (Range: -1~Long max=9223372036854775807) | +| `-help` | `--help` | Display help information. | No | - | + +### 2.2 CSV Format +#### 2.2.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |------------------------------------------| +| `-dt` | `--datatype` | Whether to include data types in the CSV file header (`true` or `false`). | No | `false` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -dt true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# Error Example +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` +## 2.3 SQL Format +#### 2.3.1 Command +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------- | +| `-aligned` | `--use_aligned` | Whether to export as aligned SQL format (`true` or `false`). | No | `true` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.3.3 Examples +```Shell +# Valid Example +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -aligned true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# Error Example +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 TsFile-Specific Parameters + +* None + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn export-data.tsfile -q "SELECT * FROM root.ln" -timeout 10000 + +# Error Example +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` diff --git a/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md b/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md rename to src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md index e330c0564..848afe982 100644 --- a/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md +++ b/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md @@ -99,7 +99,7 @@ IoTDB supports three methods for data import: error: Source file or directory /non_path does not exist > tools/import-data.sh -ft csv -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` #### 2.2.4 Import Notes @@ -190,7 +190,7 @@ error: Source file or directory /path/sql does not exist > tools/import-data.sh -ft sql -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ### 2.4 TsFile Format @@ -238,7 +238,7 @@ error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' > tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` diff --git a/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md b/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..ab7ade070 --- /dev/null +++ b/src/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,325 @@ +# Data Import + +## 1. Overview +IoTDB supports three methods for data import: +- Data Import Tool: Use the `import-data.sh/bat` script in the `tools` directory to manually import CSV, SQL, or TsFile (open-source time-series file format) data into IoTDB. +- `TsFile` Auto-Loading Feature +- Load `TsFile` SQL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVimport-data.sh/batCan be used for single or batch import of CSV files into IoTDB
SQLCan be used for single or batch import of SQL files into IoTDB
TsFileCan be used for single or batch import of TsFile files into IoTDB
TsFile Auto-Loading FeatureCan automatically monitor a specified directory for newly generated TsFiles and load them into IoTDB
Load SQLCan be used for single or batch import of TsFile files into IoTDB
+ +## 2. Data Import Tool +### 2.1 Common Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |-----------------------------------------------| +| `-ft` | `--file_type` | File type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | +| `-p` | `--port` | IoTDB server port. | No | `6667` | +| `-u` | `--username` | Username. | No | `root` | +| `-pw` | `--password` | Password. | No | `TimechoDB@2021`(Before V2.0.6 it is `root` ) | +| `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | +| `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | +| `-tz` | `--timezone` | Timezone (e.g., `+08:00`, `-01:00`). | No | System default | +| `-help` | `--help` | Display help (general or format-specific: `-help csv`). | No | - | + +### 2.2 CSV Format + +#### 2.2.1 Command +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------------- |----------------------------------------------------------| ---------- |-----------------| +| `-fd` | `--fail_dir` | Directory to save failed files. | No | YOUR_CSV_FILE_PATH | +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-aligned` | `--use_aligned` | Import as aligned time series. | No | `false` | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-ti` | `--type_infer` | Type mapping (e.g., `BOOLEAN=text,INT=long`). | No | - | +| `-tp` | `--timestamp_precision` | Timestamp precision: `ms`, `us`, `ns`. | No | `ms` | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 100 -aligned true -ti "BOOLEAN=text,INT=long,FLOAT=double" + -tp ms -tz +08:00 -batch 5000 -tn 4 + +# Error Example +> tools/import-data.sh -ft csv -s /non_path +error: Source file or directory /non_path does not exist + +> tools/import-data.sh -ft csv -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + +#### 2.2.4 Import Notes + +1. CSV Import Specifications + +- Special Character Escaping Rules: If a text-type field contains special characters (e.g., commas ,), they must be escaped using a backslash (\). +- Supported Time Formats: yyyy-MM-dd'T'HH:mm:ss, yyyy-MM-dd HH:mm:ss, or yyyy-MM-dd'T'HH:mm:ss.SSSZ. +- Timestamp Column Requirement: The timestamp column must be the first column in the data file. + +2. CSV File Example + +- Time Alignment + +```sql +-- Headers without data types +Time,root.test.t1.str,root.test.t2.str,root.test.t2.var +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,"123",, + +-- Headers with data types (Text-type data supports both quoted and unquoted formats) +Time,root.test.t1.str(TEXT),root.test.t2.str(TEXT),root.test.t2.var(INT32) +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,123,hello world,123 +1970-01-01T08:00:00.003+08:00,"123",, +1970-01-01T08:00:00.004+08:00,123,,12 +``` + +- Device Alignment + +```sql +-- Headers without data types +Time,Device,str,var +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 + +-- Headers with data types (Text-type data supports both quoted and unquoted formats) +Time,Device,str(TEXT),var(INT32) +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 +1970-01-01T08:00:00.002+08:00,root.test.t1,hello world,123 +``` + + +### 2.3 SQL Format + +#### 2.3.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| -------------- | ------------------------------- | -------------------------------------------------------------------- | ---------- | ------------------ | +| `-fd` | `--fail_dir` | Directory to save failed files. | No |YOUR_CSV_FILE_PATH| +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | + +#### 2.3.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 500 -tz +08:00 + -batch 100000 -tn 4 + +# Error Example +> tools/import-data.sh -ft sql -s /path/sql -fd /non_path +error: Source file or directory /path/sql does not exist + + +> tools/import-data.sh -ft sql -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` +#### 2.4.2 TsFile-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ----------- | ----------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------- | --------------------------- | +| `-os` | `--on_success` | Action for successful files:
`none`: Do not delete the file.
`mv`: Move the successful file to the target directory.
`cp`:Create a hard link (copy) of the successful file to the target directory.
`delete`:Delete the file. | ​**Yes** | - | +| `-sd` | `--success_dir` | Target directory for `mv`/`cp` actions on success. Required if `-os` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/success` | +| `-of` | `--on_fail` | Action for failed files:
`none`:Skip the file.
`mv`:Move the failed file to the target directory.
`cp`:Create a hard link (copy) of the failed file to the target directory.
`delete`:Delete the file.. | ​**Yes** | - | +| `-fd` | `--fail_dir` | Target directory for `mv`/`cp` actions on failure. Required if `-of` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/fail` | +| `-tp` | `--timestamp_precision` | TsFile timestamp precision: `ms`, `us`, `ns`.
For non-remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The system will manually verify if the timestamp precision matches the server. If it does not match, an error will be returned.
​For remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The Pipe system will automatically verify if the timestamp precision matches. If it does not match, a Pipe error will be returned. | No | `ms` | + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 + -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir + -tn 8 -tz +08:00 -tp ms + +# Error Example +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -fd /path/failure/dir -tn 8 +error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' + +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -sd /path/success/dir -fd /path/failure/dir -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + + +## 3. TsFile Auto-Loading + +This feature enables IoTDB to automatically monitor a specified directory for new TsFiles and load them into the database without manual intervention. + +![](/img/Data-import2.png) + +### 3.1 Configuration + +Add the following parameters to `iotdb-system.properties` (template: `iotdb-system.properties.template`): + +| Parameter | Description | Value Range | Required | Default | Hot-Load? | +| ---------------------------------------------------- |---------------------------------------------------------------------------------------| --------------------------------- | ---------- | ----------------------------- | ----------------------- | +| `load_active_listening_enable` | Enable auto-loading. | `true`/`false` | Optional | `true` | Yes | +| `load_active_listening_dirs` | Directories to monitor (subdirectories included). Multiple paths separated by commas. | String | Optional | `ext/load/pending` | Yes | +| `load_active_listening_fail_dir` | Directory to store failed TsFiles. Only can set one. | String | Optional | `ext/load/failed` | Yes | +| `load_active_listening_max_thread_num` | Maximum Threads for TsFile Loading Tasks:The default value for this parameter, when commented out, is max(1, CPU cores / 2). If the value set by the user falls outside the range [1, CPU cores / 2], it will be reset to the default value of max(1, CPU cores / 2). | `1` to `Long.MAX_VALUE` | Optional | `max(1, CPU_CORES / 2)` | No (restart required) | +| `load_active_listening_check_interval_seconds` | Active Listening Polling Interval (in seconds):The active listening feature for TsFiles is implemented through polling the target directory. This configuration specifies the time interval between two consecutive checks of the `load_active_listening_dirs`. After each check, the next check will be performed after `load_active_listening_check_interval_seconds` seconds. If the polling interval set by the user is less than 1, it will be reset to the default value of 5 seconds. | `1` to `Long.MAX_VALUE` | Optional | `5` | No (restart required) | + +### 3.2 Notes + +1. ​​**Mods Files**​: If TsFiles have associated `.mods` files, move `.mods` files to the monitored directory ​**before** their corresponding TsFiles. Ensure `.mods` and TsFiles are in the same directory. +2. ​​**Restricted Directories**​: Do NOT set Pipe receiver directories, data directories, or other system paths as monitored directories. +3. ​​**Directory Conflicts**​: Ensure `load_active_listening_fail_dir` does not overlap with `load_active_listening_dirs` or its subdirectories. +4. ​​**Permissions**​: The monitored directory must have write permissions. Files are deleted after successful loading; insufficient permissions may cause duplicate loading. + +## 4. Load SQL + +IoTDB supports importing one or multiple TsFile files containing time series into another running IoTDB instance directly via SQL execution through the CLI. + +### 4.1 Command + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` : The path to a TsFile or a folder containing multiple TsFiles. +* ``: Optional parameters, as described below. + +| Key | Key Description | Value Type | Value Range | Value is Required | Default Value | +|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|--------------------------------|-------------------|----------------------------| +| `database-level` | When the database corresponding to the TsFile does not exist, the database hierarchy level can be specified via the ` database-level` parameter. The default is the level set in `iotdb-common.properties`. For example, setting level=1 means the prefix path of level 1 in all time series in the TsFile will be used as the database. | Integer | `[1: Integer.MAX_VALUE]` | No | 1 | +| `on-success` | Action for successfully loaded TsFiles: `delete` (delete the TsFile after successful import) or `none` (retain the TsFile in the source folder). | String | `delete / none` | No | delete | +| `model` | Specifies whether the TsFile uses the `table` model or `tree` model. | String | `tree / table` | No | Aligns with `-sql_dialect` | +| `database-name` | Table model only: Target database for import. Automatically created if it does not exist. The database-name must not include the `root.` prefix (an error will occur if included). | String | `-` | No | null | +| `convert-on-type-mismatch` | Whether to perform type conversion during loading if data types in the TsFile mismatch the target schema. | Boolean | `true / false` | No | true | +| `verify` | Whether to validate the schema before loading the TsFile. | Boolean | `true / false` | No | true | +| `tablet-conversion-threshold` | Size threshold (in bytes) for converting TsFiles into tablet format during loading. Default: `-1` (no conversion for any TsFile). | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | No | -1 | +| `async` | Whether to enable asynchronous loading. If enabled, TsFiles are moved to an active-load directory and loaded into the `database-name` asynchronously. | Boolean | `true / false` | No | false | + +### 4.2 Example + +```SQL +-- Before import +IoTDB> show databases ++-------------+-----------------------+---------------------+-------------------+---------------------+ +| Database|SchemaReplicationFactor|DataReplicationFactor|TimePartitionOrigin|TimePartitionInterval| ++-------------+-----------------------+---------------------+-------------------+---------------------+ +|root.__system| 1| 1| 0| 604800000| ++-------------+-----------------------+---------------------+-------------------+---------------------+ + +-- Import tsfile by excuting load sql +IoTDB> load '/home/dump1.tsfile' with ( 'on-success'='none') +Msg: The statement is executed successfully. + +-- Verify whether the import was successful +IoTDB> select * from root.testdb.** ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time|root.testdb.device.model.temperature|root.testdb.device.model.humidity|root.testdb.device.model.status| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|2025-04-17T10:35:47.218+08:00| 22.3| 19.4| true| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` \ No newline at end of file diff --git a/src/UserGuide/latest/Tools-System/Schema-Export-Tool.md b/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md similarity index 94% rename from src/UserGuide/latest/Tools-System/Schema-Export-Tool.md rename to src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md index e6b102d06..f2423a678 100644 --- a/src/UserGuide/latest/Tools-System/Schema-Export-Tool.md +++ b/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ The schema export tool `export-schema.sh/bat` is located in the `tools` director ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------- | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | -| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | -| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | -| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | -| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | -| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | | `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md b/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..e126ccd89 --- /dev/null +++ b/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,82 @@ + + +# Schema Export + +## 1. Overview + +The schema export tool `export-schema.sh/bat` is located in the `tools` directory. It can export schema from a specified database in IoTDB to a script file. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | TimechoDB@2021(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 Examples + + +```Bash +# Export schema under root.treedb +./export-schema.sh -sql_dialect tree -t /home/ -path "root.treedb.**" + +# Output +Timeseries,Alias,DataType,Encoding,Compression +root.treedb.device.temperature,,DOUBLE,GORILLA,LZ4 +root.treedb.device.humidity,,DOUBLE,GORILLA,LZ4 +``` \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md b/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md similarity index 87% rename from src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md rename to src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md index c3018730e..9bc72440c 100644 --- a/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md +++ b/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md @@ -29,19 +29,19 @@ The schema import tool `import-schema.sh/bat` is located in `tools` directory. ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- | ------------------------------------------------ | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database for import | Yes | - | -| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | -| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | -| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | | `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/latest/Tools-System/Schema-Import-Tool.md b/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md similarity index 87% rename from src/UserGuide/latest/Tools-System/Schema-Import-Tool.md rename to src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md index c3018730e..6f0d82fc0 100644 --- a/src/UserGuide/latest/Tools-System/Schema-Import-Tool.md +++ b/src/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md @@ -29,19 +29,19 @@ The schema import tool `import-schema.sh/bat` is located in `tools` directory. ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- | ------------------------------------------------ | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database for import | Yes | - | -| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | -| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | -| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | TimechoDB@2021(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | | `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/Master/Tree/User-Manual/Authority-Management.md b/src/UserGuide/Master/Tree/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/UserGuide/Master/Tree/User-Manual/Authority-Management.md rename to src/UserGuide/Master/Tree/User-Manual/Authority-Management_apache.md diff --git a/src/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md b/src/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..466329109 --- /dev/null +++ b/src/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,519 @@ + + +# Authority Management + +IoTDB provides permission management operations, offering users the ability to manage permissions for data and cluster systems, ensuring data and system security. + +This article introduces the basic concepts of the permission module in IoTDB, including user definition, permission management, authentication logic, and use cases. In the JAVA programming environment, you can use the [JDBC API](https://chat.openai.com/API/Programming-JDBC.md) to execute permission management statements individually or in batches. + +## 1. Basic Concepts + +### 1.1 User + +A user is a legitimate user of the database. Each user corresponds to a unique username and has a password as a means of authentication. Before using the database, a person must provide a valid (i.e., stored in the database) username and password for a successful login. + +### 1.2 Permission + +The database provides various operations, but not all users can perform all operations. If a user can perform a certain operation, they are said to have permission to execute that operation. Permissions are typically limited in scope by a path, and [path patterns](https://chat.openai.com/Basic-Concept/Data-Model-and-Terminology.md) can be used to manage permissions flexibly. + +### 1.3 Role + +A role is a collection of multiple permissions and has a unique role name as an identifier. Roles often correspond to real-world identities (e.g., a traffic dispatcher), and a real-world identity may correspond to multiple users. Users with the same real-world identity often have the same permissions, and roles are abstractions for unified management of such permissions. + +### 1.4 Default Users and Roles + +After installation and initialization, IoTDB includes a default user: root, with the default password TimechoDB@2021 (Before V2.0.6.x it is root). This user is an administrator with fixed permissions, which cannot be granted or revoked and cannot be deleted. There is only one administrator user in the database. + +A newly created user or role does not have any permissions initially. + +## 2. User Definition + +Users with MANAGE_USER and MANAGE_ROLE permissions or administrators can create users or roles. Creating a user must meet the following constraints. + +### 2.1 Username Constraints + +4 to 32 characters, supports the use of uppercase and lowercase English letters, numbers, and special characters (`!@#$%^&*()_+-=`). + +Users cannot create users with the same name as the administrator. + +### 2.2 Password Constraints + +4 to 32 characters, can use uppercase and lowercase letters, numbers, and special characters (`!@#$%^&*()_+-=`). Passwords are encrypted by default using SHA-256. + +### 2.3 Role Name Constraints + +4 to 32 characters, supports the use of uppercase and lowercase English letters, numbers, and special characters (`!@#$%^&*()_+-=`). + +Users cannot create roles with the same name as the administrator. + + + +## 3. Permission Management + +IoTDB primarily has two types of permissions: series permissions and global permissions. + +### 3.1 Series Permissions + +Series permissions constrain the scope and manner in which users access data. IOTDB support authorization for both absolute paths and prefix-matching paths, and can be effective at the timeseries granularity. + +The table below describes the types and scope of these permissions: + + + +| Permission Name | Description | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| READ_DATA | Allows reading time series data under the authorized path. | +| WRITE_DATA | Allows reading time series data under the authorized path.
Allows inserting and deleting time series data under the authorized path.
Allows importing and loading data under the authorized path. When importing data, you need the WRITE_DATA permission for the corresponding path. When automatically creating databases or time series, you need MANAGE_DATABASE and WRITE_SCHEMA permissions. | +| READ_SCHEMA | Allows obtaining detailed information about the metadata tree under the authorized path,
including databases, child paths, child nodes, devices, time series, templates, views, etc. | +| WRITE_SCHEMA | Allows obtaining detailed information about the metadata tree under the authorized path.
Allows creating, deleting, and modifying time series, templates, views, etc. under the authorized path. When creating or modifying views, it checks the WRITE_SCHEMA permission for the view path and READ_SCHEMA permission for the data source. When querying and inserting data into views, it checks the READ_DATA and WRITE_DATA permissions for the view path.
Allows setting, unsetting, and viewing TTL under the authorized path.
Allows attaching or detaching templates under the authorized path. | + + +### 3.2 Global Permissions + +Global permissions constrain the database functions that users can use and restrict commands that change the system and task state. Once a user obtains global authorization, they can manage the database. +The table below describes the types of system permissions: + + +| Permission Name | Description | +|:---------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| MANAGE_DATABASE | Allow users to create and delete databases. | +| MANAGE_USER | Allow users to create, delete, modify, and view users. | +| MANAGE_ROLE | Allow users to create, delete, modify, and view roles.
Allow users to grant/revoke roles to/from other users. | +| USE_TRIGGER | Allow users to create, delete, and view triggers.
Independent of data source permission checks for triggers. | +| USE_UDF | Allow users to create, delete, and view user-defined functions.
Independent of data source permission checks for user-defined functions. | +| USE_CQ | Allow users to create, delete, and view continuous queries.
Independent of data source permission checks for continuous queries. | +| USE_PIPE | Allow users to create, start, stop, delete, and view pipelines.
Allow users to create, delete, and view pipeline plugins.
Independent of data source permission checks for pipelines. | +| EXTEND_TEMPLATE | Permission to automatically create templates. | +| MAINTAIN | Allow users to query and cancel queries.
Allow users to view variables.
Allow users to view cluster status. | +| USE_MODEL | Allow users to create, delete and view deep learning model. | +Regarding template permissions: + +1. Only administrators are allowed to create, delete, modify, query, mount, and unmount templates. +2. To activate a template, you need to have WRITE_SCHEMA permission for the activation path. +3. If automatic creation is enabled, writing to a non-existent path that has a template mounted will automatically extend the template and insert data. Therefore, one needs EXTEND_TEMPLATE permission and WRITE_DATA permission for writing to the sequence. +4. To deactivate a template, WRITE_SCHEMA permission for the mounted template path is required. +5. To query paths that use a specific metadata template, you needs READ_SCHEMA permission for the paths; otherwise, it will return empty results. + + + +### 3.3 Granting and Revoking Permissions + +In IoTDB, users can obtain permissions through three methods: + +1. Granted by administrator, who has control over the permissions of other users. +2. Granted by a user allowed to authorize permissions, and this user was assigned the grant option keyword when obtaining the permission. +3. Granted a certain role by administrator or a user with MANAGE_ROLE, thereby obtaining permissions. + +Revoking a user's permissions can be done through the following methods: + +1. Revoked by administrator. +2. Revoked by a user allowed to authorize permissions, and this user was assigned the grant option keyword when obtaining the permission. +3. Revoked from a user's role by administrator or a user with MANAGE_ROLE, thereby revoking the permissions. + +- When granting permissions, a path must be specified. Global permissions need to be specified as root.**, while series-specific permissions must be absolute paths or prefix paths ending with a double wildcard. +- When granting user/role permissions, you can specify the "with grant option" keyword for that permission, which means that the user can grant permissions on their authorized paths and can also revoke permissions on other users' authorized paths. For example, if User A is granted read permission for `group1.company1.**` with the grant option keyword, then A can grant read permissions to others on any node or series below `group1.company1`, and can also revoke read permissions on any node below `group1.company1` for other users. +- When revoking permissions, the revocation statement will match against all of the user's permission paths and clear the matched permission paths. For example, if User A has read permission for `group1.company1.factory1`, when revoking read permission for `group1.company1.**`, it will remove A's read permission for `group1.company1.factory1`. + + + +## 4. Authentication + +User permissions mainly consist of three parts: permission scope (path), permission type, and the "with grant option" flag: + +``` +userTest1: + root.t1.** - read_schema, read_data - with grant option + root.** - write_schema, write_data - with grant option +``` + +Each user has such a permission access list, identifying all the permissions they have acquired. You can view their permissions by using the command `LIST PRIVILEGES OF USER `. + +When authorizing a path, the database will match the path with the permissions. For example, when checking the read_schema permission for `root.t1.t2`, it will first match with the permission access list `root.t1.**`. If it matches successfully, it will then check if that path contains the permission to be authorized. If not, it continues to the next path-permission match until a match is found or all matches are exhausted. + +When performing authorization for multiple paths, such as executing a multi-path query task, the database will only present data for which the user has permissions. Data for which the user does not have permissions will not be included in the results, and information about these paths without permissions will be output to the alert messages. + +Please note that the following operations require checking multiple permissions: + +1. Enabling the automatic sequence creation feature requires not only write permission for the corresponding sequence when a user inserts data into a non-existent sequence but also metadata modification permission for the sequence. + +2. When executing the "select into" statement, it is necessary to check the read permission for the source sequence and the write permission for the target sequence. It should be noted that the source sequence data may only be partially accessible due to insufficient permissions, and if the target sequence has insufficient write permissions, an error will occur, terminating the task. + +3. View permissions and data source permissions are independent. Performing read and write operations on a view will only check the permissions of the view itself and will not perform permission validation on the source path. + + +## 5. Function Syntax and Examples + +IoTDB provides composite permissions for user authorization: + +| Permission Name | Permission Scope | +|-----------------|--------------------------| +| ALL | All permissions | +| READ | READ_SCHEMA, READ_DATA | +| WRITE | WRITE_SCHEMA, WRITE_DATA | + +Composite permissions are not specific permissions themselves but a shorthand way to denote a combination of permissions, with no difference from directly specifying the corresponding permission names. + +The following series of specific use cases will demonstrate the usage of permission statements. Non-administrator users executing the following statements require obtaining the necessary permissions, which are indicated after the operation description. + +### 5.1 User and Role Related + +- Create user (Requires MANAGE_USER permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- Delete user (Requires MANAGE_USER permission) + +```sql +DROP USER +eg: DROP USER user1 +``` + +- Create role (Requires MANAGE_ROLE permission) + +```sql +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- Delete role (Requires MANAGE_ROLE permission) + +```sql +DROP ROLE +eg: DROP ROLE role1 +``` + +- Grant role to user (Requires MANAGE_ROLE permission) + +```sql +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- Revoke role from user(Requires MANAGE_ROLE permission) + +```sql +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- List all user (Requires MANAGE_USER permission) + +```sql +LIST USER +``` + +- List all role (Requires MANAGE_ROLE permission) + +```sql +LIST ROLE +``` + +- List all users granted specific role.(Requires MANAGE_USER permission) + +```sql +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- List all role granted to specific user. + + Users can list their own roles, but listing roles of other users requires the MANAGE_ROLE permission. + +```sql +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- List all privileges of user + +Users can list their own privileges, but listing privileges of other users requires the MANAGE_USER permission. + +```sql +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; +``` + +- List all privileges of role + +Users can list the permission information of roles they have, but listing permissions of other roles requires the MANAGE_ROLE permission. + +```sql +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- Modify password + +Users can modify their own password, but modifying passwords of other users requires the MANAGE_USER permission. + +```sql +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 5.2 Authorization and Deauthorization + +Users can use authorization statements to grant permissions to other users. The syntax is as follows: + +```sql +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +Users can use deauthorization statements to revoke permissions from others. The syntax is as follows: + +```sql +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + +- **When non-administrator users execute authorization/deauthorization statements, they need to have \ permissions on \, and these permissions must be marked with WITH GRANT OPTION.** + +- When granting or revoking global permissions or when the statement contains global permissions (expanding ALL includes global permissions), you must specify the path as root**. For example, the following authorization/deauthorization statements are valid: + + ```sql + GRANT MANAGE_USER ON root.** TO USER user1; + GRANT MANAGE_ROLE ON root.** TO ROLE role1 WITH GRANT OPTION; + GRANT ALL ON root.** TO role role1 WITH GRANT OPTION; + REVOKE MANAGE_USER ON root.** FROM USER user1; + REVOKE MANAGE_ROLE ON root.** FROM ROLE role1; + REVOKE ALL ON root.** FROM ROLE role1; + ``` + + The following statements are invalid: + + ```sql + GRANT READ, MANAGE_ROLE ON root.t1.** TO USER user1; + GRANT ALL ON root.t1.t2 TO USER user1 WITH GRANT OPTION; + REVOKE ALL ON root.t1.t2 FROM USER user1; + REVOKE READ, MANAGE_ROLE ON root.t1.t2 FROM ROLE ROLE1; + ``` + +- \ must be a full path or a matching path ending with a double wildcard. The following paths are valid: + + ```sql + root.** + root.t1.t2.** + root.t1.t2.t3 + ``` + + The following paths are invalid: + + ```sql + root.t1.* + root.t1.**.t2 + root.t1*.t2.t3 + ``` + + + +## 6. Examples + + Based on the described [sample data](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt), IoTDB's sample data may belong to different power generation groups such as ln, sgcc, and so on. Different power generation groups do not want other groups to access their database data, so we need to implement data isolation at the group level. + +#### Create Users +Use `CREATE USER ` to create users. For example, we can create two users for the ln and sgcc groups with the root user, who has all permissions, and name them ln_write_user and sgcc_write_user. It is recommended to enclose the username in backticks. The SQL statements are as follows: +```SQL +CREATE USER `ln_write_user` 'write_pwd' +CREATE USER `sgcc_write_user` 'write_pwd' +``` + +Now, using the SQL statement to display users: + +```sql +LIST USER +``` + +We can see that these two users have been created, and the result is as follows: + +```sql +IoTDB> CREATE USER `ln_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> CREATE USER `sgcc_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> LIST USER; ++---------------+ +| user| ++---------------+ +| ln_write_user| +| root| +|sgcc_write_user| ++---------------+ +Total line number = 3 +It costs 0.012s +``` + +#### Granting Permissions to Users + +At this point, although two users have been created, they do not have any permissions, so they cannot operate on the database. For example, if we use the ln_write_user to write data to the database, the SQL statement is as follows: + +```sql +INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +``` + +At this point, the system does not allow this operation, and an error is displayed: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +Now, we will grant each user write permissions to the corresponding paths using the root user. + +We use the `GRANT ON TO USER ` statement to grant permissions to users, for example: + +```sql +GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +``` + +The execution status is as follows: + +```sql +IoTDB> GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +Then, using ln_write_user, try to write data again: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: The statement is executed successfully. +``` + +#### Revoking User Permissions + +After granting user permissions, we can use the `REVOKE ON FROM USER ` to revoke the permissions granted to users. For example, using the root user to revoke the permissions of ln_write_user and sgcc_write_user: + +```sql +REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +``` + + +The execution status is as follows: + +```sql +IoTDB> REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +After revoking the permissions, ln_write_user no longer has the permission to write data to root.ln.**: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +## 7. Other Explanations + +Roles are collections of permissions, and both permissions and roles are attributes of users. In other words, a role can have multiple permissions, and a user can have multiple roles and permissions (referred to as the user's self-permissions). + +Currently, in IoTDB, there are no conflicting permissions. Therefore, the actual permissions a user has are the union of their self-permissions and the permissions of all their roles. In other words, to determine if a user can perform a certain operation, it's necessary to check whether their self-permissions or the permissions of all their roles allow that operation. Self-permissions, role permissions, and the permissions of multiple roles a user has may contain the same permission, but this does not have any impact. + +It's important to note that if a user has a certain permission (corresponding to operation A) on their own, and one of their roles has the same permission, revoking the permission from the user alone will not prevent the user from performing operation A. To prevent the user from performing operation A, you need to revoke the permission from both the user and the role, or remove the user from the role that has the permission. Similarly, if you only revoke the permission from the role, it won't prevent the user from performing operation A if they have the same permission on their own. + +At the same time, changes to roles will be immediately reflected in all users who have that role. For example, adding a certain permission to a role will immediately grant that permission to all users who have that role, and removing a certain permission will cause those users to lose that permission (unless the user has it on their own). + + + +## 8. Upgrading from a previous version + +Before version 1.3, there were many different permission types. In 1.3 version's implementation, we have streamlined the permission types. + +The permission paths in version 1.3 of the database must be either full paths or matching paths ending with a double wildcard. During system upgrades, any invalid permission paths and permission types will be automatically converted. The first invalid node on the path will be replaced with "**", and any unsupported permission types will be mapped to the permissions supported by the current system. + +| Permission | Path | Mapped-Permission | Mapped-path | +|-------------------|-----------------|-------------------|---------------| +| CREATE_DATBASE | root.db.t1.* | MANAGE_DATABASE | root.** | +| INSERT_TIMESERIES | root.db.t2.*.t3 | WRITE_DATA | root.db.t2.** | +| CREATE_TIMESERIES | root.db.t2*c.t3 | WRITE_SCHEMA | root.db.** | +| LIST_ROLE | root.** | (ignore) | | + + + +You can refer to the table below for a comparison of permission types between the old and new versions (where "--IGNORE" indicates that the new version ignores that permission): + +| Permission Name | Path-Related | New Permission Name | Path-Related | +|---------------------------|--------------|---------------------|--------------| +| CREATE_DATABASE | YES | MANAGE_DATABASE | NO | +| INSERT_TIMESERIES | YES | WRITE_DATA | YES | +| UPDATE_TIMESERIES | YES | WRITE_DATA | YES | +| READ_TIMESERIES | YES | READ_DATA | YES | +| CREATE_TIMESERIES | YES | WRITE_SCHEMA | YES | +| DELETE_TIMESERIES | YES | WRITE_SCHEMA | YES | +| CREATE_USER | NO | MANAGE_USER | NO | +| DELETE_USER | NO | MANAGE_USER | NO | +| MODIFY_PASSWORD | NO | -- IGNORE | | +| LIST_USER | NO | -- IGNORE | | +| GRANT_USER_PRIVILEGE | NO | -- IGNORE | | +| REVOKE_USER_PRIVILEGE | NO | -- IGNORE | | +| GRANT_USER_ROLE | NO | MANAGE_ROLE | NO | +| REVOKE_USER_ROLE | NO | MANAGE_ROLE | NO | +| CREATE_ROLE | NO | MANAGE_ROLE | NO | +| DELETE_ROLE | NO | MANAGE_ROLE | NO | +| LIST_ROLE | NO | -- IGNORE | | +| GRANT_ROLE_PRIVILEGE | NO | -- IGNORE | | +| REVOKE_ROLE_PRIVILEGE | NO | -- IGNORE | | +| CREATE_FUNCTION | NO | USE_UDF | NO | +| DROP_FUNCTION | NO | USE_UDF | NO | +| CREATE_TRIGGER | YES | USE_TRIGGER | NO | +| DROP_TRIGGER | YES | USE_TRIGGER | NO | +| START_TRIGGER | YES | USE_TRIGGER | NO | +| STOP_TRIGGER | YES | USE_TRIGGER | NO | +| CREATE_CONTINUOUS_QUERY | NO | USE_CQ | NO | +| DROP_CONTINUOUS_QUERY | NO | USE_CQ | NO | +| ALL | NO | All privilegs | | +| DELETE_DATABASE | YES | MANAGE_DATABASE | NO | +| ALTER_TIMESERIES | YES | WRITE_SCHEMA | YES | +| UPDATE_TEMPLATE | NO | -- IGNORE | | +| READ_TEMPLATE | NO | -- IGNORE | | +| APPLY_TEMPLATE | YES | WRITE_SCHEMA | YES | +| READ_TEMPLATE_APPLICATION | NO | -- IGNORE | | +| SHOW_CONTINUOUS_QUERIES | NO | -- IGNORE | | +| CREATE_PIPEPLUGIN | NO | USE_PIPE | NO | +| DROP_PIPEPLUGINS | NO | USE_PIPE | NO | +| SHOW_PIPEPLUGINS | NO | -- IGNORE | | +| CREATE_PIPE | NO | USE_PIPE | NO | +| START_PIPE | NO | USE_PIPE | NO | +| STOP_PIPE | NO | USE_PIPE | NO | +| DROP_PIPE | NO | USE_PIPE | NO | +| SHOW_PIPES | NO | -- IGNORE | | +| CREATE_VIEW | YES | WRITE_SCHEMA | YES | +| ALTER_VIEW | YES | WRITE_SCHEMA | YES | +| RENAME_VIEW | YES | WRITE_SCHEMA | YES | +| DELETE_VIEW | YES | WRITE_SCHEMA | YES | diff --git a/src/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md b/src/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md index 39fa9f999..8050ad9a4 100644 --- a/src/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md +++ b/src/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md @@ -590,50 +590,50 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :----------------------------------------------------------- | :------- | :------------ | -| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | #### iotdb-air-gap-sink -| key | value | value Range | required or not | Default Value | -| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- | :----------- | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Required | - | -| node-urls | The URL of the data service port of any DataNode nodes on the target IoTDB | String. Example: :'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Required | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| air-gap.handshake-timeout-ms | The timeout duration of the handshake request when the sender and receiver first attempt to establish a connection, unit: ms | Integer | Optional | 5000 | +| key | value | value Range | required or not | Default Value | +| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Required | - | +| node-urls | The URL of the data service port of any DataNode nodes on the target IoTDB | String. Example: :'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Required | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| air-gap.handshake-timeout-ms | The timeout duration of the handshake request when the sender and receiver first attempt to establish a connection, unit: ms | Integer | Optional | 5000 | #### iotdb-thrift-ssl-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------| :------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------|:---------------------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | diff --git a/src/UserGuide/latest/User-Manual/Data-subscription.md b/src/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md similarity index 99% rename from src/UserGuide/latest/User-Manual/Data-subscription.md rename to src/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md index 3d219df6b..6fc310866 100644 --- a/src/UserGuide/latest/User-Manual/Data-subscription.md +++ b/src/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md @@ -130,7 +130,7 @@ Result set: ## 4. API interface -In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API.md)). +In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API_apache)). ## 5. Frequently Asked Questions diff --git a/src/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md b/src/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md new file mode 100644 index 000000000..2d13c01b8 --- /dev/null +++ b/src/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md @@ -0,0 +1,148 @@ +# Data Subscription + +## 1. Feature Introduction + +The IoTDB data subscription module (also known as the IoTDB subscription client) is a feature supported after IoTDB V1.3.3, which provides users with a streaming data consumption method that is different from data queries. It refers to the basic concepts and logic of message queue products such as Kafka, **providing data subscription and consumption interfaces**, but it is not intended to completely replace these consumer queue products. Instead, it offers more convenient data subscription services for scenarios where simple streaming data acquisition is needed. + +Using the IoTDB Subscription Client to consume data has significant advantages in the following application scenarios: + +1. **Continuously obtaining the latest data**: By using a subscription method, it is more real-time than scheduled queries, simpler to program applications, and has a lower system burden; + +2. **Simplify data push to third-party systems**: No need to develop data push components for different systems within IoTDB, data can be streamed within third-party systems, making it easier to send data to systems such as Flink, Kafka, DataX, Camel, MySQL, PG, etc. + +## 2. Key Concepts + +The IoTDB Subscription Client encompasses three core concepts: Topic, Consumer, and Consumer Group. The specific relationships are illustrated in the diagram below: + +
+ +
+ +1. **Topic**: Topic is the data space of IoTDB, represented by paths and time ranges (such as the full time range of root. * *). Consumers can subscribe to data on these topics (currently existing and future written). Unlike Kafka, IoTDB can create topics after data is stored, and the output format can be either Message or TsFile. + +2. **Consumer**: Consumer is an IoTDB subscription client is located, responsible for receiving and processing data published to specific topics. Consumers retrieve data from the queue and process it accordingly. There are two types of Consumers available in the IoTDB subscription client: + - `SubscriptionPullConsumer`, which corresponds to the pull consumption model in message queues, where user code needs to actively invoke data retrieval logic. + - `SubscriptionPushConsumer`, which corresponds to the push consumption model in message queues, where user code is triggered by newly arriving data events. + + +3. **Consumer Group**: A Consumer Group is a collection of Consumers who share the same Consumer Group ID. The Consumer Group has the following characteristics: + - Consumer Group and Consumer are in a one to many relationship. That is, there can be any number of consumers in a consumer group, but a consumer is not allowed to join multiple consumer groups simultaneously. + - A Consumer Group can have different types of Consumers (`SubscriptionPullConsumer` and `SubscriptionPushConsumer`). + - It is not necessary for all consumers in a Consumer Group to subscribe to the same topic. + - When different Consumers in the same Consumer Group subscribe to the same Topic, each piece of data under that Topic will only be processed by one Consumer within the group, ensuring that data is not processed repeatedly. + +## 3. SQL Statements + +### 3.1 Topic Management + +IoTDB supports the creation, deletion, and viewing of Topics through SQL statements. The status changes of Topics are illustrated in the diagram below: + +
+ +
+ +#### 3.1.1 Create Topic + +The SQL statement is as follows: + +```SQL + CREATE TOPIC [IF NOT EXISTS] + WITH ( + [ = ,], + ); +``` + +**IF NOT EXISTS semantics**: Used in creation operations to ensure that the create command is executed when the specified topic does not exist, preventing errors caused by attempting to create an existing topic. + +Detailed explanation of each parameter is as follows: + +| Key | Required or Optional with Default | Description | +| :-------------------------------------------- | :--------------------------------- | :----------------------------------------------------------- | +| **path** | optional: `root.**` | The path of the time series data corresponding to the topic, representing a set of time series to be subscribed. | +| **start-time** | optional: `MIN_VALUE` | The start time (event time) of the time series data corresponding to the topic. Can be in ISO format, such as 2011-12-03T10:15:30 or 2011-12-03T10:15:30+01:00, or a long value representing a raw timestamp consistent with the database's timestamp precision. Supports the special value `now`, which means the creation time of the topic. When start-time is `now` and end-time is MAX_VALUE, it indicates that only real-time data is subscribed. | +| **end-time** | optional: `MAX_VALUE` | The end time (event time) of the time series data corresponding to the topic. Can be in ISO format, such as 2011-12-03T10:15:30 or 2011-12:03T10:15:30+01:00, or a long value representing a raw timestamp consistent with the database's timestamp precision. Supports the special value `now`, which means the creation time of the topic. When end-time is `now` and start-time is MIN_VALUE, it indicates that only historical data is subscribed. | +| **processor** | optional: `do-nothing-processor` | The name and parameter configuration of the processor plugin, representing the custom processing logic applied to the original subscribed data, which can be specified in a similar way to pipe processor plugins. + | +| **format** | optional: `SessionDataSetsHandler` | Represents the form in which data is subscribed from the topic. Currently supports the following two forms of data: `SessionDataSetsHandler`: Data subscribed from the topic is obtained using `SubscriptionSessionDataSetsHandler`, and consumers can consume each piece of data row by row. `TsFileHandler`: Data subscribed from the topic is obtained using `SubscriptionTsFileHandler`, and consumers can directly subscribe to the TsFile storing the corresponding data. | +| **mode** **(supported in versions 1.3.3.2 and later)** | option: `live` | The subscription mode corresponding to the topic, with two options: `live`: When subscribing to this topic, the subscribed dataset mode is a dynamic dataset, which means that you can continuously consume the latest data. `snapshot`: When the consumer subscribes to this topic, the subscribed dataset mode is a static dataset, which means the snapshot of the data at the moment the consumer group subscribes to the topic (not the moment the topic is created); the formed static dataset after subscription does not support TTL.| +| **loose-range** **(supported in versions 1.3.3.2 and later)** | option: `""` | String: Whether to strictly filter the data corresponding to this topic according to the path and time range, for example: "": Strictly filter the data corresponding to this topic according to the path and time range. `"time"`: Do not strictly filter the data corresponding to this topic according to the time range (rough filter); strictly filter the data corresponding to this topic according to the path. `"path"`: Do not strictly filter the data corresponding to this topic according to the path (rough filter); strictly filter the data corresponding to this topic according to the time range. `"time, path"` / `"path, time"` / `"all"`: Do not strictly filter the data corresponding to this topic according to the path and time range (rough filter).| + +Examples are as follows: + +```SQL +-- Full subscription +CREATE TOPIC root_all; + +-- Custom subscription +CREATE TOPIC IF NOT EXISTS db_timerange +WITH ( + 'path' = 'root.db.**', + 'start-time' = '2023-01-01', + 'end-time' = '2023-12-31' +); +``` + +#### 3.1.2 Delete Topic + +A Topic can only be deleted if it is not subscribed to. When a Topic is deleted, its related consumption progress will be cleared. + +```SQL +DROP TOPIC [IF EXISTS] ; +``` +**IF EXISTS semantics**: Used in deletion operations to ensure that the delete command is executed when a specified topic exists, preventing errors caused by attempting to delete non-existent topics. + +#### 3.1.3 View Topic + +```SQL +SHOW TOPICS; +SHOW TOPIC ; +``` + +Result set: + +```SQL +[TopicName|TopicConfigs] +``` + +- TopicName: Topic ID +- TopicConfigs: Topic configurations + +### 3.2 Check Subscription Status + +View all subscription relationships: + +```SQL +-- Query the subscription relationships between all topics and consumer groups +SHOW SUBSCRIPTIONS +-- Query all subscriptions under a specific topic +SHOW SUBSCRIPTIONS ON +``` + +Result set: + +```SQL +[TopicName|ConsumerGroupName|SubscribedConsumers] +``` + +- TopicName: The ID of the topic. +- ConsumerGroupName: The ID of the consumer group specified in the user's code. +- SubscribedConsumers: All client IDs in the consumer group that have subscribed to the topic. + +## 4. API interface + +In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API_timecho)). + + +## 5. Frequently Asked Questions + +### 5.1 What is the difference between IoTDB data subscription and Kafka? + +1. Consumption Orderliness + +- **Kafka guarantees that messages within a single partition are ordered**,when a topic corresponds to only one partition and only one consumer subscribes to this topic, the order in which the consumer (single-threaded) consumes the topic data is the same as the order in which the data is written. +- The IoTDB subscription client **does not guarantee** that the order in which the consumer consumes the data is the same as the order in which the data is written, but it will try to reflect the order of data writing. + +2. Message Delivery Semantics + +- Kafka can achieve Exactly once semantics for both Producers and Consumers through configuration. +- The IoTDB subscription client currently cannot provide Exactly once semantics for Consumers. \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md b/src/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md index b136941e2..111bf1f01 100644 --- a/src/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md +++ b/src/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md @@ -308,7 +308,7 @@ AS SELECT temperature FROM root.db.* ``` -This is modelled on the query writeback (`SELECT INTO`) convention for naming rules, which uses variable placeholders to specify naming rules. See also: [QUERY WRITEBACK (SELECT INTO)](../Basic-Concept/Query-Data.md#into-clause-query-write-back) +This is modelled on the query writeback (`SELECT INTO`) convention for naming rules, which uses variable placeholders to specify naming rules. See also: [QUERY WRITEBACK (SELECT INTO)](../Basic-Concept/Query-Data_timecho#into-clause-query-write-back) Here `root.db.*.temperature` specifies what time series will be included in the view; and `${2}` specifies from which node in the time series the name is extracted to name the sequence view. diff --git a/src/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md b/src/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md index 2d3d56cf3..b6f07efdd 100644 --- a/src/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md +++ b/src/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md @@ -186,7 +186,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 When users use UDF, they will be involved in the `USE_UDF` permission, and only users with this permission are allowed to perform UDF registration, uninstallation, and query operations. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_apache). ## 3. UDF Libraries diff --git a/src/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md b/src/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md index 368138332..20cdd065f 100644 --- a/src/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md +++ b/src/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md @@ -187,7 +187,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 When users use UDF, they will be involved in the `USE_UDF` permission, and only users with this permission are allowed to perform UDF registration, uninstallation, and query operations. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_timecho). ## 3. UDF Libraries diff --git a/src/UserGuide/latest-Table/API/Programming-CSharp-Native-API.md b/src/UserGuide/latest-Table/API/Programming-CSharp-Native-API_apache.md similarity index 100% rename from src/UserGuide/latest-Table/API/Programming-CSharp-Native-API.md rename to src/UserGuide/latest-Table/API/Programming-CSharp-Native-API_apache.md diff --git a/src/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md b/src/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md new file mode 100644 index 000000000..fc89b0c2d --- /dev/null +++ b/src/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md @@ -0,0 +1,402 @@ + +# C# Native API + +## 1. Feature Overview + +IoTDB provides a C# native client driver and corresponding connection pool, offering object-oriented interfaces that allow direct assembly of time-series objects for writing without SQL construction. It is recommended to use the connection pool for multi-threaded parallel database operations. + +## 2. Usage Instructions + +**Environment Requirements:** + +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 + +**Dependency Installation:** + +It supports installation using tools such as NuGet Package Manager or .NET CLI. Taking .NET CLI as an example: + +If using .NET 5.0 or a later version of the SDK, enter the following command to install the latest NuGet package: + +```Plain +dotnet add package Apache.IoTDB +``` + +## 3. Read/Write Operations + +### 3.1 TableSessionPool + +#### 3.1.1 Functional Description + +The `TableSessionPool` defines basic operations for interacting with IoTDB, supporting data insertion, query execution, and session closure. It also serves as a connection pool to efficiently reuse connections and properly release resources when unused. This interface defines how to acquire sessions from the pool and how to close the pool. + +#### 3.1.2 Method List + +Below are the methods defined in `TableSessionPool` with detailed descriptions: + +| Method | Description | Parameters | Return Type | +| ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |-----------------------------------------------------------------------------------------------------------| ---------------------------- | +| `Open(bool enableRpcCompression)` | Opens a session connection with custom `enableRpcCompression` | `enableRpcCompression`: Whether to enable `RpcCompression` (requires server-side configuration alignment) | `Task` | +| `Open()` | Opens a session connection without enabling `RpcCompression` | None | `Task` | +| `InsertAsync(Tablet tablet)` | Inserts a `Tablet` object containing time-series data into the database | `tablet`: The Tablet object to insert | `Task` | +| `ExecuteNonQueryStatementAsync(string sql)` | Executes a non-query SQL statement (e.g., DDL/DML commands) | `sql`: The SQL statement to execute | `Task` | +| `ExecuteQueryStatementAsync(string sql)` | Executes a query SQL statement and returns a `SessionDataSet` with results | `sql`: The SQL query to execute | `Task` | +| `ExecuteQueryStatementAsync(string sql, long timeoutInMs)` | Executes a query SQL statement with a timeout (milliseconds) | `sql`: The SQL query to execute
`timeoutInMs`: Query timeout in milliseconds | `Task` | +| `Close()` | Closes the session and releases held resources | None | `Task` | + +#### 3.1.3 Interface Examples + +```C# +public async Task Open(bool enableRpcCompression, CancellationToken cancellationToken = default) + + public async Task Open(CancellationToken cancellationToken = default) + + public async Task InsertAsync(Tablet tablet) + + public async Task ExecuteNonQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql, long timeoutInMs) + + public async Task Close() +``` + +### 3.2 TableSessionPool.Builder + +#### 3.2.1 Functional Description + +The `TableSessionPool.Builder` class configures and creates instances of `TableSessionPool`, allowing developers to set connection parameters, session settings, and pooling behaviors. + +#### 3.2.2 Configuration Options + +Below are the available configuration options for `TableSessionPool.Builder` and their defaults: + +| ​**Configuration Method** | ​**Description** | ​**Default Value** | +| --------------------------------------------- | -------------------------------------------------------------------------------- |---------------------------------------------------| +| `SetHost(string host)` | Sets the IoTDB node host | `localhost` | +| `SetPort(int port)` | Sets the IoTDB node port | `6667` | +| `SetNodeUrls(List nodeUrls)` | Sets IoTDB cluster node URLs (overrides `SetHost`/`SetPort` when used) | Not set | +| `SetUsername(string username)` | Sets the connection username | `"root"` | +| `SetPassword(string password)` | Sets the connection password | `"TimechoDB@2021"` //before V2.0.6 it is root | +| `SetFetchSize(int fetchSize)` | Sets the fetch size for query results | `1024` | +| `SetZoneId(string zoneId)` | Sets the timezone ZoneID | `UTC+08:00` | +| `SetPoolSize(int poolSize)` | Sets the maximum number of sessions in the connection pool | `8` | +| `SetEnableRpcCompression(bool enable)` | Enables/disables RPC compression | `false` | +| `SetConnectionTimeoutInMs(int timeout)` | Sets the connection timeout in milliseconds | `500` | +| `SetDatabase(string database)` | Sets the target database name | `""` | + +#### 3.2.3 Interface Examples + +```c# +public Builder SetHost(string host) + { + _host = host; + return this; + } + + public Builder SetPort(int port) + { + _port = port; + return this; + } + + public Builder SetUsername(string username) + { + _username = username; + return this; + } + + public Builder SetPassword(string password) + { + _password = password; + return this; + } + + public Builder SetFetchSize(int fetchSize) + { + _fetchSize = fetchSize; + return this; + } + + public Builder SetZoneId(string zoneId) + { + _zoneId = zoneId; + return this; + } + + public Builder SetPoolSize(int poolSize) + { + _poolSize = poolSize; + return this; + } + + public Builder SetEnableRpcCompression(bool enableRpcCompression) + { + _enableRpcCompression = enableRpcCompression; + return this; + } + + public Builder SetConnectionTimeoutInMs(int timeout) + { + _connectionTimeoutInMs = timeout; + return this; + } + + public Builder SetNodeUrls(List nodeUrls) + { + _nodeUrls = nodeUrls; + return this; + } + + protected internal Builder SetSqlDialect(string sqlDialect) + { + _sqlDialect = sqlDialect; + return this; + } + + public Builder SetDatabase(string database) + { + _database = database; + return this; + } + + public Builder() + { + _host = "localhost"; + _port = 6667; + _username = "root"; + _password = "TimechoDB@2021"; //before V2.0.6 it is root + _fetchSize = 1024; + _zoneId = "UTC+08:00"; + _poolSize = 8; + _enableRpcCompression = false; + _connectionTimeoutInMs = 500; + _sqlDialect = IoTDBConstant.TABLE_SQL_DIALECT; + _database = ""; + } + + public TableSessionPool Build() + { + SessionPool sessionPool; + // if nodeUrls is not empty, use nodeUrls to create session pool + if (_nodeUrls.Count > 0) + { + sessionPool = new SessionPool(_nodeUrls, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + else + { + sessionPool = new SessionPool(_host, _port, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + return new TableSessionPool(sessionPool); + } +``` + +## 4. Example + +Complete example : [samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs](https://github.com/apache/iotdb-client-csharp/blob/main/samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs) + +```c# +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Apache.IoTDB.DataStructure; + +namespace Apache.IoTDB.Samples; + +public class TableSessionPoolTest +{ + private readonly SessionPoolTest sessionPoolTest; + + public TableSessionPoolTest(SessionPoolTest sessionPoolTest) + { + this.sessionPoolTest = sessionPoolTest; + } + + public async Task Test() + { + await TestCleanup(); + + await TestSelectAndInsert(); + await TestUseDatabase(); + // await TestCleanup(); + } + + + public async Task TestSelectAndInsert() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test2"); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // or use full qualified table name + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table test1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + // show tables by specifying another database + // using SHOW tables FROM + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES FROM test1"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + var tableName = "testTable1"; + List columnNames = + new List { + "region_id", + "plant_id", + "device_id", + "model", + "temperature", + "humidity" }; + List dataTypes = + new List{ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.FLOAT, + TSDataType.DOUBLE}; + List columnCategories = + new List{ + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.ATTRIBUTE, + ColumnCategory.FIELD, + ColumnCategory.FIELD}; + var values = new List> { }; + var timestamps = new List { }; + for (long timestamp = 0; timestamp < 100; timestamp++) + { + timestamps.Add(timestamp); + values.Add(new List { "1", "5", "3", "A", 1.23F + timestamp, 111.1 + timestamp }); + } + var tablet = new Tablet(tableName, columnNames, columnCategories, dataTypes, values, timestamps); + + await tableSessionPool.InsertAsync(tablet); + + + res = await tableSessionPool.ExecuteQueryStatementAsync("select * from testTable1 " + + "where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + + public async Task TestUseDatabase() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetDatabase("test1") + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // show tables from current database + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + public async Task TestCleanup() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test2"); + + await tableSessionPool.Close(); + } +} +``` diff --git a/src/UserGuide/latest-Table/API/Programming-Cpp-Native-API.md b/src/UserGuide/latest-Table/API/Programming-Cpp-Native-API_apache.md similarity index 100% rename from src/UserGuide/latest-Table/API/Programming-Cpp-Native-API.md rename to src/UserGuide/latest-Table/API/Programming-Cpp-Native-API_apache.md diff --git a/src/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md b/src/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md new file mode 100644 index 000000000..22c41a533 --- /dev/null +++ b/src/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md @@ -0,0 +1,250 @@ + + +# C++ Native API + +## 1. Dependencies + +- Java 8+ +- Flex +- Bison 2.7+ +- Boost 1.56+ +- OpenSSL 1.0+ +- GCC 5.5.0+ + +## 2. Installation + +### 2.1 Install Required Dependencies + +- **MAC** + 1. Install Bison: + + Use the following brew command to install the Bison version: + ```shell + brew install bison + ``` + + 2. Install Boost: Make sure to install the latest version of Boost. + + ```shell + brew install boost + ``` + + 3. Check OpenSSL: Make sure the OpenSSL library is installed. The default OpenSSL header file path is "/usr/local/opt/openssl/include". + + If you encounter errors related to OpenSSL not being found during compilation, try adding `-Dopenssl.include.dir=""`. + +- **Ubuntu 16.04+ or Other Debian-based Systems** + + Use the following commands to install dependencies: + + ```shell + sudo apt-get update + sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-dev + ``` + +- **CentOS 7.7+/Fedora/Rocky Linux or Other Red Hat-based Systems** + + Use the yum command to install dependencies: + + ```shell + sudo yum update + sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel + ``` + +- **Windows** + + 1. Set Up the Build Environment + - Install MS Visual Studio (version 2019+ recommended): Make sure to select Visual Studio C/C++ IDE and compiler (supporting CMake, Clang, MinGW) during installation. + - Download and install [CMake](https://cmake.org/download/). + + 2. Download and Install Flex, Bison + - Download [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/). + - After downloading, rename the executables to flex.exe and bison.exe to ensure they can be found during compilation, and add the directory of these executables to the PATH environment variable. + + 3. Install Boost Library + - Download [Boost](https://www.boost.org/users/download/). + - Compile Boost locally: Run `bootstrap.bat` and `b2.exe` in sequence. + - Add the Boost installation directory to the PATH environment variable, e.g., `C:\Program Files (x86)\boost_1_78_0`. + + 4. Install OpenSSL + - Download and install [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html). + - Add the include directory under the installation directory to the PATH environment variable. + +### 2.2 Compilation + +Clone the source code from git: +```shell +git clone https://github.com/apache/iotdb.git +``` + +The default main branch is the master branch. If you want to use a specific release version, switch to that branch (e.g., version 1.3.2): +```shell +git checkout rc/1.3.2 +``` + +Run Maven to compile in the IoTDB root directory: + +- Mac or Linux with glibc version >= 2.32 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- Linux with glibc version >= 2.31 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT + ``` + +- Linux with glibc version >= 2.17 + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT + ``` + +- Windows using Visual Studio 2022 + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- Windows using Visual Studio 2019 + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 16 2019" -Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT + ``` + - If you haven't added the Boost library path to the PATH environment variable, you need to add the relevant parameters to the compile command, e.g., `-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"`. + +After successful compilation, the packaged library files will be located in `iotdb-client/client-cpp/target`, and you can find the compiled example program under `example/client-cpp-example/target`. + +### 2.3 Compilation Q&A + +Q: What are the requirements for the environment on Linux? + +A: +- The known minimum version requirement for glibc (x86_64 version) is 2.17, and the minimum version for GCC is 5.5. +- The known minimum version requirement for glibc (ARM version) is 2.31, and the minimum version for GCC is 10.2. +- If the above requirements are not met, you can try compiling Thrift locally: + - Download the code from https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift. + - Run `./mvnw clean install`. + - Go back to the IoTDB code directory and run `./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp`. + +Q: How to resolve the `undefined reference to '_libc_single_thread'` error during Linux compilation? + +A: +- This issue is caused by the precompiled Thrift dependencies requiring a higher version of glibc. +- You can try adding `-Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT` or `-Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT` to the Maven compile command. + +Q: What if I need to compile using Visual Studio 2017 or earlier on Windows? + +A: +- You can try compiling Thrift locally before compiling the client: + - Download the code from https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift. + - Run `.\mvnw.cmd clean install`. + - Go back to the IoTDB code directory and run `.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 15 2017"`. + +## 3. Usage + +### 3.1 TableSession Class + +All operations in the C++ client are performed through the TableSession class. Below are the method descriptions defined in the TableSession interface. + +#### 3.1.1 Method List + +1. `insert(Tablet& tablet, bool sorted = false)`: Inserts a Tablet object containing time series data into the database. The sorted parameter indicates whether the rows in the tablet are already sorted by time. +2. `executeNonQueryStatement(string& sql)`: Executes non-query SQL statements, such as DDL (Data Definition Language) or DML (Data Manipulation Language) commands. +3. `executeQueryStatement(string& sql)`: Executes query SQL statements and returns a SessionDataSet object containing the query results. The optional timeoutInMs parameter indicates the timeout return time. +4. `open(bool enableRPCCompression = false)`: Opens the connection and determines whether to enable RPC compression (client state must match server state, disabled by default). +5. `close()`: Closes the connection. + +#### 3.1.2 Interface Display + +```cpp +class TableSession { +private: + Session* session; +public: + TableSession(Session* session) { + this->session = session; + } + void insert(Tablet& tablet, bool sorted = false); + void executeNonQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql, int64_t timeoutInMs); + string getDatabase(); //Get the currently selected database, can be replaced by executeNonQueryStatement + void open(bool enableRPCCompression = false); + void close(); +}; +``` + +### 3.2 TableSessionBuilder Class + +The TableSessionBuilder class is a builder used to configure and create instances of the TableSession class. Through it, you can conveniently set connection parameters, query parameters, and other settings when creating instances. + +#### 3.2.1 Usage Example + +```cpp +//Set connection IP, port, username, password +//The order of settings is arbitrary, just ensure build() is called last, the created instance is connected by default through open() +session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //before V2.0.6 it is root + ->build(); +``` + +#### 3.2.2 Configurable Parameter List + +| **Parameter Name** | **Description** | **Default Value** | +| :---: | :---: |:-------------------------------------------:| +| host | Set the connected node IP | "127.0.0.1" ("localhost") | +| rpcPort | Set the connected node port | 6667 | +| username | Set the connection username | "root" | +| password | Set the connection password | "TimechoDB@2021" //before V2.0.6 it is root | +| zoneId | Set the ZoneId related to timezone | "" | +| fetchSize | Set the query result fetch size | 10000 | +| database | Set the target database name | "" | + +## 4. Examples + +The sample code of using these interfaces is in: + +- `example/client-cpp-example/src/TableSessionExample.cpp`: [TableSessionExample](https://github.com/apache/iotdb/tree/rc/2.0.1/example/client-cpp-example/src/TableSessionExample.cpp) + +If the compilation finishes successfully, the example project will be placed under `example/client-cpp-example/target` + +## 5. FAQ + +### 5.1 on Mac + +If errors occur when compiling thrift source code, try to downgrade your xcode-commandline from 12 to 11.5 + +see https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087 + + +### 5.2 on Windows + +When Building Thrift and downloading packages via "wget", a possible annoying issue may occur with +error message looks like: +```shell +Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser +``` +Possible fixes: +- Try to delete the ".m2\repository\\.cache\" directory and try again. +- Add "\true\" configuration to the download-maven-plugin maven phase that complains this error. + diff --git a/src/UserGuide/latest-Table/API/Programming-Go-Native-API.md b/src/UserGuide/latest-Table/API/Programming-Go-Native-API_apache.md similarity index 100% rename from src/UserGuide/latest-Table/API/Programming-Go-Native-API.md rename to src/UserGuide/latest-Table/API/Programming-Go-Native-API_apache.md diff --git a/src/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md b/src/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md new file mode 100644 index 000000000..c0d6afb8c --- /dev/null +++ b/src/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md @@ -0,0 +1,571 @@ + + +# Go Native API + +The Git repository for the Go Native API client is located [here](https://github.com/apache/iotdb-client-go/) + +## 1. Usage +### 1.1 Dependencies + +* golang >= 1.13 +* make >= 3.0 +* curl >= 7.1.1 +* thrift 0.15.0 +* Linux、Macos or other unix-like systems +* Windows+bash (WSL、cygwin、Git Bash) + +### 1.2 Installation + +* go mod + +```sh +export GO111MODULE=on +export GOPROXY=https://goproxy.io + +mkdir session_example && cd session_example + +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +go mod init session_example +go run session_example.go +``` + +* GOPATH + +```sh +# get thrift 0.15.0 +go get github.com/apache/thrift +cd $GOPATH/src/github.com/apache/thrift +git checkout 0.15.0 + +mkdir -p $GOPATH/src/iotdb-client-go-example/session_example +cd $GOPATH/src/iotdb-client-go-example/session_example +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go +go run session_example.go +``` + +## 2. ITableSession Interface +### 2.1 Description + +Defines core operations for interacting with IoTDB tables, including data insertion, query execution, and session closure. Not thread-safe. + +### 2.2 Method List + +| **Method Name** | **Description** | **Parameters** | **Return Value** | **Return Error** | +| -------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| `Insert(tablet *Tablet)` | Inserts a`Tablet`containing time-series data into the database.| `tablet`: A pointer to a Tablet containing time-series data to be inserted. | A pointer to TSStatus indicating the execution result. | An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `xecuteNonQueryStatement(sql string)`| Executes non-query SQL statements such as DDL or DML commands. | `sql`: The SQL statement to execute.| A pointer to TSStatus indicating the execution result.| An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `ExecuteQueryStatement (sql string, timeoutInMs *int64)` | Executes a query SQL statement with a specified timeout in milliseconds. | `sql`: The SQL query statement.`timeoutInMs`: Query timeout in milliseconds. | A pointer to SessionDataSet containing the query results. | An error if an issue occurs during the operation, such as a connection error or execution failure. | +| `Close()` | Closes the session and releases resources. | None | None | An error if there is an issue with closing the IoTDB connection. | + +### 2.3 Interface Definition +1. ITableSession + +```go +// ITableSession defines an interface for interacting with IoTDB tables. +// It supports operations such as data insertion, executing queries, and closing the session. +// Implementations of this interface are expected to manage connections and ensure +// proper resource cleanup. +// +// Each method may return an error to indicate issues such as connection errors +// or execution failures. +// +// Since this interface includes a Close method, it is recommended to use +// defer to ensure the session is properly closed. +type ITableSession interface { + + // Insert inserts a Tablet into the database. + // + // Parameters: + // - tablet: A pointer to a Tablet containing time-series data to be inserted. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + Insert(tablet *Tablet) (r *common.TSStatus, err error) + + // ExecuteNonQueryStatement executes a non-query SQL statement, such as a DDL or DML command. + // + // Parameters: + // - sql: The SQL statement to execute. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err error) + + // ExecuteQueryStatement executes a query SQL statement and returns the result set. + // + // Parameters: + // - sql: The SQL query statement to execute. + // - timeoutInMs: A pointer to the timeout duration in milliseconds for the query execution. + // + // Returns: + // - result: A pointer to SessionDataSet containing the query results. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteQueryStatement(sql string, timeoutInMs *int64) (*SessionDataSet, error) + + // Close closes the session, releasing any held resources. + // + // Returns: + // - err: An error if there is an issue with closing the IoTDB connection. + Close() (err error) +} +``` + +2. Constructing a TableSession + +* There’s no need to manually set the `sqlDialect` field in the `Config`structs. This is automatically handled by the corresponding `NewSession` function during initialization. Simply use the appropriate constructor based on your use case (single-node or cluster). + +```Go +type Config struct { + Host string + Port string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Version Version + Database string +} + +type ClusterConfig struct { + NodeUrls []string //ip:port + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Database string +} + +// NewTableSession creates a new TableSession instance using the provided configuration. +// +// Parameters: +// - config: The configuration for the session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// - connectionTimeoutInMs: The timeout in milliseconds for establishing a connection. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewTableSession(config *Config, enableRPCCompression bool, connectionTimeoutInMs int) (ITableSession, error) + +// NewClusterTableSession creates a new TableSession instance for a cluster setup. +// +// Parameters: +// - clusterConfig: The configuration for the cluster session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewClusterTableSession(clusterConfig *ClusterConfig, enableRPCCompression bool) (ITableSession, error) +``` + +> Note: +> +> When creating a `TableSession` via `NewTableSession` or `NewClusterTableSession`, the connection is already established; no additional `Open` operation is required. + +### 2.4 Example + +```go +package main + +import ( + "flag" + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "math/rand" + "strconv" + "time" +) + +func main() { + flag.Parse() + config := &client.Config{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_session", + } + session, err := client.NewTableSession(config, false, 0) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + checkError(session.ExecuteNonQueryStatement("create database test_db")) + checkError(session.ExecuteNonQueryStatement("use test_db")) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + insertRelationalTablet(session) + showTables(session) + query(session) +} + +func getTextValueFromDataSet(dataSet *client.SessionDataSet, columnName string) string { + if dataSet.IsNull(columnName) { + return "null" + } else { + return dataSet.GetText(columnName) + } +} + +func insertRelationalTablet(session client.ITableSession) { + tablet, err := client.NewRelationalTablet("t1", []*client.MeasurementSchema{ + { + Measurement: "id1", + DataType: client.STRING, + }, + { + Measurement: "id2", + DataType: client.STRING, + }, + { + Measurement: "s1", + DataType: client.TEXT, + }, + { + Measurement: "s2", + DataType: client.TEXT, + }, + }, []client.ColumnCategory{client.TAG, client.TAG, client.FIELD, client.FIELD}, 1024) + if err != nil { + log.Fatal("Failed to create relational tablet {}", err) + } + ts := time.Now().UTC().UnixNano() / 1000000 + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_"+strconv.Itoa(row), 0, row) + tablet.SetValueAt("id2_field_"+strconv.Itoa(row), 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) + + tablet.Reset() + + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_1", 0, row) + tablet.SetValueAt("id2_field_1", 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + + nullValueColumn := rand.Intn(4) + tablet.SetValueAt(nil, nullValueColumn, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) +} + +func showTables(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("tableName is", dataSet.GetText("TableName")) + } +} + +func query(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("select * from t1", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("%v %v %v %v", getTextValueFromDataSet(dataSet, "id1"), getTextValueFromDataSet(dataSet, "id2"), getTextValueFromDataSet(dataSet, "s1"), getTextValueFromDataSet(dataSet, "s2")) + } +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + +## 3. TableSessionPool Interface +### 3.1 Description + +Manages a pool of `ITableSession` instances for efficient connection reuse and resource cleanup. + +### 3.2 Method List + +| **Method Name** | **Description** | **Return Value** | **Return Error** | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------- | ------------------------------------------- | +| `GetSession()` | Acquires a session from the pool for database interaction. | A usable ITableSession instance for interacting with IoTDB. | An error if a session cannot be acquired. | +| `Close()` | Closes the session pool and releases resources.。 | None | None | + +### 3.3 Interface Definition +1. TableSessionPool + +```Go +// TableSessionPool manages a pool of ITableSession instances, enabling efficient +// reuse and management of resources. It provides methods to acquire a session +// from the pool and to close the pool, releasing all held resources. +// +// This implementation ensures proper lifecycle management of sessions, +// including efficient reuse and cleanup of resources. + +// GetSession acquires an ITableSession instance from the pool. +// +// Returns: +// - A usable ITableSession instance for interacting with IoTDB. +// - An error if a session cannot be acquired. +func (spool *TableSessionPool) GetSession() (ITableSession, error) { + return spool.sessionPool.getTableSession() +} + +// Close closes the TableSessionPool, releasing all held resources. +// Once closed, no further sessions can be acquired from the pool. +func (spool *TableSessionPool) Close() +``` + +2. Constructing a TableSessionPool + +```Go +type PoolConfig struct { + Host string + Port string + NodeUrls []string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + Database string + sqlDialect string +} + +// NewTableSessionPool creates a new TableSessionPool with the specified configuration. +// +// Parameters: +// - conf: PoolConfig defining the configuration for the pool. +// - maxSize: The maximum number of sessions the pool can hold. +// - connectionTimeoutInMs: Timeout for establishing a connection in milliseconds. +// - waitToGetSessionTimeoutInMs: Timeout for waiting to acquire a session in milliseconds. +// - enableCompression: A boolean indicating whether to enable compression. +// +// Returns: +// - A TableSessionPool instance. +func NewTableSessionPool(conf *PoolConfig, maxSize, connectionTimeoutInMs, waitToGetSessionTimeoutInMs int, + enableCompression bool) TableSessionPool +``` + +> Note: +> +> * If a `Database` is specified when creating the `TableSessionPool`, all sessions acquired from the pool will automatically use this database. There is no need to explicitly set the database during operations. +> * Automatic State Reset: If a session temporarily switches to another database using `USE DATABASE` during usage, the session will automatically revert to the original database specified in the pool when closed and returned to the pool. + +### 3.4 Example + +```go +package main + +import ( + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "strconv" + "sync" + "sync/atomic" + "time" +) + +func main() { + sessionPoolWithSpecificDatabaseExample() + sessionPoolWithoutSpecificDatabaseExample() + putBackToSessionPoolExample() +} + +func putBackToSessionPoolExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 4000, false) + defer sessionPool.Close() + + num := 4 + successGetSessionNum := int32(0) + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database "+dbName+"because ", err) + return + } + atomic.AddInt32(&successGetSessionNum, 1) + defer func() { + time.Sleep(6 * time.Second) + // put back to session pool + session.Close() + }() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table table_of_" + dbName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() + log.Println("success num is", successGetSessionNum) + + log.Println("All session's database have been reset.") + // the using database will automatically reset to session pool's database after the session closed + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to get session because ", err) + } + defer session.Close() + timeout := int64(3000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Println("table is", dataSet.GetText("TableName")) + } + }() + } + wg.Wait() +} + +func sessionPoolWithSpecificDatabaseExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + tableName := "t" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create table "+tableName+"because ", err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create table " + tableName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func sessionPoolWithoutSpecificDatabaseExample() { + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //before V2.0.6 it is root + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database ", dbName, err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + diff --git a/src/UserGuide/latest-Table/API/Programming-JDBC_timecho.md b/src/UserGuide/latest-Table/API/Programming-JDBC_timecho.md index 2767e036d..5ef239cc9 100644 --- a/src/UserGuide/latest-Table/API/Programming-JDBC_timecho.md +++ b/src/UserGuide/latest-Table/API/Programming-JDBC_timecho.md @@ -120,7 +120,7 @@ public class TableModelJDBCExample { // don't specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "TimechoDB@2021"); //before V2.0.6 it is root Statement statement = connection.createStatement()) { statement.execute("CREATE DATABASE test1"); @@ -161,7 +161,7 @@ public class TableModelJDBCExample { // specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "TimechoDB@2021"); //before V2.0.6 it is root Statement statement = connection.createStatement()) { // show tables from current database test1 try (ResultSet resultSet = statement.executeQuery("SHOW TABLES")) { diff --git a/src/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md b/src/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md index ea4532116..c04b18e80 100644 --- a/src/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md +++ b/src/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md @@ -138,10 +138,10 @@ The `TableSessionBuilder` class is a builder for configuring and creating instan #### 3.2.2 Parameter Configuration | **Parameter** | **Description** | **Default Value** | -|-----------------------------------------------------| ------------------------------------------------------------ | ------------------------------------------------- | +|-----------------------------------------------------| ------------------------------------------------------------ |---------------------------------------------------| | nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("``localhost:6667``")` | | username(String username) | Sets the username for the connection. | `"root"` | -| password(String password) | Sets the password for the connection. | `"root"` | +| password(String password) | Sets the password for the connection. | `"TimechoDB@2021"` //before V2.0.6 it is root | | database(String database) | Sets the target database name. | `null` | | queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000` (1 minute) | | fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | @@ -202,7 +202,7 @@ public class TableSessionBuilder { * * @param password the password. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //before V2.0.6 it is root */ public TableSessionBuilder password(String password); @@ -397,28 +397,28 @@ The `TableSessionPoolBuilder` class is a builder for configuring and creating `I #### 4.2.2 Parameter Configuration -| **Parameter** | **Description** | **Default Value** | -|---------------------------------------------------------------| ------------------------------------------------------------ | --------------------------------------------- | -| nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("localhost:6667")` | -| maxSize(int maxSize) | Sets the maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `5` | -| user(String user) | Sets the username for the connection. | `"root"` | -| password(String password) | Sets the password for the connection. | `"root"` | -| database(String database) | Sets the target database name. | `"root"` | -| queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000`(1 minute) | -| fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | -| zoneId(ZoneId zoneId) | Sets the timezone-related `ZoneId`. | `ZoneId.systemDefault()` | -| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | Sets the timeout duration (in milliseconds) for acquiring a session from the pool. | `30000`(30 seconds) | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | Sets the default buffer size for the Thrift client (in bytes). | `1024`(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | Sets the maximum frame size for the Thrift client (in bytes). | `64 * 1024 * 1024`(64MB) | -| enableCompression(boolean enableCompression) | Enables or disables compression for the connection. | `false` | -| enableRedirection(boolean enableRedirection) | Enables or disables redirection for cluster nodes. | `true` | -| connectionTimeoutInMs(int connectionTimeoutInMs) | Sets the connection timeout in milliseconds. | `10000` (10 seconds) | -| enableAutoFetch(boolean enableAutoFetch) | Enables or disables automatic fetching of available DataNodes. | `true` | -| maxRetryCount(int maxRetryCount) | Sets the maximum number of connection retry attempts. | `60` | -| retryIntervalInMs(long retryIntervalInMs) | Sets the interval between retry attempts (in milliseconds). | `500` (500 milliseconds) | -| useSSL(boolean useSSL) | Enables or disables SSL for secure connections. | `false` | -| trustStore(String keyStore) | Sets the path to the trust store for SSL connections. | `null` | -| trustStorePwd(String keyStorePwd) | Sets the password for the SSL trust store. | `null` | +| **Parameter** | **Description** | **Default Value** | +|---------------------------------------------------------------| ------------------------------------------------------------ |------------------------------------------------| +| nodeUrls(List\ nodeUrls) | Sets the list of IoTDB cluster node URLs. | `Collections.singletonList("localhost:6667")` | +| maxSize(int maxSize) | Sets the maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `5` | +| user(String user) | Sets the username for the connection. | `"root"` | +| password(String password) | Sets the password for the connection. | `"TimechoDB@2021"` //before V2.0.6 it is root | +| database(String database) | Sets the target database name. | `"root"` | +| queryTimeoutInMs(long queryTimeoutInMs) | Sets the query timeout in milliseconds. | `60000`(1 minute) | +| fetchSize(int fetchSize) | Sets the fetch size for query results. | `5000` | +| zoneId(ZoneId zoneId) | Sets the timezone-related `ZoneId`. | `ZoneId.systemDefault()` | +| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | Sets the timeout duration (in milliseconds) for acquiring a session from the pool. | `30000`(30 seconds) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | Sets the default buffer size for the Thrift client (in bytes). | `1024`(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | Sets the maximum frame size for the Thrift client (in bytes). | `64 * 1024 * 1024`(64MB) | +| enableCompression(boolean enableCompression) | Enables or disables compression for the connection. | `false` | +| enableRedirection(boolean enableRedirection) | Enables or disables redirection for cluster nodes. | `true` | +| connectionTimeoutInMs(int connectionTimeoutInMs) | Sets the connection timeout in milliseconds. | `10000` (10 seconds) | +| enableAutoFetch(boolean enableAutoFetch) | Enables or disables automatic fetching of available DataNodes. | `true` | +| maxRetryCount(int maxRetryCount) | Sets the maximum number of connection retry attempts. | `60` | +| retryIntervalInMs(long retryIntervalInMs) | Sets the interval between retry attempts (in milliseconds). | `500` (500 milliseconds) | +| useSSL(boolean useSSL) | Enables or disables SSL for secure connections. | `false` | +| trustStore(String keyStore) | Sets the path to the trust store for SSL connections. | `null` | +| trustStorePwd(String keyStorePwd) | Sets the password for the SSL trust store. | `null` | #### 4.2.3 Sample Code @@ -472,7 +472,7 @@ public class TableSessionPoolBuilder { * * @param password the password. * @return the current {@link TableSessionPoolBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //before V2.0.6 it is root */ public TableSessionPoolBuilder password(String password); @@ -679,7 +679,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021") //before V2.0.6 it is root .maxSize(1) .build(); @@ -780,7 +780,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021")//before V2.0.6 it is root .maxSize(1) .database("test1") .build(); diff --git a/src/UserGuide/Master/Table/API/Programming-Python-Native-API.md b/src/UserGuide/latest-Table/API/Programming-Python-Native-API_apache.md similarity index 99% rename from src/UserGuide/Master/Table/API/Programming-Python-Native-API.md rename to src/UserGuide/latest-Table/API/Programming-Python-Native-API_apache.md index 3ad3483ea..f2bc616c0 100644 --- a/src/UserGuide/Master/Table/API/Programming-Python-Native-API.md +++ b/src/UserGuide/latest-Table/API/Programming-Python-Native-API_apache.md @@ -414,7 +414,7 @@ def prepare_data(): session.execute_non_query_statement("CREATE DATABASE IF NOT EXISTS db1") session.execute_non_query_statement('USE "db1"') session.execute_non_query_statement( - "CREATE TABLE table0 (id1 string tag, attr1 string attribute, " + "CREATE TABLE table0 (id1 string id, attr1 string attribute, " + "m1 double " + "field)" ) diff --git a/src/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md b/src/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..7e2fb95e5 --- /dev/null +++ b/src/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,543 @@ + +# Python Native API + +IoTDB provides a Python native client driver and a session pool management mechanism. These tools allow developers to interact with IoTDB in a programmatic and efficient manner. Using the Python API, developers can encapsulate time-series data into objects (e.g., `Tablet`, `NumpyTablet`) and insert them into the database directly, without the need to manually construct SQL statements. For multi-threaded operations, the `TableSessionPool` is recommended to optimize resource utilization and enhance performance. + +## 1. Prerequisites + +To use the IoTDB Python API, install the required package using pip: + +```shell +pip3 install apache-iotdb>=2.0 +``` + +## 2. Read and Write Operations + +### 2.1 TableSession + +`TableSession` is a core class in IoTDB, enabling users to interact with the IoTDB database. It provides methods to execute SQL statements, insert data, and manage database sessions. + +#### Method Overview + +| **Method Name** | **Descripton** | **Parameter Type** | **Return Type** | +| --------------------------- | ----------------------------------------------------- | ------------------------------------ | ---------------- | +| insert | Inserts data into the database. | tablet: `Union[Tablet, NumpyTablet]` | None | +| execute_non_query_statement | Executes non-query SQL statements like DDL/DML. | sql: `str` | None | +| execute_query_statement | Executes a query SQL statement and retrieves results. | sql: `str` | `SessionDataSet` | +| close | Closes the session and releases resources. | None | None | + +#### Sample Code + +```Python +class TableSession(object): +def insert(self, tablet: Union[Tablet, NumpyTablet]): + """ + Insert data into the database. + + Parameters: + tablet (Tablet | NumpyTablet): The tablet containing the data to be inserted. + Accepts either a `Tablet` or `NumpyTablet`. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_non_query_statement(self, sql: str): + """ + Execute a non-query SQL statement. + + Parameters: + sql (str): The SQL statement to execute. Typically used for commands + such as INSERT, DELETE, or UPDATE. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_query_statement(self, sql: str, timeout_in_ms: int = 0) -> "SessionDataSet": + """ + Execute a query SQL statement and return the result set. + + Parameters: + sql (str): The SQL query to execute. + timeout_in_ms (int, optional): Timeout for the query in milliseconds. Defaults to 0, + which means no timeout. + + Returns: + SessionDataSet: The result set of the query. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def close(self): + """ + Close the session and release resources. + + Raises: + IoTDBConnectionException: If there is an issue closing the connection. + """ + pass +``` + +### 2.2 TableSessionConfig + +`TableSessionConfig` is a configuration class that sets parameters for creating a `TableSession` instance, defining essential settings for connecting to the IoTDB database. + +#### Parameter Configuration + +| **Parameter** | **Description** | **Type** | **Default Value** | +| ------------------ | ------------------------------------- | -------- |-----------------------------------------------| +| node_urls | List of database node URLs. | `list` | `["localhost:6667"]` | +| username | Username for the database connection. | `str` | `"root"` | +| password | Password for the database connection. | `str` | `"TimechoDB@2021"`,before V2.0.6 it is root | +| database | Target database to connect to. | `str` | `None` | +| fetch_size | Number of rows to fetch per query. | `int` | `5000` | +| time_zone | Default session time zone. | `str` | `Session.DEFAULT_ZONE_ID` | +| enable_compression | Enable data compression. | `bool` | `False` | + +#### Sample Code + +```Python +class TableSessionConfig(object): + """ + Configuration class for a TableSession. + + This class defines various parameters for connecting to and interacting + with the IoTDB tables. + """ + + def __init__( + self, + node_urls: list = None, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_compression: bool = False, + ): + """ + Initialize a TableSessionConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to ["localhost:6667"]. + username (str, optional): The username for the database connection. + Defaults to "root". + password (str, optional): The password for the database connection. + Defaults to "TimechoDB@2021",before V2.0.6 it is root + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session. + Defaults to Session.DEFAULT_ZONE_ID. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + """ +``` + +**Note:** After using a `TableSession`, make sure to call the `close` method to release resources. + +## 3. Session Pool + +### 3.1 TableSessionPool + +`TableSessionPool` is a session pool management class designed for creating and managing `TableSession` instances. It provides functionality to retrieve sessions from the pool and close the pool when it is no longer needed. + +#### Method Overview + +| **Method Name** | **Description** | **Return Type** | **Exceptions** | +| --------------- | ------------------------------------------------------ | --------------- | -------------- | +| get_session | Retrieves a new `TableSession` instance from the pool. | `TableSession` | None | +| close | Closes the session pool and releases all resources. | None | None | + +#### Sample Code + +```Python +def get_session(self) -> TableSession: + """ + Retrieve a new TableSession instance. + + Returns: + TableSession: A new session object configured with the session pool. + + Notes: + The session is initialized with the underlying session pool for managing + connections. Ensure proper usage of the session's lifecycle. + """ + +def close(self): + """ + Close the session pool and release all resources. + + This method closes the underlying session pool, ensuring that all + resources associated with it are properly released. + + Notes: + After calling this method, the session pool cannot be used to retrieve + new sessions, and any attempt to do so may raise an exception. + """ +``` + +### 3.2 TableSessionPoolConfig + +`TableSessionPoolConfig` is a configuration class used to define parameters for initializing and managing a `TableSessionPool` instance. It specifies the settings needed for efficient session pool management in IoTDB. + +#### Parameter Configuration + +| **Paramater** | **Description** | **Type** | **Default Value** | +| ------------------ | ------------------------------------------------------------ | -------- | -------------------------- | +| node_urls | List of IoTDB cluster node URLs. | `list` | None | +| max_pool_size | Maximum size of the session pool, i.e., the maximum number of sessions allowed in the pool. | `int` | `5` | +| username | Username for the connection. | `str` | `Session.DEFAULT_USER` | +| password | Password for the connection. | `str` | `Session.DEFAULT_PASSWORD` | +| database | Target database to connect to. | `str` | None | +| fetch_size | Fetch size for query results | `int` | `5000` | +| time_zone | Timezone-related `ZoneId` | `str` | `Session.DEFAULT_ZONE_ID` | +| enable_redirection | Whether to enable redirection. | `bool` | `False` | +| enable_compression | Whether to enable data compression. | `bool` | `False` | +| wait_timeout_in_ms | Sets the connection timeout in milliseconds. | `int` | `10000` | +| max_retry | Maximum number of connection retry attempts. | `int` | `3` | + +#### Sample Code + +```Python +class TableSessionPoolConfig(object): + """ + Configuration class for a TableSessionPool. + + This class defines the parameters required to initialize and manage + a session pool for interacting with the IoTDB database. + """ + def __init__( + self, + node_urls: list = None, + max_pool_size: int = 5, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_redirection: bool = False, + enable_compression: bool = False, + wait_timeout_in_ms: int = 10000, + max_retry: int = 3, + ): + """ + Initialize a TableSessionPoolConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to None. + max_pool_size (int, optional): The maximum number of sessions in the pool. + Defaults to 5. + username (str, optional): The username for the database connection. + Defaults to Session.DEFAULT_USER. + password (str, optional): The password for the database connection. + Defaults to Session.DEFAULT_PASSWORD. + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session pool. + Defaults to Session.DEFAULT_ZONE_ID. + enable_redirection (bool, optional): Whether to enable redirection. + Defaults to False. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + wait_timeout_in_ms (int, optional): The maximum time (in milliseconds) to wait for a session + to become available. Defaults to 10000. + max_retry (int, optional): The maximum number of retry attempts for operations. Defaults to 3. + + """ +``` + +**Notes:** + +- Ensure that `TableSession` instances retrieved from the `TableSessionPool` are properly closed after use. +- After closing the `TableSessionPool`, it will no longer be possible to retrieve new sessions. + +### 3.3 SSL Connection + +#### 3.3.1 Server Certificate Configuration + +In the `conf/iotdb-system.properties` configuration file, locate or add the following configuration items: + +``` +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 Configure Python Client Certificate + +- Set `use_ssl` to True to enable SSL. +- Specify the client certificate path using the `ca_certs` parameter. + +``` +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**Example Code: Using SSL to Connect to IoTDB** + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021",before V2.0.6 it is root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. Sample Code + +**Session** Example: You can find the full example code at [Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_example.py). + +**Session Pool** Example: You can find the full example code at [SessionPool Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_pool_example.py). + +Here is an excerpt of the sample code: + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +import threading + +import numpy as np + +from iotdb.table_session_pool import TableSessionPool, TableSessionPoolConfig +from iotdb.utils.IoTDBConstants import TSDataType +from iotdb.utils.NumpyTablet import NumpyTablet +from iotdb.utils.Tablet import ColumnType, Tablet + + +def prepare_data(): + print("create database") + # Get a session from the pool + session = session_pool.get_session() + session.execute_non_query_statement("CREATE DATABASE IF NOT EXISTS db1") + session.execute_non_query_statement('USE "db1"') + session.execute_non_query_statement( + "CREATE TABLE table0 (id1 string id, attr1 string attribute, " + + "m1 double " + + "field)" + ) + session.execute_non_query_statement( + "CREATE TABLE table1 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + + print("now the tables are:") + # show result + res = session.execute_query_statement("SHOW TABLES") + while res.has_next(): + print(res.next()) + + session.close() + + +def insert_data(num: int): + print("insert data for table" + str(num)) + # Get a session from the pool + session = session_pool.get_session() + column_names = [ + "id1", + "attr1", + "m1", + ] + data_types = [ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.DOUBLE, + ] + column_types = [ColumnType.TAG, ColumnType.ATTRIBUTE, ColumnType.FIELD] + timestamps = [] + values = [] + for row in range(15): + timestamps.append(row) + values.append(["id:" + str(row), "attr:" + str(row), row * 1.0]) + tablet = Tablet( + "table" + str(num), column_names, data_types, values, timestamps, column_types + ) + session.insert(tablet) + session.execute_non_query_statement("FLush") + + np_timestamps = np.arange(15, 30, dtype=np.dtype(">i8")) + np_values = [ + np.array(["id:{}".format(i) for i in range(15, 30)]), + np.array(["attr:{}".format(i) for i in range(15, 30)]), + np.linspace(15.0, 29.0, num=15, dtype=TSDataType.DOUBLE.np_dtype()), + ] + + np_tablet = NumpyTablet( + "table" + str(num), + column_names, + data_types, + np_values, + np_timestamps, + column_types=column_types, + ) + session.insert(np_tablet) + session.close() + + +def query_data(): + # Get a session from the pool + session = session_pool.get_session() + + print("get data from table0") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + print("get data from table1") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + session.close() + + +def delete_data(): + session = session_pool.get_session() + session.execute_non_query_statement("drop database db1") + print("data has been deleted. now the databases are:") + res = session.execute_query_statement("show databases") + while res.has_next(): + print(res.next()) + session.close() + + +# Create a session pool +username = "root" +password = "TimechoDB@2021",before V2.0.6 it is root +node_urls = ["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"] +fetch_size = 1024 +database = "db1" +max_pool_size = 5 +wait_timeout_in_ms = 3000 +config = TableSessionPoolConfig( + node_urls=node_urls, + username=username, + password=password, + database=database, + max_pool_size=max_pool_size, + fetch_size=fetch_size, + wait_timeout_in_ms=wait_timeout_in_ms, +) +session_pool = TableSessionPool(config) + +prepare_data() + +insert_thread1 = threading.Thread(target=insert_data, args=(0,)) +insert_thread2 = threading.Thread(target=insert_data, args=(1,)) + +insert_thread1.start() +insert_thread2.start() + +insert_thread1.join() +insert_thread2.join() + +query_data() +delete_data() +session_pool.close() +print("example is finished!") +``` + diff --git a/src/UserGuide/latest-Table/QuickStart/QuickStart_apache.md b/src/UserGuide/latest-Table/QuickStart/QuickStart_apache.md index 7f057a3a0..04d64e104 100644 --- a/src/UserGuide/latest-Table/QuickStart/QuickStart_apache.md +++ b/src/UserGuide/latest-Table/QuickStart/QuickStart_apache.md @@ -67,7 +67,7 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Data Synchronization: [Data Sync](../User-Manual/Data-Sync_apache.md) -6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_apache.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_apache.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. +6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_apache.md)、[Python Native API](../API/Programming-Python-Native-API_apache)、[JDBC](../API/Programming-JDBC_apache.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. ## 3. Want to learn more technical details? diff --git a/src/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md b/src/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md index 39fc660d0..a8c89a2dc 100644 --- a/src/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md +++ b/src/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md @@ -74,7 +74,7 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Data Synchronization: [Data Sync](../User-Manual/Data-Sync_timecho.md) -6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_timecho.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_timecho.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. +6. Application Programming Interfaces (APIs): IoTDB provides various application programming interfaces (APIs) to facilitate developers' interaction with IoTDB in applications. Currently supported interfaces include [Java Native API](../API/Programming-Java-Native-API_timecho.md)、[Python Native API](../API/Programming-Python-Native-API_timecho)、[JDBC](../API/Programming-JDBC_timecho.md), and more. For more programming interfaces, please refer to the [Application Programming Interfaces] section on the official website. ## 3. What other convenient tools are available? diff --git a/src/UserGuide/Master/Table/Tools-System/CLI.md b/src/UserGuide/latest-Table/Tools-System/CLI_apache.md similarity index 70% rename from src/UserGuide/Master/Table/Tools-System/CLI.md rename to src/UserGuide/latest-Table/Tools-System/CLI_apache.md index c8ae8cb21..f2128b7ef 100644 --- a/src/UserGuide/Master/Table/Tools-System/CLI.md +++ b/src/UserGuide/latest-Table/Tools-System/CLI_apache.md @@ -47,26 +47,27 @@ Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect tab # V2.0.4.x and later versions Shell> sbin\windows\start-cli.bat -sql_dialect table #or +# V2.0.4.x and later versions Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table ``` **Parameter Explanation** -| **Parameter** | **Type** | **Required** | **Description** | **Example** | -| -------------------------- | -------- | ------------ | ------------------------------------------------------------ | ------------------- | -| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | -| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | -| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | -| -pw `` | string | No | The password to connect to the IoTDB server. (Default: root) | -pw root | -| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | -| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | -| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | +| **Parameter** | **Type** | **Required** | **Description** | **Example** | +| -------------------------- | -------- | ------------ |-----------------------------------------------------------------------------------| ------------------- | +| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | +| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | +| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | +| -pw `` | string | No | The password to connect to the IoTDB server. (Default: root) | -pw root | +| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | +| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | +| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | | -disableISO8601 | Flag | No | If set, timestamps will be displayed as numeric values instead of ISO8601 format. | -disableISO8601 | -| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | -| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | -| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | -| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | -| -help | Flag | No | Displays help information for the CLI tool. | -help | +| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | +| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | +| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | +| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | +| -help | Flag | No | Displays help information for the CLI tool. | -help | The figure below indicates a successful startup: diff --git a/src/UserGuide/latest-Table/Tools-System/CLI_timecho.md b/src/UserGuide/latest-Table/Tools-System/CLI_timecho.md new file mode 100644 index 000000000..c2d2fde6e --- /dev/null +++ b/src/UserGuide/latest-Table/Tools-System/CLI_timecho.md @@ -0,0 +1,109 @@ + +# CLI + +The IoTDB Command Line Interface (CLI) tool allows users to interact with the IoTDB server. Before using the CLI tool to connect to IoTDB, ensure that the IoTDB service is running correctly. This document explains how to launch the CLI and its related parameters. + +In this manual, `$IOTDB_HOME` represents the installation directory of IoTDB. + +## 1. CLI Launch + +The CLI client script is located in the `$IOTDB_HOME/sbin` directory. The common commands to start the CLI tool are as follows: + +#### **Linux** **MacOS** + +```Bash +Shell> bash sbin/start-cli.sh -sql_dialect table +#or +# Before version V2.0.6.x +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x and later versions +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +#### **Windows** + +```Bash +# Before version V2.0.4.x +Shell> sbin\start-cli.bat -sql_dialect table +#or +Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table + +# V2.0.4.x and later versions +Shell> sbin\windows\start-cli.bat -sql_dialect table +#or +# V2.0.4.x and later versions, before version V2.0.6.x +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x and later versions +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +**Parameter Explanation** + +| **Parameter** | **Type** | **Required** | **Description** | **Example** | +| -------------------------- | -------- | ------------ |---------------------------------------------------------------------------------------------------| ------------------- | +| -h `` | string | No | The IP address of the IoTDB server. (Default: 127.0.0.1) | -h 127.0.0.1 | +| -p `` | int | No | The RPC port of the IoTDB server. (Default: 6667) | -p 6667 | +| -u `` | string | No | The username to connect to the IoTDB server. (Default: root) | -u root | +| -pw `` | string | No | The password to connect to the IoTDB server. (Default: `TimechoDB@2021`,before V2.0.6 it is root) | -pw root | +| -sql_dialect `` | string | No | The data model type: tree or table. (Default: tree) | -sql_dialect table | +| -e `` | string | No | Batch operations in non-interactive mode. | -e "show databases" | +| -c | Flag | No | Required if rpc_thrift_compression_enable=true on the server. | -c | +| -disableISO8601 | Flag | No | If set, timestamps will be displayed as numeric values instead of ISO8601 format. | -disableISO8601 | +| -usessl `` | Boolean | No | Enable SSL connection | -usessl true | +| -ts `` | string | No | SSL certificate store path | -ts /path/to/truststore | +| -tpw `` | string | No | SSL certificate store password | -tpw myTrustPassword | +| -timeout `` | int | No | Query timeout (seconds). If not set, the server's configuration will be used. | -timeout 30 | +| -help | Flag | No | Displays help information for the CLI tool. | -help | + +The figure below indicates a successful startup: + +![](/img/Cli-01.png) + + +## 2. Example Commands + +### 2.1 **Create a Database** + +```Java +create database test +``` + +![](/img/Cli-02.png) + + +### 2.2 **Show Databases** +```Java +show databases +``` + +![](/img/Cli-03.png) + + +## 3. CLI Exit + +To exit the CLI and terminate the session, type`quit`or`exit`. + +### 3.1 Additional Notes and Shortcuts + +1. **Navigate Command History:** Use the up and down arrow keys. +2. **Auto-Complete Commands:** Use the right arrow key. +3. **Interrupt Command Execution:** Press `CTRL+C`. diff --git a/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md b/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md new file mode 100644 index 000000000..d66c1a284 --- /dev/null +++ b/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md @@ -0,0 +1,166 @@ +# Data Export + +## 1. Function Overview +The data export tool `export-data.sh/bat` is located in the `tools` directory and can export query results from specified SQL statements into CSV, SQL, or TsFile (open-source time-series file format) formats. Its specific functionalities are as follows: + +
+ + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVexport-data.sh/batPlain text format for storing structured data. Must follow the CSV format specified below.
SQLFile containing custom SQL statements.
TsFileOpen-source time-series file format.
+ + +## 2. Detailed Features +### 2.1 Common Parameters +| Short | Full Parameter | Description | Required | Default | +| ---------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------- |----------------------------------------------| +| `-ft` | `--file_type` | Export file type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | +| `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | +| `-u` | `--username` | Username for authentication. | No | `root` | +| `-pw` | `--password` | Password for authentication. | No | `root` | +| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | +| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| - | +| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | +| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | +|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | +| `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | +| `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | +| `-q` | `--query` | SQL query command to execute. | No | - | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (ms). | No | `-1` (Range: -1~Long max=9223372036854775807) | +| `-help` | `--help` | Display help information. | No | - | + +### 2.2 CSV Format +#### 2.2.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table + [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |------------------------------------------| +| `-dt` | `--datatype` | Whether to include data types in the CSV file header (`true` or `false`). | No | `false` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -db database1 -q "select * from table1" + +# Error Example +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -q "select * from table1" +Parse error: Missing required option: db +``` +## 2.3 SQL Format +#### 2.3.1 Command +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------- | +| `-aligned` | `--use_aligned` | Whether to export as aligned SQL format (`true` or `false`). | No | `true` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.3.3 Examples +```Shell +# Valid Example +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -db database1 -start_time 1 + +# Error Example +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -start_time 1 +Parse error: Missing required option: db +``` + +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 TsFile-Specific Parameters + +* None + +#### 2.4.3 Examples + +```Shell +# Valid Example +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -db database1 -start_time 0 + +# Error Example +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -start_time 0 +Parse error: Missing required option: db +``` diff --git a/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md b/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md similarity index 97% rename from src/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md rename to src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md index 921cc3783..f23293445 100644 --- a/src/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md +++ b/src/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md @@ -34,12 +34,12 @@ The data export tool `export-data.sh/bat` is located in the `tools` directory an | `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | | `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | | `-u` | `--username` | Username for authentication. | No | `root` | -| `-pw` | `--password` | Password for authentication. | No | `root` | -| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | -| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| -| -| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | -| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | -|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | +| `-pw` | `--password` | Password for authentication. | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Select server model : tree or table | No | tree | +| `-db ` | `--database` | The target database to be exported only takes effect when `-sql_dialect` is of the table type.| Yes when `-sql_dialect = table`| - | +| `-table`|`--table` | The target table to be exported only takes effect when `-sql_dialect` is of the table type. If the `-q` parameter is specified, this parameter will not take effect. If the export type is tsfile/sql, this parameter is mandatory.| ​ No | - | +| `-start_time` | `--start_time` |The start time of the data to be exported only takes effect when `-sql_dialect` is of the table type. If `-q` is specified, this parameter will not take effect. The supported time formats are the same as those for the `-tf` parameter.|No | - | +|`-end_time` |`--end_time` | The end time of the data to be exported only takes effect when `-sql_dialect` is set to the table type. If `-q` is specified, this parameter will not take effect.| No | - | | `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | | `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | | `-q` | `--query` | SQL query command to execute. | No | - | diff --git a/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md b/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md new file mode 100644 index 000000000..6d04bef39 --- /dev/null +++ b/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md @@ -0,0 +1,321 @@ +# Data Import + +## 1. Functional Overview + +IoTDB supports three methods for data import: +- Data Import Tool: Use the `import-data.sh/bat` script in the `tools` directory to manually import CSV, SQL, or TsFile (open-source time-series file format) data into IoTDB. +- `TsFile` Auto-Loading Feature +- Load `TsFile` SQL + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVimport-data.sh/batCan be used for single or batch import of CSV files into IoTDB
SQLCan be used for single or batch import of SQL files into IoTDB
TsFileCan be used for single or batch import of TsFile files into IoTDB
TsFile Auto-Loading FeatureCan automatically monitor a specified directory for newly generated TsFiles and load them into IoTDB
Load SQLCan be used for single or batch import of TsFile files into IoTDB
+ +## 2. Data Import Tool +### 2.1 Common Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |---------------------------------------------| +| `-ft` | `--file_type` | File type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | +| `-p` | `--port` | IoTDB server port. | No | `6667` | +| `-u` | `--username` | Username. | No | `root` | +| `-pw` | `--password` | Password. | No | `root` | +| +|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | +|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | +|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | +| +| `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | +| `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | +| `-tz` | `--timezone` | Timezone (e.g., `+08:00`, `-01:00`). | No | System default | +| `-help` | `--help` | Display help (general or format-specific: `-help csv`). | No | - | + +### 2.2 CSV Format + +#### 2.2.1 Command +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------------- |----------------------------------------------------------| ---------- |-----------------| +| `-fd` | `--fail_dir` | Directory to save failed files. | No | YOUR_CSV_FILE_PATH | +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-aligned` | `--use_aligned` | Import as aligned time series. | No | `false` | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-ti` | `--type_infer` | Type mapping (e.g., `BOOLEAN=text,INT=long`). | No | - | +| `-tp` | `--timestamp_precision` | Timestamp precision: `ms`, `us`, `ns`. | No | `ms` | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_0.csv -db database1 -table table1 + +# Error Example +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -table table1 +Parse error: Missing required option: db + +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -db database1 -table table5 +There are no tables or the target table table5 does not exist +``` + +#### 2.2.4 Import Notes + +1. CSV Import Specifications + +- Special Character Escaping Rules: If a text-type field contains special characters (e.g., commas `,`), they must be escaped using a backslash (`\`). +- Supported Time Formats: `yyyy-MM-dd'T'HH:mm:ss`, `yyyy-MM-dd HH:mm:ss`, or `yyyy-MM-dd'T'HH:mm:ss.SSSZ`. +- Timestamp Column Requirement: The timestamp column must be the first column in the data file. + +2. CSV File Example + +```sql +time,region,device,model,temperature,humidity +1970-01-01T08:00:00.001+08:00,"SH","101","F",90.0,35.2 +1970-01-01T08:00:00.002+08:00,"SH","101","F",90.0,34.8 +``` + + +### 2.3 SQL Format + +#### 2.3.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| -------------- | ------------------------------- | -------------------------------------------------------------------- | ---------- | ------------------ | +| `-fd` | `--fail_dir` | Directory to save failed files. | No |YOUR_CSV_FILE_PATH| +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | + +#### 2.3.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump0_0.sql -db database1 + +# Error Example +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump1_1.sql -db database1 +Source file or directory ./sql/dump1_1.sql does not exist + +# When the ​target table exists but metadata is incompatible or ​data is malformed, the system will generate a .failed file and log error details. +# Log Example +Fail to insert measurements '[column.name]' caused by [data type is not consistent, input '[column.value]', registered '[column.DataType]'] +``` +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` +#### 2.4.2 TsFile-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ----------- | ----------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------- | --------------------------- | +| `-os` | `--on_success` | Action for successful files:
`none`: Do not delete the file.
`mv`: Move the successful file to the target directory.
`cp`:Create a hard link (copy) of the successful file to the target directory.
`delete`:Delete the file. | ​**Yes** | - | +| `-sd` | `--success_dir` | Target directory for `mv`/`cp` actions on success. Required if `-os` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/success` | +| `-of` | `--on_fail` | Action for failed files:
`none`:Skip the file.
`mv`:Move the failed file to the target directory.
`cp`:Create a hard link (copy) of the failed file to the target directory.
`delete`:Delete the file.. | ​**Yes** | - | +| `-fd` | `--fail_dir` | Target directory for `mv`/`cp` actions on failure. Required if `-of` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/fail` | +| `-tp` | `--timestamp_precision` | TsFile timestamp precision: `ms`, `us`, `ns`.
For non-remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The system will manually verify if the timestamp precision matches the server. If it does not match, an error will be returned.
​For remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The Pipe system will automatically verify if the timestamp precision matches. If it does not match, a Pipe error will be returned. | No | `ms` | + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 -os none -of none + +# Error Example +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 +Parse error: Missing required options: os, of +``` + +## 3. TsFile Auto-Loading + +This feature enables IoTDB to automatically monitor a specified directory for new TsFiles and load them into the database without manual intervention. + +![](/img/Data-import2.png) + +### 3.1 Configuration + +Add the following parameters to `iotdb-system.properties` (template: `iotdb-system.properties.template`): + +| Parameter | Description | Value Range | Required | Default | Hot-Load? | +| ---------------------------------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------| ---------- | ----------------------------- | ----------------------- | +| `load_active_listening_enable` | Enable auto-loading. | `true`/`false` | Optional | `true` | Yes | +| `load_active_listening_dirs` | Directories to monitor (subdirectories included). Multiple paths separated by commas.
Note: In the table model, the directory name where the file is located will be used as the database. | String | Optional | `ext/load/pending` | Yes | +| `load_active_listening_fail_dir` | Directory to store failed TsFiles. Only can set one. | String | Optional | `ext/load/failed` | Yes | +| `load_active_listening_max_thread_num` | Maximum Threads for TsFile Loading Tasks:The default value for this parameter, when commented out, is max(1, CPU cores / 2). If the value set by the user falls outside the range [1, CPU cores / 2], it will be reset to the default value of max(1, CPU cores / 2). | `1` to `Long.MAX_VALUE` | Optional | `max(1, CPU_CORES / 2)` | No (restart required) | +| `load_active_listening_check_interval_seconds` | Active Listening Polling Interval (in seconds):The active listening feature for TsFiles is implemented through polling the target directory. This configuration specifies the time interval between two consecutive checks of the `load_active_listening_dirs`. After each check, the next check will be performed after `load_active_listening_check_interval_seconds` seconds. If the polling interval set by the user is less than 1, it will be reset to the default value of 5 seconds. | `1` to `Long.MAX_VALUE` | Optional | `5` | No (restart required) | + +### 3.2 Examples + +```bash +load_active_listening_dir/ +├─sensors/ +│ ├─temperature/ +│ │ └─temperature-table.TSFILE + +``` + +- Table model TsFile + - `temperature-table.TSFILE`: will be imported into the `temperature` database (because it is located in the `sensors/temperature/` directory) + + +### 3.3 Notes + +1. ​​**Mods Files**​: If TsFiles have associated `.mods` files, move `.mods` files to the monitored directory ​**before** their corresponding TsFiles. Ensure `.mods` and TsFiles are in the same directory. +2. ​​**Restricted Directories**​: Do NOT set Pipe receiver directories, data directories, or other system paths as monitored directories. +3. ​​**Directory Conflicts**​: Ensure `load_active_listening_fail_dir` does not overlap with `load_active_listening_dirs` or its subdirectories. +4. ​​**Permissions**​: The monitored directory must have write permissions. Files are deleted after successful loading; insufficient permissions may cause duplicate loading. + + +## 4. Load SQL + +IoTDB supports importing one or multiple TsFile files containing time series into another running IoTDB instance directly via SQL execution through the CLI. + +### 4.1 Command + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` : The path to a TsFile or a folder containing multiple TsFiles. +* ``: Optional parameters, as described below. + +| Key | Key Description | Value Type | Value Range | Value is Required | Default Value | +|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|--------------------------------|-------------------|----------------------------| +| `database-level` | When the database corresponding to the TsFile does not exist, the database hierarchy level can be specified via the ` database-level` parameter. The default is the level set in `iotdb-common.properties`. For example, setting level=1 means the prefix path of level 1 in all time series in the TsFile will be used as the database. | Integer | `[1: Integer.MAX_VALUE]` | No | 1 | +| `on-success` | Action for successfully loaded TsFiles: `delete` (delete the TsFile after successful import) or `none` (retain the TsFile in the source folder). | String | `delete / none` | No | delete | +| `model` | Specifies whether the TsFile uses the `table` model or `tree` model. | String | `tree / table` | No | Aligns with `-sql_dialect` | +| `database-name` | Table model only: Target database for import. Automatically created if it does not exist. The database-name must not include the `root.` prefix (an error will occur if included). | String | `-` | No | null | +| `convert-on-type-mismatch` | Whether to perform type conversion during loading if data types in the TsFile mismatch the target schema. | Boolean | `true / false` | No | true | +| `verify` | Whether to validate the schema before loading the TsFile. | Boolean | `true / false` | No | true | +| `tablet-conversion-threshold` | Size threshold (in bytes) for converting TsFiles into tablet format during loading. Default: `-1` (no conversion for any TsFile). | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | No | -1 | +| `async` | Whether to enable asynchronous loading. If enabled, TsFiles are moved to an active-load directory and loaded into the `database-name` asynchronously. | Boolean | `true / false` | No | false | + +### 4.2 Example + +```SQL +-- Create target database: database2 +IoTDB> create database database2 +Msg: The statement is executed successfully. + +IoTDB> use database2 +Msg: The statement is executed successfully. + +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ ++---------+-------+------+-------+ +Empty set. + +-- Import tsfile by excuting load sql +IoTDB:database2> load '/home/dump0.tsfile' with ( 'on-success'='none', 'database-name'='database2') +Msg: The statement is executed successfully. + +-- Verify whether the import was successful +IoTDB:database2> select * from table2 ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +| time|region|plant_id|device_id|temperature|humidity|status| arrival_time| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +|2024-11-30T00:00:00.000+08:00| 上海| 3002| 101| 90.0| 35.2| true| null| +|2024-11-29T00:00:00.000+08:00| 上海| 3001| 101| 85.0| 35.1| null|2024-11-29T10:00:13.000+08:00| +|2024-11-27T00:00:00.000+08:00| 北京| 1001| 101| 85.0| 35.1| true|2024-11-27T16:37:01.000+08:00| +|2024-11-29T11:00:00.000+08:00| 上海| 3002| 100| null| 45.1| true| null| +|2024-11-28T08:00:00.000+08:00| 上海| 3001| 100| 85.0| 35.2| false|2024-11-28T08:00:09.000+08:00| +|2024-11-26T13:37:00.000+08:00| 北京| 1001| 100| 90.0| 35.1| true|2024-11-26T13:37:34.000+08:00| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +``` diff --git a/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md b/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md similarity index 98% rename from src/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md rename to src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md index c7d63735a..abbb26abf 100644 --- a/src/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md +++ b/src/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md @@ -46,11 +46,11 @@ IoTDB supports three methods for data import: | `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | | `-p` | `--port` | IoTDB server port. | No | `6667` | | `-u` | `--username` | Username. | No | `root` | -| `-pw` | `--password` | Password. | No | `root` | +| `-pw` | `--password` | Password. | No | `TimechoDB@2021`(Before V2.0.6 it is root) | | -|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | -|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | -|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | +|`-sql_dialect`|`--sql_dialect`|Select server model : tree or table | No | `tree` | +|` -db `|`--database` |​Target database , applies only to `-sql_dialect=table` |Yes when `-sql_dialect = table` | - | +|`-table` |`--table `|Target table , required for CSV imports in table model | No | - | | | `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | | `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | diff --git a/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md b/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md new file mode 100644 index 000000000..ff7583917 --- /dev/null +++ b/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md @@ -0,0 +1,108 @@ + + +# Schema Export + +## 1. Overview + +The schema export tool `export-schema.sh/bat` is located in the `tools` directory. It can export schema from a specified database in IoTDB to a script file. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |---------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 Examples + +Export schema from `database1` to `/home`: + +```Bash +./export-schema.sh -sql_dialect table -t /home/ -db database1 +``` + +Output `dump_database1.sql`: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` diff --git a/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md b/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md similarity index 93% rename from src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md rename to src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md index f278576e4..885433f89 100644 --- a/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md +++ b/src/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md @@ -29,21 +29,21 @@ The schema export tool `export-schema.sh/bat` is located in the `tools` director ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------- | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | -| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | -| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | -| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | -| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | -| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | | `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md b/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md similarity index 89% rename from src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md rename to src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md index cca314db4..6c2057422 100644 --- a/src/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md +++ b/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md @@ -29,19 +29,19 @@ The schema import tool `import-schema.sh/bat` is located in `tools` directory. ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- | ------------------------------------------------ | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database for import | Yes | - | -| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | -| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | -| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | | `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md b/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md new file mode 100644 index 000000000..0dd8688ff --- /dev/null +++ b/src/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md @@ -0,0 +1,163 @@ + + +# Schema Import + +## 1. Overview + +The schema import tool `import-schema.sh/bat` is located in `tools` directory. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | `TimechoDB@2021`(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# Before version V2.0.4.x +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x and later versions +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 Examples + +Import `dump_database1.sql` from `/home` into `database2`, + +```sql +-- File content (dump_database1.sql): +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` + +Executing the command: + +```Bash +./import-schema.sh -sql_dialect table -s /home/dump_database1.sql -db database2 + +# If database2 doesn't exist +The target database database2 does not exist + +# If database2 exists +Import completely! +``` + +Verification: + +```Bash +# Before import +IoTDB:database2> show tables ++---------+-------+ +|TableName|TTL(ms)| ++---------+-------+ ++---------+-------+ +Empty set. + +# After import +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ +| table2| INF| USING| null| +| table1| INF| USING| null| ++---------+-------+------+-------+ + +IoTDB:database2> desc table1 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ + +IoTDB:database2> desc table2 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ +``` diff --git a/src/UserGuide/latest-Table/User-Manual/Authority-Management.md b/src/UserGuide/latest-Table/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/UserGuide/latest-Table/User-Manual/Authority-Management.md rename to src/UserGuide/latest-Table/User-Manual/Authority-Management_apache.md diff --git a/src/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md b/src/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..9672bc363 --- /dev/null +++ b/src/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,493 @@ + + +# Authority Management + +IoTDB provides permission management functionality to implement fine-grained access control for data and cluster systems, ensuring data and system security. This document introduces the basic concepts, user definitions, permission management, authentication logic, and functional use cases of the permission module in IoTDB's table model. + +## 1. Basic Concepts + +### 1.1 User + +A **user** is a legitimate database user. Each user is associated with a unique username and authenticated via a password. Before accessing the database, a user must provide valid credentials (a username and password that exist in the database). + +### 1.2 Permission + +A database supports multiple operations, but not all users can perform every operation. If a user is authorized to execute a specific operation, they are said to have the **permission** for that operation. + +### 1.3 Role + +A **role** is a collection of permissions, identified by a unique role name. Roles typically correspond to real-world identities (e.g., "traffic dispatcher"), where a single identity may encompass multiple users. Users sharing the same real-world identity often require the same set of permissions, and roles abstract this grouping for unified management. + +### 1.4 Default User and Role + +Upon initialization, IoTDB includes a default user: + +* ​**Username**​: `root` +* ​**Default password**​: `TimechoDB@2021` //before V2.0.6 it is root + +The `root` user is the ​**administrator**​, inherently possessing all permissions. This user cannot be granted or revoked permissions and cannot be deleted. The database maintains only one administrator user. Newly created users or roles start with **no permissions** by default. + +## 2. Permission List + +In IoTDB's table model, there are two main types of permissions: Global Permissions and Data Permissions . + +### 2.1 Global Permissions + +Global permissions include user management and role management. + +The following table describes the types of global permissions: + +| Permission Name | Description | +| ----------------- |----------------------------------------------------------------------------------------------------------------------------------| +| MANAGE\_USER | - Create users
- Delete users
- Modify user passwords
- View user permission details
- List all users | +| MANAGE\_ROLE | - Create roles
- Delete roles
- View role permission details
- Grant/revoke roles to/from users
- List all roles | + +### 2.2 Data Permissions + +Data permissions consist of permission types and permission scopes. + +* Permission Types: + * CREATE: Permission to create resources + * DROP: Permission to delete resources + * ALTER: Permission to modify definitions + * SELECT: Permission to query data + * INSERT: Permission to insert/update data + * DELETE: Permission to delete data +* Permission Scopes: + * ANY: System-wide (affects all databases and tables) + * DATABASE: Database-wide (affects the specified database and its tables) + * TABLE: Table-specific (affects only the specified table) +* Scope Enforcement Logic: + +When performing table-level operations, the system matches user permissions with data permission scopes hierarchically. Example: If a user attempts to write data to `DATABASE1.TABLE1`, the system checks for write permissions in this order: 1. `ANY` scope → 2. `DATABASE1` scope → 3. `DATABASE1.TABLE1` scope. The check stops at the first successful match or fails if no permissions are found. + +* Permission Type-Scope-Effect Matrix + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Permission TypeScope(Hierarchy)Effect
CREATEANYCreate any table/database
DATABASECreate tables in the specified database; create a database with the specified name
TABLECreate a table with the specified name
DROPANYDelete any table/database
DATABASEDelete the specified database or its tables
TABLEDelete the specified table
ALTERANYModify definitions of any table/database
DATABASEModify definitions of the specified database or its tables
TABLEModify the definition of the specified table
SELECTANYQuery data from any table in any database
DATABASEQuery data from any table in the specified database
TABLEQuery data from the specified table
INSERTANYInsert/update data in any table
DATABASEInsert/update data in any table within the specified database
TABLEInsert/update data in the specified table
DELETEANYDelete data from any table
DATABASEDelete data from tables within the specified database
TABLEDelete data from the specified table
+ +## 3. User and Role Management + +1. Create User (Requires `MANAGE_USER` Permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +Constraints: + +* Username: 4-32 characters (letters, numbers, special chars: `!@#$%^&*()_+-=`). Cannot duplicate the admin (`root`) username. +* Password: 4-32 characters (letters, numbers, special chars). Stored as SHA-256 hash by default. + +2. Modify Password + +Users can modify their own passwords. Modifying others' passwords requires `MANAGE_USER`. + +```SQL +ALTER USER SET PASSWORD +eg: ALTER USER tempuser SET PASSWORD 'newpwd' +``` + +3. Delete User (Requires `MANAGE_USER`) + +```SQL +DROP USER +eg: DROP USER user1 +``` + +4. Create Role (Requires `MANAGE_ROLE`) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +Constraints: + +* Role Name: 4-32 characters (letters, numbers, special chars). Cannot duplicate the admin role name. + +5. Delete Role (Requires `MANAGE_ROLE`) + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +6. Assign Role to User (Requires `MANAGE_ROLE`) + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +7. Revoke Role from User (Requires `MANAGE_ROLE`) + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +8. List All Users (Requires `MANAGE_USER`) + +```SQL +LIST USER +``` + +9. List All Roles (Requires `MANAGE_ROLE`) + +```SQL +LIST ROLE +``` + +10. List Users in a Role (Requires `MANAGE_USER`) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +11. List Roles of a User + +* Users can list their own permissions. +* Listing others' permissions requires `MANAGE_USER`. + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +12. List User Permissions + +* Users can list their own permissions. +* Listing others' permissions requires `MANAGE_USER`. + +```SQL +LIST PRIVILEGES OF USER +eg: LIST PRIVILEGES OF USER tempuser +``` + +13. List Role Permissions + +* Users can list permissions of roles they have. +* Listing other roles' permissions requires `MANAGE_ROLE`. + +```SQL +LIST PRIVILEGES OF ROLE +eg: LIST PRIVILEGES OF ROLE actor +``` + +## 4. Permission Management + +IoTDB supports granting and revoking permissions through the following three methods: + +* Direct assignment/revocation by a super administrator +* Assignment/revocation by users with the `GRANT OPTION` privilege +* Assignment/revocation via roles (managed by super administrators or users with `MANAGE_ROLE` permissions) + +In the IoTDB Table Model, the following principles apply when granting or revoking permissions: + +* **Global permissions** can be granted/revoked without specifying a scope. +* **Data permissions** require specifying both the permission type and permission scope. When revoking, only the explicitly defined scope is affected, regardless of hierarchical inclusion relationships. +* Preemptive permission planning is allowed—permissions can be granted for databases or tables that do not yet exist. +* Repeated granting/revoking of permissions is permitted. +* `WITH GRANT OPTION`: Allows users to manage permissions within the granted scope. Users with this option can grant or revoke permissions for other users in the same scope. + +### 4.1 Granting Permissions + +1. Grant a user the permission to manage users + +```SQL +GRANT MANAGE_USER TO USER +eg: GRANT MANAGE_USER TO USER TEST_USER +``` + +2. Grant a user the permission to create databases and tables within the database, and allow them to manage permissions in that scope + +```SQL +GRANT CREATE ON DATABASE TO USER WITH GRANT OPTION +eg: GRANT CREATE ON DATABASE TESTDB TO USER TEST_USER WITH GRANT OPTION +``` + +3. Grant a role the permission to query a database + +```SQL +GRANT SELECT ON DATABASE TO ROLE +eg: GRANT SELECT ON DATABASE TESTDB TO ROLE TEST_ROLE +``` + +4. Grant a user the permission to query a table + +```SQL +GRANT SELECT ON . TO USER +eg: GRANT SELECT ON TESTDB.TESTTABLE TO USER TEST_USER +``` + +5. Grant a role the permission to query all databases and tables + +```SQL +GRANT SELECT ON ANY TO ROLE +eg: GRANT SELECT ON ANY TO ROLE TEST_ROLE +``` + +6. ALL Syntax Sugar: ALL represents all permissions within a given scope, allowing flexible permission granting. + +```sql +GRANT ALL TO USER TESTUSER +-- Grants all possible permissions to the user, including global permissions and all data permissions under ANY scope. + +GRANT ALL ON ANY TO USER TESTUSER +-- Grants all data permissions under the ANY scope. After execution, the user will have all data permissions across all databases. + +GRANT ALL ON DATABASE TESTDB TO USER TESTUSER +-- Grants all data permissions within the specified database. After execution, the user will have all data permissions on that database. + +GRANT ALL ON TABLE TESTTABLE TO USER TESTUSER +-- Grants all data permissions on the specified table. After execution, the user will have all data permissions on that table. +``` + +### 4.2 Revoking Permissions + +1. Revoke a user's permission to manage users + +```SQL +REVOKE MANAGE_USER FROM USER +eg: REVOKE MANAGE_USER FROM USER TEST_USER +``` + +2. Revoke a user's permission to create databases and tables within the database + +```SQL +REVOKE CREATE ON DATABASE FROM USER +eg: REVOKE CREATE ON DATABASE TEST_DB FROM USER TEST_USER +``` + +3. Revoke a user's permission to query a table + +```SQL +REVOKE SELECT ON . FROM USER +eg: REVOKE SELECT ON TESTDB.TESTTABLE FROM USER TEST_USER +``` + +4. Revoke a user's permission to query all databases and tables + +```SQL +REVOKE SELECT ON ANY FROM USER +eg: REVOKE SELECT ON ANY FROM USER TEST_USER +``` + +5. ALL Syntax Sugar: ALL represents all permissions within a given scope, allowing flexible permission revocation. + +```sql +REVOKE ALL FROM USER TESTUSER +-- Revokes all global permissions and all data permissions under ANY scope. + +REVOKE ALL ON ANY FROM USER TESTUSER +-- Revokes all data permissions under the ANY scope, without affecting DB or TABLE-level permissions. + +REVOKE ALL ON DATABASE TESTDB FROM USER TESTUSER +-- Revokes all data permissions on the specified database, without affecting TABLE-level permissions. + +REVOKE ALL ON TABLE TESTDB FROM USER TESTUSER +-- Revokes all data permissions on the specified table. +``` + +### 4.3 Viewing User Permissions + +Each user has an access control list that identifies all the permissions they have been granted. You can use the `LIST PRIVILEGES OF USER ` statement to view the permission information of a specific user or role. The output format is as follows: + +| ROLE | SCOPE | PRIVIVLEGE | WITH GRANT OPTION | +|--------------|---------| -------------- |-------------------| +| | DB1.TB1 | SELECT | FALSE | +| | | MANAGE\_ROLE | TRUE | +| ROLE1 | DB2.TB2 | UPDATE | TRUE | +| ROLE1 | DB3.\* | DELETE | FALSE | +| ROLE1 | \*.\* | UPDATE | TRUE | + +* ​**ROLE column**​: If empty, it indicates the user's own permissions. If not empty, it means the permission is derived from a granted role. +* ​**SCOPE column**​: Represents the permission scope of the user/role. Table-level permissions are denoted as `DB.TABLE`, database-level permissions as `DB.*`, and ANY-level permissions as `*.*`. +* ​**PRIVILEGE column**​: Lists the specific permission types. +* ​**WITH GRANT OPTION column**​: If `TRUE`, it means the user can grant their own permissions to others. +* A user or role can have permissions in both the tree model and the table model, but the system will only display the permissions relevant to the currently connected model. Permissions under the other model will not be shown. + +## 5. Example + +Using the content from the [Sample Data](../Reference/Sample-Data.md) as an example, the data in the two tables may belong to the **bj** and **sh** data centers, respectively. To prevent each center from accessing the other's database data, we need to implement permission isolation at the data center level. + +### 5.1 Creating Users + +Use `CREATE USER ` to create users. For example, the **root** user with all permissions can create two user roles for the **ln** and **sgcc** groups, named **bj\_write\_user** and ​**sh\_write\_user**​, both with the password ​**write\_pwd**​. The SQL statements are: + +```SQL +CREATE USER bj_write_user 'write_pwd' +CREATE USER sh_write_user 'write_pwd' +``` + +To display the users, use the following SQL statement: + +```Plain +LIST USER +``` + +The result will show the two newly created users, as follows: + +```sql ++-------------+ +| User| ++-------------+ +|bj_write_user| +| root| +|sh_write_user| ++-------------+ +``` + +### 5.2 Granting User Permissions + +Although the two users have been created, they do not yet have any permissions and thus cannot perform database operations. For example, if the **bj\_write\_user** attempts to write data to ​**table1**​, the SQL statement would be: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +``` + +The system will deny the operation and display an error: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: database is not specified +IoTDB> use database1 +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: DATABASE database1 +``` + +The **root** user can grant **bj\_write\_user** write permissions for **table1** using the `GRANT ON TO USER ` statement, for example: + +```sql +GRANT INSERT ON database1.table1 TO USER bj_write_user +``` + +After granting permissions, **bj\_write\_user** can successfully write data: + +```SQL +IoTDB> use database1 +Msg: The statement is executed successfully. +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: The statement is executed successfully. +``` + +### 5.3 Revoking User Permissions + +After granting permissions, the **root** user can revoke them using the `REVOKE ON FROM USER ` statement. For example: + +```sql +REVOKE INSERT ON database1.table1 FROM USER bj_write_user +REVOKE INSERT ON database1.table2 FROM USER sh_write_user +``` + +Once permissions are revoked, **bj\_write\_user** will no longer have write access to ​**table1**​: + +```sql +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: No permissions for this operation, please add privilege INSERT ON database1.table1 +``` diff --git a/src/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md b/src/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md index 00e64f82d..97a6dff22 100644 --- a/src/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md +++ b/src/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md @@ -597,36 +597,36 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-air-gap-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- | :------------ | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| air-gap.handshake-timeout-ms | The timeout duration for the handshake requests when the sender and receiver attempt to establish a connection for the first time, in milliseconds. | Integer | No | 5000 | +| **Parameter** | **Description** | Value Range | Required | Default Value | +| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| air-gap.handshake-timeout-ms | The timeout duration for the handshake requests when the sender and receiver attempt to establish a connection for the first time, in milliseconds. | Integer | No | 5000 | #### iotdb-thrift-ssl-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------| :------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------|:---------------------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | #### write-back-sink @@ -645,5 +645,5 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink.opcua.security.dir | Directory for OPC UA's keys and certificates | String: Path, supports absolute and relative directories | No | Opc_security folder``in the conf directory of the DataNode related to iotdb
If there is no conf directory for iotdb (such as launching DataNode in IDEA), it will be the iotdb_opc_Security folder``in the user's home directory | | sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | No | true | | sink.user | User for OPC UA, specified in the configuration | String | No | root | -| sink.password | Password for OPC UA, specified in the configuration | String | No | root | +| sink.password | Password for OPC UA, specified in the configuration | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | | sink.opcua.placeholder | A placeholder string used to substitute for null mapping paths when the value of the ID column is null | String | Optional | "null" | diff --git a/src/UserGuide/latest/API/Programming-Data-Subscription.md b/src/UserGuide/latest/API/Programming-Data-Subscription_apache.md similarity index 99% rename from src/UserGuide/latest/API/Programming-Data-Subscription.md rename to src/UserGuide/latest/API/Programming-Data-Subscription_apache.md index 7019f1b51..91e21cb83 100644 --- a/src/UserGuide/latest/API/Programming-Data-Subscription.md +++ b/src/UserGuide/latest/API/Programming-Data-Subscription_apache.md @@ -21,7 +21,7 @@ # Data Subscription API -IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription.md) +IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription_apache) ## 1. Core Steps @@ -33,7 +33,7 @@ IoTDB provides powerful data subscription functionality, allowing users to acces ## 2. Detailed Steps -This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API.md#_3-native-interface-description) +This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API_apache#_3-native-interface-description) ### 2.1 Create a Maven project diff --git a/src/UserGuide/latest/API/Programming-Data-Subscription_timecho.md b/src/UserGuide/latest/API/Programming-Data-Subscription_timecho.md new file mode 100644 index 000000000..c49e12d6e --- /dev/null +++ b/src/UserGuide/latest/API/Programming-Data-Subscription_timecho.md @@ -0,0 +1,259 @@ + + + + +# Data Subscription API + +IoTDB provides powerful data subscription functionality, allowing users to access newly added data from IoTDB in real-time through subscription APIs. For detailed functional definitions and introductions:[Data subscription](../User-Manual/Data-subscription_timecho) + +## 1. Core Steps + +1. Create Topic: Create a Topic that includes the measurement points you wish to subscribe to. +2. Subscribe to Topic: Before a consumer subscribes to a topic, the topic must have been created, otherwise the subscription will fail. Consumers under the same consumer group will evenly distribute the data. +3. Consume Data: Only by explicitly subscribing to a specific topic will you receive data from that topic. +4. Unsubscribe: When a consumer is closed, it will exit the corresponding consumer group and cancel all existing subscriptions. + + +## 2. Detailed Steps + +This section is used to illustrate the core development process and does not demonstrate all parameters and interfaces. For a comprehensive understanding of all features and parameters, please refer to: [Java Native API](../API/Programming-Java-Native-API_timecho#_3-native-interface-description) + + +### 2.1 Create a Maven project + +Create a Maven project and import the following dependencies(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 Code Example + +#### 2.2.1 Topic operations + +```java +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.SubscriptionSession; +import org.apache.iotdb.session.subscription.model.Topic; + +public class DataConsumerExample { + + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + try (SubscriptionSession session = new SubscriptionSession("127.0.0.1", 6667, "root", "TimechoDB@2021", 67108864)) { //Before V2.0.6.x the default password is root + // 1. open session + session.open(); + + // 2. create a topic of all data + Properties sessionConfig = new Properties(); + sessionConfig.put(TopicConstant.PATH_KEY, "root.**"); + + session.createTopic("allData", sessionConfig); + + // 3. show all topics + Set topics = session.getTopics(); + System.out.println(topics); + + // 4. show a specific topic + Optional allData = session.getTopic("allData"); + System.out.println(allData.get()); + } + } +} +``` + +#### 2.2.2 Data Consume + +##### Scenario-1: Subscribing to newly added real-time data in IoTDB (for scenarios such as dashboard or configuration display) + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessageType; +import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.tsfile.read.common.RowRecord; + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + + // 5. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //Before V2.0.6.x the default password is root + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + final short messageType = message.getMessageType(); + if (SubscriptionMessageType.isValidatedMessageType(messageType)) { + for (final SubscriptionSessionDataSet dataSet : message.getSessionDataSetsHandler()) { + while (dataSet.hasNext()) { + final RowRecord record = dataSet.next(); + System.out.println(record); + } + } + } + } + } + } + } +} + + +``` + +##### Scenario-2: Subscribing to newly added TsFiles (for scenarios such as regular data backup) + +Prerequisite: The format of the topic to be consumed must be of the TsfileHandler type. For example:`create topic topic_all_tsfile with ('path'='root.**','format'='TsFileHandler')` + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; + + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + // 1. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + // 2. Specify the consumption type as the tsfile type + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //Before V2.0.6.x the default password is root + consumerConfig.put(ConsumerConstant.FILE_SAVE_DIR_KEY, "/Users/iotdb/Downloads"); + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all_tsfile"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + message.getTsFileHandler().copyFile("/Users/iotdb/Downloads/1.tsfile"); + } + } + } + } +} +``` + + + + +## 3. Java Native API Description + +### 3.1 Parameter List + +The consumer-related parameters can be set through the Properties parameter object. The specific parameters are as follows: + +#### SubscriptionConsumer + + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :---------------------- |:-------------------------------------------------------------------------------------| :----------------------------------------------------------- | +| host | optional: 127.0.0.1 | `String`: The RPC host of a DataNode in IoTDB | +| port | optional: 6667 | `Integer`: The RPC port of a DataNode in IoTDB | +| node-urls | optional: 127.0.0.1:6667 | `List`: The RPC addresses of all DataNodes in IoTDB, which can be multiple; either host:port or node-urls can be filled. If both host:port and node-urls are filled, the **union** of host:port and node-urls will be taken to form a new node-urls for application | +| username | optional: root | `String`: The username of the DataNode in IoTDB | +| password | optional: TimechoDB@2021 //Before V2.0.6.x the default password is root | `String`: The password of the DataNode in IoTDB | +| groupId | optional | `String`: consumer group id,if not specified, it will be randomly assigned (a new consumer group),ensuring that the consumer group id of different consumer groups are all different | +| consumerId | optional | `String`: consumer client id,if not specified, it will be randomly assigned,ensuring that each consumer client id in the same consumer group is different | +| heartbeatIntervalMs | optional: 30000 (min: 1000) | `Long`: The interval at which the consumer sends periodic heartbeat requests to the IoTDB DataNode | +| endpointsSyncIntervalMs | optional: 120000 (min: 5000) | `Long`: The interval at which the consumer detects the expansion or contraction of IoTDB cluster nodes and adjusts the subscription connection | +| fileSaveDir | optional: Paths.get(System.getProperty("user.dir"), "iotdb-subscription").toString() | `String`: The temporary directory path where the consumer stores the subscribed TsFile files | +| fileSaveFsync | optional: false | `Boolean`: Whether the consumer actively calls fsync during the subscription of TsFiles | + +Special configurations in `SubscriptionPushConsumer` : + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| ackStrategy | optional: `ACKStrategy.AFTER_CONSUME` | The acknowledgment mechanism for consumption progress includes the following options: `ACKStrategy.BEFORE_CONSUME`(the consumer submits the consumption progress immediately upon receiving the data, before `onReceive` )`ACKStrategy.AFTER_CONSUME`(the consumer submits the consumption progress after consuming the data, after `onReceive` ) | +| consumeListener | optional | The callback function for consuming data, which needs to implement the `ConsumeListener` interface, defining the processing logic for consuming `SessionDataSetsHandler` and `TsFileHandler` formatted data | +| autoPollIntervalMs | optional: 5000 (min: 500) | Long: The time interval at which the consumer automatically pulls data, in **ms** | +| autoPollTimeoutMs | optional: 10000 (min: 1000) | Long: The timeout duration for the consumer to pull data each time, in **ms** | + +Special configurations in `SubscriptionPullConsumer` : + +| **Parameter** | **required or optional with default** | **Parameter Meaning** | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| autoCommit | optional: true | Boolean: Whether to automatically commit the consumption progress. If this parameter is set to false, the `commit` method needs to be called manually to submit the consumption progress | +| autoCommitInterval | optional: 5000 (min: 500) | Long: The time interval for automatically committing the consumption progress, in **ms** .This parameter only takes effect when the `autoCommit` parameter is set to true | + + +### 3.2 Function List + +#### Data subscription + +##### SubscriptionPullConsumer + +| **Function name** | **Description** | **Parameter** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | Opens the consumer connection and starts message consumption. If `autoCommit` is enabled, it will start the automatic commit worker. | None | +| `close()` | Closes the consumer connection. If `autoCommit` is enabled, it will commit all uncommitted messages before closing. | None | +| `poll(final Duration timeout)` | Pulls messages with a specified timeout. | `timeout` : The timeout duration. | +| `poll(final long timeoutMs)` | Pulls messages with a specified timeout in milliseconds. | `timeoutMs` : The timeout duration in milliseconds. | +| `poll(final Set topicNames, final Duration timeout)` | Pulls messages from specified topics with a specified timeout. | `topicNames` : The set of topics to pull messages from. `timeout`: The timeout duration。 | +| `poll(final Set topicNames, final long timeoutMs)` | Pulls messages from specified topics with a specified timeout in milliseconds. | `topicNames` : The set of topics to pull messages from.`timeoutMs`: The timeout duration in milliseconds. | +| `commitSync(final SubscriptionMessage message)` | Synchronously commits a single message. | `message` : The message object to be committed. | +| `commitSync(final Iterable messages)` | Synchronously commits multiple messages. | `messages` : The collection of message objects to be committed. | +| `commitAsync(final SubscriptionMessage message)` | Asynchronously commits a single message. | `message` : The message object to be committed. | +| `commitAsync(final Iterable messages)` | Asynchronously commits multiple messages. | `messages` : The collection of message objects to be committed. | +| `commitAsync(final SubscriptionMessage message, final AsyncCommitCallback callback)` | Asynchronously commits a single message with a specified callback. | `message` : The message object to be committed. `callback` : The callback function to be executed after asynchronous commit. | +| `commitAsync(final Iterable messages, final AsyncCommitCallback callback)` | Asynchronously commits multiple messages with a specified callback. | `messages` : The collection of message objects to be committed.`callback` : The callback function to be executed after asynchronous commit. | + +##### SubscriptionPushConsumer + +| **Function name** | **Description** | **Parameter** | +| -------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | Opens the consumer connection, starts message consumption, and submits the automatic polling worker. | None | +| `close()` | Closes the consumer connection and stops message consumption. | None | +| `toString()` | Returns the core configuration information of the consumer object. | None | +| `coreReportMessage()` | Obtains the key-value representation of the consumer's core configuration. | None | +| `allReportMessage()` | Obtains the key-value representation of all the consumer's configurations. | None | +| `buildPushConsumer()` | Builds a `SubscriptionPushConsumer` instance through the `Builder` | None | +| `ackStrategy(final AckStrategy ackStrategy)` | Configures the message acknowledgment strategy for the consumer. | `ackStrategy`: The specified message acknowledgment strategy. | +| `consumeListener(final ConsumeListener consumeListener)` | Configures the message consumption logic for the consumer. | `consumeListener`: The processing logic when the consumer receives messages. | +| `autoPollIntervalMs(final long autoPollIntervalMs)` | Configures the interval for automatic polling. | `autoPollIntervalMs` : The interval for automatic polling, in milliseconds. | +| `autoPollTimeoutMs(final long autoPollTimeoutMs)` | Configures the timeout for automatic polling.间。 | `autoPollTimeoutMs`: The timeout for automatic polling, in milliseconds. | \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/API/Programming-JDBC.md b/src/UserGuide/latest/API/Programming-JDBC_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/API/Programming-JDBC.md rename to src/UserGuide/latest/API/Programming-JDBC_apache.md index b83c2865b..1a2902672 100644 --- a/src/UserGuide/Master/Tree/API/Programming-JDBC.md +++ b/src/UserGuide/latest/API/Programming-JDBC_apache.md @@ -22,8 +22,7 @@ # JDBC **Note**: The current JDBC implementation is only for connecting with third-party tools. We do not recommend using JDBC (when executing insert statements) as it cannot provide high-performance writing. For queries, we recommend using JDBC. - -PLEASE USE [Java Native API](./Programming-Java-Native-API.md) INSTEAD* +PLEASE USE [Java Native API](./Programming-Java-Native-API_apache) INSTEAD* ## 1. Dependencies diff --git a/src/UserGuide/latest/API/Programming-JDBC_timecho.md b/src/UserGuide/latest/API/Programming-JDBC_timecho.md new file mode 100644 index 000000000..782d7e9ab --- /dev/null +++ b/src/UserGuide/latest/API/Programming-JDBC_timecho.md @@ -0,0 +1,295 @@ + + +# JDBC + +**Note**: The current JDBC implementation is only for connecting with third-party tools. We do not recommend using JDBC (when executing insert statements) as it cannot provide high-performance writing. For queries, we recommend using JDBC. +PLEASE USE [Java Native API](./Programming-Java-Native-API_timecho) INSTEAD* + +## 1. Dependencies + +* JDK >= 1.8+ +* Maven >= 3.9+ + +## 2. Installation + +In root directory: + +```shell +mvn clean install -pl iotdb-client/jdbc -am -DskipTests +``` + +## 3. Use IoTDB JDBC with Maven + +```xml + + + org.apache.iotdb + iotdb-jdbc + 1.3.1 + + +``` + +## 4. Coding Examples + +This chapter provides an example of how to open a database connection, execute an SQL query, and display the results. + +It requires including the packages containing the JDBC classes needed for database programming. + +**NOTE: For faster insertion, the insertTablet() in Session is recommended.** + +```java +import java.sql.*; +import org.apache.iotdb.jdbc.IoTDBSQLException; + +public class JDBCExample { + /** + * Before executing a SQL statement with a Statement object, you need to create a Statement object using the createStatement() method of the Connection object. + * After creating a Statement object, you can use its execute() method to execute a SQL statement + * Finally, remember to close the 'statement' and 'connection' objects by using their close() method + * For statements with query results, we can use the getResultSet() method of the Statement object to get the result set. + */ + public static void main(String[] args) throws SQLException { + Connection connection = getConnection(); + if (connection == null) { + System.out.println("get connection defeat"); + return; + } + Statement statement = connection.createStatement(); + //Create database + try { + statement.execute("CREATE DATABASE root.demo"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + + + //SHOW DATABASES + statement.execute("SHOW DATABASES"); + outputResult(statement.getResultSet()); + + //Create time series + //Different data type has different encoding methods. Here use INT32 as an example + try { + statement.execute("CREATE TIMESERIES root.demo.s0 WITH DATATYPE=INT32,ENCODING=RLE;"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + //Show time series + statement.execute("SHOW TIMESERIES root.demo"); + outputResult(statement.getResultSet()); + //Show devices + statement.execute("SHOW DEVICES"); + outputResult(statement.getResultSet()); + //Count time series + statement.execute("COUNT TIMESERIES root"); + outputResult(statement.getResultSet()); + //Count nodes at the given level + statement.execute("COUNT NODES root LEVEL=3"); + outputResult(statement.getResultSet()); + //Count timeseries group by each node at the given level + statement.execute("COUNT TIMESERIES root GROUP BY LEVEL=3"); + outputResult(statement.getResultSet()); + + + //Execute insert statements in batch + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(1,1);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(1,1);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(2,15);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) VALUES(2,17);"); + statement.addBatch("INSERT INTO root.demo(timestamp,s0) values(4,12);"); + statement.executeBatch(); + statement.clearBatch(); + + //Full query statement + String sql = "SELECT * FROM root.demo"; + ResultSet resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Exact query statement + sql = "SELECT s0 FROM root.demo WHERE time = 4;"; + resultSet= statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Time range query + sql = "SELECT s0 FROM root.demo WHERE time >= 2 AND time < 5;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Aggregate query + sql = "SELECT COUNT(s0) FROM root.demo;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Delete time series + statement.execute("DELETE timeseries root.demo.s0"); + + //close connection + statement.close(); + connection.close(); + } + + public static Connection getConnection() { + // JDBC driver name and database URL + String driver = "org.apache.iotdb.jdbc.IoTDBDriver"; + String url = "jdbc:iotdb://127.0.0.1:6667/"; + // set rpc compress mode + // String url = "jdbc:iotdb://127.0.0.1:6667?rpc_compress=true"; + + // Database credentials + String username = "root"; + String password = "TimechoDB@2021"; //Before V2.0.6.x the default password is root + + Connection connection = null; + try { + Class.forName(driver); + connection = DriverManager.getConnection(url, username, password); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return connection; + } + + /** + * This is an example of outputting the results in the ResultSet + */ + private static void outputResult(ResultSet resultSet) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print(resultSet.getString(i)); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` + +The parameter `version` can be used in the url: +````java +String url = "jdbc:iotdb://127.0.0.1:6667?version=V_1_0"; +```` +The parameter `version` represents the SQL semantic version used by the client, which is used in order to be compatible with the SQL semantics of `0.12` when upgrading to `0.13`. +The possible values are: `V_0_12`, `V_0_13`, `V_1_0`. + +In addition, IoTDB provides additional interfaces in JDBC for users to read and write the database using different character sets (e.g., GB18030) in the connection. +The default character set for IoTDB is UTF-8. When users want to use a character set other than UTF-8, they need to specify the charset property in the JDBC connection. For example: +1. Create a connection using the GB18030 charset: +```java +DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root +``` +2. When executing SQL with the `IoTDBStatement` interface, the SQL can be provided as a `byte[]` array, and it will be parsed into a string according to the specified charset. +```java +public boolean execute(byte[] sql) throws SQLException; +``` +3. When outputting query results, the `getBytes` method of `ResultSet` can be used to get `byte[]`, which will be encoded using the charset specified in the connection. +```java +System.out.print(resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); +``` +Here is a complete example: +```java +public class JDBCCharsetExample { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCCharsetExample.class); + + public static void main(String[] args) throws Exception { + Class.forName("org.apache.iotdb.jdbc.IoTDBDriver"); + + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + + final String insertSQLWithGB18030 = + "insert into root.测试(timestamp, 维语, 彝语, 繁体, 蒙文, 简体, 标点符号, 藏语) values(1, 'ئۇيغۇر تىلى', 'ꆈꌠꉙ', \"繁體\", 'ᠮᠣᠩᠭᠣᠯ ᠬᠡᠯᠡ', '简体', '——?!', \"བོད་སྐད།\");"; + final byte[] insertSQLWithGB18030Bytes = insertSQLWithGB18030.getBytes("GB18030"); + statement.execute(insertSQLWithGB18030Bytes); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + + outputResult("GB18030"); + outputResult("UTF-8"); + outputResult("UTF-16"); + outputResult("GBK"); + outputResult("ISO-8859-1"); + } + + private static void outputResult(String charset) throws SQLException { + System.out.println("[Charset: " + charset + "]"); + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=" + charset, "root", "TimechoDB@2021"); //Before V2.0.6.x the default password is root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + outputResult(statement.executeQuery("select ** from root"), Charset.forName(charset)); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + } + + private static void outputResult(ResultSet resultSet, Charset charset) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print( + resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` \ No newline at end of file diff --git a/src/UserGuide/latest/API/Programming-Java-Native-API.md b/src/UserGuide/latest/API/Programming-Java-Native-API_apache.md similarity index 99% rename from src/UserGuide/latest/API/Programming-Java-Native-API.md rename to src/UserGuide/latest/API/Programming-Java-Native-API_apache.md index 245a49723..0f0778b7c 100644 --- a/src/UserGuide/latest/API/Programming-Java-Native-API.md +++ b/src/UserGuide/latest/API/Programming-Java-Native-API_apache.md @@ -32,7 +32,7 @@ In the native API of IoTDB, the `Session` is the core interface for interacting ## 2. Detailed Steps -This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API.md#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) +This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API_apache#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) ### 2.1 Create a Maven Project diff --git a/src/UserGuide/latest/API/Programming-Java-Native-API_timecho.md b/src/UserGuide/latest/API/Programming-Java-Native-API_timecho.md new file mode 100644 index 000000000..dd8c3663b --- /dev/null +++ b/src/UserGuide/latest/API/Programming-Java-Native-API_timecho.md @@ -0,0 +1,498 @@ + + +# Java Native API + +In the native API of IoTDB, the `Session` is the core interface for interacting with the database. It integrates a rich set of methods that support data writing, querying, and metadata operations. By instantiating a `Session`, you can establish a connection to the IoTDB server and perform various database operations within the environment constructed by this connection. The `Session` is not thread-safe and should not be called simultaneously by multiple threads. + +`SessionPool` is a connection pool for `Session`, and it is recommended to use `SessionPool` for programming. In scenarios with multi-threaded concurrency, `SessionPool` can manage and allocate connection resources effectively, thereby improving system performance and resource utilization efficiency. + +## 1. Overview of Steps + +1. Create a Connection Pool Instance: Initialize a SessionPool object to manage multiple Session instances. +2. Perform Operations: Directly obtain a Session instance from the SessionPool and execute database operations, without the need to open and close connections each time. +3. Close Connection Pool Resources: When database operations are no longer needed, close the SessionPool to release all related resources. + + +## 2. Detailed Steps + +This section provides an overview of the core development process and does not demonstrate all parameters and interfaces. For a complete list of functionalities and parameters, please refer to:[Java Native API](./Programming-Java-Native-API_timecho#_3-native-interface-description) or check the: [Source Code](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) + +### 2.1 Create a Maven Project + +Create a Maven project and add the following dependencies to the pom.xml file (JDK >= 1.8, Maven >= 3.6): + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 Creating a Connection Pool Instance + + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.session.pool.SessionPool; + +public class IoTDBSessionPoolExample { + private static SessionPool sessionPool; + + public static void main(String[] args) { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root " + .maxSize(3) + .build(); + } +} +``` + +### 2.3 Performing Database Operations + +#### 2.3.1 Data Insertion + +In industrial scenarios, data insertion can be categorized into the following types: inserting multiple rows of data, and inserting multiple rows of data for a single device. Below, we introduce the insertion interfaces for different scenarios. + +##### Multi-Row Data Insertion Interface + +Interface Description: Supports inserting multiple rows of data at once, where each row corresponds to multiple measurement values for a device at a specific timestamp. + + +Interface List: + +| **Interface Name** | **Function Description** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Inserts multiple rows of data, suitable for scenarios where measurements are independently collected. | + +Code Example: + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertRecordsExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + public static void insertRecordsExample() throws IoTDBConnectionException, StatementExecutionException { + String deviceId = "root.sg1.d1"; + List measurements = new ArrayList<>(); + measurements.add("s1"); + measurements.add("s2"); + measurements.add("s3"); + List deviceIds = new ArrayList<>(); + List> measurementsList = new ArrayList<>(); + List> valuesList = new ArrayList<>(); + List timestamps = new ArrayList<>(); + List> typesList = new ArrayList<>(); + + for (long time = 0; time < 500; time++) { + List values = new ArrayList<>(); + List types = new ArrayList<>(); + values.add(1L); + values.add(2L); + values.add(3L); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + + deviceIds.add(deviceId); + measurementsList.add(measurements); + valuesList.add(values); + typesList.add(types); + timestamps.add(time); + if (time != 0 && time % 100 == 0) { + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + deviceIds.clear(); + measurementsList.clear(); + valuesList.clear(); + typesList.clear(); + timestamps.clear(); + } + } + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +##### Single-Device Multi-Row Data Insertion Interface + +Interface Description: Supports inserting multiple rows of data for a single device at once, where each row corresponds to multiple measurement values for a specific timestamp. + +Interface List: + +| **Interface Name** | **Function Description** | +| ----------------------------- | ------------------------------------------------------------ | +| `insertTablet(Tablet tablet)` | Inserts multiple rows of data for a single device, suitable for scenarios where measurements are independently collected. | + +Code Example: + +```java +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.write.record.Tablet; +import org.apache.tsfile.write.schema.IMeasurementSchema; +import org.apache.tsfile.write.schema.MeasurementSchema; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertTabletExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + //nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + private static void insertTabletExample() throws IoTDBConnectionException, StatementExecutionException { + /* + * A Tablet example: + * device1 + * time s1, s2, s3 + * 1, 1, 1, 1 + * 2, 2, 2, 2 + * 3, 3, 3, 3 + */ + // The schema of measurements of one device + // only measurementId and data type in MeasurementSchema take effects in Tablet + List schemaList = new ArrayList<>(); + schemaList.add(new MeasurementSchema("s1", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s2", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s3", TSDataType.INT64)); + + Tablet tablet = new Tablet("root.sg.d1",schemaList,100); + + // Method 1 to add tablet data + long timestamp = System.currentTimeMillis(); + + Random random = new Random(); + for (long row = 0; row < 100; row++) { + int rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, timestamp); + for (int s = 0; s < 3; s++) { + long value = random.nextLong(); + tablet.addValue(schemaList.get(s).getMeasurementName(), rowIndex, value); + } + if (tablet.getRowSize() == tablet.getMaxRowNumber()) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + timestamp++; + } + if (tablet.getRowSize() != 0) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +#### 2.3.2 SQL Operations + +SQL operations are divided into two categories: queries and non-queries. The corresponding interfaces are executeQuery and executeNonQuery. The difference between them is that the former executes specific query statements and returns a result set, while the latter performs insert, delete, and update operations and does not return a result set. + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.isession.pool.SessionDataSetWrapper; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. executes a non-query SQL statement, such as a DDL or DML command. + executeQueryExample(); + // 3. executes a query SQL statement and returns the result set. + executeNonQueryExample(); + // 4. close SessionPool + closeSessionPool(); + } + + private static void executeNonQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. create a nonAligned time series + sessionPool.executeNonQueryStatement("create timeseries root.test.d1.s1 with dataType = int32"); + // 2. set ttl + sessionPool.executeNonQueryStatement("set TTL to root.test.** 10000"); + // 3. delete time series + sessionPool.executeNonQueryStatement("delete timeseries root.test.d1.s1"); + } + + private static void executeQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. execute normal query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select s1 from root.sg1.d1 limit 10")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + // 2. execute aggregate query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select count(s1) from root.sg1.d1 group by ([0, 40), 5ms) ")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //Before V2.0.6.x the default password is root + .maxSize(3) + .build(); + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +### 3. Native Interface Description + +#### 3.1 Parameter List + +The Session class has the following fields, which can be set through the constructor or the Session.Builder method: + +| **Field Name** | **Type** | **Description** | +| -------------------------------- | ----------------------------------- | ------------------------------------------------------------ | +| `nodeUrls` | `List` | List of URLs for database nodes, supporting multiple node connections | +| `username` | `String` | Username | +| `password` | `String` | Password | +| `fetchSize` | `int` | Default batch size for query results | +| `useSSL` | `boolean` | Whether to enable SSL | +| `trustStore` | `String` | Path to the trust store | +| `trustStorePwd` | `String` | Password for the trust store | +| `queryTimeoutInMs` | `long` | Query timeout in milliseconds | +| `enableRPCCompression` | `boolean` | Whether to enable RPC compression | +| `connectionTimeoutInMs` | `int` | Connection timeout in milliseconds | +| `zoneId` | `ZoneId` | Time zone setting for the session | +| `thriftDefaultBufferSize` | `int` | Default buffer size for Thrift Thrift | +| `thriftMaxFrameSize` | `int` | Maximum frame size for Thrift Thrift | +| `defaultEndPoint` | `TEndPoint` | Default database endpoint information | +| `defaultSessionConnection` | `SessionConnection` | Default session connection object | +| `isClosed` | `boolean` | Whether the current session is closed | +| `enableRedirection` | `boolean` | Whether to enable redirection | +| `enableRecordsAutoConvertTablet` | `boolean` | Whether to enable the function of recording the automatic transfer to Tablet | +| `deviceIdToEndpoint` | `Map` | Mapping of device IDs to database endpoints | +| `endPointToSessionConnection` | `Map` | Mapping of database endpoints to session connections | +| `executorService` | `ScheduledExecutorService` | Thread pool for periodically updating the node list | +| `availableNodes` | `INodeSupplier` | Supplier of available nodes | +| `enableQueryRedirection` | `boolean` | Whether to enable query redirection | +| `version` | `Version` | Client version number, used for compatibility judgment with the server | +| `enableAutoFetch` | `boolean` | Whether to enable automatic fetching | +| `maxRetryCount` | `int` | Maximum number of retries | +| `retryIntervalInMs` | `long` | Retry interval in milliseconds | + + + +#### 3.2 Interface list + +##### 3.2.1 Metadata Management + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------ | +| `createDatabase(String database)` | Create a database | `database`: The name of the database to be created | +| `deleteDatabase(String database)` | Delete a specified database | `database`: The name of the database to be deleted | +| `deleteDatabases(List databases)` | Batch delete databases | `databases`: A list of database names to be deleted | +| `createTimeseries(String path, TSDataType dataType, TSEncoding encoding, CompressionType compressor)` | Create a single time series | `path`: The path of the time series,`dataType`: The data type,`encoding`: The encoding type,`compressor`: The compression type | +| `createAlignedTimeseries(...)` | Create aligned time series | Device ID, list of measurement points, list of data types, list of encodings, list of compression types | +| `createMultiTimeseries(...)` | Batch create time series | Multiple paths, data types, encodings, compression types, properties, tags, aliases, etc. | +| `deleteTimeseries(String path)` | Delete a time series | `path`: The path of the time series to be deleted | +| `deleteTimeseries(List paths)` | Batch delete time series | `paths`: A list of time series paths to be deleted | +| `setSchemaTemplate(String templateName, String prefixPath)` | Set a schema template | `templateName`: The name of template,`prefixPath`: The path where the template is applied | +| `createSchemaTemplate(Template template)` | Create a schema template | `template`: The template object | +| `dropSchemaTemplate(String templateName)` | Delete a schema template | `templateName`: The name of template to be deleted | +| `addAlignedMeasurementsInTemplate(...)` | Add aligned measurements to a template | Template name, list of measurement paths, data type, encoding type, compression type | +| `addUnalignedMeasurementsInTemplate(...)` | Add unaligned measurements to a template | Same as above | +| `deleteNodeInTemplate(String templateName, String path)` | Delete a node in a template | `templateName`: The name of template,`path`: The path to be deleted | +| `countMeasurementsInTemplate(String name)` | Count the number of measurements in a template | `name`: The name of template | +| `isMeasurementInTemplate(String templateName, String path)` | Check if a measurement exists in a template | `templateName`: The name of template,`path`: The path of the measurement | +| `isPathExistInTemplate(String templateName, String path)` | Check if a path exists in a template | same as above | +| `showMeasurementsInTemplate(String templateName)` | Show measurements in a template | `templateName`: The name of template | +| `showMeasurementsInTemplate(String templateName, String pattern)` | Show measurements in a template by pattern | `templateName`: The name of template,`pattern`: The matching pattern | +| `showAllTemplates()` | Show all templates | No parameters | +| `showPathsTemplateSetOn(String templateName)` | Show paths where a template is set | `templateName`: The name of the template | +| `showPathsTemplateUsingOn(String templateName)` | Show actual paths using a template | Same as above上 | +| `unsetSchemaTemplate(String prefixPath, String templateName)` | Unset the template setting for a path | `prefixPath`: The path,`templateName`: The name of template | + + +##### 3.2.2 Data Insertion + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `insertRecord(String deviceId, long time, List measurements, List types, Object... values)` | Insert a single record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`types`: List of data types,`values`: List of values | +| `insertRecord(String deviceId, long time, List measurements, List values)` | Insert a single record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`values`: List of values | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | Insert multiple records | `deviceIds`: List of device IDs,`times`: List of timestamps,`measurementsList`: List of timestamps,`valuesList`: List of lists of values | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple records | Same as above,plus `typesList`: List of lists of data types | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`typesList`: List of lists of types,`valuesList`: List of lists of values | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | Insert sorted multiple records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | Insert string-formatted records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | Insert sorted string-formatted records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted序 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List types, List values)` | Insert a single aligned record | `deviceId`: Device ID,`time`: Timestamp,`measurements`: List of measurement points,`types`: List of types,`values`: List of values | +| `insertAlignedRecord(String deviceId, long time, List measurements, List values)` | Insert a single string-formatted aligned record | `deviceId`: Device ID`time`: Timestamp,`measurements`: List of measurement points,`values`: List of values | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | Insert multiple aligned records | `deviceIds`: List of device IDs,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple aligned records | Same as above, plus `typesList`: List of lists of data types | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | Insert multiple aligned records for a single device | Same as above | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | Insert sorted multiple aligned records for a single device | Same as above, plus `haveSorted`: Whether the data is already sorted | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | Insert string-formatted aligned records for a single device | `deviceId`: Device ID,`times`: List of timestamps,`measurementsList`: List of lists of measurement points,`valuesList`: List of lists of values | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | Insert sorted string-formatted aligned records for a single device | Same as above, plus w `haveSorted`: whether the data is already sorted | +| `insertTablet(Tablet tablet)` | Insert a single Tablet data | `tablet`: The Tablet data to be inserted | +| `insertTablet(Tablet tablet, boolean sorted)` | Insert a sorted Tablet data | Same as above, plus `sorted`: whether the data is already sorted | +| `insertAlignedTablet(Tablet tablet)` | Insert an aligned Tablet data | `tablet`: The Tablet data to be inserted | +| `insertAlignedTablet(Tablet tablet, boolean sorted)` | Insert a sorted aligned Tablet data | Same as above, plus `sorted`: whether the data is already sorted | +| `insertTablets(Map tablets)` | Insert multiple Tablet data in batch | `tablets`: Mapping from device IDs to Tablet data | +| `insertTablets(Map tablets, boolean sorted)` | Insert sorted multiple Tablet data in batch | Same as above, plus `sorted`: whether the data is already sorted | +| `insertAlignedTablets(Map tablets)` | Insert multiple aligned Tablet data in batch | `tablets`: Mapping from device IDs to Tablet data | +| `insertAlignedTablets(Map tablets, boolean sorted)` | Insert sorted multiple aligned Tablet data in batch | Same as above, plus `sorted`: whether the data is already sorted | + +##### 3.2.3 Data Deletion + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------- | +| `deleteTimeseries(String path)` | Delete a single time series | `path`: The path of the time series | +| `deleteTimeseries(List paths)` | Batch delete time series | `paths`: A list of time series paths | +| `deleteData(String path, long endTime)` | Delete historical data for a specified path | `path`: The path,`endTime`: The end timestamp | +| `deleteData(List paths, long endTime)` | Batch delete historical data for specified paths | `paths`: A list of paths,`endTime`: The end timestamp | +| `deleteData(List paths, long startTime, long endTime)` | Delete historical data within a time range for specified paths | Same as above, plus `startTime`: The start timestamp | + + +##### 3.2.4 Data Query + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| ------------------------------------------------------------ | -------------------------------------------------------- | ------------------------------------------------------------ | +| `executeQueryStatement(String sql)` | Execute a query statement | `sql`: The query SQL statement | +| `executeQueryStatement(String sql, long timeoutInMs)` | Execute a query statement with timeout | `sql`: The query SQL statement, `timeoutInMs`: The query timeout (in milliseconds), default to the server configuration, which is 60s. | +| `executeRawDataQuery(List paths, long startTime, long endTime)` | Query raw data for specified paths | paths: A list of query paths, `startTime`: The start timestamp, `endTime`: The end timestamp | +| `executeRawDataQuery(List paths, long startTime, long endTime, long timeOut)` | Query raw data for specified paths (with timeout) | Same as above, plus `timeOut`: The timeout time | +| `executeLastDataQuery(List paths)` | Query the latest data | `paths`: A list of query paths | +| `executeLastDataQuery(List paths, long lastTime)` | Query the latest data at a specified time | `paths`: A list of query paths, `lastTime`: The specified timestamp | +| `executeLastDataQuery(List paths, long lastTime, long timeOut)` | Query the latest data at a specified time (with timeout) | Same as above, plus `timeOut`: The timeout time | +| `executeLastDataQueryForOneDevice(String db, String device, List sensors, boolean isLegalPathNodes)` | Query the latest data for a single device | `db`: The database name, `device`: The device name, `sensors`: A list of sensors, `isLegalPathNodes`: Whether the path nodes are legal | +| `executeAggregationQuery(List paths, List aggregations)` | Execute an aggregation query | `paths`: A list of query paths, `aggregations`: A list of aggregation types | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime)` | Execute an aggregation query with a time range | Same as above, plus `startTime`: The start timestamp, `endTime`:` The end timestamp | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval)` | Execute an aggregation query with a time interval | Same as above, plus `interval`: The time interval | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval, long slidingStep)` | Execute a sliding window aggregation query | Same as above, plus `slidingStep`: The sliding step | +| `fetchAllConnections()` | Get information of all active connections | No parameters | + +##### 3.2.5 System Status and Backup + +| **Method Name** | **Function Description** | **Parameter Explanation** | +| -------------------------- | ----------------------------------------- | ------------------------------------------ | +| `getBackupConfiguration()` | Get backup configuration information | No parameters | +| `fetchAllConnections()` | Get information of all active connections | No parameters | +| `getSystemStatus()` | Get the system status | Deprecated, returns `SystemStatus.NORMAL` | \ No newline at end of file diff --git a/src/UserGuide/latest/API/Programming-OPC-UA_timecho.md b/src/UserGuide/latest/API/Programming-OPC-UA_timecho.md index f631a865d..a638f0f6d 100644 --- a/src/UserGuide/latest/API/Programming-OPC-UA_timecho.md +++ b/src/UserGuide/latest/API/Programming-OPC-UA_timecho.md @@ -80,23 +80,23 @@ create pipe p1 'sink.opcua.tcp.port' = '12686', 'sink.opcua.https.port' = '8443', 'sink.user' = 'root', - 'sink.password' = 'root', + 'sink.password' = 'TimechoDB@2021', //Before V2.0.6.x the default password is root 'sink.opcua.security.dir' = '...' ) ``` ### 2.2 Parameters -| key | value | value range | required or not | default value | -| :------------------------------ | :----------------------------------------------------------- | :------------------------------------- | :------- | :------------- | -| sink | OPC UA SINK | String: opc-ua-sink | Required | | -| sink.opcua.model | OPC UA model used | String: client-server / pub-sub | Optional | pub-sub | -| sink.opcua.tcp.port | OPC UA's TCP port | Integer: [0, 65536] | Optional | 12686 | -| sink.opcua.https.port | OPC UA's HTTPS port | Integer: [0, 65536] | Optional | 8443 | +| key | value | value range | required or not | default value | +| :------------------------------ | :----------------------------------------------------------- | :------------------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| sink | OPC UA SINK | String: opc-ua-sink | Required | | +| sink.opcua.model | OPC UA model used | String: client-server / pub-sub | Optional | pub-sub | +| sink.opcua.tcp.port | OPC UA's TCP port | Integer: [0, 65536] | Optional | 12686 | +| sink.opcua.https.port | OPC UA's HTTPS port | Integer: [0, 65536] | Optional | 8443 | | sink.opcua.security.dir | Directory for OPC UA's keys and certificates | String: Path, supports absolute and relative directories | Optional | Opc_security folder/in the conf directory of the DataNode related to iotdb
If there is no conf directory for iotdb (such as launching DataNode in IDEA), it will be the iotdb_opc_Security folder/in the user's home directory | -| sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | Optional | true | -| sink.user | User for OPC UA, specified in the configuration | String | Optional | root | -| sink.password | Password for OPC UA, specified in the configuration | String | Optional | root | +| sink.opcua.enable-anonymous-access | Whether OPC UA allows anonymous access | Boolean | Optional | true | +| sink.user | User for OPC UA, specified in the configuration | String | Optional | root | +| sink.password | Password for OPC UA, specified in the configuration | String | Optional | TimechoDB@2021 //Before V2.0.6.x the default password is root | ### 2.3 Example @@ -104,7 +104,7 @@ create pipe p1 create pipe p1 with sink ('sink' = 'opc-ua-sink', 'sink.user' = 'root', - 'sink.password' = 'root'); + 'sink.password' = 'TimechoDB@2021' //Before V2.0.6.x the default password is root start pipe p1; ``` diff --git a/src/UserGuide/latest/API/Programming-Python-Native-API.md b/src/UserGuide/latest/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/UserGuide/latest/API/Programming-Python-Native-API.md rename to src/UserGuide/latest/API/Programming-Python-Native-API_apache.md diff --git a/src/UserGuide/latest/API/Programming-Python-Native-API_timecho.md b/src/UserGuide/latest/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..8df2a7996 --- /dev/null +++ b/src/UserGuide/latest/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,826 @@ + + +# Python Native API + +## 1. Requirements + +You have to install thrift (>=0.13) before using the package. + + + +## 2. How to use (Example) + +First, download the package: `pip3 install apache-iotdb>=2.0` + +You can get an example of using the package to read and write data at here:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_example.py) + +An example of aligned timeseries: [Aligned Timeseries Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_aligned_timeseries_example.py) + +(you need to add `import iotdb` in the head of the file) + +Or: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + +## 3. Initialization + +* Initialize a Session + +```python +session = Session( + ip="127.0.0.1", + port="6667", + user="root", + password="TimechoDB@2021", //Before V2.0.6.x the default password is root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* Initialize a Session to connect multiple nodes + +```python +session = Session.init_from_node_urls( + node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], + user="root", + password="TimechoDB@2021", //Before V2.0.6.x the default password is root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* Open a session, with a parameter to specify whether to enable RPC compression + +```python +session.open(enable_rpc_compression=False) +``` + +Notice: this RPC compression status of client must comply with that of IoTDB server + +* Close a Session + +```python +session.close() +``` + +## 4. Managing Session through SessionPool + +Utilizing SessionPool to manage sessions eliminates the need to worry about session reuse. When the number of session connections reaches the maximum capacity of the pool, requests for acquiring a session will be blocked, and you can set the blocking wait time through parameters. After using a session, it should be returned to the SessionPool using the `putBack` method for proper management. + +### 4.1 Create SessionPool + +```python +pool_config = PoolConfig(host=ip,port=port, user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 + +# # Create the connection pool +session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) +``` +### 4.2 Create a SessionPool using distributed nodes. +```python +pool_config = PoolConfig(node_urls=node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 +``` +### 4.3 Acquiring a session through SessionPool and manually calling PutBack after use + +```python +session = session_pool.get_session() +session.set_storage_group(STORAGE_GROUP_NAME) +session.create_time_series( + TIMESERIES_PATH, TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.SNAPPY +) +# After usage, return the session using putBack +session_pool.put_back(session) +# When closing the sessionPool, all managed sessions will be closed as well +session_pool.close() +``` +### 4.4 SSL Connection + +#### 4.4.1 Server Certificate Configuration + +In the `conf/iotdb-system.properties` configuration file, locate or add the following configuration items: + +```Java +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 4.4.2 Configure Python Client Certificate + +- Set `use_ssl` to True to enable SSL. +- Specify the client certificate path using the `ca_certs` parameter. + +```Java +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**Example Code: Using SSL to Connect to IoTDB** + +```Java +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 5. Data Definition Interface (DDL Interface) + +### 5.1 Database Management + +* CREATE DATABASE + +```python +session.set_storage_group(group_name) +``` + +* Delete one or several databases + +```python +session.delete_storage_group(group_name) +session.delete_storage_groups(group_name_lst) +``` +### 5.2 Timeseries Management + +* Create one or multiple timeseries + +```python +session.create_time_series(ts_path, data_type, encoding, compressor, + props=None, tags=None, attributes=None, alias=None) + +session.create_multi_time_series( + ts_path_lst, data_type_lst, encoding_lst, compressor_lst, + props_lst=None, tags_lst=None, attributes_lst=None, alias_lst=None +) +``` + +* Create aligned timeseries + +```python +session.create_aligned_time_series( + device_id, measurements_lst, data_type_lst, encoding_lst, compressor_lst +) +``` + +Attention: Alias of measurements are **not supported** currently. + +* Delete one or several timeseries + +```python +session.delete_time_series(paths_list) +``` + +* Check whether the specific timeseries exists + +```python +session.check_time_series_exists(path) +``` + +## 6. Data Manipulation Interface (DML Interface) + +### 6.1 Insert + +It is recommended to use insertTablet to help improve write efficiency. + +* Insert a Tablet,which is multiple rows of a device, each row has the same measurements + * **Better Write Performance** + * **Support null values**: fill the null value with any value, and then mark the null value via BitMap (from v0.13) + + +We have two implementations of Tablet in Python API. + +* Normal Tablet + +```python +values_ = [ + [False, 10, 11, 1.1, 10011.1, "test01"], + [True, 100, 11111, 1.25, 101.0, "test02"], + [False, 100, 1, 188.1, 688.25, "test03"], + [True, 0, 0, 0, 6.25, "test04"], +] +timestamps_ = [1, 2, 3, 4] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) + +values_ = [ + [None, 10, 11, 1.1, 10011.1, "test01"], + [True, None, 11111, 1.25, 101.0, "test02"], + [False, 100, None, 188.1, 688.25, "test03"], + [True, 0, 0, 0, None, None], +] +timestamps_ = [16, 17, 18, 19] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) +``` +* Numpy Tablet + +Comparing with Tablet, Numpy Tablet is using [numpy.ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) to record data. +With less memory footprint and time cost of serialization, the insert performance will be better. + +**Notice** +1. time and numerical value columns in Tablet is ndarray +2. recommended to use the specific dtypes to each ndarray, see the example below + (if not, the default dtypes are also ok). + +```python +import numpy as np +data_types_ = [ + TSDataType.BOOLEAN, + TSDataType.INT32, + TSDataType.INT64, + TSDataType.FLOAT, + TSDataType.DOUBLE, + TSDataType.TEXT, +] +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([1, 2, 3, 4], TSDataType.INT64.np_dtype()) +np_tablet_ = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_ +) +session.insert_tablet(np_tablet_) + +# insert one numpy tablet with None into the database. +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([98, 99, 100, 101], TSDataType.INT64.np_dtype()) +np_bitmaps_ = [] +for i in range(len(measurements_)): + np_bitmaps_.append(BitMap(len(np_timestamps_))) +np_bitmaps_[0].mark(0) +np_bitmaps_[1].mark(1) +np_bitmaps_[2].mark(2) +np_bitmaps_[4].mark(3) +np_bitmaps_[5].mark(3) +np_tablet_with_none = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_, np_bitmaps_ +) +session.insert_tablet(np_tablet_with_none) +``` + +* Insert multiple Tablets + +```python +session.insert_tablets(tablet_lst) +``` + +* Insert a Record + +```python +session.insert_record(device_id, timestamp, measurements_, data_types_, values_) +``` + +* Insert multiple Records + +```python +session.insert_records( + device_ids_, time_list_, measurements_list_, data_type_list_, values_list_ +) +``` + +* Insert multiple Records that belong to the same device. + With type info the server has no need to do type inference, which leads a better performance + + +```python +session.insert_records_of_one_device(device_id, time_list, measurements_list, data_types_list, values_list) +``` + +### 6.2 Insert with type inference + +When the data is of String type, we can use the following interface to perform type inference based on the value of the value itself. For example, if value is "true" , it can be automatically inferred to be a boolean type. If value is "3.2" , it can be automatically inferred as a flout type. Without type information, server has to do type inference, which may cost some time. + +* Insert a Record, which contains multiple measurement value of a device at a timestamp + +```python +session.insert_str_record(device_id, timestamp, measurements, string_values) +``` + +### 6.3 Insert of Aligned Timeseries + +The Insert of aligned timeseries uses interfaces like insert_aligned_XXX, and others are similar to the above interfaces: + +* insert_aligned_record +* insert_aligned_records +* insert_aligned_records_of_one_device +* insert_aligned_tablet +* insert_aligned_tablets + + +## 7. IoTDB-SQL Interface + +* Execute query statement + +```python +session.execute_query_statement(sql) +``` + +* Execute non query statement + +```python +session.execute_non_query_statement(sql) +``` + +* Execute statement + +```python +session.execute_statement(sql) +``` + +## 8. Schema Template +### 8.1 Create Schema Template +The step for creating a metadata template is as follows +1. Create the template class +2. Adding MeasurementNode +3. Execute create schema template function + +```python +template = Template(name=template_name, share_time=True) + +m_node_x = MeasurementNode("x", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_y = MeasurementNode("y", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_z = MeasurementNode("z", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) + +template.add_template(m_node_x) +template.add_template(m_node_y) +template.add_template(m_node_z) + +session.create_schema_template(template) +``` +### 8.2 Modify Schema Template measurements +Modify measurements in a template, the template must be already created. These are functions that add or delete some measurement nodes. +* add node in template +```python +session.add_measurements_in_template(template_name, measurements_path, data_types, encodings, compressors, is_aligned) +``` + +* delete node in template +```python +session.delete_node_in_template(template_name, path) +``` + +### 8.3 Set Schema Template +```python +session.set_schema_template(template_name, prefix_path) +``` + +### 8.4 Uset Schema Template +```python +session.unset_schema_template(template_name, prefix_path) +``` + +### 8.5 Show Schema Template +* Show all schema templates +```python +session.show_all_templates() +``` +* Count all measurements in templates +```python +session.count_measurements_in_template(template_name) +``` + +* Judge whether the path is measurement or not in templates, This measurement must be in the template +```python +session.count_measurements_in_template(template_name, path) +``` + +* Judge whether the path is exist or not in templates, This path may not belong to the template +```python +session.is_path_exist_in_template(template_name, path) +``` + +* Show nodes under in schema template +```python +session.show_measurements_in_template(template_name) +``` + +* Show the path prefix where a schema template is set +```python +session.show_paths_template_set_on(template_name) +``` + +* Show the path prefix where a schema template is used (i.e. the time series has been created) +```python +session.show_paths_template_using_on(template_name) +``` + +### 8.6 Drop Schema Template +Delete an existing metadata template,dropping an already set template is not supported +```python +session.drop_schema_template("template_python") +``` + + +## 9. Pandas Support + +To easily transform a query result to a [Pandas Dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) +the SessionDataSet has a method `.todf()` which consumes the dataset and transforms it to a pandas dataframe. + +Example: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +result = session.execute_query_statement("SELECT * FROM root.*") + +# Transform to Pandas Dataset +df = result.todf() + +session.close() + +# Now you can work with the dataframe +df = ... +``` + + +## 10. IoTDB Testcontainer + +The Test Support is based on the lib `testcontainers` (https://testcontainers-python.readthedocs.io/en/latest/index.html) which you need to install in your project if you want to use the feature. + +To start (and stop) an IoTDB Database in a Docker container simply do: +```python +class MyTestCase(unittest.TestCase): + + def test_something(self): + with IoTDBContainer() as c: + session = Session("localhost", c.get_exposed_port(6667), "root", "TimechoDB@2021") //Before V2.0.6.x the default password is root + session.open(False) + result = session.execute_query_statement("SHOW TIMESERIES") + print(result) + session.close() +``` + +by default it will load the image `apache/iotdb:latest`, if you want a specific version just pass it like e.g. `IoTDBContainer("apache/iotdb:0.12.0")` to get version `0.12.0` running. + +## 11. IoTDB DBAPI + +IoTDB DBAPI implements the Python DB API 2.0 specification (https://peps.python.org/pep-0249/), which defines a common +interface for accessing databases in Python. + +### 11.1 Examples ++ Initialization + +The initialized parameters are consistent with the session part (except for the sqlalchemy_mode). +```python +from iotdb.dbapi import connect + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +conn = connect(ip, port_, username_, password_,fetch_size=1024,zone_id="UTC+8",sqlalchemy_mode=False) +cursor = conn.cursor() +``` ++ simple SQL statement execution +```python +cursor.execute("SELECT ** FROM root") +for row in cursor.fetchall(): + print(row) +``` + ++ execute SQL with parameter + +IoTDB DBAPI supports pyformat style parameters +```python +cursor.execute("SELECT ** FROM root WHERE time < %(time)s",{"time":"2017-11-01T00:08:00.000"}) +for row in cursor.fetchall(): + print(row) +``` + ++ execute SQL with parameter sequences +```python +seq_of_parameters = [ + {"timestamp": 1, "temperature": 1}, + {"timestamp": 2, "temperature": 2}, + {"timestamp": 3, "temperature": 3}, + {"timestamp": 4, "temperature": 4}, + {"timestamp": 5, "temperature": 5}, +] +sql = "insert into root.cursor(timestamp,temperature) values(%(timestamp)s,%(temperature)s)" +cursor.executemany(sql,seq_of_parameters) +``` + ++ close the connection and cursor +```python +cursor.close() +conn.close() +``` + +## 12. IoTDB SQLAlchemy Dialect (Experimental) +The SQLAlchemy dialect of IoTDB is written to adapt to Apache Superset. +This part is still being improved. +Please do not use it in the production environment! +### 12.1 Mapping of the metadata +The data model used by SQLAlchemy is a relational data model, which describes the relationships between different entities through tables. +While the data model of IoTDB is a hierarchical data model, which organizes the data through a tree structure. +In order to adapt IoTDB to the dialect of SQLAlchemy, the original data model in IoTDB needs to be reorganized. +Converting the data model of IoTDB into the data model of SQLAlchemy. + +The metadata in the IoTDB are: + +1. Database +2. Path +3. Entity +4. Measurement + +The metadata in the SQLAlchemy are: +1. Schema +2. Table +3. Column + +The mapping relationship between them is: + +| The metadata in the SQLAlchemy | The metadata in the IoTDB | +| -------------------- | -------------------------------------------- | +| Schema | Database | +| Table | Path ( from database to entity ) + Entity | +| Column | Measurement | + +The following figure shows the relationship between the two more intuitively: + +![sqlalchemy-to-iotdb](/img/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true) + +### 12.2 Data type mapping +| data type in IoTDB | data type in SQLAlchemy | +|--------------------|-------------------------| +| BOOLEAN | Boolean | +| INT32 | Integer | +| INT64 | BigInteger | +| FLOAT | Float | +| DOUBLE | Float | +| TEXT | Text | +| LONG | BigInteger | + +### 12.3 Example + ++ execute statement + +```python +from sqlalchemy import create_engine + +engine = create_engine("iotdb://root:root@127.0.0.1:6667") +connect = engine.connect() +result = connect.execute("SELECT ** FROM root") +for row in result.fetchall(): + print(row) +``` + ++ ORM (now only simple queries are supported) + +```python +from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +metadata = MetaData( + schema='root.factory' +) +Base = declarative_base(metadata=metadata) + + +class Device(Base): + __tablename__ = "room2.device1" + Time = Column(BigInteger, primary_key=True) + temperature = Column(Float) + status = Column(Float) + + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //Before V2.0.6.x the default password is root + +DbSession = sessionmaker(bind=engine) +session = DbSession() + +res = session.query(Device.status).filter(Device.temperature > 1) + +for row in res: + print(row) +``` + + +## 13. Developers + +### 13.1 Introduction + +This is an example of how to connect to IoTDB with python, using the thrift rpc interfaces. Things are almost the same on Windows or Linux, but pay attention to the difference like path separator. + + + +### 13.2 Prerequisites + +Python3.7 or later is preferred. + +You have to install Thrift (0.11.0 or later) to compile our thrift file into python code. Below is the official tutorial of installation, eventually, you should have a thrift executable. + +``` +http://thrift.apache.org/docs/install/ +``` + +Before starting you need to install `requirements_dev.txt` in your python environment, e.g. by calling +```shell +pip install -r requirements_dev.txt +``` + + + +### 13.3 Compile the thrift library and Debug + +In the root of IoTDB's source code folder, run `mvn clean generate-sources -pl iotdb-client/client-py -am`. + +This will automatically delete and repopulate the folder `iotdb/thrift` with the generated thrift files. +This folder is ignored from git and should **never be pushed to git!** + +**Notice** Do not upload `iotdb/thrift` to the git repo. + + + + +### 13.4 Session Client & Example + +We packed up the Thrift interface in `client-py/src/iotdb/Session.py` (similar with its Java counterpart), also provided an example file `client-py/src/SessionExample.py` of how to use the session module. please read it carefully. + + +Or, another simple example: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //Before V2.0.6.x the default password is root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + + + +### 13.5 Tests + +Please add your custom tests in `tests` folder. + +To run all defined tests just type `pytest .` in the root folder. + +**Notice** Some tests need docker to be started on your system as a test instance is started in a docker container using [testcontainers](https://testcontainers-python.readthedocs.io/en/latest/index.html). + + + +### 13.6 Futher Tools + +[black](https://pypi.org/project/black/) and [flake8](https://pypi.org/project/flake8/) are installed for autoformatting and linting. +Both can be run by `black .` or `flake8 .` respectively. + + + +## 14. Releasing + +To do a release just ensure that you have the right set of generated thrift files. +Then run linting and auto-formatting. +Then, ensure that all tests work (via `pytest .`). +Then you are good to go to do a release! + + + +### 14.1 Preparing your environment + +First, install all necessary dev dependencies via `pip install -r requirements_dev.txt`. + + + +### 14.2 Doing the Release + +There is a convenient script `release.sh` to do all steps for a release. +Namely, these are + +* Remove all transient directories from last release (if exists) +* (Re-)generate all generated sources via mvn +* Run Linting (flake8) +* Run Tests via pytest +* Build +* Release to pypi + diff --git a/src/UserGuide/latest/API/RestServiceV1.md b/src/UserGuide/latest/API/RestServiceV1_apache.md similarity index 100% rename from src/UserGuide/latest/API/RestServiceV1.md rename to src/UserGuide/latest/API/RestServiceV1_apache.md diff --git a/src/UserGuide/latest/API/RestServiceV1_timecho.md b/src/UserGuide/latest/API/RestServiceV1_timecho.md new file mode 100644 index 000000000..a10bacce8 --- /dev/null +++ b/src/UserGuide/latest/API/RestServiceV1_timecho.md @@ -0,0 +1,924 @@ + + +# REST API V1(Not Recommend) +IoTDB's RESTful services can be used for query, write, and management operations, using the OpenAPI standard to define interfaces and generate frameworks. + +## 1. Enable RESTful Services + +RESTful services are disabled by default. + + Find the `conf/conf/iotdb-system.properties` file under the IoTDB installation directory and set `enable_rest_service` to `true` to enable the module. + + ```properties + enable_rest_service=true + ``` + +## 2. Authentication +Except the liveness probe API `/ping`, RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`. + +The username used in the following examples is: `root`, and password is: `TimechoDB@2021` //Before V2.0.6.x the default password is root. + +And the authorization header is + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- If a user authorized with incorrect username or password, the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- If the `Authorization` header is missing,the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. Interface + +### 3.1 ping + +The `/ping` API can be used for service liveness probing. + +Request method: `GET` + +Request path: `http://ip:port/ping` + +The user name used in the example is: root, password: root + +Example request: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +Response status codes: + +- `200`: The service is alive. +- `503`: The service cannot accept any requests now. + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +|code | integer | status code | +| message | string | message | + +Sample response: + +- With HTTP status code `200`: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- With HTTP status code `503`: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` can be accessed without authorization. + +### 3.2 query + +The query interface can be used to handle data queries and metadata queries. + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/query` + +Parameter Description: + +| parameter name | parameter type | required | parameter description | +|----------------| -------------- | -------- | ------------------------------------------------------------ | +| sql | string | yes | | +| rowLimit | integer | no | The maximum number of rows in the result set that can be returned by a query.
If this parameter is not set, the `rest_query_default_row_size_limit` of the configuration file will be used as the default value.
When the number of rows in the returned result set exceeds the limit, the status code `411` will be returned. | + +Response parameters: + +| parameter name | parameter type | parameter description | +|----------------| -------------- | ------------------------------------------------------------ | +| expressions | array | Array of result set column names for data query, `null` for metadata query | +| columnNames | array | Array of column names for metadata query result set, `null` for data query | +| timestamps | array | Timestamp column, `null` for metadata query | +| values | array | A two-dimensional array, the first dimension has the same length as the result set column name array, and the second dimension array represents a column of the result set | + +**Examples:** + +Tip: Statements like `select * from root.xx.**` are not recommended because those statements may cause OOM. + +**Expression query** + + ```shell + curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v1/query + ```` +Response instance + ```json + { + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] + } + ``` + +**Show child paths** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +**Show child nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +**Show all ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +**Show ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +**Show functions** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +**Show timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Show latest timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Count timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Count nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Show devices** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**Show devices with database** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**List user** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +**Aggregation** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +**Group by level** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +**Group by** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +**Last** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +**Disable align** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +**Align by device** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +**Select into** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/nonQuery` + +Parameter Description: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| sql | string | query content | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v1/nonQuery +``` + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v1/insertTablet` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:---------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements | array | yes | The name of the measuring point | +| dataTypes | array | yes | The data type | +| values | array | yes | Value columns, the values in each column can be `null` | +| isAligned | boolean | yes | Whether to align the timeseries | +| deviceId | string | yes | Device name | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"dataTypes":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"isAligned":false,"deviceId":"root.sg27"}' http://127.0.0.1:18080/rest/v1/insertTablet +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +## 4. Configuration + +The configuration is located in 'iotdb-system.properties'. + +* Set 'enable_rest_service' to 'true' to enable the module, and 'false' to disable the module. By default, this value is' false '. + +```properties +enable_rest_service=true +``` + +* This parameter is valid only when 'enable_REST_service =true'. Set 'rest_service_port' to a number (1025 to 65535) to customize the REST service socket port. By default, the value is 18080. + +```properties +rest_service_port=18080 +``` + +* Set 'enable_swagger' to 'true' to display rest service interface information through swagger, and 'false' to do not display the rest service interface information through the swagger. By default, this value is' false '. + +```properties +enable_swagger=false +``` + +* The maximum number of rows in the result set that can be returned by a query. When the number of rows in the returned result set exceeds the limit, the status code `411` is returned. + +````properties +rest_query_default_row_size_limit=10000 +```` + +* Expiration time for caching customer login information (used to speed up user authentication, in seconds, 8 hours by default) + +```properties +cache_expire=28800 +``` + + +* Maximum number of users stored in the cache (default: 100) + +```properties +cache_max_num=100 +``` + +* Initial cache size (default: 10) + +```properties +cache_init_num=10 +``` + +* REST Service whether to enable SSL configuration, set 'enable_https' to' true 'to enable the module, and set' false 'to disable the module. By default, this value is' false '. + +```properties +enable_https=false +``` + +* keyStore location path (optional) + +```properties +key_store_path= +``` + + +* keyStore password (optional) + +```properties +key_store_pwd= +``` + + +* trustStore location path (optional) + +```properties +trust_store_path= +``` + +* trustStore password (optional) + +```properties +trust_store_pwd= +``` + + +* SSL timeout period, in seconds + +```properties +idle_timeout=5000 +``` diff --git a/src/UserGuide/latest/API/RestServiceV2.md b/src/UserGuide/latest/API/RestServiceV2_apache.md similarity index 100% rename from src/UserGuide/latest/API/RestServiceV2.md rename to src/UserGuide/latest/API/RestServiceV2_apache.md diff --git a/src/UserGuide/latest/API/RestServiceV2_timecho.md b/src/UserGuide/latest/API/RestServiceV2_timecho.md new file mode 100644 index 000000000..43173a3dc --- /dev/null +++ b/src/UserGuide/latest/API/RestServiceV2_timecho.md @@ -0,0 +1,964 @@ + + +# REST API V2 +IoTDB's RESTful services can be used for query, write, and management operations, using the OpenAPI standard to define interfaces and generate frameworks. + +## 1. Enable RESTful Services + +RESTful services are disabled by default. + + Find the `conf/iotdb-system.properties` file under the IoTDB installation directory and set `enable_rest_service` to `true` to enable the module. + + ```properties + enable_rest_service=true + ``` + +## 2. Authentication +Except the liveness probe API `/ping`, RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`. + +The username used in the following examples is: `root`, and password is: `TimechoDB@2021` //Before V2.0.6.x the default password is root. + +And the authorization header is + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- If a user authorized with incorrect username or password, the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- If the `Authorization` header is missing,the following error is returned: + + HTTP Status Code:`401` + + HTTP response body: + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. Interface + +### 3.1 ping + +The `/ping` API can be used for service liveness probing. + +Request method: `GET` + +Request path: `http://ip:port/ping` + +The user name used in the example is: root, password: root + +Example request: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +Response status codes: + +- `200`: The service is alive. +- `503`: The service cannot accept any requests now. + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +|code | integer | status code | +| message | string | message | + +Sample response: + +- With HTTP status code `200`: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- With HTTP status code `503`: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` can be accessed without authorization. + +### 3.2 query + +The query interface can be used to handle data queries and metadata queries. + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/query` + +Parameter Description: + +| parameter name | parameter type | required | parameter description | +|----------------| -------------- | -------- | ------------------------------------------------------------ | +| sql | string | yes | | +| row_limit | integer | no | The maximum number of rows in the result set that can be returned by a query.
If this parameter is not set, the `rest_query_default_row_size_limit` of the configuration file will be used as the default value.
When the number of rows in the returned result set exceeds the limit, the status code `411` will be returned. | + +Response parameters: + +| parameter name | parameter type | parameter description | +|----------------| -------------- | ------------------------------------------------------------ | +| expressions | array | Array of result set column names for data query, `null` for metadata query | +| column_names | array | Array of column names for metadata query result set, `null` for data query | +| timestamps | array | Timestamp column, `null` for metadata query | +| values | array | A two-dimensional array, the first dimension has the same length as the result set column name array, and the second dimension array represents a column of the result set | + +**Examples:** + +Tip: Statements like `select * from root.xx.**` are not recommended because those statements may cause OOM. + +**Expression query** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v2/query +```` + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +**Show child paths** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +**Show child nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +**Show all ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +**Show ttl** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +**Show functions** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +**Show timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Show latest timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +**Count timeseries** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Count nodes** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +**Show devices** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**Show devices with database** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +**List user** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +**Aggregation** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +**Group by level** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +**Group by** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +**Last** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +**Disable align** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +**Align by device** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +**Select into** + +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/nonQuery` + +Parameter Description: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| sql | string | query content | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v2/nonQuery +``` + +Response parameters: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/insertTablet` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:---------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements | array | yes | The name of the measuring point | +| data_types | array | yes | The data type | +| values | array | yes | Value columns, the values in each column can be `null` | +| is_aligned | boolean | yes | Whether to align the timeseries | +| device | string | yes | Device name | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"data_types":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"is_aligned":false,"device":"root.sg27"}' http://127.0.0.1:18080/rest/v2/insertTablet +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +### 3.5 insertRecords + +Request method: `POST` + +Request header: `application/json` + +Request path: `http://ip:port/rest/v2/insertRecords` + +Parameter Description: + +| parameter name |parameter type |is required|parameter describe| +|:------------------| :--- | :---| :---| +| timestamps | array | yes | Time column | +| measurements_list | array | yes | The name of the measuring point | +| data_types_list | array | yes | The data type | +| values_list | array | yes | Value columns, the values in each column can be `null` | +| devices | string | yes | Device name | +| is_aligned | boolean | yes | Whether to align the timeseries | + +Example request: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232113960,1635232151960,1635232143960,1635232143960],"measurements_list":[["s33","s44"],["s55","s66"],["s77","s88"],["s771","s881"]],"data_types_list":[["INT32","INT64"],["FLOAT","DOUBLE"],["FLOAT","DOUBLE"],["BOOLEAN","TEXT"]],"values_list":[[1,11],[2.1,2],[4,6],[false,"cccccc"]],"is_aligned":false,"devices":["root.s1","root.s1","root.s1","root.s3"]}' http://127.0.0.1:18080/rest/v2/insertRecords +``` + +Sample response: + +|parameter name |parameter type |parameter describe| +|:--- | :--- | :---| +| code | integer | status code | +| message | string | message | + +Sample response: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. Configuration + +The configuration is located in 'iotdb-system.properties'. + +* Set 'enable_rest_service' to 'true' to enable the module, and 'false' to disable the module. By default, this value is' false '. + +```properties +enable_rest_service=true +``` + +* This parameter is valid only when 'enable_REST_service =true'. Set 'rest_service_port' to a number (1025 to 65535) to customize the REST service socket port. By default, the value is 18080. + +```properties +rest_service_port=18080 +``` + +* Set 'enable_swagger' to 'true' to display rest service interface information through swagger, and 'false' to do not display the rest service interface information through the swagger. By default, this value is' false '. + +```properties +enable_swagger=false +``` + +* The maximum number of rows in the result set that can be returned by a query. When the number of rows in the returned result set exceeds the limit, the status code `411` is returned. + +````properties +rest_query_default_row_size_limit=10000 +```` + +* Expiration time for caching customer login information (used to speed up user authentication, in seconds, 8 hours by default) + +```properties +cache_expire=28800 +``` + + +* Maximum number of users stored in the cache (default: 100) + +```properties +cache_max_num=100 +``` + +* Initial cache size (default: 10) + +```properties +cache_init_num=10 +``` + +* REST Service whether to enable SSL configuration, set 'enable_https' to' true 'to enable the module, and set' false 'to disable the module. By default, this value is' false '. + +```properties +enable_https=false +``` + +* keyStore location path (optional) + +```properties +key_store_path= +``` + + +* keyStore password (optional) + +```properties +key_store_pwd= +``` + + +* trustStore location path (optional) + +```properties +trust_store_path= +``` + +* trustStore password (optional) + +```properties +trust_store_pwd= +``` + + +* SSL timeout period, in seconds + +```properties +idle_timeout=5000 +``` diff --git a/src/UserGuide/latest/Background-knowledge/Data-Type.md b/src/UserGuide/latest/Background-knowledge/Data-Type.md index 2fbb63040..ebd76e579 100644 --- a/src/UserGuide/latest/Background-knowledge/Data-Type.md +++ b/src/UserGuide/latest/Background-knowledge/Data-Type.md @@ -40,7 +40,7 @@ The difference between STRING and TEXT types is that STRING type has more statis ### 1.1 Float Precision -The time series of **FLOAT** and **DOUBLE** type can specify (MAX\_POINT\_NUMBER, see [this page](../SQL-Manual/SQL-Manual.md) for more information on how to specify), which is the number of digits after the decimal point of the floating point number, if the encoding method is [RLE](../Technical-Insider/Encoding-and-Compression.md) or [TS\_2DIFF](../Technical-Insider/Encoding-and-Compression.md). If MAX\_POINT\_NUMBER is not specified, the system will use [float\_precision](../Reference/DataNode-Config-Manual.md) in the configuration file `iotdb-system.properties`. +The time series of **FLOAT** and **DOUBLE** type can specify (MAX\_POINT\_NUMBER, see [this page](../SQL-Manual/SQL-Manual_timecho) for more information on how to specify), which is the number of digits after the decimal point of the floating point number, if the encoding method is [RLE](../Technical-Insider/Encoding-and-Compression.md) or [TS\_2DIFF](../Technical-Insider/Encoding-and-Compression.md). If MAX\_POINT\_NUMBER is not specified, the system will use [float\_precision](../Reference/DataNode-Config-Manual.md) in the configuration file `iotdb-system.properties`. ```sql CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=FLOAT, ENCODING=RLE, 'MAX_POINT_NUMBER'='2'; diff --git a/src/UserGuide/latest/Basic-Concept/Delete-Data.md b/src/UserGuide/latest/Basic-Concept/Delete-Data.md index 2fa82332c..8c4d883c4 100644 --- a/src/UserGuide/latest/Basic-Concept/Delete-Data.md +++ b/src/UserGuide/latest/Basic-Concept/Delete-Data.md @@ -20,9 +20,9 @@ --> # Delete Data -Users can delete data that meet the deletion condition in the specified timeseries by using the [DELETE statement](../SQL-Manual/SQL-Manual.md#delete-data). When deleting data, users can select one or more timeseries paths, prefix paths, or paths with star to delete data within a certain time interval. +Users can delete data that meet the deletion condition in the specified timeseries by using the DELETE statement. When deleting data, users can select one or more timeseries paths, prefix paths, or paths with star to delete data within a certain time interval. -In a JAVA programming environment, you can use the [Java JDBC](../API/Programming-JDBC.md) to execute single or batch UPDATE statements. +In a JAVA programming environment, you can use the Java JDBC to execute single or batch UPDATE statements. ## 1. Delete Single Timeseries diff --git a/src/UserGuide/latest/Basic-Concept/Operate-Metadata_apache.md b/src/UserGuide/latest/Basic-Concept/Operate-Metadata_apache.md index 7d590ad24..d4c6e51dd 100644 --- a/src/UserGuide/latest/Basic-Concept/Operate-Metadata_apache.md +++ b/src/UserGuide/latest/Basic-Concept/Operate-Metadata_apache.md @@ -57,7 +57,7 @@ Besides, if deploy on Windows system, the LayerName is case-insensitive, which m ### 1.2 Show Databases -After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual.md) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual.md) to view the databases. The SQL statements are as follows: +After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual_apache) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual_apache) to view the databases. The SQL statements are as follows: ``` IoTDB> SHOW DATABASES diff --git a/src/UserGuide/latest/Basic-Concept/Operate-Metadata_timecho.md b/src/UserGuide/latest/Basic-Concept/Operate-Metadata_timecho.md index 94598c1c0..8d8740b97 100644 --- a/src/UserGuide/latest/Basic-Concept/Operate-Metadata_timecho.md +++ b/src/UserGuide/latest/Basic-Concept/Operate-Metadata_timecho.md @@ -57,7 +57,7 @@ Besides, if deploy on Windows system, the LayerName is case-insensitive, which m ### 1.2 Show Databases -After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual.md) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual.md) to view the databases. The SQL statements are as follows: +After creating the database, we can use the [SHOW DATABASES](../SQL-Manual/SQL-Manual_timecho) statement and [SHOW DATABASES \](../SQL-Manual/SQL-Manual_timecho) to view the databases. The SQL statements are as follows: ``` IoTDB> SHOW DATABASES diff --git a/src/UserGuide/latest/Basic-Concept/Query-Data.md b/src/UserGuide/latest/Basic-Concept/Query-Data_apache.md similarity index 99% rename from src/UserGuide/latest/Basic-Concept/Query-Data.md rename to src/UserGuide/latest/Basic-Concept/Query-Data_apache.md index ce50bb6f3..7a0b65600 100644 --- a/src/UserGuide/latest/Basic-Concept/Query-Data.md +++ b/src/UserGuide/latest/Basic-Concept/Query-Data_apache.md @@ -277,7 +277,7 @@ Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C+ - Execute the query statement in the SQL command line terminal: start the SQL command line terminal, and directly enter the query statement to execute, see [SQL command line terminal](../Tools-System/CLI.md). -- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC.md) for details. +- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC_apache) for details. - Execute query statements in native APIs such as JAVA / C++ / Python / Go. For details, please refer to the relevant documentation in the Application Programming Interface chapter. The interface prototype is as follows: @@ -285,7 +285,7 @@ Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C+ SessionDataSet executeQueryStatement(String sql) ```` -- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1.md) or [HTTP API V2](../API/RestServiceV2.md) for details. +- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1_apache) or [HTTP API V2](../API/RestServiceV2_apache) for details. #### Efficient execution interfaces @@ -3016,7 +3016,7 @@ The user must have the following permissions to execute a query write-back state * All `WRITE_SCHEMA` permissions for the source series in the `select` clause. * All `WRITE_DATA` permissions for the target series in the `into` clause. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_apache). ### 10.4 Configurable Properties diff --git a/src/UserGuide/latest/Basic-Concept/Query-Data_timecho.md b/src/UserGuide/latest/Basic-Concept/Query-Data_timecho.md new file mode 100644 index 000000000..6e4b8135c --- /dev/null +++ b/src/UserGuide/latest/Basic-Concept/Query-Data_timecho.md @@ -0,0 +1,3023 @@ + +# Query Data +## 1. OVERVIEW + +### 1.1 Syntax Definition + +In IoTDB, `SELECT` statement is used to retrieve data from one or more selected time series. Here is the syntax definition of `SELECT` statement: + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... ) | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires that the status and temperature sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.018s +``` + +#### Select Multiple Columns of Data for the Same Device According to Multiple Time Intervals + +IoTDB supports specifying multiple time interval conditions in a query. Users can combine time interval conditions at will according to their needs. For example, the SQL statement is: + +```sql +select status,temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature"; the statement specifies two different time intervals, namely "2017-11-01T00:05:00.000 to 2017-11-01T00:12:00.000" and "2017-11-01T16:35:00.000 to 2017-11-01T16:37:00.000". The SQL statement requires that the values of selected timeseries satisfying any time interval be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| +|2017-11-01T16:35:00.000+08:00| true| 23.44| +|2017-11-01T16:36:00.000+08:00| false| 21.98| +|2017-11-01T16:37:00.000+08:00| false| 21.93| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 9 +It costs 0.018s +``` + + +#### Choose Multiple Columns of Data for Different Devices According to Multiple Time Intervals + +The system supports the selection of data in any column in a query, i.e., the selected columns can come from different devices. For example, the SQL statement is: + +```sql +select wf01.wt01.status,wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +which means: + +The selected timeseries are "the power supply status of ln group wf01 plant wt01 device" and "the hardware version of ln group wf02 plant wt02 device"; the statement specifies two different time intervals, namely "2017-11-01T00:05:00.000 to 2017-11-01T00:12:00.000" and "2017-11-01T16:35:00.000 to 2017-11-01T16:37:00.000". The SQL statement requires that the values of selected timeseries satisfying any time interval be selected. + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+------------------------+--------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf02.wt02.hardware| ++-----------------------------+------------------------+--------------------------+ +|2017-11-01T00:06:00.000+08:00| false| v1| +|2017-11-01T00:07:00.000+08:00| false| v1| +|2017-11-01T00:08:00.000+08:00| false| v1| +|2017-11-01T00:09:00.000+08:00| false| v1| +|2017-11-01T00:10:00.000+08:00| true| v2| +|2017-11-01T00:11:00.000+08:00| false| v1| +|2017-11-01T16:35:00.000+08:00| true| v2| +|2017-11-01T16:36:00.000+08:00| false| v1| +|2017-11-01T16:37:00.000+08:00| false| v1| ++-----------------------------+------------------------+--------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### Order By Time Query + +IoTDB supports the 'order by time' statement since 0.11, it's used to display results in descending order by time. +For example, the SQL statement is: + +```sql +select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +The execution result of this SQL statement is as follows: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-07T23:59:00.000+08:00| v1| false| 21.07| false| +|2017-11-07T23:58:00.000+08:00| v1| false| 22.93| false| +|2017-11-07T23:57:00.000+08:00| v2| true| 24.39| true| +|2017-11-07T23:56:00.000+08:00| v2| true| 24.44| true| +|2017-11-07T23:55:00.000+08:00| v2| true| 25.9| true| +|2017-11-07T23:54:00.000+08:00| v1| false| 22.52| false| +|2017-11-07T23:53:00.000+08:00| v2| true| 24.58| true| +|2017-11-07T23:52:00.000+08:00| v1| false| 20.18| false| +|2017-11-07T23:51:00.000+08:00| v1| false| 22.24| false| +|2017-11-07T23:50:00.000+08:00| v2| true| 23.7| true| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.016s +``` + +### 1.4 Execution Interface + +In IoTDB, there are two ways to execute data query: + +- Execute queries using IoTDB-SQL. +- Efficient execution interfaces for common queries, including time-series raw data query, last query, and aggregation query. + +#### Execute queries using IoTDB-SQL + +Data query statements can be used in SQL command-line terminals, JDBC, JAVA / C++ / Python / Go and other native APIs, and RESTful APIs. + +- Execute the query statement in the SQL command line terminal: start the SQL command line terminal, and directly enter the query statement to execute, see [SQL command line terminal](../Tools-System/CLI.md). + +- Execute query statements in JDBC, see [JDBC](../API/Programming-JDBC_timecho) for details. + +- Execute query statements in native APIs such as JAVA / C++ / Python / Go. For details, please refer to the relevant documentation in the Application Programming Interface chapter. The interface prototype is as follows: + + ````java + SessionDataSet executeQueryStatement(String sql) + ```` + +- Used in RESTful API, see [HTTP API V1](../API/RestServiceV1_timecho) or [HTTP API V2](../API/RestServiceV2_timecho) for details. + +#### Efficient execution interfaces + +The native APIs provide efficient execution interfaces for commonly used queries, which can save time-consuming operations such as SQL parsing. include: + +* Time-series raw data query with time range: + - The specified query time range is a left-closed right-open interval, including the start time but excluding the end time. + +```java +SessionDataSet executeRawDataQuery(List paths, long startTime, long endTime); +``` + +* Last query: + - Query the last data, whose timestamp is greater than or equal LastTime. + +```java +SessionDataSet executeLastDataQuery(List paths, long LastTime); +``` + +* Aggregation query: + - Support specified query time range: The specified query time range is a left-closed right-open interval, including the start time but not the end time. + - Support GROUP BY TIME. + +```java +SessionDataSet executeAggregationQuery(List paths, List aggregations); + +SessionDataSet executeAggregationQuery( + List paths, List aggregations, long startTime, long endTime); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval, + long slidingStep); +``` + +## 2. `SELECT` CLAUSE +The `SELECT` clause specifies the output of the query, consisting of several `selectExpr`. Each `selectExpr` defines one or more columns in the query result. For select expression details, see document [Operator-and-Expression](../SQL-Manual/Operator-and-Expression.md). + +- Example 1: + +```sql +select temperature from root.ln.wf01.wt01 +``` + +- Example 2: + +```sql +select status, temperature from root.ln.wf01.wt01 +``` + +### 2.1 Last Query + +The last query is a special type of query in Apache IoTDB. It returns the data point with the largest timestamp of the specified time series. In other word, it returns the latest state of a time series. This feature is especially important in IoT data analysis scenarios. To meet the performance requirement of real-time device monitoring systems, Apache IoTDB caches the latest values of all time series to achieve microsecond read latency. + +The last query is to return the most recent data point of the given timeseries in a three column format. + +The SQL syntax is defined as: + +```sql +select last [COMMA ]* from < PrefixPath > [COMMA < PrefixPath >]* [ORDER BY TIMESERIES (DESC | ASC)?] +``` + +which means: Query and return the last data points of timeseries prefixPath.path. + +- Only time filter is supported in \. Any other filters given in the \ will give an exception. When the cached most recent data point does not satisfy the criterion specified by the filter, IoTDB will have to get the result from the external storage, which may cause a decrease in performance. + +- The result will be returned in a four column table format. + + ``` + | Time | timeseries | value | dataType | + ``` + + **Note:** The `value` colum will always return the value as `string` and thus also has `TSDataType.TEXT`. Therefore, the column `dataType` is returned also which contains the _real_ type how the value should be interpreted. + +- We can use `TIME/TIMESERIES/VALUE/DATATYPE (DESC | ASC)` to specify that the result set is sorted in descending/ascending order based on a particular column. When the value column contains multiple types of data, the sorting is based on the string representation of the values. + +**Example 1:** get the last point of root.ln.wf01.wt01.status: + +``` +IoTDB> select last status from root.ln.wf01.wt01 ++-----------------------------+------------------------+-----+--------+ +| Time| timeseries|value|dataType| ++-----------------------------+------------------------+-----+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.status|false| BOOLEAN| ++-----------------------------+------------------------+-----+--------+ +Total line number = 1 +It costs 0.000s +``` + +**Example 2:** get the last status and temperature points of root.ln.wf01.wt01, whose timestamp larger or equal to 2017-11-07T23:50:00。 + +``` +IoTDB> select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 3:** get the last points of all sensor in root.ln.wf01.wt01, and order the result by the timeseries column in descending order + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by timeseries desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 4:** get the last points of all sensor in root.ln.wf01.wt01, and order the result by the dataType column in descending order + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by dataType desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**Note:** The requirement to query the latest data point with other filtering conditions can be implemented through function composition. For example: + +``` +IoTDB> select max_time(*), last_value(*) from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 and status = false align by device ++-----------------+---------------------+----------------+-----------------------+------------------+ +| Device|max_time(temperature)|max_time(status)|last_value(temperature)|last_value(status)| ++-----------------+---------------------+----------------+-----------------------+------------------+ +|root.ln.wf01.wt01| 1510077540000| 1510077540000| 21.067368| false| ++-----------------+---------------------+----------------+-----------------------+------------------+ +Total line number = 1 +It costs 0.021s +``` + + +## 3. `WHERE` CLAUSE + +In IoTDB query statements, two filter conditions, **time filter** and **value filter**, are supported. + +The supported operators are as follows: + +- Comparison operators: greater than (`>`), greater than or equal ( `>=`), equal ( `=` or `==`), not equal ( `!=` or `<>`), less than or equal ( `<=`), less than ( `<`). +- Logical operators: and ( `AND` or `&` or `&&`), or ( `OR` or `|` or `||`), not ( `NOT` or `!`). +- Range contains operator: contains ( `IN` ). +- String matches operator: `LIKE`, `REGEXP`. + +### 3.1 Time Filter + +Use time filters to filter data for a specific time range. For supported formats of timestamps, please refer to [Timestamp](../Background-knowledge/Data-Type.md) . + +An example is as follows: + +1. Select data with timestamp greater than 2022-01-01T00:05:00.000: + + ```sql + select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; + ```` + +2. Select data with timestamp equal to 2022-01-01T00:05:00.000: + + ```sql + select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; + ```` + +3. Select the data in the time interval [2017-11-01T00:05:00.000, 2017-11-01T00:12:00.000): + + ```sql + select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; + ```` + +Note: In the above example, `time` can also be written as `timestamp`. + +### 3.2 Value Filter + +Use value filters to filter data whose data values meet certain criteria. **Allow** to use a time series not selected in the select clause as a value filter. + +An example is as follows: + +1. Select data with a value greater than 36.5: + + ```sql + select temperature from root.sg1.d1 where temperature > 36.5; + ```` + +2. Select data with value equal to true: + + ```sql + select status from root.sg1.d1 where status = true; + ```` + +3. Select data for the interval [36.5,40] or not: + + ```sql + select temperature from root.sg1.d1 where temperature between 36.5 and 40; + ```` + + ```sql + select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + ```` + +4. Select data with values within a specific range: + + ```sql + select code from root.sg1.d1 where code in ('200', '300', '400', '500'); + ```` + +5. Select data with values outside a certain range: + + ```sql + select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); + ```` + +6. Select data with values is null: + + ```sql + select code from root.sg1.d1 where temperature is null; + ```` + +7. Select data with values is not null: + + ```sql + select code from root.sg1.d1 where temperature is not null; + ```` + +### 3.3 Fuzzy Query + +Fuzzy query is divided into Like statement and Regexp statement, both of which can support fuzzy matching of TEXT type data. + +Like statement: + +#### Fuzzy matching using `Like` + +In the value filter condition, for TEXT type data, use `Like` and `Regexp` operators to perform fuzzy matching on data. + +**Matching rules:** + +- The percentage (`%`) wildcard matches any string of zero or more characters. +- The underscore (`_`) wildcard matches any single character. + +**Example 1:** Query data containing `'cc'` in `value` under `root.sg.d1`. + +``` +IoTDB> select * from root.sg.d1 where value like '%cc%' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 2:** Query data that consists of 3 characters and the second character is `'b'` in `value` under `root.sg.d1`. + +``` +IoTDB> select * from root.sg.device where value like '_b_' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:02.000+08:00| abc| ++-----------------------------+----------------+ +Total line number = 1 +It costs 0.002s +``` + +#### Fuzzy matching using `Regexp` + +The filter conditions that need to be passed in are regular expressions in the Java standard library style. + +**Examples of common regular matching:** + +``` +All characters with a length of 3-20: ^.{3,20}$ +Uppercase english characters: ^[A-Z]+$ +Numbers and English characters: ^[A-Za-z0-9]+$ +Beginning with a: ^a.* +``` + +**Example 1:** Query a string composed of 26 English characters for the value under root.sg.d1 + +``` +IoTDB> select * from root.sg.d1 where value regexp '^[A-Za-z]+$' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**Example 2:** Query root.sg.d1 where the value value is a string composed of 26 lowercase English characters and the time is greater than 100 + +``` +IoTDB> select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +## 4. `GROUP BY` CLAUSE + +IoTDB supports using `GROUP BY` clause to aggregate the time series by segment and group. + +Segmented aggregation refers to segmenting data in the row direction according to the time dimension, aiming at the time relationship between different data points in the same time series, and obtaining an aggregated value for each segment. Currently only **group by time**、**group by variation**、**group by condition**、**group by session** and **group by count** is supported, and more segmentation methods will be supported in the future. + +Group aggregation refers to grouping the potential business attributes of time series for different time series. Each group contains several time series, and each group gets an aggregated value. Support **group by path level** and **group by tag** two grouping methods. + +### 4.1 Aggregate By Segment + +#### Aggregate By Time + +Aggregate by time is a typical query method for time series data. Data is collected at high frequency and needs to be aggregated and calculated at certain time intervals. For example, to calculate the daily average temperature, the sequence of temperature needs to be segmented by day, and then calculated. average value. + +Aggregate by time refers to a query method that uses a lower frequency than the time frequency of data collection, and is a special case of segmented aggregation. For example, the frequency of data collection is one second. If you want to display the data in one minute, you need to use time aggregagtion. + +This section mainly introduces the related examples of time aggregation, using the `GROUP BY` clause. IoTDB supports partitioning result sets according to time interval and customized sliding step. And by default results are sorted by time in ascending order. + +The GROUP BY statement provides users with three types of specified parameters: + +* Parameter 1: The display window on the time axis +* Parameter 2: Time interval for dividing the time axis(should be positive) +* Parameter 3: Time sliding step (optional and defaults to equal the time interval if not set) + +The actual meanings of the three types of parameters are shown in Figure below. +Among them, the parameter 3 is optional. + +
+
+ + +There are three typical examples of frequency reduction aggregation: + +##### Aggregate By Time without Specifying the Sliding Step Length + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` + +which means: + +Since the sliding step length is not specified, the `GROUP BY` statement by default set the sliding step the same as the time interval which is `1d`. + +The fist parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2017-11-07T23:00:00). + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1d) as time interval and startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [0,1d), [1d, 2d), [2d, 3d), etc. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-11-01T00:00:00, 2017-11-07 T23:00:00]), and map these data to the previously segmented time axis (in this case there are mapped data in every 1-day period from 2017-11-01T00:00:00 to 2017-11-07T23:00:00:00). + +Since there is data for each time period in the result range to be displayed, the execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 1440| 26.0| +|2017-11-02T00:00:00.000+08:00| 1440| 26.0| +|2017-11-03T00:00:00.000+08:00| 1440| 25.99| +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.024s +``` + +##### Aggregate By Time Specifying the Sliding Step Length + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +which means: + +Since the user specifies the sliding step parameter as 1d, the `GROUP BY` statement will move the time interval `1 day` long instead of `3 hours` as default. + +That means we want to fetch all the data of 00:00:00 to 02:59:59 every day from 2017-11-01 to 2017-11-07. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2017-11-07T23:00:00). + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (3h) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-11-01T00:00:00, 2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00), [2017-11-03T00:00:00, 2017-11-03T03:00:00), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-11-01T00:00:00, 2017-11-07T23:00:00]), and map these data to the previously segmented time axis (in this case there are mapped data in every 3-hour period for each day from 2017-11-01T00:00:00 to 2017-11-07T23:00:00:00). + +Since there is data for each time period in the result range to be displayed, the execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-02T00:00:00.000+08:00| 180| 25.98| +|2017-11-03T00:00:00.000+08:00| 180| 25.96| +|2017-11-04T00:00:00.000+08:00| 180| 25.96| +|2017-11-05T00:00:00.000+08:00| 180| 26.0| +|2017-11-06T00:00:00.000+08:00| 180| 25.85| +|2017-11-07T00:00:00.000+08:00| 180| 25.99| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.006s +``` + +The sliding step can be smaller than the interval, in which case there is overlapping time between the aggregation windows (similar to a sliding window). + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-01 10:00:00), 4h, 2h); +``` + +The execution result of the SQL statement is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-01T02:00:00.000+08:00| 180| 25.98| +|2017-11-01T04:00:00.000+08:00| 180| 25.96| +|2017-11-01T06:00:00.000+08:00| 180| 25.96| +|2017-11-01T08:00:00.000+08:00| 180| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 5 +It costs 0.006s +``` + +##### Aggregate by Natural Month + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +which means: + +Since the user specifies the sliding step parameter as `2mo`, the `GROUP BY` statement will move the time interval `2 months` long instead of `1 month` as default. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-11-01T00:00:00, 2019-11-07T23:00:00). + +The start time is 2017-11-01T00:00:00. The sliding step will increment monthly based on the start date, and the 1st day of the month will be used as the time interval's start time. + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1mo) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-11-01T00:00:00, 2017-12-01T00:00:00), [2018-02-01T00:00:00, 2018-03-01T00:00:00), [2018-05-03T00:00:00, 2018-06-01T00:00:00)), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of (2017-11-01T00:00:00, 2019-11-07T23:00:00], and map these data to the previously segmented time axis (in this case there are mapped data of the first month in every two month period from 2017-11-01T00:00:00 to 2019-11-07T23:00:00). + +The SQL execution result is: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-01T00:00:00.000+08:00| 259| +|2018-01-01T00:00:00.000+08:00| 250| +|2018-03-01T00:00:00.000+08:00| 259| +|2018-05-01T00:00:00.000+08:00| 251| +|2018-07-01T00:00:00.000+08:00| 242| +|2018-09-01T00:00:00.000+08:00| 225| +|2018-11-01T00:00:00.000+08:00| 216| +|2019-01-01T00:00:00.000+08:00| 207| +|2019-03-01T00:00:00.000+08:00| 216| +|2019-05-01T00:00:00.000+08:00| 207| +|2019-07-01T00:00:00.000+08:00| 199| +|2019-09-01T00:00:00.000+08:00| 181| +|2019-11-01T00:00:00.000+08:00| 60| ++-----------------------------+-------------------------------+ +``` + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +which means: + +Since the user specifies the sliding step parameter as `2mo`, the `GROUP BY` statement will move the time interval `2 months` long instead of `1 month` as default. + +The first parameter of the `GROUP BY` statement above is the display window parameter, which determines the final display range is [2017-10-31T00:00:00, 2019-11-07T23:00:00). + +Different from the previous example, the start time is set to 2017-10-31T00:00:00. The sliding step will increment monthly based on the start date, and the 31st day of the month meaning the last day of the month will be used as the time interval's start time. If the start time is set to the 30th date, the sliding step will use the 30th or the last day of the month. + +The start time is 2017-10-31T00:00:00. The sliding step will increment monthly based on the start time, and the 1st day of the month will be used as the time interval's start time. + +The second parameter of the `GROUP BY` statement above is the time interval for dividing the time axis. Taking this parameter (1mo) as time interval and the startTime of the display window as the dividing origin, the time axis is divided into several continuous intervals, which are [2017-10-31T00:00:00, 2017-11-31T00:00:00), [2018-02-31T00:00:00, 2018-03-31T00:00:00), [2018-05-31T00:00:00, 2018-06-31T00:00:00), etc. + +The third parameter of the `GROUP BY` statement above is the sliding step for each time interval moving. + +Then the system will use the time and value filtering condition in the `WHERE` clause and the first parameter of the `GROUP BY` statement as the data filtering condition to obtain the data satisfying the filtering condition (which in this case is the data in the range of [2017-10-31T00:00:00, 2019-11-07T23:00:00) and map these data to the previously segmented time axis (in this case there are mapped data of the first month in every two month period from 2017-10-31T00:00:00 to 2019-11-07T23:00:00). + +The SQL execution result is: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-10-31T00:00:00.000+08:00| 251| +|2017-12-31T00:00:00.000+08:00| 250| +|2018-02-28T00:00:00.000+08:00| 259| +|2018-04-30T00:00:00.000+08:00| 250| +|2018-06-30T00:00:00.000+08:00| 242| +|2018-08-31T00:00:00.000+08:00| 225| +|2018-10-31T00:00:00.000+08:00| 216| +|2018-12-31T00:00:00.000+08:00| 208| +|2019-02-28T00:00:00.000+08:00| 216| +|2019-04-30T00:00:00.000+08:00| 208| +|2019-06-30T00:00:00.000+08:00| 199| +|2019-08-31T00:00:00.000+08:00| 181| +|2019-10-31T00:00:00.000+08:00| 69| ++-----------------------------+-------------------------------+ +``` + +##### Left Open And Right Close Range + +The SQL statement is: + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +In this sql, the time interval is left open and right close, so we won't include the value of timestamp 2017-11-01T00:00:00 and instead we will include the value of timestamp 2017-11-07T23:00:00. + +We will get the result like following: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### Aggregation By Variation + +IoTDB supports grouping by continuous stable values through the `GROUP BY VARIATION` statement. + +Group-By-Variation wil set the first point in group as the base point, +then if the difference between the new data and base point is small than or equal to delta, +the data point will be grouped together and execute aggregation query (The calculation of difference and the meaning of delte are introduced below). The groups won't overlap and there is no fixed start time and end time. +The syntax of clause is as follows: + +```sql +group by variation(controlExpression[,delta][,ignoreNull=true/false]) +``` + +The different parameters mean: + +* controlExpression + +The value that is used to calculate difference. It can be any columns or the expression of them. + +* delta + +The threshold that is used when grouping. The difference of controlExpression between the first data point and new data point should less than or equal to delta. +When delta is zero, all the continuous data with equal expression value will be grouped into the same group. + +* ignoreNull + +Used to specify how to deal with the data when the value of controlExpression is null. When ignoreNull is false, null will be treated as a new value and when ignoreNull is true, the data point will be directly skipped. + +The supported return types of controlExpression and how to deal with null value when ignoreNull is false are shown in the following table: + +| delta | Return Type Supported By controlExpression | The Handling of null when ignoreNull is False | +| -------- | ------------------------------------------ | ------------------------------------------------------------ | +| delta!=0 | INT32、INT64、FLOAT、DOUBLE | If the processing group doesn't contains null, null value should be treated as infinity/infinitesimal and will end current group.
Continuous null values are treated as stable values and assigned to the same group. | +| delta=0 | TEXT、BINARY、INT32、INT64、FLOAT、DOUBLE | Null is treated as a new value in a new group and continuous nulls belong to the same group. | + +groupByVariation + +##### Precautions for Use + +1. The result of controlExpression should be a unique value. If multiple columns appear after using wildcard stitching, an error will be reported. +2. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +3. Each device is grouped separately when used with `ALIGN BY DEVICE`. +4. Delta is zero and ignoreNull is true by default. +5. Currently `GROUP BY VARIATION` is not supported with `GROUP BY LEVEL`. + +Using the raw data below, several examples of `GROUP BY VARIAITON` queries will be given. + +``` ++-----------------------------+-------+-------+-------+--------+-------+-------+ +| Time| s1| s2| s3| s4| s5| s6| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +|1970-01-01T08:00:00.000+08:00| 4.5| 9.0| 0.0| 45.0| 9.0| 8.25| +|1970-01-01T08:00:00.010+08:00| null| 19.0| 10.0| 145.0| 19.0| 8.25| +|1970-01-01T08:00:00.020+08:00| 24.5| 29.0| null| 245.0| 29.0| null| +|1970-01-01T08:00:00.030+08:00| 34.5| null| 30.0| 345.0| null| null| +|1970-01-01T08:00:00.040+08:00| 44.5| 49.0| 40.0| 445.0| 49.0| 8.25| +|1970-01-01T08:00:00.050+08:00| null| 59.0| 50.0| 545.0| 59.0| 6.25| +|1970-01-01T08:00:00.060+08:00| 64.5| 69.0| 60.0| 645.0| 69.0| null| +|1970-01-01T08:00:00.070+08:00| 74.5| 79.0| null| null| 79.0| 3.25| +|1970-01-01T08:00:00.080+08:00| 84.5| 89.0| 80.0| 845.0| 89.0| 3.25| +|1970-01-01T08:00:00.090+08:00| 94.5| 99.0| 90.0| 945.0| 99.0| 3.25| +|1970-01-01T08:00:00.150+08:00| 66.5| 77.0| 90.0| 945.0| 99.0| 9.25| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +``` + +##### delta = 0 + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +``` + +Get the result below which ignores the row with null value in `s6`. + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.040+08:00| 24.5| 3| 50.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +when ignoreNull is false, the row with null value in `s6` will be considered. + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +``` + +Get the following result. + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.020+08:00|1970-01-01T08:00:00.030+08:00| 29.5| 1| 30.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.040+08:00| 44.5| 1| 40.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.060+08:00|1970-01-01T08:00:00.060+08:00| 64.5| 1| 60.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +##### delta !=0 + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.050+08:00| 24.5| 4| 100.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +The sql is shown below: + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.050+08:00| 44.5| 2| 90.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.080+08:00| 79.5| 2| 80.0| +|1970-01-01T08:00:00.090+08:00|1970-01-01T08:00:00.150+08:00| 80.5| 2| 180.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` + +#### Aggregation By Condition + +When you need to filter the data according to a specific condition and group the continuous ones for an aggregation query. +`GROUP BY CONDITION` is suitable for you.The rows which don't meet the given condition will be simply ignored because they don't belong to any group. +Its syntax is defined below: + +```sql +group by condition(predict,[keep>/>=/=/<=/<]threshold,[,ignoreNull=true/false]) +``` + +* predict + +Any legal expression return the type of boolean for filtering in grouping. + +* [keep>/>=/=/<=/<]threshold + +Keep expression is used to specify the number of continuous rows that meet the `predict` condition to form a group. Only the number of rows in group satisfy the keep condition, the result of group will be output. +Keep expression consists of a 'keep' string and a threshold of type `long` or a single 'long' type data. + +* ignoreNull=true/false + +Used to specify how to handle data rows that encounter null predict, skip the row when it's true and end current group when it's false. + +##### Precautions for Use + +1. keep condition is required in the query, but you can omit the 'keep' string and given a `long` number which defaults to 'keep=long number' condition. +2. IgnoreNull defaults to true. +3. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +4. Each device is grouped separately when used with `ALIGN BY DEVICE`. +5. Currently `GROUP BY CONDITION` is not supported with `GROUP BY LEVEL`. + +For the following raw data, several query examples are given below: + +``` ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +| Time|root.sg.beijing.car01.soc|root.sg.beijing.car01.charging_status|root.sg.beijing.car01.vehicle_status| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| 1| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| 1| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +``` + +The sql statement to query data with at least two continuous row shown below: + +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=true) +``` + +Get the result below: + +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 10| 5| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` + +When ignoreNull is false, the null value will be treated as a row that doesn't meet the condition. + +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=false) +``` + +Get the result below, the original group is split. + +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 7| 3| 36.0| +|1970-01-01T08:00:00.009+08:00| 10| 2| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` + +#### Aggregation By Session + +`GROUP BY SESSION` can be used to group data according to the interval of the time. Data with a time interval less than or equal to the given threshold will be assigned to the same group. +For example, in industrial scenarios, devices don't always run continuously, `GROUP BY SESSION` will group the data generated by each access session of the device. +Its syntax is defined as follows: + +```sql +group by session(timeInterval) +``` + +* timeInterval + +A given interval threshold to create a new group of data when the difference between the time of data is greater than the threshold. + +The figure below is a grouping diagram under `GROUP BY SESSION`. + +groupBySession + +##### Precautions for Use + +1. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +2. Each device is grouped separately when used with `ALIGN BY DEVICE`. +3. Currently `GROUP BY SESSION` is not supported with `GROUP BY LEVEL`. + +For the raw data below, a few query examples are given: + +``` ++-----------------------------+-----------------+-----------+--------+------+ +| Time| Device|temperature|hardware|status| ++-----------------------------+-----------------+-----------+--------+------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01| 35.7| 11| false| +|1970-01-01T08:00:02.000+08:00|root.ln.wf02.wt01| 35.8| 22| true| +|1970-01-01T08:00:03.000+08:00|root.ln.wf02.wt01| 35.4| 33| false| +|1970-01-01T08:00:04.000+08:00|root.ln.wf02.wt01| 36.4| 44| false| +|1970-01-01T08:00:05.000+08:00|root.ln.wf02.wt01| 36.8| 55| false| +|1970-01-01T08:00:10.000+08:00|root.ln.wf02.wt01| 36.8| 110| false| +|1970-01-01T08:00:20.000+08:00|root.ln.wf02.wt01| 37.8| 220| true| +|1970-01-01T08:00:30.000+08:00|root.ln.wf02.wt01| 37.5| 330| false| +|1970-01-01T08:00:40.000+08:00|root.ln.wf02.wt01| 37.4| 440| false| +|1970-01-01T08:00:50.000+08:00|root.ln.wf02.wt01| 37.9| 550| false| +|1970-01-01T08:01:40.000+08:00|root.ln.wf02.wt01| 38.0| 110| false| +|1970-01-01T08:02:30.000+08:00|root.ln.wf02.wt01| 38.8| 220| true| +|1970-01-01T08:03:20.000+08:00|root.ln.wf02.wt01| 38.6| 330| false| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01| 38.4| 440| false| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01| 38.3| 550| false| +|1970-01-01T08:06:40.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:07:50.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:08:00.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01| 38.2| 110| false| +|1970-01-02T08:08:02.000+08:00|root.ln.wf02.wt01| 37.5| 220| true| +|1970-01-02T08:08:03.000+08:00|root.ln.wf02.wt01| 37.4| 330| false| +|1970-01-02T08:08:04.000+08:00|root.ln.wf02.wt01| 36.8| 440| false| +|1970-01-02T08:08:05.000+08:00|root.ln.wf02.wt01| 37.4| 550| false| ++-----------------------------+-----------------+-----------+--------+------+ +``` + +TimeInterval can be set by different time units, the sql is shown below: + +```sql +select __endTime,count(*) from root.** group by session(1d) +``` + +Get the result: + +``` ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time| __endTime|count(root.ln.wf02.wt01.temperature)|count(root.ln.wf02.wt01.hardware)|count(root.ln.wf02.wt01.status)| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|1970-01-01T08:00:01.000+08:00|1970-01-01T08:08:00.000+08:00| 15| 18| 15| +|1970-01-02T08:08:01.000+08:00|1970-01-02T08:08:05.000+08:00| 5| 5| 5| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` + +It can be also used with `HAVING` and `ALIGN BY DEVICE` clauses. + +```sql +select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` + +Get the result below: + +``` ++-----------------------------+-----------------+-----------------------------+-------------+ +| Time| Device| __endTime|sum(hardware)| ++-----------------------------+-----------------+-----------------------------+-------------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01|1970-01-01T08:03:20.000+08:00| 2475.0| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:04:20.000+08:00| 440.0| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:05:20.000+08:00| 550.0| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01|1970-01-02T08:08:05.000+08:00| 1650.0| ++-----------------------------+-----------------+-----------------------------+-------------+ +``` + +#### Aggregation By Count + +`GROUP BY COUNT`can aggregate the data points according to the number of points. It can group fixed number of continuous data points together for aggregation query. +Its syntax is defined as follows: + +```sql +group by count(controlExpression, size[,ignoreNull=true/false]) +``` + +* controlExpression + +The object to count during processing, it can be any column or an expression of columns. + +* size + +The number of data points in a group, a number of `size` continuous points will be divided to the same group. + +* ignoreNull=true/false + +Whether to ignore the data points with null in `controlExpression`, when ignoreNull is true, data points with the `controlExpression` of null will be skipped during counting. + +##### Precautions for Use + +1. For a group in resultSet, the time column output the start time of the group by default. __endTime can be used in select clause to output the endTime of groups in resultSet. +2. Each device is grouped separately when used with `ALIGN BY DEVICE`. +3. Currently `GROUP BY SESSION` is not supported with `GROUP BY LEVEL`. +4. When the final number of data points in a group is less than `size`, the result of the group will not be output. + +For the data below, some examples will be given. + +``` ++-----------------------------+-----------+-----------------------+ +| Time|root.sg.soc|root.sg.charging_status| ++-----------------------------+-----------+-----------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| ++-----------------------------+-----------+-----------------------+ +``` + +The sql is shown below + +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +``` + +Get the result below, in the second group from 1970-01-01T08:00:00.006+08:00 to 1970-01-01T08:00:00.010+08:00. There are only four points included which is less than `size`. So it won't be output. + +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` + +When `ignoreNull=false` is used to take null value into account. There will be two groups with 5 points in the resultSet, which is shown as follows: + +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` + +Get the results: + +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| +|1970-01-01T08:00:00.006+08:00|1970-01-01T08:00:00.010+08:00| 24.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` + +### 4.2 Aggregate By Group + +#### Aggregation By Level + +Aggregation by level statement is used to group the query result whose name is the same at the given level. + +- Keyword `LEVEL` is used to specify the level that need to be grouped. By convention, `level=0` represents *root* level. +- All aggregation functions are supported. When using five aggregations: sum, avg, min_value, max_value and extreme, please make sure all the aggregated series have exactly the same data type. Otherwise, it will generate a syntax error. + +**Example 1:** there are multiple series named `status` under different databases, like "root.ln.wf01.wt01.status", "root.ln.wf02.wt02.status", and "root.sgcc.wf03.wt01.status". If you need to count the number of data points of the `status` sequence under different databases, use the following query: + +```sql +select count(status) from root.** group by level = 1 +``` + +Result: + +``` ++-------------------------+---------------------------+ +|count(root.ln.*.*.status)|count(root.sgcc.*.*.status)| ++-------------------------+---------------------------+ +| 20160| 10080| ++-------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 2:** If you need to count the number of data points under different devices, you can specify level = 3, + +```sql +select count(status) from root.** group by level = 3 +``` + +Result: + +``` ++---------------------------+---------------------------+ +|count(root.*.*.wt01.status)|count(root.*.*.wt02.status)| ++---------------------------+---------------------------+ +| 20160| 10080| ++---------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 3:** Attention,the devices named `wt01` under databases `ln` and `sgcc` are grouped together, since they are regarded as devices with the same name. If you need to further count the number of data points in different devices under different databases, you can use the following query: + +```sql +select count(status) from root.** group by level = 1, 3 +``` + +Result: + +``` ++----------------------------+----------------------------+------------------------------+ +|count(root.ln.*.wt01.status)|count(root.ln.*.wt02.status)|count(root.sgcc.*.wt01.status)| ++----------------------------+----------------------------+------------------------------+ +| 10080| 10080| 10080| ++----------------------------+----------------------------+------------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**Example 4:** Assuming that you want to query the maximum value of temperature sensor under all time series, you can use the following query statement: + +```sql +select max_value(temperature) from root.** group by level = 0 +``` + +Result: + +``` ++---------------------------------+ +|max_value(root.*.*.*.temperature)| ++---------------------------------+ +| 26.0| ++---------------------------------+ +Total line number = 1 +It costs 0.013s +``` + +**Example 5:** The above queries are for a certain sensor. In particular, **if you want to query the total data points owned by all sensors at a certain level**, you need to explicitly specify `*` is selected. + +```sql +select count(*) from root.ln.** group by level = 2 +``` + +Result: + +``` ++----------------------+----------------------+ +|count(root.*.wf01.*.*)|count(root.*.wf02.*.*)| ++----------------------+----------------------+ +| 20160| 20160| ++----------------------+----------------------+ +Total line number = 1 +It costs 0.013s +``` + +##### Aggregate By Time with Level Clause + +Level could be defined to show count the number of points of each node at the given level in current Metadata Tree. + +This could be used to query the number of points under each device. + +The SQL statement is: + +Get time aggregation by level. + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +``` + +Result: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.006s +``` + +Time aggregation with sliding step and by level. + +```sql +select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +Result: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| +|2017-11-02T00:00:00.000+08:00| 180| +|2017-11-03T00:00:00.000+08:00| 180| +|2017-11-04T00:00:00.000+08:00| 180| +|2017-11-05T00:00:00.000+08:00| 180| +|2017-11-06T00:00:00.000+08:00| 180| +|2017-11-07T00:00:00.000+08:00| 180| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### Aggregation By Tags + +IotDB allows you to do aggregation query with the tags defined in timeseries through `GROUP BY TAGS` clause as well. + +Firstly, we can put these example data into IoTDB, which will be used in the following feature introduction. + +These are the temperature data of the workshops, which belongs to the factory `factory1` and locates in different cities. The time range is `[1000, 10000)`. + +The device node of the timeseries path is the ID of the device. The information of city and workshop are modelled in the tags `city` and `workshop`. +The devices `d1` and `d2` belong to the workshop `d1` in `Beijing`. +`d3` and `d4` belong to the workshop `w2` in `Beijing`. +`d5` and `d6` belong to the workshop `w1` in `Shanghai`. +`d7` belongs to the workshop `w2` in `Shanghai`. +`d8` and `d9` are under maintenance, and don't belong to any workshops, so they have no tags. + + +```SQL +CREATE DATABASE root.factory1; +create timeseries root.factory1.d1.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d2.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d3.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d4.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d5.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d6.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d7.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w2); +create timeseries root.factory1.d8.temperature with datatype=FLOAT; +create timeseries root.factory1.d9.temperature with datatype=FLOAT; + +insert into root.factory1.d1(time, temperature) values(1000, 104.0); +insert into root.factory1.d1(time, temperature) values(3000, 104.2); +insert into root.factory1.d1(time, temperature) values(5000, 103.3); +insert into root.factory1.d1(time, temperature) values(7000, 104.1); + +insert into root.factory1.d2(time, temperature) values(1000, 104.4); +insert into root.factory1.d2(time, temperature) values(3000, 103.7); +insert into root.factory1.d2(time, temperature) values(5000, 103.3); +insert into root.factory1.d2(time, temperature) values(7000, 102.9); + +insert into root.factory1.d3(time, temperature) values(1000, 103.9); +insert into root.factory1.d3(time, temperature) values(3000, 103.8); +insert into root.factory1.d3(time, temperature) values(5000, 102.7); +insert into root.factory1.d3(time, temperature) values(7000, 106.9); + +insert into root.factory1.d4(time, temperature) values(1000, 103.9); +insert into root.factory1.d4(time, temperature) values(5000, 102.7); +insert into root.factory1.d4(time, temperature) values(7000, 106.9); + +insert into root.factory1.d5(time, temperature) values(1000, 112.9); +insert into root.factory1.d5(time, temperature) values(7000, 113.0); + +insert into root.factory1.d6(time, temperature) values(1000, 113.9); +insert into root.factory1.d6(time, temperature) values(3000, 113.3); +insert into root.factory1.d6(time, temperature) values(5000, 112.7); +insert into root.factory1.d6(time, temperature) values(7000, 112.3); + +insert into root.factory1.d7(time, temperature) values(1000, 101.2); +insert into root.factory1.d7(time, temperature) values(3000, 99.3); +insert into root.factory1.d7(time, temperature) values(5000, 100.1); +insert into root.factory1.d7(time, temperature) values(7000, 99.8); + +insert into root.factory1.d8(time, temperature) values(1000, 50.0); +insert into root.factory1.d8(time, temperature) values(3000, 52.1); +insert into root.factory1.d8(time, temperature) values(5000, 50.1); +insert into root.factory1.d8(time, temperature) values(7000, 50.5); + +insert into root.factory1.d9(time, temperature) values(1000, 50.3); +insert into root.factory1.d9(time, temperature) values(3000, 52.1); +``` + +##### Aggregation query by one single tag + +If the user wants to know the average temperature of each workshop, he can query like this + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +The query will calculate the average of the temperatures of those timeseries which have the same tag value of the key `city`. +The results are + +``` ++--------+------------------+ +| city| avg(temperature)| ++--------+------------------+ +| Beijing|104.04666697184244| +|Shanghai|107.85000076293946| +| NULL| 50.84999910990397| ++--------+------------------+ +Total line number = 3 +It costs 0.231s +``` + +From the results we can see that the differences between aggregation by tags query and aggregation by time or level query are: + +1. Aggregation query by tags will no longer remove wildcard to raw timeseries, but do the aggregation through the data of multiple timeseries, which have the same tag value. +2. Except for the aggregate result column, the result set contains the key-value column of the grouped tag. The column name is the tag key, and the values in the column are tag values which present in the searched timeseries. + If some searched timeseries doesn't have the grouped tag, a `NULL` value in the key-value column of the grouped tag will be presented, which means the aggregation of all the timeseries lacking the tagged key. + +##### Aggregation query by multiple tags + +Except for the aggregation query by one single tag, aggregation query by multiple tags in a particular order is allowed as well. + +For example, a user wants to know the average temperature of the devices in each workshop. +As the workshop names may be same in different city, it's not correct to aggregated by the tag `workshop` directly. +So the aggregation by the tag `city` should be done first, and then by the tag `workshop`. + +SQL + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +The results + +``` ++--------+--------+------------------+ +| city|workshop| avg(temperature)| ++--------+--------+------------------+ +| NULL| NULL| 50.84999910990397| +|Shanghai| w1|113.01666768391927| +| Beijing| w2| 104.4000004359654| +|Shanghai| w2|100.10000038146973| +| Beijing| w1|103.73750019073486| ++--------+--------+------------------+ +Total line number = 5 +It costs 0.027s +``` + +We can see that in a multiple tags aggregation query, the result set will output the key-value columns of all the grouped tag keys, which have the same order with the one in `GROUP BY TAGS`. + +##### Downsampling Aggregation by tags based on Time Window + +Downsampling aggregation by time window is one of the most popular features in a time series database. IoTDB supports to do aggregation query by tags based on time window. + +For example, a user wants to know the average temperature of the devices in each workshop, in every 5 seconds, in the range of time `[1000, 10000)`. + +SQL + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +The results + +``` ++-----------------------------+--------+--------+------------------+ +| Time| city|workshop| avg(temperature)| ++-----------------------------+--------+--------+------------------+ +|1970-01-01T08:00:01.000+08:00| NULL| NULL| 50.91999893188476| +|1970-01-01T08:00:01.000+08:00|Shanghai| w1|113.20000076293945| +|1970-01-01T08:00:01.000+08:00| Beijing| w2| 103.4| +|1970-01-01T08:00:01.000+08:00|Shanghai| w2| 100.1999994913737| +|1970-01-01T08:00:01.000+08:00| Beijing| w1|103.81666692097981| +|1970-01-01T08:00:06.000+08:00| NULL| NULL| 50.5| +|1970-01-01T08:00:06.000+08:00|Shanghai| w1| 112.6500015258789| +|1970-01-01T08:00:06.000+08:00| Beijing| w2| 106.9000015258789| +|1970-01-01T08:00:06.000+08:00|Shanghai| w2| 99.80000305175781| +|1970-01-01T08:00:06.000+08:00| Beijing| w1| 103.5| ++-----------------------------+--------+--------+------------------+ +``` + +Comparing to the pure tag aggregations, this kind of aggregation will divide the data according to the time window specification firstly, and do the aggregation query by the multiple tags in each time window secondly. +The result set will also contain a time column, which have the same meaning with the time column of the result in downsampling aggregation query by time window. + +##### Limitation of Aggregation by Tags + +As this feature is still under development, some queries have not been completed yet and will be supported in the future. + +> 1. Temporarily not support `HAVING` clause to filter the results. +> 2. Temporarily not support ordering by tag values. +> 3. Temporarily not support `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`. +> 4. Temporarily not support `ALIGN BY DEVICE`. +> 5. Temporarily not support expressions as aggregation function parameter,e.g. `count(s+1)`. +> 6. Not support the value filter, which stands the same with the `GROUP BY LEVEL` query. + +## 5. `HAVING` CLAUSE + +If you want to filter the results of aggregate queries, +you can use the `HAVING` clause after the `GROUP BY` clause. + +> NOTE: +> +> 1.The expression in HAVING clause must consist of aggregate values; the original sequence cannot appear alone. +> The following usages are incorrect: +> +> ```sql +> select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 +> select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 +> ``` +> +> 2.When filtering the `GROUP BY LEVEL` result, the PATH in `SELECT` and `HAVING` can only have one node. +> The following usages are incorrect: +> +> ```sql +> select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 +> select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 +> ``` + +Here are a few examples of using the 'HAVING' clause to filter aggregate results. + +Aggregation result 1: + +``` ++-----------------------------+---------------------+---------------------+ +| Time|count(root.test.*.s1)|count(root.test.*.s2)| ++-----------------------------+---------------------+---------------------+ +|1970-01-01T08:00:00.001+08:00| 4| 4| +|1970-01-01T08:00:00.003+08:00| 1| 0| +|1970-01-01T08:00:00.005+08:00| 2| 4| +|1970-01-01T08:00:00.007+08:00| 3| 2| +|1970-01-01T08:00:00.009+08:00| 4| 4| ++-----------------------------+---------------------+---------------------+ +``` + +Aggregation result filtering query 1: + +```sql + select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 1 +``` + +Filtering result 1: + +``` ++-----------------------------+---------------------+ +| Time|count(root.test.*.s1)| ++-----------------------------+---------------------+ +|1970-01-01T08:00:00.001+08:00| 4| +|1970-01-01T08:00:00.005+08:00| 2| +|1970-01-01T08:00:00.009+08:00| 4| ++-----------------------------+---------------------+ +``` + +Aggregation result 2: + +``` ++-----------------------------+-------------+---------+---------+ +| Time| Device|count(s1)|count(s2)| ++-----------------------------+-------------+---------+---------+ +|1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.003+08:00|root.test.sg1| 1| 0| +|1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.007+08:00|root.test.sg1| 2| 1| +|1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| +|1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| +|1970-01-01T08:00:00.003+08:00|root.test.sg2| 0| 0| +|1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| +|1970-01-01T08:00:00.007+08:00|root.test.sg2| 1| 1| +|1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| ++-----------------------------+-------------+---------+---------+ +``` + +Aggregation result filtering query 2: + +```sql + select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device +``` + +Filtering result 2: + +``` ++-----------------------------+-------------+---------+---------+ +| Time| Device|count(s1)|count(s2)| ++-----------------------------+-------------+---------+---------+ +|1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| +|1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| +|1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| +|1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| +|1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| ++-----------------------------+-------------+---------+---------+ +``` + +## 6. `FILL` CLAUSE + +### 6.1 Introduction + +When executing some queries, there may be no data for some columns in some rows, and data in these locations will be null, but this kind of null value is not conducive to data visualization and analysis, and the null value needs to be filled. + +In IoTDB, users can use the FILL clause to specify the fill mode when data is missing. Fill null value allows the user to fill any query result with null values according to a specific method, such as taking the previous value that is not null, or linear interpolation. The query result after filling the null value can better reflect the data distribution, which is beneficial for users to perform data analysis. + +### 6.2 Syntax Definition + +**The following is the syntax definition of the `FILL` clause:** + +```sql +FILL '(' PREVIOUS | LINEAR | constant ')' +``` + +**Note:** + +- We can specify only one fill method in the `FILL` clause, and this method applies to all columns of the result set. +- Null value fill is not compatible with version 0.13 and previous syntax (`FILL(([(, , )?])+)`) is not supported anymore. + +### 6.3 Fill Methods + +**IoTDB supports the following three fill methods:** + +- `PREVIOUS`: Fill with the previous non-null value of the column. +- `LINEAR`: Fill the column with a linear interpolation of the previous non-null value and the next non-null value of the column. +- Constant: Fill with the specified constant. + +**Following table lists the data types and supported fill methods.** + +| Data Type | Supported Fill Methods | +| :-------- | :---------------------- | +| boolean | previous, value | +| int32 | previous, linear, value | +| int64 | previous, linear, value | +| float | previous, linear, value | +| double | previous, linear, value | +| text | previous, value | + +**Note:** For columns whose data type does not support specifying the fill method, we neither fill it nor throw exception, just keep it as it is. + +**For examples:** + +If we don't use any fill methods: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000; +``` + +the original result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### `PREVIOUS` Fill + +**For null values in the query result set, fill with the previous non-null value of the column.** + +**Note:** If the first value of this column is null, we will keep first value as null and won't fill it until we meet first non-null value + +For example, with `PREVIOUS` fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 21.93| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| false| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +**While using `FILL(PREVIOUS)`, you can specify a time interval. If the interval between the timestamp of the current null value and the timestamp of the previous non-null value exceeds the specified time interval, no filling will be performed.** + +> 1. In the case of FILL(LINEAR) and FILL(CONSTANT), if the second parameter is specified, an exception will be thrown +> 2. The interval parameter only supports integers + For example, the raw data looks like this: + +```sql +select s1 from root.db.d1 +``` +``` ++-----------------------------+-------------+ +| Time|root.db.d1.s1| ++-----------------------------+-------------+ +|2023-11-08T16:41:50.008+08:00| 1.0| ++-----------------------------+-------------+ +|2023-11-08T16:46:50.011+08:00| 2.0| ++-----------------------------+-------------+ +|2023-11-08T16:48:50.011+08:00| 3.0| ++-----------------------------+-------------+ +``` + +We want to group the data by 1 min time interval: + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| null| ++-----------------------------+------------------+ +``` + +After grouping, we want to fill the null value: + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +we also don't want the null value to be filled if it keeps null for 2 min. + +```sql +select avg(s1) +from root.db.d1 +group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS, 2m); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +#### `LINEAR` Fill + +**For null values in the query result set, fill the column with a linear interpolation of the previous non-null value and the next non-null value of the column.** + +**Note:** + +- If all the values before current value are null or all the values after current value are null, we will keep current value as null and won't fill it. +- If the column's data type is boolean/text, we neither fill it nor throw exception, just keep it as it is. + +Here we give an example of filling null values using the linear method. The SQL statement is as follows: + +For example, with `LINEAR` fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 22.08| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### Constant Fill + +**For null values in the query result set, fill with the specified constant.** + +**Note:** + +- When using the ValueFill, IoTDB neither fill the query result if the data type is different from the input constant nor throw exception, just keep it as it is. + + | Constant Value Data Type | Support Data Type | + | :----------------------- | :-------------------------------------- | + | `BOOLEAN` | `BOOLEAN` `TEXT` | + | `INT64` | `INT32` `INT64` `FLOAT` `DOUBLE` `TEXT` | + | `DOUBLE` | `FLOAT` `DOUBLE` `TEXT` | + | `TEXT` | `TEXT` | + +- If constant value is larger than Integer.MAX_VALUE, IoTDB neither fill the query result if the data type is int32 nor throw exception, just keep it as it is. + +For example, with `FLOAT` constant fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 2.0| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +For example, with `BOOLEAN` constant fill, the SQL is as follows: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +result will be like: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| true| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +## 7. `LIMIT` and `SLIMIT` CLAUSES (PAGINATION) + +When the query result set has a large amount of data, it is not conducive to display on one page. You can use the `LIMIT/SLIMIT` clause and the `OFFSET/SOFFSET` clause to control paging. + +- The `LIMIT` and `SLIMIT` clauses are used to control the number of rows and columns of query results. +- The `OFFSET` and `SOFFSET` clauses are used to control the starting position of the result display. + +### 7.1 Row Control over Query Results + +By using LIMIT and OFFSET clauses, users control the query results in a row-related manner. We demonstrate how to use LIMIT and OFFSET clauses through the following examples. + +* Example 1: basic LIMIT clause + +The SQL statement is: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 10 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires the first 10 rows of the query result. + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:00:00.000+08:00| true| 25.96| +|2017-11-01T00:01:00.000+08:00| true| 24.36| +|2017-11-01T00:02:00.000+08:00| false| 20.09| +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 10 +It costs 0.000s +``` + +* Example 2: LIMIT clause with OFFSET + +The SQL statement is: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is "status" and "temperature". The SQL statement requires rows 3 to 7 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.342s +``` + +* Example 3: LIMIT clause combined with WHERE clause + +The SQL statement is: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2024-07-07T00:05:00.000 and time< 2024-07-12T00:12:00.000 limit 5 offset 3 +``` + +which means: + +The selected equipment is the ln group wf01 factory wt01 equipment; The selected time series are "state" and "temperature". The SQL statement requires the return of the status and temperature sensor values between the time "2024-07-07T00:05:00.000" and "2024-07-12T00:12:00.0000" on lines 3 to 7 (the first line is numbered as line 0). + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2024-07-09T17:32:11.943+08:00| true| 24.941973| +|2024-07-09T17:32:12.944+08:00| true| 20.05108| +|2024-07-09T17:32:13.945+08:00| true| 20.541632| +|2024-07-09T17:32:14.945+08:00| null| 23.09016| +|2024-07-09T17:32:14.946+08:00| true| null| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.070s +``` + +* Example 4: LIMIT clause combined with GROUP BY clause + +The SQL statement is: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 5 offset 3 +``` + +which means: + +The SQL statement clause requires rows 3 to 7 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 4 +It costs 0.016s +``` + +### 7.2 Column Control over Query Results + +By using SLIMIT and SOFFSET clauses, users can control the query results in a column-related manner. We will demonstrate how to use SLIMIT and SOFFSET clauses through the following examples. + +* Example 1: basic SLIMIT clause + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is the first column under this device, i.e., the power supply status. The SQL statement requires the status sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The result is shown below: + +``` ++-----------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.temperature| ++-----------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| 20.71| +|2017-11-01T00:07:00.000+08:00| 21.45| +|2017-11-01T00:08:00.000+08:00| 22.58| +|2017-11-01T00:09:00.000+08:00| 20.98| +|2017-11-01T00:10:00.000+08:00| 25.52| +|2017-11-01T00:11:00.000+08:00| 22.91| ++-----------------------------+-----------------------------+ +Total line number = 6 +It costs 0.000s +``` + +* Example 2: SLIMIT clause with SOFFSET + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is the second column under this device, i.e., the temperature. The SQL statement requires the temperature sensor values between the time point of "2017-11-01T00:05:00.000" and "2017-11-01T00:12:00.000" be selected. + +The result is shown below: + +``` ++-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.status| ++-----------------------------+------------------------+ +|2017-11-01T00:06:00.000+08:00| false| +|2017-11-01T00:07:00.000+08:00| false| +|2017-11-01T00:08:00.000+08:00| false| +|2017-11-01T00:09:00.000+08:00| false| +|2017-11-01T00:10:00.000+08:00| true| +|2017-11-01T00:11:00.000+08:00| false| ++-----------------------------+------------------------+ +Total line number = 6 +It costs 0.003s +``` + +* Example 3: SLIMIT clause combined with GROUP BY clause + +The SQL statement is: + +```sql +select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +The result is shown below: + +``` ++-----------------------------+-----------------------------------+ +| Time|max_value(root.ln.wf01.wt01.status)| ++-----------------------------+-----------------------------------+ +|2017-11-01T00:00:00.000+08:00| true| +|2017-11-02T00:00:00.000+08:00| true| +|2017-11-03T00:00:00.000+08:00| true| +|2017-11-04T00:00:00.000+08:00| true| +|2017-11-05T00:00:00.000+08:00| true| +|2017-11-06T00:00:00.000+08:00| true| +|2017-11-07T00:00:00.000+08:00| true| ++-----------------------------+-----------------------------------+ +Total line number = 7 +It costs 0.000s +``` + +### 7.3 Row and Column Control over Query Results + +In addition to row or column control over query results, IoTDB allows users to control both rows and columns of query results. Here is a complete example with both LIMIT clauses and SLIMIT clauses. + +The SQL statement is: + +```sql +select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +which means: + +The selected device is ln group wf01 plant wt01 device; the selected timeseries is columns 0 to 1 under this device (with the first column numbered as column 0). The SQL statement clause requires rows 100 to 109 of the query result be returned (with the first row numbered as row 0). + +The result is shown below: + +``` ++-----------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+-----------------------------+------------------------+ +|2017-11-01T01:40:00.000+08:00| 21.19| false| +|2017-11-01T01:41:00.000+08:00| 22.79| false| +|2017-11-01T01:42:00.000+08:00| 22.98| false| +|2017-11-01T01:43:00.000+08:00| 21.52| false| +|2017-11-01T01:44:00.000+08:00| 23.45| true| +|2017-11-01T01:45:00.000+08:00| 24.06| true| +|2017-11-01T01:46:00.000+08:00| 22.6| false| +|2017-11-01T01:47:00.000+08:00| 23.78| true| +|2017-11-01T01:48:00.000+08:00| 24.72| true| +|2017-11-01T01:49:00.000+08:00| 24.68| true| ++-----------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.009s +``` + +### 7.4 Error Handling + +If the parameter N/SN of LIMIT/SLIMIT exceeds the size of the result set, IoTDB returns all the results as expected. For example, the query result of the original SQL statement consists of six rows, and we select the first 100 rows through the LIMIT clause: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 100 +``` + +The result is shown below: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.005s +``` + +If the parameter N/SN of LIMIT/SLIMIT clause exceeds the allowable maximum value (N/SN is of type int64), the system prompts errors. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 9223372036854775808 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 416: Out of range. LIMIT : N should be Int64. +``` + +If the parameter N/SN of LIMIT/SLIMIT clause is not a positive intege, the system prompts errors. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 13.1 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 401: line 1:129 mismatched input '.' expecting {, ';'} +``` + +If the parameter OFFSET of LIMIT clause exceeds the size of the result set, IoTDB will return an empty result set. For example, executing the following SQL statement: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 2 offset 6 +``` + +The result is shown below: + +``` ++----+------------------------+-----------------------------+ +|Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++----+------------------------+-----------------------------+ ++----+------------------------+-----------------------------+ +Empty set. +It costs 0.005s +``` + +If the parameter SOFFSET of SLIMIT clause is not smaller than the number of available timeseries, the system prompts errors. For example, executing the following SQL statement: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 2 +``` + +The SQL statement will not be executed and the corresponding error prompt is given as follows: + +``` +Msg: 411: Meet error in query process: The value of SOFFSET (2) is equal to or exceeds the number of sequences (2) that can actually be returned. +``` + +## 8. `ORDER BY` CLAUSE + +### 8.1 Order by in ALIGN BY TIME mode + +The result set of IoTDB is in ALIGN BY TIME mode by default and `ORDER BY TIME` clause can also be used to specify the ordering of timestamp. The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` + +Results: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-01T00:01:00.000+08:00| v2| true| 24.36| true| +|2017-11-01T00:00:00.000+08:00| v2| true| 25.96| true| +|1970-01-01T08:00:00.002+08:00| v2| false| null| null| +|1970-01-01T08:00:00.001+08:00| v1| true| null| null| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +``` + +### 8.2 Order by in ALIGN BY DEVICE mode + +When querying in ALIGN BY DEVICE mode, `ORDER BY` clause can be used to specify the ordering of result set. + +ALIGN BY DEVICE mode supports four kinds of clauses with two sort keys which are `Device` and `Time`. + +1. ``ORDER BY DEVICE``: sort by the alphabetical order of the device name. The devices with the same column names will be clustered in a group view. + +2. ``ORDER BY TIME``: sort by the timestamp, the data points from different devices will be shuffled according to the timestamp. + +3. ``ORDER BY DEVICE,TIME``: sort by the alphabetical order of the device name. The data points with the same device name will be sorted by timestamp. + +4. ``ORDER BY TIME,DEVICE``: sort by timestamp. The data points with the same time will be sorted by the alphabetical order of the device name. + +> To make the result set more legible, when `ORDER BY` clause is not used, default settings will be provided. +> The default ordering clause is `ORDER BY DEVICE,TIME` and the default ordering is `ASC`. + +When `Device` is the main sort key, the result set is sorted by device name first, then by timestamp in the group with the same device name, the SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +When `Time` is the main sort key, the result set is sorted by timestamp first, then by device name in data points with the same timestamp. The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +When `ORDER BY` clause is not used, sort in default way, the SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +The result below indicates `ORDER BY DEVICE ASC,TIME ASC` is the clause in default situation. +`ASC` can be omitted because it's the default ordering. + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| ++-----------------------------+-----------------+--------+------+-----------+ +``` + +Besides,`ALIGN BY DEVICE` and `ORDER BY` clauses can be used with aggregate query,the SQL statement is: + +```sql +select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` + +The result shows below: + +``` ++-----------------------------+-----------------+---------------+-------------+------------------+ +| Time| Device|count(hardware)|count(status)|count(temperature)| ++-----------------------------+-----------------+---------------+-------------+------------------+ +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| 1| 1| +|2017-11-01T00:02:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:03:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| 1| 1| null| +|2017-11-01T00:02:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| +|2017-11-01T00:03:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| ++-----------------------------+-----------------+---------------+-------------+------------------+ +``` + +### 8.3 Order by arbitrary expressions + +In addition to the predefined keywords "Time" and "Device" in IoTDB, `ORDER BY` can also be used to sort by any expressions. + +When sorting, `ASC` or `DESC` can be used to specify the sorting order, and `NULLS` syntax is supported to specify the priority of NULL values in the sorting. By default, `NULLS FIRST` places NULL values at the top of the result, and `NULLS LAST` ensures that NULL values appear at the end of the result. If not specified in the clause, the default order is ASC with NULLS LAST. + +Here are several examples of queries for sorting arbitrary expressions using the following data: + +``` ++-----------------------------+-------------+-------+-------+--------+-------+ +| Time| Device| base| score| bonus| total| ++-----------------------------+-------------+-------+-------+--------+-------+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0| 107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0| 105.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0| 103.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00| root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.020+08:00| root.three| 8| null| 22.5| 30.5| +|1970-01-01T08:00:00.030+08:00| root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0| 104.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0| 102.0| ++-----------------------------+-------------+-------+-------+--------+-------+ +``` + +When you need to sort the results based on the base score score, you can use the following SQL: + +```Sql +select score from root.** order by score desc align by device +``` + +This will give you the following results: + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +If you want to sort the results based on the total score, you can use an expression in the `ORDER BY` clause to perform the calculation: + +```Sql +select score,total from root.one order by base+score+bonus desc +``` + +This SQL is equivalent to: + +```Sql +select score,total from root.one order by total desc +``` + +Here are the results: + +``` ++-----------------------------+--------------+--------------+ +| Time|root.one.score|root.one.total| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.000+08:00| 50.0| 107.0| +|1970-01-02T08:00:00.000+08:00| 50.0| 105.0| +|1970-01-03T08:00:00.000+08:00| 50.0| 103.0| ++-----------------------------+--------------+--------------+ +``` + +If you want to sort the results based on the total score and, in case of tied scores, sort by score, base, bonus, and submission time in descending order, you can specify multiple layers of sorting using multiple expressions: + +```Sql +select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +``` + +Here are the results: + +``` ++-----------------------------+----------+----+-----+-----+-----+ +| Time| Device|base|score|bonus|total| ++-----------------------------+----------+----+-----+-----+-----+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0|107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0|105.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0|104.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0|103.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0|102.0| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.000+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00|root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.030+08:00|root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.020+08:00|root.three| 8| null| 22.5| 30.5| ++-----------------------------+----------+----+-----+-----+-----+ +``` + +In the `ORDER BY` clause, you can also use aggregate query expressions. For example: + +```Sql +select min_value(total) from root.** order by min_value(total) asc align by device +``` + +This will give you the following results: + +``` ++----------+----------------+ +| Device|min_value(total)| ++----------+----------------+ +|root.three| 30.5| +| root.two| 33.0| +| root.four| 85.0| +| root.five| 102.0| +| root.one| 103.0| ++----------+----------------+ +``` + +When specifying multiple columns in the query, the unsorted columns will change order along with the rows and sorted columns. The order of rows when the sorting columns are the same may vary depending on the specific implementation (no fixed order). For example: + +```Sql +select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +``` + +This will give you the following results: +· + +``` ++----------+----------------+---------------+ +| Device|min_value(total)|max_value(base)| ++----------+----------------+---------------+ +| root.one| 103.0| 12| +| root.five| 102.0| 7| +| root.four| 85.0| 9| +| root.two| 33.0| 9| +|root.three| 30.5| 9| ++----------+----------------+---------------+ +``` + +You can use both `ORDER BY DEVICE,TIME` and `ORDER BY EXPRESSION` together. For example: + +```Sql +select score from root.** order by device asc, score desc, time asc align by device +``` + +This will give you the following results: + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +## 9. `ALIGN BY` CLAUSE + +In addition, IoTDB supports another result set format: `ALIGN BY DEVICE`. + +### 9.1 Align by Device + +The `ALIGN BY DEVICE` indicates that the deviceId is considered as a column. Therefore, there are totally limited columns in the dataset. + +> NOTE: +> +> 1.You can see the result of 'align by device' as one relational table, `Time + Device` is the primary key of this Table. +> +> 2.The result is order by `Device` firstly, and then by `Time` order. + +The SQL statement is: + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +The result shows below: + +``` ++-----------------------------+-----------------+-----------+------+--------+ +| Time| Device|temperature|status|hardware| ++-----------------------------+-----------------+-----------+------+--------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| 25.96| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| 24.36| true| null| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| null| true| v1| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| null| false| v2| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| null| true| v2| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| null| true| v2| ++-----------------------------+-----------------+-----------+------+--------+ +Total line number = 6 +It costs 0.012s +``` + +### 9.2 Ordering in ALIGN BY DEVICE + +ALIGN BY DEVICE mode arranges according to the device first, and sort each device in ascending order according to the timestamp. The ordering and priority can be adjusted through `ORDER BY` clause. + +## 10. `INTO` CLAUSE (QUERY WRITE-BACK) + +The `SELECT INTO` statement copies data from query result set into target time series. + +The application scenarios are as follows: + +- **Implement IoTDB internal ETL**: ETL the original data and write a new time series. +- **Query result storage**: Persistently store the query results, which acts like a materialized view. +- **Non-aligned time series to aligned time series**: Rewrite non-aligned time series into another aligned time series. + +### 10.1 SQL Syntax + +#### Syntax Definition + +**The following is the syntax definition of the `select` statement:** + +```sql +selectIntoStatement +: SELECT + resultColumn [, resultColumn] ... + INTO intoItem [, intoItem] ... + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY groupByTimeClause, groupByLevelClause] + [FILL {PREVIOUS | LINEAR | constant}] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] +; + +intoItem +: [ALIGNED] intoDevicePath '(' intoMeasurementName [',' intoMeasurementName]* ')' + ; +``` + +#### `INTO` Clause + +The `INTO` clause consists of several `intoItem`. + +Each `intoItem` consists of a target device and a list of target measurements (similar to the `INTO` clause in an `INSERT` statement). + +Each target measurement and device form a target time series, and an `intoItem` contains a series of time series. For example: `root.sg_copy.d1(s1, s2)` specifies two target time series `root.sg_copy.d1.s1` and `root.sg_copy.d1.s2`. + +The target time series specified by the `INTO` clause must correspond one-to-one with the columns of the query result set. The specific rules are as follows: + +- **Align by time** (default): The number of target time series contained in all `intoItem` must be consistent with the number of columns in the query result set (except the time column) and correspond one-to-one in the order from left to right in the header. +- **Align by device** (using `ALIGN BY DEVICE`): the number of target devices specified in all `intoItem` is the same as the number of devices queried (i.e., the number of devices matched by the path pattern in the `FROM` clause), and One-to-one correspondence according to the output order of the result set device. +
The number of measurements specified for each target device should be consistent with the number of columns in the query result set (except for the time and device columns). It should be in one-to-one correspondence from left to right in the header. + +For examples: + +- **Example 1** (aligned by time) + +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; ++--------------+-------------------+--------+ +| source column| target timeseries| written| ++--------------+-------------------+--------+ +| root.sg.d1.s1| root.sg_copy.d1.t1| 8000| ++--------------+-------------------+--------+ +| root.sg.d2.s1| root.sg_copy.d2.t1| 10000| ++--------------+-------------------+--------+ +| root.sg.d1.s2| root.sg_copy.d2.t2| 12000| ++--------------+-------------------+--------+ +| root.sg.d2.s2| root.sg_copy.d1.t2| 10000| ++--------------+-------------------+--------+ +Total line number = 4 +It costs 0.725s +``` + +This statement writes the query results of the four time series under the `root.sg` database to the four specified time series under the `root.sg_copy` database. Note that `root.sg_copy.d2(t1, t2)` can also be written as `root.sg_copy.d2(t1), root.sg_copy.d2(t2)`. + +We can see that the writing of the `INTO` clause is very flexible as long as the combined target time series is not repeated and corresponds to the query result column one-to-one. + +> In the result set displayed by `CLI`, the meaning of each column is as follows: +> +> - The `source column` column represents the column name of the query result. +> - `target timeseries` represents the target time series for the corresponding column to write. +> - `written` indicates the amount of data expected to be written. + + +- **Example 2** (aligned by time) + +```shell +IoTDB> select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); ++--------------------------------------+-------------------------+--------+ +| source column| target timeseries| written| ++--------------------------------------+-------------------------+--------+ +| count(root.sg.d1.s1 + root.sg.d1.s2)| root.agg.count.s1_add_s2| 10| ++--------------------------------------+-------------------------+--------+ +| last_value(root.sg.d1.s2)| root.agg.last_value.s2| 10| ++--------------------------------------+-------------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +This statement stores the results of an aggregated query into the specified time series. + +- **Example 3** (aligned by device) + +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+-------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s1| root.sg_copy.d1.t1| 8000| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s2| root.sg_copy.d1.t2| 11000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s1| root.sg_copy.d2.t1| 12000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s2| root.sg_copy.d2.t2| 9000| ++--------------+--------------+-------------------+--------+ +Total line number = 4 +It costs 0.625s +``` + +This statement also writes the query results of the four time series under the `root.sg` database to the four specified time series under the `root.sg_copy` database. However, in ALIGN BY DEVICE, the number of `intoItem` must be the same as the number of queried devices, and each queried device corresponds to one `intoItem`. + +> When aligning the query by device, the result set displayed by `CLI` has one more column, the `source device` column indicating the queried device. + +- **Example 4** (aligned by device) + +```shell +IoTDB> select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+------------------------+--------+ +| root.sg.d1| s1 + s2| root.expr.add.d1s1_d1s2| 10000| ++--------------+--------------+------------------------+--------+ +| root.sg.d2| s1 + s2| root.expr.add.d2s1_d2s2| 10000| ++--------------+--------------+------------------------+--------+ +Total line number = 2 +It costs 0.532s +``` + +This statement stores the result of evaluating an expression into the specified time series. + +#### Using variable placeholders + +In particular, We can use variable placeholders to describe the correspondence between the target and query time series, simplifying the statement. The following two variable placeholders are currently supported: + +- Suffix duplication character `::`: Copy the suffix (or measurement) of the query device, indicating that from this layer to the last layer (or measurement) of the device, the node name (or measurement) of the target device corresponds to the queried device The node name (or measurement) is the same. +- Single-level node matcher `${i}`: Indicates that the current level node name of the target sequence is the same as the i-th level node name of the query sequence. For example, for the path `root.sg1.d1.s1`, `${1}` means `sg1`, `${2}` means `d1`, and `${3}` means `s1`. + +When using variable placeholders, there must be no ambiguity in the correspondence between `intoItem` and the columns of the query result set. The specific cases are classified as follows: + +##### ALIGN BY TIME (default) + +> Note: The variable placeholder **can only describe the correspondence between time series**. If the query includes aggregation and expression calculation, the columns in the query result cannot correspond to a time series, so neither the target device nor the measurement can use variable placeholders. + +###### (1) The target device does not use variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** + +1. In each `intoItem`, the length of the list of physical quantities must be 1.
(If the length can be greater than 1, e.g. `root.sg1.d1(::, s1)`, it is not possible to determine which columns match `::`) +2. The number of `intoItem` is 1, or the same as the number of columns in the query result set.
(When the length of each target measurement list is 1, if there is only one `intoItem`, it means that all the query sequences are written to the same device; if the number of `intoItem` is consistent with the query sequence, it is expressed as each query time series specifies a target device; if `intoItem` is greater than one and less than the number of query sequences, it cannot be a one-to-one correspondence with the query sequence) + +**Matching method:** Each query time series specifies the target device, and the target measurement is generated from the variable placeholder. + +**Example:** + +```sql +select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; +```` + +This statement is equivalent to: + +```sql +select s1, s2 +into root.sg_copy.d1(s1), root.sg_copy.d2(s1), root.sg_copy.d1(s2), root.sg_copy.d2(s2) +from root.sg.d1, root.sg.d2; +```` + +As you can see, the statement is not very simplified in this case. + +###### (2) The target device uses variable placeholders & the target measurement list does not use variable placeholders + +**Limitations:** The number of target measurements in all `intoItem` is the same as the number of columns in the query result set. + +**Matching method:** The target measurement is specified for each query time series, and the target device is generated according to the target device placeholder of the `intoItem` where the corresponding target measurement is located. + +**Example:** + +```sql +select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; +```` + +###### (3) The target device uses variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** There is only one `intoItem`, and the length of the list of measurement list is 1. + +**Matching method:** Each query time series can get a target time series according to the variable placeholder. + +**Example:** + +```sql +select * into root.sg_bk.::(::) from root.sg.**; +```` + +Write the query results of all time series under `root.sg` to `root.sg_bk`, the device name suffix and measurement remain unchanged. + +##### ALIGN BY DEVICE + +> Note: The variable placeholder **can only describe the correspondence between time series**. If the query includes aggregation and expression calculation, the columns in the query result cannot correspond to a specific physical quantity, so the target measurement cannot use variable placeholders. + +###### (1) The target device does not use variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** In each `intoItem`, if the list of measurement uses variable placeholders, the length of the list must be 1. + +**Matching method:** Each query time series specifies the target device, and the target measurement is generated from the variable placeholder. + +**Example:** + +```sql +select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; +```` + +###### (2) The target device uses variable placeholders & the target measurement list does not use variable placeholders + +**Limitations:** There is only one `intoItem`. (If there are multiple `intoItem` with placeholders, we will not know which source devices each `intoItem` needs to match) + +**Matching method:** Each query device obtains a target device according to the variable placeholder, and the target measurement written in each column of the result set under each device is specified by the target measurement list. + +**Example:** + +```sql +select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; +```` + +###### (3) The target device uses variable placeholders & the target measurement list uses variable placeholders + +**Limitations:** There is only one `intoItem` and the length of the target measurement list is 1. + +**Matching method:** Each query time series can get a target time series according to the variable placeholder. + +**Example:** + +```sql +select * into ::(backup_${4}) from root.sg.** align by device; +```` + +Write the query result of each time series in `root.sg` to the same device, and add `backup_` before the measurement. + +#### Specify the target time series as the aligned time series + +We can use the `ALIGNED` keyword to specify the target device for writing to be aligned, and each `intoItem` can be set independently. + +**Example:** + +```sql +select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` + +This statement specifies that `root.sg_copy.d1` is an unaligned device and `root.sg_copy.d2` is an aligned device. + +#### Unsupported query clauses + +- `SLIMIT`, `SOFFSET`: The query columns are uncertain, so they are not supported. +- `LAST`, `GROUP BY TAGS`, `DISABLE ALIGN`: The table structure is inconsistent with the writing structure, so it is not supported. + +#### Other points to note + +- For general aggregation queries, the timestamp is meaningless, and the convention is to use 0 to store. +- When the target time-series exists, the data type of the source column and the target time-series must be compatible. About data type compatibility, see the document [Data Type](../Background-knowledge/Data-Type.md#Data Type Compatibility). +- When the target time series does not exist, the system automatically creates it (including the database). +- When the queried time series does not exist, or the queried sequence does not have data, the target time series will not be created automatically. + +### 10.2 Application examples + +#### Implement IoTDB internal ETL + +ETL the original data and write a new time series. + +```shell +IOTDB > SELECT preprocess_udf(s1, s2) INTO ::(preprocessed_s1, preprocessed_s2) FROM root.sg.* ALIGN BY DEIVCE; ++--------------+-------------------+---------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s1)| root.sg.d1.preprocessed_s1| 8000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s2)| root.sg.d1.preprocessed_s2| 10000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s1)| root.sg.d2.preprocessed_s1| 11000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s2)| root.sg.d2.preprocessed_s2| 9000| ++--------------+-------------------+---------------------------+--------+ +``` + +#### Query result storage + +Persistently store the query results, which acts like a materialized view. + +```shell +IOTDB > SELECT count(s1), last_value(s1) INTO root.sg.agg_${2}(count_s1, last_value_s1) FROM root.sg1.d1 GROUP BY ([0, 10000), 10ms); ++--------------------------+-----------------------------+--------+ +| source column| target timeseries| written| ++--------------------------+-----------------------------+--------+ +| count(root.sg.d1.s1)| root.sg.agg_d1.count_s1| 1000| ++--------------------------+-----------------------------+--------+ +| last_value(root.sg.d1.s2)| root.sg.agg_d1.last_value_s2| 1000| ++--------------------------+-----------------------------+--------+ +Total line number = 2 +It costs 0.115s +``` + +#### Non-aligned time series to aligned time series + +Rewrite non-aligned time series into another aligned time series. + +**Note:** It is recommended to use the `LIMIT & OFFSET` clause or the `WHERE` clause (time filter) to batch data to prevent excessive data volume in a single operation. + +```shell +IOTDB > SELECT s1, s2 INTO ALIGNED root.sg1.aligned_d(s1, s2) FROM root.sg1.non_aligned_d WHERE time >= 0 and time < 10000; ++--------------------------+----------------------+--------+ +| source column| target timeseries| written| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s1| root.sg1.aligned_d.s1| 10000| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s2| root.sg1.aligned_d.s2| 10000| ++--------------------------+----------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +### 10.3 User Permission Management + +The user must have the following permissions to execute a query write-back statement: + +* All `WRITE_SCHEMA` permissions for the source series in the `select` clause. +* All `WRITE_DATA` permissions for the target series in the `into` clause. + +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_timecho). + +### 10.4 Configurable Properties + +* `select_into_insert_tablet_plan_row_limit`: The maximum number of rows can be processed in one insert-tablet-plan when executing select-into statements. 10000 by default. diff --git a/src/UserGuide/Master/Tree/Basic-Concept/Write-Data.md b/src/UserGuide/latest/Basic-Concept/Write-Data_apache.md similarity index 89% rename from src/UserGuide/Master/Tree/Basic-Concept/Write-Data.md rename to src/UserGuide/latest/Basic-Concept/Write-Data_apache.md index 5709e15da..35ebef8b5 100644 --- a/src/UserGuide/Master/Tree/Basic-Concept/Write-Data.md +++ b/src/UserGuide/latest/Basic-Concept/Write-Data_apache.md @@ -23,15 +23,15 @@ # Write Data ## 1. CLI INSERT -IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC.md) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual.md). +IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC_apache) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache). -NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) for real-time data import in the scenario. +NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) for real-time data import in the scenario. Writing a repeat timestamp covers the original timestamp data, which can be regarded as updated data. ### 1.1 Use of INSERT Statements -The [INSERT SQL statement](../SQL-Manual/SQL-Manual.md#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). +The [INSERT SQL statement](../SQL-Manual/SQL-Manual_apache#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). In the scenario of this section, take two timeseries `root.ln.wf02.wt02.status` and `root.ln.wf02.wt02.hardware` as an example, and their data types are BOOLEAN and TEXT, respectively. @@ -122,12 +122,12 @@ The Native API ( Session ) is the most widely used series of APIs of IoTDB, incl #### Java -Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API.md). -then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API.md#insert) +Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API_apache). +then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API_apache#insert) #### Python -Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API.md#insert) +Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API_apache#insert) #### C++ @@ -139,7 +139,7 @@ Refer to [Go Native API](../API/Programming-Go-Native-API.md) ## 3. REST API WRITE -Refer to [insertTablet (v1)](../API/RestServiceV1.md#inserttablet) or [insertTablet (v2)](../API/RestServiceV2.md#inserttablet) +Refer to [insertTablet (v1)](../API/RestServiceV1_apache#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_apache#inserttablet) Example: @@ -185,11 +185,11 @@ In different scenarios, the IoTDB provides a variety of methods for importing da ### 5.1 TsFile Batch Load -TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool.md). +TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool_apache). ### 5.2 CSV Batch Load -CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool.md). +CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool_apache). ## 6. SCHEMALESS WRITING In IoT scenarios, the types and quantities of devices may dynamically increase or decrease over time, and different devices may generate data with varying fields (e.g., temperature, humidity, status codes). Additionally, businesses often require rapid deployment and flexible integration of new devices without cumbersome predefined processes. Therefore, unlike traditional time-series databases that typically require predefining data models, IoTDB supports schema-less writing, where the database automatically identifies and registers the necessary metadata during data writing, enabling automatic modeling. diff --git a/src/UserGuide/latest/Basic-Concept/Write-Data_timecho.md b/src/UserGuide/latest/Basic-Concept/Write-Data_timecho.md new file mode 100644 index 000000000..380ab5037 --- /dev/null +++ b/src/UserGuide/latest/Basic-Concept/Write-Data_timecho.md @@ -0,0 +1,200 @@ + + + +# Write Data +## 1. CLI INSERT + +IoTDB provides users with a variety of ways to insert real-time data, such as directly inputting [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) in [Client/Shell tools](../Tools-System/CLI.md), or using [Java JDBC](../API/Programming-JDBC_timecho) to perform single or batch execution of [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho). + +NOTE: This section mainly introduces the use of [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) for real-time data import in the scenario. + +Writing a repeat timestamp covers the original timestamp data, which can be regarded as updated data. + +### 1.1 Use of INSERT Statements + +The [INSERT SQL statement](../SQL-Manual/SQL-Manual_timecho#insert-data) statement is used to insert data into one or more specified timeseries created. For each point of data inserted, it consists of a [timestamp](../Basic-Concept/Operate-Metadata.md) and a sensor acquisition value (see [Data Type](../Background-knowledge/Data-Type.md)). + +In the scenario of this section, take two timeseries `root.ln.wf02.wt02.status` and `root.ln.wf02.wt02.hardware` as an example, and their data types are BOOLEAN and TEXT, respectively. + +The sample code for single column data insertion is as follows: + +``` +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +The above example code inserts the long integer timestamp and the value "true" into the timeseries `root.ln.wf02.wt02.status` and inserts the long integer timestamp and the value "v1" into the timeseries `root.ln.wf02.wt02.hardware`. When the execution is successful, cost time is shown to indicate that the data insertion has been completed. + +> Note: In IoTDB, TEXT type data can be represented by single and double quotation marks. The insertion statement above uses double quotation marks for TEXT type data. The following example will use single quotation marks for TEXT type data. + +The INSERT statement can also support the insertion of multi-column data at the same time point. The sample code of inserting the values of the two timeseries at the same time point '2' is as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (2, false, 'v2') +``` + +In addition, The INSERT statement support insert multi-rows at once. The sample code of inserting two rows as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +After inserting the data, we can simply query the inserted data using the SELECT statement: + +```sql +IoTDB > select * from root.ln.wf02.wt02 where time < 5 +``` + +The result is shown below. The query result shows that the insertion statements of single column and multi column data are performed correctly. + +``` ++-----------------------------+--------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status| ++-----------------------------+--------------------------+------------------------+ +|1970-01-01T08:00:00.001+08:00| v1| true| +|1970-01-01T08:00:00.002+08:00| v2| false| +|1970-01-01T08:00:00.003+08:00| v3| false| +|1970-01-01T08:00:00.004+08:00| v4| true| ++-----------------------------+--------------------------+------------------------+ +Total line number = 4 +It costs 0.004s +``` + +In addition, we can omit the timestamp column, and the system will use the current system timestamp as the timestamp of the data point. The sample code is as follows: + +```sql +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` + +**Note:** Timestamps must be specified when inserting multiple rows of data in a SQL. + +### 1.2 Insert Data Into Aligned Timeseries + +To insert data into a group of aligned time series, we only need to add the `ALIGNED` keyword in SQL, and others are similar. + +The sample code is as follows: + +```sql +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +The result is shown below. The query result shows that the insertion statements are performed correctly. + +``` ++-----------------------------+--------------+--------------+ +| Time|root.sg1.d1.s1|root.sg1.d1.s2| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.001+08:00| 1| 1.0| +|1970-01-01T08:00:00.002+08:00| 2| 2.0| +|1970-01-01T08:00:00.003+08:00| 3| 3.0| ++-----------------------------+--------------+--------------+ +Total line number = 3 +It costs 0.004s +``` + +## 2. NATIVE API WRITE + +The Native API ( Session ) is the most widely used series of APIs of IoTDB, including multiple APIs, adapted to different data collection scenarios, with high performance and multi-language support. + +### 2.1 Multi-language API write + +#### Java + +Before writing via the Java API, you need to establish a connection, refer to [Java Native API](../API/Programming-Java-Native-API_timecho). +then refer to [ JAVA Data Manipulation Interface (DML) ](../API/Programming-Java-Native-API_timecho#insert) + +#### Python + +Refer to [ Python Data Manipulation Interface (DML) ](../API/Programming-Python-Native-API_timecho#insert) + +#### C++ + +Refer to [ C++ Data Manipulation Interface (DML) ](../API/Programming-Cpp-Native-API.md#insert) + +#### Go + +Refer to [Go Native API](../API/Programming-Go-Native-API.md) + +## 3. REST API WRITE + +Refer to [insertTablet (v1)](../API/RestServiceV1_timecho#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_timecho#inserttablet) + +Example: + +```JSON +{ +      "timestamps": [ +            1, +            2, +            3 +      ], +      "measurements": [ +            "temperature", +            "status" +      ], +      "data_types": [ +            "FLOAT", +            "BOOLEAN" +      ], +      "values": [ +            [ +                  1.1, +                  2.2, +                  3.3 +            ], +            [ +                  false, +                  true, +                  true +            ] +      ], +      "is_aligned": false, +      "device": "root.ln.wf01.wt01" +} +``` + +## 4. MQTT WRITE + +Refer to [Built-in MQTT Service](../API/Programming-MQTT.md#built-in-mqtt-service) + +## 5. BATCH DATA LOAD + +In different scenarios, the IoTDB provides a variety of methods for importing data in batches. This section describes the two most common methods for importing data in CSV format and TsFile format. + +### 5.1 TsFile Batch Load + +TsFile is the file format of time series used in IoTDB. You can directly import one or more TsFile files with time series into another running IoTDB instance through tools such as CLI. For details, see [Data Import](../Tools-System/Data-Import-Tool_timecho). + +### 5.2 CSV Batch Load + +CSV stores table data in plain text. You can write multiple formatted data into a CSV file and import the data into the IoTDB in batches. Before importing data, you are advised to create the corresponding metadata in the IoTDB. Don't worry if you forget to create one, the IoTDB can automatically infer the data in the CSV to its corresponding data type, as long as you have a unique data type for each column. In addition to a single file, the tool supports importing multiple CSV files as folders and setting optimization parameters such as time precision. For details, see [Data Import](../Tools-System/Data-Import-Tool_timecho). + +## 6. SCHEMALESS WRITING +In IoT scenarios, the types and quantities of devices may dynamically increase or decrease over time, and different devices may generate data with varying fields (e.g., temperature, humidity, status codes). Additionally, businesses often require rapid deployment and flexible integration of new devices without cumbersome predefined processes. Therefore, unlike traditional time-series databases that typically require predefining data models, IoTDB supports schema-less writing, where the database automatically identifies and registers the necessary metadata during data writing, enabling automatic modeling. + +Users can either use CLI `INSERT` statements or native APIs to write data in real-time, either in batches or row-by-row, for single or multiple devices. Alternatively, they can import historical data in formats such as CSV or TsFile using import tools, during which metadata like time series, data types, and compression encoding methods are automatically created. + + + diff --git a/src/UserGuide/latest/QuickStart/QuickStart_apache.md b/src/UserGuide/latest/QuickStart/QuickStart_apache.md index ea209fa53..131c0b882 100644 --- a/src/UserGuide/latest/QuickStart/QuickStart_apache.md +++ b/src/UserGuide/latest/QuickStart/QuickStart_apache.md @@ -53,9 +53,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Introduction to SQL syntax[SQL syntax](../Basic-Concept/Operate-Metadata_apache.md) -2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data) +2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data_apache) -3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data.md) +3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data_apache) 4. Other advanced features: In addition to common functions such as writing and querying in databases, IoTDB also supports "Data Synchronisation、Stream Framework、Database Administration " and other functions, specific usage methods can be found in the specific document: @@ -63,9 +63,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Stream Framework: [Stream Framework](../User-Manual/Streaming_apache.md) - - Authority Management:[Authority Management](../User-Manual/Authority-Management.md) + - Authority Management:[Authority Management](../User-Manual/Authority-Management_apache) -5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports [Java Native API](../API/Programming-Java-Native-API.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[C++ Native API](../API/Programming-Cpp-Native-API.md) ,For more API, please refer to the official website 【API】 and other chapters +5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports [Java Native API](../API/Programming-Java-Native-API_apache)、[Python Native API](../API/Programming-Python-Native-API_apache)、[C++ Native API](../API/Programming-Cpp-Native-API.md) ,For more API, please refer to the official website 【API】 and other chapters ## 3. What other convenient tools are available? @@ -73,9 +73,9 @@ In addition to its rich features, IoTDB also has a comprehensive range of tools - Benchmark Tool: IoT benchmark is a time series database benchmark testing tool developed based on Java and big data environments, developed and open sourced by the School of Software at Tsinghua University. It supports multiple writing and querying methods, can store test information and results for further query or analysis, and supports integration with Tableau to visualize test results. For specific usage instructions, please refer to: [Benchmark Tool](../Tools-System/Benchmark.md) - - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool.md) + - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool_apache) - - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool.md) + - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool_apache) ## 4. Want to Learn More About the Technical Details? diff --git a/src/UserGuide/latest/QuickStart/QuickStart_timecho.md b/src/UserGuide/latest/QuickStart/QuickStart_timecho.md index 47b6e7d76..89e04adc7 100644 --- a/src/UserGuide/latest/QuickStart/QuickStart_timecho.md +++ b/src/UserGuide/latest/QuickStart/QuickStart_timecho.md @@ -60,9 +60,9 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Introduction to SQL syntax[SQL syntax](../Basic-Concept/Operate-Metadata_timecho.md) -2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data) +2. Write Data: In terms of data writing, IoTDB provides multiple ways to insert real-time data. Please refer to the basic data writing operations for details [Write Data](../Basic-Concept/Write-Data_timecho) -3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data.md) +3. Query Data: IoTDB provides rich data query functions. Please refer to the basic introduction of data query [Query Data](../Basic-Concept/Query-Data_timecho) 4. Other advanced features: In addition to common functions such as writing and querying in databases, IoTDB also supports "Data Synchronisation、Stream Framework、Security Management、Database Administration、AI Capability"and other functions, specific usage methods can be found in the specific document: @@ -72,11 +72,11 @@ This guide will assist you in quickly installing and deploying IoTDB. You can qu - Security Management: [Security Management](../User-Manual/White-List_timecho.md) - - Database Administration: [Database Administration](../User-Manual/Authority-Management.md) + - Database Administration: [Database Administration](../User-Manual/Authority-Management_timecho) - AI Capability :[AI Capability](../AI-capability/AINode_timecho.md) -5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports[ Java Native API](../API/Programming-Java-Native-API.md)、[Python Native API](../API/Programming-Python-Native-API.md)、[C++ Native API](../API/Programming-Cpp-Native-API.md)、[Go Native API](../API/Programming-Go-Native-API.md), For more API, please refer to the official website 【API】 and other chapters +5. API: IoTDB provides multiple application programming interfaces (API) for developers to interact with IoTDB in their applications, and currently supports[ Java Native API](../API/Programming-Java-Native-API_timecho)、[Python Native API](../API/Programming-Python-Native-API_timecho)、[C++ Native API](../API/Programming-Cpp-Native-API.md)、[Go Native API](../API/Programming-Go-Native-API.md), For more API, please refer to the official website 【API】 and other chapters ## 3. What other convenient tools are available? @@ -88,9 +88,9 @@ In addition to its rich features, IoTDB also has a comprehensive range of tools - Benchmark Tool: IoT benchmark is a time series database benchmark testing tool developed based on Java and big data environments, developed and open sourced by the School of Software at Tsinghua University. It supports multiple writing and querying methods, can store test information and results for further query or analysis, and supports integration with Tableau to visualize test results. For specific usage instructions, please refer to: [Benchmark Tool](../Tools-System/Benchmark.md) - - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool.md) + - Data Import Script: For different scenarios, IoTDB provides users with multiple ways to batch import data. For specific usage instructions, please refer to: [Data Import](../Tools-System/Data-Import-Tool_timecho) - - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool.md) + - Data Export Script: For different scenarios, IoTDB provides users with multiple ways to batch export data. For specific usage instructions, please refer to: [Data Export](../Tools-System/Data-Export-Tool_timecho) ## 4. Want to Learn More About the Technical Details? diff --git a/src/UserGuide/latest/SQL-Manual/SQL-Manual.md b/src/UserGuide/latest/SQL-Manual/SQL-Manual_apache.md similarity index 99% rename from src/UserGuide/latest/SQL-Manual/SQL-Manual.md rename to src/UserGuide/latest/SQL-Manual/SQL-Manual_apache.md index 194ef0ccd..fccf82926 100644 --- a/src/UserGuide/latest/SQL-Manual/SQL-Manual.md +++ b/src/UserGuide/latest/SQL-Manual/SQL-Manual_apache.md @@ -409,7 +409,7 @@ IoTDB> count devices root.ln.** ### 5.1 Insert Data -For more details, see document [Write-Data](../Basic-Concept/Write-Data). +For more details, see document [Write-Data](../Basic-Concept/Write-Data_apache). #### Use of INSERT Statements @@ -444,7 +444,7 @@ IoTDB > select * from root.sg1.d1 ### 5.2 Load External TsFile Tool -For more details, see document [Data Import](../Tools-System/Data-Import-Tool.md). +For more details, see document [Data Import](../Tools-System/Data-Import-Tool_apache). #### Load with SQL @@ -471,7 +471,7 @@ For more details, see document [Data Import](../Tools-System/Data-Import-Tool.md ## 6. DELETE DATA -For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data). +For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data_apache). ### 6.1 Delete Single Timeseries @@ -508,7 +508,7 @@ IoTDB > DELETE PARTITION root.ln 0,1,2 ## 7. QUERY DATA -For more details, see document [Query-Data](../Basic-Concept/Query-Data.md). +For more details, see document [Query-Data](../Basic-Concept/Query-Data_apache). ```sql SELECT [LAST] selectExpr [, selectExpr] ... diff --git a/src/UserGuide/latest/SQL-Manual/SQL-Manual_timecho.md b/src/UserGuide/latest/SQL-Manual/SQL-Manual_timecho.md new file mode 100644 index 000000000..a46f271c3 --- /dev/null +++ b/src/UserGuide/latest/SQL-Manual/SQL-Manual_timecho.md @@ -0,0 +1,1759 @@ + + +# SQL Manual + +## 1. DATABASE MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 1.1 Create Database + +```sql +IoTDB > create database root.ln +IoTDB > create database root.sgcc +``` + +### 1.2 Show Databases + +```sql +IoTDB> SHOW DATABASES +IoTDB> SHOW DATABASES root.** +``` + +### 1.3 Delete Database + +```sql +IoTDB > DELETE DATABASE root.ln +IoTDB > DELETE DATABASE root.sgcc +// delete all data, all timeseries and all databases +IoTDB > DELETE DATABASE root.** +``` + +### 1.4 Count Databases + +```sql +IoTDB> count databases +IoTDB> count databases root.* +IoTDB> count databases root.sgcc.* +IoTDB> count databases root.sgcc +``` + +### 1.5 Setting up heterogeneous databases (Advanced operations) + +#### Set heterogeneous parameters when creating a Database + +```sql +CREATE DATABASE root.db WITH SCHEMA_REPLICATION_FACTOR=1, DATA_REPLICATION_FACTOR=3, SCHEMA_REGION_GROUP_NUM=1, DATA_REGION_GROUP_NUM=2; +``` + +#### Adjust heterogeneous parameters at run time + +```sql +ALTER DATABASE root.db WITH SCHEMA_REGION_GROUP_NUM=1, DATA_REGION_GROUP_NUM=2; +``` + +#### Show heterogeneous databases + +```sql +SHOW DATABASES DETAILS +``` + +### 1.6 TTL + +#### Set TTL + +```sql +IoTDB> set ttl to root.ln 3600000 +IoTDB> set ttl to root.sgcc.** 3600000 +IoTDB> set ttl to root.** 3600000 +``` + +#### Unset TTL + +```sql +IoTDB> unset ttl from root.ln +IoTDB> unset ttl from root.sgcc.** +IoTDB> unset ttl from root.** +``` + +#### Show TTL + +```sql +IoTDB> SHOW ALL TTL +IoTDB> SHOW TTL ON StorageGroupNames +IoTDB> SHOW DEVICES +``` + +## 2. DEVICE TEMPLATE + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +![img](/img/%E6%A8%A1%E6%9D%BF.png) + + + + + +![img](/img/templateEN.jpg) + +### 2.1 Create Device Template + +**Example 1:** Create a template containing two non-aligned timeseires + +```shell +IoTDB> create device template t1 (temperature FLOAT, status BOOLEAN) +``` + +**Example 2:** Create a template containing a group of aligned timeseires + +```shell +IoTDB> create device template t2 aligned (lat FLOAT, lon FLOAT) +``` + +The` lat` and `lon` measurements are aligned. + +### 2.2 Set Device Template + +```sql +IoTDB> set device template t1 to root.sg1.d1 +``` + +### 2.3 Activate Device Template + +```sql +IoTDB> set device template t1 to root.sg1.d1 +IoTDB> set device template t2 to root.sg1.d2 +IoTDB> create timeseries using device template on root.sg1.d1 +IoTDB> create timeseries using device template on root.sg1.d2 +``` + +### 2.4 Show Device Template + +```sql +IoTDB> show device templates +IoTDB> show nodes in device template t1 +IoTDB> show paths set device template t1 +IoTDB> show paths using device template t1 +``` + +### 2.5 Deactivate Device Template + +```sql +IoTDB> delete timeseries of device template t1 from root.sg1.d1 +IoTDB> deactivate device template t1 from root.sg1.d1 +IoTDB> delete timeseries of device template t1 from root.sg1.*, root.sg2.* +IoTDB> deactivate device template t1 from root.sg1.*, root.sg2.* +``` + +### 2.6 Unset Device Template + +```sql +IoTDB> unset device template t1 from root.sg1.d1 +``` + +### 2.7 Drop Device Template + +```sql +IoTDB> drop device template t1 +``` + +### 2.8 Alter Device Template + +```sql +IoTDB> alter device template t1 add (speed FLOAT) +``` + +## 3. TIMESERIES MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 3.1 Create Timeseries + +```sql +IoTDB > create timeseries root.ln.wf01.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.ln.wf01.wt01.temperature with datatype=FLOAT +IoTDB > create timeseries root.ln.wf02.wt02.hardware with datatype=TEXT +IoTDB > create timeseries root.ln.wf02.wt02.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.temperature with datatype=FLOAT +``` + +- From v0.13, you can use a simplified version of the SQL statements to create timeseries: + +```sql +IoTDB > create timeseries root.ln.wf01.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.ln.wf01.wt01.temperature with datatype=FLOAT +IoTDB > create timeseries root.ln.wf02.wt02.hardware with datatype=TEXT +IoTDB > create timeseries root.ln.wf02.wt02.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.status with datatype=BOOLEAN +IoTDB > create timeseries root.sgcc.wf03.wt01.temperature with datatype=FLOAT +``` + +- Notice that when in the CREATE TIMESERIES statement the encoding method conflicts with the data type, the system gives the corresponding error prompt as shown below: + +```sql +IoTDB > create timeseries root.ln.wf02.wt02.status WITH DATATYPE=BOOLEAN +error: encoding TS_2DIFF does not support BOOLEAN +``` + +### 3.2 Create Aligned Timeseries + +```sql +IoTDB> CREATE ALIGNED TIMESERIES root.ln.wf01.GPS(latitude FLOAT , longitude FLOAT) +``` + +### 3.3 Delete Timeseries + +```sql +IoTDB> delete timeseries root.ln.wf01.wt01.status +IoTDB> delete timeseries root.ln.wf01.wt01.temperature, root.ln.wf02.wt02.hardware +IoTDB> delete timeseries root.ln.wf02.* +IoTDB> drop timeseries root.ln.wf02.* +``` + +### 3.4 Show Timeseries + +```sql +IoTDB> show timeseries root.** +IoTDB> show timeseries root.ln.** +IoTDB> show timeseries root.ln.** limit 10 offset 10 +IoTDB> show timeseries root.ln.** where timeseries contains 'wf01.wt' +IoTDB> show timeseries root.ln.** where dataType=FLOAT +``` + +### 3.5 Count Timeseries + +```sql +IoTDB > COUNT TIMESERIES root.** +IoTDB > COUNT TIMESERIES root.ln.** +IoTDB > COUNT TIMESERIES root.ln.*.*.status +IoTDB > COUNT TIMESERIES root.ln.wf01.wt01.status +IoTDB > COUNT TIMESERIES root.** WHERE TIMESERIES contains 'sgcc' +IoTDB > COUNT TIMESERIES root.** WHERE DATATYPE = INT64 +IoTDB > COUNT TIMESERIES root.** WHERE TAGS(unit) contains 'c' +IoTDB > COUNT TIMESERIES root.** WHERE TAGS(unit) = 'c' +IoTDB > COUNT TIMESERIES root.** WHERE TIMESERIES contains 'sgcc' group by level = 1 +IoTDB > COUNT TIMESERIES root.** GROUP BY LEVEL=1 +IoTDB > COUNT TIMESERIES root.ln.** GROUP BY LEVEL=2 +IoTDB > COUNT TIMESERIES root.ln.wf01.* GROUP BY LEVEL=2 +``` + +### 3.6 Tag and Attribute Management + +```sql +create timeseries root.turbine.d1.s1(temprature) with datatype=FLOAT tags(tag1=v1, tag2=v2) attributes(attr1=v1, attr2=v2) +``` + +* Rename the tag/attribute key + +```SQL +ALTER timeseries root.turbine.d1.s1 RENAME tag1 TO newTag1 +``` + +* Reset the tag/attribute value + +```SQL +ALTER timeseries root.turbine.d1.s1 SET newTag1=newV1, attr1=newV1 +``` + +* Delete the existing tag/attribute + +```SQL +ALTER timeseries root.turbine.d1.s1 DROP tag1, tag2 +``` + +* Add new tags + +```SQL +ALTER timeseries root.turbine.d1.s1 ADD TAGS tag3=v3, tag4=v4 +``` + +* Add new attributes + +```SQL +ALTER timeseries root.turbine.d1.s1 ADD ATTRIBUTES attr3=v3, attr4=v4 +``` + +* Upsert alias, tags and attributes + +> add alias or a new key-value if the alias or key doesn't exist, otherwise, update the old one with new value. + +```SQL +ALTER timeseries root.turbine.d1.s1 UPSERT ALIAS=newAlias TAGS(tag3=v3, tag4=v4) ATTRIBUTES(attr3=v3, attr4=v4) +``` + +* Show timeseries using tags. Use TAGS(tagKey) to identify the tags used as filter key + +```SQL +SHOW TIMESERIES (<`PathPattern`>)? timeseriesWhereClause +``` + +returns all the timeseries information that satisfy the where condition and match the pathPattern. SQL statements are as follows: + +```SQL +ALTER timeseries root.ln.wf02.wt02.hardware ADD TAGS unit=c +ALTER timeseries root.ln.wf02.wt02.status ADD TAGS description=test1 +show timeseries root.ln.** where TAGS(unit)='c' +show timeseries root.ln.** where TAGS(description) contains 'test1' +``` + +- count timeseries using tags + +```SQL +COUNT TIMESERIES (<`PathPattern`>)? timeseriesWhereClause +COUNT TIMESERIES (<`PathPattern`>)? timeseriesWhereClause GROUP BY LEVEL= +``` + +returns all the number of timeseries that satisfy the where condition and match the pathPattern. SQL statements are as follows: + +```SQL +count timeseries +count timeseries root.** where TAGS(unit)='c' +count timeseries root.** where TAGS(unit)='c' group by level = 2 +``` + +create aligned timeseries + +```SQL +create aligned timeseries root.sg1.d1(s1 INT32 tags(tag1=v1, tag2=v2) attributes(attr1=v1, attr2=v2), s2 DOUBLE tags(tag3=v3, tag4=v4) attributes(attr3=v3, attr4=v4)) +``` + +The execution result is as follows: + +```SQL +IoTDB> show timeseries ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +| timeseries|alias| database|dataType|encoding|compression| tags| attributes|deadband|deadband parameters| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +|root.sg1.d1.s1| null| root.sg1| INT32| RLE| SNAPPY|{"tag1":"v1","tag2":"v2"}|{"attr2":"v2","attr1":"v1"}| null| null| +|root.sg1.d1.s2| null| root.sg1| DOUBLE| GORILLA| SNAPPY|{"tag4":"v4","tag3":"v3"}|{"attr4":"v4","attr3":"v3"}| null| null| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +``` + +Support query: + +```SQL +IoTDB> show timeseries where TAGS(tag1)='v1' ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +| timeseries|alias| database|dataType|encoding|compression| tags| attributes|deadband|deadband parameters| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +|root.sg1.d1.s1| null| root.sg1| INT32| RLE| SNAPPY|{"tag1":"v1","tag2":"v2"}|{"attr2":"v2","attr1":"v1"}| null| null| ++--------------+-----+-------------+--------+--------+-----------+-------------------------+---------------------------+--------+-------------------+ +``` + +The above operations are supported for timeseries tag, attribute updates, etc. + +## 4. NODE MANAGEMENT + +For more details, see document [Operate-Metadata](../Basic-Concept/Operate-Metadata.md). + +### 4.1 Show Child Paths + +```SQL +SHOW CHILD PATHS pathPattern +``` + +### 4.2 Show Child Nodes + +```SQL +SHOW CHILD NODES pathPattern +``` + +### 4.3 Count Nodes + +```SQL +IoTDB > COUNT NODES root.** LEVEL=2 +IoTDB > COUNT NODES root.ln.** LEVEL=2 +IoTDB > COUNT NODES root.ln.wf01.** LEVEL=3 +IoTDB > COUNT NODES root.**.temperature LEVEL=3 +``` + +### 4.4 Show Devices + +```SQL +IoTDB> show devices +IoTDB> show devices root.ln.** +IoTDB> show devices root.ln.** where device contains 't' +IoTDB> show devices with database +IoTDB> show devices root.ln.** with database +``` + +### 4.5 Count Devices + +```SQL +IoTDB> show devices +IoTDB> count devices +IoTDB> count devices root.ln.** +``` + +## 5. INSERT & LOAD DATA + +### 5.1 Insert Data + +For more details, see document [Write-Data](../Basic-Concept/Write-Data_timecho). + +#### Use of INSERT Statements + +- Insert Single Timeseries + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +- Insert Multiple Timeseries + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (2, false, 'v2') +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +- Use the Current System Timestamp as the Timestamp of the Data Point + +```SQL +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` + +#### Insert Data Into Aligned Timeseries + +```SQL +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +### 5.2 Load External TsFile Tool + +For more details, see document [Data Import](../Tools-System/Data-Import-Tool_timecho). + +#### Load with SQL + +1. Load a single tsfile by specifying a file path (absolute path). + +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile'` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' sglevel=1` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' onSuccess=delete` +- `load '/Users/Desktop/data/1575028885956-101-0.tsfile' sglevel=1 onSuccess=delete` + + +2. Load a batch of files by specifying a folder path (absolute path). + +- `load '/Users/Desktop/data'` +- `load '/Users/Desktop/data' sglevel=1` +- `load '/Users/Desktop/data' onSuccess=delete` +- `load '/Users/Desktop/data' sglevel=1 onSuccess=delete` + +#### Load with Script + +``` +./load-rewrite.bat -f D:\IoTDB\data -h 192.168.0.101 -p 6667 -u root -pw root +``` + +## 6. DELETE DATA + +For more details, see document [Write-Delete-Data](../Basic-Concept/Write-Data_timecho). + +### 6.1 Delete Single Timeseries + +```sql +IoTDB > delete from root.ln.wf02.wt02.status where time<=2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.status where time>=2017-01-01T00:00:00 and time<=2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.status where time < 10 +IoTDB > delete from root.ln.wf02.wt02.status where time <= 10 +IoTDB > delete from root.ln.wf02.wt02.status where time < 20 and time > 10 +IoTDB > delete from root.ln.wf02.wt02.status where time <= 20 and time >= 10 +IoTDB > delete from root.ln.wf02.wt02.status where time > 20 +IoTDB > delete from root.ln.wf02.wt02.status where time >= 20 +IoTDB > delete from root.ln.wf02.wt02.status where time = 20 +IoTDB > delete from root.ln.wf02.wt02.status where time > 4 or time < 0 +Msg: 303: Check metadata error: For delete statement, where clause can only contain atomic +expressions like : time > XXX, time <= XXX, or two atomic expressions connected by 'AND' +IoTDB > delete from root.ln.wf02.wt02.status +``` + +### 6.2 Delete Multiple Timeseries + +```sql +IoTDB > delete from root.ln.wf02.wt02 where time <= 2017-11-01T16:26:00; +IoTDB > delete from root.ln.wf02.wt02.* where time <= 2017-11-01T16:26:00; +IoTDB> delete from root.ln.wf03.wt02.status where time < now() +Msg: The statement is executed successfully. +``` + +### 6.3 Delete Time Partition (experimental) + +```sql +IoTDB > DELETE PARTITION root.ln 0,1,2 +``` + +## 7. QUERY DATA + +For more details, see document [Query-Data](../Basic-Concept/Query-Data_timecho). + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... ) | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ select temperature from root.ln.wf01.wt01 where time < 2017-11-01T00:08:00.000 +``` + +#### Select Multiple Columns of Data Based on a Time Interval + +```sql +IoTDB > select status, temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +#### Select Multiple Columns of Data for the Same Device According to Multiple Time Intervals + +```sql +IoTDB > select status,temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +#### Choose Multiple Columns of Data for Different Devices According to Multiple Time Intervals + +```sql +IoTDB > select wf01.wt01.status,wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +#### Order By Time Query + +```sql +IoTDB > select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +### 7.2 `SELECT` CLAUSE + +#### Use Alias + +```sql +IoTDB > select s1 as temperature, s2 as speed from root.ln.wf01.wt01; +``` + +#### Nested Expressions + +##### Nested Expressions with Time Series Query + +```sql +IoTDB > select a, + b, + ((a + 1) * 2 - 1) % 2 + 1.5, + sin(a + sin(a + sin(b))), + -(a + b) * (sin(a + b) * sin(a + b) + cos(a + b) * cos(a + b)) + 1 +from root.sg1; + +IoTDB > select (a + b) * 2 + sin(a) from root.sg + +IoTDB > select (a + *) / 2 from root.sg1 + +IoTDB > select (a + b) * 3 from root.sg, root.ln +``` + +##### Nested Expressions query with aggregations + +```sql +IoTDB > select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) +from root.ln.wf01.wt01; + +IoTDB > select avg(*), + (avg(*) + 1) * 3 / 2 -1 +from root.sg1 + +IoTDB > select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) as custom_sum +from root.ln.wf01.wt01 +GROUP BY([10, 90), 10ms); +``` + +#### Last Query + +```sql +IoTDB > select last status from root.ln.wf01.wt01 +IoTDB > select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 +IoTDB > select last * from root.ln.wf01.wt01 order by timeseries desc; +IoTDB > select last * from root.ln.wf01.wt01 order by dataType desc; +``` + +### 7.3 `WHERE` CLAUSE + +#### Time Filter + +```sql +IoTDB > select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; +IoTDB > select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; +IoTDB > select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +#### Value Filter + +```sql +IoTDB > select temperature from root.sg1.d1 where temperature > 36.5; +IoTDB > select status from root.sg1.d1 where status = true; +IoTDB > select temperature from root.sg1.d1 where temperature between 36.5 and 40; +IoTDB > select temperature from root.sg1.d1 where temperature not between 36.5 and 40; +IoTDB > select code from root.sg1.d1 where code in ('200', '300', '400', '500'); +IoTDB > select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); +IoTDB > select code from root.sg1.d1 where temperature is null; +IoTDB > select code from root.sg1.d1 where temperature is not null; +``` + +#### Fuzzy Query + +- Fuzzy matching using `Like` + +```sql +IoTDB > select * from root.sg.d1 where value like '%cc%' +IoTDB > select * from root.sg.device where value like '_b_' +``` + +- Fuzzy matching using `Regexp` + +```sql +IoTDB > select * from root.sg.d1 where value regexp '^[A-Za-z]+$' +IoTDB > select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 +``` + +### 7.4 `GROUP BY` CLAUSE + +- Aggregate By Time without Specifying the Sliding Step Length + +```sql +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` + +- Aggregate By Time Specifying the Sliding Step Length + +```sql +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +- Aggregate by Natural Month + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +IoTDB > select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +- Left Open And Right Close Range + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +- Aggregation By Variation + +```sql +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +IoTDB > select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` + +- Aggregation By Condition + +```sql +IoTDB > select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=true) +IoTDB > select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoringNull=false) +``` + +- Aggregation By Session + +```sql +IoTDB > select __endTime,count(*) from root.** group by session(1d) +IoTDB > select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` + +- Aggregation By Count + +```sql +IoTDB > select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +IoTDB > select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` + +- Aggregation By Level + +```sql +IoTDB > select count(status) from root.** group by level = 1 +IoTDB > select count(status) from root.** group by level = 3 +IoTDB > select count(status) from root.** group by level = 1, 3 +IoTDB > select max_value(temperature) from root.** group by level = 0 +IoTDB > select count(*) from root.ln.** group by level = 2 +``` + +- Aggregate By Time with Level Clause + +```sql +IoTDB > select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +IoTDB > select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +- Aggregation query by one single tag + +```sql +IoTDB > SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +- Aggregation query by multiple tags + +```sql +IoTDB > SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +- Downsampling Aggregation by tags based on Time Window + +```sql +IoTDB > SELECT avg(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +### 7.5 `HAVING` CLAUSE + +Correct: + +```sql +IoTDB > select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 1 +IoTDB > select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device +``` + +Incorrect: + +```sql +IoTDB > select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 +IoTDB > select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 +IoTDB > select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 +IoTDB > select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 +``` + +### 7.6 `FILL` CLAUSE + +#### `PREVIOUS` Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +#### `PREVIOUS` FILL and specify the fill timeout threshold +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous, 2m); +``` + +#### `LINEAR` Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +#### Constant Fill + +```sql +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +IoTDB > select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +### 7.7 `LIMIT` and `SLIMIT` CLAUSES (PAGINATION) + +#### Row Control over Query Results + +```sql +IoTDB > select status, temperature from root.ln.wf01.wt01 limit 10 +IoTDB > select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +IoTDB > select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time< 2017-11-01T00:12:00.000 limit 2 offset 3 +IoTDB > select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 5 offset 3 +``` + +#### Column Control over Query Results + +```sql +IoTDB > select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +IoTDB > select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +IoTDB > select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +#### Row and Column Control over Query Results + +```sql +IoTDB > select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +### 7.8 `ORDER BY` CLAUSE + +#### Order by in ALIGN BY TIME mode + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` + +#### Order by in ALIGN BY DEVICE mode + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +IoTDB > select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` + +#### Order by arbitrary expressions + +```sql +IoTDB > select score from root.** order by score desc align by device +IoTDB > select score,total from root.one order by base+score+bonus desc +IoTDB > select score,total from root.one order by total desc +IoTDB > select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +IoTDB > select min_value(total) from root.** order by min_value(total) asc align by device +IoTDB > select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +IoTDB > select score from root.** order by device asc, score desc, time asc align by device +``` + +### 7.9 `ALIGN BY` CLAUSE + +#### Align by Device + +```sql +IoTDB > select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +### 7.10 `INTO` CLAUSE (QUERY WRITE-BACK) + +```sql +IoTDB > select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; +IoTDB > select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); +IoTDB > select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +IoTDB > select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; +``` + +- Using variable placeholders: + +```sql +IoTDB > select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; + +IoTDB > select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; + +IoTDB > select * into root.sg_bk.::(::) from root.sg.**; + +IoTDB > select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; + +IoTDB > select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; + +IoTDB > select * into ::(backup_${4}) from root.sg.** align by device; + +IoTDB > select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` + +## 8. Maintennance +Generate the corresponding query plan: +``` +explain select s1,s2 from root.sg.d1 +``` +Execute the corresponding SQL, analyze the execution and output: +``` +explain analyze select s1,s2 from root.sg.d1 order by s1 +``` +## 9. OPERATOR + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md). + +### 9.1 Arithmetic Operators + +For details and examples, see the document [Arithmetic Operators and Functions](./Operator-and-Expression.md#arithmetic-operators). + +```sql +select s1, - s1, s2, + s2, s1 + s2, s1 - s2, s1 * s2, s1 / s2, s1 % s2 from root.sg.d1 +``` + +### 9.2 Comparison Operators + +For details and examples, see the document [Comparison Operators and Functions](./Operator-and-Expression.md#comparison-operators). + +```sql +# Basic comparison operators +select a, b, a > 10, a <= b, !(a <= b), a > 10 && a > b from root.test; + +# `BETWEEN ... AND ...` operator +select temperature from root.sg1.d1 where temperature between 36.5 and 40; +select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + +# Fuzzy matching operator: Use `Like` for fuzzy matching +select * from root.sg.d1 where value like '%cc%' +select * from root.sg.device where value like '_b_' + +# Fuzzy matching operator: Use `Regexp` for fuzzy matching +select * from root.sg.d1 where value regexp '^[A-Za-z]+$' +select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 +select b, b like '1%', b regexp '[0-2]' from root.test; + +# `IS NULL` operator +select code from root.sg1.d1 where temperature is null; +select code from root.sg1.d1 where temperature is not null; + +# `IN` operator +select code from root.sg1.d1 where code in ('200', '300', '400', '500'); +select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); +select a, a in (1, 2) from root.test; +``` + +### 9.3 Logical Operators + +For details and examples, see the document [Logical Operators](./Operator-and-Expression.md#logical-operators). + +```sql +select a, b, a > 10, a <= b, !(a <= b), a > 10 && a > b from root.test; +``` + +## 10. BUILT-IN FUNCTIONS + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md#built-in-functions). + +### 10.1 Aggregate Functions + +For details and examples, see the document [Aggregate Functions](./Operator-and-Expression.md#aggregate-functions). + +```sql +select count(status) from root.ln.wf01.wt01; + +select count_if(s1=0 & s2=0, 3), count_if(s1=1 & s2=0, 3) from root.db.d1; +select count_if(s1=0 & s2=0, 3, 'ignoreNull'='false'), count_if(s1=1 & s2=0, 3, 'ignoreNull'='false') from root.db.d1; + +select time_duration(s1) from root.db.d1; +``` + +### 10.2 Arithmetic Functions + +For details and examples, see the document [Arithmetic Operators and Functions](./Operator-and-Expression.md#arithmetic-functions). + +```sql +select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000; +select s4,round(s4),round(s4,2),round(s4,-1) from root.sg1.d1; +``` + +### 10.3 Comparison Functions + +For details and examples, see the document [Comparison Operators and Functions](./Operator-and-Expression.md#comparison-functions). + +```sql +select ts, on_off(ts, 'threshold'='2') from root.test; +select ts, in_range(ts, 'lower'='2', 'upper'='3.1') from root.test; +``` + +### 10.4 String Processing Functions + +For details and examples, see the document [String Processing](./Operator-and-Expression.md#string-processing-functions). + +```sql +select s1, string_contains(s1, 's'='warn') from root.sg1.d4; +select s1, string_matches(s1, 'regex'='[^\\s]+37229') from root.sg1.d4; +select s1, length(s1) from root.sg1.d1 +select s1, locate(s1, "target"="1") from root.sg1.d1 +select s1, locate(s1, "target"="1", "reverse"="true") from root.sg1.d1 +select s1, startswith(s1, "target"="1") from root.sg1.d1 +select s1, endswith(s1, "target"="1") from root.sg1.d1 +select s1, s2, concat(s1, s2, "target1"="IoT", "target2"="DB") from root.sg1.d1 +select s1, s2, concat(s1, s2, "target1"="IoT", "target2"="DB", "series_behind"="true") from root.sg1.d1 +select s1, substring(s1 from 1 for 2) from root.sg1.d1 +select s1, replace(s1, 'es', 'tt') from root.sg1.d1 +select s1, upper(s1) from root.sg1.d1 +select s1, lower(s1) from root.sg1.d1 +select s3, trim(s3) from root.sg1.d1 +select s1, s2, strcmp(s1, s2) from root.sg1.d1 +select strreplace(s1, "target"=",", "replace"="/", "limit"="2") from root.test.d1 +select strreplace(s1, "target"=",", "replace"="/", "limit"="1", "offset"="1", "reverse"="true") from root.test.d1 +select regexmatch(s1, "regex"="\d+\.\d+\.\d+\.\d+", "group"="0") from root.test.d1 +select regexreplace(s1, "regex"="192\.168\.0\.(\d+)", "replace"="cluster-$1", "limit"="1") from root.test.d1 +select regexsplit(s1, "regex"=",", "index"="-1") from root.test.d1 +select regexsplit(s1, "regex"=",", "index"="3") from root.test.d1 +``` + +### 10.5 Data Type Conversion Function + +For details and examples, see the document [Data Type Conversion Function](./Operator-and-Expression.md#data-type-conversion-function). + +```sql +SELECT cast(s1 as INT32) from root.sg +``` + +### 10.6 Constant Timeseries Generating Functions + +For details and examples, see the document [Constant Timeseries Generating Functions](./Operator-and-Expression.md#constant-timeseries-generating-functions). + +```sql +select s1, s2, const(s1, 'value'='1024', 'type'='INT64'), pi(s2), e(s1, s2) from root.sg1.d1; +``` + +### 10.7 Selector Functions + +For details and examples, see the document [Selector Functions](./Operator-and-Expression.md#selector-functions). + +```sql +select s1, top_k(s1, 'k'='2'), bottom_k(s1, 'k'='2') from root.sg1.d2 where time > 2020-12-10T20:36:15.530+08:00; +``` + +### 10.8 Continuous Interval Functions + +For details and examples, see the document [Continuous Interval Functions](./Operator-and-Expression.md#continuous-interval-functions). + +```sql +select s1, zero_count(s1), non_zero_count(s2), zero_duration(s3), non_zero_duration(s4) from root.sg.d2; +``` + +### 10.9 Variation Trend Calculation Functions + +For details and examples, see the document [Variation Trend Calculation Functions](./Operator-and-Expression.md#variation-trend-calculation-functions). + +```sql +select s1, time_difference(s1), difference(s1), non_negative_difference(s1), derivative(s1), non_negative_derivative(s1) from root.sg1.d1 limit 5 offset 1000; + +SELECT DIFF(s1), DIFF(s2) from root.test; +SELECT DIFF(s1, 'ignoreNull'='false'), DIFF(s2, 'ignoreNull'='false') from root.test; +``` + +### 10.10 Sample Functions + +For details and examples, see the document [Sample Functions](./Operator-and-Expression.md#sample-functions). + +```sql +select equal_size_bucket_random_sample(temperature,'proportion'='0.1') as random_sample from root.ln.wf01.wt01; +select equal_size_bucket_agg_sample(temperature, 'type'='avg','proportion'='0.1') as agg_avg, equal_size_bucket_agg_sample(temperature, 'type'='max','proportion'='0.1') as agg_max, equal_size_bucket_agg_sample(temperature,'type'='min','proportion'='0.1') as agg_min, equal_size_bucket_agg_sample(temperature, 'type'='sum','proportion'='0.1') as agg_sum, equal_size_bucket_agg_sample(temperature, 'type'='extreme','proportion'='0.1') as agg_extreme, equal_size_bucket_agg_sample(temperature, 'type'='variance','proportion'='0.1') as agg_variance from root.ln.wf01.wt01; +select equal_size_bucket_m4_sample(temperature, 'proportion'='0.1') as M4_sample from root.ln.wf01.wt01; +select equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='avg', 'number'='2') as outlier_avg_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='stendis', 'number'='2') as outlier_stendis_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='cos', 'number'='2') as outlier_cos_sample, equal_size_bucket_outlier_sample(temperature, 'proportion'='0.1', 'type'='prenextdis', 'number'='2') as outlier_prenextdis_sample from root.ln.wf01.wt01; + +select M4(s1,'timeInterval'='25','displayWindowBegin'='0','displayWindowEnd'='100') from root.vehicle.d1 +select M4(s1,'windowSize'='10') from root.vehicle.d1 +``` + +### 10.11 Change Points Function + +For details and examples, see the document [Time-Series](./Operator-and-Expression.md#change-points-function). + +```sql +select change_points(s1), change_points(s2), change_points(s3), change_points(s4), change_points(s5), change_points(s6) from root.testChangePoints.d1 +``` + +## 11. DATA QUALITY FUNCTION LIBRARY + +For more details, see document [Operator-and-Expression](../SQL-Manual/UDF-Libraries.md). + +### 11.1 Data Quality + +For details and examples, see the document [Data-Quality](../SQL-Manual/UDF-Libraries.md#data-quality). + +```sql +# Completeness +select completeness(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select completeness(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Consistency +select consistency(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select consistency(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Timeliness +select timeliness(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select timeliness(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Validity +select Validity(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 +select Validity(s1,"window"="15") from root.test.d1 where time <= 2020-01-01 00:01:00 + +# Accuracy +select Accuracy(t1,t2,t3,m1,m2,m3) from root.test +``` + +### 11.2 Data Profiling + +For details and examples, see the document [Data-Profiling](../SQL-Manual/UDF-Libraries.md#data-profiling). + +```sql +# ACF +select acf(s1) from root.test.d1 where time <= 2020-01-01 00:00:05 + +# Distinct +select distinct(s2) from root.test.d2 + +# Histogram +select histogram(s1,"min"="1","max"="20","count"="10") from root.test.d1 + +# Integral +select integral(s1) from root.test.d1 where time <= 2020-01-01 00:00:10 +select integral(s1, "unit"="1m") from root.test.d1 where time <= 2020-01-01 00:00:10 + +# IntegralAvg +select integralavg(s1) from root.test.d1 where time <= 2020-01-01 00:00:10 + +# Mad +select mad(s0) from root.test +select mad(s0, "error"="0.01") from root.test + +# Median +select median(s0, "error"="0.01") from root.test + +# MinMax +select minmax(s1) from root.test + +# Mode +select mode(s2) from root.test.d2 + +# MvAvg +select mvavg(s1, "window"="3") from root.test + +# PACF +select pacf(s1, "lag"="5") from root.test + +# Percentile +select percentile(s0, "rank"="0.2", "error"="0.01") from root.test + +# Quantile +select quantile(s0, "rank"="0.2", "K"="800") from root.test + +# Period +select period(s1) from root.test.d3 + +# QLB +select QLB(s1) from root.test.d1 + +# Resample +select resample(s1,'every'='5m','interp'='linear') from root.test.d1 +select resample(s1,'every'='30m','aggr'='first') from root.test.d1 +select resample(s1,'every'='30m','start'='2021-03-06 15:00:00') from root.test.d1 + +# Sample +select sample(s1,'method'='reservoir','k'='5') from root.test.d1 +select sample(s1,'method'='isometric','k'='5') from root.test.d1 + +# Segment +select segment(s1, "error"="0.1") from root.test + +# Skew +select skew(s1) from root.test.d1 + +# Spline +select spline(s1, "points"="151") from root.test + +# Spread +select spread(s1) from root.test.d1 where time <= 2020-01-01 00:00:30 + +# Stddev +select stddev(s1) from root.test.d1 + +# ZScore +select zscore(s1) from root.test +``` + +### 11.3 Anomaly Detection + +For details and examples, see the document [Anomaly-Detection](../SQL-Manual/UDF-Libraries.md#anomaly-detection). + +```sql +# IQR +select iqr(s1) from root.test + +# KSigma +select ksigma(s1,"k"="1.0") from root.test.d1 where time <= 2020-01-01 00:00:30 + +# LOF +select lof(s1,s2) from root.test.d1 where time<1000 +select lof(s1, "method"="series") from root.test.d1 where time<1000 + +# MissDetect +select missdetect(s2,'minlen'='10') from root.test.d2 + +# Range +select range(s1,"lower_bound"="101.0","upper_bound"="125.0") from root.test.d1 where time <= 2020-01-01 00:00:30 + +# TwoSidedFilter +select TwoSidedFilter(s0, 'len'='5', 'threshold'='0.3') from root.test + +# Outlier +select outlier(s1,"r"="5.0","k"="4","w"="10","s"="5") from root.test + +# MasterTrain +select MasterTrain(lo,la,m_lo,m_la,'p'='3','eta'='1.0') from root.test + +# MasterDetect +select MasterDetect(lo,la,m_lo,m_la,model,'output_type'='repair','p'='3','k'='3','eta'='1.0') from root.test +select MasterDetect(lo,la,m_lo,m_la,model,'output_type'='anomaly','p'='3','k'='3','eta'='1.0') from root.test +``` + +### 11.4 Frequency Domain + +For details and examples, see the document [Frequency-Domain](../SQL-Manual/UDF-Libraries.md#frequency-domain-analysis). + +```sql +# Conv +select conv(s1,s2) from root.test.d2 + +# Deconv +select deconv(s3,s2) from root.test.d2 +select deconv(s3,s2,'result'='remainder') from root.test.d2 + +# DWT +select dwt(s1,"method"="haar") from root.test.d1 + +# FFT +select fft(s1) from root.test.d1 +select fft(s1, 'result'='real', 'compress'='0.99'), fft(s1, 'result'='imag','compress'='0.99') from root.test.d1 + +# HighPass +select highpass(s1,'wpass'='0.45') from root.test.d1 + +# IFFT +select ifft(re, im, 'interval'='1m', 'start'='2021-01-01 00:00:00') from root.test.d1 + +# LowPass +select lowpass(s1,'wpass'='0.45') from root.test.d1 + +# Envelope +select envelope(s1) from root.test.d1 +``` + +### 11.5 Data Matching + +For details and examples, see the document [Data-Matching](../SQL-Manual/UDF-Libraries.md#data-matching). + +```sql +# Cov +select cov(s1,s2) from root.test.d2 + +# DTW +select dtw(s1,s2) from root.test.d2 + +# Pearson +select pearson(s1,s2) from root.test.d2 + +# PtnSym +select ptnsym(s4, 'window'='5', 'threshold'='0') from root.test.d1 + +# XCorr +select xcorr(s1, s2) from root.test.d1 where time <= 2020-01-01 00:00:05 +``` + +### 11.6 Data Repairing + +For details and examples, see the document [Data-Repairing](../SQL-Manual/UDF-Libraries.md#data-repairing). + +```sql +# TimestampRepair +select timestamprepair(s1,'interval'='10000') from root.test.d2 +select timestamprepair(s1) from root.test.d2 + +# ValueFill +select valuefill(s1) from root.test.d2 +select valuefill(s1,"method"="previous") from root.test.d2 + +# ValueRepair +select valuerepair(s1) from root.test.d2 +select valuerepair(s1,'method'='LsGreedy') from root.test.d2 + +# MasterRepair +select MasterRepair(t1,t2,t3,m1,m2,m3) from root.test + +# SeasonalRepair +select seasonalrepair(s1,'period'=3,'k'=2) from root.test.d2 +select seasonalrepair(s1,'method'='improved','period'=3) from root.test.d2 +``` + +### 11.7 Series Discovery + +For details and examples, see the document [Series-Discovery](../SQL-Manual/UDF-Libraries.md#series-discovery). + +```sql +# ConsecutiveSequences +select consecutivesequences(s1,s2,'gap'='5m') from root.test.d1 +select consecutivesequences(s1,s2) from root.test.d1 + +# ConsecutiveWindows +select consecutivewindows(s1,s2,'length'='10m') from root.test.d1 +``` + +### 11.8 Machine Learning + +For details and examples, see the document [Machine-Learning](../SQL-Manual/UDF-Libraries.md#machine-learning). + +```sql +# AR +select ar(s0,"p"="2") from root.test.d0 + +# Representation +select representation(s0,"tb"="3","vb"="2") from root.test.d0 + +# RM +select rm(s0, s1,"tb"="3","vb"="2") from root.test.d0 +``` + +## 12. LAMBDA EXPRESSION + +For details and examples, see the document [Lambda](../SQL-Manual/UDF-Libraries.md#lambda-expression). + +```sql +select jexl(temperature, 'expr'='x -> {x + x}') as jexl1, jexl(temperature, 'expr'='x -> {x * 3}') as jexl2, jexl(temperature, 'expr'='x -> {x * x}') as jexl3, jexl(temperature, 'expr'='x -> {multiply(x, 100)}') as jexl4, jexl(temperature, st, 'expr'='(x, y) -> {x + y}') as jexl5, jexl(temperature, st, str, 'expr'='(x, y, z) -> {x + y + z}') as jexl6 from root.ln.wf01.wt01;``` +``` + +## 13. CONDITIONAL EXPRESSION + +For details and examples, see the document [Conditional Expressions](../SQL-Manual/UDF-Libraries.md#conditional-expressions). + +```sql +select T, P, case +when 1000=1050 then "bad temperature" +when P<=1000000 or P>=1100000 then "bad pressure" +end as `result` +from root.test1 + +select str, case +when str like "%cc%" then "has cc" +when str like "%dd%" then "has dd" +else "no cc and dd" end as `result` +from root.test2 + +select +count(case when x<=1 then 1 end) as `(-∞,1]`, +count(case when 1 +[RESAMPLE + [EVERY ] + [BOUNDARY ] + [RANGE [, end_time_offset]] +] +[TIMEOUT POLICY BLOCKED|DISCARD] +BEGIN + SELECT CLAUSE + INTO CLAUSE + FROM CLAUSE + [WHERE CLAUSE] + [GROUP BY([, ]) [, level = ]] + [HAVING CLAUSE] + [FILL ({PREVIOUS | LINEAR | constant} (, interval=DURATION_LITERAL)?)] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] +END +``` + +### 15.1 Configuring execution intervals + +```sql +CREATE CONTINUOUS QUERY cq1 +RESAMPLE EVERY 20s +BEGIN +SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) +END +``` + +### 15.2 Configuring time range for resampling + +```sql +CREATE CONTINUOUS QUERY cq2 +RESAMPLE RANGE 40s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) +END +``` + +### 15.3 Configuring execution intervals and CQ time ranges + +```sql +CREATE CONTINUOUS QUERY cq3 +RESAMPLE EVERY 20s RANGE 40s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) + FILL(100.0) +END +``` + +### 15.4 Configuring end_time_offset for CQ time range + +```sql +CREATE CONTINUOUS QUERY cq4 +RESAMPLE EVERY 20s RANGE 40s, 20s +BEGIN + SELECT max_value(temperature) + INTO root.ln.wf02.wt02(temperature_max), root.ln.wf02.wt01(temperature_max), root.ln.wf01.wt02(temperature_max), root.ln.wf01.wt01(temperature_max) + FROM root.ln.*.* + GROUP BY(10s) + FILL(100.0) +END +``` + +### 15.5 CQ without group by clause + +```sql +CREATE CONTINUOUS QUERY cq5 +RESAMPLE EVERY 20s +BEGIN + SELECT temperature + 1 + INTO root.precalculated_sg.::(temperature) + FROM root.ln.*.* + align by device +END +``` + +### 15.6 CQ Management + +#### Listing continuous queries + +```sql +SHOW (CONTINUOUS QUERIES | CQS) +``` + +#### Dropping continuous queries + +```sql +DROP (CONTINUOUS QUERY | CQ) +``` + +#### Altering continuous queries + +CQs can't be altered once they're created. To change a CQ, you must `DROP` and re`CREATE` it with the updated settings. + +## 16. USER-DEFINED FUNCTION (UDF) + +For more details, see document [Operator-and-Expression](../SQL-Manual/UDF-Libraries.md). + +### 16.1 UDF Registration + +```sql +CREATE FUNCTION AS (USING URI URI-STRING)? +``` + +### 16.2 UDF Deregistration + +```sql +DROP FUNCTION +``` + +### 16.3 UDF Queries + +```sql +SELECT example(*) from root.sg.d1 +SELECT example(s1, *) from root.sg.d1 +SELECT example(*, *) from root.sg.d1 + +SELECT example(s1, 'key1'='value1', 'key2'='value2'), example(*, 'key3'='value3') FROM root.sg.d1; +SELECT example(s1, s2, 'key1'='value1', 'key2'='value2') FROM root.sg.d1; + +SELECT s1, s2, example(s1, s2) FROM root.sg.d1; +SELECT *, example(*) FROM root.sg.d1 DISABLE ALIGN; +SELECT s1 * example(* / s1 + s2) FROM root.sg.d1; +SELECT s1, s2, s1 + example(s1, s2), s1 - example(s1 + example(s1, s2) / s2) FROM root.sg.d1; +``` + +### 16.4 Show All Registered UDFs + +```sql +SHOW FUNCTIONS +``` + +## 17. ADMINISTRATION MANAGEMENT + +For more details, see document [Operator-and-Expression](./Operator-and-Expression.md). + +### 17.1 SQL Statements + +- Create user (Requires MANAGE_USER permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- Delete user (Requires MANAGE_USER permission) + +```sql +DROP USER +eg: DROP USER user1 +``` + +- Create role (Requires MANAGE_ROLE permission) + +```sql +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- Delete role (Requires MANAGE_ROLE permission) + +```sql +DROP ROLE +eg: DROP ROLE role1 +``` + +- Grant role to user (Requires MANAGE_ROLE permission) + +```sql +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- Revoke role from user(Requires MANAGE_ROLE permission) + +```sql +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- List all user (Requires MANAGE_USER permission) + +```sql +LIST USER +``` + +- List all role (Requires MANAGE_ROLE permission) + +```sql +LIST ROLE +``` + +- List all users granted specific role.(Requires MANAGE_USER permission) + +```sql +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- List all role granted to specific user. + +```sql +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- List all privileges of user + +```sql +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; +``` + +- List all privileges of role + +```sql +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- Modify password + +```sql +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 17.2 Authorization and Deauthorization + + +```sql +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +```sql +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + + +#### Delete Time Partition (experimental) + +``` +Eg: IoTDB > DELETE PARTITION root.ln 0,1,2 +``` + +#### Continuous Query,CQ + +``` +Eg: IoTDB > CREATE CONTINUOUS QUERY cq1 BEGIN SELECT max_value(temperature) INTO temperature_max FROM root.ln.*.* GROUP BY time(10s) END +``` + +#### Maintenance Command + +- FLUSH + +``` +Eg: IoTDB > flush +``` + +- MERGE + +``` +Eg: IoTDB > MERGE +Eg: IoTDB > FULL MERGE +``` + +- CLEAR CACHE + +```sql +Eg: IoTDB > CLEAR CACHE +``` + +- START REPAIR DATA + +```sql +Eg: IoTDB > START REPAIR DATA +``` + +- STOP REPAIR DATA + +```sql +Eg: IoTDB > STOP REPAIR DATA +``` + +- SET SYSTEM TO READONLY / WRITABLE + +``` +Eg: IoTDB > SET SYSTEM TO READONLY / WRITABLE +``` + +- Query abort + +``` +Eg: IoTDB > KILL QUERY 1 +``` \ No newline at end of file diff --git a/src/UserGuide/latest/Technical-Insider/Encoding-and-Compression.md b/src/UserGuide/latest/Technical-Insider/Encoding-and-Compression.md index b71925665..f70a704d5 100644 --- a/src/UserGuide/latest/Technical-Insider/Encoding-and-Compression.md +++ b/src/UserGuide/latest/Technical-Insider/Encoding-and-Compression.md @@ -119,7 +119,7 @@ IoTDB allows you to specify the compression method of the column when creating a * LZMA2 -The specified syntax for compression is detailed in [Create Timeseries Statement](../SQL-Manual/SQL-Manual.md). +The specified syntax for compression is detailed in [Create Timeseries Statement](../SQL-Manual/SQL-Manual_timecho). ### 2.2 Compression Ratio Statistics diff --git a/src/UserGuide/latest/Tools-System/CLI_apache.md b/src/UserGuide/latest/Tools-System/CLI_apache.md index 5261ff35a..758846624 100644 --- a/src/UserGuide/latest/Tools-System/CLI_apache.md +++ b/src/UserGuide/latest/Tools-System/CLI_apache.md @@ -60,10 +60,10 @@ Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root The Windows system startup commands are as follows: ```shell -# Before version V2.0.4.x +# Before version V2.0.4 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x and later versions +# V2.0.4 and later versions Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root ``` diff --git a/src/UserGuide/latest/Tools-System/CLI_timecho.md b/src/UserGuide/latest/Tools-System/CLI_timecho.md index d2bf58f53..3a3807cb1 100644 --- a/src/UserGuide/latest/Tools-System/CLI_timecho.md +++ b/src/UserGuide/latest/Tools-System/CLI_timecho.md @@ -29,7 +29,7 @@ IoTDB provides Cli/shell tools for users to interact with IoTDB server in comman ## 1. Running Cli After installation, there is a default user in IoTDB: `root`, and the -default password is `root`. Users can use this username to try IoTDB Cli/Shell tool. The cli startup script is the `start-cli` file under the \$IOTDB\_HOME/bin folder. When starting the script, you need to specify the IP and PORT. (Make sure the IoTDB cluster is running properly when you use Cli/Shell tool to connect to it.) +default password is `TimechoDB@2021`(Before V2.0.6 it is `root`). Users can use this username to try IoTDB Cli/Shell tool. The cli startup script is the `start-cli` file under the \$IOTDB\_HOME/bin folder. When starting the script, you need to specify the IP and PORT. (Make sure the IoTDB cluster is running properly when you use Cli/Shell tool to connect to it.) Here is an example where the cluster is started locally and the user has not changed the running port. The default rpc port is 6667
@@ -40,7 +40,11 @@ You also can set your own environment variable at the front of the start script The Linux and MacOS system startup commands are as follows: ```shell +# Before version V2.0.6.x Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x and later versions +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` The Windows system startup commands are as follows: @@ -49,8 +53,11 @@ The Windows system startup commands are as follows: # Before version V2.0.4.x Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x and later versions +# V2.0.4.x and later versions, before version V2.0.6.x Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x and later versions +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` After operating these commands, the cli can be started successfully. The successful status will be as follows: diff --git a/src/UserGuide/latest/Tools-System/Data-Export-Tool.md b/src/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md similarity index 98% rename from src/UserGuide/latest/Tools-System/Data-Export-Tool.md rename to src/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md index 5601f3b8a..af564f3ec 100644 --- a/src/UserGuide/latest/Tools-System/Data-Export-Tool.md +++ b/src/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md @@ -79,7 +79,7 @@ The data export tool, export-data.sh (Unix/OS X) or export-data.bat (Windows), l # Error Example > tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ## 2.3 SQL Format #### 2.3.1 Command @@ -118,7 +118,7 @@ Parse error: Missing required option: t # Error Example > tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.4 TsFile Format @@ -153,5 +153,5 @@ Parse error: Missing required option: t # Error Example > tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` diff --git a/src/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md b/src/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..21366ef6b --- /dev/null +++ b/src/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,163 @@ +# Data Export + +## 1. Overview +The data export tool, export-data.sh (Unix/OS X) or export-data.bat (Windows), located in the tools directory, allows users to export query results from specified SQL statements into CSV, SQL, or TsFile (open-source time-series file format) formats. The specific functionalities are as follows: + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVexport-data.sh/batPlain text format for storing structured data. Must follow the CSV format specified below.
SQLFile containing custom SQL statements.
TsFileOpen-source time-series file format.
+ + +## 2. Detailed Functionality +### 2.1 Common Parameters +| Short | Full Parameter | Description | Required | Default | +| ---------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------- |------------------------------------------------| +| `-ft` | `--file_type` | Export file type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | Hostname of the IoTDB server. | No | `127.0.0.1` | +| `-p` | `--port` | Port number of the IoTDB server. | No | `6667` | +| `-u` | `--username` | Username for authentication. | No | `root` | +| `-pw` | `--password` | Password for authentication. | No | `TimechoDB@2021`(Before V2.0.6 it is `root` ) | +| `-t` | `--target` | Target directory for the output files. If the path does not exist, it will be created. | ​**Yes** | - | +| `-pfn` | `--prefix_file_name` | Prefix for the exported file names. For example, `abc` will generate files like `abc_0.tsfile`, `abc_1.tsfile`. | No | `dump_0.tsfile` | +| `-q` | `--query` | SQL query command to execute. | No | - | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (ms). | No | `-1` (Range: -1~Long max=9223372036854775807) | +| `-help` | `--help` | Display help information. | No | - | + +### 2.2 CSV Format +#### 2.2.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |------------------------------------------| +| `-dt` | `--datatype` | Whether to include data types in the CSV file header (`true` or `false`). | No | `false` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -dt true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# Error Example +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` +## 2.3 SQL Format +#### 2.3.1 Command +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------- | +| `-aligned` | `--use_aligned` | Whether to export as aligned SQL format (`true` or `false`). | No | `true` | +| `-lpf` | `--lines_per_file` | Number of rows per exported file. | No | `10000` (Range:0~Integer.Max=2147483647) | +| `-tf` | `--time_format` | Time format for the CSV file. Options: 1) Timestamp (numeric, long), 2) ISO8601 (default), 3) Custom pattern (e.g., `yyyy-MM-dd HH:mm:ss`). SQL file timestamps are unaffected by this setting. | No | `ISO8601` | +| `-tz` | `--timezone` | Timezone setting (e.g., `+08:00`, `-01:00`). | No | System default | + +#### 2.3.3 Examples +```Shell +# Valid Example +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -aligned true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# Error Example +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# Before version V2.0.4.x +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 TsFile-Specific Parameters + +* None + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn export-data.tsfile -q "SELECT * FROM root.ln" -timeout 10000 + +# Error Example +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` diff --git a/src/UserGuide/latest/Tools-System/Data-Import-Tool.md b/src/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md similarity index 99% rename from src/UserGuide/latest/Tools-System/Data-Import-Tool.md rename to src/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md index e330c0564..848afe982 100644 --- a/src/UserGuide/latest/Tools-System/Data-Import-Tool.md +++ b/src/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md @@ -99,7 +99,7 @@ IoTDB supports three methods for data import: error: Source file or directory /non_path does not exist > tools/import-data.sh -ft csv -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` #### 2.2.4 Import Notes @@ -190,7 +190,7 @@ error: Source file or directory /path/sql does not exist > tools/import-data.sh -ft sql -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ### 2.4 TsFile Format @@ -238,7 +238,7 @@ error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' > tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` diff --git a/src/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md b/src/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..ab7ade070 --- /dev/null +++ b/src/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,325 @@ +# Data Import + +## 1. Overview +IoTDB supports three methods for data import: +- Data Import Tool: Use the `import-data.sh/bat` script in the `tools` directory to manually import CSV, SQL, or TsFile (open-source time-series file format) data into IoTDB. +- `TsFile` Auto-Loading Feature +- Load `TsFile` SQL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File FormatIoTDB ToolDescription
CSVimport-data.sh/batCan be used for single or batch import of CSV files into IoTDB
SQLCan be used for single or batch import of SQL files into IoTDB
TsFileCan be used for single or batch import of TsFile files into IoTDB
TsFile Auto-Loading FeatureCan automatically monitor a specified directory for newly generated TsFiles and load them into IoTDB
Load SQLCan be used for single or batch import of TsFile files into IoTDB
+ +## 2. Data Import Tool +### 2.1 Common Parameters + +| Short | Full Parameter | Description | Required | Default | +| ------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |-----------------------------------------------| +| `-ft` | `--file_type` | File type: `csv`, `sql`, `tsfile`. | ​**Yes** | - | +| `-h` | `--host` | IoTDB server hostname. | No | `127.0.0.1` | +| `-p` | `--port` | IoTDB server port. | No | `6667` | +| `-u` | `--username` | Username. | No | `root` | +| `-pw` | `--password` | Password. | No | `TimechoDB@2021`(Before V2.0.6 it is `root` ) | +| `-s` | `--source` | Local path to the file/directory to import. ​​**Supported formats**​: CSV, SQL, TsFile. Unsupported formats trigger error: `The file name must end with "csv", "sql", or "tsfile"!` | ​**Yes** | - | +| `-tn` | `--thread_num` | Maximum parallel threads | No | `8`
Range: 0 to Integer.Max(2147483647). | +| `-tz` | `--timezone` | Timezone (e.g., `+08:00`, `-01:00`). | No | System default | +| `-help` | `--help` | Display help (general or format-specific: `-help csv`). | No | - | + +### 2.2 CSV Format + +#### 2.2.1 Command +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 CSV-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ---------------- | ------------------------------- |----------------------------------------------------------| ---------- |-----------------| +| `-fd` | `--fail_dir` | Directory to save failed files. | No | YOUR_CSV_FILE_PATH | +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-aligned` | `--use_aligned` | Import as aligned time series. | No | `false` | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-ti` | `--type_infer` | Type mapping (e.g., `BOOLEAN=text,INT=long`). | No | - | +| `-tp` | `--timestamp_precision` | Timestamp precision: `ms`, `us`, `ns`. | No | `ms` | + +#### 2.2.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 100 -aligned true -ti "BOOLEAN=text,INT=long,FLOAT=double" + -tp ms -tz +08:00 -batch 5000 -tn 4 + +# Error Example +> tools/import-data.sh -ft csv -s /non_path +error: Source file or directory /non_path does not exist + +> tools/import-data.sh -ft csv -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + +#### 2.2.4 Import Notes + +1. CSV Import Specifications + +- Special Character Escaping Rules: If a text-type field contains special characters (e.g., commas ,), they must be escaped using a backslash (\). +- Supported Time Formats: yyyy-MM-dd'T'HH:mm:ss, yyyy-MM-dd HH:mm:ss, or yyyy-MM-dd'T'HH:mm:ss.SSSZ. +- Timestamp Column Requirement: The timestamp column must be the first column in the data file. + +2. CSV File Example + +- Time Alignment + +```sql +-- Headers without data types +Time,root.test.t1.str,root.test.t2.str,root.test.t2.var +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,"123",, + +-- Headers with data types (Text-type data supports both quoted and unquoted formats) +Time,root.test.t1.str(TEXT),root.test.t2.str(TEXT),root.test.t2.var(INT32) +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,123,hello world,123 +1970-01-01T08:00:00.003+08:00,"123",, +1970-01-01T08:00:00.004+08:00,123,,12 +``` + +- Device Alignment + +```sql +-- Headers without data types +Time,Device,str,var +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 + +-- Headers with data types (Text-type data supports both quoted and unquoted formats) +Time,Device,str(TEXT),var(INT32) +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 +1970-01-01T08:00:00.002+08:00,root.test.t1,hello world,123 +``` + + +### 2.3 SQL Format + +#### 2.3.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 SQL-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| -------------- | ------------------------------- | -------------------------------------------------------------------- | ---------- | ------------------ | +| `-fd` | `--fail_dir` | Directory to save failed files. | No |YOUR_CSV_FILE_PATH| +| `-lpf` | `--lines_per_failed_file` | Max lines per failed file. | No | `100000`
Range: 0 to Integer.Max(2147483647). | +| `-batch` | `--batch_size` | Rows processed per API call. | No | `100000`
Range: 0 to Integer.Max(2147483647). | + +#### 2.3.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 500 -tz +08:00 + -batch 100000 -tn 4 + +# Error Example +> tools/import-data.sh -ft sql -s /path/sql -fd /non_path +error: Source file or directory /path/sql does not exist + + +> tools/import-data.sh -ft sql -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` +### 2.4 TsFile Format + +#### 2.4.1 Command + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# Before version V2.0.4.x +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x and later versions +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` +#### 2.4.2 TsFile-Specific Parameters + +| Short | Full Parameter | Description | Required | Default | +| ----------- | ----------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------- | --------------------------- | +| `-os` | `--on_success` | Action for successful files:
`none`: Do not delete the file.
`mv`: Move the successful file to the target directory.
`cp`:Create a hard link (copy) of the successful file to the target directory.
`delete`:Delete the file. | ​**Yes** | - | +| `-sd` | `--success_dir` | Target directory for `mv`/`cp` actions on success. Required if `-os` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/success` | +| `-of` | `--on_fail` | Action for failed files:
`none`:Skip the file.
`mv`:Move the failed file to the target directory.
`cp`:Create a hard link (copy) of the failed file to the target directory.
`delete`:Delete the file.. | ​**Yes** | - | +| `-fd` | `--fail_dir` | Target directory for `mv`/`cp` actions on failure. Required if `-of` is `mv`/`cp`. The file name will be flattened and concatenated with the original file name. | Conditional | `${EXEC_DIR}/fail` | +| `-tp` | `--timestamp_precision` | TsFile timestamp precision: `ms`, `us`, `ns`.
For non-remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The system will manually verify if the timestamp precision matches the server. If it does not match, an error will be returned.
​For remote TsFile imports: Use -tp to specify the timestamp precision of the TsFile. The Pipe system will automatically verify if the timestamp precision matches. If it does not match, a Pipe error will be returned. | No | `ms` | + +#### 2.4.3 Examples + +```Shell +# Valid Example +> tools/import-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 + -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir + -tn 8 -tz +08:00 -tp ms + +# Error Example +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -fd /path/failure/dir -tn 8 +error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' + +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -sd /path/success/dir -fd /path/failure/dir -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# Note: Before version V2.0.6, the default value for the -pw parameter was root. +``` + + +## 3. TsFile Auto-Loading + +This feature enables IoTDB to automatically monitor a specified directory for new TsFiles and load them into the database without manual intervention. + +![](/img/Data-import2.png) + +### 3.1 Configuration + +Add the following parameters to `iotdb-system.properties` (template: `iotdb-system.properties.template`): + +| Parameter | Description | Value Range | Required | Default | Hot-Load? | +| ---------------------------------------------------- |---------------------------------------------------------------------------------------| --------------------------------- | ---------- | ----------------------------- | ----------------------- | +| `load_active_listening_enable` | Enable auto-loading. | `true`/`false` | Optional | `true` | Yes | +| `load_active_listening_dirs` | Directories to monitor (subdirectories included). Multiple paths separated by commas. | String | Optional | `ext/load/pending` | Yes | +| `load_active_listening_fail_dir` | Directory to store failed TsFiles. Only can set one. | String | Optional | `ext/load/failed` | Yes | +| `load_active_listening_max_thread_num` | Maximum Threads for TsFile Loading Tasks:The default value for this parameter, when commented out, is max(1, CPU cores / 2). If the value set by the user falls outside the range [1, CPU cores / 2], it will be reset to the default value of max(1, CPU cores / 2). | `1` to `Long.MAX_VALUE` | Optional | `max(1, CPU_CORES / 2)` | No (restart required) | +| `load_active_listening_check_interval_seconds` | Active Listening Polling Interval (in seconds):The active listening feature for TsFiles is implemented through polling the target directory. This configuration specifies the time interval between two consecutive checks of the `load_active_listening_dirs`. After each check, the next check will be performed after `load_active_listening_check_interval_seconds` seconds. If the polling interval set by the user is less than 1, it will be reset to the default value of 5 seconds. | `1` to `Long.MAX_VALUE` | Optional | `5` | No (restart required) | + +### 3.2 Notes + +1. ​​**Mods Files**​: If TsFiles have associated `.mods` files, move `.mods` files to the monitored directory ​**before** their corresponding TsFiles. Ensure `.mods` and TsFiles are in the same directory. +2. ​​**Restricted Directories**​: Do NOT set Pipe receiver directories, data directories, or other system paths as monitored directories. +3. ​​**Directory Conflicts**​: Ensure `load_active_listening_fail_dir` does not overlap with `load_active_listening_dirs` or its subdirectories. +4. ​​**Permissions**​: The monitored directory must have write permissions. Files are deleted after successful loading; insufficient permissions may cause duplicate loading. + +## 4. Load SQL + +IoTDB supports importing one or multiple TsFile files containing time series into another running IoTDB instance directly via SQL execution through the CLI. + +### 4.1 Command + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` : The path to a TsFile or a folder containing multiple TsFiles. +* ``: Optional parameters, as described below. + +| Key | Key Description | Value Type | Value Range | Value is Required | Default Value | +|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|--------------------------------|-------------------|----------------------------| +| `database-level` | When the database corresponding to the TsFile does not exist, the database hierarchy level can be specified via the ` database-level` parameter. The default is the level set in `iotdb-common.properties`. For example, setting level=1 means the prefix path of level 1 in all time series in the TsFile will be used as the database. | Integer | `[1: Integer.MAX_VALUE]` | No | 1 | +| `on-success` | Action for successfully loaded TsFiles: `delete` (delete the TsFile after successful import) or `none` (retain the TsFile in the source folder). | String | `delete / none` | No | delete | +| `model` | Specifies whether the TsFile uses the `table` model or `tree` model. | String | `tree / table` | No | Aligns with `-sql_dialect` | +| `database-name` | Table model only: Target database for import. Automatically created if it does not exist. The database-name must not include the `root.` prefix (an error will occur if included). | String | `-` | No | null | +| `convert-on-type-mismatch` | Whether to perform type conversion during loading if data types in the TsFile mismatch the target schema. | Boolean | `true / false` | No | true | +| `verify` | Whether to validate the schema before loading the TsFile. | Boolean | `true / false` | No | true | +| `tablet-conversion-threshold` | Size threshold (in bytes) for converting TsFiles into tablet format during loading. Default: `-1` (no conversion for any TsFile). | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | No | -1 | +| `async` | Whether to enable asynchronous loading. If enabled, TsFiles are moved to an active-load directory and loaded into the `database-name` asynchronously. | Boolean | `true / false` | No | false | + +### 4.2 Example + +```SQL +-- Before import +IoTDB> show databases ++-------------+-----------------------+---------------------+-------------------+---------------------+ +| Database|SchemaReplicationFactor|DataReplicationFactor|TimePartitionOrigin|TimePartitionInterval| ++-------------+-----------------------+---------------------+-------------------+---------------------+ +|root.__system| 1| 1| 0| 604800000| ++-------------+-----------------------+---------------------+-------------------+---------------------+ + +-- Import tsfile by excuting load sql +IoTDB> load '/home/dump1.tsfile' with ( 'on-success'='none') +Msg: The statement is executed successfully. + +-- Verify whether the import was successful +IoTDB> select * from root.testdb.** ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time|root.testdb.device.model.temperature|root.testdb.device.model.humidity|root.testdb.device.model.status| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|2025-04-17T10:35:47.218+08:00| 22.3| 19.4| true| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md b/src/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md similarity index 94% rename from src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md rename to src/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md index e6b102d06..f2423a678 100644 --- a/src/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md +++ b/src/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ The schema export tool `export-schema.sh/bat` is located in the `tools` director ### 2.1 Parameter -| **Short Param** | **Full Param** | **Description** | Required | Default | -| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------- | -| `-h` | `-- host` | Hostname | No | 127.0.0.1 | -| `-p` | `--port` | Port number | No | 6667 | -| `-u` | `--username` | Username | No | root | -| `-pw` | `--password` | Password | No | root | -| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | -| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | -| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | -| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | -| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | -| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | -| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | | `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | -| `-help` | `--help` | Display help information | No | | +| `-help` | `--help` | Display help information | No | | ### 2.2 Command diff --git a/src/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md b/src/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..e126ccd89 --- /dev/null +++ b/src/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,82 @@ + + +# Schema Export + +## 1. Overview + +The schema export tool `export-schema.sh/bat` is located in the `tools` directory. It can export schema from a specified database in IoTDB to a script file. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | -------------------------- | ------------------------------------------------------------------------ | ------------------------------------- |-----------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | TimechoDB@2021(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database to export (only applies when`-sql_dialect=table`) | Required if`-sql_dialect=table` | - | +| `-table` | `--table` | Target table to export (only applies when`-sql_dialect=table`) | No | - | +| `-t` | `--target` | Output directory (created if it doesn't exist) | Yes | | +| `-path` | `--path_pattern` | Path pattern for metadata export | Required if`-sql_dialect=tree` | | +| `-pfn` | `--prefix_file_name` | Output filename prefix | No | `dump_dbname.sql` | +| `-lpf` | `--lines_per_file` | Maximum lines per dump file (only applies when`-sql_dialect=tree`) | No | `10000` | +| `-timeout` | `--query_timeout` | Query timeout in milliseconds (`-1`= no timeout) | No | -1Range:`-1 to Long. max=9223372036854775807` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# Before version V2.0.4.x +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x and later versions +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 Examples + + +```Bash +# Export schema under root.treedb +./export-schema.sh -sql_dialect tree -t /home/ -path "root.treedb.**" + +# Output +Timeseries,Alias,DataType,Encoding,Compression +root.treedb.device.temperature,,DOUBLE,GORILLA,LZ4 +root.treedb.device.humidity,,DOUBLE,GORILLA,LZ4 +``` \ No newline at end of file diff --git a/src/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md b/src/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md new file mode 100644 index 000000000..9bc72440c --- /dev/null +++ b/src/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md @@ -0,0 +1,87 @@ + + +# Schema Import + +## 1. Overview + +The schema import tool `import-schema.sh/bat` is located in `tools` directory. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | root | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# Before version V2.0.4.x +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x and later versions +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 Examples + +```Bash +# Before import +IoTDB> show timeseries root.treedb.** ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ + +# Execution +./import-schema.sh -sql_dialect tree -s /home/dump0_0.csv -db root.treedb + +# Verification +IoTDB> show timeseries root.treedb.** ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +| Timeseries|Alias| Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|root.treedb.device.temperature| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| +| root.treedb.device.humidity| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +``` diff --git a/src/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md b/src/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md new file mode 100644 index 000000000..6f0d82fc0 --- /dev/null +++ b/src/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md @@ -0,0 +1,87 @@ + + +# Schema Import + +## 1. Overview + +The schema import tool `import-schema.sh/bat` is located in `tools` directory. + +## 2. Detailed Functionality + +### 2.1 Parameter + +| **Short Param** | **Full Param** | **Description** | Required | Default | +| ----------------------- | ------------------------------- | --------------------------------------------------------------------------- | ---------- |-------------------------------------------| +| `-h` | `-- host` | Hostname | No | 127.0.0.1 | +| `-p` | `--port` | Port number | No | 6667 | +| `-u` | `--username` | Username | No | root | +| `-pw` | `--password` | Password | No | TimechoDB@2021(Before V2.0.6 it is root) | +| `-sql_dialect` | `--sql_dialect` | Specifies whether the server uses`tree `model or`table `model | No | tree | +| `-db` | `--database` | Target database for import | Yes | - | +| `-table` | `--table` | Target table for import (only applies when`-sql_dialect=table`) | No | - | +| `-s` | `--source` | Local directory path containing script file(s) to import | Yes | | +| `-fd` | `--fail_dir` | Directory to save failed import files | No | | +| `-lpf` | `--lines_per_failed_file` | Maximum lines per failed file (only applies when`-sql_dialect=table`) | No | 100000Range:`0 to Integer.Max=2147483647` | +| `-help` | `--help` | Display help information | No | | + +### 2.2 Command + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# Before version V2.0.4.x +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x and later versions +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 Examples + +```Bash +# Before import +IoTDB> show timeseries root.treedb.** ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ + +# Execution +./import-schema.sh -sql_dialect tree -s /home/dump0_0.csv -db root.treedb + +# Verification +IoTDB> show timeseries root.treedb.** ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +| Timeseries|Alias| Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|root.treedb.device.temperature| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| +| root.treedb.device.humidity| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +``` diff --git a/src/UserGuide/latest/User-Manual/Authority-Management.md b/src/UserGuide/latest/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/UserGuide/latest/User-Manual/Authority-Management.md rename to src/UserGuide/latest/User-Manual/Authority-Management_apache.md diff --git a/src/UserGuide/latest/User-Manual/Authority-Management_timecho.md b/src/UserGuide/latest/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..466329109 --- /dev/null +++ b/src/UserGuide/latest/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,519 @@ + + +# Authority Management + +IoTDB provides permission management operations, offering users the ability to manage permissions for data and cluster systems, ensuring data and system security. + +This article introduces the basic concepts of the permission module in IoTDB, including user definition, permission management, authentication logic, and use cases. In the JAVA programming environment, you can use the [JDBC API](https://chat.openai.com/API/Programming-JDBC.md) to execute permission management statements individually or in batches. + +## 1. Basic Concepts + +### 1.1 User + +A user is a legitimate user of the database. Each user corresponds to a unique username and has a password as a means of authentication. Before using the database, a person must provide a valid (i.e., stored in the database) username and password for a successful login. + +### 1.2 Permission + +The database provides various operations, but not all users can perform all operations. If a user can perform a certain operation, they are said to have permission to execute that operation. Permissions are typically limited in scope by a path, and [path patterns](https://chat.openai.com/Basic-Concept/Data-Model-and-Terminology.md) can be used to manage permissions flexibly. + +### 1.3 Role + +A role is a collection of multiple permissions and has a unique role name as an identifier. Roles often correspond to real-world identities (e.g., a traffic dispatcher), and a real-world identity may correspond to multiple users. Users with the same real-world identity often have the same permissions, and roles are abstractions for unified management of such permissions. + +### 1.4 Default Users and Roles + +After installation and initialization, IoTDB includes a default user: root, with the default password TimechoDB@2021 (Before V2.0.6.x it is root). This user is an administrator with fixed permissions, which cannot be granted or revoked and cannot be deleted. There is only one administrator user in the database. + +A newly created user or role does not have any permissions initially. + +## 2. User Definition + +Users with MANAGE_USER and MANAGE_ROLE permissions or administrators can create users or roles. Creating a user must meet the following constraints. + +### 2.1 Username Constraints + +4 to 32 characters, supports the use of uppercase and lowercase English letters, numbers, and special characters (`!@#$%^&*()_+-=`). + +Users cannot create users with the same name as the administrator. + +### 2.2 Password Constraints + +4 to 32 characters, can use uppercase and lowercase letters, numbers, and special characters (`!@#$%^&*()_+-=`). Passwords are encrypted by default using SHA-256. + +### 2.3 Role Name Constraints + +4 to 32 characters, supports the use of uppercase and lowercase English letters, numbers, and special characters (`!@#$%^&*()_+-=`). + +Users cannot create roles with the same name as the administrator. + + + +## 3. Permission Management + +IoTDB primarily has two types of permissions: series permissions and global permissions. + +### 3.1 Series Permissions + +Series permissions constrain the scope and manner in which users access data. IOTDB support authorization for both absolute paths and prefix-matching paths, and can be effective at the timeseries granularity. + +The table below describes the types and scope of these permissions: + + + +| Permission Name | Description | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| READ_DATA | Allows reading time series data under the authorized path. | +| WRITE_DATA | Allows reading time series data under the authorized path.
Allows inserting and deleting time series data under the authorized path.
Allows importing and loading data under the authorized path. When importing data, you need the WRITE_DATA permission for the corresponding path. When automatically creating databases or time series, you need MANAGE_DATABASE and WRITE_SCHEMA permissions. | +| READ_SCHEMA | Allows obtaining detailed information about the metadata tree under the authorized path,
including databases, child paths, child nodes, devices, time series, templates, views, etc. | +| WRITE_SCHEMA | Allows obtaining detailed information about the metadata tree under the authorized path.
Allows creating, deleting, and modifying time series, templates, views, etc. under the authorized path. When creating or modifying views, it checks the WRITE_SCHEMA permission for the view path and READ_SCHEMA permission for the data source. When querying and inserting data into views, it checks the READ_DATA and WRITE_DATA permissions for the view path.
Allows setting, unsetting, and viewing TTL under the authorized path.
Allows attaching or detaching templates under the authorized path. | + + +### 3.2 Global Permissions + +Global permissions constrain the database functions that users can use and restrict commands that change the system and task state. Once a user obtains global authorization, they can manage the database. +The table below describes the types of system permissions: + + +| Permission Name | Description | +|:---------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| MANAGE_DATABASE | Allow users to create and delete databases. | +| MANAGE_USER | Allow users to create, delete, modify, and view users. | +| MANAGE_ROLE | Allow users to create, delete, modify, and view roles.
Allow users to grant/revoke roles to/from other users. | +| USE_TRIGGER | Allow users to create, delete, and view triggers.
Independent of data source permission checks for triggers. | +| USE_UDF | Allow users to create, delete, and view user-defined functions.
Independent of data source permission checks for user-defined functions. | +| USE_CQ | Allow users to create, delete, and view continuous queries.
Independent of data source permission checks for continuous queries. | +| USE_PIPE | Allow users to create, start, stop, delete, and view pipelines.
Allow users to create, delete, and view pipeline plugins.
Independent of data source permission checks for pipelines. | +| EXTEND_TEMPLATE | Permission to automatically create templates. | +| MAINTAIN | Allow users to query and cancel queries.
Allow users to view variables.
Allow users to view cluster status. | +| USE_MODEL | Allow users to create, delete and view deep learning model. | +Regarding template permissions: + +1. Only administrators are allowed to create, delete, modify, query, mount, and unmount templates. +2. To activate a template, you need to have WRITE_SCHEMA permission for the activation path. +3. If automatic creation is enabled, writing to a non-existent path that has a template mounted will automatically extend the template and insert data. Therefore, one needs EXTEND_TEMPLATE permission and WRITE_DATA permission for writing to the sequence. +4. To deactivate a template, WRITE_SCHEMA permission for the mounted template path is required. +5. To query paths that use a specific metadata template, you needs READ_SCHEMA permission for the paths; otherwise, it will return empty results. + + + +### 3.3 Granting and Revoking Permissions + +In IoTDB, users can obtain permissions through three methods: + +1. Granted by administrator, who has control over the permissions of other users. +2. Granted by a user allowed to authorize permissions, and this user was assigned the grant option keyword when obtaining the permission. +3. Granted a certain role by administrator or a user with MANAGE_ROLE, thereby obtaining permissions. + +Revoking a user's permissions can be done through the following methods: + +1. Revoked by administrator. +2. Revoked by a user allowed to authorize permissions, and this user was assigned the grant option keyword when obtaining the permission. +3. Revoked from a user's role by administrator or a user with MANAGE_ROLE, thereby revoking the permissions. + +- When granting permissions, a path must be specified. Global permissions need to be specified as root.**, while series-specific permissions must be absolute paths or prefix paths ending with a double wildcard. +- When granting user/role permissions, you can specify the "with grant option" keyword for that permission, which means that the user can grant permissions on their authorized paths and can also revoke permissions on other users' authorized paths. For example, if User A is granted read permission for `group1.company1.**` with the grant option keyword, then A can grant read permissions to others on any node or series below `group1.company1`, and can also revoke read permissions on any node below `group1.company1` for other users. +- When revoking permissions, the revocation statement will match against all of the user's permission paths and clear the matched permission paths. For example, if User A has read permission for `group1.company1.factory1`, when revoking read permission for `group1.company1.**`, it will remove A's read permission for `group1.company1.factory1`. + + + +## 4. Authentication + +User permissions mainly consist of three parts: permission scope (path), permission type, and the "with grant option" flag: + +``` +userTest1: + root.t1.** - read_schema, read_data - with grant option + root.** - write_schema, write_data - with grant option +``` + +Each user has such a permission access list, identifying all the permissions they have acquired. You can view their permissions by using the command `LIST PRIVILEGES OF USER `. + +When authorizing a path, the database will match the path with the permissions. For example, when checking the read_schema permission for `root.t1.t2`, it will first match with the permission access list `root.t1.**`. If it matches successfully, it will then check if that path contains the permission to be authorized. If not, it continues to the next path-permission match until a match is found or all matches are exhausted. + +When performing authorization for multiple paths, such as executing a multi-path query task, the database will only present data for which the user has permissions. Data for which the user does not have permissions will not be included in the results, and information about these paths without permissions will be output to the alert messages. + +Please note that the following operations require checking multiple permissions: + +1. Enabling the automatic sequence creation feature requires not only write permission for the corresponding sequence when a user inserts data into a non-existent sequence but also metadata modification permission for the sequence. + +2. When executing the "select into" statement, it is necessary to check the read permission for the source sequence and the write permission for the target sequence. It should be noted that the source sequence data may only be partially accessible due to insufficient permissions, and if the target sequence has insufficient write permissions, an error will occur, terminating the task. + +3. View permissions and data source permissions are independent. Performing read and write operations on a view will only check the permissions of the view itself and will not perform permission validation on the source path. + + +## 5. Function Syntax and Examples + +IoTDB provides composite permissions for user authorization: + +| Permission Name | Permission Scope | +|-----------------|--------------------------| +| ALL | All permissions | +| READ | READ_SCHEMA, READ_DATA | +| WRITE | WRITE_SCHEMA, WRITE_DATA | + +Composite permissions are not specific permissions themselves but a shorthand way to denote a combination of permissions, with no difference from directly specifying the corresponding permission names. + +The following series of specific use cases will demonstrate the usage of permission statements. Non-administrator users executing the following statements require obtaining the necessary permissions, which are indicated after the operation description. + +### 5.1 User and Role Related + +- Create user (Requires MANAGE_USER permission) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- Delete user (Requires MANAGE_USER permission) + +```sql +DROP USER +eg: DROP USER user1 +``` + +- Create role (Requires MANAGE_ROLE permission) + +```sql +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- Delete role (Requires MANAGE_ROLE permission) + +```sql +DROP ROLE +eg: DROP ROLE role1 +``` + +- Grant role to user (Requires MANAGE_ROLE permission) + +```sql +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- Revoke role from user(Requires MANAGE_ROLE permission) + +```sql +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- List all user (Requires MANAGE_USER permission) + +```sql +LIST USER +``` + +- List all role (Requires MANAGE_ROLE permission) + +```sql +LIST ROLE +``` + +- List all users granted specific role.(Requires MANAGE_USER permission) + +```sql +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- List all role granted to specific user. + + Users can list their own roles, but listing roles of other users requires the MANAGE_ROLE permission. + +```sql +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- List all privileges of user + +Users can list their own privileges, but listing privileges of other users requires the MANAGE_USER permission. + +```sql +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; +``` + +- List all privileges of role + +Users can list the permission information of roles they have, but listing permissions of other roles requires the MANAGE_ROLE permission. + +```sql +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- Modify password + +Users can modify their own password, but modifying passwords of other users requires the MANAGE_USER permission. + +```sql +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 5.2 Authorization and Deauthorization + +Users can use authorization statements to grant permissions to other users. The syntax is as follows: + +```sql +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +Users can use deauthorization statements to revoke permissions from others. The syntax is as follows: + +```sql +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + +- **When non-administrator users execute authorization/deauthorization statements, they need to have \ permissions on \, and these permissions must be marked with WITH GRANT OPTION.** + +- When granting or revoking global permissions or when the statement contains global permissions (expanding ALL includes global permissions), you must specify the path as root**. For example, the following authorization/deauthorization statements are valid: + + ```sql + GRANT MANAGE_USER ON root.** TO USER user1; + GRANT MANAGE_ROLE ON root.** TO ROLE role1 WITH GRANT OPTION; + GRANT ALL ON root.** TO role role1 WITH GRANT OPTION; + REVOKE MANAGE_USER ON root.** FROM USER user1; + REVOKE MANAGE_ROLE ON root.** FROM ROLE role1; + REVOKE ALL ON root.** FROM ROLE role1; + ``` + + The following statements are invalid: + + ```sql + GRANT READ, MANAGE_ROLE ON root.t1.** TO USER user1; + GRANT ALL ON root.t1.t2 TO USER user1 WITH GRANT OPTION; + REVOKE ALL ON root.t1.t2 FROM USER user1; + REVOKE READ, MANAGE_ROLE ON root.t1.t2 FROM ROLE ROLE1; + ``` + +- \ must be a full path or a matching path ending with a double wildcard. The following paths are valid: + + ```sql + root.** + root.t1.t2.** + root.t1.t2.t3 + ``` + + The following paths are invalid: + + ```sql + root.t1.* + root.t1.**.t2 + root.t1*.t2.t3 + ``` + + + +## 6. Examples + + Based on the described [sample data](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt), IoTDB's sample data may belong to different power generation groups such as ln, sgcc, and so on. Different power generation groups do not want other groups to access their database data, so we need to implement data isolation at the group level. + +#### Create Users +Use `CREATE USER ` to create users. For example, we can create two users for the ln and sgcc groups with the root user, who has all permissions, and name them ln_write_user and sgcc_write_user. It is recommended to enclose the username in backticks. The SQL statements are as follows: +```SQL +CREATE USER `ln_write_user` 'write_pwd' +CREATE USER `sgcc_write_user` 'write_pwd' +``` + +Now, using the SQL statement to display users: + +```sql +LIST USER +``` + +We can see that these two users have been created, and the result is as follows: + +```sql +IoTDB> CREATE USER `ln_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> CREATE USER `sgcc_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> LIST USER; ++---------------+ +| user| ++---------------+ +| ln_write_user| +| root| +|sgcc_write_user| ++---------------+ +Total line number = 3 +It costs 0.012s +``` + +#### Granting Permissions to Users + +At this point, although two users have been created, they do not have any permissions, so they cannot operate on the database. For example, if we use the ln_write_user to write data to the database, the SQL statement is as follows: + +```sql +INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +``` + +At this point, the system does not allow this operation, and an error is displayed: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +Now, we will grant each user write permissions to the corresponding paths using the root user. + +We use the `GRANT ON TO USER ` statement to grant permissions to users, for example: + +```sql +GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +``` + +The execution status is as follows: + +```sql +IoTDB> GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +Then, using ln_write_user, try to write data again: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: The statement is executed successfully. +``` + +#### Revoking User Permissions + +After granting user permissions, we can use the `REVOKE ON FROM USER ` to revoke the permissions granted to users. For example, using the root user to revoke the permissions of ln_write_user and sgcc_write_user: + +```sql +REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +``` + + +The execution status is as follows: + +```sql +IoTDB> REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +After revoking the permissions, ln_write_user no longer has the permission to write data to root.ln.**: + +```sql +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +## 7. Other Explanations + +Roles are collections of permissions, and both permissions and roles are attributes of users. In other words, a role can have multiple permissions, and a user can have multiple roles and permissions (referred to as the user's self-permissions). + +Currently, in IoTDB, there are no conflicting permissions. Therefore, the actual permissions a user has are the union of their self-permissions and the permissions of all their roles. In other words, to determine if a user can perform a certain operation, it's necessary to check whether their self-permissions or the permissions of all their roles allow that operation. Self-permissions, role permissions, and the permissions of multiple roles a user has may contain the same permission, but this does not have any impact. + +It's important to note that if a user has a certain permission (corresponding to operation A) on their own, and one of their roles has the same permission, revoking the permission from the user alone will not prevent the user from performing operation A. To prevent the user from performing operation A, you need to revoke the permission from both the user and the role, or remove the user from the role that has the permission. Similarly, if you only revoke the permission from the role, it won't prevent the user from performing operation A if they have the same permission on their own. + +At the same time, changes to roles will be immediately reflected in all users who have that role. For example, adding a certain permission to a role will immediately grant that permission to all users who have that role, and removing a certain permission will cause those users to lose that permission (unless the user has it on their own). + + + +## 8. Upgrading from a previous version + +Before version 1.3, there were many different permission types. In 1.3 version's implementation, we have streamlined the permission types. + +The permission paths in version 1.3 of the database must be either full paths or matching paths ending with a double wildcard. During system upgrades, any invalid permission paths and permission types will be automatically converted. The first invalid node on the path will be replaced with "**", and any unsupported permission types will be mapped to the permissions supported by the current system. + +| Permission | Path | Mapped-Permission | Mapped-path | +|-------------------|-----------------|-------------------|---------------| +| CREATE_DATBASE | root.db.t1.* | MANAGE_DATABASE | root.** | +| INSERT_TIMESERIES | root.db.t2.*.t3 | WRITE_DATA | root.db.t2.** | +| CREATE_TIMESERIES | root.db.t2*c.t3 | WRITE_SCHEMA | root.db.** | +| LIST_ROLE | root.** | (ignore) | | + + + +You can refer to the table below for a comparison of permission types between the old and new versions (where "--IGNORE" indicates that the new version ignores that permission): + +| Permission Name | Path-Related | New Permission Name | Path-Related | +|---------------------------|--------------|---------------------|--------------| +| CREATE_DATABASE | YES | MANAGE_DATABASE | NO | +| INSERT_TIMESERIES | YES | WRITE_DATA | YES | +| UPDATE_TIMESERIES | YES | WRITE_DATA | YES | +| READ_TIMESERIES | YES | READ_DATA | YES | +| CREATE_TIMESERIES | YES | WRITE_SCHEMA | YES | +| DELETE_TIMESERIES | YES | WRITE_SCHEMA | YES | +| CREATE_USER | NO | MANAGE_USER | NO | +| DELETE_USER | NO | MANAGE_USER | NO | +| MODIFY_PASSWORD | NO | -- IGNORE | | +| LIST_USER | NO | -- IGNORE | | +| GRANT_USER_PRIVILEGE | NO | -- IGNORE | | +| REVOKE_USER_PRIVILEGE | NO | -- IGNORE | | +| GRANT_USER_ROLE | NO | MANAGE_ROLE | NO | +| REVOKE_USER_ROLE | NO | MANAGE_ROLE | NO | +| CREATE_ROLE | NO | MANAGE_ROLE | NO | +| DELETE_ROLE | NO | MANAGE_ROLE | NO | +| LIST_ROLE | NO | -- IGNORE | | +| GRANT_ROLE_PRIVILEGE | NO | -- IGNORE | | +| REVOKE_ROLE_PRIVILEGE | NO | -- IGNORE | | +| CREATE_FUNCTION | NO | USE_UDF | NO | +| DROP_FUNCTION | NO | USE_UDF | NO | +| CREATE_TRIGGER | YES | USE_TRIGGER | NO | +| DROP_TRIGGER | YES | USE_TRIGGER | NO | +| START_TRIGGER | YES | USE_TRIGGER | NO | +| STOP_TRIGGER | YES | USE_TRIGGER | NO | +| CREATE_CONTINUOUS_QUERY | NO | USE_CQ | NO | +| DROP_CONTINUOUS_QUERY | NO | USE_CQ | NO | +| ALL | NO | All privilegs | | +| DELETE_DATABASE | YES | MANAGE_DATABASE | NO | +| ALTER_TIMESERIES | YES | WRITE_SCHEMA | YES | +| UPDATE_TEMPLATE | NO | -- IGNORE | | +| READ_TEMPLATE | NO | -- IGNORE | | +| APPLY_TEMPLATE | YES | WRITE_SCHEMA | YES | +| READ_TEMPLATE_APPLICATION | NO | -- IGNORE | | +| SHOW_CONTINUOUS_QUERIES | NO | -- IGNORE | | +| CREATE_PIPEPLUGIN | NO | USE_PIPE | NO | +| DROP_PIPEPLUGINS | NO | USE_PIPE | NO | +| SHOW_PIPEPLUGINS | NO | -- IGNORE | | +| CREATE_PIPE | NO | USE_PIPE | NO | +| START_PIPE | NO | USE_PIPE | NO | +| STOP_PIPE | NO | USE_PIPE | NO | +| DROP_PIPE | NO | USE_PIPE | NO | +| SHOW_PIPES | NO | -- IGNORE | | +| CREATE_VIEW | YES | WRITE_SCHEMA | YES | +| ALTER_VIEW | YES | WRITE_SCHEMA | YES | +| RENAME_VIEW | YES | WRITE_SCHEMA | YES | +| DELETE_VIEW | YES | WRITE_SCHEMA | YES | diff --git a/src/UserGuide/latest/User-Manual/Data-Sync_timecho.md b/src/UserGuide/latest/User-Manual/Data-Sync_timecho.md index 39fa9f999..8050ad9a4 100644 --- a/src/UserGuide/latest/User-Manual/Data-Sync_timecho.md +++ b/src/UserGuide/latest/User-Manual/Data-Sync_timecho.md @@ -590,50 +590,50 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :----------------------------------------------------------- | :------- | :------------ | -| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-thrift-sink or iotdb-thrift-async-sink | String: iotdb-thrift-sink or iotdb-thrift-async-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | The maximum number of bytes allowed to be transmitted per second. The compressed bytes (such as after compression) are calculated. If it is less than 0, there is no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | #### iotdb-air-gap-sink -| key | value | value Range | required or not | Default Value | -| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- | :----------- | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Required | - | -| node-urls | The URL of the data service port of any DataNode nodes on the target IoTDB | String. Example: :'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Required | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| air-gap.handshake-timeout-ms | The timeout duration of the handshake request when the sender and receiver first attempt to establish a connection, unit: ms | Integer | Optional | 5000 | +| key | value | value Range | required or not | Default Value | +| :--------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :------- |:---------------------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | Required | - | +| node-urls | The URL of the data service port of any DataNode nodes on the target IoTDB | String. Example: :'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Required | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| air-gap.handshake-timeout-ms | The timeout duration of the handshake request when the sender and receiver first attempt to establish a connection, unit: ms | Integer | Optional | 5000 | #### iotdb-thrift-ssl-sink -| **Parameter** | **Description** | Value Range | Required | Default Value | -|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------| :------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | -| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | -| password | Password for the username. | String | No | root | -| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | -| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | -| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | -| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | -| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | -| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | -| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | -| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | -| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | -| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | +| **Parameter** | **Description** | Value Range | Required | Default Value | +|:----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------|:---------------------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | Yes | - | +| node-urls | URLs of the DataNode service ports on the target IoTDB. (please note that the synchronization task does not support forwarding to its own service). | String. Example:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| user/username | Username for connecting to the target IoTDB. Must have appropriate permissions. | String | No | root | +| password | Password for the username. | String | No | TimechoDB@2021 (Before V2.0.6.x it is root) | +| batch.enable | Enables batch mode for log transmission to improve throughput and reduce IOPS. | Boolean: true, false | No | true | +| batch.max-delay-seconds | Maximum delay (in seconds) for batch transmission. | Integer | No | 1 | +| batch.size-bytes | Maximum batch size (in bytes) for batch transmission. | Long | No | 16*1024*1024 | +| compressor | The selected RPC compression algorithm. Multiple algorithms can be configured and will be adopted in sequence for each request. | String: snappy / gzip / lz4 / zstd / lzma2 | No | "" | +| compressor.zstd.level | When the selected RPC compression algorithm is zstd, this parameter can be used to additionally configure the compression level of the zstd algorithm. | Int: [-131072, 22] | No | 3 | +| rate-limit-bytes-per-second | Maximum bytes allowed per second for transmission (calculated after compression). Set to a value less than 0 for no limit. | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | No | -1 | +| load-tsfile-strategy | When synchronizing file data, ​​whether the receiver waits for the local load tsfile operation to complete before responding to the sender​​:
​​sync​​: Wait for the local load tsfile operation to complete before returning the response.
​​async​​: Do not wait for the local load tsfile operation to complete; return the response immediately. | String: sync / async | No | sync | +| ssl.trust-store-path | Path to the trust store certificate for SSL connection. | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | Yes | - | +| ssl.trust-store-pwd | Password for the trust store certificate. | Integer | Yes | - | +| format | The payload formats for data transmission include the following options:
- hybrid: The format depends on what is passed from the processor (either tsfile or tablet), and the sink performs no conversion.
- tsfile: Data is forcibly converted to tsfile format before transmission. This is suitable for scenarios like data file backup.
- tablet: Data is forcibly converted to tsfile format before transmission. This is useful for data synchronization when the sender and receiver have incompatible data types (to minimize errors). | String: hybrid / tsfile / tablet | No | hybrid | diff --git a/src/UserGuide/Master/Tree/User-Manual/Data-subscription.md b/src/UserGuide/latest/User-Manual/Data-subscription_apache.md similarity index 99% rename from src/UserGuide/Master/Tree/User-Manual/Data-subscription.md rename to src/UserGuide/latest/User-Manual/Data-subscription_apache.md index 3d219df6b..6fc310866 100644 --- a/src/UserGuide/Master/Tree/User-Manual/Data-subscription.md +++ b/src/UserGuide/latest/User-Manual/Data-subscription_apache.md @@ -130,7 +130,7 @@ Result set: ## 4. API interface -In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API.md)). +In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API_apache)). ## 5. Frequently Asked Questions diff --git a/src/UserGuide/latest/User-Manual/Data-subscription_timecho.md b/src/UserGuide/latest/User-Manual/Data-subscription_timecho.md new file mode 100644 index 000000000..2d13c01b8 --- /dev/null +++ b/src/UserGuide/latest/User-Manual/Data-subscription_timecho.md @@ -0,0 +1,148 @@ +# Data Subscription + +## 1. Feature Introduction + +The IoTDB data subscription module (also known as the IoTDB subscription client) is a feature supported after IoTDB V1.3.3, which provides users with a streaming data consumption method that is different from data queries. It refers to the basic concepts and logic of message queue products such as Kafka, **providing data subscription and consumption interfaces**, but it is not intended to completely replace these consumer queue products. Instead, it offers more convenient data subscription services for scenarios where simple streaming data acquisition is needed. + +Using the IoTDB Subscription Client to consume data has significant advantages in the following application scenarios: + +1. **Continuously obtaining the latest data**: By using a subscription method, it is more real-time than scheduled queries, simpler to program applications, and has a lower system burden; + +2. **Simplify data push to third-party systems**: No need to develop data push components for different systems within IoTDB, data can be streamed within third-party systems, making it easier to send data to systems such as Flink, Kafka, DataX, Camel, MySQL, PG, etc. + +## 2. Key Concepts + +The IoTDB Subscription Client encompasses three core concepts: Topic, Consumer, and Consumer Group. The specific relationships are illustrated in the diagram below: + +
+ +
+ +1. **Topic**: Topic is the data space of IoTDB, represented by paths and time ranges (such as the full time range of root. * *). Consumers can subscribe to data on these topics (currently existing and future written). Unlike Kafka, IoTDB can create topics after data is stored, and the output format can be either Message or TsFile. + +2. **Consumer**: Consumer is an IoTDB subscription client is located, responsible for receiving and processing data published to specific topics. Consumers retrieve data from the queue and process it accordingly. There are two types of Consumers available in the IoTDB subscription client: + - `SubscriptionPullConsumer`, which corresponds to the pull consumption model in message queues, where user code needs to actively invoke data retrieval logic. + - `SubscriptionPushConsumer`, which corresponds to the push consumption model in message queues, where user code is triggered by newly arriving data events. + + +3. **Consumer Group**: A Consumer Group is a collection of Consumers who share the same Consumer Group ID. The Consumer Group has the following characteristics: + - Consumer Group and Consumer are in a one to many relationship. That is, there can be any number of consumers in a consumer group, but a consumer is not allowed to join multiple consumer groups simultaneously. + - A Consumer Group can have different types of Consumers (`SubscriptionPullConsumer` and `SubscriptionPushConsumer`). + - It is not necessary for all consumers in a Consumer Group to subscribe to the same topic. + - When different Consumers in the same Consumer Group subscribe to the same Topic, each piece of data under that Topic will only be processed by one Consumer within the group, ensuring that data is not processed repeatedly. + +## 3. SQL Statements + +### 3.1 Topic Management + +IoTDB supports the creation, deletion, and viewing of Topics through SQL statements. The status changes of Topics are illustrated in the diagram below: + +
+ +
+ +#### 3.1.1 Create Topic + +The SQL statement is as follows: + +```SQL + CREATE TOPIC [IF NOT EXISTS] + WITH ( + [ = ,], + ); +``` + +**IF NOT EXISTS semantics**: Used in creation operations to ensure that the create command is executed when the specified topic does not exist, preventing errors caused by attempting to create an existing topic. + +Detailed explanation of each parameter is as follows: + +| Key | Required or Optional with Default | Description | +| :-------------------------------------------- | :--------------------------------- | :----------------------------------------------------------- | +| **path** | optional: `root.**` | The path of the time series data corresponding to the topic, representing a set of time series to be subscribed. | +| **start-time** | optional: `MIN_VALUE` | The start time (event time) of the time series data corresponding to the topic. Can be in ISO format, such as 2011-12-03T10:15:30 or 2011-12-03T10:15:30+01:00, or a long value representing a raw timestamp consistent with the database's timestamp precision. Supports the special value `now`, which means the creation time of the topic. When start-time is `now` and end-time is MAX_VALUE, it indicates that only real-time data is subscribed. | +| **end-time** | optional: `MAX_VALUE` | The end time (event time) of the time series data corresponding to the topic. Can be in ISO format, such as 2011-12-03T10:15:30 or 2011-12:03T10:15:30+01:00, or a long value representing a raw timestamp consistent with the database's timestamp precision. Supports the special value `now`, which means the creation time of the topic. When end-time is `now` and start-time is MIN_VALUE, it indicates that only historical data is subscribed. | +| **processor** | optional: `do-nothing-processor` | The name and parameter configuration of the processor plugin, representing the custom processing logic applied to the original subscribed data, which can be specified in a similar way to pipe processor plugins. + | +| **format** | optional: `SessionDataSetsHandler` | Represents the form in which data is subscribed from the topic. Currently supports the following two forms of data: `SessionDataSetsHandler`: Data subscribed from the topic is obtained using `SubscriptionSessionDataSetsHandler`, and consumers can consume each piece of data row by row. `TsFileHandler`: Data subscribed from the topic is obtained using `SubscriptionTsFileHandler`, and consumers can directly subscribe to the TsFile storing the corresponding data. | +| **mode** **(supported in versions 1.3.3.2 and later)** | option: `live` | The subscription mode corresponding to the topic, with two options: `live`: When subscribing to this topic, the subscribed dataset mode is a dynamic dataset, which means that you can continuously consume the latest data. `snapshot`: When the consumer subscribes to this topic, the subscribed dataset mode is a static dataset, which means the snapshot of the data at the moment the consumer group subscribes to the topic (not the moment the topic is created); the formed static dataset after subscription does not support TTL.| +| **loose-range** **(supported in versions 1.3.3.2 and later)** | option: `""` | String: Whether to strictly filter the data corresponding to this topic according to the path and time range, for example: "": Strictly filter the data corresponding to this topic according to the path and time range. `"time"`: Do not strictly filter the data corresponding to this topic according to the time range (rough filter); strictly filter the data corresponding to this topic according to the path. `"path"`: Do not strictly filter the data corresponding to this topic according to the path (rough filter); strictly filter the data corresponding to this topic according to the time range. `"time, path"` / `"path, time"` / `"all"`: Do not strictly filter the data corresponding to this topic according to the path and time range (rough filter).| + +Examples are as follows: + +```SQL +-- Full subscription +CREATE TOPIC root_all; + +-- Custom subscription +CREATE TOPIC IF NOT EXISTS db_timerange +WITH ( + 'path' = 'root.db.**', + 'start-time' = '2023-01-01', + 'end-time' = '2023-12-31' +); +``` + +#### 3.1.2 Delete Topic + +A Topic can only be deleted if it is not subscribed to. When a Topic is deleted, its related consumption progress will be cleared. + +```SQL +DROP TOPIC [IF EXISTS] ; +``` +**IF EXISTS semantics**: Used in deletion operations to ensure that the delete command is executed when a specified topic exists, preventing errors caused by attempting to delete non-existent topics. + +#### 3.1.3 View Topic + +```SQL +SHOW TOPICS; +SHOW TOPIC ; +``` + +Result set: + +```SQL +[TopicName|TopicConfigs] +``` + +- TopicName: Topic ID +- TopicConfigs: Topic configurations + +### 3.2 Check Subscription Status + +View all subscription relationships: + +```SQL +-- Query the subscription relationships between all topics and consumer groups +SHOW SUBSCRIPTIONS +-- Query all subscriptions under a specific topic +SHOW SUBSCRIPTIONS ON +``` + +Result set: + +```SQL +[TopicName|ConsumerGroupName|SubscribedConsumers] +``` + +- TopicName: The ID of the topic. +- ConsumerGroupName: The ID of the consumer group specified in the user's code. +- SubscribedConsumers: All client IDs in the consumer group that have subscribed to the topic. + +## 4. API interface + +In addition to SQL statements, IoTDB also supports using data subscription features through Java native interfaces, more details see([link](../API/Programming-Java-Native-API_timecho)). + + +## 5. Frequently Asked Questions + +### 5.1 What is the difference between IoTDB data subscription and Kafka? + +1. Consumption Orderliness + +- **Kafka guarantees that messages within a single partition are ordered**,when a topic corresponds to only one partition and only one consumer subscribes to this topic, the order in which the consumer (single-threaded) consumes the topic data is the same as the order in which the data is written. +- The IoTDB subscription client **does not guarantee** that the order in which the consumer consumes the data is the same as the order in which the data is written, but it will try to reflect the order of data writing. + +2. Message Delivery Semantics + +- Kafka can achieve Exactly once semantics for both Producers and Consumers through configuration. +- The IoTDB subscription client currently cannot provide Exactly once semantics for Consumers. \ No newline at end of file diff --git a/src/UserGuide/latest/User-Manual/IoTDB-View_timecho.md b/src/UserGuide/latest/User-Manual/IoTDB-View_timecho.md index b136941e2..111bf1f01 100644 --- a/src/UserGuide/latest/User-Manual/IoTDB-View_timecho.md +++ b/src/UserGuide/latest/User-Manual/IoTDB-View_timecho.md @@ -308,7 +308,7 @@ AS SELECT temperature FROM root.db.* ``` -This is modelled on the query writeback (`SELECT INTO`) convention for naming rules, which uses variable placeholders to specify naming rules. See also: [QUERY WRITEBACK (SELECT INTO)](../Basic-Concept/Query-Data.md#into-clause-query-write-back) +This is modelled on the query writeback (`SELECT INTO`) convention for naming rules, which uses variable placeholders to specify naming rules. See also: [QUERY WRITEBACK (SELECT INTO)](../Basic-Concept/Query-Data_timecho#into-clause-query-write-back) Here `root.db.*.temperature` specifies what time series will be included in the view; and `${2}` specifies from which node in the time series the name is extracted to name the sequence view. diff --git a/src/UserGuide/latest/User-Manual/User-defined-function_apache.md b/src/UserGuide/latest/User-Manual/User-defined-function_apache.md index 2d3d56cf3..b6f07efdd 100644 --- a/src/UserGuide/latest/User-Manual/User-defined-function_apache.md +++ b/src/UserGuide/latest/User-Manual/User-defined-function_apache.md @@ -186,7 +186,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 When users use UDF, they will be involved in the `USE_UDF` permission, and only users with this permission are allowed to perform UDF registration, uninstallation, and query operations. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_apache). ## 3. UDF Libraries diff --git a/src/UserGuide/latest/User-Manual/User-defined-function_timecho.md b/src/UserGuide/latest/User-Manual/User-defined-function_timecho.md index 368138332..20cdd065f 100644 --- a/src/UserGuide/latest/User-Manual/User-defined-function_timecho.md +++ b/src/UserGuide/latest/User-Manual/User-defined-function_timecho.md @@ -187,7 +187,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 When users use UDF, they will be involved in the `USE_UDF` permission, and only users with this permission are allowed to perform UDF registration, uninstallation, and query operations. -For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management.md). +For more user permissions related content, please refer to [Account Management Statements](../User-Manual/Authority-Management_timecho). ## 3. UDF Libraries diff --git a/src/zh/Download/README.md b/src/zh/Download/README.md index 88374a60f..d3df74f04 100644 --- a/src/zh/Download/README.md +++ b/src/zh/Download/README.md @@ -405,7 +405,7 @@ insert into root.sg(time, a) values(4, "\u96d5") - 如何从 v0.13.x 升级到 v1.0.x? - - 0.13 版本与 1.0 版本的文件目录结构不同,**不能将 0.13 的 data 目录直接拷贝到 1.0 集群使用**。如果需要将 0.13 的数据导入至 1.0,可以使用 [LOAD](../UserGuide/latest/Tools-System/Data-Import-Tool.md) 功能; + - 0.13 版本与 1.0 版本的文件目录结构不同,**不能将 0.13 的 data 目录直接拷贝到 1.0 集群使用**。如果需要将 0.13 的数据导入至 1.0,可以使用 [LOAD](../UserGuide/latest/Tools-System/Data-Import-Tool_apache) 功能; - **0.13 版本的默认 RPC 地址是 0.0.0.0,1.0 版本的默认 RPC 地址是 127.0.0.1** - 如何从 v1.0.0 升级到 v1.x.0? diff --git a/src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API.md rename to src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API_apache.md diff --git a/src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md new file mode 100644 index 000000000..00f9b5d13 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/API/Programming-CSharp-Native-API_timecho.md @@ -0,0 +1,402 @@ + +# C# 原生接口 + +## 1. 功能介绍 + +IoTDB具备C#原生客户端驱动和对应的连接池,提供对象化接口,可以直接组装时序对象进行写入,无需拼装 SQL。推荐使用连接池,多线程并行操作数据库。 + +## 2. 使用方式 + +**环境要求:** + +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 + +**依赖安装:** + +支持使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 + +如果使用的是\\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 + +```Plain +dotnet add package Apache.IoTDB +``` + +## 3. 读写操作 + +### 3.1 TableSessionPool + +#### 3.1.1 功能描述 + +TableSessionPool 定义了与IoTDB交互的基本操作,可以执行数据插入、查询操作以及关闭会话等,同时也是一个连接池这个池可以帮助我们高效地重用连接,并且在不需要时正确地清理资源, 该接口定义了如何从池中获取会话以及如何关闭池的基本操作。 + +#### 3.1.2 方法列表 + +以下是 TableSessionPool 中定义的方法及其详细说明: + +| 方法 | 描述 | 参数 | 返回值 | +| ---------------------------------------------------------------- | ---------------------------------------------------------------- |-------------------------------------------------------------------|--------------------| +| `Open(bool enableRpcCompression)` | 打开会话连接,自定义`enableRpcCompression` | `enableRpcCompression`:是否启用`RpcCompression`,此参数需配合 Server 端配置一同使用 | `Task` | +| `Open()` | 打开会话连接,不开启`RpcCompression` | 无 | `Task` | +| `InsertAsync(Tablet tablet)` | 将一个包含时间序列数据的Tablet 对象插入到数据库中 | tablet: 要插入的Tablet对象 | `Task` | +| `ExecuteNonQueryStatementAsync(string sql)` | 执行非查询SQL语句,如DDL(数据定义语言)或DML(数据操作语言)命令 | sql: 要执行的SQL语句。 | `Task` | +| `ExecuteQueryStatementAsync(string sql)` | 执行查询SQL语句,并返回包含查询结果的SessionDataSet对象 | sql: 要执行的SQL语句。 | `Task` | +| `ExecuteQueryStatementAsync(string sql, long timeoutInMs)` | 执行查询SQL语句,并设置查询超时时间(以毫秒为单位) | sql: 要执行的查询SQL语句。
timeoutInMs: 查询超时时间(毫秒) | `Task` | +| `Close()` | 关闭会话,释放所持有的资源 | 无 | `Task` | + +#### 3.1.3 接口展示 + +```C# +public async Task Open(bool enableRpcCompression, CancellationToken cancellationToken = default) + + public async Task Open(CancellationToken cancellationToken = default) + + public async Task InsertAsync(Tablet tablet) + + public async Task ExecuteNonQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql, long timeoutInMs) + + public async Task Close() +``` + +### 3.2 TableSessionPool.Builder + +#### 3.2.1 功能描述 + +TableSessionPool.Builder 是 TableSessionPool的构造器,用于配置和创建 TableSessionPool 的实例。允许开发者配置连接参数、会话参数和池化行为等。 + +#### 3.2.2 配置选项 + +以下是 TableSessionPool.Builder 类的可用配置选项及其默认值: + +| **配置项** | **描述** | **默认值** | +| ---------------------------------------------------- | ---------------------------------------------------------------- |---------------------| +| `SetHost(string host)` | 设置IoTDB的节点 host | `localhost` | +| `SetPort(int port)` | 设置IoTDB的节点端口 | `6667` | +| `SetNodeUrls(List nodeUrls)` | 设置IoTDB集群的节点URL列表,当设置此项时会忽略SetHost和SetPort | `无 ` | +| `SetUsername(string username)` | 设置连接的用户名 | `"root"` | +| `SetPassword(string password)` | 设置连接的密码 | `"TimechoDB@2021"` //V2.0.6.x 之前默认密码是root | +| `SetFetchSize(int fetchSize)` | 设置查询结果的获取大小 | `1024 ` | +| `SetZoneId(string zoneId)` | 设置时区相关的ZoneId | `UTC+08:00` | +| `SetPoolSize(int poolSize)` | 设置会话池的最大大小,即池中允许的最大会话数 | `8 ` | +| `SetEnableRpcCompression(bool enableRpcCompression)` | 是否启用RPC压缩 | `false` | +| `SetConnectionTimeoutInMs(int timeout)` | 设置连接超时时间(毫秒) | `500` | +| `SetDatabase(string database)` | 设置目标数据库名称 | ` "" ` | + +#### 3.2.3 接口展示 + +```c# +public Builder SetHost(string host) + { + _host = host; + return this; + } + + public Builder SetPort(int port) + { + _port = port; + return this; + } + + public Builder SetUsername(string username) + { + _username = username; + return this; + } + + public Builder SetPassword(string password) + { + _password = password; + return this; + } + + public Builder SetFetchSize(int fetchSize) + { + _fetchSize = fetchSize; + return this; + } + + public Builder SetZoneId(string zoneId) + { + _zoneId = zoneId; + return this; + } + + public Builder SetPoolSize(int poolSize) + { + _poolSize = poolSize; + return this; + } + + public Builder SetEnableRpcCompression(bool enableRpcCompression) + { + _enableRpcCompression = enableRpcCompression; + return this; + } + + public Builder SetConnectionTimeoutInMs(int timeout) + { + _connectionTimeoutInMs = timeout; + return this; + } + + public Builder SetNodeUrls(List nodeUrls) + { + _nodeUrls = nodeUrls; + return this; + } + + protected internal Builder SetSqlDialect(string sqlDialect) + { + _sqlDialect = sqlDialect; + return this; + } + + public Builder SetDatabase(string database) + { + _database = database; + return this; + } + + public Builder() + { + _host = "localhost"; + _port = 6667; + _username = "root"; + _password = "TimechoDB@2021"; //V2.0.6.x 之前默认密码是root + _fetchSize = 1024; + _zoneId = "UTC+08:00"; + _poolSize = 8; + _enableRpcCompression = false; + _connectionTimeoutInMs = 500; + _sqlDialect = IoTDBConstant.TABLE_SQL_DIALECT; + _database = ""; + } + + public TableSessionPool Build() + { + SessionPool sessionPool; + // if nodeUrls is not empty, use nodeUrls to create session pool + if (_nodeUrls.Count > 0) + { + sessionPool = new SessionPool(_nodeUrls, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + else + { + sessionPool = new SessionPool(_host, _port, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + return new TableSessionPool(sessionPool); + } +``` + +## 4. 示例代码 + +完整示例:[samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs](https://github.com/apache/iotdb-client-csharp/blob/main/samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs) + +```c# +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Apache.IoTDB.DataStructure; + +namespace Apache.IoTDB.Samples; + +public class TableSessionPoolTest +{ + private readonly SessionPoolTest sessionPoolTest; + + public TableSessionPoolTest(SessionPoolTest sessionPoolTest) + { + this.sessionPoolTest = sessionPoolTest; + } + + public async Task Test() + { + await TestCleanup(); + + await TestSelectAndInsert(); + await TestUseDatabase(); + // await TestCleanup(); + } + + + public async Task TestSelectAndInsert() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test2"); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // or use full qualified table name + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table test1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + // show tables by specifying another database + // using SHOW tables FROM + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES FROM test1"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + var tableName = "testTable1"; + List columnNames = + new List { + "region_id", + "plant_id", + "device_id", + "model", + "temperature", + "humidity" }; + List dataTypes = + new List{ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.FLOAT, + TSDataType.DOUBLE}; + List columnCategories = + new List{ + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.ATTRIBUTE, + ColumnCategory.FIELD, + ColumnCategory.FIELD}; + var values = new List> { }; + var timestamps = new List { }; + for (long timestamp = 0; timestamp < 100; timestamp++) + { + timestamps.Add(timestamp); + values.Add(new List { "1", "5", "3", "A", 1.23F + timestamp, 111.1 + timestamp }); + } + var tablet = new Tablet(tableName, columnNames, columnCategories, dataTypes, values, timestamps); + + await tableSessionPool.InsertAsync(tablet); + + + res = await tableSessionPool.ExecuteQueryStatementAsync("select * from testTable1 " + + "where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + + public async Task TestUseDatabase() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetDatabase("test1") + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // show tables from current database + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + public async Task TestCleanup() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test2"); + + await tableSessionPool.Close(); + } +} +``` diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API.md b/src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API.md rename to src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API_apache.md diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md new file mode 100644 index 000000000..3b3b47c24 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/API/Programming-Cpp-Native-API_timecho.md @@ -0,0 +1,461 @@ + + +# C++ 原生接口 + +## 1. 依赖 + +- Java 8+ +- Flex +- Bison 2.7+ +- Boost 1.56+ +- OpenSSL 1.0+ +- GCC 5.5.0+ + + +## 2. 安装 + +### 2.1 安装相关依赖 + +- **MAC** +1. 安装 Bison : + + 使用下面 brew 命令安装 bison 版本: + ```shell + brew install bison + ``` + +2. 安装 Boost :确保安装最新的 Boost 版本。 + + ```shell + brew install boost + ``` + +3. 检查 OpenSSL :确保 openssl 库已安装,默认的 openssl 头文件路径为"/usr/local/opt/openssl/include" + + 如果在编译过程中出现找不到 openssl 的错误,尝试添加`-Dopenssl.include.dir=""` + + +- **Ubuntu 16.04+ 或其他 Debian 系列** + + 使用以下命令安装所赖: + + ```shell + sudo apt-get update + sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-dev + ``` + + +- **CentOS 7.7+/Fedora/Rocky Linux 或其他 Red-hat 系列** + + 使用 yum 命令安装依赖: + + ```shell + sudo yum update + sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel + ``` + + +- **Windows** + +1. 构建编译环境 + - 安装 MS Visual Studio(推荐安装 2019+ 版本):安装时需要勾选 Visual Studio C/C++ IDE and compiler(supporting CMake, Clang, MinGW) + - 下载安装 [CMake](https://cmake.org/download/) 。 + +2. 下载安装 Flex、Bison + - 下载 [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/) + - 下载后需要将可执行文件重命名为 flex.exe 和 bison.exe 以保证编译时能够被找到,添加可执行文件的目录到 PATH 环境变量中 + +3. 安装 Boost 库 + - 下载 [Boost](https://www.boost.org/users/download/) + - 本地编译 Boost :依次执行 bootstrap.bat 和 b2.exe + - 添加 Boost 安装目录到 PATH 环境变量中,例如 `C:\Program Files (x86)\boost_1_78_0` + +4. 安装 OpenSSL + - 下载安装 [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) + - 添加 OpenSSL 下的 include 目录到 PATH 环境变量中 + + +### 2.2 执行编译 + +从 git 克隆源代码: +```shell +git clone https://github.com/apache/iotdb.git +``` + +默认的主分支是 master 分支,如果你想使用某个发布版本,请切换分支 (如 1.3.2 版本): +```shell +git checkout rc/1.3.2 +``` + +在 IoTDB 根目录下执行 maven 编译: + +- Mac 或 glibc 版本 >= 2.32 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- glibc 版本 >= 2.31 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT + ``` + +- glibc 版本 >= 2.17 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT + ``` + +- 使用 Visual Studio 2022 的 Windows + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- 使用 Visual Studio 2019 的 Windows + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 16 2019" -Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT + ``` + - 如果没有将 Boost 库地址加入 PATH 环境变量,在编译命令中还需添加相关参数,例如:`-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"` + +编译成功后,打包好的库文件位于 `iotdb-client/client-cpp/target` 中,同时可以在 `example/client-cpp-example/target` 下找到编译好的示例程序。 + +### 2.3 编译 Q&A + +Q:Linux 上的环境有哪些要求呢? + +A: +- 已知依赖的 glibc (x86_64 版本) 最低版本要求为 2.17,GCC 最低版本为 5.5 +- 已知依赖的 glibc (ARM 版本) 最低版本要求为 2.31,GCC 最低版本为 10.2 +- 如果不满足上面的要求,可以尝试自己本地编译 Thrift + - 下载 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 这里的代码 + - 执行 `./mvnw clean install` + - 回到 iotdb 代码目录执行 `./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp` + + +Q:Linux 编译报错`undefined reference to '_libc_sinle_thread'`如何处理? + +A: +- 该问题是用于默认的预编译 Thrift 依赖了过高的 glibc 版本导致的 +- 可以尝试在编译的 maven 命令中增加 `-Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT` 或者 `-Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT` + +Q:如果在 Windows 上需要使用 Visual Studio 2017 或更早版本进行编译,要怎么做? + +A: +- 可以尝试自己本地编译 Thrift 后再进行客户端的编译 + - 下载 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 这里的代码 + - 执行 `.\mvnw.cmd clean install` + - 回到 iotdb 代码目录执行 `.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 15 2017"` + +Q: Windows 上使用 Visual Studio 进行编译时出现乱码,如何解决? + +A: +- 该问题是由于项目整体使用 utf-8 编码,而编译用到的一些 windows 系统文件编码不是 utf-8(系统编码默认跟随地区,在中国为 GBK) +- 可以在控制面板中更改系统区域设置,具体操作方法为:打开控制面板 -> 时钟和区域 -> 区域,切换到管理选项卡,在 "非Unicode程序的语言" 下,选择更改系统区域设置,勾选 `Beta版:使用Unicode UTF-8提供全球语言支持` 后重启电脑。(细节可能随windows版本有差异,可在网上寻找详细教程) +- 注意,修改 windows 系统编码后可能会导致一些其他使用 GBK 编码的程序出现乱码,将系统区域改回后可复原,请自行斟酌。 + +## 3. 使用方式 + +### 3.1 TableSession 类 + +C++ 客户端的操作均通过 TableSession 类进行,下面将给出 TableSession 接口中定义的方法说明。 + +#### 3.1.1 方法列表 + +1. `insert(Tablet& tablet, bool sorted = false)`,将一个包含时间序列数据的Tablet对象插入到数据库中,sorted参数指明tablet中的行是否已按时间排序。 +2. `executeNonQueryStatement(string& sql)`,执行非查询SQL语句,如DDL(数据定义语言)或DML(数据操作语言)命令。 +3. `executeQueryStatement(string& sql)`,执行查询SQL语句,并返回包含查询结果的SessionDataSet对象,可选timeoutInMs参数指示超时返回时间。 +4. `open(bool enableRPCCompression = false)`,开启连接,并决定是否启用RPC压缩(客户端状态须与服务端一致,默认不开启)。 +5. `close()`,关闭连接。 + +#### 3.1.2 接口展示 + +```cpp +class TableSession { +private: + Session* session; +public: + TableSession(Session* session) { + this->session = session; + } + void insert(Tablet& tablet, bool sorted = false); + void executeNonQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql, int64_t timeoutInMs); + string getDatabase(); //获取当前选择的database,可由executeNonQueryStatement代替 + void open(bool enableRPCCompression = false); + void close(); +}; +``` + +### 3.2 TableSessionBuilder 类 + +TableSessionBuilder类是一个构建器,用于配置和创建TableSession类的实例,通过它可以在创建实例时方便地设置连接参数、查询参数等。 + +#### 3.2.1 使用示例 + +```cpp +//设置连接的IP、端口、用户名、密码 +//设置的顺序任意,确保最后调用build()即可,创建的实例默认已进行open()连接操作 +session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->build(); +``` + +#### 3.2.2 可设置的参数列表 + +| **参数名** | **描述** | **默认值** | +| :---: | :---: |:-------------------------:| +| host | 设置连接的节点IP | "127.0.0.1" ("localhost") | +| rpcPort | 设置连接的节点端口 | 6667 | +| username | 设置连接的用户名 | "root" | +| password | 设置连接密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | +| zoneId | 设置时区相关的ZoneId | "" | +| fetchSize | 设置查询结果的获取大小 | 10000 | +| database | 设置目标数据库名称 | "" | + + +## 4. 示例代码 + +示例工程源代码: + +- `example/client-cpp-example/src/TableModelSessionExample.cpp` : [TableModelSessionExample](https://github.com/apache/iotdb/tree/rc/2.0.1/example/client-cpp-example/src/TableModelSessionExample.cpp) + +编译成功后,示例代码工程位于 `example/client-cpp-example/target` + +```cpp +#include "TableSession.h" +#include "TableSessionBuilder.h" + +using namespace std; + +TableSession *session; + +void insertRelationalTablet() { + + vector> schemaList { + make_pair("region_id", TSDataType::TEXT), + make_pair("plant_id", TSDataType::TEXT), + make_pair("device_id", TSDataType::TEXT), + make_pair("model", TSDataType::TEXT), + make_pair("temperature", TSDataType::FLOAT), + make_pair("humidity", TSDataType::DOUBLE) + }; + + vector columnTypes = { + ColumnCategory::TAG, + ColumnCategory::TAG, + ColumnCategory::TAG, + ColumnCategory::ATTRIBUTE, + ColumnCategory::FIELD, + ColumnCategory::FIELD + }; + + Tablet tablet("table1", schemaList, columnTypes, 100); + + for (int row = 0; row < 100; row++) { + int rowIndex = tablet.rowSize++; + tablet.timestamps[rowIndex] = row; + tablet.addValue("region_id", rowIndex, "1"); + tablet.addValue("plant_id", rowIndex, "5"); + tablet.addValue("device_id", rowIndex, "3"); + tablet.addValue("model", rowIndex, "A"); + tablet.addValue("temperature", rowIndex, 37.6F); + tablet.addValue("humidity", rowIndex, 111.1); + if (tablet.rowSize == tablet.maxRowNumber) { + session->insert(tablet); + tablet.reset(); + } + } + + if (tablet.rowSize != 0) { + session->insert(tablet); + tablet.reset(); + } +} + +void Output(unique_ptr &dataSet) { + for (const string &name: dataSet->getColumnNames()) { + cout << name << " "; + } + cout << endl; + while (dataSet->hasNext()) { + cout << dataSet->next()->toString(); + // 可通过 RowRecord* row = dataSet->next(); + // for(auto field: row.fields) field.intV/longV/stringV 来获取值 + } + cout << endl; +} + +void OutputWithType(unique_ptr &dataSet) { + for (const string &name: dataSet->getColumnNames()) { + cout << name << " "; + } + cout << endl; + for (const string &type: dataSet->getColumnTypeList()) { + cout << type << " "; + } + cout << endl; + while (dataSet->hasNext()) { + cout << dataSet->next()->toString(); + } + cout << endl; +} + +int main() { + try { + session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->build(); + + + cout << "[Create Database db1,db2]\n" << endl; + try { + session->executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS db1"); + session->executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Use db1 as database]\n" << endl; + try { + session->executeNonQueryStatement("USE db1"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Create Table table1,table2]\n" << endl; + try { + session->executeNonQueryStatement("create table db1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + session->executeNonQueryStatement("create table db2.table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show Tables]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show tables from specific database]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES FROM db1"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[InsertTablet]\n" << endl; + try { + insertRelationalTablet(); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Query Table Data]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SELECT * FROM table1" + " where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + OutputWithType(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + session->close(); + + // specify database in constructor + session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->database("db1") + ->build(); + + cout << "[Show tables from current database(db1)]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Change database to db2]\n" << endl; + try { + session->executeNonQueryStatement("USE db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show tables from current database(db2)]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Drop Database db1,db2]\n" << endl; + try { + session->executeNonQueryStatement("DROP DATABASE db1"); + session->executeNonQueryStatement("DROP DATABASE db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "session close\n" << endl; + session->close(); + + delete session; + + cout << "finished!\n" << endl; + } catch (IoTDBConnectionException &e) { + cout << e.what() << endl; + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + return 0; +} +``` + +## 5. FAQ + +### 5.1 Thrift 编译相关问题 + +1. MAC:本地 Maven 编译 Thrift 时如出现以下链接的问题,可以尝试将 xcode-commandline 版本从 12 降低到 11.5 + https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087 + + +2. Windows:Maven 编译 Thrift 时需要使用 wget 下载远端文件,可能出现以下报错: + ``` + Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser + ``` + + 解决方法: + - 尝试删除 ".m2\repository\\.cache\" 目录并重试。 + - 在添加 pom 文件对应的 download-maven-plugin 中添加 "\true\" diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API.md b/src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API.md rename to src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API_apache.md diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md new file mode 100644 index 000000000..da1533a2e --- /dev/null +++ b/src/zh/UserGuide/Master/Table/API/Programming-Go-Native-API_timecho.md @@ -0,0 +1,593 @@ + + +# Go 原生接口 + +## 1. 使用方法 +### 1.1 依赖 + +* golang >= 1.13 +* make >= 3.0 +* curl >= 7.1.1 +* thrift 0.15.0 +* Linux、Macos 或其他类 unix 系统 +* Windows+bash (下载 IoTDB Go client 需要 git ,通过 WSL、cygwin、Git Bash 任意一种方式均可) + +### 1.2 安装方法 + +* 通过 go mod + +```sh +# 切换到 GOPATH 的 HOME 路径,启用 Go Modules 功能 +export GO111MODULE=on + +# 配置 GOPROXY 环境变量 +export GOPROXY=https://goproxy.io + +# 创建命名的文件夹或目录,并切换当前目录 +mkdir session_example && cd session_example + +# 保存文件,自动跳转到新的地址 +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +# 初始化 go module 环境 +go mod init session_example + +# 下载依赖包 +go mod tidy + +# 编译并运行程序 +go run session_example.go +``` + +* 通过 GOPATH + +```sh +# get thrift 0.13.0 +go get github.com/apache/thrift@0.13.0 + +# 递归创建目录 +mkdir -p $GOPATH/src/iotdb-client-go-example/session_example + +# 切换到当前目录 +cd $GOPATH/src/iotdb-client-go-example/session_example + +# 保存文件,自动跳转到新的地址 +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +# 初始化 go module 环境 +go mod init + +# 下载依赖包 +go mod tidy + +# 编译并运行程序 +go run session_example.go +``` + +## 2. ITableSession 接口 +### 2.1 功能描述 + +ITableSession 接口定义了与 IoTDB 交互的基本操作,可以执行数据插入、查询操作以及关闭会话等,非线程安全。 + +### 2.2 方法列表 + +以下是 ITableSession 接口中定义的方法及其详细说明: + +| **方法名** | **描述** | **参数** | **返回值** | **返回异常** | +| -------------------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------- | +| `Insert(tablet *Tablet)` | 将一个包含时间序列数据的Tablet 插入到数据库中| `tablet`: 要插入的`Tablet`| `TSStatus`:执行结果的状态,由 common 包定义。 | `errer`:操作过程中的错误(如连接失败)。 | +| `xecuteNonQueryStatement(sql string)`| 执行非查询 SQL 语句,如 DDL (数据定义语言)或 DML (数据操作语言)命令 | `sql`: 要执行的 SQL 语句。| 同上 | 同上| +| `ExecuteQueryStatement (sql string, timeoutInMs *int64)` | 执行查询 SQL 语句,并返回查询结果集 | `sql`: 要执行的查询 SQL 语句。`timeoutInMs`: 查询超时时间(毫秒) | `SessionDataSet`:查询结果数据集。 | `errer`:操作过程中的错误(如连接失败)。 | +| `Close()` | 关闭会话,释放所持有的资源 | 无 | 无 | `errer`:关闭连接过程中的错误 | + +### 2.3 接口展示 +1. ITableSession + +```go +// ITableSession defines an interface for interacting with IoTDB tables. +// It supports operations such as data insertion, executing queries, and closing the session. +// Implementations of this interface are expected to manage connections and ensure +// proper resource cleanup. +// +// Each method may return an error to indicate issues such as connection errors +// or execution failures. +// +// Since this interface includes a Close method, it is recommended to use +// defer to ensure the session is properly closed. +type ITableSession interface { + + // Insert inserts a Tablet into the database. + // + // Parameters: + // - tablet: A pointer to a Tablet containing time-series data to be inserted. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + Insert(tablet *Tablet) (r *common.TSStatus, err error) + + // ExecuteNonQueryStatement executes a non-query SQL statement, such as a DDL or DML command. + // + // Parameters: + // - sql: The SQL statement to execute. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err error) + + // ExecuteQueryStatement executes a query SQL statement and returns the result set. + // + // Parameters: + // - sql: The SQL query statement to execute. + // - timeoutInMs: A pointer to the timeout duration in milliseconds for the query execution. + // + // Returns: + // - result: A pointer to SessionDataSet containing the query results. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteQueryStatement(sql string, timeoutInMs *int64) (*SessionDataSet, error) + + // Close closes the session, releasing any held resources. + // + // Returns: + // - err: An error if there is an issue with closing the IoTDB connection. + Close() (err error) +} +``` + +2. 构造 TableSession + +* Config 中不需要手动设置 sqlDialect,使用时只需要使用对应的 NewSession 函数 + +```Go +type Config struct { + Host string + Port string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Version Version + Database string +} + +type ClusterConfig struct { + NodeUrls []string //ip:port + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Database string +} + +// NewTableSession creates a new TableSession instance using the provided configuration. +// +// Parameters: +// - config: The configuration for the session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// - connectionTimeoutInMs: The timeout in milliseconds for establishing a connection. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewTableSession(config *Config, enableRPCCompression bool, connectionTimeoutInMs int) (ITableSession, error) + +// NewClusterTableSession creates a new TableSession instance for a cluster setup. +// +// Parameters: +// - clusterConfig: The configuration for the cluster session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewClusterTableSession(clusterConfig *ClusterConfig, enableRPCCompression bool) (ITableSession, error) +``` + +> 注意: +> +> 通过 *NewTableSession 或 NewClusterTableSession* 得到的 TableSession,连接已经建立,不需要额外的 open 操作。 + +### 2.4 示例代码 + +```Go +package main + +import ( + "flag" + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "math/rand" + "strconv" + "time" +) + +func main() { + flag.Parse() + config := &client.Config{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_session", + } + session, err := client.NewTableSession(config, false, 0) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + checkError(session.ExecuteNonQueryStatement("create database test_db")) + checkError(session.ExecuteNonQueryStatement("use test_db")) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + insertRelationalTablet(session) + showTables(session) + query(session) +} + +func getTextValueFromDataSet(dataSet *client.SessionDataSet, columnName string) string { + if dataSet.IsNull(columnName) { + return "null" + } else { + return dataSet.GetText(columnName) + } +} + +func insertRelationalTablet(session client.ITableSession) { + tablet, err := client.NewRelationalTablet("t1", []*client.MeasurementSchema{ + { + Measurement: "id1", + DataType: client.STRING, + }, + { + Measurement: "id2", + DataType: client.STRING, + }, + { + Measurement: "s1", + DataType: client.TEXT, + }, + { + Measurement: "s2", + DataType: client.TEXT, + }, + }, []client.ColumnCategory{client.TAG, client.TAG, client.FIELD, client.FIELD}, 1024) + if err != nil { + log.Fatal("Failed to create relational tablet {}", err) + } + ts := time.Now().UTC().UnixNano() / 1000000 + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_"+strconv.Itoa(row), 0, row) + tablet.SetValueAt("id2_field_"+strconv.Itoa(row), 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) + + tablet.Reset() + + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_1", 0, row) + tablet.SetValueAt("id2_field_1", 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + + nullValueColumn := rand.Intn(4) + tablet.SetValueAt(nil, nullValueColumn, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) +} + +func showTables(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("tableName is", dataSet.GetText("TableName")) + } +} + +func query(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("select * from t1", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("%v %v %v %v", getTextValueFromDataSet(dataSet, "id1"), getTextValueFromDataSet(dataSet, "id2"), getTextValueFromDataSet(dataSet, "s1"), getTextValueFromDataSet(dataSet, "s2")) + } +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + +## 3. TableSessionPool 接口 +### 3.1 功能描述 + +TableSessionPool 是一个用于管理 ITableSession 实例的池。这个池可以帮助我们高效地重用连接,并且在不需要时正确地清理资源, 该接口定义了如何从池中获取会话以及如何关闭池的基本操作。 + +### 3.2 方法列表 + +| **方法名** | **描述** | **返回值** | **返回异常** | +| -------------------- | -------------------------------------------------------------------- | --------------------------- | --------------------------------- | +| `GetSession()` | 从池中获取一个 ITableSession 实例,用于与 IoTDB 交互。 | `ITableSession `实例| `error`:获取失败的错误原因 | +| `Close()` | 关闭会话池,释放任何持有的资源。关闭后,不能再从池中获取新的会话。 | 无 | 无 | + +### 3.3 接口展示 +1. TableSessionPool + +```Go +// TableSessionPool manages a pool of ITableSession instances, enabling efficient +// reuse and management of resources. It provides methods to acquire a session +// from the pool and to close the pool, releasing all held resources. +// +// This implementation ensures proper lifecycle management of sessions, +// including efficient reuse and cleanup of resources. + +// GetSession acquires an ITableSession instance from the pool. +// +// Returns: +// - A usable ITableSession instance for interacting with IoTDB. +// - An error if a session cannot be acquired. +func (spool *TableSessionPool) GetSession() (ITableSession, error) { + return spool.sessionPool.getTableSession() +} + +// Close closes the TableSessionPool, releasing all held resources. +// Once closed, no further sessions can be acquired from the pool. +func (spool *TableSessionPool) Close() +``` + +2. 构造 TableSessionPool + +```Go +type PoolConfig struct { + Host string + Port string + NodeUrls []string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + Database string + sqlDialect string +} + +// NewTableSessionPool creates a new TableSessionPool with the specified configuration. +// +// Parameters: +// - conf: PoolConfig defining the configuration for the pool. +// - maxSize: The maximum number of sessions the pool can hold. +// - connectionTimeoutInMs: Timeout for establishing a connection in milliseconds. +// - waitToGetSessionTimeoutInMs: Timeout for waiting to acquire a session in milliseconds. +// - enableCompression: A boolean indicating whether to enable compression. +// +// Returns: +// - A TableSessionPool instance. +func NewTableSessionPool(conf *PoolConfig, maxSize, connectionTimeoutInMs, waitToGetSessionTimeoutInMs int, + enableCompression bool) TableSessionPool +``` + +> 注意: +> +> * 通过 TableSessionPool 得到的 TableSession,如果已经在创建 TableSessionPool 指定了 Database,使用时可以不再指定 Database。 +> * 如果使用过程中通过 use database 指定了其他 database,在 close 放回 TableSessionPool 时会自动恢复为 TableSessionPool 所用的 database。 + +### 3.4 示例代码 + +```go +package main + +import ( + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "strconv" + "sync" + "sync/atomic" + "time" +) + +func main() { + sessionPoolWithSpecificDatabaseExample() + sessionPoolWithoutSpecificDatabaseExample() + putBackToSessionPoolExample() +} + +func putBackToSessionPoolExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 4000, false) + defer sessionPool.Close() + + num := 4 + successGetSessionNum := int32(0) + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database "+dbName+"because ", err) + return + } + atomic.AddInt32(&successGetSessionNum, 1) + defer func() { + time.Sleep(6 * time.Second) + // put back to session pool + session.Close() + }() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table table_of_" + dbName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() + log.Println("success num is", successGetSessionNum) + + log.Println("All session's database have been reset.") + // the using database will automatically reset to session pool's database after the session closed + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to get session because ", err) + } + defer session.Close() + timeout := int64(3000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Println("table is", dataSet.GetText("TableName")) + } + }() + } + wg.Wait() +} + +func sessionPoolWithSpecificDatabaseExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + tableName := "t" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create table "+tableName+"because ", err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create table " + tableName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func sessionPoolWithoutSpecificDatabaseExample() { + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database ", dbName, err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + diff --git a/src/zh/UserGuide/Master/Table/API/Programming-JDBC_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-JDBC_timecho.md index 18a767829..4bc3ea2bb 100644 --- a/src/zh/UserGuide/Master/Table/API/Programming-JDBC_timecho.md +++ b/src/zh/UserGuide/Master/Table/API/Programming-JDBC_timecho.md @@ -76,7 +76,7 @@ IoTDB JDBC接口提供了一种标准的方式来与IoTDB数据库进行交互 String url = "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table"; ``` -JDBC接口示例代码:[src/main/java/org/apache/iotdb/TableModelJDBCExample.java](https://github.com/apache/iotdb/blob/master/example/jdbc/src/main/java/org/apache/iotdb/TableModelJDBCExample.java) +JDBC接口示例代码:[src/main/java/org/apache/iotdb/TableModelJDBCExample.java](https://github.com/apache/iotdb/blob/rc/2.0.1/example/jdbc/src/main/java/org/apache/iotdb/TableModelJDBCExample.java) ```Java @@ -123,7 +123,7 @@ public class TableModelJDBCExample { // don't specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "TimechoDB@2021"); //V2.0.6.x 之前默认密码是root Statement statement = connection.createStatement()) { statement.execute("CREATE DATABASE test1"); @@ -164,7 +164,7 @@ public class TableModelJDBCExample { // specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "TimechoDB@2021"); //V2.0.6.x 之前默认密码是root Statement statement = connection.createStatement()) { // show tables from current database test1 try (ResultSet resultSet = statement.executeQuery("SHOW TABLES")) { diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md index 209421a64..cf6c935a2 100644 --- a/src/zh/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md +++ b/src/zh/UserGuide/Master/Table/API/Programming-Java-Native-API_timecho.md @@ -142,17 +142,17 @@ TableSessionBuilder类是一个构建器,用于配置和创建ITableSession接 以下是TableSessionBuilder类中可用的配置选项及其默认值: -| **配置项** | **描述** | **默认值** | -| ---------------------------------------------------- | ---------------------------------------- | ------------------------------------------- | +| **配置项** | **描述** | **默认值** | +| ---------------------------------------------------- | ---------------------------------------- |---------------------------------------------| | nodeUrls(List`` nodeUrls) | 设置IoTDB集群的节点URL列表 | Collections.singletonList("localhost:6667") | | username(String username) | 设置连接的用户名 | "root" | -| password(String password) | 设置连接的密码 | "root" | +| password(String password) | 设置连接的密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | | database(String database) | 设置目标数据库名称 | null | -| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | +| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | | fetchSize(int fetchSize) | 设置查询结果的获取大小 | 5000 | | zoneId(ZoneId zoneId) | 设置时区相关的ZoneId | ZoneId.systemDefault() | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | | enableRedirection(boolean enableRedirection) | 是否启用集群节点的重定向 | true | | enableAutoFetch(boolean enableAutoFetch) | 是否启用自动获取可用DataNodes | true | | maxRetryCount(int maxRetryCount) | 设置连接尝试的最大重试次数 | 60 | @@ -161,7 +161,7 @@ TableSessionBuilder类是一个构建器,用于配置和创建ITableSession接 | trustStore(String keyStore) | 设置SSL连接的信任库路径 | null | | trustStorePwd(String keyStorePwd) | 设置SSL连接的信任库密码 | null | | enableCompression(boolean enableCompression) | 是否启用RPC压缩 | false | -| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 0(无超时) | +| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 0(无超时) | #### 3.2.3 接口展示 @@ -198,7 +198,7 @@ public class TableSessionBuilder { * * @param username the username. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "root“ */ public TableSessionBuilder username(String username); @@ -207,7 +207,7 @@ public class TableSessionBuilder { * * @param password the password. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //V2.0.6.x 之前默认密码是root */ public TableSessionBuilder password(String password); @@ -404,22 +404,22 @@ TableSessionPool 的构造器,用于配置和创建 ITableSessionPool 的实 以下是 TableSessionPoolBuilder 类的可用配置选项及其默认值: -| **配置项** | **描述** | **默认值** | -| ------------------------------------------------------------ | -------------------------------------------- | ------------------------------------------- | +| **配置项** | **描述** | **默认值** | +| ------------------------------------------------------------ | -------------------------------------------- |---------------------------------------------| | nodeUrls(List`` nodeUrls) | 设置IoTDB集群的节点URL列表 | Collections.singletonList("localhost:6667") | | maxSize(int maxSize) | 设置会话池的最大大小,即池中允许的最大会话数 | 5 | | user(String user) | 设置连接的用户名 | "root" | -| password(String password) | 设置连接的密码 | "root" | +| password(String password) | 设置连接的密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | | database(String database) | 设置目标数据库名称 | "root" | -| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | +| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | | fetchSize(int fetchSize) | 设置查询结果的获取大小 | 5000 | | zoneId(ZoneId zoneId) | 设置时区相关的 ZoneId | ZoneId.systemDefault() | -| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | 设置从池中获取会话的超时时间(毫秒) | 30000(30秒) | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | +| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | 设置从池中获取会话的超时时间(毫秒) | 30000(30秒) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | | enableCompression(boolean enableCompression) | 是否启用连接的压缩 | false | | enableRedirection(boolean enableRedirection) | 是否启用集群节点的重定向 | true | -| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 10000(10秒) | +| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 10000(10秒) | | enableAutoFetch(boolean enableAutoFetch) | 是否启用自动获取可用DataNodes | true | | maxRetryCount(int maxRetryCount) | 设置连接尝试的最大重试次数 | 60 | | retryIntervalInMs(long retryIntervalInMs) | 设置重试间隔时间(毫秒) | 500 | @@ -479,7 +479,7 @@ public class TableSessionPoolBuilder { * * @param password the password. * @return the current {@link TableSessionPoolBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //V2.0.6.x 之前默认密码是root */ public TableSessionPoolBuilder password(String password); @@ -686,7 +686,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root .maxSize(1) .build(); @@ -787,7 +787,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021")//V2.0.6.x 之前默认密码是root .maxSize(1) .database("test1") .build(); diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API.md b/src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API.md rename to src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API_apache.md diff --git a/src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md b/src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..2ebecf58e --- /dev/null +++ b/src/zh/UserGuide/Master/Table/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,550 @@ + + +# Python 原生接口 + +## 1. 使用方式 + +安装依赖包: + +```shell +pip3 install apache-iotdb>=2.0 +``` + +## 2. 读写操作 + +### 2.1 TableSession + +#### 2.1.1 功能描述 + +TableSession是IoTDB的一个核心类,用于与IoTDB数据库进行交互。通过这个类,用户可以执行SQL语句、插入数据以及管理数据库会话。 + +#### 2.1.2 方法列表 + +| **方法名称** | **描述** | **参数类型** | **返回类型** | +| --------------------------- | ---------------------------------- | ---------------------------------- | -------------- | +| insert | 写入数据 | tablet: Union[Tablet, NumpyTablet] | None | +| execute_non_query_statement | 执行非查询 SQL 语句,如 DDL 和 DML | sql: str | None | +| execute_query_statement | 执行查询 SQL 语句并返回结果集 | sql: str | SessionDataSet | +| close | 关闭会话并释放资源 | None | None | + +#### 2.1.3 接口展示 + +**TableSession:** + + +```Python +class TableSession(object): +def insert(self, tablet: Union[Tablet, NumpyTablet]): + """ + Insert data into the database. + + Parameters: + tablet (Tablet | NumpyTablet): The tablet containing the data to be inserted. + Accepts either a `Tablet` or `NumpyTablet`. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_non_query_statement(self, sql: str): + """ + Execute a non-query SQL statement. + + Parameters: + sql (str): The SQL statement to execute. Typically used for commands + such as INSERT, DELETE, or UPDATE. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_query_statement(self, sql: str, timeout_in_ms: int = 0) -> "SessionDataSet": + """ + Execute a query SQL statement and return the result set. + + Parameters: + sql (str): The SQL query to execute. + timeout_in_ms (int, optional): Timeout for the query in milliseconds. Defaults to 0, + which means no timeout. + + Returns: + SessionDataSet: The result set of the query. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def close(self): + """ + Close the session and release resources. + + Raises: + IoTDBConnectionException: If there is an issue closing the connection. + """ + pass +``` + +### 2.2 TableSessionConfig + +#### 2.2.1 功能描述 + +TableSessionConfig是一个配置类,用于设置和创建TableSession 实例。它定义了连接到IoTDB数据库所需的各种参数。 + +#### 2.2.2 配置选项 + +| **配置项** | **描述** | **类型** | **默认值** | +| ------------------ | ------------------------- | -------- |-----------------------------------------| +| node_urls | 数据库连接的节点 URL 列表 | list | ["localhost:6667"] | +| username | 数据库连接用户名 | str | "root" | +| password | 数据库连接密码 | str | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | +| database | 要连接的目标数据库 | str | None | +| fetch_size | 每次查询获取的行数 | int | 5000 | +| time_zone | 会话的默认时区 | str | Session.DEFAULT_ZONE_ID | +| enable_compression | 是否启用数据压缩 | bool | False | + +#### 2.2.3 接口展示 + +```Python +class TableSessionConfig(object): + """ + Configuration class for a TableSession. + + This class defines various parameters for connecting to and interacting + with the IoTDB tables. + """ + + def __init__( + self, + node_urls: list = None, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_compression: bool = False, + ): + """ + Initialize a TableSessionConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to ["localhost:6667"]. + username (str, optional): The username for the database connection. + Defaults to "root". + password (str, optional): The password for the database connection. + Defaults to "TimechoDB@2021". //V2.0.6.x 之前默认密码是root + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session. + Defaults to Session.DEFAULT_ZONE_ID. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + """ +``` + +**注意事项:** + +在使用完 TableSession 后,务必调用 close 方法来释放资源。 + +## 3. 客户端连接池 + +### 3.1 TableSessionPool + +#### 3.1.1 功能描述 + +TableSessionPool 是一个会话池管理类,用于管理 TableSession 实例的创建和销毁。它提供了从池中获取会话和关闭会话池的功能。 + +#### 3.1.2 方法列表 + +| **方法名称** | **描述** | **返回类型** | **异常** | +| ------------ | ---------------------------------------- | ------------ | -------- | +| get_session | 从会话池中检索一个新的 TableSession 实例 | TableSession | 无 | +| close | 关闭会话池并释放所有资源 | None | 无 | + +#### 3.1.3 接口展示 + +**TableSessionPool:** + +```Python +def get_session(self) -> TableSession: + """ + Retrieve a new TableSession instance. + + Returns: + TableSession: A new session object configured with the session pool. + + Notes: + The session is initialized with the underlying session pool for managing + connections. Ensure proper usage of the session's lifecycle. + """ + +def close(self): + """ + Close the session pool and release all resources. + + This method closes the underlying session pool, ensuring that all + resources associated with it are properly released. + + Notes: + After calling this method, the session pool cannot be used to retrieve + new sessions, and any attempt to do so may raise an exception. + """ +``` + +### 3.2 TableSessionPoolConfig + +#### 3.2.1 功能描述 + +TableSessionPoolConfig是一个配置类,用于设置和创建 TableSessionPool 实例。它定义了初始化和管理 IoTDB 数据库会话池所需的参数。 + +#### 3.2.2 配置选项 + +| **配置项** | **描述** | **类型** | **默认值** | +| ------------------ | ------------------------------ | -------- | ------------------------ | +| node_urls | 数据库连接的节点 URL 列表 | list | None | +| max_pool_size | 会话池中的最大会话数 | int | 5 | +| username | 数据库连接用户名 | str | Session.DEFAULT_USER | +| password | 数据库连接密码 | str | Session.DEFAULT_PASSWORD | +| database | 要连接的目标数据库 | str | None | +| fetch_size | 每次查询获取的行数 | int | 5000 | +| time_zone | 会话池的默认时区 | str | Session.DEFAULT_ZONE_ID | +| enable_redirection | 是否启用重定向 | bool | False | +| enable_compression | 是否启用数据压缩 | bool | False | +| wait_timeout_in_ms | 等待会话可用的最大时间(毫秒) | int | 10000 | +| max_retry | 操作的最大重试次数 | int | 3 | + +#### 3.2.3 接口展示 + + +```Python +class TableSessionPoolConfig(object): + """ + Configuration class for a TableSessionPool. + + This class defines the parameters required to initialize and manage + a session pool for interacting with the IoTDB database. + """ + def __init__( + self, + node_urls: list = None, + max_pool_size: int = 5, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_redirection: bool = False, + enable_compression: bool = False, + wait_timeout_in_ms: int = 10000, + max_retry: int = 3, + ): + """ + Initialize a TableSessionPoolConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to None. + max_pool_size (int, optional): The maximum number of sessions in the pool. + Defaults to 5. + username (str, optional): The username for the database connection. + Defaults to Session.DEFAULT_USER. + password (str, optional): The password for the database connection. + Defaults to Session.DEFAULT_PASSWORD. + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session pool. + Defaults to Session.DEFAULT_ZONE_ID. + enable_redirection (bool, optional): Whether to enable redirection. + Defaults to False. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + wait_timeout_in_ms (int, optional): The maximum time (in milliseconds) to wait for a session + to become available. Defaults to 10000. + max_retry (int, optional): The maximum number of retry attempts for operations. Defaults to 3. + + """ +``` +### 3.3 SSL 连接 + +#### 3.3.1 服务器端配置证书 + +`conf/iotdb-system.properties` 配置文件中查找或添加以下配置项: + +``` +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 配置 python 客户端证书 + +- 设置 use_ssl 为 True 以启用 SSL。 +- 指定客户端证书路径,使用 ca_certs 参数。 + +``` +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**示例代码:使用 SSL 连接 IoTDB** + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前默认密码是root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. 示例代码 + +Session示例代码:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_example.py) + +SessionPool示例代码:[SessionPool Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_pool_example.py) + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +import threading + +import numpy as np + +from iotdb.table_session_pool import TableSessionPool, TableSessionPoolConfig +from iotdb.utils.IoTDBConstants import TSDataType +from iotdb.utils.NumpyTablet import NumpyTablet +from iotdb.utils.Tablet import ColumnType, Tablet + + +def prepare_data(): + print("create database") + # Get a session from the pool + session = session_pool.get_session() + session.execute_non_query_statement("CREATE DATABASE IF NOT EXISTS db1") + session.execute_non_query_statement('USE "db1"') + session.execute_non_query_statement( + "CREATE TABLE table0 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + session.execute_non_query_statement( + "CREATE TABLE table1 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + + print("now the tables are:") + # show result + res = session.execute_query_statement("SHOW TABLES") + while res.has_next(): + print(res.next()) + + session.close() + + +def insert_data(num: int): + print("insert data for table" + str(num)) + # Get a session from the pool + session = session_pool.get_session() + column_names = [ + "id1", + "attr1", + "m1", + ] + data_types = [ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.DOUBLE, + ] + column_types = [ColumnType.TAG, ColumnType.ATTRIBUTE, ColumnType.FIELD] + timestamps = [] + values = [] + for row in range(15): + timestamps.append(row) + values.append(["id:" + str(row), "attr:" + str(row), row * 1.0]) + tablet = Tablet( + "table" + str(num), column_names, data_types, values, timestamps, column_types + ) + session.insert(tablet) + session.execute_non_query_statement("FLush") + + np_timestamps = np.arange(15, 30, dtype=np.dtype(">i8")) + np_values = [ + np.array(["id:{}".format(i) for i in range(15, 30)]), + np.array(["attr:{}".format(i) for i in range(15, 30)]), + np.linspace(15.0, 29.0, num=15, dtype=TSDataType.DOUBLE.np_dtype()), + ] + + np_tablet = NumpyTablet( + "table" + str(num), + column_names, + data_types, + np_values, + np_timestamps, + column_types=column_types, + ) + session.insert(np_tablet) + session.close() + + +def query_data(): + # Get a session from the pool + session = session_pool.get_session() + + print("get data from table0") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + print("get data from table1") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + session.close() + + +def delete_data(): + session = session_pool.get_session() + session.execute_non_query_statement("drop database db1") + print("data has been deleted. now the databases are:") + res = session.execute_query_statement("show databases") + while res.has_next(): + print(res.next()) + session.close() + + +# Create a session pool +username = "root" +password = "TimechoDB@2021" //V2.0.6.x 之前默认密码是root +node_urls = ["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"] +fetch_size = 1024 +database = "db1" +max_pool_size = 5 +wait_timeout_in_ms = 3000 +config = TableSessionPoolConfig( + node_urls=node_urls, + username=username, + password=password, + database=database, + max_pool_size=max_pool_size, + fetch_size=fetch_size, + wait_timeout_in_ms=wait_timeout_in_ms, +) +session_pool = TableSessionPool(config) + +prepare_data() + +insert_thread1 = threading.Thread(target=insert_data, args=(0,)) +insert_thread2 = threading.Thread(target=insert_data, args=(1,)) + +insert_thread1.start() +insert_thread2.start() + +insert_thread1.join() +insert_thread2.join() + +query_data() +delete_data() +session_pool.close() +print("example is finished!") +``` + diff --git a/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_apache.md b/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_apache.md index 78537727c..662f73e2d 100644 --- a/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_apache.md +++ b/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_apache.md @@ -66,7 +66,7 @@ - 数据同步:[数据同步](../User-Manual/Data-Sync_apache.md) -6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_apache.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_apache.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_apache.md)、[Python 原生接口](../API/Programming-Python-Native-API_apache)、[JDBC](../API/Programming-JDBC_apache.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 想了解更多技术细节? diff --git a/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md b/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md index dc5dd94c2..52b70d8e5 100644 --- a/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md +++ b/src/zh/UserGuide/Master/Table/QuickStart/QuickStart_timecho.md @@ -73,7 +73,7 @@ - 数据同步:[数据同步](../User-Manual/Data-Sync_timecho.md) -6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_timecho.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho.md)、[Python 原生接口](../API/Programming-Python-Native-API_timecho)、[JDBC](../API/Programming-JDBC_timecho.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? diff --git a/src/zh/UserGuide/Master/Table/Tools-System/CLI.md b/src/zh/UserGuide/Master/Table/Tools-System/CLI_apache.md similarity index 80% rename from src/zh/UserGuide/Master/Table/Tools-System/CLI.md rename to src/zh/UserGuide/Master/Table/Tools-System/CLI_apache.md index 91ece8f04..37ab9452d 100644 --- a/src/zh/UserGuide/Master/Table/Tools-System/CLI.md +++ b/src/zh/UserGuide/Master/Table/Tools-System/CLI_apache.md @@ -48,32 +48,33 @@ Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect tab # V2.0.4.x 版本及之后 Shell> sbin\windows\start-cli.bat -sql_dialect table 或 +# V2.0.4.x 版本及之后 Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table ``` 其中: - -h 和-p 项是 IoTDB 所在的 IP 和 RPC 端口号(本机未修改 IP 和 RPC 端口号默认为 127.0.0.1、6667) -- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名密码均为`root`) +- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名为`root`,密码为`root`) - -sql_dialect 是登录的数据模型(表模型或树模型),此处指定为 table 代表进入表模型模式 更多参数见: | **参数名** | **参数类型** | **是否为必需参数** | **说明** | **示例** | -|:-----------------------------|:-----------|:------------| :----------------------------------------------------------- |:---------------------| -| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | -| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | -| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | -| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 root。 | -pw root | -| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | -| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | +|:-----------------------------|:-----------|:------------|:-----------------------------------------------------------|:---------------------| +| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | +| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | +| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | +| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 root。 | -pw root | +| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | +| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | | -c | 空 | 否 | 如果服务器设置了 rpc_thrift_compression_enable=true, 则 CLI 必须使用 -c | -c | -| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | -| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | -| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | -| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | -| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | -| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | +| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | +| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | +| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | +| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | +| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | +| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | 启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/Master/Table/Tools-System/CLI_timecho.md b/src/zh/UserGuide/Master/Table/Tools-System/CLI_timecho.md new file mode 100644 index 000000000..7b7bcf538 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/Tools-System/CLI_timecho.md @@ -0,0 +1,123 @@ + + +# 命令行工具 + +IoTDB 为用户提供 CLI 工具用于和服务端程序进行交互操作。在使用 CLI 工具连接 IoTDB 前,请保证 IoTDB 服务已经正常启动。下面介绍 CLI 工具的运行方式和相关参数。 + +> 本文中 $IoTDB_HOME 表示 IoTDB 的安装目录所在路径。 + +## 1. CLI 启动 + +CLI 客户端脚本是 $IoTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动命令为: + +- Linux/MacOS 系统常用启动命令为: + +```Shell +Shell> bash sbin/start-cli.sh -sql_dialect table +或 +# V2.0.6.x 版本之前 +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x 版本及之后 +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +- Windows 系统常用启动命令为: + +```Shell +# V2.0.4.x 版本之前 +Shell> sbin\start-cli.bat -sql_dialect table +或 +Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table + +# V2.0.4.x 版本及之后 +Shell> sbin\windows\start-cli.bat -sql_dialect table +或 +# V2.0.4.x 版本及之后, V2.0.6.x 版本之前 +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x 版本及之后 +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +其中: + +- -h 和-p 项是 IoTDB 所在的 IP 和 RPC 端口号(本机未修改 IP 和 RPC 端口号默认为 127.0.0.1、6667) +- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名为`root`,密码为`TimechoDB@2021`,V2.0.6版本之前密码为`root`) +- -sql_dialect 是登录的数据模型(表模型或树模型),此处指定为 table 代表进入表模型模式 + +更多参数见: + +| **参数名** | **参数类型** | **是否为必需参数** | **说明** | **示例** | +|:-----------------------------|:-----------|:------------|:-----------------------------------------------------------|:---------------------| +| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | +| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | +| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | +| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 TimechoDB@2021(V2.0.6版本之前为root)。 | -pw root | +| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | +| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | +| -c | 空 | 否 | 如果服务器设置了 rpc_thrift_compression_enable=true, 则 CLI 必须使用 -c | -c | +| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | +| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | +| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | +| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | +| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | +| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | + +启动后出现如图提示即为启动成功。 + +![](/img/Cli-01.png) + + +## 2. 在 CLI 中执行语句 + +进入 CLI 后,用户可以直接在对话中输入 SQL 语句进行交互。如: + +- 创建数据库 + +```Java +create database test +``` + +![](/img/Cli-02.png) + + +- 查看数据库 + +```Java +show databases +``` + +![](/img/Cli-03.png) + + +## 3. CLI 退出 + +在 CLI 中输入`quit`或`exit`可退出 CLI 结束本次会话。 + +## 4. 其他说明 + +CLI中使用命令小技巧: + +(1)快速切换历史命令: 上下箭头 + +(2)历史命令自动补全:右箭头 + +(3)中断执行命令: CTRL+C \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md b/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md similarity index 94% rename from src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md rename to src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md index 0855802c9..8aa7709d1 100644 --- a/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool.md +++ b/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_apache.md @@ -31,23 +31,23 @@ ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- | ------------------------------------------ | -| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | | -h | -- host | 主机名 | 否 | 127.0.0.1 | | -p | --port | 端口号 | 否 | 6667 | | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | -| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| -| -| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | -| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | -|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | -| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | -| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | -| -q | --query | 要执行的查询命令 | 否 | 无 | +| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| - | +| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | +| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | +|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | | -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | -| -help | --help | 显示帮助信息 | 否 | | +| -help | --help | 显示帮助信息 | 否 | | ### 2.2 CSV 格式 diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md b/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..47bab5a88 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,176 @@ +# 数据导出 + +## 1. 功能概述 + +数据导出工具 `export-data.sh/bat` 位于 `tools` 目录下,能够将指定 SQL 的查询结果导出为 CSV、SQL 及 TsFile(开源时间序列文件格式)格式。具体功能如下: + +
+ + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVexport-data.sh/bat纯文本格式,存储格式化数据,需按照下文指定 CSV 格式进行构造
SQL包含自定义 SQL 语句的文件
TsFile开源时序数据文件格式
+ + +## 2. 功能详解 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| - | +| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | +| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | +|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | +| -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | +| -help | --help | 显示帮助信息 | 否 | | + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table + [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |--------------------------------------| +| -dt | --datatype | 是否在 CSV 文件的表头输出时间序列的数据类型,可以选择`true`或`false` | 否 | false | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定 CSV 文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL 文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601 | +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.2.3 运行示例: + +```Shell +# 正确示例 +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -db database1 -q "select * from table1" + +# 异常示例 +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -q "select * from table1" +Parse error: Missing required option: db +``` + +### 2.3 SQL 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------------------------------------- | +| -aligned | --use\_aligned | 是否导出为对齐的 SQL 格式 | 否 | true | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定 CSV 文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL 文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601| +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.3.3 运行示例: + +```Shell +# 正确示例 +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -db database1 -start_time 1 + +# 异常示例 +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -start_time 1 +Parse error: Missing required option: db +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 私有参数 + +* 无 + +#### 2.4.3 运行示例: + +```Shell +# 正确示例 +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -db database1 -start_time 0 + +# 异常示例 +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -start_time 0 +Parse error: Missing required option: db +``` diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md b/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md similarity index 99% rename from src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md rename to src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md index aa75f662a..57c7217f2 100644 --- a/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool.md +++ b/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_apache.md @@ -51,9 +51,9 @@ IoTDB 支持三种方式进行数据导入: | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | | -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为 csv sql tsfile 这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | -|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | -| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | -|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | +|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | +| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | +|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | | -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | | -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | | -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md b/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..eeaabf87f --- /dev/null +++ b/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,325 @@ +# 数据导入 + +## 1. 功能概述 + +IoTDB 支持三种方式进行数据导入: +- 数据导入工具 :`import-data.sh/bat` 位于 `tools` 目录下,可以将 `CSV`、`SQL`、及`TsFile`(开源时序文件格式)的数据导入 `IoTDB`。 +- `TsFile` 自动加载功能。 +- `Load SQL` 导入 `TsFile` 。 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVimport-data.sh/bat可用于单个或一个目录的 CSV 文件批量导入 IoTDB
SQL可用于单个或一个目录的 SQL 文件批量导入 IoTDB
TsFile可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
TsFile 自动加载可以监听指定路径下新产生的 TsFile 文件,并将其加载进 IoTDB
Load SQL可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
+ +- **表模型 TsFile 导入暂时只支持本地导入。** + +## 2. 数据导入工具 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |-------------------------------------| +| -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为 csv sql tsfile 这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | +|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | +| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | +|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | +| -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | + + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- |-------------------------------------------|---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -aligned | --use\_aligned | 是否导入为对齐序列 | 否 | false | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -ti | --type\_infer | 通过选项定义类型信息,例如`"boolean=text,int=long, ..."` | 否 | 无 | +| -tp | --timestamp\_precision | 时间戳精度 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms +| + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_0.csv -db database1 -table table1 + +# 异常示例 +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -table table1 +Parse error: Missing required option: db + +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -db database1 -table table5 +There are no tables or the target table table5 does not exist +``` + +#### 2.2.4 导入说明 + +1. CSV 导入规范 + + - 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号`,`),需使用反斜杠(`\`)​进行转义处理。 + - 支持的时间格式:`yyyy-MM-dd'T'HH:mm:ss`, `yyy-MM-dd HH:mm:ss`, 或者 `yyyy-MM-dd'T'HH:mm:ss.SSSZ` 。 + - 时间戳列​必须作为数据文件的首列存在。 + +2. CSV 文件示例 + +```sql +time,region,device,model,temperature,humidity +1970-01-01T08:00:00.001+08:00,"上海","101","F",90.0,35.2 +1970-01-01T08:00:00.002+08:00,"上海","101","F",90.0,34.8 +``` + + +### 2.3 SQL 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- | -------------- |---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | + +#### 2.3.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump0_0.sql -db database1 + +# 异常示例 +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump1_1.sql -db database1 +Source file or directory ./sql/dump1_1.sql does not exist + +# 目标表存在但是元数据不适配/数据异常:生成.failed异常文件记录该条信息,日志打印错误信息如下 +Fail to insert measurements '[column.name]' caused by [data type is not consistent, input '[column.value]', registered '[column.DataType]'] +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` + +#### 2.4.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ------------------------ |----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------| -------------------- | +| -os| --on\_succcess| 1. none:不删除
2. mv:移动成功的文件到目标文件夹
3. cp:硬连接(拷贝)成功的文件到目标文件夹
4. delete:删除 | √ || +| -sd | --success\_dir | 当`--on_succcess`为 mv 或 cp 时,mv 或 cp 的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_succcess`为mv或cp时需要填写 | `${EXEC_DIR}/success`| +| -of| --on\_fail| 1. none:跳过
2. mv:移动失败的文件到目标文件夹
3. cp:硬连接(拷贝)失败的文件到目标文件夹
4. delete:删除 | √ || +| -fd | --fail\_dir | 当`--on_fail`指定为 mv 或 cp 时,mv 或 cp 的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_fail`指定为 mv 或 cp 时需要填写 | `${EXEC_DIR}/fail` | +| -tp | --timestamp\_precision | 时间戳精度
tsfile 非远程导入:-tp 指定 tsfile 文件的时间精度 手动校验和服务器的时间戳是否一致 不一致返回报错信息
远程导入:-tp 指定 tsfile 文件的时间精度 pipe 自动校验时间戳精度是否一致 不一致返回 pipe 报错信息 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms| + + +#### 2.4.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 -os none -of none + +# 异常示例 +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 +Parse error: Missing required options: os, of +``` + +## 3. TsFile 自动加载功能 + +本功能允许 IoTDB 主动监听指定目录下的新增 TsFile,并将 TsFile 自动加载至 IoTDB 中。通过此功能,IoTDB 能自动检测并加载 TsFile,无需手动执行任何额外的加载操作。 + +![](/img/Data-import1.png) + +### 3.1 配置参数 + +可通过从配置文件模版 `iotdb-system.properties.template` 中找到下列参数,添加到 IoTDB 配置文件 `iotdb-system.properties` 中开启 TsFile 自动加载功能。完整配置如下: + +| **配置参数** | **参数说明** | **value 取值范围** | **是否必填** | **默认值** | **加载方式** | +| --------------------------------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------------------- | -------------------- | ------------------------ | -------------------- | +| load\_active\_listening\_enable | 是否开启 DataNode 主动监听并且加载 tsfile 的功能(默认开启)。 | Boolean: true,false | 选填 | true | 热加载 | +| load\_active\_listening\_dirs | 需要监听的目录(自动包括目录中的子目录),如有多个使用 “,“ 隔开;
默认的目录为 `ext/load/pending`;
支持热装载;
**注意:表模型中,文件所在的目录名会作为 database**; | String: 一个或多个文件目录 | 选填 | `ext/load/pending` | 热加载 | +| load\_active\_listening\_fail\_dir | 执行加载 tsfile 文件失败后将文件转存的目录,只能配置一个 | String: 一个文件目录 | 选填 | `ext/load/failed` | 热加载 | +| load\_active\_listening\_max\_thread\_num | 同时执行加载 tsfile 任务的最大线程数,参数被注释掉时的默值为 max(1, CPU 核心数 / 2),当用户设置的值不在这个区间[1, CPU核心数 /2]内时,会设置为默认值 (1, CPU 核心数 / 2) | Long: [1, Long.MAX\_VALUE] | 选填 | max(1, CPU 核心数 / 2) | 重启后生效 | +| load\_active\_listening\_check\_interval\_seconds | 主动监听轮询间隔,单位秒。主动监听 tsfile 的功能是通过轮询检查文件夹实现的。该配置指定了两次检查 `load_active_listening_dirs` 的时间间隔,每次检查完成 `load_active_listening_check_interval_seconds` 秒后,会执行下一次检查。当用户设置的轮询间隔小于 1 时,会被设置为默认值 5 秒 | Long: [1, Long.MAX\_VALUE] | 选填 | 5 | 重启后生效 | + +### 3.2 示例说明 + +```bash +load_active_listening_dir/ +├─sensors/ +│ ├─temperature/ +│ │ └─temperature-table.TSFILE + +``` + +- 表模型 TsFile + - `temperature-table.TSFILE`: 会被导入到 `temperature` database 下(因为它位于`sensors/temperature/` 目录下) + +### 3.3 注意事项 + +1. 如果待加载的文件中,存在 mods 文件,应优先将 mods 文件移动到监听目录下面,然后再移动 tsfile 文件,且 mods 文件应和对应的 tsfile 文件处于同一目录。防止加载到 tsfile 文件时,加载不到对应的 mods 文件 +2. 禁止设置 Pipe 的 receiver 目录、存放数据的 data 目录等作为监听目录 +3. 禁止 `load_active_listening_fail_dir` 与 `load_active_listening_dirs` 存在相同的目录,或者互相嵌套 +4. 保证 `load_active_listening_dirs` 目录有足够的权限,在加载成功之后,文件将会被删除,如果没有删除权限,则会重复加载 + +## 4. Load SQL + +IoTDB 支持通过 CLI 执行 SQL 直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的 IoTDB 实例中。 + +### 4.1 运行命令 + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` :文件本身,或是包含若干文件的文件夹路径 +* ``:可选参数,具体如下表所示 + +| Key | Key 描述 | Value 类型 | Value 取值范围 | Value 是否必填 | Value 默认值 | +| --------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ | ----------------------------------------- | ---------------- | -------------------------- | +| `database-level` | 当 tsfile 对应的 database 不存在时,可以通过` database-level`参数的值来制定 database 的级别,默认为`iotdb-common.properties`中设置的级别。
例如当设置 level 参数为 1 时表明此 tsfile 中所有时间序列中层级为1的前缀路径是 database。 | Integer | `[1: Integer.MAX_VALUE]` | 否 | 1 | +| `on-success` | 表示对于成功载入的 tsfile 的处置方式:默认为`delete`,即tsfile 成功加载后将被删除;`none `表明 tsfile 成功加载之后依然被保留在源文件夹, | String | `delete / none` | 否 | delete | +| `model` | 指定写入的 tsfile 是表模型还是树模型 | String | `tree / table` | 否 | 与`-sql_dialect`一致 | +| `database-name` | **仅限表模型有效**: 文件导入的目标 database,不存在时会自动创建,`database-name`中不允许包括"`root.`"前缀,如果包含,将会报错。 | String | `-` | 否 | null | +| `convert-on-type-mismatch` | 加载 tsfile 时,如果数据类型不一致,是否进行转换 | Boolean | `true / false` | 否 | true | +| `verify` | 加载 tsfile 前是否校验 schema | Boolean | `true / false` | 否 | true | +| `tablet-conversion-threshold` | 转换为 tablet 形式的 tsfile 大小阈值,针对小文件 tsfile 加载,采用将其转换为 tablet 形式进行写入:默认值为 -1,即任意大小 tsfile 都不进行转换 | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | 否 | -1 | +| `async` | 是否开启异步加载 tsfile,将文件移到 active load 目录下面,所有的 tsfile 都 load 到`database-name`下. | Boolean | `true / false` | 否 | false | + +### 4.2 运行示例 + +```SQL +-- 准备目标数据库 database2 +IoTDB> create database database2 +Msg: The statement is executed successfully. + +IoTDB> use database2 +Msg: The statement is executed successfully. + +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ ++---------+-------+------+-------+ +Empty set. + +--通过执行load sql 导入tsfile +IoTDB:database2> load '/home/dump0.tsfile' with ( 'on-success'='none', 'database-name'='database2') +Msg: The statement is executed successfully. + +-- 验证数据导入成功 +IoTDB:database2> select * from table2 ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +| time|region|plant_id|device_id|temperature|humidity|status| arrival_time| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +|2024-11-30T00:00:00.000+08:00| 上海| 3002| 101| 90.0| 35.2| true| null| +|2024-11-29T00:00:00.000+08:00| 上海| 3001| 101| 85.0| 35.1| null|2024-11-29T10:00:13.000+08:00| +|2024-11-27T00:00:00.000+08:00| 北京| 1001| 101| 85.0| 35.1| true|2024-11-27T16:37:01.000+08:00| +|2024-11-29T11:00:00.000+08:00| 上海| 3002| 100| null| 45.1| true| null| +|2024-11-28T08:00:00.000+08:00| 上海| 3001| 100| 85.0| 35.2| false|2024-11-28T08:00:09.000+08:00| +|2024-11-26T13:37:00.000+08:00| 北京| 1001| 100| 90.0| 35.1| true|2024-11-26T13:37:34.000+08:00| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +``` diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md similarity index 95% rename from src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md rename to src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md index 8243acec7..b77a6525a 100644 --- a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool.md +++ b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | -| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | -| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | -| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | -| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | | `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..e8c65a2a6 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,108 @@ + + +# 元数据导出 + +## 1. 功能概述 + +元数据导出工具 `export-schema.sh/bat` 位于tools 目录下,能够将 IoTDB 中指定数据库下的元数据导出为脚本文件。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 运行示例 + +将 `database1` 下的元数据导出到`/home`下 + +```Bash +./export-schema.sh -sql_dialect table -t /home/ -db database1 +``` + +导出文件 `dump_database1.sql`,内容格式如下: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md similarity index 91% rename from src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md rename to src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md index 26d704be3..ce053fd18 100644 --- a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool.md +++ b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_apache.md @@ -29,19 +29,19 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- | --------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | -| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | -| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-----------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | | `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md new file mode 100644 index 000000000..c96a19d7a --- /dev/null +++ b/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool_timecho.md @@ -0,0 +1,163 @@ + + +# 元数据导入 + +## 1. 功能概述 + +元数据导入工具 `import-schema.sh/bat` 位于tools 目录下,能够将指定路径下创建元数据的脚本文件导入到 IoTDB 中。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# V2.0.4.x 版本之前 +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x 版本及之后 +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 运行示例 + + +将 `/home `下的文件 `dump_database1.sql` 导入到 `database2 `中,文件内容如下: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` + +执行脚本: + +```Bash +./import-schema.sh -sql_dialect table -s /home/dump_database1.sql -db database2 + +# database2 不存在时,提示错误信息如下 +The target database database2 does not exist + +# database2 存在时,提示成功 +Import completely! +``` + +验证导入元数据: + +```Bash +# 导入前 +IoTDB:database2> show tables ++---------+-------+ +|TableName|TTL(ms)| ++---------+-------+ ++---------+-------+ +Empty set. + +# 导入后 +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ +| table2| INF| USING| null| +| table1| INF| USING| null| ++---------+-------+------+-------+ + +IoTDB:database2> desc table1 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ + +IoTDB:database2> desc table2 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ +``` diff --git a/src/zh/UserGuide/Master/Table/User-Manual/Authority-Management.md b/src/zh/UserGuide/Master/Table/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Table/User-Manual/Authority-Management.md rename to src/zh/UserGuide/Master/Table/User-Manual/Authority-Management_apache.md diff --git a/src/zh/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md b/src/zh/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..575243a8e --- /dev/null +++ b/src/zh/UserGuide/Master/Table/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,483 @@ + + +# 权限管理 + +IoTDB 提供了权限管理功能,用于对数据和集群系统执行精细的访问控制,保障数据与系统安全。本篇介绍了 IoTDB 表模型中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。 + +## 1. 基本概念 + +### 1.1 用户 + +用户即数据库的合法使用者。一个用户与一个唯一的用户名相对应,并且拥有密码作为身份验证的手段。一个人在使用数据库之前,必须先提供合法的(即存于数据库中的)用户名与密码。 + +### 1.2 权限 + +数据库提供多种操作,但并非所有的用户都能执行所有操作。如果一个用户可以执行某项操作,则称该用户有执行该操作的权限。 + +### 1.3 角色 + +角色是若干权限的集合,并且有一个唯一的角色名作为标识符。角色通常和一个现实身份相对应(例如交通调度员),而一个现实身份可能对应着多个用户。这些具有相同现实身份的用户往往具有相同的一些权限,角色就是为了能对这样的权限进行统一的管理的抽象。 + +### 1.4 默认用户与角色 + +安装初始化后的 IoTDB 中有一个默认用户 root,默认密码为 TimechoDB@2021(V2.0.6.x 之前为 root)。该用户为管理员用户,拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。一个新创建的用户或角色不具备任何权限。 + + +## 2. 权限列表 + +IoTDB 表模型主要有两类权限:全局权限、数据权限。 + +### 2.1 全局权限 + +全局权限包含用户管理和角色管理。 + +下表描述了全局权限的种类: + +| 权限名称 | 描述 | +| ----------------- |----------------------------------------------------------------------------------------| +| MANAGE\_USER | - 允许用户创建用户
- 允许用户删除用户
- 允许用户修改用户密码
- 允许用户查看用户的权限信息
- 允许用户列出所有用户 | +| MANAGE\_ROLE | - 允许用户创建角色
- 允许用户删除角色
- 允许用户查看角色的权限信息
- 允许用户将角色授予某个用户或撤销
- 允许用户列出所有角色 | + + +### 2.2 数据权限 + +数据权限由权限类型和范围组成。 + +* 权限类型包括:CREATE(创建权限),DROP(删除权限),ALTER(修改权限),SELECT(查询数据权限),INSERT(插入/更新数据权限),DELETE(删除数据权限)。 + +* 范围包括:ANY(系统范围内),DATABASE(数据库范围内),TABLE(单个表)。 + - 作用于 ANY 的权限会影响所有数据库和表。 + - 作用于数据库的权限会影响该数据库及其所有表。 + - 作用于表的权限仅影响该表。 + +* 范围生效说明:执行单表操作时,数据库会匹配用户权限与数据权限范围。例如,用户尝试向 DATABASE1.TABLE1 写入数据时,系统会依次检查用户是否有对 ANY、DATABASE1或 DATABASE1.TABLE1 的写入权限,直到匹配成功或者匹配失败。 + +* 权限类型、范围及效果逻辑关系如下表所示: + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
权限类型权限范围(层级)权限效果
CREATEANY允许创建任意表、创建任意数据库
数据库允许用户在该数据库下创建表;允许用户创建该名称的数据库
允许用户创建该名称的表
DROPANY允许删除任意表、删除任意数据库
数据库允许用户删除该数据库;允许用户删除该数据库下的表
D允许用户删除该表
ALTERANY允许修改任意表的定义、任意数据库的定义
数据库允许用户修改数据库的定义,允许用户修改数据库下表的定义
允许用户修改表的定义
SELECTANY允许查询系统内任意数据库中任意表的数据
数据库允许用户查询该数据库中任意表的数据
允许用户查询该表中的数据。执行多表查询时,数据库仅展示用户有权限访问的数据。
INSERTANY允许任意数据库的任意表插入/更新数据
数据库允许用户向该数据库范围内任意表插入/更新数据
允许用户向该表中插入/更新数据
DELETEANY允许删除任意表的数据
数据库允许用户删除该数据库范围内的数据
允许用户删除该表中的数据
+ +## 3. 用户、角色管理 +1. 创建用户(需 MANAGE_USER 权限) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- 用户名约束:4~32个字符,支持使用英文大小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,用户无法创建和管理员用户同名的用户。 +- 密码约束:4~32个字符,可使用大写小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,密码默认采用 SHA-256 进行加密。 + +2. 修改密码 + +用户可以修改自己的密码,但修改其他用户密码需要具备 MANAGE_USER 权限。 + +```SQL +ALTER USER SET PASSWORD +eg: ALTER USER tempuser SET PASSWORD 'newpwd' +``` + +3. 删除用户(需 MANAGE_USER 权限) + +```SQL +DROP USER +eg: DROP USER user1 +``` + +4. 创建角色 (需 MANAGE_ROLE 权限) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +角色名约束:4~32个字符,支持使用英文大小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,用户无法创建和管理员用户同名的角色。 + +5. 删除角色 (需 MANAGE_ROLE 权限) + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +6. 赋予用户角色 (需 MANAGE_ROLE 权限) + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +7. 移除用户角色 (需 MANAGE_ROLE 权限) + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +8. 列出所有用户(需 MANAGE_USER 权限) + +```SQL +LIST USER +``` + +9. 列出所有的角色 (需 MANAGE_ROLE 权限) + +```SQL +LIST ROLE +``` + +10. 列出指定角色下所有用户(需 MANAGE_USER 权限) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +11. 列出指定用户下的所有角色 + +用户可以列出自己的角色,但列出其他用户的角色需要拥有 MANAGE_ROLE 权限。 + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +12. 列出用户所有权限 + +用户可以列出自己的权限信息,但列出其他用户的权限需要拥有 MANAGE_USER 权限。 + +```SQL +LIST PRIVILEGES OF USER +eg: LIST PRIVILEGES OF USER tempuser +``` + +13. 列出角色所有权限 + +用户可以列出自己具有的角色的权限信息,列出其他角色的权限需要有 MANAGE_ROLE 权限。 + +```SQL +LIST PRIVILEGES OF ROLE +eg: LIST PRIVILEGES OF ROLE actor +``` + +## 4. 权限管理 + +IoTDB支持通过如下三种途径进行用户授权和撤销权限: + +- 超级管理员直接授予或撤销 + +- 拥有GRANT OPTION权限的用户授予或撤销 + +- 通过角色授予或撤销(由超级管理员或具备MANAGE_ROLE权限的用户操作角色) + +在IoTDB 表模型中,授权或撤销权限时需遵循以下原则: + +- 授权/撤销全局权限时,无需指定权限的范围。 + +- 授予/撤销数据权限时,需要指定权限类型和权限范围。在撤销权限时只会撤销指定的权限范围,不会受权限范围包含关系的影响。 + +- 允许对尚未创建的数据库或表提前进行权限规划和授权。 + +- 允许重复授权/撤销权限。 + +- WITH GRANT OPTION: 允许用户在授权范围内管理权限。用户可以授予或撤销其他用户在该范围内的权限。 + +### 4.1 授予权限 + +1. 给用户授予管理用户的权限 + +```SQL +GRANT MANAGE_USER TO USER +eg: GRANT MANAGE_USER TO USER TEST_USER +``` + +2. 给用户授予创建数据库及在数据库范围内创建表的权限,且允许用户在该范围内管理权限 + +```SQL +GRANT CREATE ON DATABASE TO USER WITH GRANT OPTION +eg: GRANT CREATE ON DATABASE TESTDB TO USER TEST_USER WITH GRANT OPTION +``` + +3. 给角色授予查询数据库的权限 + +```SQL +GRANT SELECT ON DATABASE TO ROLE +eg: GRANT SELECT ON DATABASE TESTDB TO ROLE TEST_ROLE +``` + +4. 给用户授予查询表的权限 + +```SQL +GRANT SELECT ON . TO USER +eg: GRANT SELECT ON TESTDB.TESTTABLE TO USER TEST_USER +``` + +5. 给角色授予查询所有数据库及表的权限 + +```SQL +GRANT SELECT ON ANY TO ROLE +eg: GRANT SELECT ON ANY TO ROLE TEST_ROLE +``` + +6. ALL 语法糖:ALL 表示对象范围内所有权限,可以使用 ALL 字段灵活地授予权限。 + +```sql +GRANT ALL TO USER TESTUSER +-- 将用户可以获取的所有权限授予给用户,包括全局权限和 ANY 范围的所有数据权限 + +GRANT ALL ON ANY TO USER TESTUSER +-- 将 ANY 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在所有数据库上的所有数据权限 + +GRANT ALL ON DATABASE TESTDB TO USER TESTUSER +-- 将 DB 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在该数据库上的所有数据权限 + +GRANT ALL ON TABLE TESTTABLE TO USER TESTUSER +-- 将 TABLE 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在该表上的所有数据权限 +``` + +### 4.2 撤销权限 + +1. 取消用户管理用户的权限 + +```SQL +REVOKE MANAGE_USER FROM USER +eg: REVOKE MANAGE_USER FROM USER TEST_USER +``` + +2. 取消用户创建数据库及在数据库范围内创建表的权限 + +```SQL +REVOKE CREATE ON DATABASE FROM USER +eg: REVOKE CREATE ON DATABASE TEST_DB FROM USER TEST_USER +``` + +3. 取消用户查询表的权限 + +```SQL +REVOKE SELECT ON . FROM USER +eg: REVOKE SELECT ON TESTDB.TESTTABLE FROM USER TEST_USER +``` + +4. 取消用户查询所有数据库及表的权限 + +```SQL +REVOKE SELECT ON ANY FROM USER +eg: REVOKE SELECT ON ANY FROM USER TEST_USER +``` + +5. ALL 语法糖:ALL 表示对象范围内所有权限,可以使用 ALL 字段灵活地撤销权限。 + +```sql +REVOKE ALL FROM USER TESTUSER +-- 取消用户所有的全局权限以及 ANY 范围的所有数据权限 + +REVOKE ALL ON ANY FROM USER TESTUSER +-- 取消用户 ANY 范围的所有数据权限,不会影响 DB 范围和 TABLE 范围的权限 + +REVOKE ALL ON DATABASE TESTDB FROM USER TESTUSER +-- 取消用户在 DB 上的所有数据权限,不会影响 TABLE 权限 + +REVOKE ALL ON TABLE TESTDB FROM USER TESTUSER +-- 取消用户在 TABLE 上的所有数据权限 +``` + +### 4.3 查看用户权限 + +每个用户都有一个权限访问列表,标识其获得的所有权限。可使用 `LIST PRIVILEGES OF USER ` 语句查看某个用户或角色的权限信息,输出格式如下: + +| ROLE | SCOPE | PRIVIVLEGE | WITH GRANT OPTION | +|--------------|---------| -------------- |-------------------| +| | DB1.TB1 | SELECT | FALSE | +| | | MANAGE\_ROLE | TRUE | +| ROLE1 | DB2.TB2 | UPDATE | TRUE | +| ROLE1 | DB3.\* | DELETE | FALSE | +| ROLE1 | \*.\* | UPDATE | TRUE | + +其中: +- `ROLE` 列:如果为空,则表示为该用户的自身权限。如果不为空,则表示该权限来源于被授予的角色。 +- `SCOPE` 列:表示该用户/角色的权限范围,表范围的权限表示为`DB.TABLE`,数据库范围的权限表示为`DB.*`, ANY 范围的权限表示为`*.*`。 +- `PRIVIVLEGE` 列:列出具体的权限类型。 +- `WITH GRANT OPTION` 列:如果为 TRUE,表示用户可以将自己的权限授予他人。 +- 用户或者角色可以同时具有树模型和表模型的权限,但系统会根据当前连接的模型来显示相应的权限,另一种模型下的权限则不会显示。 + +## 5. 示例 + +以 [示例数据](../Reference/Sample-Data.md) 内容为例,两个表的数据可能分别属于 bj、sh 两个数据中心,彼此间不希望对方获取自己的数据库数据,因此我们需要将不同的数据在数据中心层进行权限隔离。 + +### 5.1 创建用户 + +使用 `CREATE USER ` 创建用户。例如,可以使用具有所有权限的root用户为 ln 和 sgcc 集团创建两个用户角色,名为 `bj_write_user`, `sh_write_user`,密码均为 `write_pwd`。SQL 语句为: + +```SQL +CREATE USER bj_write_user 'write_pwd' +CREATE USER sh_write_user 'write_pwd' +``` + +使用展示用户的 SQL 语句: + +```Plain +LIST USER +``` + +可以看到这两个已经被创建的用户,结果如下: + +```sql ++-------------+ +| User| ++-------------+ +|bj_write_user| +| root| +|sh_write_user| ++-------------+ +``` + +### 5.2 赋予用户权限 + +虽然两个用户已经创建,但是不具有任何权限,因此并不能对数据库进行操作,例如使用 `bj_write_user` 用户对 table1 中的数据进行写入,SQL 语句为: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +``` + +系统不允许用户进行此操作,会提示错误: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: database is not specified +IoTDB> use database1 +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: DATABASE database1 +``` + +root 用户使用 `GRANT ON TO USER ` 语句赋予用户`bj_write_user`对 table1 的写入权限,例如: + +```sql +GRANT INSERT ON database1.table1 TO USER bj_write_user +``` + +使用`bj_write_user`再尝试写入数据 + +```SQL +IoTDB> use database1 +Msg: The statement is executed successfully. +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: The statement is executed successfully. +``` + +### 5.3 撤销用户权限 + +授予用户权限后,可以使用 `REVOKE ON FROM USER `来撤销已经授予用户的权限。例如,用root用户撤销`bj_write_user`和`sh_write_user`的权限: + +```sql +REVOKE INSERT ON database1.table1 FROM USER bj_write_user +REVOKE INSERT ON database1.table2 FROM USER sh_write_user +``` + +撤销权限后,`bj_write_user`就没有向table1写入数据的权限了。 + +```sql +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: No permissions for this operation, please add privilege INSERT ON database1.table1 +``` diff --git a/src/zh/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md b/src/zh/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md index bfcac2816..4a54464e8 100644 --- a/src/zh/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md +++ b/src/zh/UserGuide/Master/Table/User-Manual/Data-Sync_timecho.md @@ -574,20 +574,20 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| **参数** | **描述** | **value 取值范围** | **是否必填** | **默认取值** | -|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| -------- | ------------ | -| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| **参数** | **描述** | **value 取值范围** | **是否必填** | **默认取值** | +|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| -------- |---------------------------------| +| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | #### iotdb-air-gap-sink @@ -597,7 +597,7 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | | node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | | user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | | compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | | rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | @@ -611,7 +611,7 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | | node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | | user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | | batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | | batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | @@ -640,6 +640,6 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink.opcua.security.dir | OPC UA 的密钥及证书目录 | String: Path,支持绝对及相对目录 | 选填 | iotdb 相关 DataNode 的 conf 目录下的 opc_security 文件夹 ``。
如无 iotdb 的 conf 目录(例如 IDEA 中启动 DataNode),则为用户主目录下的 iotdb_opc_security 文件夹 `` | | sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | | sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | -| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | root | +| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | sink.opcua.placeholder | 当ID列的值出现null时,用于替代null映射路径的占位字符串 | String | 选填 | "null" | diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription.md b/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md similarity index 99% rename from src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription.md rename to src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md index 8a81d432d..aa103544a 100644 --- a/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription.md +++ b/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_apache.md @@ -21,7 +21,7 @@ # 数据订阅API -IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription.md) +IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription_apache) ## 1. 核心步骤 @@ -33,7 +33,7 @@ IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时 ## 2. 详细步骤 -本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API.md#_3-全量接口说明) +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_apache#_3-全量接口说明) ### 2.1 创建maven项目 diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md b/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md new file mode 100644 index 000000000..a927d366c --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/Programming-Data-Subscription_timecho.md @@ -0,0 +1,267 @@ + + + + +# 数据订阅API + +IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription_timecho) + +## 1. 核心步骤 + +1. 创建Topic:创建一个Topic,Topic中包含希望订阅的测点。 +2. 订阅Topic:在 consumer 订阅 topic 前,topic 必须已经被创建,否则订阅会失败。同一个 consumer group 下的 consumers 会均分数据。 +3. 消费数据:只有显式订阅了某个 topic,才会收到对应 topic 的数据。 +4. 取消订阅: consumer close 时会退出对应的 consumer group,同时取消现存的所有订阅。 + + +## 2. 详细步骤 + +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_timecho#_3-全量接口说明) + + +### 2.1 创建maven项目 + +创建一个maven项目,并导入以下依赖(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 代码案例 + +#### 2.2.1 Topic操作 + +```java +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.SubscriptionSession; +import org.apache.iotdb.session.subscription.model.Topic; + +public class DataConsumerExample { + + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + try (SubscriptionSession session = new SubscriptionSession("127.0.0.1", 6667, "root", "TimechoDB@2021", 67108864)) { //V2.0.6.x 之前默认密码为root + // 1. open session + session.open(); + + // 2. create a topic of all data + Properties sessionConfig = new Properties(); + sessionConfig.put(TopicConstant.PATH_KEY, "root.**"); + + session.createTopic("allData", sessionConfig); + + // 3. show all topics + Set topics = session.getTopics(); + System.out.println(topics); + + // 4. show a specific topic + Optional allData = session.getTopic("allData"); + System.out.println(allData.get()); + } + } +} +``` + +#### 2.2.2 数据消费 + +##### 场景-1: 订阅IoTDB中新增的实时数据(大屏或组态展示的场景) + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessageType; +import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.tsfile.read.common.RowRecord; + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + + // 5. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //V2.0.6.x 之前默认密码为root + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + final short messageType = message.getMessageType(); + if (SubscriptionMessageType.isValidatedMessageType(messageType)) { + for (final SubscriptionSessionDataSet dataSet : message.getSessionDataSetsHandler()) { + while (dataSet.hasNext()) { + final RowRecord record = dataSet.next(); + System.out.println(record); + } + } + } + } + } + } + } +} + + +``` + +##### 场景-2:订阅新增的 TsFile(定期数据备份的场景) + +前提:需要被消费的topic的格式为TsfileHandler类型,举例:`create topic topic_all_tsfile with ('path'='root.**','format'='TsFileHandler')` + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; + + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + // 1. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021");//V2.0.6.x 之前默认密码为root + consumerConfig.put(ConsumerConstant.FILE_SAVE_DIR_KEY, "/Users/iotdb/Downloads"); + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all_tsfile"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + message.getTsFileHandler().copyFile("/Users/iotdb/Downloads/1.tsfile"); + } + } + } + } +} +``` + + + + +## 3. 全量接口说明 + +### 3.1 参数列表 + +可通过Properties参数对象设置消费者相关参数,具体参数如下。 + +#### 3.1.1 SubscriptionConsumer + + +| 参数 | 是否必填(默认值) | 参数含义 | +| :---------------------- |:-------------------------------------------------------------------------------------| :----------------------------------------------------------- | +| host | optional: 127.0.0.1 | `String`: IoTDB 中某 DataNode 的 RPC host | +| port | optional: 6667 | `Integer`: IoTDB 中某 DataNode 的 RPC port | +| node-urls | optional: 127.0.0.1:6667 | `List`: IoTDB 中所有 DataNode 的 RPC 地址,可以是多个;host:port 和 node-urls 选填一个即可。当 host:port 和 node-urls 都填写了,则取 host:port 和 node-urls 的**并集**构成新的 node-urls 应用 | +| username | optional: root | `String`: IoTDB 中 DataNode 的用户名 | +| password | optional: TimechoDB@2021 //V2.0.6.x 之前默认密码为root | `String`: IoTDB 中 DataNode 的密码 | +| groupId | optional | `String`: consumer group id,若未指定则随机分配(新的 consumer group),保证不同的 consumer group 对应的 consumer group id 均不相同 | +| consumerId | optional | `String`: consumer client id,若未指定则随机分配,保证同一个 consumer group 中每一个 consumer client id 均不相同 | +| heartbeatIntervalMs | optional: 30000 (min: 1000) | `Long`: consumer 向 IoTDB DataNode 定期发送心跳请求的间隔 | +| endpointsSyncIntervalMs | optional: 120000 (min: 5000) | `Long`: consumer 探测 IoTDB 集群节点扩缩容情况调整订阅连接的间隔 | +| fileSaveDir | optional: Paths.get(System.getProperty("user.dir"), "iotdb-subscription").toString() | `String`: consumer 订阅出的 TsFile 文件临时存放的目录路径 | +| fileSaveFsync | optional: false | `Boolean`: consumer 订阅 TsFile 的过程中是否主动调用 fsync | + +`SubscriptionPushConsumer` 中的特殊配置: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| ackStrategy | optional: `ACKStrategy.AFTER_CONSUME` | 消费进度的确认机制包含以下选项:`ACKStrategy.BEFORE_CONSUME`(当 consumer 收到数据时立刻提交消费进度,`onReceive` 前)`ACKStrategy.AFTER_CONSUME`(当 consumer 消费完数据再去提交消费进度,`onReceive` 后) | +| consumeListener | optional | 消费数据的回调函数,需实现 `ConsumeListener` 接口,定义消费 `SessionDataSetsHandler` 和 `TsFileHandler` 形式数据的处理逻辑 | +| autoPollIntervalMs | optional: 5000 (min: 500) | Long: consumer 自动拉取数据的时间间隔,单位为**毫秒** | +| autoPollTimeoutMs | optional: 10000 (min: 1000) | Long: consumer 每次拉取数据的超时时间,单位为**毫秒** | + +`SubscriptionPullConsumer` 中的特殊配置: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :----------------- | :------------------------ | :----------------------------------------------------------- | +| autoCommit | optional: true | Boolean: 是否自动提交消费进度如果此参数设置为 false,则需要调用 `commit` 方法来手动提交消费进度 | +| autoCommitInterval | optional: 5000 (min: 500) | Long: 自动提交消费进度的时间间隔,单位为**毫秒**仅当 autoCommit 参数为 true 的时候才会生效 | + + +### 3.2 函数列表 + +#### 3.2.1 数据订阅 + +##### SubscriptionPullConsumer + +| **函数名** | **说明** | **参数** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | 打开消费者连接,启动消息消费。如果 `autoCommit` 启用,会启动自动提交工作器。 | 无 | +| `close()` | 关闭消费者连接。如果 `autoCommit` 启用,会在关闭前提交所有未提交的消息。 | 无 | +| `poll(final Duration timeout)` | 拉取消息,指定超时时间。 | `timeout` : 拉取的超时时间。 | +| `poll(final long timeoutMs)` | 拉取消息,指定超时时间(毫秒)。 | `timeoutMs` : 超时时间,单位为毫秒。 | +| `poll(final Set topicNames, final Duration timeout)` | 拉取指定主题的消息,指定超时时间。 | `topicNames` : 要拉取的主题集合。`timeout`: 超时时间。 | +| `poll(final Set topicNames, final long timeoutMs)` | 拉取指定主题的消息,指定超时时间(毫秒)。 | `topicNames` : 要拉取的主题集合。`timeoutMs`: 超时时间,单位为毫秒。 | +| `commitSync(final SubscriptionMessage message)` | 同步提交单条消息。 | `message` : 需要提交的消息对象。 | +| `commitSync(final Iterable messages)` | 同步提交多条消息。 | `messages` : 需要提交的消息集合。 | +| `commitAsync(final SubscriptionMessage message)` | 异步提交单条消息。 | `message` : 需要提交的消息对象。 | +| `commitAsync(final Iterable messages)` | 异步提交多条消息。 | `messages` : 需要提交的消息集合。 | +| `commitAsync(final SubscriptionMessage message, final AsyncCommitCallback callback)` | 异步提交单条消息并指定回调函数。 | `message` : 需要提交的消息对象。`callback` : 异步提交完成后的回调函数。 | +| `commitAsync(final Iterable messages, final AsyncCommitCallback callback)` | 异步提交多条消息并指定回调函数。 | `messages` : 需要提交的消息集合。`callback` : 异步提交完成后的回调函数。 | + +##### SubscriptionPushConsumer + +| **函数名** | **说明** | **参数** | +| -------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------- | +| `open()` | 打开消费者连接,启动消息消费,提交自动轮询工作器。 | 无 | +| `close()` | 关闭消费者连接,停止消息消费。 | 无 | +| `toString()` | 返回消费者对象的核心配置信息。 | 无 | +| `coreReportMessage()` | 获取消费者核心配置的键值对表示形式。 | 无 | +| `allReportMessage()` | 获取消费者所有配置的键值对表示形式。 | 无 | +| `buildPushConsumer()` | 通过 `Builder` 构建 `SubscriptionPushConsumer` 实例。 | 无 | +| `ackStrategy(final AckStrategy ackStrategy)` | 配置消费者的消息确认策略。 | `ackStrategy`: 指定的消息确认策略。 | +| `consumeListener(final ConsumeListener consumeListener)` | 配置消费者的消息消费逻辑。 | `consumeListener`: 消费者接收消息时的处理逻辑。 | +| `autoPollIntervalMs(final long autoPollIntervalMs)` | 配置自动轮询的时间间隔。 | `autoPollIntervalMs` : 自动轮询的间隔时间,单位为毫秒。 | +| `autoPollTimeoutMs(final long autoPollTimeoutMs)` | 配置自动轮询的超时时间。 | `autoPollTimeoutMs`: 自动轮询的超时时间,单位为毫秒。 | + + + + + + + + + diff --git a/src/zh/UserGuide/latest/API/Programming-JDBC.md b/src/zh/UserGuide/Master/Tree/API/Programming-JDBC_apache.md similarity index 99% rename from src/zh/UserGuide/latest/API/Programming-JDBC.md rename to src/zh/UserGuide/Master/Tree/API/Programming-JDBC_apache.md index f87dff958..f0b6ad75c 100644 --- a/src/zh/UserGuide/latest/API/Programming-JDBC.md +++ b/src/zh/UserGuide/Master/Tree/API/Programming-JDBC_apache.md @@ -23,7 +23,7 @@ **注意**: 目前的JDBC实现仅是为与第三方工具连接使用的。不推荐使用 JDBC (执行插入语句时),因无法提供高性能写入,查询推荐使用 JDBC。 -对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API.md)* +对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API_apache)* ## 1. 依赖 diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md b/src/zh/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md new file mode 100644 index 000000000..d1e85f72c --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/Programming-JDBC_timecho.md @@ -0,0 +1,293 @@ + + +# JDBC + +**注意**: 目前的JDBC实现仅是为与第三方工具连接使用的。不推荐使用 JDBC (执行插入语句时),因无法提供高性能写入,查询推荐使用 JDBC。 + +对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API_timecho)* + +## 1. 依赖 + +* JDK >= 1.8 +* Maven >= 3.6 + +## 2. 安装方法 + +在根目录下执行下面的命令: +```shell +mvn clean install -pl iotdb-client/jdbc -am -DskipTests +``` + +### 2.1 在 MAVEN 中使用 IoTDB JDBC + +```xml + + + org.apache.iotdb + iotdb-jdbc + 1.3.1 + + +``` + +### 2.2 示例代码 + +本章提供了如何建立数据库连接、执行 SQL 和显示查询结果的示例。 + +要求您已经在工程中包含了数据库编程所需引入的包和 JDBC class. + +**注意:为了更快地插入,建议使用 executeBatch()** + +```java +import java.sql.*; +import org.apache.iotdb.jdbc.IoTDBSQLException; + +public class JDBCExample { + /** + * Before executing a SQL statement with a Statement object, you need to create a Statement object using the createStatement() method of the Connection object. + * After creating a Statement object, you can use its execute() method to execute a SQL statement + * Finally, remember to close the 'statement' and 'connection' objects by using their close() method + * For statements with query results, we can use the getResultSet() method of the Statement object to get the result set. + */ + public static void main(String[] args) throws SQLException { + Connection connection = getConnection(); + if (connection == null) { + System.out.println("get connection defeat"); + return; + } + Statement statement = connection.createStatement(); + //Create database + try { + statement.execute("CREATE DATABASE root.demo"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + + //SHOW DATABASES + statement.execute("SHOW DATABASES"); + outputResult(statement.getResultSet()); + + //Create time series + //Different data type has different encoding methods. Here use INT32 as an example + try { + statement.execute("CREATE TIMESERIES root.demo.s0 WITH DATATYPE=INT32,ENCODING=RLE;"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + //Show time series + statement.execute("SHOW TIMESERIES root.demo"); + outputResult(statement.getResultSet()); + //Show devices + statement.execute("SHOW DEVICES"); + outputResult(statement.getResultSet()); + //Count time series + statement.execute("COUNT TIMESERIES root"); + outputResult(statement.getResultSet()); + //Count nodes at the given level + statement.execute("COUNT NODES root LEVEL=3"); + outputResult(statement.getResultSet()); + //Count timeseries group by each node at the given level + statement.execute("COUNT TIMESERIES root GROUP BY LEVEL=3"); + outputResult(statement.getResultSet()); + + + //Execute insert statements in batch + statement.addBatch("insert into root.demo(timestamp,s0) values(1,1);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(2,15);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(2,17);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(4,12);"); + statement.executeBatch(); + statement.clearBatch(); + + //Full query statement + String sql = "select * from root.demo"; + ResultSet resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Exact query statement + sql = "select s0 from root.demo where time = 4;"; + resultSet= statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Time range query + sql = "select s0 from root.demo where time >= 2 and time < 5;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Aggregate query + sql = "select count(s0) from root.demo;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Delete time series + statement.execute("delete timeseries root.demo.s0"); + + //close connection + statement.close(); + connection.close(); + } + + public static Connection getConnection() { + // JDBC driver name and database URL + String driver = "org.apache.iotdb.jdbc.IoTDBDriver"; + String url = "jdbc:iotdb://127.0.0.1:6667/"; + // set rpc compress mode + // String url = "jdbc:iotdb://127.0.0.1:6667?rpc_compress=true"; + + // Database credentials + String username = "root"; + String password = "TimechoDB@2021"; // V2.0.6.x 之前默认密码是 root + + Connection connection = null; + try { + Class.forName(driver); + connection = DriverManager.getConnection(url, username, password); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return connection; + } + + /** + * This is an example of outputting the results in the ResultSet + */ + private static void outputResult(ResultSet resultSet) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print(resultSet.getString(i)); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` + +可以在 url 中指定 version 参数: +```java +String url = "jdbc:iotdb://127.0.0.1:6667?version=V_1_0"; +``` +version 表示客户端使用的 SQL 语义版本,用于升级 0.13 时兼容 0.12 的 SQL 语义,可能取值有:`V_0_12`、`V_0_13`、`V_1_0`。 + +此外,IoTDB 在 JDBC 中提供了额外的接口,供用户在连接中使用不同的字符集(例如 GB18030)读写数据库。 +IoTDB 默认的字符集为 UTF-8。当用户期望使用 UTF-8 外的字符集时,需要在 JDBC 的连接中,指定 charset 属性。例如: +1. 使用 GB18030 的 charset 创建连接: +```java +DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021") +// V2.0.6.x 之前默认密码是 root +``` +2. 调用如下 `IoTDBStatement` 接口执行 SQL 时,可以接受 `byte[]` 编码的 SQL,该 SQL 将按照被指定的 charset 解析成字符串。 +```java +public boolean execute(byte[] sql) throws SQLException; +``` +3. 查询结果输出时,可使用 `ResultSet` 的 `getBytes` 方法得到的 `byte[]`,`byte[]` 的编码使用连接指定的 charset 进行。 +```java +System.out.print(resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); +``` +以下是完整示例: +```java +public class JDBCCharsetExample { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCCharsetExample.class); + + public static void main(String[] args) throws Exception { + Class.forName("org.apache.iotdb.jdbc.IoTDBDriver"); + + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); // V2.0.6.x 之前默认密码是 root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + + final String insertSQLWithGB18030 = + "insert into root.测试(timestamp, 维语, 彝语, 繁体, 蒙文, 简体, 标点符号, 藏语) values(1, 'ئۇيغۇر تىلى', 'ꆈꌠꉙ', \"繁體\", 'ᠮᠣᠩᠭᠣᠯ ᠬᠡᠯᠡ', '简体', '——?!', \"བོད་སྐད།\");"; + final byte[] insertSQLWithGB18030Bytes = insertSQLWithGB18030.getBytes("GB18030"); + statement.execute(insertSQLWithGB18030Bytes); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + + outputResult("GB18030"); + outputResult("UTF-8"); + outputResult("UTF-16"); + outputResult("GBK"); + outputResult("ISO-8859-1"); + } + + private static void outputResult(String charset) throws SQLException { + System.out.println("[Charset: " + charset + "]"); + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=" + charset, "root", "TimechoDB@2021"); // V2.0.6.x 之前默认密码是 root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + outputResult(statement.executeQuery("select ** from root"), Charset.forName(charset)); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + } + + private static void outputResult(ResultSet resultSet, Charset charset) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print( + resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` \ No newline at end of file diff --git a/src/zh/UserGuide/latest/API/Programming-Java-Native-API.md b/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md similarity index 99% rename from src/zh/UserGuide/latest/API/Programming-Java-Native-API.md rename to src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md index 3c7b3a405..9519ba080 100644 --- a/src/zh/UserGuide/latest/API/Programming-Java-Native-API.md +++ b/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_apache.md @@ -31,7 +31,7 @@ SessionPool 是 Session 的连接池,推荐使用SessionPool编程。在多线 ## 2. 详细步骤 -本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API.md#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_apache#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) ### 2.1 创建maven项目 @@ -121,7 +121,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } @@ -223,7 +223,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } @@ -349,7 +349,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md b/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md new file mode 100644 index 000000000..c238e4fe9 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API_timecho.md @@ -0,0 +1,499 @@ + + + +# Java原生API + +IoTDB 原生 API 中的 Session 是实现与数据库交互的核心接口,它集成了丰富的方法,支持数据写入、查询以及元数据操作等功能。通过实例化 Session,能够建立与 IoTDB 服务器的连接,在该连接所构建的环境中执行各类数据库操作。Session为非线程安全,不能被多线程同时调用。 + +SessionPool 是 Session 的连接池,推荐使用SessionPool编程。在多线程并发的情形下,SessionPool 能够合理地管理和分配连接资源,以提升系统性能与资源利用效率。 + +## 1. 步骤概览 + +1. 创建连接池实例:初始化一个SessionPool对象,用于管理多个Session实例。 +2. 执行操作:直接从SessionPool中获取Session实例,并执行数据库操作,无需每次都打开和关闭连接。 +3. 关闭连接池资源:在不再需要进行数据库操作时,关闭SessionPool,释放所有相关资源。 + +## 2. 详细步骤 + +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_timecho#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) + +### 2.1 创建maven项目 + +创建一个maven项目,并在pom.xml文件中添加以下依赖(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 创建连接池实例 + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.session.pool.SessionPool; + +public class IoTDBSessionPoolExample { + private static SessionPool sessionPool; + + public static void main(String[] args) { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } +} +``` + +### 2.3 执行数据库操作 + +#### 2.3.1 数据写入 + +在工业场景中,数据写入可分为以下几类:多行数据写入、单设备多行数据写入,下面按不同场景对写入接口进行介绍。 + +##### 多行数据写入接口 + +接口说明:支持一次写入多行数据,每一行对应一个设备一个时间戳的多个测点值。 + + +接口列表: + +| 接口名称 | 功能描述 | +| ------------------------------------------------------------ | ------------------------------------------ | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多行数据,适用于不同测点独立采集的场景 | + +代码案例: + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertRecordsExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + public static void insertRecordsExample() throws IoTDBConnectionException, StatementExecutionException { + String deviceId = "root.sg1.d1"; + List measurements = new ArrayList<>(); + measurements.add("s1"); + measurements.add("s2"); + measurements.add("s3"); + List deviceIds = new ArrayList<>(); + List> measurementsList = new ArrayList<>(); + List> valuesList = new ArrayList<>(); + List timestamps = new ArrayList<>(); + List> typesList = new ArrayList<>(); + + for (long time = 0; time < 500; time++) { + List values = new ArrayList<>(); + List types = new ArrayList<>(); + values.add(1L); + values.add(2L); + values.add(3L); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + + deviceIds.add(deviceId); + measurementsList.add(measurements); + valuesList.add(values); + typesList.add(types); + timestamps.add(time); + if (time != 0 && time % 100 == 0) { + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + deviceIds.clear(); + measurementsList.clear(); + valuesList.clear(); + typesList.clear(); + timestamps.clear(); + } + } + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +##### 单设备多行数据写入接口 + +接口说明:支持一次写入单个设备的多行数据,每一行对应一个时间戳的多个测点值。 + +接口列表: + +| 接口名称 | 功能描述 | +| ----------------------------- | ---------------------------------------------------- | +| `insertTablet(Tablet tablet)` | 插入单个设备的多行数据,适用于不同测点独立采集的场景 | + +代码案例: + +```java +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.write.record.Tablet; +import org.apache.tsfile.write.schema.IMeasurementSchema; +import org.apache.tsfile.write.schema.MeasurementSchema; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertTabletExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + //nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + private static void insertTabletExample() throws IoTDBConnectionException, StatementExecutionException { + /* + * A Tablet example: + * device1 + * time s1, s2, s3 + * 1, 1, 1, 1 + * 2, 2, 2, 2 + * 3, 3, 3, 3 + */ + // The schema of measurements of one device + // only measurementId and data type in MeasurementSchema take effects in Tablet + List schemaList = new ArrayList<>(); + schemaList.add(new MeasurementSchema("s1", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s2", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s3", TSDataType.INT64)); + + Tablet tablet = new Tablet("root.sg.d1",schemaList,100); + + // Method 1 to add tablet data + long timestamp = System.currentTimeMillis(); + + Random random = new Random(); + for (long row = 0; row < 100; row++) { + int rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, timestamp); + for (int s = 0; s < 3; s++) { + long value = random.nextLong(); + tablet.addValue(schemaList.get(s).getMeasurementName(), rowIndex, value); + } + if (tablet.getRowSize() == tablet.getMaxRowNumber()) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + timestamp++; + } + if (tablet.getRowSize() != 0) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +#### 2.3.2 SQL操作 + +SQL操作分为查询和非查询两类操作,对应的接口为`executeQuery`和`executeNonQuery`操作,其区别为前者执行的是具体的查询语句,会返回一个结果集,后者是执行的是增、删、改操作,不返回结果集。 + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.isession.pool.SessionDataSetWrapper; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. executes a non-query SQL statement, such as a DDL or DML command. + executeQueryExample(); + // 3. executes a query SQL statement and returns the result set. + executeNonQueryExample(); + // 4. close SessionPool + closeSessionPool(); + } + + private static void executeNonQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. create a nonAligned time series + sessionPool.executeNonQueryStatement("create timeseries root.test.d1.s1 with dataType = int32"); + // 2. set ttl + sessionPool.executeNonQueryStatement("set TTL to root.test.** 10000"); + // 3. delete time series + sessionPool.executeNonQueryStatement("delete timeseries root.test.d1.s1"); + } + + private static void executeQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. execute normal query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select s1 from root.sg1.d1 limit 10")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + // 2. execute aggregate query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select count(s1) from root.sg1.d1 group by ([0, 40), 5ms) ")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +## 3. 全量接口说明 + +### 3.1 参数列表 + +Session具有如下的字段,可以通过构造函数或Session.Builder方式设置如下参数 + +| 字段名 | 类型 | 说明 | +| -------------------------------- | ----------------------------------- | ---------------------------------------- | +| `nodeUrls` | `List` | 数据库节点的 URL 列表,支持多节点连接 | +| `username` | `String` | 用户名 | +| `password` | `String` | 密码 | +| `fetchSize` | `int` | 查询结果的默认批量返回大小 | +| `useSSL` | `boolean` | 是否启用 SSL | +| `trustStore` | `String` | 信任库路径 | +| `trustStorePwd` | `String` | 信任库密码 | +| `queryTimeoutInMs` | `long` | 查询的超时时间,单位毫秒 | +| `enableRPCCompression` | `boolean` | 是否启用 RPC 压缩 | +| `connectionTimeoutInMs` | `int` | 连接超时时间,单位毫秒 | +| `zoneId` | `ZoneId` | 会话的时区设置 | +| `thriftDefaultBufferSize` | `int` | Thrift 默认缓冲区大小 | +| `thriftMaxFrameSize` | `int` | Thrift 最大帧大小 | +| `defaultEndPoint` | `TEndPoint` | 默认的数据库端点信息 | +| `defaultSessionConnection` | `SessionConnection` | 默认的会话连接对象 | +| `isClosed` | `boolean` | 当前会话是否已关闭 | +| `enableRedirection` | `boolean` | 是否启用重定向功能 | +| `enableRecordsAutoConvertTablet` | `boolean` | 是否启用记录自动转换为 Tablet 的功能 | +| `deviceIdToEndpoint` | `Map` | 设备 ID 和数据库端点的映射关系 | +| `endPointToSessionConnection` | `Map` | 数据库端点和会话连接的映射关系 | +| `executorService` | `ScheduledExecutorService` | 用于定期更新节点列表的线程池 | +| `availableNodes` | `INodeSupplier` | 可用节点的供应器 | +| `enableQueryRedirection` | `boolean` | 是否启用查询重定向功能 | +| `version` | `Version` | 客户端的版本号,用于与服务端的兼容性判断 | +| `enableAutoFetch` | `boolean` | 是否启用自动获取功能 | +| `maxRetryCount` | `int` | 最大重试次数 | +| `retryIntervalInMs` | `long` | 重试的间隔时间,单位毫秒 | + + + +### 3.2 接口列表 + +#### 3.2.1 元数据管理 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ------------------------ | ------------------------------------------------------------ | +| `createDatabase(String database)` | 创建数据库 | `database`: 数据库名称 | +| `deleteDatabase(String database)` | 删除指定数据库 | `database`: 要删除的数据库名称 | +| `deleteDatabases(List databases)` | 批量删除数据库 | `databases`: 要删除的数据库名称列表 | +| `createTimeseries(String path, TSDataType dataType, TSEncoding encoding, CompressionType compressor)` | 创建单个时间序列 | `path`: 时间序列路径,`dataType`: 数据类型,`encoding`: 编码类型,`compressor`: 压缩类型 | +| `createAlignedTimeseries(...)` | 创建对齐时间序列 | 设备ID、测点列表、数据类型列表、编码列表、压缩类型列表 | +| `createMultiTimeseries(...)` | 批量创建时间序列 | 多个路径、数据类型、编码、压缩类型、属性、标签、别名等 | +| `deleteTimeseries(String path)` | 删除时间序列 | `path`: 要删除的时间序列路径 | +| `deleteTimeseries(List paths)` | 批量删除时间序列 | `paths`: 要删除的时间序列路径列表 | +| `setSchemaTemplate(String templateName, String prefixPath)` | 设置模式模板 | `templateName`: 模板名称,`prefixPath`: 应用模板的路径 | +| `createSchemaTemplate(Template template)` | 创建模式模板 | `template`: 模板对象 | +| `dropSchemaTemplate(String templateName)` | 删除模式模板 | `templateName`: 要删除的模板名称 | +| `addAlignedMeasurementsInTemplate(...)` | 添加对齐测点到模板 | 模板名称、测点路径列表、数据类型、编码类型、压缩类型 | +| `addUnalignedMeasurementsInTemplate(...)` | 添加非对齐测点到模板 | 同上 | +| `deleteNodeInTemplate(String templateName, String path)` | 删除模板中的节点 | `templateName`: 模板名称,`path`: 要删除的路径 | +| `countMeasurementsInTemplate(String name)` | 统计模板中测点数量 | `name`: 模板名称 | +| `isMeasurementInTemplate(String templateName, String path)` | 检查模板中是否存在某测点 | `templateName`: 模板名称,`path`: 测点路径 | +| `isPathExistInTemplate(String templateName, String path)` | 检查模板中路径是否存在 | 同上 | +| `showMeasurementsInTemplate(String templateName)` | 显示模板中的测点 | `templateName`: 模板名称 | +| `showMeasurementsInTemplate(String templateName, String pattern)` | 按模式显示模板中的测点 | `templateName`: 模板名称,`pattern`: 匹配模式 | +| `showAllTemplates()` | 显示所有模板 | 无参数 | +| `showPathsTemplateSetOn(String templateName)` | 显示模板应用的路径 | `templateName`: 模板名称 | +| `showPathsTemplateUsingOn(String templateName)` | 显示模板实际使用的路径 | 同上 | +| `unsetSchemaTemplate(String prefixPath, String templateName)` | 取消路径的模板设置 | `prefixPath`: 路径,`templateName`: 模板名称 | + + +#### 3.2.2 数据写入 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------ | +| `insertRecord(String deviceId, long time, List measurements, List types, Object... values)` | 插入单条记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`types`: 数据类型列表,`values`: 值列表 | +| `insertRecord(String deviceId, long time, List measurements, List values)` | 插入单条记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`values`: 值列表 | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | 插入多条记录 | `deviceIds`: 设备ID列表,`times`: 时间戳列表,`measurementsList`: 测点列表列表,`valuesList`: 值列表 | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多条记录 | 同上,增加 `typesList`: 数据类型列表 | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入单设备的多条记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表列表,`typesList`: 类型列表,`valuesList`: 值列表 | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | 插入排序后的单设备多条记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | 插入字符串格式的单设备记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | 插入排序的字符串格式单设备记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List types, List values)` | 插入单条对齐记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`types`: 类型列表,`values`: 值列表 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List values)` | 插入字符串格式的单条对齐记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`values`: 值列表 | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | 插入多条对齐记录 | `deviceIds`: 设备ID列表,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多条对齐记录 | 同上,增加 `typesList`: 数据类型列表 | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入单设备的多条对齐记录 | 同上 | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | 插入排序的单设备多条对齐记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | 插入字符串格式的单设备对齐记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | 插入排序的字符串格式单设备对齐记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertTablet(Tablet tablet)` | 插入单个Tablet数据 | `tablet`: 要插入的Tablet数据 | +| `insertTablet(Tablet tablet, boolean sorted)` | 插入排序的Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertAlignedTablet(Tablet tablet)` | 插入对齐的Tablet数据 | `tablet`: 要插入的Tablet数据 | +| `insertAlignedTablet(Tablet tablet, boolean sorted)` | 插入排序的对齐Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertTablets(Map tablets)` | 批量插入多个Tablet数据 | `tablets`: 设备ID到Tablet的映射表 | +| `insertTablets(Map tablets, boolean sorted)` | 批量插入排序的多个Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertAlignedTablets(Map tablets)` | 批量插入多个对齐Tablet数据 | `tablets`: 设备ID到Tablet的映射表 | +| `insertAlignedTablets(Map tablets, boolean sorted)` | 批量插入排序的多个对齐Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | + +#### 3.2.3 数据删除 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ---------------------------- | ---------------------------------------- | +| `deleteTimeseries(String path)` | 删除单个时间序列 | `path`: 时间序列路径 | +| `deleteTimeseries(List paths)` | 批量删除时间序列 | `paths`: 时间序列路径列表 | +| `deleteData(String path, long endTime)` | 删除指定路径的历史数据 | `path`: 路径,`endTime`: 结束时间戳 | +| `deleteData(List paths, long endTime)` | 批量删除路径的历史数据 | `paths`: 路径列表,`endTime`: 结束时间戳 | +| `deleteData(List paths, long startTime, long endTime)` | 删除路径时间范围内的历史数据 | 同上,增加 `startTime`: 起始时间戳 | + + +#### 3.2.4 数据查询 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | -------------------------------- | ------------------------------------------------------------ | +| `executeQueryStatement(String sql)` | 执行查询语句 | `sql`: 查询SQL语句 | +| `executeQueryStatement(String sql, long timeoutInMs)` | 执行带超时的查询语句 | `sql`: 查询SQL语句,`timeoutInMs`: 查询超时时间(毫秒),默认取服务器配置即60s | +| `executeRawDataQuery(List paths, long startTime, long endTime)` | 查询指定路径的原始数据 | `paths`: 查询路径列表,`startTime`: 起始时间戳,`endTime`: 结束时间戳 | +| `executeRawDataQuery(List paths, long startTime, long endTime, long timeOut)` | 查询指定路径的原始数据(带超时) | 同上,增加 `timeOut`: 超时时间 | +| `executeLastDataQuery(List paths)` | 查询最新数据 | `paths`: 查询路径列表 | +| `executeLastDataQuery(List paths, long lastTime)` | 查询指定时间的最新数据 | `paths`: 查询路径列表,`lastTime`: 指定的时间戳 | +| `executeLastDataQuery(List paths, long lastTime, long timeOut)` | 查询指定时间的最新数据(带超时) | 同上,增加 `timeOut`: 超时时间 | +| `executeLastDataQueryForOneDevice(String db, String device, List sensors, boolean isLegalPathNodes)` | 查询单个设备的最新数据 | `db`: 数据库名,`device`: 设备名,`sensors`: 传感器列表,`isLegalPathNodes`: 是否合法路径节点 | +| `executeAggregationQuery(List paths, List aggregations)` | 执行聚合查询 | `paths`: 查询路径列表,`aggregations`: 聚合类型列表 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime)` | 执行带时间范围的聚合查询 | 同上,增加 `startTime`: 起始时间戳,`endTime`: 结束时间戳 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval)` | 执行带时间间隔的聚合查询 | 同上,增加 `interval`: 时间间隔 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval, long slidingStep)` | 执行滑动窗口聚合查询 | 同上,增加 `slidingStep`: 滑动步长 | +| `fetchAllConnections()` | 获取所有活动连接信息 | 无参数 | + +#### 3.2.5 系统状态与备份 + +| 方法名 | 功能描述 | 参数解释 | +| -------------------------- | ---------------------- | -------------------------------------- | +| `getBackupConfiguration()` | 获取备份配置信息 | 无参数 | +| `fetchAllConnections()` | 获取所有活动的连接信息 | 无参数 | +| `getSystemStatus()` | 获取系统状态 | 已废弃,默认返回 `SystemStatus.NORMAL` | + + + diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md b/src/zh/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md index 22879945d..f37cfc625 100644 --- a/src/zh/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md +++ b/src/zh/UserGuide/Master/Tree/API/Programming-OPC-UA_timecho.md @@ -76,23 +76,23 @@ create pipe p1 'sink.opcua.tcp.port' = '12686', 'sink.opcua.https.port' = '8443', 'sink.user' = 'root', - 'sink.password' = 'root', + 'sink.password' = 'TimechoDB@2021', //V2.0.6.x 之前默认密码为root 'sink.opcua.security.dir' = '...' ) ``` ### 2.2 参数 -| **参数** | **描述** | **取值范围** | **是否必填** | **默认值** | -| ---------------------------------- | ------------------------------ | -------------------------------- | ------------ | ------------------------------------------------------------ | -| sink | OPC UA SINK | String: opc-ua-sink | 必填 | | -| sink.opcua.model | OPC UA 使用的模式 | String: client-server / pub-sub | 选填 | pub-sub | -| sink.opcua.tcp.port | OPC UA 的 TCP 端口 | Integer: [0, 65536] | 选填 | 12686 | -| sink.opcua.https.port | OPC UA 的 HTTPS 端口 | Integer: [0, 65536] | 选填 | 8443 | +| **参数** | **描述** | **取值范围** | **是否必填** | **默认值** | +| ---------------------------------- | ------------------------------ | -------------------------------- | ------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| sink | OPC UA SINK | String: opc-ua-sink | 必填 | | +| sink.opcua.model | OPC UA 使用的模式 | String: client-server / pub-sub | 选填 | pub-sub | +| sink.opcua.tcp.port | OPC UA 的 TCP 端口 | Integer: [0, 65536] | 选填 | 12686 | +| sink.opcua.https.port | OPC UA 的 HTTPS 端口 | Integer: [0, 65536] | 选填 | 8443 | | sink.opcua.security.dir | OPC UA 的密钥及证书目录 | String: Path,支持绝对及相对目录 | 选填 | iotdb 相关 DataNode 的 conf 目录下的 opc_security 文件夹 /
如无 iotdb 的 conf 目录(例如 IDEA 中启动 DataNode),则为用户主目录下的 iotdb_opc_security 文件夹 / | -| sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | -| sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | -| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | root | +| sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | +| sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | +| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | TimechoDB@2021 //V2.0.6.x 之前默认密码为root | ### 2.3 示例 @@ -100,7 +100,7 @@ create pipe p1 create pipe p1 with sink ('sink' = 'opc-ua-sink', 'sink.user' = 'root', - 'sink.password' = 'root'); + 'sink.password' = 'TimechoDB@2021'); //V2.0.6.x 之前默认密码为root start pipe p1; ``` @@ -143,7 +143,7 @@ insert into root.test.db(time, s2) values(now(), 2) ​ 此处自动创建元数据开启。 -3. 在 UAExpert 中配置 iotdb 的连接,其中 password 填写为上述参数配置中 sink.password 中设定的密码(此处以默认密码root为例): +3. 在 UAExpert 中配置 iotdb 的连接,其中 password 填写为上述参数配置中 sink.password 中设定的密码(此处以密码root为例):
@@ -173,7 +173,7 @@ insert into root.test.db(time, s2) values(now(), 2) #### 准备工作 -该代码位于 iotdb-example 包下的 [opc-ua-sink 文件夹](https://github.com/apache/iotdb/tree/master/example/pipe-opc-ua-sink/src/main/java/org/apache/iotdb/opcua)中 +该代码位于 iotdb-example 包下的 [opc-ua-sink 文件夹](https://github.com/apache/iotdb/tree/rc/2.0.1/example/pipe-opc-ua-sink/src/main/java/org/apache/iotdb/opcua)中 代码中包含: diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API.md b/src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API.md rename to src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API_apache.md diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md b/src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..a36c508a0 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,811 @@ + + +# Python 原生接口 + +## 1. 依赖 + +在使用 Python 原生接口包前,您需要安装 thrift (>=0.13) 依赖。 + +## 2. 如何使用 (示例) + +首先下载包:`pip3 install apache-iotdb>=2.0` + +您可以从这里得到一个使用该包进行数据读写的例子:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_example.py) + +关于对齐时间序列读写的例子:[Aligned Timeseries Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_aligned_timeseries_example.py) + +(您需要在文件的头部添加`import iotdb`) + +或者: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` +## 3. 基本接口说明 + +下面将给出 Session 对应的接口的简要介绍和对应参数: + +### 3.1 初始化 + +* 初始化 Session + +```python +session = Session( + ip="127.0.0.1", + port="6667", + user="root", + password="TimechoDB@2021", //V2.0.6.x 之前密码默认值为root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* 初始化可连接多节点的 Session + +```python +session = Session.init_from_node_urls( + node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], + user="root", + password="TimechoDB@2021", //V2.0.6.x 之前密码默认值为root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* 开启 Session,并决定是否开启 RPC 压缩 + +```python +session.open(enable_rpc_compression=False) +``` + +注意: 客户端的 RPC 压缩开启状态需和服务端一致 + +* 关闭 Session + +```python +session.close() +``` +### 3.2 通过SessionPool管理session连接 + +利用SessionPool管理session,不需要再考虑如何重用session。当session连接到达pool的最大值时,获取session的请求会被阻塞,可以通过参数设置阻塞等待时间。每次session使用完需要使用putBack方法将session归还到SessionPool中管理。 + +#### 创建SessionPool + +```python +pool_config = PoolConfig(host=ip,port=port, user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 + +# 通过配置参数创建连接池 +session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) +``` +#### 通过分布式节点创建SessionPool +```python +pool_config = PoolConfig(node_urls=node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 +``` + +#### 通过SessionPool获取session,使用完手动调用PutBack + +```python +session = session_pool.get_session() +session.set_storage_group(STORAGE_GROUP_NAME) +session.create_time_series( + TIMESERIES_PATH, TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.SNAPPY +) +# 使用完调用putBack归还 +session_pool.put_back(session) +# 关闭sessionPool时同时关闭管理的session +session_pool.close() +``` + +### 3.3 SSL 连接 + +#### 3.3.1 服务器端配置证书 + +`conf/iotdb-system.properties` 配置文件中查找或添加以下配置项: + +```Java +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 配置 python 客户端证书 + +- 设置 use_ssl 为 True 以启用 SSL。 +- 指定客户端证书路径,使用 ca_certs 参数。 + +```Java +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**示例代码:使用 SSL 连接 IoTDB** + +```Java +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. 数据定义接口 DDL + +### 4.1 Database 管理 + +* 设置 database + +```python +session.set_storage_group(group_name) +``` + +* 删除单个或多个 database + +```python +session.delete_storage_group(group_name) +session.delete_storage_groups(group_name_lst) +``` +### 4.2 时间序列管理 + +* 创建单个或多个时间序列 + +```python +session.create_time_series(ts_path, data_type, encoding, compressor, + props=None, tags=None, attributes=None, alias=None) + +session.create_multi_time_series( + ts_path_lst, data_type_lst, encoding_lst, compressor_lst, + props_lst=None, tags_lst=None, attributes_lst=None, alias_lst=None +) +``` + +* 创建对齐时间序列 + +```python +session.create_aligned_time_series( + device_id, measurements_lst, data_type_lst, encoding_lst, compressor_lst +) +``` + +注意:目前**暂不支持**使用传感器别名。 + +* 删除一个或多个时间序列 + +```python +session.delete_time_series(paths_list) +``` + +* 检测时间序列是否存在 + +```python +session.check_time_series_exists(path) +``` + +## 5. 数据操作接口 DML + +### 5.1 数据写入 + +推荐使用 insert_tablet 帮助提高写入效率 + +* 插入一个 Tablet,Tablet 是一个设备若干行数据块,每一行的列都相同 + * **写入效率高** + * **支持写入空值** (0.13 版本起) + +Python API 里目前有两种 Tablet 实现 + +* 普通 Tablet + +```python +values_ = [ + [False, 10, 11, 1.1, 10011.1, "test01"], + [True, 100, 11111, 1.25, 101.0, "test02"], + [False, 100, 1, 188.1, 688.25, "test03"], + [True, 0, 0, 0, 6.25, "test04"], +] +timestamps_ = [1, 2, 3, 4] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) + +values_ = [ + [None, 10, 11, 1.1, 10011.1, "test01"], + [True, None, 11111, 1.25, 101.0, "test02"], + [False, 100, None, 188.1, 688.25, "test03"], + [True, 0, 0, 0, None, None], +] +timestamps_ = [16, 17, 18, 19] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) +``` +* Numpy Tablet + +相较于普通 Tablet,Numpy Tablet 使用 [numpy.ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) 来记录数值型数据。 +内存占用和序列化耗时会降低很多,写入效率也会有很大提升。 + +**注意** +1. Tablet 中的每一列时间戳和值记录为一个 ndarray +2. Numpy Tablet 只支持大端类型数据,ndarray 构建时如果不指定数据类型会使用小端,因此推荐在构建 ndarray 时指定下面例子中类型使用大端。如果不指定,IoTDB Python客户端也会进行大小端转换,不影响使用正确性。 + +```python +import numpy as np +data_types_ = [ + TSDataType.BOOLEAN, + TSDataType.INT32, + TSDataType.INT64, + TSDataType.FLOAT, + TSDataType.DOUBLE, + TSDataType.TEXT, +] +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([1, 2, 3, 4], TSDataType.INT64.np_dtype()) +np_tablet_ = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_ +) +session.insert_tablet(np_tablet_) + +# insert one numpy tablet with None into the database. +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([98, 99, 100, 101], TSDataType.INT64.np_dtype()) +np_bitmaps_ = [] +for i in range(len(measurements_)): + np_bitmaps_.append(BitMap(len(np_timestamps_))) +np_bitmaps_[0].mark(0) +np_bitmaps_[1].mark(1) +np_bitmaps_[2].mark(2) +np_bitmaps_[4].mark(3) +np_bitmaps_[5].mark(3) +np_tablet_with_none = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_, np_bitmaps_ +) +session.insert_tablet(np_tablet_with_none) +``` + +* 插入多个 Tablet + +```python +session.insert_tablets(tablet_lst) +``` + +* 插入一个 Record,一个 Record 是一个设备一个时间戳下多个测点的数据。 + +```python +session.insert_record(device_id, timestamp, measurements_, data_types_, values_) +``` + +* 插入多个 Record + +```python +session.insert_records( + device_ids_, time_list_, measurements_list_, data_type_list_, values_list_ + ) +``` + +* 插入同属于一个 device 的多个 Record + +```python +session.insert_records_of_one_device(device_id, time_list, measurements_list, data_types_list, values_list) +``` + +### 5.2 带有类型推断的写入 + +当数据均是 String 类型时,我们可以使用如下接口,根据 value 的值进行类型推断。例如:value 为 "true" ,就可以自动推断为布尔类型。value 为 "3.2" ,就可以自动推断为数值类型。服务器需要做类型推断,可能会有额外耗时,速度较无需类型推断的写入慢 + +```python +session.insert_str_record(device_id, timestamp, measurements, string_values) +``` + +### 5.3 对齐时间序列的写入 + +对齐时间序列的写入使用 insert_aligned_xxx 接口,其余与上述接口类似: + +* insert_aligned_record +* insert_aligned_records +* insert_aligned_records_of_one_device +* insert_aligned_tablet +* insert_aligned_tablets + + +## 6. IoTDB-SQL 接口 + +* 执行查询语句 + +```python +session.execute_query_statement(sql) +``` + +* 执行非查询语句 + +```python +session.execute_non_query_statement(sql) +``` + +* 执行语句 + +```python +session.execute_statement(sql) +``` + + +## 7. 元数据模版接口 +### 7.1 构建元数据模版 +1. 首先构建 Template 类 +2. 添加子节点 MeasurementNode +3. 调用创建元数据模版接口 + +```python +template = Template(name=template_name, share_time=True) + +m_node_x = MeasurementNode("x", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_y = MeasurementNode("y", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_z = MeasurementNode("z", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) + +template.add_template(m_node_x) +template.add_template(m_node_y) +template.add_template(m_node_z) + +session.create_schema_template(template) +``` +### 7.2 改模版节点信息 +修改模版节点,其中修改的模版必须已经被创建。以下函数能够在已经存在的模版中增加或者删除物理量 +* 在模版中增加实体 +```python +session.add_measurements_in_template(template_name, measurements_path, data_types, encodings, compressors, is_aligned) +``` + +* 在模版中删除物理量 +```python +session.delete_node_in_template(template_name, path) +``` + +### 7.3 挂载元数据模板 +```python +session.set_schema_template(template_name, prefix_path) +``` + +### 7.4 卸载元数据模版 +```python +session.unset_schema_template(template_name, prefix_path) +``` + +### 7.5 查看元数据模版 +* 查看所有的元数据模版 +```python +session.show_all_templates() +``` +* 查看元数据模版中的物理量个数 +```python +session.count_measurements_in_template(template_name) +``` + +* 判断某个节点是否为物理量,该节点必须已经在元数据模版中 +```python +session.count_measurements_in_template(template_name, path) +``` + +* 判断某个路径是否在元数据模版中,这个路径有可能不在元数据模版中 +```python +session.is_path_exist_in_template(template_name, path) +``` + +* 查看某个元数据模板下的物理量 +```python +session.show_measurements_in_template(template_name) +``` + +* 查看挂载了某个元数据模板的路径前缀 +```python +session.show_paths_template_set_on(template_name) +``` + +* 查看使用了某个元数据模板(即序列已创建)的路径前缀 +```python +session.show_paths_template_using_on(template_name) +``` + +### 7.6 删除元数据模版 +删除已经存在的元数据模版,不支持删除已经挂载的模版 +```python +session.drop_schema_template("template_python") +``` + + +## 8. 对 Pandas 的支持 + +我们支持将查询结果轻松地转换为 [Pandas Dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)。 + +SessionDataSet 有一个方法`.todf()`,它的作用是消费 SessionDataSet 中的数据,并将数据转换为 pandas dataframe。 + +例子: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +result = session.execute_query_statement("SELECT ** FROM root") + +# Transform to Pandas Dataset +df = result.todf() + +session.close() + +# Now you can work with the dataframe +df = ... +``` + +## 9. IoTDB Testcontainer + +Python 客户端对测试的支持是基于`testcontainers`库 (https://testcontainers-python.readthedocs.io/en/latest/index.html) 的,如果您想使用该特性,就需要将其安装到您的项目中。 + +要在 Docker 容器中启动(和停止)一个 IoTDB 数据库,只需这样做: + +```python +class MyTestCase(unittest.TestCase): + + def test_something(self): + with IoTDBContainer() as c: + session = Session("localhost", c.get_exposed_port(6667), "root", "TimechoDB@2021") //V2.0.6.x 之前密码默认值为root + session.open(False) + result = session.execute_query_statement("SHOW TIMESERIES") + print(result) + session.close() +``` + +默认情况下,它会拉取最新的 IoTDB 镜像 `apache/iotdb:latest`进行测试,如果您想指定待测 IoTDB 的版本,您只需要将版本信息像这样声明:`IoTDBContainer("apache/iotdb:0.12.0")`,此时,您就会得到一个`0.12.0`版本的 IoTDB 实例。 + +## 10. IoTDB DBAPI + +IoTDB DBAPI 遵循 Python DB API 2.0 规范 (https://peps.python.org/pep-0249/),实现了通过Python语言访问数据库的通用接口。 + +### 10.1 例子 ++ 初始化 + +初始化的参数与Session部分保持一致(sqlalchemy_mode参数除外,该参数仅在SQLAlchemy方言中使用) +```python +from iotdb.dbapi import connect + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +conn = connect(ip, port_, username_, password_,fetch_size=1024,zone_id="UTC+8",sqlalchemy_mode=False) +cursor = conn.cursor() +``` ++ 执行简单的SQL语句 +```python +cursor.execute("SELECT ** FROM root") +for row in cursor.fetchall(): + print(row) +``` + ++ 执行带有参数的SQL语句 + +IoTDB DBAPI 支持pyformat风格的参数 +```python +cursor.execute("SELECT ** FROM root WHERE time < %(time)s",{"time":"2017-11-01T00:08:00.000"}) +for row in cursor.fetchall(): + print(row) +``` + ++ 批量执行带有参数的SQL语句 +```python +seq_of_parameters = [ + {"timestamp": 1, "temperature": 1}, + {"timestamp": 2, "temperature": 2}, + {"timestamp": 3, "temperature": 3}, + {"timestamp": 4, "temperature": 4}, + {"timestamp": 5, "temperature": 5}, +] +sql = "insert into root.cursor(timestamp,temperature) values(%(timestamp)s,%(temperature)s)" +cursor.executemany(sql,seq_of_parameters) +``` + ++ 关闭连接 +```python +cursor.close() +conn.close() +``` + +## 11. IoTDB SQLAlchemy Dialect(实验性) +IoTDB的SQLAlchemy方言主要是为了适配Apache superset而编写的,该部分仍在完善中,请勿在生产环境中使用! +### 11.1 元数据模型映射 +SQLAlchemy 所使用的数据模型为关系数据模型,这种数据模型通过表格来描述不同实体之间的关系。 +而 IoTDB 的数据模型为层次数据模型,通过树状结构来对数据进行组织。 +为了使 IoTDB 能够适配 SQLAlchemy 的方言,需要对 IoTDB 中原有的数据模型进行重新组织, +把 IoTDB 的数据模型转换成 SQLAlchemy 的数据模型。 + +IoTDB 中的元数据有: + +1. Database:数据库 +2. Path:存储路径 +3. Entity:实体 +4. Measurement:物理量 + +SQLAlchemy 中的元数据有: +1. Schema:数据模式 +2. Table:数据表 +3. Column:数据列 + +它们之间的映射关系为: + +| SQLAlchemy中的元数据 | IoTDB中对应的元数据 | +| -------------------- | ---------------------------------------------- | +| Schema | Database | +| Table | Path ( from database to entity ) + Entity | +| Column | Measurement | + +下图更加清晰的展示了二者的映射关系: + +![sqlalchemy-to-iotdb](/img/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true) + +### 11.2 数据类型映射 +| IoTDB 中的数据类型 | SQLAlchemy 中的数据类型 | +|--------------|-------------------| +| BOOLEAN | Boolean | +| INT32 | Integer | +| INT64 | BigInteger | +| FLOAT | Float | +| DOUBLE | Float | +| TEXT | Text | +| LONG | BigInteger | +### 11.3 Example + ++ 执行语句 + +```python +from sqlalchemy import create_engine + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //V2.0.6.x 之前密码默认值为root +connect = engine.connect() +result = connect.execute("SELECT ** FROM root") +for row in result.fetchall(): + print(row) +``` + ++ ORM (目前只支持简单的查询) + +```python +from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +metadata = MetaData( + schema='root.factory' +) +Base = declarative_base(metadata=metadata) + + +class Device(Base): + __tablename__ = "room2.device1" + Time = Column(BigInteger, primary_key=True) + temperature = Column(Float) + status = Column(Float) + + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //V2.0.6.x 之前密码默认值为root + +DbSession = sessionmaker(bind=engine) +session = DbSession() + +res = session.query(Device.status).filter(Device.temperature > 1) + +for row in res: + print(row) +``` + +## 12. 给开发人员 + +### 12.1 介绍 + +这是一个使用 thrift rpc 接口连接到 IoTDB 的示例。在 Windows 和 Linux 上操作几乎是一样的,但要注意路径分隔符等不同之处。 + +### 12.2 依赖 + +首选 Python3.7 或更高版本。 + +必须安装 thrift(0.11.0 或更高版本)才能将 thrift 文件编译为 Python 代码。下面是官方的安装教程,最终,您应该得到一个 thrift 可执行文件。 + +``` +http://thrift.apache.org/docs/install/ +``` + +在开始之前,您还需要在 Python 环境中安装`requirements_dev.txt`中的其他依赖: +```shell +pip install -r requirements_dev.txt +``` + +### 12.3 编译 thrift 库并调试 + +在 IoTDB 源代码文件夹的根目录下,运行`mvn clean generate-sources -pl iotdb-client/client-py -am`, + +这个指令将自动删除`iotdb/thrift`中的文件,并使用新生成的 thrift 文件重新填充该文件夹。 + +这个文件夹在 git 中会被忽略,并且**永远不应该被推到 git 中!** + +**注意**不要将`iotdb/thrift`上传到 git 仓库中 ! + +### 12.4 Session 客户端 & 使用示例 + +我们将 thrift 接口打包到`client-py/src/iotdb/session.py `中(与 Java 版本类似),还提供了一个示例文件`client-py/src/SessionExample.py`来说明如何使用 Session 模块。请仔细阅读。 + +另一个简单的例子: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + +### 12.5 测试 + +请在`tests`文件夹中添加自定义测试。 + +要运行所有的测试,只需在根目录中运行`pytest . `即可。 + +**注意**一些测试需要在您的系统上使用 docker,因为测试的 IoTDB 实例是使用 [testcontainers](https://testcontainers-python.readthedocs.io/en/latest/index.html) 在 docker 容器中启动的。 + +### 12.6 其他工具 + +[black](https://pypi.org/project/black/) 和 [flake8](https://pypi.org/project/flake8/) 分别用于自动格式化和 linting。 +它们可以通过 `black .` 或 `flake8 .` 分别运行。 + +## 13. 发版 + +要进行发版, + +只需确保您生成了正确的 thrift 代码, + +运行了 linting 并进行了自动格式化, + +然后,确保所有测试都正常通过(通过`pytest . `), + +最后,您就可以将包发布到 pypi 了。 + +### 13.1 准备您的环境 + +首先,通过`pip install -r requirements_dev.txt`安装所有必要的开发依赖。 + +### 13.2 发版 + +有一个脚本`release.sh`可以用来执行发版的所有步骤。 + +这些步骤包括: + +* 删除所有临时目录(如果存在) + +* (重新)通过 mvn 生成所有必须的源代码 + +* 运行 linting (flke8) + +* 通过 pytest 运行测试 + +* Build + +* 发布到 pypi diff --git a/src/zh/UserGuide/Master/Tree/API/RestServiceV1.md b/src/zh/UserGuide/Master/Tree/API/RestServiceV1_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Tree/API/RestServiceV1.md rename to src/zh/UserGuide/Master/Tree/API/RestServiceV1_apache.md diff --git a/src/zh/UserGuide/Master/Tree/API/RestServiceV1_timecho.md b/src/zh/UserGuide/Master/Tree/API/RestServiceV1_timecho.md new file mode 100644 index 000000000..78859f1ba --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/RestServiceV1_timecho.md @@ -0,0 +1,941 @@ + + +# REST API V1(不推荐) +IoTDB 的 RESTful 服务可用于查询、写入和管理操作,它使用 OpenAPI 标准来定义接口并生成框架。 + +## 1. 开启RESTful 服务 +RESTful 服务默认情况是关闭的 + + 找到IoTDB安装目录下面的`conf/iotdb-system.properties`文件,将 `enable_rest_service` 设置为 `true` 以启用该模块。 + + ```properties + enable_rest_service=true + ``` + +## 2. 鉴权 +除了检活接口 `/ping`,RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。 + +示例中使用的用户名为:`root`,密码为:`TimechoDB@2021`,对应的 Basic 鉴权 Header 格式为 + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- 若用户名密码认证失败,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- 若未设置 `Authorization`,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. 接口 + +### 3.1 ping + +ping 接口可以用于线上服务检活。 + +请求方式:`GET` + +请求路径:`http://ip:port/ping +` +请求示例: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +返回的 HTTP 状态码: + +- `200`:当前服务工作正常,可以接收外部请求。 +- `503`:当前服务出现异常,不能接收外部请求。 + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: + +- HTTP 状态码为 `200` 时: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- HTTP 状态码为 `503` 时: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` 接口访问不需要鉴权。 + +### 3.2 query + +query 接口可以用于处理数据查询和元数据查询。 + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/query` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-----------| ------------ | ------------ |------------ | +| sql | string | 是 | | +| rowLimit | integer | 否 | 一次查询能返回的结果集的最大行数。
如果不设置该参数,将使用配置文件的 `rest_query_default_row_size_limit` 作为默认值。
当返回结果集的行数超出限制时,将返回状态码 `411`。 | + +响应参数: + +| 参数名称 |参数类型 |参数描述| +|--------------| ------------ | ------------| +| expressions | array | 用于数据查询时结果集列名的数组,用于元数据查询时为`null`| +| columnNames | array | 用于元数据查询结果集列名数组,用于数据查询时为`null` | +| timestamps | array | 时间戳列,用于元数据查询时为`null` | +| values |array|二维数组,第一维与结果集列名数组的长度相同,第二维数组代表结果集的一列| + +请求示例如下所示: + +提示:为了避免OOM问题,不推荐使用select * from root.xx.** 这种查找方式。 + +1. 请求示例 表达式查询: + ```shell + curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v1/query +``` + + - 响应示例: + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +2. 请求示例 show child paths: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +3. 请求示例 show child nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +4. 请求示例 show all ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +5. 请求示例 show ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +6. 请求示例 show functions: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +7. 请求示例 show timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +8. 请求示例 show latest timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +9. 请求示例 count timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +10. 请求示例 count nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +11. 请求示例 show devices: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +12. 请求示例 show devices with database: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +13. 请求示例 list user: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +14. 请求示例 原始聚合查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +15. 请求示例 group by level: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +16. 请求示例 group by: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +17. 请求示例 last: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +18. 请求示例 disable align: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +19. 请求示例 align by device: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +20. 请求示例 select into: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/nonQuery` + +参数说明: + +|参数名称 |参数类型 |是否必填|参数描述| +| ------------ | ------------ | ------------ |------------ | +| sql | string | 是 | | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v1/nonQuery +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/insertTablet` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|--------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements | array | 是 | 测点名称 | +| dataTypes | array | 是 | 数据类型 | +| values | array | 是 | 值列,每一列中的值可以为 `null` | +| isAligned | boolean | 是 | 是否是对齐时间序列 | +| deviceId | string | 是 | 设备名称 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"dataTypes":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"isAligned":false,"deviceId":"root.sg27"}' http://127.0.0.1:18080/rest/v1/insertTablet +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. 配置 + +配置位于 `iotdb-system.properties` 中。 + + + +* 将 `enable_rest_service` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_rest_service=true +``` + +* 仅在 `enable_rest_service=true` 时生效。将 `rest_service_port `设置为数字(1025~65535),以自定义REST服务套接字端口。默认情况下,值为 `18080`。 + +```properties +rest_service_port=18080 +``` + +* 将 'enable_swagger' 设置 'true' 启用swagger来展示rest接口信息, 而设置为 'false' 关闭该功能. 默认情况下,该值为 `false`。 + +```properties +enable_swagger=false +``` + +* 一次查询能返回的结果集最大行数。当返回结果集的行数超出参数限制时,您只会得到在行数范围内的结果集,且将得到状态码`411`。 + +```properties +rest_query_default_row_size_limit=10000 +``` + +* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时) + +```properties +cache_expire=28800 +``` + +* 缓存中存储的最大用户数量(默认是100) + +```properties +cache_max_num=100 +``` + +* 缓存初始容量(默认是10) + +```properties +cache_init_num=10 +``` + +* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_https=false +``` + +* keyStore 所在路径(非必填) + +```properties +key_store_path= +``` + + +* keyStore 密码(非必填) + +```properties +key_store_pwd= +``` + + +* trustStore 所在路径(非必填) + +```properties +trust_store_path= +``` + +* trustStore 密码(非必填) + +```properties +trust_store_pwd= +``` + + +* SSL 超时时间,单位为秒 + +```properties +idle_timeout=5000 +``` diff --git a/src/zh/UserGuide/Master/Tree/API/RestServiceV2.md b/src/zh/UserGuide/Master/Tree/API/RestServiceV2_apache.md similarity index 100% rename from src/zh/UserGuide/Master/Tree/API/RestServiceV2.md rename to src/zh/UserGuide/Master/Tree/API/RestServiceV2_apache.md diff --git a/src/zh/UserGuide/Master/Tree/API/RestServiceV2_timecho.md b/src/zh/UserGuide/Master/Tree/API/RestServiceV2_timecho.md new file mode 100644 index 000000000..8b753fa68 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/RestServiceV2_timecho.md @@ -0,0 +1,980 @@ + + +# REST API V2 +IoTDB 的 RESTful 服务可用于查询、写入和管理操作,它使用 OpenAPI 标准来定义接口并生成框架。 + +## 1. 开启RESTful 服务 +RESTful 服务默认情况是关闭的 + + 找到IoTDB安装目录下面的`conf/iotdb-system.properties`文件,将 `enable_rest_service` 设置为 `true` 以启用该模块。 + + ```properties + enable_rest_service=true + ``` + +## 2. 鉴权 +除了检活接口 `/ping`,RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。 + +示例中使用的用户名为:`root`,密码为:`TimechoDB@2021`,对应的 Basic 鉴权 Header 格式为 + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- 若用户名密码认证失败,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- 若未设置 `Authorization`,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. 接口 + +### 3.1 ping + +ping 接口可以用于线上服务检活。 + +请求方式:`GET` + +请求路径:http://ip:port/ping + +请求示例: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +返回的 HTTP 状态码: + +- `200`:当前服务工作正常,可以接收外部请求。 +- `503`:当前服务出现异常,不能接收外部请求。 + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: + +- HTTP 状态码为 `200` 时: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- HTTP 状态码为 `503` 时: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` 接口访问不需要鉴权。 + +### 3.2 query + +query 接口可以用于处理数据查询和元数据查询。 + +请求方式:`POST` + +请求头:`application/json` + +请求路径: `http://ip:port/rest/v2/query` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-----------| ------------ | ------------ |------------ | +| sql | string | 是 | | +| row_limit | integer | 否 | 一次查询能返回的结果集的最大行数。
如果不设置该参数,将使用配置文件的 `rest_query_default_row_size_limit` 作为默认值。
当返回结果集的行数超出限制时,将返回状态码 `411`。 | + +响应参数: + +| 参数名称 |参数类型 |参数描述| +|--------------| ------------ | ------------| +| expressions | array | 用于数据查询时结果集列名的数组,用于元数据查询时为`null`| +| column_names | array | 用于元数据查询结果集列名数组,用于数据查询时为`null` | +| timestamps | array | 时间戳列,用于元数据查询时为`null` | +| values |array|二维数组,第一维与结果集列名数组的长度相同,第二维数组代表结果集的一列| + +请求示例如下所示: + +提示:为了避免OOM问题,不推荐使用select * from root.xx.** 这种查找方式。 + +1. 请求示例 表达式查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +2.请求示例 show child paths: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +3. 请求示例 show child nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +4. 请求示例 show all ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +5. 请求示例 show ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +6. 请求示例 show functions: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +7. 请求示例 show timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +8. 请求示例 show latest timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +9. 请求示例 count timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +10. 请求示例 count nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +11. 请求示例 show devices: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +12. 请求示例 show devices with database: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +13. 请求示例 list user: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +14. 请求示例 原始聚合查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +15. 请求示例 group by level: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +16. 请求示例 group by: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +17. 请求示例 last: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +18. 请求示例 disable align: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +19. 请求示例 align by device: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +20. 请求示例 select into: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/nonQuery` + +参数说明: + +|参数名称 |参数类型 |是否必填|参数描述| +| ------------ | ------------ | ------------ |------------ | +| sql | string | 是 | | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v2/nonQuery +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/insertTablet` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|--------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements | array | 是 | 测点名称 | +| data_types | array | 是 | 数据类型 | +| values | array | 是 | 值列,每一列中的值可以为 `null` | +| is_aligned | boolean | 是 | 是否是对齐时间序列 | +| device | string | 是 | 设备名称 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"data_types":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"is_aligned":false,"device":"root.sg27"}' http://127.0.0.1:18080/rest/v2/insertTablet +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +### 3.5 insertRecords + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/insertRecords` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-------------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements_list | array | 是 | 测点名称 | +| data_types_list | array | 是 | 数据类型 | +| values_list | array | 是 | 值列,每一列中的值可以为 `null` | +| devices | string | 是 | 设备名称 | +| is_aligned | string | 是 | 是否是对齐时间序列 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232113960,1635232151960,1635232143960,1635232143960],"measurements_list":[["s33","s44"],["s55","s66"],["s77","s88"],["s771","s881"]],"data_types_list":[["INT32","INT64"],["FLOAT","DOUBLE"],["FLOAT","DOUBLE"],["BOOLEAN","TEXT"]],"values_list":[[1,11],[2.1,2],[4,6],[false,"cccccc"]],"is_aligned":false,"devices":["root.s1","root.s1","root.s1","root.s3"]}' http://127.0.0.1:18080/rest/v2/insertRecords +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. 配置 + +配置位于 `iotdb-system.properties` 中。 + + + +* 将 `enable_rest_service` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_rest_service=true +``` + +* 仅在 `enable_rest_service=true` 时生效。将 `rest_service_port `设置为数字(1025~65535),以自定义REST服务套接字端口。默认情况下,值为 `18080`。 + +```properties +rest_service_port=18080 +``` + +* 将 'enable_swagger' 设置 'true' 启用swagger来展示rest接口信息, 而设置为 'false' 关闭该功能. 默认情况下,该值为 `false`。 + +```properties +enable_swagger=false +``` + +* 一次查询能返回的结果集最大行数。当返回结果集的行数超出参数限制时,您只会得到在行数范围内的结果集,且将得到状态码`411`。 + +```properties +rest_query_default_row_size_limit=10000 +``` + +* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时) + +```properties +cache_expire=28800 +``` + +* 缓存中存储的最大用户数量(默认是100) + +```properties +cache_max_num=100 +``` + +* 缓存初始容量(默认是10) + +```properties +cache_init_num=10 +``` + +* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_https=false +``` + +* keyStore 所在路径(非必填) + +```properties +key_store_path= +``` + + +* keyStore 密码(非必填) + +```properties +key_store_pwd= +``` + + +* trustStore 所在路径(非必填) + +```properties +trust_store_path= +``` + +* trustStore 密码(非必填) + +```properties +trust_store_pwd= +``` + + +* SSL 超时时间,单位为秒 + +```properties +idle_timeout=5000 +``` diff --git a/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data.md b/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md similarity index 99% rename from src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data.md rename to src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md index ba97766b3..7906532dc 100644 --- a/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data.md +++ b/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_apache.md @@ -279,7 +279,7 @@ It costs 0.016s - 在 SQL 命令行终端中执行查询语句:启动 SQL 命令行终端,直接输入查询语句执行即可,详见 [SQL 命令行终端](../Tools-System/CLI.md)。 -- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC.md) 。 +- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC_apache) 。 - 在 JAVA / C++ / Python / Go 等编程语言 API 中执行查询语句,详见应用编程接口一章相应文档。接口原型如下: @@ -287,7 +287,7 @@ It costs 0.016s SessionDataSet executeQueryStatement(String sql); ``` -- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1.md) 或者 [HTTP API V2](../API/RestServiceV2.md)。 +- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1_apache) 或者 [HTTP API V2](../API/RestServiceV2_apache)。 #### 常用查询的高效执行接口 @@ -3041,7 +3041,7 @@ It costs 0.375s * 所有 `SELECT` 子句中源序列的 `WRITE_SCHEMA` 权限。 * 所有 `INTO` 子句中目标序列 `WRITE_DATA` 权限。 -更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management.md)。 +更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management_apache)。 ### 10.4 相关配置参数 diff --git a/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md b/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md new file mode 100644 index 000000000..e1417e0a9 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Basic-Concept/Query-Data_timecho.md @@ -0,0 +1,3055 @@ + + +# 数据查询 +## 1. 概述 + +在 IoTDB 中,使用 `SELECT` 语句从一条或多条时间序列中查询数据,IoTDB 不区分历史数据和实时数据,用户可以用统一的sql语法进行查询,通过 `WHERE` 子句中的时间过滤谓词决定查询的时间范围。 + +### 1.1 语法定义 + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +其含义为: + +被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为供电状态(status)和温度传感器(temperature);该语句要求选择出 “2017-11-01T00:05:00.000” 至 “2017-11-01T00:12:00.000” 之间的所选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.018s +``` + +#### 示例3:按照多个时间区间选择同一设备的多列数据 + +IoTDB 支持在一次查询中指定多个时间区间条件,用户可以根据需求随意组合时间区间条件。例如, + +SQL 语句为: + +```sql +select status, temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +其含义为: + +被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为“供电状态(status)”和“温度传感器(temperature)”;该语句指定了两个不同的时间区间,分别为“2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000”和“2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任一时间区间的被选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| +|2017-11-01T16:35:00.000+08:00| true| 23.44| +|2017-11-01T16:36:00.000+08:00| false| 21.98| +|2017-11-01T16:37:00.000+08:00| false| 21.93| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 9 +It costs 0.018s +``` + +#### 示例4:按照多个时间区间选择不同设备的多列数据 + +该系统支持在一次查询中选择任意列的数据,也就是说,被选择的列可以来源于不同的设备。例如,SQL 语句为: + +```sql +select wf01.wt01.status, wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +其含义为: + +被选择的时间序列为 “ln 集团 wf01 子站 wt01 设备的供电状态” 以及 “ln 集团 wf02 子站 wt02 设备的硬件版本”;该语句指定了两个时间区间,分别为 “2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000” 和 “2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任意时间区间的被选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+--------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf02.wt02.hardware| ++-----------------------------+------------------------+--------------------------+ +|2017-11-01T00:06:00.000+08:00| false| v1| +|2017-11-01T00:07:00.000+08:00| false| v1| +|2017-11-01T00:08:00.000+08:00| false| v1| +|2017-11-01T00:09:00.000+08:00| false| v1| +|2017-11-01T00:10:00.000+08:00| true| v2| +|2017-11-01T00:11:00.000+08:00| false| v1| +|2017-11-01T16:35:00.000+08:00| true| v2| +|2017-11-01T16:36:00.000+08:00| false| v1| +|2017-11-01T16:37:00.000+08:00| false| v1| ++-----------------------------+------------------------+--------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### 示例5:根据时间降序返回结果集 + +IoTDB 支持 `order by time` 语句,用于对结果按照时间进行降序展示。例如,SQL 语句为: + +```sql +select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +语句执行的结果为: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-07T23:59:00.000+08:00| v1| false| 21.07| false| +|2017-11-07T23:58:00.000+08:00| v1| false| 22.93| false| +|2017-11-07T23:57:00.000+08:00| v2| true| 24.39| true| +|2017-11-07T23:56:00.000+08:00| v2| true| 24.44| true| +|2017-11-07T23:55:00.000+08:00| v2| true| 25.9| true| +|2017-11-07T23:54:00.000+08:00| v1| false| 22.52| false| +|2017-11-07T23:53:00.000+08:00| v2| true| 24.58| true| +|2017-11-07T23:52:00.000+08:00| v1| false| 20.18| false| +|2017-11-07T23:51:00.000+08:00| v1| false| 22.24| false| +|2017-11-07T23:50:00.000+08:00| v2| true| 23.7| true| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.016s +``` + +### 1.4 查询执行接口 + +在 IoTDB 中,提供两种方式执行数据查询操作: +- 使用 IoTDB-SQL 执行查询。 +- 常用查询的高效执行接口,包括时间序列原始数据范围查询、最新点查询、简单聚合查询。 + +#### 使用 IoTDB-SQL 执行查询 + +数据查询语句支持在 SQL 命令行终端、JDBC、JAVA / C++ / Python / Go 等编程语言 API、RESTful API 中使用。 + +- 在 SQL 命令行终端中执行查询语句:启动 SQL 命令行终端,直接输入查询语句执行即可,详见 [SQL 命令行终端](../Tools-System/CLI.md)。 + +- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC_timecho) 。 + +- 在 JAVA / C++ / Python / Go 等编程语言 API 中执行查询语句,详见应用编程接口一章相应文档。接口原型如下: + + ```java + SessionDataSet executeQueryStatement(String sql); + ``` + +- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1_timecho) 或者 [HTTP API V2](../API/RestServiceV2_timecho)。 + +#### 常用查询的高效执行接口 + +各编程语言的 API 为常用的查询提供了高效执行接口,可以省去 SQL 解析等操作的耗时。包括: + +* 时间序列原始数据范围查询: + - 指定的查询时间范围为左闭右开区间,包含开始时间但不包含结束时间。 + +```java +SessionDataSet executeRawDataQuery(List paths, long startTime, long endTime); +``` + +* 最新点查询: + - 查询最后一条时间戳大于等于某个时间点的数据。 + +```java +SessionDataSet executeLastDataQuery(List paths, long lastTime); +``` + +* 聚合查询: + - 支持指定查询时间范围。指定的查询时间范围为左闭右开区间,包含开始时间但不包含结束时间。 + - 支持按照时间区间分段查询。 + +```java +SessionDataSet executeAggregationQuery(List paths, List aggregations); + +SessionDataSet executeAggregationQuery( + List paths, List aggregations, long startTime, long endTime); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval, + long slidingStep); +``` + +## 2. 选择表达式(SELECT FROM 子句) + +`SELECT` 子句指定查询的输出,由若干个 `selectExpr` 组成。 每个 `selectExpr` 定义了查询结果中的一列或多列。 + +**`selectExpr` 是一个由时间序列路径后缀、常量、函数和运算符组成的表达式。即 `selectExpr` 中可以包含:** +- 时间序列路径后缀(支持使用通配符) +- 运算符 + - 算数运算符 + - 比较运算符 + - 逻辑运算符 +- 函数 + - 聚合函数 + - 时间序列生成函数(包括内置函数和用户自定义函数) +- 常量 + +### 2.1 使用别名 + +由于 IoTDB 独特的数据模型,在每个传感器前都附带有设备等诸多额外信息。有时,我们只针对某个具体设备查询,而这些前缀信息频繁显示造成了冗余,影响了结果集的显示与分析。 + +IoTDB 支持使用`AS`为查询结果集中的列指定别名。 + +**示例:** + +```sql +select s1 as temperature, s2 as speed from root.ln.wf01.wt01; +``` + +结果集将显示为: + +| Time | temperature | speed | +| ---- | ----------- | ----- | +| ... | ... | ... | + +### 2.2 运算符 + +IoTDB 中支持的运算符列表见文档 [运算符和函数](../SQL-Manual/Operator-and-Expression.md)。 + +### 2.3 函数 + +#### 聚合函数 + +聚合函数是多对一函数。它们对一组值进行聚合计算,得到单个聚合结果。 + +**包含聚合函数的查询称为聚合查询**,否则称为时间序列查询。 + +**注意:聚合查询和时间序列查询不能混合使用。** 下列语句是不支持的: + +```sql +select s1, count(s1) from root.sg.d1; +select sin(s1), count(s1) from root.sg.d1; +select s1, count(s1) from root.sg.d1 group by ([10,100),10ms); +``` + +IoTDB 支持的聚合函数见文档 [聚合函数](../SQL-Manual/Operator-and-Expression.md#内置函数)。 + +#### 时间序列生成函数 + +时间序列生成函数接受若干原始时间序列作为输入,产生一列时间序列输出。与聚合函数不同的是,时间序列生成函数的结果集带有时间戳列。 + +所有的时间序列生成函数都可以接受 * 作为输入,都可以与原始时间序列查询混合进行。 + +##### 内置时间序列生成函数 + +IoTDB 中支持的内置函数列表见文档 [运算符和函数](../SQL-Manual/Operator-and-Expression.md)。 + +##### 自定义时间序列生成函数 + +IoTDB 支持通过用户自定义函数(点击查看: [用户自定义函数](../User-Manual/Database-Programming.md#用户自定义函数) )能力进行函数功能扩展。 + +### 2.4 嵌套表达式举例 + +IoTDB 支持嵌套表达式,由于聚合查询和时间序列查询不能在一条查询语句中同时出现,我们将支持的嵌套表达式分为时间序列查询嵌套表达式和聚合查询嵌套表达式两类。 + +#### 时间序列查询嵌套表达式 + +IoTDB 支持在 `SELECT` 子句中计算由**时间序列、常量、时间序列生成函数(包括用户自定义函数)和运算符**组成的任意嵌套表达式。 + +**说明:** + +- 当某个时间戳下左操作数和右操作数都不为空(`null`)时,表达式才会有结果,否则表达式值为`null`,且默认不出现在结果集中。 +- 如果表达式中某个操作数对应多条时间序列(如通配符 `*`),那么每条时间序列对应的结果都会出现在结果集中(按照笛卡尔积形式)。 + +**示例 1:** + +```sql +select a, + b, + ((a + 1) * 2 - 1) % 2 + 1.5, + sin(a + sin(a + sin(b))), + -(a + b) * (sin(a + b) * sin(a + b) + cos(a + b) * cos(a + b)) + 1 +from root.sg1; +``` + +运行结果: + +``` ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Time|root.sg1.a|root.sg1.b|((((root.sg1.a + 1) * 2) - 1) % 2) + 1.5|sin(root.sg1.a + sin(root.sg1.a + sin(root.sg1.b)))|(-root.sg1.a + root.sg1.b * ((sin(root.sg1.a + root.sg1.b) * sin(root.sg1.a + root.sg1.b)) + (cos(root.sg1.a + root.sg1.b) * cos(root.sg1.a + root.sg1.b)))) + 1| ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|1970-01-01T08:00:00.010+08:00| 1| 1| 2.5| 0.9238430524420609| -1.0| +|1970-01-01T08:00:00.020+08:00| 2| 2| 2.5| 0.7903505371876317| -3.0| +|1970-01-01T08:00:00.030+08:00| 3| 3| 2.5| 0.14065207680386618| -5.0| +|1970-01-01T08:00:00.040+08:00| 4| null| 2.5| null| null| +|1970-01-01T08:00:00.050+08:00| null| 5| null| null| null| +|1970-01-01T08:00:00.060+08:00| 6| 6| 2.5| -0.7288037411970916| -11.0| ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +Total line number = 6 +It costs 0.048s +``` + +**示例 2:** + +```sql +select (a + b) * 2 + sin(a) from root.sg +``` + +运行结果: + +``` ++-----------------------------+----------------------------------------------+ +| Time|((root.sg.a + root.sg.b) * 2) + sin(root.sg.a)| ++-----------------------------+----------------------------------------------+ +|1970-01-01T08:00:00.010+08:00| 59.45597888911063| +|1970-01-01T08:00:00.020+08:00| 100.91294525072763| +|1970-01-01T08:00:00.030+08:00| 139.01196837590714| +|1970-01-01T08:00:00.040+08:00| 180.74511316047935| +|1970-01-01T08:00:00.050+08:00| 219.73762514629607| +|1970-01-01T08:00:00.060+08:00| 259.6951893788978| +|1970-01-01T08:00:00.070+08:00| 300.7738906815579| +|1970-01-01T08:00:00.090+08:00| 39.45597888911063| +|1970-01-01T08:00:00.100+08:00| 39.45597888911063| ++-----------------------------+----------------------------------------------+ +Total line number = 9 +It costs 0.011s +``` + +**示例 3:** + +```sql +select (a + *) / 2 from root.sg1 +``` + +运行结果: + +``` ++-----------------------------+-----------------------------+-----------------------------+ +| Time|(root.sg1.a + root.sg1.a) / 2|(root.sg1.a + root.sg1.b) / 2| ++-----------------------------+-----------------------------+-----------------------------+ +|1970-01-01T08:00:00.010+08:00| 1.0| 1.0| +|1970-01-01T08:00:00.020+08:00| 2.0| 2.0| +|1970-01-01T08:00:00.030+08:00| 3.0| 3.0| +|1970-01-01T08:00:00.040+08:00| 4.0| null| +|1970-01-01T08:00:00.060+08:00| 6.0| 6.0| ++-----------------------------+-----------------------------+-----------------------------+ +Total line number = 5 +It costs 0.011s +``` + +**示例 4:** + +```sql +select (a + b) * 3 from root.sg, root.ln +``` + +运行结果: + +``` ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +| Time|(root.sg.a + root.sg.b) * 3|(root.sg.a + root.ln.b) * 3|(root.ln.a + root.sg.b) * 3|(root.ln.a + root.ln.b) * 3| ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +|1970-01-01T08:00:00.010+08:00| 90.0| 270.0| 360.0| 540.0| +|1970-01-01T08:00:00.020+08:00| 150.0| 330.0| 690.0| 870.0| +|1970-01-01T08:00:00.030+08:00| 210.0| 450.0| 570.0| 810.0| +|1970-01-01T08:00:00.040+08:00| 270.0| 240.0| 690.0| 660.0| +|1970-01-01T08:00:00.050+08:00| 330.0| null| null| null| +|1970-01-01T08:00:00.060+08:00| 390.0| null| null| null| +|1970-01-01T08:00:00.070+08:00| 450.0| null| null| null| +|1970-01-01T08:00:00.090+08:00| 60.0| null| null| null| +|1970-01-01T08:00:00.100+08:00| 60.0| null| null| null| ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### 聚合查询嵌套表达式 + +IoTDB 支持在 `SELECT` 子句中计算由**聚合函数、常量、时间序列生成函数和表达式**组成的任意嵌套表达式。 + +**说明:** +- 当某个时间戳下左操作数和右操作数都不为空(`null`)时,表达式才会有结果,否则表达式值为`null`,且默认不出现在结果集中。但在使用`GROUP BY`子句的聚合查询嵌套表达式中,我们希望保留每个时间窗口的值,所以表达式值为`null`的窗口也包含在结果集中。 +- 如果表达式中某个操作数对应多条时间序列(如通配符`*`),那么每条时间序列对应的结果都会出现在结果集中(按照笛卡尔积形式)。 + +**示例 1:** + +```sql +select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) +from root.ln.wf01.wt01; +``` + +运行结果: + +``` ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +|avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|avg(root.ln.wf01.wt01.temperature) + sum(root.ln.wf01.wt01.hardware)| ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +| 15.927999999999999| -0.21826546964855045| 16.927999999999997| -7426.0| 7441.928| ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +Total line number = 1 +It costs 0.009s +``` + +**示例 2:** + +```sql +select avg(*), + (avg(*) + 1) * 3 / 2 -1 +from root.sg1 +``` + +运行结果: + +``` ++---------------+---------------+-------------------------------------+-------------------------------------+ +|avg(root.sg1.a)|avg(root.sg1.b)|(avg(root.sg1.a) + 1) * 3 / 2 - 1 |(avg(root.sg1.b) + 1) * 3 / 2 - 1 | ++---------------+---------------+-------------------------------------+-------------------------------------+ +| 3.2| 3.4| 5.300000000000001| 5.6000000000000005| ++---------------+---------------+-------------------------------------+-------------------------------------+ +Total line number = 1 +It costs 0.007s +``` + +**示例 3:** + +```sql +select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) as custom_sum +from root.ln.wf01.wt01 +GROUP BY([10, 90), 10ms); +``` + +运行结果: + +``` ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +| Time|avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|custom_sum| ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +|1970-01-01T08:00:00.010+08:00| 13.987499999999999| 0.9888207947857667| 14.987499999999999| -3211.0| 3224.9875| +|1970-01-01T08:00:00.020+08:00| 29.6| -0.9701057337071853| 30.6| -3720.0| 3749.6| +|1970-01-01T08:00:00.030+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.040+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.050+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.060+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.070+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.080+08:00| null| null| null| null| null| ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +Total line number = 8 +It costs 0.012s +``` + +### 2.5 最新点查询 + +最新点查询是时序数据库 Apache IoTDB 中提供的一种特殊查询。它返回指定时间序列中时间戳最大的数据点,即一条序列的最新状态。 + +在物联网数据分析场景中,此功能尤为重要。为了满足了用户对设备实时监控的需求,Apache IoTDB 对最新点查询进行了**缓存优化**,能够提供毫秒级的返回速度。 + +SQL 语法: + +```sql +select last [COMMA ]* from < PrefixPath > [COMMA < PrefixPath >]* [ORDER BY TIMESERIES (DESC | ASC)?] +``` + +其含义是: 查询时间序列 prefixPath.path 中最近时间戳的数据。 + +- `whereClause` 中当前只支持时间过滤条件,任何其他过滤条件都将会返回异常。当缓存的最新点不满足过滤条件时,IoTDB 需要从存储中获取结果,此时性能将会有所下降。 + +- 结果集为四列的结构: + + ``` + +----+----------+-----+--------+ + |Time|timeseries|value|dataType| + +----+----------+-----+--------+ + ``` + +- 可以使用 `ORDER BY TIME/TIMESERIES/VALUE/DATATYPE (DESC | ASC)` 指定结果集按照某一列进行降序/升序排列。当值列包含多种类型的数据时,按照字符串类型来排序。 + +**示例 1:** 查询 root.ln.wf01.wt01.status 的最新数据点 + +``` +IoTDB> select last status from root.ln.wf01.wt01 ++-----------------------------+------------------------+-----+--------+ +| Time| timeseries|value|dataType| ++-----------------------------+------------------------+-----+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.status|false| BOOLEAN| ++-----------------------------+------------------------+-----+--------+ +Total line number = 1 +It costs 0.000s +``` + +**示例 2:** 查询 root.ln.wf01.wt01 下 status,temperature 时间戳大于等于 2017-11-07T23:50:00 的最新数据点。 + +``` +IoTDB> select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 3:** 查询 root.ln.wf01.wt01 下所有序列的最新数据点,并按照序列名降序排列。 + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by timeseries desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 4:** 查询 root.ln.wf01.wt01 下所有序列的最新数据点,并按照dataType降序排列。 + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by dataType desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**注意:** 可以通过函数组合方式实现其他过滤条件查询最新点的需求,例如 + +``` +IoTDB> select max_time(*), last_value(*) from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 and status = false align by device ++-----------------+---------------------+----------------+-----------------------+------------------+ +| Device|max_time(temperature)|max_time(status)|last_value(temperature)|last_value(status)| ++-----------------+---------------------+----------------+-----------------------+------------------+ +|root.ln.wf01.wt01| 1510077540000| 1510077540000| 21.067368| false| ++-----------------+---------------------+----------------+-----------------------+------------------+ +Total line number = 1 +It costs 0.021s +``` + + +## 3. 查询过滤条件(WHERE 子句) + +`WHERE` 子句指定了对数据行的筛选条件,由一个 `whereCondition` 组成。 + +`whereCondition` 是一个逻辑表达式,对于要选择的每一行,其计算结果为真。如果没有 `WHERE` 子句,将选择所有行。 +在 `whereCondition` 中,可以使用除聚合函数之外的任何 IOTDB 支持的函数和运算符。 + +根据过滤条件的不同,可以分为时间过滤条件和值过滤条件。时间过滤条件和值过滤条件可以混合使用。 + +### 3.1 时间过滤条件 + +使用时间过滤条件可以筛选特定时间范围的数据。对于时间戳支持的格式,请参考 [时间戳类型](../Background-knowledge/Data-Type.md) 。 + +示例如下: + +1. 选择时间戳大于 2022-01-01T00:05:00.000 的数据: + + ```sql + select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; + ``` + +2. 选择时间戳等于 2022-01-01T00:05:00.000 的数据: + + ```sql + select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; + ``` + +3. 选择时间区间 [2017-11-01T00:05:00.000, 2017-11-01T00:12:00.000) 内的数据: + + ```sql + select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; + ``` + +注:在上述示例中,`time` 也可写做 `timestamp`。 + +### 3.2 值过滤条件 + +使用值过滤条件可以筛选数据值满足特定条件的数据。 +**允许**使用 select 子句中未选择的时间序列作为值过滤条件。 + +示例如下: + +1. 选择值大于 36.5 的数据: + + ```sql + select temperature from root.sg1.d1 where temperature > 36.5; + ``` + +2. 选择值等于 true 的数据: + + ```sql + select status from root.sg1.d1 where status = true; + +3. 选择区间 [36.5,40] 内或之外的数据: + + ```sql + select temperature from root.sg1.d1 where temperature between 36.5 and 40; + ```` + ```sql + select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + ```` + +4. 选择值在特定范围内的数据: + + ```sql + select code from root.sg1.d1 where code in ('200', '300', '400', '500'); + ``` + +5. 选择值在特定范围外的数据: + + ```sql + select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); + ``` + +6. 选择值为空的数据: + + ```sql + select code from root.sg1.d1 where temperature is null; + ```` + +7. 选择值为非空的数据: + + ```sql + select code from root.sg1.d1 where temperature is not null; + ```` + +### 3.3 模糊查询 + +对于 TEXT 类型的数据,支持使用 `Like` 和 `Regexp` 运算符对数据进行模糊匹配 + +#### 使用 `Like` 进行模糊匹配 + +**匹配规则:** + +- `%` 表示任意0个或多个字符。 +- `_` 表示任意单个字符。 + +**示例 1:** 查询 `root.sg.d1` 下 `value` 含有`'cc'`的数据。 + +``` +IoTDB> select * from root.sg.d1 where value like '%cc%' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 2:** 查询 `root.sg.d1` 下 `value` 中间为 `'b'`、前后为任意单个字符的数据。 + +``` +IoTDB> select * from root.sg.device where value like '_b_' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:02.000+08:00| abc| ++-----------------------------+----------------+ +Total line number = 1 +It costs 0.002s +``` + +#### 使用 `Regexp` 进行模糊匹配 + +需要传入的过滤条件为 **Java 标准库风格的正则表达式**。 + +**常见的正则匹配举例:** + +``` +长度为3-20的所有字符:^.{3,20}$ +大写英文字符:^[A-Z]+$ +数字和英文字符:^[A-Za-z0-9]+$ +以a开头的:^a.* +``` + +**示例 1:** 查询 root.sg.d1 下 value 值为26个英文字符组成的字符串。 + +```shell +IoTDB> select * from root.sg.d1 where value regexp '^[A-Za-z]+$' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 2:** 查询 root.sg.d1 下 value 值为26个小写英文字符组成的字符串且时间大于100的。 + +```shell +IoTDB> select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +## 4. 分段分组聚合(GROUP BY 子句) +IoTDB支持通过`GROUP BY`子句对序列进行分段或者分组聚合。 + +分段聚合是指按照时间维度,针对同时间序列中不同数据点之间的时间关系,对数据在行的方向进行分段,每个段得到一个聚合值。目前支持**时间区间分段**、**差值分段**、**条件分段**、**会话分段**和**点数分段**,未来将支持更多分段方式。 + +分组聚合是指针对不同时间序列,在时间序列的潜在业务属性上分组,每个组包含若干条时间序列,每个组得到一个聚合值。支持**按路径层级分组**和**按序列标签分组**两种分组方式。 + +### 4.1 分段聚合 + +#### 时间区间分段聚合 + +时间区间分段聚合是一种时序数据典型的查询方式,数据以高频进行采集,需要按照一定的时间间隔进行聚合计算,如计算每天的平均气温,需要将气温的序列按天进行分段,然后计算平均值。 + +在 IoTDB 中,聚合查询可以通过 `GROUP BY` 子句指定按照时间区间分段聚合。用户可以指定聚合的时间间隔和滑动步长,相关参数如下: + +* 参数 1:时间轴显示时间窗口大小 +* 参数 2:聚合窗口的大小(必须为正数) +* 参数 3:聚合窗口的滑动步长(可选,默认与聚合窗口大小相同) + +下图中指出了这三个参数的含义: + + + +接下来,我们给出几个典型例子: + +##### 未指定滑动步长的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` +这条查询的含义是: + +由于用户没有指定滑动步长,滑动步长将会被默认设置为跟时间间隔参数相同,也就是`1d`。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1d`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[0,1d), [1d, 2d), [2d, 3d) 等等。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 1440| 26.0| +|2017-11-02T00:00:00.000+08:00| 1440| 26.0| +|2017-11-03T00:00:00.000+08:00| 1440| 25.99| +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.024s +``` + +##### 指定滑动步长的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`1d`,GROUP BY 语句执行时将会每次把时间间隔往后移动一天的步长,而不是默认的 3 小时。 + +也就意味着,我们想要取从 2017-11-01 到 2017-11-07 每一天的凌晨 0 点到凌晨 3 点的数据。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`3h`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00), [2017-11-03T00:00:00, 2017-11-03T03:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天的凌晨 0 点到凌晨 3 点) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-02T00:00:00.000+08:00| 180| 25.98| +|2017-11-03T00:00:00.000+08:00| 180| 25.96| +|2017-11-04T00:00:00.000+08:00| 180| 25.96| +|2017-11-05T00:00:00.000+08:00| 180| 26.0| +|2017-11-06T00:00:00.000+08:00| 180| 25.85| +|2017-11-07T00:00:00.000+08:00| 180| 25.99| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.006s +``` + +滑动步长可以小于聚合窗口,此时聚合窗口之间有重叠时间(类似于一个滑动窗口)。 + +例如 SQL: +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-01 10:00:00), 4h, 2h); +``` + +SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-01T02:00:00.000+08:00| 180| 25.98| +|2017-11-01T04:00:00.000+08:00| 180| 25.96| +|2017-11-01T06:00:00.000+08:00| 180| 25.96| +|2017-11-01T08:00:00.000+08:00| 180| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 5 +It costs 0.006s +``` + +##### 按照自然月份的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 where time > 2017-11-01T01:00:00 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`2mo`,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。 + +也就意味着,我们想要取从 2017-11-01 到 2019-11-07 每 2 个自然月的第一个月的数据。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2019-11-07T23:00:00)。 + +起始时间为 2017-11-01T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 1 号作为时间间隔的起始时间。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1mo`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-12-01T00:00:00), [2018-02-01T00:00:00, 2018-03-01T00:00:00), [2018-05-03T00:00:00, 2018-06-01T00:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-01T00:00:00.000+08:00| 259| +|2018-01-01T00:00:00.000+08:00| 250| +|2018-03-01T00:00:00.000+08:00| 259| +|2018-05-01T00:00:00.000+08:00| 251| +|2018-07-01T00:00:00.000+08:00| 242| +|2018-09-01T00:00:00.000+08:00| 225| +|2018-11-01T00:00:00.000+08:00| 216| +|2019-01-01T00:00:00.000+08:00| 207| +|2019-03-01T00:00:00.000+08:00| 216| +|2019-05-01T00:00:00.000+08:00| 207| +|2019-07-01T00:00:00.000+08:00| 199| +|2019-09-01T00:00:00.000+08:00| 181| +|2019-11-01T00:00:00.000+08:00| 60| ++-----------------------------+-------------------------------+ +``` + +对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`2mo`,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。 + +也就意味着,我们想要取从 2017-10-31 到 2019-11-07 每 2 个自然月的第一个月的数据。 + +与上述示例不同的是起始时间为 2017-10-31T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 31 号(即最后一天)作为时间间隔的起始时间。若起始时间设置为 30 号,滑动步长会将时间间隔的起始时间设置为当月 30 号,若不存在则为最后一天。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-10-31T00:00:00, 2019-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1mo`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-10-31T00:00:00, 2017-11-31T00:00:00), [2018-02-31T00:00:00, 2018-03-31T00:00:00), [2018-05-31T00:00:00, 2018-06-31T00:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-10-31T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-10-31T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-10-31T00:00:00.000+08:00| 251| +|2017-12-31T00:00:00.000+08:00| 250| +|2018-02-28T00:00:00.000+08:00| 259| +|2018-04-30T00:00:00.000+08:00| 250| +|2018-06-30T00:00:00.000+08:00| 242| +|2018-08-31T00:00:00.000+08:00| 225| +|2018-10-31T00:00:00.000+08:00| 216| +|2018-12-31T00:00:00.000+08:00| 208| +|2019-02-28T00:00:00.000+08:00| 216| +|2019-04-30T00:00:00.000+08:00| 208| +|2019-06-30T00:00:00.000+08:00| 199| +|2019-08-31T00:00:00.000+08:00| 181| +|2019-10-31T00:00:00.000+08:00| 69| ++-----------------------------+-------------------------------+ +``` + +##### 左开右闭区间 + +每个区间的结果时间戳为区间右端点,对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +这条查询语句的时间区间是左开右闭的,结果中不会包含时间点 2017-11-01 的数据,但是会包含时间点 2017-11-07 的数据。 + +SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### 差值分段聚合 +IoTDB支持通过`GROUP BY VARIATION`语句来根据差值进行分组。`GROUP BY VARIATION`会将第一个点作为一个组的**基准点**,每个新的数据在按照给定规则与基准点进行差值运算后, +如果差值小于给定的阈值则将该新点归于同一组,否则结束当前分组,以这个新的数据为新的基准点开启新的分组。 +该分组方式不会重叠,且没有固定的开始结束时间。其子句语法如下: +```sql +group by variation(controlExpression[,delta][,ignoreNull=true/false]) +``` +不同的参数含义如下 +* controlExpression + +分组所参照的值,**可以是查询数据中的某一列或是多列的表达式 +(多列表达式计算后仍为一个值,使用多列表达式时指定的列必须都为数值列)**, 差值便是根据数据的controlExpression的差值运算。 +* delta + +分组所使用的阈值,同一分组中**每个点的controlExpression对应的值与该组中基准点对应值的差值都小于`delta`**。当`delta=0`时,相当于一个等值分组,所有连续且expression值相同的数据将被分到一组。 + +* ignoreNull + +用于指定`controlExpression`的值为null时对数据的处理方式,当`ignoreNull`为false时,该null值会被视为新的值,`ignoreNull`为true时,则直接跳过对应的点。 + +在`delta`取不同值时,`controlExpression`支持的返回数据类型以及当`ignoreNull`为false时对于null值的处理方式可以见下表: + +| delta | controlExpression支持的返回类型 | ignoreNull=false时对于Null值的处理 | +|----------|--------------------------------------|-----------------------------------------------------------------| +| delta!=0 | INT32、INT64、FLOAT、DOUBLE | 若正在维护分组的值不为null,null视为无穷大/无穷小,结束当前分组。连续的null视为差值相等的值,会被分配在同一个分组 | +| delta=0 | TEXT、BINARY、INT32、INT64、FLOAT、DOUBLE | null被视为新分组中的新值,连续的null属于相同的分组 | + +下图为差值分段的一个分段方式示意图,与组中第一个数据的控制列值的差值在delta内的控制列对应的点属于相同的分组。 + +groupByVariation + +##### 使用注意事项 +1. `controlExpression`的结果应该为唯一值,如果使用通配符拼接后出现多列,则报错。 +2. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +3. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +4. 当没有指定`delta`和`ignoreNull`时,`delta`默认为0,`ignoreNull`默认为true。 +5. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + +使用如下的原始数据,接下来会给出几个事件分段查询的使用样例 +``` ++-----------------------------+-------+-------+-------+--------+-------+-------+ +| Time| s1| s2| s3| s4| s5| s6| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +|1970-01-01T08:00:00.000+08:00| 4.5| 9.0| 0.0| 45.0| 9.0| 8.25| +|1970-01-01T08:00:00.010+08:00| null| 19.0| 10.0| 145.0| 19.0| 8.25| +|1970-01-01T08:00:00.020+08:00| 24.5| 29.0| null| 245.0| 29.0| null| +|1970-01-01T08:00:00.030+08:00| 34.5| null| 30.0| 345.0| null| null| +|1970-01-01T08:00:00.040+08:00| 44.5| 49.0| 40.0| 445.0| 49.0| 8.25| +|1970-01-01T08:00:00.050+08:00| null| 59.0| 50.0| 545.0| 59.0| 6.25| +|1970-01-01T08:00:00.060+08:00| 64.5| 69.0| 60.0| 645.0| 69.0| null| +|1970-01-01T08:00:00.070+08:00| 74.5| 79.0| null| null| 79.0| 3.25| +|1970-01-01T08:00:00.080+08:00| 84.5| 89.0| 80.0| 845.0| 89.0| 3.25| +|1970-01-01T08:00:00.090+08:00| 94.5| 99.0| 90.0| 945.0| 99.0| 3.25| +|1970-01-01T08:00:00.150+08:00| 66.5| 77.0| 90.0| 945.0| 99.0| 9.25| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +``` +##### delta=0时的等值事件分段 +使用如下sql语句 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +``` +得到如下的查询结果,这里忽略了s6为null的行 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.040+08:00| 24.5| 3| 50.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +当指定ignoreNull为false时,会将s6为null的数据也考虑进来 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +``` +得到如下的结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.020+08:00|1970-01-01T08:00:00.030+08:00| 29.5| 1| 30.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.040+08:00| 44.5| 1| 40.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.060+08:00|1970-01-01T08:00:00.060+08:00| 64.5| 1| 60.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +##### delta!=0时的差值事件分段 +使用如下sql语句 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +``` +得到如下的查询结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.050+08:00| 24.5| 4| 100.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +group by子句中的controlExpression同样支持列的表达式 + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` +得到如下的查询结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.050+08:00| 44.5| 2| 90.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.080+08:00| 79.5| 2| 80.0| +|1970-01-01T08:00:00.090+08:00|1970-01-01T08:00:00.150+08:00| 80.5| 2| 180.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +#### 条件分段聚合 +当需要根据指定条件对数据进行筛选,并将连续的符合条件的行分为一组进行聚合运算时,可以使用`GROUP BY CONDITION`的分段方式;不满足给定条件的行因为不属于任何分组会被直接简单忽略。 +其语法定义如下: +```sql +group by condition(predict,[keep>/>=/=/<=/<]threshold,[,ignoreNull=true/false]) +``` +* predict + +返回boolean数据类型的合法表达式,用于分组的筛选。 +* keep[>/>=/=/<=/<]threshold + +keep表达式用来指定形成分组所需要连续满足`predict`条件的数据行数,只有行数满足keep表达式的分组才会被输出。keep表达式由一个'keep'字符串和`long`类型的threshold组合或者是单独的`long`类型数据构成。 + +* ignoreNull=true/false + +用于指定遇到predict为null的数据行时的处理方式,为true则跳过该行,为false则结束当前分组。 + +##### 使用注意事项 +1. keep条件在查询中是必需的,但可以省略掉keep字符串给出一个`long`类型常数,默认为`keep=该long型常数`的等于条件。 +2. `ignoreNull`默认为true。 +3. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +4. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +5. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + + +对于如下原始数据,下面会给出几个查询样例: +``` ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +| Time|root.sg.beijing.car01.soc|root.sg.beijing.car01.charging_status|root.sg.beijing.car01.vehicle_status| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| 1| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| 1| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +``` +查询至少连续两行以上的charging_status=1的数据,sql语句如下: +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoreNull=true) +``` +得到结果如下: +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 10| 5| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` +当设置`ignoreNull`为false时,遇到null值为将其视为一个不满足条件的行,会结束正在计算的分组。 +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoreNull=false) +``` +得到如下结果,原先的分组被含null的行拆分: +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 7| 3| 36.0| +|1970-01-01T08:00:00.009+08:00| 10| 2| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` +#### 会话分段聚合 +`GROUP BY SESSION`可以根据时间列的间隔进行分组,在结果集的时间列中,时间间隔小于等于设定阈值的数据会被分为一组。例如在工业场景中,设备并不总是连续运行,`GROUP BY SESSION`会将设备每次接入会话所产生的数据分为一组。 +其语法定义如下: +```sql +group by session(timeInterval) +``` +* timeInterval + +设定的时间差阈值,当两条数据时间列的差值大于该阈值,则会给数据创建一个新的分组。 + +下图为`group by session`下的一个分组示意图 + + + +##### 使用注意事项 +1. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +2. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +3. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + +对于下面的原始数据,给出几个查询样例。 +``` ++-----------------------------+-----------------+-----------+--------+------+ +| Time| Device|temperature|hardware|status| ++-----------------------------+-----------------+-----------+--------+------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01| 35.7| 11| false| +|1970-01-01T08:00:02.000+08:00|root.ln.wf02.wt01| 35.8| 22| true| +|1970-01-01T08:00:03.000+08:00|root.ln.wf02.wt01| 35.4| 33| false| +|1970-01-01T08:00:04.000+08:00|root.ln.wf02.wt01| 36.4| 44| false| +|1970-01-01T08:00:05.000+08:00|root.ln.wf02.wt01| 36.8| 55| false| +|1970-01-01T08:00:10.000+08:00|root.ln.wf02.wt01| 36.8| 110| false| +|1970-01-01T08:00:20.000+08:00|root.ln.wf02.wt01| 37.8| 220| true| +|1970-01-01T08:00:30.000+08:00|root.ln.wf02.wt01| 37.5| 330| false| +|1970-01-01T08:00:40.000+08:00|root.ln.wf02.wt01| 37.4| 440| false| +|1970-01-01T08:00:50.000+08:00|root.ln.wf02.wt01| 37.9| 550| false| +|1970-01-01T08:01:40.000+08:00|root.ln.wf02.wt01| 38.0| 110| false| +|1970-01-01T08:02:30.000+08:00|root.ln.wf02.wt01| 38.8| 220| true| +|1970-01-01T08:03:20.000+08:00|root.ln.wf02.wt01| 38.6| 330| false| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01| 38.4| 440| false| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01| 38.3| 550| false| +|1970-01-01T08:06:40.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:07:50.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:08:00.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01| 38.2| 110| false| +|1970-01-02T08:08:02.000+08:00|root.ln.wf02.wt01| 37.5| 220| true| +|1970-01-02T08:08:03.000+08:00|root.ln.wf02.wt01| 37.4| 330| false| +|1970-01-02T08:08:04.000+08:00|root.ln.wf02.wt01| 36.8| 440| false| +|1970-01-02T08:08:05.000+08:00|root.ln.wf02.wt01| 37.4| 550| false| ++-----------------------------+-----------------+-----------+--------+------+ +``` +可以按照不同的时间单位设定时间间隔,sql语句如下: +```sql +select __endTime,count(*) from root.** group by session(1d) +``` +得到如下结果: +``` ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time| __endTime|count(root.ln.wf02.wt01.temperature)|count(root.ln.wf02.wt01.hardware)|count(root.ln.wf02.wt01.status)| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|1970-01-01T08:00:01.000+08:00|1970-01-01T08:08:00.000+08:00| 15| 18| 15| +|1970-01-02T08:08:01.000+08:00|1970-01-02T08:08:05.000+08:00| 5| 5| 5| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` +也可以和`HAVING`、`ALIGN BY DEVICE`共同使用 +```sql +select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` +得到如下结果,其中排除了`sum(hardware)`为0的部分 +``` ++-----------------------------+-----------------+-----------------------------+-------------+ +| Time| Device| __endTime|sum(hardware)| ++-----------------------------+-----------------+-----------------------------+-------------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01|1970-01-01T08:03:20.000+08:00| 2475.0| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:04:20.000+08:00| 440.0| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:05:20.000+08:00| 550.0| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01|1970-01-02T08:08:05.000+08:00| 1650.0| ++-----------------------------+-----------------+-----------------------------+-------------+ +``` +#### 点数分段聚合 +`GROUP BY COUNT`可以根据点数分组进行聚合运算,将连续的指定数量数据点分为一组,即按照固定的点数进行分组。 +其语法定义如下: +```sql +group by count(controlExpression, size[,ignoreNull=true/false]) +``` +* controlExpression + +计数参照的对象,可以是结果集的任意列或是列的表达式 + +* size + +一个组中数据点的数量,每`size`个数据点会被分到同一个组 + +* ignoreNull=true/false + +是否忽略`controlExpression`为null的数据点,当ignoreNull为true时,在计数时会跳过`controlExpression`结果为null的数据点 + +##### 使用注意事项 +1. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +2. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +3. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 +4. 当一个分组内最终的点数不满足`size`的数量时,不会输出该分组的结果 + +对于下面的原始数据,给出几个查询样例。 +``` ++-----------------------------+-----------+-----------------------+ +| Time|root.sg.soc|root.sg.charging_status| ++-----------------------------+-----------+-----------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| ++-----------------------------+-----------+-----------------------+ +``` +sql语句如下 +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +``` +得到如下结果,其中由于第二个1970-01-01T08:00:00.006+08:00到1970-01-01T08:00:00.010+08:00的窗口中包含四个点,不符合`size = 5`的条件,因此不被输出 +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` +而当使用ignoreNull将null值也考虑进来时,可以得到两个点计数为5的窗口,sql如下 +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` +得到如下结果 +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| +|1970-01-01T08:00:00.006+08:00|1970-01-01T08:00:00.010+08:00| 24.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` +### 4.2 分组聚合 + +#### 路径层级分组聚合 + +在时间序列层级结构中,路径层级分组聚合查询用于**对某一层级下同名的序列进行聚合查询**。 + +- 使用 `GROUP BY LEVEL = INT` 来指定需要聚合的层级,并约定 `ROOT` 为第 0 层。若统计 "root.ln" 下所有序列则需指定 level 为 1。 +- 路径层次分组聚合查询支持使用所有内置聚合函数。对于 `sum`,`avg`,`min_value`, `max_value`, `extreme` 五种聚合函数,需保证所有聚合的时间序列数据类型相同。其他聚合函数没有此限制。 + +**示例1:** 不同 database 下均存在名为 status 的序列, 如 "root.ln.wf01.wt01.status", "root.ln.wf02.wt02.status", 以及 "root.sgcc.wf03.wt01.status", 如果需要统计不同 database 下 status 序列的数据点个数,使用以下查询: + +```sql +select count(status) from root.** group by level = 1 +``` + +运行结果为: + +``` ++-------------------------+---------------------------+ +|count(root.ln.*.*.status)|count(root.sgcc.*.*.status)| ++-------------------------+---------------------------+ +| 20160| 10080| ++-------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**示例2:** 统计不同设备下 status 序列的数据点个数,可以规定 level = 3, + +```sql +select count(status) from root.** group by level = 3 +``` + +运行结果为: + +``` ++---------------------------+---------------------------+ +|count(root.*.*.wt01.status)|count(root.*.*.wt02.status)| ++---------------------------+---------------------------+ +| 20160| 10080| ++---------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +注意,这时会将 database `ln` 和 `sgcc` 下名为 `wt01` 的设备视为同名设备聚合在一起。 + +**示例3:** 统计不同 database 下的不同设备中 status 序列的数据点个数,可以使用以下查询: + +```sql +select count(status) from root.** group by level = 1, 3 +``` + +运行结果为: + +``` ++----------------------------+----------------------------+------------------------------+ +|count(root.ln.*.wt01.status)|count(root.ln.*.wt02.status)|count(root.sgcc.*.wt01.status)| ++----------------------------+----------------------------+------------------------------+ +| 10080| 10080| 10080| ++----------------------------+----------------------------+------------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**示例4:** 查询所有序列下温度传感器 temperature 的最大值,可以使用下列查询语句: + +```sql +select max_value(temperature) from root.** group by level = 0 +``` + +运行结果: + +``` ++---------------------------------+ +|max_value(root.*.*.*.temperature)| ++---------------------------------+ +| 26.0| ++---------------------------------+ +Total line number = 1 +It costs 0.013s +``` + +**示例5:** 上面的查询都是针对某一个传感器,特别地,**如果想要查询某一层级下所有传感器拥有的总数据点数,则需要显式规定测点为 `*`** + +```sql +select count(*) from root.ln.** group by level = 2 +``` + +运行结果: + +``` ++----------------------+----------------------+ +|count(root.*.wf01.*.*)|count(root.*.wf02.*.*)| ++----------------------+----------------------+ +| 20160| 20160| ++----------------------+----------------------+ +Total line number = 1 +It costs 0.013s +``` + +##### 与时间区间分段聚合混合使用 + +通过定义 LEVEL 来统计指定层级下的数据点个数。 + +例如: + +统计降采样后的数据点个数 + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +``` + +结果: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.006s +``` + +加上滑动 Step 的降采样后的结果也可以汇总 + +```sql +select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| +|2017-11-02T00:00:00.000+08:00| 180| +|2017-11-03T00:00:00.000+08:00| 180| +|2017-11-04T00:00:00.000+08:00| 180| +|2017-11-05T00:00:00.000+08:00| 180| +|2017-11-06T00:00:00.000+08:00| 180| +|2017-11-07T00:00:00.000+08:00| 180| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### 标签分组聚合 + +IoTDB 支持通过 `GROUP BY TAGS` 语句根据时间序列中定义的标签的键值做分组聚合查询。 + +我们先在 IoTDB 中写入如下示例数据,稍后会以这些数据为例介绍标签聚合查询。 + +这些是某工厂 `factory1` 在多个城市的多个车间的设备温度数据, 时间范围为 [1000, 10000)。 + +时间序列路径中的设备一级是设备唯一标识。城市信息 `city` 和车间信息 `workshop` 则被建模在该设备时间序列的标签中。 +其中,设备 `d1`、`d2` 在 `Beijing` 的 `w1` 车间, `d3`、`d4` 在 `Beijing` 的 `w2` 车间,`d5`、`d6` 在 `Shanghai` 的 `w1` 车间,`d7` 在 `Shanghai` 的 `w2` 车间。 +`d8` 和 `d9` 设备目前处于调试阶段,还未被分配到具体的城市和车间,所以其相应的标签值为空值。 + +```SQL +create database root.factory1; +create timeseries root.factory1.d1.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d2.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d3.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d4.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d5.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d6.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d7.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w2); +create timeseries root.factory1.d8.temperature with datatype=FLOAT; +create timeseries root.factory1.d9.temperature with datatype=FLOAT; + +insert into root.factory1.d1(time, temperature) values(1000, 104.0); +insert into root.factory1.d1(time, temperature) values(3000, 104.2); +insert into root.factory1.d1(time, temperature) values(5000, 103.3); +insert into root.factory1.d1(time, temperature) values(7000, 104.1); + +insert into root.factory1.d2(time, temperature) values(1000, 104.4); +insert into root.factory1.d2(time, temperature) values(3000, 103.7); +insert into root.factory1.d2(time, temperature) values(5000, 103.3); +insert into root.factory1.d2(time, temperature) values(7000, 102.9); + +insert into root.factory1.d3(time, temperature) values(1000, 103.9); +insert into root.factory1.d3(time, temperature) values(3000, 103.8); +insert into root.factory1.d3(time, temperature) values(5000, 102.7); +insert into root.factory1.d3(time, temperature) values(7000, 106.9); + +insert into root.factory1.d4(time, temperature) values(1000, 103.9); +insert into root.factory1.d4(time, temperature) values(5000, 102.7); +insert into root.factory1.d4(time, temperature) values(7000, 106.9); + +insert into root.factory1.d5(time, temperature) values(1000, 112.9); +insert into root.factory1.d5(time, temperature) values(7000, 113.0); + +insert into root.factory1.d6(time, temperature) values(1000, 113.9); +insert into root.factory1.d6(time, temperature) values(3000, 113.3); +insert into root.factory1.d6(time, temperature) values(5000, 112.7); +insert into root.factory1.d6(time, temperature) values(7000, 112.3); + +insert into root.factory1.d7(time, temperature) values(1000, 101.2); +insert into root.factory1.d7(time, temperature) values(3000, 99.3); +insert into root.factory1.d7(time, temperature) values(5000, 100.1); +insert into root.factory1.d7(time, temperature) values(7000, 99.8); + +insert into root.factory1.d8(time, temperature) values(1000, 50.0); +insert into root.factory1.d8(time, temperature) values(3000, 52.1); +insert into root.factory1.d8(time, temperature) values(5000, 50.1); +insert into root.factory1.d8(time, temperature) values(7000, 50.5); + +insert into root.factory1.d9(time, temperature) values(1000, 50.3); +insert into root.factory1.d9(time, temperature) values(3000, 52.1); +``` + +##### 单标签聚合查询 + +用户想统计该工厂每个地区的设备的温度的平均值,可以使用如下查询语句 + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +该查询会将具有同一个 `city` 标签值的时间序列的所有满足查询条件的点做平均值计算,计算结果如下 + +``` ++--------+------------------+ +| city| avg(temperature)| ++--------+------------------+ +| Beijing|104.04666697184244| +|Shanghai|107.85000076293946| +| NULL| 50.84999910990397| ++--------+------------------+ +Total line number = 3 +It costs 0.231s +``` + +从结果集中可以看到,和分段聚合、按层次分组聚合相比,标签聚合的查询结果的不同点是: +1. 标签聚合查询的聚合结果不会再做去星号展开,而是将多个时间序列的数据作为一个整体进行聚合计算。 +2. 标签聚合查询除了输出聚合结果列,还会输出聚合标签的键值列。该列的列名为聚合指定的标签键,列的值则为所有查询的时间序列中出现的该标签的值。 +如果某些时间序列未设置该标签,则在键值列中有一行单独的 `NULL` ,代表未设置标签的所有时间序列数据的聚合结果。 + +##### 多标签分组聚合查询 + +除了基本的单标签聚合查询外,还可以按顺序指定多个标签进行聚合计算。 + +例如,用户想统计每个城市的每个车间内设备的平均温度。但因为各个城市的车间名称有可能相同,所以不能直接按照 `workshop` 做标签聚合。必须要先按照城市,再按照车间处理。 + +SQL 语句如下 + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +查询结果如下 + +``` ++--------+--------+------------------+ +| city|workshop| avg(temperature)| ++--------+--------+------------------+ +| NULL| NULL| 50.84999910990397| +|Shanghai| w1|113.01666768391927| +| Beijing| w2| 104.4000004359654| +|Shanghai| w2|100.10000038146973| +| Beijing| w1|103.73750019073486| ++--------+--------+------------------+ +Total line number = 5 +It costs 0.027s +``` + +从结果集中可以看到,和单标签聚合相比,多标签聚合的查询结果会根据指定的标签顺序,输出相应标签的键值列。 + +##### 基于时间区间的标签聚合查询 + +按照时间区间聚合是时序数据库中最常用的查询需求之一。IoTDB 在基于时间区间的聚合基础上,支持进一步按照标签进行聚合查询。 + +例如,用户想统计时间 `[1000, 10000)` 范围内,每个城市每个车间中的设备每 5 秒内的平均温度。 + +SQL 语句如下 + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +查询结果如下 + +``` ++-----------------------------+--------+--------+------------------+ +| Time| city|workshop| avg(temperature)| ++-----------------------------+--------+--------+------------------+ +|1970-01-01T08:00:01.000+08:00| NULL| NULL| 50.91999893188476| +|1970-01-01T08:00:01.000+08:00|Shanghai| w1|113.20000076293945| +|1970-01-01T08:00:01.000+08:00| Beijing| w2| 103.4| +|1970-01-01T08:00:01.000+08:00|Shanghai| w2| 100.1999994913737| +|1970-01-01T08:00:01.000+08:00| Beijing| w1|103.81666692097981| +|1970-01-01T08:00:06.000+08:00| NULL| NULL| 50.5| +|1970-01-01T08:00:06.000+08:00|Shanghai| w1| 112.6500015258789| +|1970-01-01T08:00:06.000+08:00| Beijing| w2| 106.9000015258789| +|1970-01-01T08:00:06.000+08:00|Shanghai| w2| 99.80000305175781| +|1970-01-01T08:00:06.000+08:00| Beijing| w1| 103.5| ++-----------------------------+--------+--------+------------------+ +``` + +和标签聚合相比,基于时间区间的标签聚合的查询会首先按照时间区间划定聚合范围,在时间区间内部再根据指定的标签顺序,进行相应数据的聚合计算。在输出的结果集中,会包含一列时间列,该时间列值的含义和时间区间聚合查询的相同。 + +##### 标签分组聚合的限制 + +由于标签聚合功能仍然处于开发阶段,目前有如下未实现功能。 + +> 1. 暂不支持 `HAVING` 子句过滤查询结果。 +> 2. 暂不支持结果按照标签值排序。 +> 3. 暂不支持 `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`。 +> 4. 暂不支持 `ALIGN BY DEVICE`。 +> 5. 暂不支持聚合函数内部包含表达式,例如 `count(s+1)`。 +> 6. 不支持值过滤条件聚合,和分层聚合查询行为保持一致。 + +## 5. 聚合结果过滤(HAVING 子句) + +如果想对聚合查询的结果进行过滤,可以在 `GROUP BY` 子句之后使用 `HAVING` 子句。 + +**注意:** + +1. `HAVING`子句中的过滤条件必须由聚合值构成,原始序列不能单独出现。 + + 下列使用方式是不正确的: + ```sql + select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 + select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 + ``` + +2. 对`GROUP BY LEVEL`结果进行过滤时,`SELECT`和`HAVING`中出现的PATH只能有一级。 + + 下列使用方式是不正确的: + ```sql + select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 + select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 + ``` + +**SQL 示例:** + +- **示例 1:** + + 对于以下聚合结果进行过滤: + + ``` + +-----------------------------+---------------------+---------------------+ + | Time|count(root.test.*.s1)|count(root.test.*.s2)| + +-----------------------------+---------------------+---------------------+ + |1970-01-01T08:00:00.001+08:00| 4| 4| + |1970-01-01T08:00:00.003+08:00| 1| 0| + |1970-01-01T08:00:00.005+08:00| 2| 4| + |1970-01-01T08:00:00.007+08:00| 3| 2| + |1970-01-01T08:00:00.009+08:00| 4| 4| + +-----------------------------+---------------------+---------------------+ + ``` + + ```sql + select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 2; + ``` + + 执行结果如下: + + ``` + +-----------------------------+---------------------+ + | Time|count(root.test.*.s1)| + +-----------------------------+---------------------+ + |1970-01-01T08:00:00.001+08:00| 4| + |1970-01-01T08:00:00.005+08:00| 2| + |1970-01-01T08:00:00.009+08:00| 4| + +-----------------------------+---------------------+ + ``` + +- **示例 2:** + + 对于以下聚合结果进行过滤: + ``` + +-----------------------------+-------------+---------+---------+ + | Time| Device|count(s1)|count(s2)| + +-----------------------------+-------------+---------+---------+ + |1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.003+08:00|root.test.sg1| 1| 0| + |1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.007+08:00|root.test.sg1| 2| 1| + |1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| + |1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| + |1970-01-01T08:00:00.003+08:00|root.test.sg2| 0| 0| + |1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| + |1970-01-01T08:00:00.007+08:00|root.test.sg2| 1| 1| + |1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| + +-----------------------------+-------------+---------+---------+ + ``` + + ```sql + select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device; + ``` + + 执行结果如下: + + ``` + +-----------------------------+-------------+---------+---------+ + | Time| Device|count(s1)|count(s2)| + +-----------------------------+-------------+---------+---------+ + |1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| + |1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| + |1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| + |1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| + +-----------------------------+-------------+---------+---------+ + ``` + + +## 6. 结果集补空值(FILL 子句) + +### 6.1 功能介绍 + +当执行一些数据查询时,结果集的某行某列可能没有数据,则此位置结果为空,但这种空值不利于进行数据可视化展示和分析,需要对空值进行填充。 + +在 IoTDB 中,用户可以使用 `FILL` 子句指定数据缺失情况下的填充模式,允许用户按照特定的方法对任何查询的结果集填充空值,如取前一个不为空的值、线性插值等。 + +### 6.2 语法定义 + +**`FILL` 子句的语法定义如下:** + +```sql +FILL '(' PREVIOUS | LINEAR | constant ')' +``` + +**注意:** +- 在 `Fill` 语句中只能指定一种填充方法,该方法作用于结果集的全部列。 +- 空值填充不兼容 0.13 版本及以前的语法(即不支持 `FILL(([(, , )?])+)`) + +### 6.3 填充方式 + +**IoTDB 目前支持以下三种空值填充方式:** + +- `PREVIOUS` 填充:使用该列前一个非空值进行填充。 +- `LINEAR` 填充:使用该列前一个非空值和下一个非空值的线性插值进行填充。 +- 常量填充:使用指定常量填充。 + +**各数据类型支持的填充方法如下表所示:** + +| 数据类型 | 支持的填充方法 | +| :------- |:------------------------| +| BOOLEAN | `PREVIOUS`、常量 | +| INT32 | `PREVIOUS`、`LINEAR`、常量 | +| INT64 | `PREVIOUS`、`LINEAR`、常量 | +| FLOAT | `PREVIOUS`、`LINEAR`、常量 | +| DOUBLE | `PREVIOUS`、`LINEAR`、常量 | +| TEXT | `PREVIOUS`、常量 | + +**注意:** 对于数据类型不支持指定填充方法的列,既不会填充它,也不会报错,只是让那一列保持原样。 + +**下面通过举例进一步说明。** + +如果我们不使用任何填充方式: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000; +``` + +查询结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### `PREVIOUS` 填充 + +**对于查询结果集中的空值,使用该列前一个非空值进行填充。** + +**注意:** 如果结果集的某一列第一个值就为空,则不会填充该值,直到遇到该列第一个非空值为止。 + +例如,使用 `PREVIOUS` 填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +`PREVIOUS` 填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 21.93| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| false| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +**在前值填充时,能够支持指定一个时间间隔,如果当前null值的时间戳与前一个非null值的时间戳的间隔,超过指定的时间间隔,则不进行填充。** + +> 1. 在线性填充和常量填充的情况下,如果指定了第二个参数,会抛出异常 +> 2. 时间超时参数仅支持整数 + 例如,原始数据如下所示: + +```sql +select s1 from root.db.d1 +``` +``` ++-----------------------------+-------------+ +| Time|root.db.d1.s1| ++-----------------------------+-------------+ +|2023-11-08T16:41:50.008+08:00| 1.0| ++-----------------------------+-------------+ +|2023-11-08T16:46:50.011+08:00| 2.0| ++-----------------------------+-------------+ +|2023-11-08T16:48:50.011+08:00| 3.0| ++-----------------------------+-------------+ +``` + +根据时间分组,每1分钟求一个平均值 + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| null| ++-----------------------------+------------------+ +``` + +根据时间分组并用前值填充 + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +根据时间分组并用前值填充,并指定超过2分钟的就不填充 + +```sql +select avg(s1) +from root.db.d1 +group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS, 2m); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + + +#### `LINEAR` 填充 + +**对于查询结果集中的空值,使用该列前一个非空值和下一个非空值的线性插值进行填充。** + +**注意:** +- 如果某个值之前的所有值都为空,或者某个值之后的所有值都为空,则不会填充该值。 +- 如果某列的数据类型为boolean/text,我们既不会填充它,也不会报错,只是让那一列保持原样。 + +例如,使用 `LINEAR` 填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +`LINEAR` 填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 22.08| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### 常量填充 + +**对于查询结果集中的空值,使用指定常量填充。** + +**注意:** +- 如果某列数据类型与常量类型不兼容,既不填充该列,也不报错,将该列保持原样。对于常量兼容的数据类型,如下表所示: + + | 常量类型 | 能够填充的序列数据类型 | + |:------ |:------------------ | + | `BOOLEAN` | `BOOLEAN` `TEXT` | + | `INT64` | `INT32` `INT64` `FLOAT` `DOUBLE` `TEXT` | + | `DOUBLE` | `FLOAT` `DOUBLE` `TEXT` | + | `TEXT` | `TEXT` | +- 当常量值大于 `INT32` 所能表示的最大值时,对于 `INT32` 类型的列,既不填充该列,也不报错,将该列保持原样。 + +例如,使用 `FLOAT` 类型的常量填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +``` + +`FLOAT` 类型的常量填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 2.0| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +再比如,使用 `BOOLEAN` 类型的常量填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +`BOOLEAN` 类型的常量填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| true| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + + +## 7. 查询结果分页(LIMIT/SLIMIT 子句) + +当查询结果集数据量很大,放在一个页面不利于显示,可以使用 `LIMIT/SLIMIT` 子句和 `OFFSET/SOFFSET `子句进行分页控制。 + +- `LIMIT` 和 `SLIMIT` 子句用于控制查询结果的行数和列数。 +- `OFFSET` 和 `SOFFSET` 子句用于控制结果显示的起始位置。 + +### 7.1 按行分页 + +用户可以通过 `LIMIT` 和 `OFFSET` 子句控制查询结果的行数,`LIMIT rowLimit` 指定查询结果的行数,`OFFSET rowOffset` 指定查询结果显示的起始行位置。 + +注意: +- 当 `rowOffset` 超过结果集的大小时,返回空结果集。 +- 当 `rowLimit` 超过结果集的大小时,返回所有查询结果。 +- 当 `rowLimit` 和 `rowOffset` 不是正整数,或超过 `INT64` 允许的最大值时,系统将提示错误。 + +我们将通过以下示例演示如何使用 `LIMIT` 和 `OFFSET` 子句。 + +- **示例 1:** 基本的 `LIMIT` 子句 + +SQL 语句: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 10 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的前 10 行。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:00:00.000+08:00| true| 25.96| +|2017-11-01T00:01:00.000+08:00| true| 24.36| +|2017-11-01T00:02:00.000+08:00| false| 20.09| +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 10 +It costs 0.000s +``` + +- **示例 2:** 带 `OFFSET` 的 `LIMIT` 子句 + +SQL 语句: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的第 3 至 7 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.342s +``` + +- **示例 3:** `LIMIT` 子句与 `WHERE` 子句结合 + +SQL 语句: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2024-07-07T00:05:00.000 and time< 2024-07-12T00:12:00.000 limit 5 offset 3 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回时间“ 2024-07-07T00:05:00.000”和“ 2024-07-12T00:12:00.000”之间的状态和温度传感器值的第 3 至 7 行(第一行编号为第 0 行)。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2024-07-09T17:32:11.943+08:00| true| 24.941973| +|2024-07-09T17:32:12.944+08:00| true| 20.05108| +|2024-07-09T17:32:13.945+08:00| true| 20.541632| +|2024-07-09T17:32:14.945+08:00| null| 23.09016| +|2024-07-09T17:32:14.946+08:00| true| null| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.070s +`` + +- **示例 4:** `LIMIT` 子句与 `GROUP BY` 子句组合 + +SQL 语句: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 4 offset 3 +``` + +含义: + +SQL 语句子句要求返回查询结果的第 3 至 6 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 4 +It costs 0.016s +``` + +### 7.2 按列分页 + +用户可以通过 `SLIMIT` 和 `SOFFSET` 子句控制查询结果的列数,`SLIMIT seriesLimit` 指定查询结果的列数,`SOFFSET seriesOffset` 指定查询结果显示的起始列位置。 + +注意: +- 仅用于控制值列,对时间列和设备列无效。 +- 当 `seriesOffset` 超过结果集的大小时,返回空结果集。 +- 当 `seriesLimit` 超过结果集的大小时,返回所有查询结果。 +- 当 `seriesLimit` 和 `seriesOffset` 不是正整数,或超过 `INT64` 允许的最大值时,系统将提示错误。 + +我们将通过以下示例演示如何使用 `SLIMIT` 和 `SOFFSET` 子句。 + +- **示例 1:** 基本的 `SLIMIT` 子句 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第二列,即温度。 SQL 语句要求在"2017-11-01T00:05:00.000"和"2017-11-01T00:12:00.000"的时间点之间选择温度传感器值。 + +结果如下所示: + +``` ++-----------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.temperature| ++-----------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| 20.71| +|2017-11-01T00:07:00.000+08:00| 21.45| +|2017-11-01T00:08:00.000+08:00| 22.58| +|2017-11-01T00:09:00.000+08:00| 20.98| +|2017-11-01T00:10:00.000+08:00| 25.52| +|2017-11-01T00:11:00.000+08:00| 22.91| ++-----------------------------+-----------------------------+ +Total line number = 6 +It costs 0.000s +``` + +- **示例 2:** 带 `SOFFSET` 的 `SLIMIT` 子句 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第一列,即电源状态。 SQL 语句要求在" 2017-11-01T00:05:00.000"和"2017-11-01T00:12:00.000"的时间点之间选择状态传感器值。 + +结果如下所示: + +``` ++-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.status| ++-----------------------------+------------------------+ +|2017-11-01T00:06:00.000+08:00| false| +|2017-11-01T00:07:00.000+08:00| false| +|2017-11-01T00:08:00.000+08:00| false| +|2017-11-01T00:09:00.000+08:00| false| +|2017-11-01T00:10:00.000+08:00| true| +|2017-11-01T00:11:00.000+08:00| false| ++-----------------------------+------------------------+ +Total line number = 6 +It costs 0.003s +``` + +- **示例 3:** `SLIMIT` 子句与 `GROUP BY` 子句结合 + +SQL 语句: + +```sql +select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +含义: + +``` ++-----------------------------+-----------------------------------+ +| Time|max_value(root.ln.wf01.wt01.status)| ++-----------------------------+-----------------------------------+ +|2017-11-01T00:00:00.000+08:00| true| +|2017-11-02T00:00:00.000+08:00| true| +|2017-11-03T00:00:00.000+08:00| true| +|2017-11-04T00:00:00.000+08:00| true| +|2017-11-05T00:00:00.000+08:00| true| +|2017-11-06T00:00:00.000+08:00| true| +|2017-11-07T00:00:00.000+08:00| true| ++-----------------------------+-----------------------------------+ +Total line number = 7 +It costs 0.000s +``` + +- **示例 4:** `SLIMIT` 子句与 `LIMIT` 子句结合 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是此设备下的第 0 列至第 1 列(第一列编号为第 0 列)。 SQL 语句子句要求返回查询结果的第 100 至 109 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+-----------------------------+------------------------+ +|2017-11-01T01:40:00.000+08:00| 21.19| false| +|2017-11-01T01:41:00.000+08:00| 22.79| false| +|2017-11-01T01:42:00.000+08:00| 22.98| false| +|2017-11-01T01:43:00.000+08:00| 21.52| false| +|2017-11-01T01:44:00.000+08:00| 23.45| true| +|2017-11-01T01:45:00.000+08:00| 24.06| true| +|2017-11-01T01:46:00.000+08:00| 22.6| false| +|2017-11-01T01:47:00.000+08:00| 23.78| true| +|2017-11-01T01:48:00.000+08:00| 24.72| true| +|2017-11-01T01:49:00.000+08:00| 24.68| true| ++-----------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.009s +``` + +## 8. 结果集排序(ORDER BY 子句) + +### 8.1 时间对齐模式下的排序 +IoTDB的查询结果集默认按照时间对齐,可以使用`ORDER BY TIME`的子句指定时间戳的排列顺序。示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` +执行结果: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-01T00:01:00.000+08:00| v2| true| 24.36| true| +|2017-11-01T00:00:00.000+08:00| v2| true| 25.96| true| +|1970-01-01T08:00:00.002+08:00| v2| false| null| null| +|1970-01-01T08:00:00.001+08:00| v1| true| null| null| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +``` +### 8.2 设备对齐模式下的排序 +当使用`ALIGN BY DEVICE`查询对齐模式下的结果集时,可以使用`ORDER BY`子句对返回的结果集顺序进行规定。 + +在设备对齐模式下支持4种排序模式的子句,其中包括两种排序键,`DEVICE`和`TIME`,靠前的排序键为主排序键,每种排序键都支持`ASC`和`DESC`两种排列顺序。 +1. ``ORDER BY DEVICE``: 按照设备名的字典序进行排序,排序方式为字典序排序,在这种情况下,相同名的设备会以组的形式进行展示。 + +2. ``ORDER BY TIME``: 按照时间戳进行排序,此时不同的设备对应的数据点会按照时间戳的优先级被打乱排序。 + +3. ``ORDER BY DEVICE,TIME``: 按照设备名的字典序进行排序,设备名相同的数据点会通过时间戳进行排序。 + +4. ``ORDER BY TIME,DEVICE``: 按照时间戳进行排序,时间戳相同的数据点会通过设备名的字典序进行排序。 + +> 为了保证结果的可观性,当不使用`ORDER BY`子句,仅使用`ALIGN BY DEVICE`时,会为设备视图提供默认的排序方式。其中默认的排序视图为``ORDER BY DEVCE,TIME``,默认的排序顺序为`ASC`, +> 即结果集默认先按照设备名升序排列,在相同设备名内再按照时间戳升序排序。 + + +当主排序键为`DEVICE`时,结果集的格式与默认情况类似:先按照设备名对结果进行排列,在相同的设备名下内按照时间戳进行排序。示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +``` +执行结果: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` +主排序键为`Time`时,结果集会先按照时间戳进行排序,在时间戳相等时按照设备名排序。 +示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +``` +执行结果: +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` +当没有显式指定时,主排序键默认为`Device`,排序顺序默认为`ASC`,示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` +结果如图所示,可以看出,`ORDER BY DEVICE ASC,TIME ASC`就是默认情况下的排序方式,由于`ASC`是默认排序顺序,此处可以省略。 +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| ++-----------------------------+-----------------+--------+------+-----------+ +``` +同样,可以在聚合查询中使用`ALIGN BY DEVICE`和`ORDER BY`子句,对聚合后的结果进行排序,示例代码如下所示: +```sql +select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` +执行结果: +``` ++-----------------------------+-----------------+---------------+-------------+------------------+ +| Time| Device|count(hardware)|count(status)|count(temperature)| ++-----------------------------+-----------------+---------------+-------------+------------------+ +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| 1| 1| +|2017-11-01T00:02:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:03:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| 1| 1| null| +|2017-11-01T00:02:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| +|2017-11-01T00:03:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| ++-----------------------------+-----------------+---------------+-------------+------------------+ +``` + +### 8.3 任意表达式排序 +除了IoTDB中规定的Time,Device关键字外,还可以通过`ORDER BY`子句对指定时间序列中任意列的表达式进行排序。 + +排序在通过`ASC`,`DESC`指定排序顺序的同时,可以通过`NULLS`语法来指定NULL值在排序中的优先级,`NULLS FIRST`默认NULL值在结果集的最上方,`NULLS LAST`则保证NULL值在结果集的最后。如果没有在子句中指定,则默认顺序为`ASC`,`NULLS LAST`。 + +对于如下的数据,将给出几个任意表达式的查询示例供参考: +``` ++-----------------------------+-------------+-------+-------+--------+-------+ +| Time| Device| base| score| bonus| total| ++-----------------------------+-------------+-------+-------+--------+-------+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0| 107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0| 105.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0| 103.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00| root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.020+08:00| root.three| 8| null| 22.5| 30.5| +|1970-01-01T08:00:00.030+08:00| root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0| 104.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0| 102.0| ++-----------------------------+-------------+-------+-------+--------+-------+ +``` + +当需要根据基础分数score对结果进行排序时,可以直接使用 +```Sql +select score from root.** order by score desc align by device +``` +会得到如下结果 + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +当想要根据总分对结果进行排序,可以在order by子句中使用表达式进行计算 +```Sql +select score,total from root.one order by base+score+bonus desc +``` +该sql等价于 +```Sql +select score,total from root.one order by total desc +``` +得到如下结果 + +``` ++-----------------------------+--------------+--------------+ +| Time|root.one.score|root.one.total| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.000+08:00| 50.0| 107.0| +|1970-01-02T08:00:00.000+08:00| 50.0| 105.0| +|1970-01-03T08:00:00.000+08:00| 50.0| 103.0| ++-----------------------------+--------------+--------------+ +``` +而如果要对总分进行排序,且分数相同时依次根据score, base, bonus和提交时间进行排序时,可以通过多个表达式来指定多层排序 + +```Sql +select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +``` +得到如下结果 +``` ++-----------------------------+----------+----+-----+-----+-----+ +| Time| Device|base|score|bonus|total| ++-----------------------------+----------+----+-----+-----+-----+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0|107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0|105.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0|104.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0|103.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0|102.0| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.000+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00|root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.030+08:00|root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.020+08:00|root.three| 8| null| 22.5| 30.5| ++-----------------------------+----------+----+-----+-----+-----+ +``` +在order by中同样可以使用聚合查询表达式 +```Sql +select min_value(total) from root.** order by min_value(total) asc align by device +``` +得到如下结果 +``` ++----------+----------------+ +| Device|min_value(total)| ++----------+----------------+ +|root.three| 30.5| +| root.two| 33.0| +| root.four| 85.0| +| root.five| 102.0| +| root.one| 103.0| ++----------+----------------+ +``` +当在查询中指定多列,未被排序的列会随着行和排序列一起改变顺序,当排序列相同时行的顺序和具体实现有关(没有固定顺序) +```Sql +select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +``` +得到结果如下 +· +``` ++----------+----------------+---------------+ +| Device|min_value(total)|max_value(base)| ++----------+----------------+---------------+ +| root.one| 103.0| 12| +| root.five| 102.0| 7| +| root.four| 85.0| 9| +| root.two| 33.0| 9| +|root.three| 30.5| 9| ++----------+----------------+---------------+ +``` + +Order by device, time可以和order by expression共同使用 +```Sql +select score from root.** order by device asc, score desc, time asc align by device +``` +会得到如下结果 +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +## 9. 查询对齐模式(ALIGN BY DEVICE 子句) + +在 IoTDB 中,查询结果集**默认按照时间对齐**,包含一列时间列和若干个值列,每一行数据各列的时间戳相同。 + +除按照时间对齐外,还支持以下对齐模式: + +- 按设备对齐 `ALIGN BY DEVICE` + +### 9.1 按设备对齐 + +在按设备对齐模式下,设备名会单独作为一列出现,查询结果集包含一列时间列、一列设备列和若干个值列。如果 `SELECT` 子句中选择了 `N` 列,则结果集包含 `N + 2` 列(时间列和设备名字列)。 + +在默认情况下,结果集按照 `Device` 进行排列,在每个 `Device` 内按照 `Time` 列升序排序。 + +当查询多个设备时,要求设备之间同名的列数据类型相同。 + +为便于理解,可以按照关系模型进行对应。设备可以视为关系模型中的表,选择的列可以视为表中的列,`Time + Device` 看做其主键。 + +**示例:** + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +执行如下: + +``` ++-----------------------------+-----------------+-----------+------+--------+ +| Time| Device|temperature|status|hardware| ++-----------------------------+-----------------+-----------+------+--------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| 25.96| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| 24.36| true| null| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| null| true| v1| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| null| false| v2| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| null| true| v2| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| null| true| v2| ++-----------------------------+-----------------+-----------+------+--------+ +Total line number = 6 +It costs 0.012s +``` +### 9.2 设备对齐模式下的排序 +在设备对齐模式下,默认按照设备名的字典序升序排列,每个设备内部按照时间戳大小升序排列,可以通过 `ORDER BY` 子句调整设备列和时间列的排序优先级。 + +详细说明及示例见文档 [结果集排序](../SQL-Manual/Operator-and-Expression.md)。 + +## 10. 查询写回(INTO 子句) + +`SELECT INTO` 语句用于将查询结果写入一系列指定的时间序列中。 + +应用场景如下: +- **实现 IoTDB 内部 ETL**:对原始数据进行 ETL 处理后写入新序列。 +- **查询结果存储**:将查询结果进行持久化存储,起到类似物化视图的作用。 +- **非对齐序列转对齐序列**:对齐序列从0.13版本开始支持,可以通过该功能将非对齐序列的数据写入新的对齐序列中。 + +### 10.1 语法定义 + +#### 整体描述 + +```sql +selectIntoStatement + : SELECT + resultColumn [, resultColumn] ... + INTO intoItem [, intoItem] ... + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY groupByTimeClause, groupByLevelClause] + [FILL {PREVIOUS | LINEAR | constant}] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] + ; + +intoItem + : [ALIGNED] intoDevicePath '(' intoMeasurementName [',' intoMeasurementName]* ')' + ; +``` + +#### `INTO` 子句 + +`INTO` 子句由若干个 `intoItem` 构成。 + +每个 `intoItem` 由一个目标设备路径和一个包含若干目标物理量名的列表组成(与 `INSERT` 语句中的 `INTO` 子句写法类似)。 + +其中每个目标物理量名与目标设备路径组成一个目标序列,一个 `intoItem` 包含若干目标序列。例如:`root.sg_copy.d1(s1, s2)` 指定了两条目标序列 `root.sg_copy.d1.s1` 和 `root.sg_copy.d1.s2`。 + +`INTO` 子句指定的目标序列要能够与查询结果集的列一一对应。具体规则如下: + +- **按时间对齐**(默认):全部 `intoItem` 包含的目标序列数量要与查询结果集的列数(除时间列外)一致,且按照表头从左到右的顺序一一对应。 +- **按设备对齐**(使用 `ALIGN BY DEVICE`):全部 `intoItem` 中指定的目标设备数和查询的设备数(即 `FROM` 子句中路径模式匹配的设备数)一致,且按照结果集设备的输出顺序一一对应。 + 为每个目标设备指定的目标物理量数量要与查询结果集的列数(除时间和设备列外)一致,且按照表头从左到右的顺序一一对应。 + +下面通过示例进一步说明: + +- **示例 1**(按时间对齐) +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; ++--------------+-------------------+--------+ +| source column| target timeseries| written| ++--------------+-------------------+--------+ +| root.sg.d1.s1| root.sg_copy.d1.t1| 8000| ++--------------+-------------------+--------+ +| root.sg.d2.s1| root.sg_copy.d2.t1| 10000| ++--------------+-------------------+--------+ +| root.sg.d1.s2| root.sg_copy.d2.t2| 12000| ++--------------+-------------------+--------+ +| root.sg.d2.s2| root.sg_copy.d1.t2| 10000| ++--------------+-------------------+--------+ +Total line number = 4 +It costs 0.725s +``` + +该语句将 `root.sg` database 下四条序列的查询结果写入到 `root.sg_copy` database 下指定的四条序列中。注意,`root.sg_copy.d2(t1, t2)` 也可以写做 `root.sg_copy.d2(t1), root.sg_copy.d2(t2)`。 + +可以看到,`INTO` 子句的写法非常灵活,只要满足组合出的目标序列没有重复,且与查询结果列一一对应即可。 + +> `CLI` 展示的结果集中,各列的含义如下: +> - `source column` 列表示查询结果的列名。 +> - `target timeseries` 表示对应列写入的目标序列。 +> - `written` 表示预期写入的数据量。 + +- **示例 2**(按时间对齐) +```shell +IoTDB> select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); ++--------------------------------------+-------------------------+--------+ +| source column| target timeseries| written| ++--------------------------------------+-------------------------+--------+ +| count(root.sg.d1.s1 + root.sg.d1.s2)| root.agg.count.s1_add_s2| 10| ++--------------------------------------+-------------------------+--------+ +| last_value(root.sg.d1.s2)| root.agg.last_value.s2| 10| ++--------------------------------------+-------------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +该语句将聚合查询的结果存储到指定序列中。 + +- **示例 3**(按设备对齐) +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+-------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s1| root.sg_copy.d1.t1| 8000| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s2| root.sg_copy.d1.t2| 11000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s1| root.sg_copy.d2.t1| 12000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s2| root.sg_copy.d2.t2| 9000| ++--------------+--------------+-------------------+--------+ +Total line number = 4 +It costs 0.625s +``` + +该语句同样是将 `root.sg` database 下四条序列的查询结果写入到 `root.sg_copy` database 下指定的四条序列中。但在按设备对齐中,`intoItem` 的数量必须和查询的设备数量一致,每个查询设备对应一个 `intoItem`。 + +> 按设备对齐查询时,`CLI` 展示的结果集多出一列 `source device` 列表示查询的设备。 + +- **示例 4**(按设备对齐) +```shell +IoTDB> select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+------------------------+--------+ +| root.sg.d1| s1 + s2| root.expr.add.d1s1_d1s2| 10000| ++--------------+--------------+------------------------+--------+ +| root.sg.d2| s1 + s2| root.expr.add.d2s1_d2s2| 10000| ++--------------+--------------+------------------------+--------+ +Total line number = 2 +It costs 0.532s +``` + +该语句将表达式计算的结果存储到指定序列中。 + +#### 使用变量占位符 + +特别地,可以使用变量占位符描述目标序列与查询序列之间的对应规律,简化语句书写。目前支持以下两种变量占位符: + +- 后缀复制符 `::`:复制查询设备后缀(或物理量),表示从该层开始一直到设备的最后一层(或物理量),目标设备的节点名(或物理量名)与查询的设备对应的节点名(或物理量名)相同。 +- 单层节点匹配符 `${i}`:表示目标序列当前层节点名与查询序列的第`i`层节点名相同。比如,对于路径`root.sg1.d1.s1`而言,`${1}`表示`sg1`,`${2}`表示`d1`,`${3}`表示`s1`。 + +在使用变量占位符时,`intoItem`与查询结果集列的对应关系不能存在歧义,具体情况分类讨论如下: + +##### 按时间对齐(默认) + +> 注:变量占位符**只能描述序列与序列之间的对应关系**,如果查询中包含聚合、表达式计算,此时查询结果中的列无法与某个序列对应,因此目标设备和目标物理量都不能使用变量占位符。 + +###### (1)目标设备不使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** + 1. 每个 `intoItem` 中,物理量列表的长度必须为 1。
(如果长度可以大于1,例如 `root.sg1.d1(::, s1)`,无法确定具体哪些列与`::`匹配) + 2. `intoItem` 数量为 1,或与查询结果集列数一致。
(在每个目标物理量列表长度均为 1 的情况下,若 `intoItem` 只有 1 个,此时表示全部查询序列写入相同设备;若 `intoItem` 数量与查询序列一致,则表示为每个查询序列指定一个目标设备;若 `intoItem` 大于 1 小于查询序列数,此时无法与查询序列一一对应) + +**匹配方法:** 每个查询序列指定目标设备,而目标物理量根据变量占位符生成。 + +**示例:** + +```sql +select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; +``` +该语句等价于: +```sql +select s1, s2 +into root.sg_copy.d1(s1), root.sg_copy.d2(s1), root.sg_copy.d1(s2), root.sg_copy.d2(s2) +from root.sg.d1, root.sg.d2; +``` +可以看到,在这种情况下,语句并不能得到很好地简化。 + +###### (2)目标设备使用变量占位符 & 目标物理量列表不使用变量占位符 + +**限制:** 全部 `intoItem` 中目标物理量的数量与查询结果集列数一致。 + +**匹配方式:** 为每个查询序列指定了目标物理量,目标设备根据对应目标物理量所在 `intoItem` 的目标设备占位符生成。 + +**示例:** +```sql +select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; +``` + +###### (3)目标设备使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** `intoItem` 只有一个且物理量列表的长度为 1。 + +**匹配方式:** 每个查询序列根据变量占位符可以得到一个目标序列。 + +**示例:** +```sql +select * into root.sg_bk.::(::) from root.sg.**; +``` +将 `root.sg` 下全部序列的查询结果写到 `root.sg_bk`,设备名后缀和物理量名保持不变。 + +##### 按设备对齐(使用 `ALIGN BY DEVICE`) + +> 注:变量占位符**只能描述序列与序列之间的对应关系**,如果查询中包含聚合、表达式计算,此时查询结果中的列无法与某个物理量对应,因此目标物理量不能使用变量占位符。 + +###### (1)目标设备不使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** 每个 `intoItem` 中,如果物理量列表使用了变量占位符,则列表的长度必须为 1。 + +**匹配方法:** 每个查询序列指定目标设备,而目标物理量根据变量占位符生成。 + +**示例:** +```sql +select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; +``` + +###### (2)目标设备使用变量占位符 & 目标物理量列表不使用变量占位符 + +**限制:** `intoItem` 只有一个。(如果出现多个带占位符的 `intoItem`,我们将无法得知每个 `intoItem` 需要匹配哪几个源设备) + +**匹配方式:** 每个查询设备根据变量占位符得到一个目标设备,每个设备下结果集各列写入的目标物理量由目标物理量列表指定。 + +**示例:** +```sql +select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; +``` + +###### (3)目标设备使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** `intoItem` 只有一个且物理量列表的长度为 1。 + +**匹配方式:** 每个查询序列根据变量占位符可以得到一个目标序列。 + +**示例:** +```sql +select * into ::(backup_${4}) from root.sg.** align by device; +``` +将 `root.sg` 下每条序列的查询结果写到相同设备下,物理量名前加`backup_`。 + +#### 指定目标序列为对齐序列 + +通过 `ALIGNED` 关键词可以指定写入的目标设备为对齐写入,每个 `intoItem` 可以独立设置。 + +**示例:** +```sql +select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` +该语句指定了 `root.sg_copy.d1` 是非对齐设备,`root.sg_copy.d2`是对齐设备。 + +#### 不支持使用的查询子句 + +- `SLIMIT`、`SOFFSET`:查询出来的列不确定,功能不清晰,因此不支持。 +- `LAST`查询、`GROUP BY TAGS`、`DISABLE ALIGN`:表结构和写入结构不一致,因此不支持。 + +#### 其他要注意的点 + +- 对于一般的聚合查询,时间戳是无意义的,约定使用 0 来存储。 +- 当目标序列存在时,需要保证源序列和目标时间序列的数据类型兼容。关于数据类型的兼容性,查看文档 [数据类型](../Background-knowledge/Data-Type.md#数据类型兼容性)。 +- 当目标序列不存在时,系统将自动创建目标序列(包括 database)。 +- 当查询的序列不存在或查询的序列不存在数据,则不会自动创建目标序列。 + +### 10.2 应用举例 + +#### 实现 IoTDB 内部 ETL +对原始数据进行 ETL 处理后写入新序列。 +```shell +IOTDB > SELECT preprocess_udf(s1, s2) INTO ::(preprocessed_s1, preprocessed_s2) FROM root.sg.* ALIGN BY DEIVCE; ++--------------+-------------------+---------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s1)| root.sg.d1.preprocessed_s1| 8000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s2)| root.sg.d1.preprocessed_s2| 10000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s1)| root.sg.d2.preprocessed_s1| 11000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s2)| root.sg.d2.preprocessed_s2| 9000| ++--------------+-------------------+---------------------------+--------+ +``` +以上语句使用自定义函数对数据进行预处理,将预处理后的结果持久化存储到新序列中。 + +#### 查询结果存储 +将查询结果进行持久化存储,起到类似物化视图的作用。 +```shell +IOTDB > SELECT count(s1), last_value(s1) INTO root.sg.agg_${2}(count_s1, last_value_s1) FROM root.sg1.d1 GROUP BY ([0, 10000), 10ms); ++--------------------------+-----------------------------+--------+ +| source column| target timeseries| written| ++--------------------------+-----------------------------+--------+ +| count(root.sg.d1.s1)| root.sg.agg_d1.count_s1| 1000| ++--------------------------+-----------------------------+--------+ +| last_value(root.sg.d1.s2)| root.sg.agg_d1.last_value_s2| 1000| ++--------------------------+-----------------------------+--------+ +Total line number = 2 +It costs 0.115s +``` +以上语句将降采样查询的结果持久化存储到新序列中。 + +#### 非对齐序列转对齐序列 +对齐序列从 0.13 版本开始支持,可以通过该功能将非对齐序列的数据写入新的对齐序列中。 + +**注意:** 建议配合使用 `LIMIT & OFFSET` 子句或 `WHERE` 子句(时间过滤条件)对数据进行分批,防止单次操作的数据量过大。 + +```shell +IOTDB > SELECT s1, s2 INTO ALIGNED root.sg1.aligned_d(s1, s2) FROM root.sg1.non_aligned_d WHERE time >= 0 and time < 10000; ++--------------------------+----------------------+--------+ +| source column| target timeseries| written| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s1| root.sg1.aligned_d.s1| 10000| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s2| root.sg1.aligned_d.s2| 10000| ++--------------------------+----------------------+--------+ +Total line number = 2 +It costs 0.375s +``` +以上语句将一组非对齐的序列的数据迁移到一组对齐序列。 + +### 10.3 相关用户权限 + +用户必须有下列权限才能正常执行查询写回语句: + +* 所有 `SELECT` 子句中源序列的 `WRITE_SCHEMA` 权限。 +* 所有 `INTO` 子句中目标序列 `WRITE_DATA` 权限。 + +更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management_timecho)。 + +### 10.4 相关配置参数 + +* `select_into_insert_tablet_plan_row_limit` + + | 参数名 | select_into_insert_tablet_plan_row_limit | + | ---- | ---- | + | 描述 | 写入过程中每一批 `Tablet` 的最大行数 | + | 类型 | int32 | + | 默认值 | 10000 | + | 改后生效方式 | 重启后生效 | diff --git a/src/zh/UserGuide/latest/Basic-Concept/Write-Data.md b/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md similarity index 94% rename from src/zh/UserGuide/latest/Basic-Concept/Write-Data.md rename to src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md index e35ac1bcb..12f6dafd8 100644 --- a/src/zh/UserGuide/latest/Basic-Concept/Write-Data.md +++ b/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_apache.md @@ -23,7 +23,7 @@ # 数据写入 ## 1. CLI写入数据 -IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC.md) 接口)单条或批量执行插入数据的 INSERT 语句。 +IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC_apache) 接口)单条或批量执行插入数据的 INSERT 语句。 本节主要为您介绍实时数据接入的 INSERT 语句在场景中的实际使用示例,有关 INSERT SQL 语句的详细语法请参见本文 [INSERT 语句](../SQL-Manual/SQL-Manual.md#写入数据) 节。 @@ -117,11 +117,11 @@ It costs 0.004s ### 2.1 多语言接口写入 * ### Java - 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API.md)。 - 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API.md#数据写入)写入。 + 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API_apache)。 + 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API_apache#数据写入)写入。 * ### Python - 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API.md#数据写入) + 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API_apache#数据写入) * ### C++ 参考 [ C++ 数据操作接口(DML)](../API/Programming-Cpp-Native-API.md) @@ -131,7 +131,7 @@ It costs 0.004s ## 3. REST API写入 -参考 [insertTablet (v1)](../API/RestServiceV1.md#inserttablet) or [insertTablet (v2)](../API/RestServiceV2.md#inserttablet) +参考 [insertTablet (v1)](../API/RestServiceV1_apache#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_apache#inserttablet) 示例如下: ```JSON @@ -176,11 +176,11 @@ It costs 0.004s ### 5.1 TsFile批量导入 -TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool.md)。 +TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_apache)。 ### 5.2 CSV批量导入 -CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool.md)。 +CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_apache)。 ## 6. 无模式写入 在物联网场景中,由于设备的类型、数量可能随时间动态增减,不同设备可能产生不同字段的数据(如温度、湿度、状态码等),业务上又往往需要快速部署,需要灵活接入新设备且无需繁琐的预定义流程。因此,不同于传统时序数据库通常需要预先定义数据模型,IoTDB支持不提前创建元数据,在写入数据时,数据库中将自动识别并注册所需的元数据,实现自动建模。 diff --git a/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md b/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md new file mode 100644 index 000000000..a7f0fb2e7 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data_timecho.md @@ -0,0 +1,188 @@ + + + +# 数据写入 +## 1. CLI写入数据 + +IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC_timecho) 接口)单条或批量执行插入数据的 INSERT 语句。 + +本节主要为您介绍实时数据接入的 INSERT 语句在场景中的实际使用示例,有关 INSERT SQL 语句的详细语法请参见本文 [INSERT 语句](../SQL-Manual/SQL-Manual.md#写入数据) 节。 + +注:写入重复时间戳的数据则原时间戳数据被覆盖,可视为更新数据。 + +### 1.1 使用 INSERT 语句 + +使用 INSERT 语句可以向指定的已经创建的一条或多条时间序列中插入数据。对于每一条数据,均由一个时间戳类型的时间戳和一个数值或布尔值、字符串类型的传感器采集值组成。 + +在本节的场景实例下,以其中的两个时间序列`root.ln.wf02.wt02.status`和`root.ln.wf02.wt02.hardware`为例 ,它们的数据类型分别为 BOOLEAN 和 TEXT。 + +单列数据插入示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +以上示例代码将长整型的 timestamp 以及值为 true 的数据插入到时间序列`root.ln.wf02.wt02.status`中和将长整型的 timestamp 以及值为”v1”的数据插入到时间序列`root.ln.wf02.wt02.hardware`中。执行成功后会返回执行时间,代表数据插入已完成。 + +> 注意:在 IoTDB 中,TEXT 类型的数据单双引号都可以来表示,上面的插入语句是用的是双引号表示 TEXT 类型数据,下面的示例将使用单引号表示 TEXT 类型数据。 + +INSERT 语句还可以支持在同一个时间点下多列数据的插入,同时向 2 时间点插入上述两个时间序列的值,多列数据插入示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) values (2, false, 'v2') +``` + +此外,INSERT 语句支持一次性插入多行数据,同时向 2 个不同时间点插入上述时间序列的值,示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +插入数据后我们可以使用 SELECT 语句简单查询已插入的数据。 + +```sql +IoTDB > select * from root.ln.wf02.wt02 where time < 5 +``` + +结果如图所示。由查询结果可以看出,单列、多列数据的插入操作正确执行。 + +``` ++-----------------------------+--------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status| ++-----------------------------+--------------------------+------------------------+ +|1970-01-01T08:00:00.001+08:00| v1| true| +|1970-01-01T08:00:00.002+08:00| v2| false| +|1970-01-01T08:00:00.003+08:00| v3| false| +|1970-01-01T08:00:00.004+08:00| v4| true| ++-----------------------------+--------------------------+------------------------+ +Total line number = 4 +It costs 0.004s +``` + +此外,我们可以省略 timestamp 列,此时系统将使用当前的系统时间作为该数据点的时间戳,示例代码如下: +```sql +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` +**注意:** 当一次插入多行数据时必须指定时间戳。 + +### 1.2 向对齐时间序列插入数据 + +向对齐时间序列插入数据只需在SQL中增加`ALIGNED`关键词,其他类似。 + +示例代码如下: + +```sql +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +结果如图所示。由查询结果可以看出,数据的插入操作正确执行。 + +``` ++-----------------------------+--------------+--------------+ +| Time|root.sg1.d1.s1|root.sg1.d1.s2| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.001+08:00| 1| 1.0| +|1970-01-01T08:00:00.002+08:00| 2| 2.0| +|1970-01-01T08:00:00.003+08:00| 3| 3.0| ++-----------------------------+--------------+--------------+ +Total line number = 3 +It costs 0.004s +``` + +## 2. 原生接口写入 +原生接口 (Session) 是目前IoTDB使用最广泛的系列接口,包含多种写入接口,适配不同的数据采集场景,性能高效且支持多语言。 + +### 2.1 多语言接口写入 +* ### Java + 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API_timecho)。 + 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API_timecho#数据写入)写入。 + +* ### Python + 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API_timecho#数据写入) + +* ### C++ + 参考 [ C++ 数据操作接口(DML)](../API/Programming-Cpp-Native-API.md) + +* ### Go + 参考 [Go 原生接口](../API/Programming-Go-Native-API.md) + +## 3. REST API写入 + +参考 [insertTablet (v1)](../API/RestServiceV1_timecho#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_timecho#inserttablet) + +示例如下: +```JSON +{ +      "timestamps": [ +            1, +            2, +            3 +      ], +      "measurements": [ +            "temperature", +            "status" +      ], +      "data_types": [ +            "FLOAT", +            "BOOLEAN" +      ], +      "values": [ +            [ +                  1.1, +                  2.2, +                  3.3 +            ], +            [ +                  false, +                  true, +                  true +            ] +      ], +      "is_aligned": false, +      "device": "root.ln.wf01.wt01" +} +``` + +## 4. MQTT写入 + +参考 [内置 MQTT 服务](../API/Programming-MQTT.md#内置-mqtt-服务) + +## 5. 批量数据导入 + +针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,本章节向大家介绍最为常用的两种方式为 CSV文本形式的导入 和 TsFile文件形式的导入。 + +### 5.1 TsFile批量导入 + +TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_timecho)。 + +### 5.2 CSV批量导入 + +CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_timecho)。 + +## 6. 无模式写入 +在物联网场景中,由于设备的类型、数量可能随时间动态增减,不同设备可能产生不同字段的数据(如温度、湿度、状态码等),业务上又往往需要快速部署,需要灵活接入新设备且无需繁琐的预定义流程。因此,不同于传统时序数据库通常需要预先定义数据模型,IoTDB支持不提前创建元数据,在写入数据时,数据库中将自动识别并注册所需的元数据,实现自动建模。 + +用户既可以通过CLI使用insert语句或者原生接口的方式,批量或者单行实时写入一个设备或者多个设备的测点数据,也可以通过导入工具导入csv,TsFile等格式的历史数据,在导入过程中会自动创建序列,数据类型,压缩编码方式等元数据。 diff --git a/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md b/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md index f0669fb92..523ed7ad7 100644 --- a/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md +++ b/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_apache.md @@ -51,9 +51,9 @@ - SQL 语法介绍:[SQL 语法介绍](../Basic-Concept/Operate-Metadata_apache.md) -2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data) +2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data_apache) -3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data.md) +3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data_apache) 4. 其他进阶功能:除了数据库常见的写入、查询等功能外,IoTDB 还支持“数据同步、流处理框架、权限管理”等功能,具体使用方法可参见具体文档: @@ -61,9 +61,9 @@ - 流处理框架:[流处理框架](../User-Manual/Streaming_apache.md) - - 权限管理:[权限管理](../User-Manual/Authority-Management.md) + - 权限管理:[权限管理](../User-Manual/Authority-Management_apache) -5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持 [Java](../API/Programming-Java-Native-API.md)、[Python](../API/Programming-Python-Native-API.md)、[C++](../API/Programming-Cpp-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持 [Java](../API/Programming-Java-Native-API_apache)、[Python](../API/Programming-Python-Native-API_apache)、[C++](../API/Programming-Cpp-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? @@ -71,10 +71,10 @@ IoTDB 除了自身拥有丰富的功能外,其周边的工具体系包含的 - 测试工具:IoT-benchmark 是一个基于 Java 和大数据环境开发的时序数据库基准测试工具,由清华大学软件学院研发并开源。它支持多种写入和查询方式,能够存储测试信息和结果供进一步查询或分析,并支持与 Tableau 集成以可视化测试结果。具体使用介绍请查看:[测试工具](../Tools-System/Benchmark.md) - - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool.md) + - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool_apache) - - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool.md) + - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool_apache) ## 4. 想了解更多技术细节? diff --git a/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md b/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md index 6bcda0c34..314ad1aae 100644 --- a/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md +++ b/src/zh/UserGuide/Master/Tree/QuickStart/QuickStart_timecho.md @@ -59,9 +59,9 @@ - SQL 语法介绍:[SQL 语法介绍](../Basic-Concept/Operate-Metadata_timecho.md) -2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data) +2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data_timecho) -3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data.md) +3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data_timecho) 4. 其他进阶功能:除了数据库常见的写入、查询等功能外,IoTDB 还支持“数据同步、流处理框架、安全控制、权限管理、AI 分析”等功能,具体使用方法可参见具体文档: @@ -71,11 +71,11 @@ - 安全控制:[安全控制](../User-Manual/White-List_timecho.md) - - 权限管理:[权限管理](../User-Manual/Authority-Management.md) + - 权限管理:[权限管理](../User-Manual/Authority-Management_timecho) - AI 分析:[AI 能力](../AI-capability/AINode_timecho.md) -5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[C++原生接口](../API/Programming-Cpp-Native-API.md)、[Go 原生接口](../API/Programming-Go-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho)、[Python 原生接口](../API/Programming-Python-Native-API_timecho)、[C++原生接口](../API/Programming-Cpp-Native-API.md)、[Go 原生接口](../API/Programming-Go-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? @@ -87,10 +87,10 @@ IoTDB 除了自身拥有丰富的功能外,其周边的工具体系包含的 - 测试工具:IoT-benchmark 是一个基于 Java 和大数据环境开发的时序数据库基准测试工具,由清华大学软件学院研发并开源。它支持多种写入和查询方式,能够存储测试信息和结果供进一步查询或分析,并支持与 Tableau 集成以可视化测试结果。具体使用介绍请查看:[测试工具](../Tools-System/Benchmark.md) - - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool.md) + - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool_timecho) - - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool.md) + - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool_timecho) ## 4. 想了解更多技术细节? diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/CLI_apache.md b/src/zh/UserGuide/Master/Tree/Tools-System/CLI_apache.md index d69e49e06..62320a0e6 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/CLI_apache.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/CLI_apache.md @@ -38,7 +38,7 @@ IOTDB 为用户提供 cli/Shell 工具用于启动客户端和服务端程序。 ## 2. 运行 ### 2.1 Cli 运行方式 -安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
+安装后的 IoTDB 中有一个默认用户:`root`,默认密码为 `root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
用户也可以在启动脚本的最前方设置自己的环境变量,如 JAVA_HOME 等。 Linux 系统与 MacOS 系统启动命令如下: @@ -49,10 +49,10 @@ Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root Windows 系统启动命令如下: ```shell -# V2.0.4.x 版本之前 +# V2.0.4 版本之前 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x 版本及之后 +# V2.0.4 版本及之后, Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root ``` 回车后即可成功启动客户端。启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/CLI_timecho.md b/src/zh/UserGuide/Master/Tree/Tools-System/CLI_timecho.md index 2ec16f94c..e102cd6be 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/CLI_timecho.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/CLI_timecho.md @@ -25,13 +25,17 @@ IOTDB 为用户提供 cli/Shell 工具用于启动客户端和服务端程序。 > \$IOTDB\_HOME 表示 IoTDB 的安装目录所在路径。 ## 1. Cli 运行方式 -安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
+安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`TimechoDB@2021`(V2.0.6.x 版本之前为`root`)。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
用户也可以在启动脚本的最前方设置自己的环境变量,如 JAVA_HOME 等。 Linux 系统与 MacOS 系统启动命令如下: ```shell +# V2.0.6.x 版本之前 Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x 版本及之后 +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` Windows 系统启动命令如下: @@ -39,8 +43,11 @@ Windows 系统启动命令如下: # V2.0.4.x 版本之前 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x 版本及之后 +# V2.0.4.x 版本及之后, V2.0.6.x 版本之前 Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x 版本及之后 +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` 回车后即可成功启动客户端。启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md similarity index 95% rename from src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md rename to src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md index cfc3b5105..d8827ad35 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_apache.md @@ -31,18 +31,18 @@ ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- | ------------------------------------------ | -| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | | -h | -- host | 主机名 | 否 | 127.0.0.1 | | -p | --port | 端口号 | 否 | 6667 | | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | -| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | -| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | -| -q | --query | 要执行的查询命令 | 否 | 无 | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | | -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | -| -help | --help | 显示帮助信息 | 否 | | +| -help | --help | 显示帮助信息 | 否 | | ### 2.2 Csv 格式 @@ -84,7 +84,7 @@ # 异常示例 > tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.3 Sql 格式 @@ -128,7 +128,7 @@ Parse error: Missing required option: t # 异常示例 > tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.4 TsFile 格式 @@ -163,5 +163,5 @@ Parse error: Missing required option: t # 异常示例 > tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..e060fe818 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,173 @@ +# 数据导出 + +## 1. 功能概述 + +数据导出工具 export-data.sh/bat 位于 tools 目录下,能够将指定 SQL 的查询结果导出为 CSV、SQL 及 TsFile(开源时间序列文件格式)格式。具体功能如下: + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVexport-data.sh/bat纯文本格式,存储格式化数据,需按照下文指定 CSV 格式进行构造
SQL包含自定义 SQL 语句的文件
TsFile开源时序数据文件格式
+ + +## 2. 功能详解 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | +| -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | +| -help | --help | 显示帮助信息 | 否 | | + +### 2.2 Csv 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |--------------------------------------| +| -dt | --datatype | 是否在CSV文件的表头输出时间序列的数据类型,可以选择`true`或`false` | 否 | false | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定CSV文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601 | +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.2.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -dt true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# 异常示例 +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.3 Sql 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------------------------------------- | +| -aligned | --use\_aligned | 是否导出为对齐的SQL格式 | 否 | true | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定CSV文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601| +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.3.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -aligned true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# 异常示例 +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 私有参数 + +* 无 + +#### 2.4.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn export-data.tsfile -q "SELECT * FROM root.ln" -timeout 10000 + +# 异常示例 +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` diff --git a/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool.md b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md similarity index 98% rename from src/zh/UserGuide/latest/Tools-System/Data-Import-Tool.md rename to src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md index 57e843a33..be01c58c4 100644 --- a/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_apache.md @@ -41,18 +41,18 @@ IoTDB 支持三种方式进行数据导入: ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |----------------------------------| +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |---------------------------| | -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | | -| -h | -- host | 主机名 | 否 | 127.0.0.1 | -| -p | --port | 端口号 | 否 | 6667 | -| -u | --username | 用户名 | 否 | root | -| -pw | --password | 密码 | 否 | root | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | root | | -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为csv sql tsfile这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | | | -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | -| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | | -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | | @@ -106,7 +106,7 @@ IoTDB 支持三种方式进行数据导入: error: Source file or directory /non_path does not exist > tools/import-data.sh -ft csv -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` #### 2.3.4 导入说明 @@ -196,7 +196,7 @@ error: Source file or directory /path/sql does not exist > tools/import-data.sh -ft sql -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ### 2.4 TsFile 格式 @@ -247,7 +247,7 @@ error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' > tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ## 3. TsFile 自动加载功能 diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..136c026fc --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,332 @@ +# 数据导入 + +## 1. 功能概述 + +IoTDB 支持三种方式进行数据导入: +- 数据导入工具 :`import-data.sh/bat` 位于 `tools` 目录下,可以将 `CSV`、`SQL`、及`TsFile`(开源时序文件格式)的数据导入 `IoTDB`。 +- `TsFile` 自动加载功能。 +- `Load SQL` 导入 `TsFile` 。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVimport-data.sh/bat可用于单个或一个目录的 CSV 文件批量导入 IoTDB
SQL可用于单个或一个目录的 SQL 文件批量导入 IoTDB
TsFile可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
TsFile 自动加载可以监听指定路径下新产生的 TsFile 文件,并将其加载进 IoTDB
Load SQL可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
+ +## 2. 数据导入工具 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |--------------------------------------| +| -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | +| +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为csv sql tsfile这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | +| +| -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | +| + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- |-------------------------------------------|---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -aligned | --use\_aligned | 是否导入为对齐序列 | 否 | false | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -ti | --type\_infer | 通过选项定义类型信息,例如`"boolean=text,int=long, ..."` | 否 | 无 | +| -tp | --timestamp\_precision | 时间戳精度 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms +| + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 100 -aligned true -ti "BOOLEAN=text,INT=long,FLOAT=double" + -tp ms -tz +08:00 -batch 5000 -tn 4 + +# 异常示例 +> tools/import-data.sh -ft csv -s /non_path +error: Source file or directory /non_path does not exist + +> tools/import-data.sh -ft csv -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +#### 2.3.4 导入说明 + +1. CSV 导入规范 + +- 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号,),需使用反斜杠(\)​进行转义处理。 +- 支持的时间格式:yyyy-MM-dd'T'HH:mm:ss, yyy-MM-dd HH:mm:ss, 或者 yyyy-MM-dd'T'HH:mm:ss.SSSZ。 +- 时间戳列​必须作为数据文件的首列存在。 + +2. CSV 文件示例 + +- 时间对齐 + +```sql +-- header 中不包含数据类型 + Time,root.test.t1.str,root.test.t2.str,root.test.t2.var + 1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 + 1970-01-01T08:00:00.002+08:00,"123",, + +-- header 中包含数据类型(Text 类型数据支持加双引号和不加双引号) +Time,root.test.t1.str(TEXT),root.test.t2.str(TEXT),root.test.t2.var(INT32) +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,123,hello world,123 +1970-01-01T08:00:00.003+08:00,"123",, +1970-01-01T08:00:00.004+08:00,123,,12 +``` + +- 设备对齐 + +```sql +-- header 中不包含数据类型 + Time,Device,str,var + 1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", + 1970-01-01T08:00:00.002+08:00,root.test.t1,"123", + 1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 + +-- header 中包含数据类型(Text 类型数据支持加双引号和不加双引号) +Time,Device,str(TEXT),var(INT32) +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 +1970-01-01T08:00:00.002+08:00,root.test.t1,hello world,123 +``` + +### 2.3 SQL 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x 版本及之后 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- | -------------- |---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 500 -tz +08:00 + -batch 100000 -tn 4 + +# 异常示例 +> tools/import-data.sh -ft sql -s /path/sql -fd /non_path +error: Source file or directory /path/sql does not exist + + +> tools/import-data.sh -ft sql -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` + +#### 2.4.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ------------------------ |----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------| -------------------- | +| -os| --on\_succcess| 1. none:不删除
2. mv:移动成功的文件到目标文件夹
3. cp:硬连接(拷贝)成功的文件到目标文件夹
4. delete:删除 | √ || +| -sd | --success\_dir | 当`--on_succcess`为mv或cp时,mv或cp的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_succcess`为mv或cp时需要填写 | `${EXEC_DIR}/success`| +| -of| --on\_fail| 1. none:跳过
2. mv:移动失败的文件到目标文件夹
3. cp:硬连接(拷贝)失败的文件到目标文件夹
4. delete:删除 | √ || +| -fd | --fail\_dir | 当`--on_fail`指定为mv或cp时,mv或cp的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_fail`指定为mv或cp时需要填写 | `${EXEC_DIR}/fail` | +| -tp | --timestamp\_precision | 时间戳精度
tsfile非远程导入:-tp 指定tsfile文件的时间精度 手动校验和服务器的时间戳是否一致 不一致返回报错信息
远程导入:-tp 指定tsfile文件的时间精度 pipe自动校验时间戳精度是否一致 不一致返回pipe报错信息 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms| + + +#### 2.4.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 + -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir + -tn 8 -tz +08:00 -tp ms + +# 异常示例 +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -fd /path/failure/dir -tn 8 +error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' + +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -sd /path/success/dir -fd /path/failure/dir -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` +## 3. TsFile 自动加载功能 + +本功能允许 IoTDB 主动监听指定目录下的新增 TsFile,并将 TsFile 自动加载至 IoTDB 中。通过此功能,IoTDB 能自动检测并加载 TsFile,无需手动执行任何额外的加载操作。 + +![](/img/Data-import1.png) + +### 3.1 配置参数 + +可通过从配置文件模版 `iotdb-system.properties.template` 中找到下列参数,添加到 IoTDB 配置文件 `iotdb-system.properties` 中开启 TsFile 自动加载功能。完整配置如下: + +| **配置参数** | **参数说明** | **value 取值范围** | **是否必填** | **默认值** | **加载方式** | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------- | ------------------------ | -------------------- | +| load\_active\_listening\_enable | 是否开启 DataNode 主动监听并且加载 tsfile 的功能(默认开启)。 | Boolean: true,false | 选填 | true | 热加载 | +| load\_active\_listening\_dirs | 需要监听的目录(自动包括目录中的子目录),如有多个使用 “,“ 隔开默认的目录为 `ext/load/pending`(支持热装载) | String: 一个或多个文件目录 | 选填 | `ext/load/pending` | 热加载 | +| load\_active\_listening\_fail\_dir | 执行加载 tsfile 文件失败后将文件转存的目录,只能配置一个 | String: 一个文件目录 | 选填 | `ext/load/failed` | 热加载 | +| load\_active\_listening\_max\_thread\_num | 同时执行加载 tsfile 任务的最大线程数,参数被注释掉时的默值为 max(1, CPU 核心数 / 2),当用户设置的值不在这个区间[1, CPU核心数 /2]内时,会设置为默认值 (1, CPU 核心数 / 2) | Long: [1, Long.MAX\_VALUE] | 选填 | max(1, CPU 核心数 / 2) | 重启后生效 | +| load\_active\_listening\_check\_interval\_seconds | 主动监听轮询间隔,单位秒。主动监听 tsfile 的功能是通过轮询检查文件夹实现的。该配置指定了两次检查 `load_active_listening_dirs` 的时间间隔,每次检查完成 `load_active_listening_check_interval_seconds` 秒后,会执行下一次检查。当用户设置的轮询间隔小于 1 时,会被设置为默认值 5 秒 | Long: [1, Long.MAX\_VALUE] | 选填 | 5 | 重启后生效 | + +### 3.2 注意事项 + +1. 如果待加载的文件中,存在 mods 文件,应优先将 mods 文件移动到监听目录下面,然后再移动 tsfile 文件,且 mods 文件应和对应的 tsfile 文件处于同一目录。防止加载到 tsfile 文件时,加载不到对应的 mods 文件 +2. 禁止设置 Pipe 的 receiver 目录、存放数据的 data 目录等作为监听目录 +3. 禁止 `load_active_listening_fail_dir` 与 `load_active_listening_dirs` 存在相同的目录,或者互相嵌套 +4. 保证 `load_active_listening_dirs` 目录有足够的权限,在加载成功之后,文件将会被删除,如果没有删除权限,则会重复加载 + +## 4. Load SQL + +IoTDB 支持通过 CLI 执行 SQL 直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的 IoTDB 实例中。 + +### 4.1 运行命令 + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` :文件本身,或是包含若干文件的文件夹路径 +* ``:可选参数,具体如下表所示 + +| Key | Key 描述 | Value 类型 | Value 取值范围 | Value 是否必填 | Value 默认值 | +| --------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ | ----------------------------------------- | ---------------- | -------------------------- | +| `database-level` | 当 tsfile 对应的 database 不存在时,可以通过` database-level`参数的值来制定 database 的级别,默认为`iotdb-common.properties`中设置的级别。
例如当设置 level 参数为 1 时表明此 tsfile 中所有时间序列中层级为1的前缀路径是 database。 | Integer | `[1: Integer.MAX_VALUE]` | 否 | 1 | +| `on-success` | 表示对于成功载入的 tsfile 的处置方式:默认为`delete`,即tsfile 成功加载后将被删除;`none `表明 tsfile 成功加载之后依然被保留在源文件夹, | String | `delete / none` | 否 | delete | +| `model` | 指定写入的 tsfile 是表模型还是树模型 | String | `tree / table` | 否 | 与`-sql_dialect`一致 | +| `database-name` | **仅限表模型有效**: 文件导入的目标 database,不存在时会自动创建,`database-name`中不允许包括"`root.`"前缀,如果包含,将会报错。 | String | `-` | 否 | null | +| `convert-on-type-mismatch` | 加载 tsfile 时,如果数据类型不一致,是否进行转换 | Boolean | `true / false` | 否 | true | +| `verify` | 加载 tsfile 前是否校验 schema | Boolean | `true / false` | 否 | true | +| `tablet-conversion-threshold` | 转换为 tablet 形式的 tsfile 大小阈值,针对小文件 tsfile 加载,采用将其转换为 tablet 形式进行写入:默认值为 -1,即任意大小 tsfile 都不进行转换 | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | 否 | -1 | +| `async` | 是否开启异步加载 tsfile,将文件移到 active load 目录下面,所有的 tsfile 都 load 到`database-name`下. | Boolean | `true / false` | 否 | false | + +### 4.2 运行示例 + +```SQL +-- 准备待导入环境 +IoTDB> show databases ++-------------+-----------------------+---------------------+-------------------+---------------------+ +| Database|SchemaReplicationFactor|DataReplicationFactor|TimePartitionOrigin|TimePartitionInterval| ++-------------+-----------------------+---------------------+-------------------+---------------------+ +|root.__system| 1| 1| 0| 604800000| ++-------------+-----------------------+---------------------+-------------------+---------------------+ + +-- 通过load sql 导入 tsfile +IoTDB> load '/home/dump1.tsfile' with ( 'on-success'='none') +Msg: The statement is executed successfully. + +-- 验证数据导入成功 +IoTDB> select * from root.testdb.** ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time|root.testdb.device.model.temperature|root.testdb.device.model.humidity|root.testdb.device.model.status| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|2025-04-17T10:35:47.218+08:00| 22.3| 19.4| true| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md similarity index 94% rename from src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md rename to src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md index ec7298763..feaac6100 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | -| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | -| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | -| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | -| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | | `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..bc035727b --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,81 @@ + + +# 元数据导出 + +## 1. 功能概述 + +元数据导出工具 `export-schema.sh/bat` 位于tools 目录下,能够将 IoTDB 中指定数据库下的元数据导出为脚本文件。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 运行示例 + +```Bash +# 导出 root.treedb路径下的元数据 +./export-schema.sh -sql_dialect tree -t /home/ -path "root.treedb.**" + +# 导出结果内容格式如下 +Timeseries,Alias,DataType,Encoding,Compression +root.treedb.device.temperature,,DOUBLE,GORILLA,LZ4 +root.treedb.device.humidity,,DOUBLE,GORILLA,LZ4 +``` diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md new file mode 100644 index 000000000..855e27003 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_apache.md @@ -0,0 +1,87 @@ + + +# 元数据导入 + +## 1. 功能概述 + +元数据导入工具 `import-schema.sh/bat` 位于tools 目录下,能够将指定路径下创建元数据的脚本文件导入到 IoTDB 中。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-----------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# V2.0.4.x 版本之前 +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x 版本及之后 +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 运行示例 + +```Bash +# 导入前 +IoTDB> show timeseries root.treedb.** ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ + +# 执行导入命令 +./import-schema.sh -sql_dialect tree -s /home/dump0_0.csv -db root.treedb + +# 导入成功后验证 +IoTDB> show timeseries root.treedb.** ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +| Timeseries|Alias| Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|root.treedb.device.temperature| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| +| root.treedb.device.humidity| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +``` diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md similarity index 93% rename from src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md rename to src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md index 7d398cccf..2e3cc9a8f 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool.md +++ b/src/zh/UserGuide/Master/Tree/Tools-System/Schema-Import-Tool_timecho.md @@ -29,18 +29,18 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- | --------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | -| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |--------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | | `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | | `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | -| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | | `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/latest/User-Manual/Authority-Management.md b/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_apache.md similarity index 98% rename from src/zh/UserGuide/latest/User-Manual/Authority-Management.md rename to src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_apache.md index 8427d8b28..d1295fa2d 100644 --- a/src/zh/UserGuide/latest/User-Manual/Authority-Management.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_apache.md @@ -22,7 +22,7 @@ # 权限管理 IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群系统的权限管理功能,保障数据与系统安全。 -本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC.md) 单条或批量执行权限管理类语句。 +本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC_apache) 单条或批量执行权限管理类语句。 ## 1. 基本概念 @@ -40,7 +40,7 @@ IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群 ### 1.4 默认用户与角色 -安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为 root。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 +安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为`root`。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 一个新创建的用户或角色不具备任何权限。 diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md b/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..507082a87 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,510 @@ + + +# 权限管理 + +IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群系统的权限管理功能,保障数据与系统安全。 +本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC_timecho) 单条或批量执行权限管理类语句。 + +## 1. 基本概念 + +### 1.1 用户 + +用户即数据库的合法使用者。一个用户与一个唯一的用户名相对应,并且拥有密码作为身份验证的手段。一个人在使用数据库之前,必须先提供合法的(即存于数据库中的)用户名与密码,作为用户成功登录。 + +### 1.2 权限 + +数据库提供多种操作,但并非所有的用户都能执行所有操作。如果一个用户可以执行某项操作,则称该用户有执行该操作的权限。权限通常需要一个路径来限定其生效范围,可以使用[路径模式](../Basic-Concept/Operate-Metadata.md)灵活管理权限。 + +### 1.3 角色 + +角色是若干权限的集合,并且有一个唯一的角色名作为标识符。角色通常和一个现实身份相对应(例如交通调度员),而一个现实身份可能对应着多个用户。这些具有相同现实身份的用户往往具有相同的一些权限,角色就是为了能对这样的权限进行统一的管理的抽象。 + +### 1.4 默认用户与角色 + +安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为`TimechoDB@2021`(V2.0.6.x 版本之前为`root`)。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 + +一个新创建的用户或角色不具备任何权限。 + +## 2. 用户定义 + +拥有 MANAGE_USER、MANAGE_ROLE 的用户或者管理员可以创建用户或者角色,需要满足以下约束: + +### 2.1 用户名限制 + +4~32个字符,支持使用英文大小写字母、数字、特殊字符(`!@#$%^&*()_+-=`) + +用户无法创建和管理员用户同名的用户。 + +### 2.2 密码限制 + +4~32个字符,可使用大写小写字母、数字、特殊字符(`!@#$%^&*()_+-=`),密码默认采用 SHA-256 进行加密。 + +### 2.3 角色名限制 + +4~32个字符,支持使用英文大小写字母、数字、特殊字符(`!@#$%^&*()_+-=`) + +用户无法创建和管理员用户同名的角色。 + +## 3. 权限管理 + +IoTDB 主要有两类权限:序列权限、全局权限。 + +### 3.1 序列权限 + +序列权限约束了用户访问数据的范围与方式,支持对绝对路径与前缀匹配路径授权,可对timeseries 粒度生效。 + +下表描述了这类权限的种类与范围: + +| 权限名称 | 描述 | +|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| READ_DATA | 允许读取授权路径下的序列数据。 | +| WRITE_DATA | 允许读取授权路径下的序列数据。
允许插入、删除授权路径下的的序列数据。
允许在授权路径下导入、加载数据,在导入数据时,需要拥有对应路径的 WRITE_DATA 权限,在自动创建数据库与序列时,需要有 MANAGE_DATABASE 与 WRITE_SCHEMA 权限。 | +| READ_SCHEMA | 允许获取授权路径下元数据树的详细信息:
包括:路径下的数据库、子路径、子节点、设备、序列、模版、视图等。 | +| WRITE_SCHEMA | 允许获取授权路径下元数据树的详细信息。
允许在授权路径下对序列、模版、视图等进行创建、删除、修改操作。
在创建或修改 view 的时候,会检查 view 路径的 WRITE_SCHEMA 权限、数据源的 READ_SCHEMA 权限。
在对 view 进行查询、插入时,会检查 view 路径的 READ_DATA 权限、WRITE_DATA 权限。
允许在授权路径下设置、取消、查看TTL。
允许在授权路径下挂载或者接触挂载模板。 | + +### 3.2 全局权限 + +全局权限约束了用户使用的数据库功能、限制了用户执行改变系统状态与任务状态的命令,用户获得全局授权后,可对数据库进行管理。 + +下表描述了系统权限的种类: + +| 权限名称 | 描述 | +|:---------------:|:------------------------------------------------------------------| +| MANAGE_DATABASE | - 允许用户创建、删除数据库. | +| MANAGE_USER | - 允许用户创建、删除、修改、查看用户。 | +| MANAGE_ROLE | - 允许用户创建、删除、查看角色。
允许用户将角色授予给其他用户,或取消其他用户的角色。 | +| USE_TRIGGER | - 允许用户创建、删除、查看触发器。
与触发器的数据源权限检查相独立。 | +| USE_UDF | - 允许用户创建、删除、查看用户自定义函数。
与自定义函数的数据源权限检查相独立。 | +| USE_CQ | - 允许用户创建、开始、停止、删除、查看管道。
允许用户创建、删除、查看管道插件。
与管道的数据源权限检查相独立。 | +| USE_PIPE | - 允许用户注册、开始、停止、卸载、查询流处理任务。
- 允许用户注册、卸载、查询注册流处理任务插件。 | +| EXTEND_TEMPLATE | - 允许自动扩展模板。 | +| MAINTAIN | - 允许用户查询、取消查询。
允许用户查看变量。
允许用户查看集群状态。 | +| USE_MODEL | - 允许用户创建、删除、查询深度学习模型 | + +关于模板权限: + +1. 模板的创建、删除、修改、查询、挂载、卸载仅允许管理员操作。 +2. 激活模板需要拥有激活路径的 WRITE_SCHEMA 权限 +3. 若开启了自动创建,在向挂载了模板的不存在路径写入时,数据库会自动扩展模板并写入数据,因此需要有 EXTEND_TEMPLATE 权限与写入序列的 WRITE_DATA 权限。 +4. 解除模板,需要拥有挂载模板路径的 WRITE_SCHEMA 权限。 +5. 查询使用了某个元数据模板的路径,需要有路径的 READ_SCHEMA 权限,否则将返回为空。 + +### 3.3 权限授予与取消 + +在 IoTDB 中,用户可以由三种途径获得权限: + +1. 由超级管理员授予,超级管理员可以控制其他用户的权限。 +2. 由允许权限授权的用户授予,该用户获得权限时被指定了 grant option 关键字。 +3. 由超级管理员或者有 MANAGE_ROLE 的用户授予某个角色进而获取权限。 + +取消用户的权限,可以由以下几种途径: + +1. 由超级管理员取消用户的权限。 +2. 由允许权限授权的用户取消权限,该用户获得权限时被指定了 grant option 关键字。 +3. 由超级管理员或者MANAGE_ROLE 的用户取消用户的某个角色进而取消权限。 + +- 在授权时,必须指定路径。全局权限需要指定为 root.**, 而序列相关权限必须为绝对路径或者以双通配符结尾的前缀路径。 +- 当授予角色权限时,可以为该权限指定 with grant option 关键字,意味着用户可以转授其授权路径上的权限,也可以取消其他用户的授权路径上的权限。例如用户 A 在被授予`集团1.公司1.**`的读权限时制定了 grant option 关键字,那么 A 可以将`集团1.公司1`以下的任意节点、序列的读权限转授给他人, 同样也可以取消其他用户 `集团1.公司1` 下任意节点的读权限。 +- 在取消授权时,取消授权语句会与用户所有的权限路径进行匹配,将匹配到的权限路径进行清理,例如用户A 具有 `集团1.公司1.工厂1 `的读权限, 在取消 `集团1.公司1.** `的读权限时,会清除用户A 的 `集团1.公司1.工厂1` 的读权限。 + + + +## 4. 鉴权 + +用户权限主要由三部分组成:权限生效范围(路径), 权限类型, with grant option 标记: + +``` +userTest1 : + root.t1.** - read_schema, read_data - with grant option + root.** - write_schema, write_data - with grant option +``` + +每个用户都有一个这样的权限访问列表,标识他们获得的所有权限,可以通过 `LIST PRIVILEGES OF USER ` 查看他们的权限。 + +在对一个路径进行鉴权时,数据库会进行路径与权限的匹配。例如检查 `root.t1.t2` 的 read_schema 权限时,首先会与权限访问列表的 `root.t1.**`进行匹配,匹配成功,则检查该路径是否包含待鉴权的权限,否则继续下一条路径-权限的匹配,直到匹配成功或者匹配结束。 + +在进行多路径鉴权时,对于多路径查询任务,数据库只会将有权限的数据呈现出来,无权限的数据不会包含在结果中;对于多路径写入任务,数据库要求必须所有的目标序列都获得了对应的权限,才能进行写入。 + +请注意,下面的操作需要检查多重权限 +1. 开启了自动创建序列功能,在用户将数据插入到不存在的序列中时,不仅需要对应序列的写入权限,还需要序列的元数据修改权限。 +2. 执行 select into 语句时,需要检查源序列的读权限与目标序列的写权限。需要注意的是源序列数据可能因为权限不足而仅能获取部分数据,目标序列写入权限不足时会报错终止任务。 +3. View 权限与数据源的权限是独立的,向 view 执行读写操作仅会检查 view 的权限,而不再对源路径进行权限校验。 + + + +## 5. 功能语法与示例 + +IoTDB 提供了组合权限,方便用户授权: + +| 权限名称 | 权限范围 | +|-------|-------------------------| +| ALL | 所有权限 | +| READ | READ_SCHEMA、READ_DATA | +| WRITE | WRITE_SCHEMA、WRITE_DATA | + +组合权限并不是一种具体的权限,而是一种简写方式,与直接书写对应的权限名称没有差异。 + +下面将通过一系列具体的用例展示权限语句的用法,非管理员执行下列语句需要提前获取权限,所需的权限标记在操作描述后。 + +### 5.1 用户与角色相关 + +- 创建用户(需 MANAGE_USER 权限) + + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- 删除用户 (需 MANEGE_USER 权限) + + +```SQL +DROP USER +eg: DROP USER user1 +``` + +- 创建角色 (需 MANAGE_ROLE 权限) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- 删除角色 (需 MANAGE_ROLE 权限) + + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +- 赋予用户角色 (需 MANAGE_ROLE 权限) + + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- 移除用户角色 (需 MANAGE_ROLE 权限) + + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- 列出所有用户 (需 MANEGE_USER 权限) + +```SQL +LIST USER +``` + +- 列出所有角色 (需 MANAGE_ROLE 权限) + +```SQL +LIST ROLE +``` + +- 列出指定角色下所有用户 (需 MANEGE_USER 权限) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- 列出指定用户下所有角色 + +用户可以列出自己的角色,但列出其他用户的角色需要拥有 MANAGE_ROLE 权限。 + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- 列出用户所有权限 + +用户可以列出自己的权限信息,但列出其他用户的权限需要拥有 MANAGE_USER 权限。 + +```SQL +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; + +``` + +- 列出角色所有权限 + +用户可以列出自己具有的角色的权限信息,列出其他角色的权限需要有 MANAGE_ROLE 权限。 + +```SQL +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- 修改密码 + +用户可以修改自己的密码,但修改其他用户密码需要具备MANAGE_USER 权限。 + +```SQL +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 5.2 授权与取消授权 + +用户使用授权语句对赋予其他用户权限,语法如下: + +```SQL +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +用户使用取消授权语句可以将其他的权限取消,语法如下: + +```SQL +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + +- **非管理员用户执行授权/取消授权语句时,需要对\ 有\ 权限,并且该权限是被标记带有 WITH GRANT OPTION 的。** + +- 在授予取消全局权限时,或者语句中包含全局权限时(ALL 展开会包含全局权限),须指定 path 为 root.**。 例如,以下授权/取消授权语句是合法的: + + ```SQL + GRANT MANAGE_USER ON root.** TO USER user1; + GRANT MANAGE_ROLE ON root.** TO ROLE role1 WITH GRANT OPTION; + GRANT ALL ON root.** TO role role1 WITH GRANT OPTION; + REVOKE MANAGE_USER ON root.** FROM USER user1; + REVOKE MANAGE_ROLE ON root.** FROM ROLE role1; + REVOKE ALL ON root.** FROM ROLE role1; + ``` + 下面的语句是非法的: + + ```SQL + GRANT READ, MANAGE_ROLE ON root.t1.** TO USER user1; + GRANT ALL ON root.t1.t2 TO USER user1 WITH GRANT OPTION; + REVOKE ALL ON root.t1.t2 FROM USER user1; + REVOKE READ, MANAGE_ROLE ON root.t1.t2 FROM ROLE ROLE1; + ``` + +- \ 必须为全路径或者以双通配符结尾的匹配路径,以下路径是合法的: + + ```SQL + root.** + root.t1.t2.** + root.t1.t2.t3 + ``` + + 以下的路径是非法的: + + ```SQL + root.t1.* + root.t1.**.t2 + root.t1*.t2.t3 + ``` + +## 6. 示例 + +根据本文中描述的 [样例数据](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt) 内容,IoTDB 的样例数据可能同时属于 ln, sgcc 等不同发电集团,不同的发电集团不希望其他发电集团获取自己的数据库数据,因此我们需要将不同的数据在集团层进行权限隔离。 + +### 6.1 创建用户 + +使用 `CREATE USER ` 创建用户。例如,我们可以使用具有所有权限的root用户为 ln 和 sgcc 集团创建两个用户角色,名为 ln_write_user, sgcc_write_user,密码均为 write_pwd。建议使用反引号(`)包裹用户名。SQL 语句为: + +```SQL +CREATE USER `ln_write_user` 'write_pwd' +CREATE USER `sgcc_write_user` 'write_pwd' +``` +此时使用展示用户的 SQL 语句: + +```SQL +LIST USER +``` + +我们可以看到这两个已经被创建的用户,结果如下: + +```SQL +IoTDB> CREATE USER `ln_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> CREATE USER `sgcc_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> LIST USER; ++---------------+ +| user| ++---------------+ +| ln_write_user| +| root| +|sgcc_write_user| ++---------------+ +Total line number = 3 +It costs 0.012s +``` + +### 6.2 赋予用户权限 + +此时,虽然两个用户已经创建,但是他们不具有任何权限,因此他们并不能对数据库进行操作,例如我们使用 ln_write_user 用户对数据库中的数据进行写入,SQL 语句为: + +```SQL +INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +``` + +此时,系统不允许用户进行此操作,会提示错误: + +```SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +现在,我们用 root 用户分别赋予他们向对应路径的写入权限. + +我们使用 `GRANT ON TO USER ` 语句赋予用户权限,例如: +```SQL +GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +``` + +执行状态如下所示: + +```SQL +IoTDB> GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +接着使用ln_write_user再尝试写入数据 + +```SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: The statement is executed successfully. +``` + +### 6.3 撤销用户权限 +授予用户权限后,我们可以使用 `REVOKE ON FROM USER `来撤销已经授予用户的权限。例如,用root用户撤销ln_write_user和sgcc_write_user的权限: + +``` SQL +REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +``` + +执行状态如下所示: +``` SQL +IoTDB> REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +撤销权限后,ln_write_user就没有向root.ln.**写入数据的权限了。 + +``` SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +## 7. 其他说明 + +角色是权限的集合,而权限和角色都是用户的一种属性。即一个角色可以拥有若干权限。一个用户可以拥有若干角色与权限(称为用户自身权限)。 + +目前在 IoTDB 中并不存在相互冲突的权限,因此一个用户真正具有的权限是用户自身权限与其所有的角色的权限的并集。即要判定用户是否能执行某一项操作,就要看用户自身权限或用户的角色的所有权限中是否有一条允许了该操作。用户自身权限与其角色权限,他的多个角色的权限之间可能存在相同的权限,但这并不会产生影响。 + +需要注意的是:如果一个用户自身有某种权限(对应操作 A),而他的某个角色有相同的权限。那么如果仅从该用户撤销该权限无法达到禁止该用户执行操作 A 的目的,还需要从这个角色中也撤销对应的权限,或者从这个用户将该角色撤销。同样,如果仅从上述角色将权限撤销,也不能禁止该用户执行操作 A。 + +同时,对角色的修改会立即反映到所有拥有该角色的用户上,例如对角色增加某种权限将立即使所有拥有该角色的用户都拥有对应权限,删除某种权限也将使对应用户失去该权限(除非用户本身有该权限)。 + +## 8. 升级说明 + +在 1.3 版本前,权限类型较多,在这一版实现中,权限类型做了精简,并且添加了对权限路径的约束。 + +数据库 1.3 版本的权限路径必须为全路径或者以双通配符结尾的匹配路径,在系统升级时,会自动转换不合法的权限路径和权限类型。 +路径上首个非法节点会被替换为`**`, 不在支持的权限类型也会映射到当前系统支持的权限上。 + +例如: + +| 权限类型 | 权限路径 | 映射之后的权限类型 | 权限路径 | +| ----------------- | --------------- |-----------------| ------------- | +| CREATE_DATBASE | root.db.t1.* | MANAGE_DATABASE | root.** | +| INSERT_TIMESERIES | root.db.t2.*.t3 | WRITE_DATA | root.db.t2.** | +| CREATE_TIMESERIES | root.db.t2*c.t3 | WRITE_SCHEMA | root.db.** | +| LIST_ROLE | root.** | (忽略) | | + + +新旧版本的权限类型对照可以参照下面的表格(--IGNORE 表示新版本忽略该权限): + +| 权限名称 | 是否路径相关 | 新权限名称 | 是否路径相关 | +|---------------------------|--------|-----------------|--------| +| CREATE_DATABASE | 是 | MANAGE_DATABASE | 否 | +| INSERT_TIMESERIES | 是 | WRITE_DATA | 是 | +| UPDATE_TIMESERIES | 是 | WRITE_DATA | 是 | +| READ_TIMESERIES | 是 | READ_DATA | 是 | +| CREATE_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| DELETE_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| CREATE_USER | 否 | MANAGE_USER | 否 | +| DELETE_USER | 否 | MANAGE_USER | 否 | +| MODIFY_PASSWORD | 否 | -- IGNORE | | +| LIST_USER | 否 | -- IGNORE | | +| GRANT_USER_PRIVILEGE | 否 | -- IGNORE | | +| REVOKE_USER_PRIVILEGE | 否 | -- IGNORE | | +| GRANT_USER_ROLE | 否 | MANAGE_ROLE | 否 | +| REVOKE_USER_ROLE | 否 | MANAGE_ROLE | 否 | +| CREATE_ROLE | 否 | MANAGE_ROLE | 否 | +| DELETE_ROLE | 否 | MANAGE_ROLE | 否 | +| LIST_ROLE | 否 | -- IGNORE | | +| GRANT_ROLE_PRIVILEGE | 否 | -- IGNORE | | +| REVOKE_ROLE_PRIVILEGE | 否 | -- IGNORE | | +| CREATE_FUNCTION | 否 | USE_UDF | 否 | +| DROP_FUNCTION | 否 | USE_UDF | 否 | +| CREATE_TRIGGER | 是 | USE_TRIGGER | 否 | +| DROP_TRIGGER | 是 | USE_TRIGGER | 否 | +| START_TRIGGER | 是 | USE_TRIGGER | 否 | +| STOP_TRIGGER | 是 | USE_TRIGGER | 否 | +| CREATE_CONTINUOUS_QUERY | 否 | USE_CQ | 否 | +| DROP_CONTINUOUS_QUERY | 否 | USE_CQ | 否 | +| ALL | 否 | All privilegs | | +| DELETE_DATABASE | 是 | MANAGE_DATABASE | 否 | +| ALTER_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| UPDATE_TEMPLATE | 否 | -- IGNORE | | +| READ_TEMPLATE | 否 | -- IGNORE | | +| APPLY_TEMPLATE | 是 | WRITE_SCHEMA | 是 | +| READ_TEMPLATE_APPLICATION | 否 | -- IGNORE | | +| SHOW_CONTINUOUS_QUERIES | 否 | -- IGNORE | | +| CREATE_PIPEPLUGIN | 否 | USE_PIPE | 否 | +| DROP_PIPEPLUGINS | 否 | USE_PIPE | 否 | +| SHOW_PIPEPLUGINS | 否 | -- IGNORE | | +| CREATE_PIPE | 否 | USE_PIPE | 否 | +| START_PIPE | 否 | USE_PIPE | 否 | +| STOP_PIPE | 否 | USE_PIPE | 否 | +| DROP_PIPE | 否 | USE_PIPE | 否 | +| SHOW_PIPES | 否 | -- IGNORE | | +| CREATE_VIEW | 是 | WRITE_SCHEMA | 是 | +| ALTER_VIEW | 是 | WRITE_SCHEMA | 是 | +| RENAME_VIEW | 是 | WRITE_SCHEMA | 是 | +| DELETE_VIEW | 是 | WRITE_SCHEMA | 是 | diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md b/src/zh/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md index 1c30b63db..0326faf02 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/Data-Sync_timecho.md @@ -585,50 +585,50 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -|-----------------------------| ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | ------------ | -| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +|-----------------------------| ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |----------------------------------| +| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | #### iotdb-air-gap-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -| ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | -------- | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| air-gap.handshake-timeout-ms | 发送端与接收端在首次尝试建立连接时握手请求的超时时长,单位:毫秒 | Integer | 选填 | 5000 | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +| ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |-----------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| air-gap.handshake-timeout-ms | 发送端与接收端在首次尝试建立连接时握手请求的超时时长,单位:毫秒 | Integer | 选填 | 5000 | #### iotdb-thrift-ssl-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | ------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| ssl.trust-store-path | 连接目标端 DataNode 所需的 trust store 证书路径 | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| ssl.trust-store-pwd | 连接目标端 DataNode 所需的 trust store 证书密码 | Integer | 必填 | - | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |-----------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| ssl.trust-store-path | 连接目标端 DataNode 所需的 trust store 证书路径 | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| ssl.trust-store-pwd | 连接目标端 DataNode 所需的 trust store 证书密码 | Integer | 必填 | - | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription.md b/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md similarity index 99% rename from src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription.md rename to src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md index cb46617a5..8c95f84f8 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_apache.md @@ -127,7 +127,7 @@ SHOW SUBSCRIPTIONS ON ## 4. API 接口 -除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API.md))。 +除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API_apache))。 ## 5. 常见问题 diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md b/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md new file mode 100644 index 000000000..77267b8e7 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/User-Manual/Data-subscription_timecho.md @@ -0,0 +1,144 @@ +# 数据订阅 + +## 1. 功能介绍 + +IoTDB 数据订阅模块(又称 IoTDB 订阅客户端)是IoTDB V1.3.3 版本后支持的功能,它为用户提供了一种区别于数据查询的流式数据消费方式。它参考了 Kafka 等消息队列产品的基本概念和逻辑,**提供数据订阅和消费接口**,但并不是为了完全替代这些消费队列的产品,更多的是在简单流式获取数据的场景为用户提供更加便捷的数据订阅服务。 + +在下面应用场景中,使用 IoTDB 订阅客户端消费数据会有显著的优势: + +1. **持续获取最新数据**:使用订阅的方式,比定时查询更实时、应用编程更简单、系统负担更小; +2. **简化数据推送至第三方系统**:无需在 IoTDB 内部开发不同系统的数据推送组件,可以在第三方系统内实现数据的流式获取,更方便将数据发送至 Flink、Kafka、DataX、Camel、MySQL、PG 等系统。 + +## 2. 主要概念 + +IoTDB 订阅客户端包含 3 个核心概念:Topic、Consumer、Consumer Group,具体关系如下图 + +
+ +
+ +1. **Topic(主题)**: Topic 是 IoTDB 的数据空间,由路径和时间范围表示(如 root.** 的全时间范围)。消费者可以订阅这些主题的数据(当前已有的和未来写入的)。不同于 Kafka,IoTDB 可在数据入库后再创建 Topic,且输出格式可选择 Message 或 TsFile 两种。 + +2. **Consumer(消费者)**: Consumer 是 IoTDB 的订阅客户端,负责接收和处理发布到特定 Topic 的数据。Consumer 从队列中获取数据并进行相应的处理。在 IoTDB 订阅客户端中提供了两种类型的 Consumers: + - 一种是 `SubscriptionPullConsumer`,对应的是消息队列中的 pull 消费模式,用户代码需要主动调用数据获取逻辑 + - 一种是 `SubscriptionPushConsumer`,对应的是消息队列中的 push 消费模式,用户代码由新到达的数据事件触发 + +3. **Consumer Group(消费者组)**: Consumer Group 是一组 Consumers 的集合,拥有相同 Consumer Group ID 的消费者属于同一个消费者组。Consumer Group 有以下特点: + - Consumer Group 与 Consumer 为一对多的关系。即一个 consumer group 中的 consumers 可以有任意多个,但不允许一个 consumer 同时加入多个 consumer groups + - 允许一个 Consumer Group 中有不同类型的 Consumer(`SubscriptionPullConsumer` 和 `SubscriptionPushConsumer`) + - 一个 topic 不需要被一个 consumer group 中的所有 consumer 订阅 + - 当同一个 Consumer Group 中不同的 Consumers 订阅了相同的 Topic 时,该 Topic 下的每条数据只会被组内的一个 Consumer 处理,确保数据不会被重复处理 + +## 3. SQL 语句 + +### 3.1 Topic 管理 + +IoTDB 支持通过 SQL 语句对 Topic 进行创建、删除、查看操作。Topic状态变化如下图所示: + +
+ +
+ +#### 3.1.1 创建 Topic + +SQL 语句为: + +```SQL + CREATE TOPIC [IF NOT EXISTS] + WITH ( + [ = ,], + ); +``` +**IF NOT EXISTS 语义**:用于创建操作中,确保当指定 Topic 不存在时,执行创建命令,防止因尝试创建已存在的 Topic 而导致报错。 + +各参数详细解释如下: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :-------------------------------------------- | :--------------------------------- | :----------------------------------------------------------- | +| **path** | optional: `root.**` | topic 对应订阅数据时间序列的路径 path,表示一组需要订阅的时间序列集合 | +| **start-time** | optional: `MIN_VALUE` | topic 对应订阅数据时间序列的开始时间(event time)可以为 ISO 格式,例如 2011-12-03T10:15:30 或 2011-12-03T10:15:30+01:00也可以为 long 值,含义为裸时间戳,单位与数据库时间戳精度一致支持特殊 value **`now`**,含义为 topic 的创建时间,当 start-time 为 `now` 且 end-time 为 MAX_VALUE 时表示只订阅实时数据 | +| **end-time** | optional: `MAX_VALUE` | topic 对应订阅数据时间序列的结束时间(event time)可以为 ISO 格式,例如 2011-12-03T10:15:30 或 2011-12-03T10:15:30+01:00也可以为 long 值,含义为裸时间戳,单位与数据库时间戳精度一致支持特殊 value `now`,含义为 topic 的创建时间,当 end-time 为 `now` 且 start-time 为 MIN_VALUE 时表示只订阅历史数据 | +| **processor** | optional: `do-nothing-processor` | processor 插件名及其参数配置,表示对原始订阅数据应用的自定义处理逻辑,可以通过类似 pipe processor 插件的方式指定 | +| **format** | optional: `SessionDataSetsHandler` | 表示从该主题订阅出的数据呈现形式,目前支持下述两种数据形式:`SessionDataSetsHandler`:使用 `SubscriptionSessionDataSetsHandler` 获取从该主题订阅出的数据,消费者可以按行消费每条数据`TsFileHandler`:使用 `SubscriptionTsFileHandler` 获取从该主题订阅出的数据,消费者可以直接订阅到存储相应数据的 TsFile | +| **mode** **(v1.3.3.2 及之后版本支持)** | option: `live` | topic 对应的订阅模式,有两个选项:`live`:订阅该主题时,订阅的数据集模式为动态数据集,即可以不断消费到最新的数据`snapshot`:consumer 订阅该主题时,订阅的数据集模式为静态数据集,即 consumer group 订阅该主题的时刻(不是创建主题的时刻)数据的 snapshot;形成订阅后的静态数据集不支持 TTL | +| **loose-range** **(v1.3.3.2 及之后版本支持)** | option: `""` | String: 是否严格按照 path 和 time range 来筛选该 topic 对应的数据,例如:`""`:严格按照 path 和 time range 来筛选该 topic 对应的数据`"time"`:不严格按照 time range 来筛选该 topic 对应的数据(粗筛);严格按照 path 来筛选该 topic 对应的数据`"path"`:不严格按照 path 来筛选该 topic 对应的数据(粗筛);严格按照 time range 来筛选该 topic 对应的数据`"time, path"` / `"path, time"` / `"all"`:不严格按照 path 和 time range 来筛选该 topic 对应的数据(粗筛) | + +示例如下: + +```SQL +-- 全量订阅 +CREATE TOPIC root_all; + +-- 自定义订阅 +CREATE TOPIC IF NOT EXISTS db_timerange +WITH ( + 'path' = 'root.db.**', + 'start-time' = '2023-01-01', + 'end-time' = '2023-12-31' +); +``` + +#### 3.1.2 删除 Topic + +Topic 在没有被订阅的情况下,才能被删除,Topic 被删除时,其相关的消费进度都会被清理 + +```SQL +DROP TOPIC [IF EXISTS] ; +``` + +**IF EXISTS 语义**:用于删除操作中,确保当指定 Topic 存在时,执行删除命令,防止因尝试删除不存在的 Topic 而导致报错。 + +#### 3.1.3 查看 Topic + +```SQL +SHOW TOPICS; +SHOW TOPIC ; +``` + +结果集: + +```SQL +[TopicName|TopicConfigs] +``` + +- TopicName:主题 ID +- TopicConfigs:主题配置 + +### 3.2 查看订阅状态 + +查看所有订阅关系: + +```SQL +-- 查询所有的 topics 与 consumer group 的订阅关系 +SHOW SUBSCRIPTIONS +-- 查询某个 topic 下所有的 subscriptions +SHOW SUBSCRIPTIONS ON +``` + +结果集: + +```SQL +[TopicName|ConsumerGroupName|SubscribedConsumers] +``` + +- TopicName:主题 ID +- ConsumerGroupName:用户代码中指定的消费者组 ID +- SubscribedConsumers:该消费者组中订阅了该主题的所有客户端 ID + +## 4. API 接口 + +除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API_timecho))。 + +## 5. 常见问题 + +### 5.1 IoTDB 数据订阅与 Kafka 的区别是什么? + +1. 消费有序性 + +- **Kafka 保证消息在单个 partition 内是有序的**,当某个 topic 仅对应一个 partition 且只有一个 consumer 订阅了这个 topic,即可保证该 consumer(单线程) 消费该 topic 数据的顺序即为数据写入的顺序。 +- IoTDB 订阅客户端**不保证** consumer 消费数据的顺序即为数据写入的顺序,但会尽量反映数据写入的顺序。 + +2. 消息送达语义 + +- Kafka 可以通过配置实现 Producer 和 Consumer 的 Exactly once 语义。 +- IoTDB 订阅客户端目前无法提供 Consumer 的 Exactly once 语义。 \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md b/src/zh/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md index e5dc7c08f..6d86293d2 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/IoTDB-View_timecho.md @@ -308,7 +308,7 @@ AS SELECT temperature FROM root.db.* ``` -这里仿照了查询写回(`SELECT INTO`)对命名规则的约定,使用变量占位符来指定命名规则。可以参考:[查询写回(SELECT INTO)](../Basic-Concept/Query-Data.md#查询写回(INTO-子句)) +这里仿照了查询写回(`SELECT INTO`)对命名规则的约定,使用变量占位符来指定命名规则。可以参考:[查询写回(SELECT INTO)](../Basic-Concept/Query-Data_timecho#查询写回(INTO-子句)) 这里`root.db.*.temperature`指定了有哪些时间序列会被包含在视图中;`${2}`则指定了从时间序列中的哪个节点提取出名字来命名序列视图。 diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md b/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md index 7e6bef172..5101840d2 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_apache.md @@ -184,7 +184,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 用户在使用 UDF 时会涉及到 `USE_UDF` 权限,具备该权限的用户才被允许执行 UDF 注册、卸载和查询操作。 -更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management.md##权限管理)。 +更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management_apache##权限管理)。 ## 3. UDF 函数库 diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md b/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md index b71338c08..885f31322 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md +++ b/src/zh/UserGuide/Master/Tree/User-Manual/User-defined-function_timecho.md @@ -185,7 +185,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 用户在使用 UDF 时会涉及到 `USE_UDF` 权限,具备该权限的用户才被允许执行 UDF 注册、卸载和查询操作。 -更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management.md##权限管理)。 +更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management_timecho##权限管理)。 ## 3. UDF 函数库 diff --git a/src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API.md rename to src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API_apache.md diff --git a/src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md new file mode 100644 index 000000000..00f9b5d13 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/API/Programming-CSharp-Native-API_timecho.md @@ -0,0 +1,402 @@ + +# C# 原生接口 + +## 1. 功能介绍 + +IoTDB具备C#原生客户端驱动和对应的连接池,提供对象化接口,可以直接组装时序对象进行写入,无需拼装 SQL。推荐使用连接池,多线程并行操作数据库。 + +## 2. 使用方式 + +**环境要求:** + +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 + +**依赖安装:** + +支持使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 + +如果使用的是\\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 + +```Plain +dotnet add package Apache.IoTDB +``` + +## 3. 读写操作 + +### 3.1 TableSessionPool + +#### 3.1.1 功能描述 + +TableSessionPool 定义了与IoTDB交互的基本操作,可以执行数据插入、查询操作以及关闭会话等,同时也是一个连接池这个池可以帮助我们高效地重用连接,并且在不需要时正确地清理资源, 该接口定义了如何从池中获取会话以及如何关闭池的基本操作。 + +#### 3.1.2 方法列表 + +以下是 TableSessionPool 中定义的方法及其详细说明: + +| 方法 | 描述 | 参数 | 返回值 | +| ---------------------------------------------------------------- | ---------------------------------------------------------------- |-------------------------------------------------------------------|--------------------| +| `Open(bool enableRpcCompression)` | 打开会话连接,自定义`enableRpcCompression` | `enableRpcCompression`:是否启用`RpcCompression`,此参数需配合 Server 端配置一同使用 | `Task` | +| `Open()` | 打开会话连接,不开启`RpcCompression` | 无 | `Task` | +| `InsertAsync(Tablet tablet)` | 将一个包含时间序列数据的Tablet 对象插入到数据库中 | tablet: 要插入的Tablet对象 | `Task` | +| `ExecuteNonQueryStatementAsync(string sql)` | 执行非查询SQL语句,如DDL(数据定义语言)或DML(数据操作语言)命令 | sql: 要执行的SQL语句。 | `Task` | +| `ExecuteQueryStatementAsync(string sql)` | 执行查询SQL语句,并返回包含查询结果的SessionDataSet对象 | sql: 要执行的SQL语句。 | `Task` | +| `ExecuteQueryStatementAsync(string sql, long timeoutInMs)` | 执行查询SQL语句,并设置查询超时时间(以毫秒为单位) | sql: 要执行的查询SQL语句。
timeoutInMs: 查询超时时间(毫秒) | `Task` | +| `Close()` | 关闭会话,释放所持有的资源 | 无 | `Task` | + +#### 3.1.3 接口展示 + +```C# +public async Task Open(bool enableRpcCompression, CancellationToken cancellationToken = default) + + public async Task Open(CancellationToken cancellationToken = default) + + public async Task InsertAsync(Tablet tablet) + + public async Task ExecuteNonQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql) + + public async Task ExecuteQueryStatementAsync(string sql, long timeoutInMs) + + public async Task Close() +``` + +### 3.2 TableSessionPool.Builder + +#### 3.2.1 功能描述 + +TableSessionPool.Builder 是 TableSessionPool的构造器,用于配置和创建 TableSessionPool 的实例。允许开发者配置连接参数、会话参数和池化行为等。 + +#### 3.2.2 配置选项 + +以下是 TableSessionPool.Builder 类的可用配置选项及其默认值: + +| **配置项** | **描述** | **默认值** | +| ---------------------------------------------------- | ---------------------------------------------------------------- |---------------------| +| `SetHost(string host)` | 设置IoTDB的节点 host | `localhost` | +| `SetPort(int port)` | 设置IoTDB的节点端口 | `6667` | +| `SetNodeUrls(List nodeUrls)` | 设置IoTDB集群的节点URL列表,当设置此项时会忽略SetHost和SetPort | `无 ` | +| `SetUsername(string username)` | 设置连接的用户名 | `"root"` | +| `SetPassword(string password)` | 设置连接的密码 | `"TimechoDB@2021"` //V2.0.6.x 之前默认密码是root | +| `SetFetchSize(int fetchSize)` | 设置查询结果的获取大小 | `1024 ` | +| `SetZoneId(string zoneId)` | 设置时区相关的ZoneId | `UTC+08:00` | +| `SetPoolSize(int poolSize)` | 设置会话池的最大大小,即池中允许的最大会话数 | `8 ` | +| `SetEnableRpcCompression(bool enableRpcCompression)` | 是否启用RPC压缩 | `false` | +| `SetConnectionTimeoutInMs(int timeout)` | 设置连接超时时间(毫秒) | `500` | +| `SetDatabase(string database)` | 设置目标数据库名称 | ` "" ` | + +#### 3.2.3 接口展示 + +```c# +public Builder SetHost(string host) + { + _host = host; + return this; + } + + public Builder SetPort(int port) + { + _port = port; + return this; + } + + public Builder SetUsername(string username) + { + _username = username; + return this; + } + + public Builder SetPassword(string password) + { + _password = password; + return this; + } + + public Builder SetFetchSize(int fetchSize) + { + _fetchSize = fetchSize; + return this; + } + + public Builder SetZoneId(string zoneId) + { + _zoneId = zoneId; + return this; + } + + public Builder SetPoolSize(int poolSize) + { + _poolSize = poolSize; + return this; + } + + public Builder SetEnableRpcCompression(bool enableRpcCompression) + { + _enableRpcCompression = enableRpcCompression; + return this; + } + + public Builder SetConnectionTimeoutInMs(int timeout) + { + _connectionTimeoutInMs = timeout; + return this; + } + + public Builder SetNodeUrls(List nodeUrls) + { + _nodeUrls = nodeUrls; + return this; + } + + protected internal Builder SetSqlDialect(string sqlDialect) + { + _sqlDialect = sqlDialect; + return this; + } + + public Builder SetDatabase(string database) + { + _database = database; + return this; + } + + public Builder() + { + _host = "localhost"; + _port = 6667; + _username = "root"; + _password = "TimechoDB@2021"; //V2.0.6.x 之前默认密码是root + _fetchSize = 1024; + _zoneId = "UTC+08:00"; + _poolSize = 8; + _enableRpcCompression = false; + _connectionTimeoutInMs = 500; + _sqlDialect = IoTDBConstant.TABLE_SQL_DIALECT; + _database = ""; + } + + public TableSessionPool Build() + { + SessionPool sessionPool; + // if nodeUrls is not empty, use nodeUrls to create session pool + if (_nodeUrls.Count > 0) + { + sessionPool = new SessionPool(_nodeUrls, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + else + { + sessionPool = new SessionPool(_host, _port, _username, _password, _fetchSize, _zoneId, _poolSize, _enableRpcCompression, _connectionTimeoutInMs, _sqlDialect, _database); + } + return new TableSessionPool(sessionPool); + } +``` + +## 4. 示例代码 + +完整示例:[samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs](https://github.com/apache/iotdb-client-csharp/blob/main/samples/Apache.IoTDB.Samples/TableSessionPoolTest.cs) + +```c# +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Apache.IoTDB.DataStructure; + +namespace Apache.IoTDB.Samples; + +public class TableSessionPoolTest +{ + private readonly SessionPoolTest sessionPoolTest; + + public TableSessionPoolTest(SessionPoolTest sessionPoolTest) + { + this.sessionPoolTest = sessionPoolTest; + } + + public async Task Test() + { + await TestCleanup(); + + await TestSelectAndInsert(); + await TestUseDatabase(); + // await TestCleanup(); + } + + + public async Task TestSelectAndInsert() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("CREATE DATABASE test2"); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // or use full qualified table name + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table test1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + + await tableSessionPool.ExecuteNonQueryStatementAsync( + "create table table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + // show tables by specifying another database + // using SHOW tables FROM + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES FROM test1"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + var tableName = "testTable1"; + List columnNames = + new List { + "region_id", + "plant_id", + "device_id", + "model", + "temperature", + "humidity" }; + List dataTypes = + new List{ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.FLOAT, + TSDataType.DOUBLE}; + List columnCategories = + new List{ + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.ATTRIBUTE, + ColumnCategory.FIELD, + ColumnCategory.FIELD}; + var values = new List> { }; + var timestamps = new List { }; + for (long timestamp = 0; timestamp < 100; timestamp++) + { + timestamps.Add(timestamp); + values.Add(new List { "1", "5", "3", "A", 1.23F + timestamp, 111.1 + timestamp }); + } + var tablet = new Tablet(tableName, columnNames, columnCategories, dataTypes, values, timestamps); + + await tableSessionPool.InsertAsync(tablet); + + + res = await tableSessionPool.ExecuteQueryStatementAsync("select * from testTable1 " + + "where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + + public async Task TestUseDatabase() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetDatabase("test1") + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + + // show tables from current database + var res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("use test2"); + + // show tables from current database + res = await tableSessionPool.ExecuteQueryStatementAsync("SHOW TABLES"); + res.ShowTableNames(); + while (res.HasNext()) Console.WriteLine(res.Next()); + await res.Close(); + + await tableSessionPool.Close(); + } + + public async Task TestCleanup() + { + var tableSessionPool = new TableSessionPool.Builder() + .SetNodeUrls(sessionPoolTest.nodeUrls) + .SetUsername(sessionPoolTest.username) + .SetPassword(sessionPoolTest.password) + .SetFetchSize(1024) + .Build(); + + await tableSessionPool.Open(false); + + if (sessionPoolTest.debug) tableSessionPool.OpenDebugMode(); + + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test1"); + await tableSessionPool.ExecuteNonQueryStatementAsync("drop database test2"); + + await tableSessionPool.Close(); + } +} +``` diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API.md b/src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API.md rename to src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API_apache.md diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md new file mode 100644 index 000000000..559c6d6e6 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/API/Programming-Cpp-Native-API_timecho.md @@ -0,0 +1,461 @@ + + +# C++ 原生接口 + +## 1. 依赖 + +- Java 8+ +- Flex +- Bison 2.7+ +- Boost 1.56+ +- OpenSSL 1.0+ +- GCC 5.5.0+ + + +## 2. 安装 + +### 2.1 安装相关依赖 + +- **MAC** + 1. 安装 Bison : + + 使用下面 brew 命令安装 bison 版本: + ```shell + brew install bison + ``` + + 2. 安装 Boost :确保安装最新的 Boost 版本。 + + ```shell + brew install boost + ``` + + 3. 检查 OpenSSL :确保 openssl 库已安装,默认的 openssl 头文件路径为"/usr/local/opt/openssl/include" + + 如果在编译过程中出现找不到 openssl 的错误,尝试添加`-Dopenssl.include.dir=""` + + +- **Ubuntu 16.04+ 或其他 Debian 系列** + + 使用以下命令安装所赖: + + ```shell + sudo apt-get update + sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-dev + ``` + + +- **CentOS 7.7+/Fedora/Rocky Linux 或其他 Red-hat 系列** + + 使用 yum 命令安装依赖: + + ```shell + sudo yum update + sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel + ``` + + +- **Windows** + +1. 构建编译环境 + - 安装 MS Visual Studio(推荐安装 2019+ 版本):安装时需要勾选 Visual Studio C/C++ IDE and compiler(supporting CMake, Clang, MinGW) + - 下载安装 [CMake](https://cmake.org/download/) 。 + +2. 下载安装 Flex、Bison + - 下载 [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/) + - 下载后需要将可执行文件重命名为 flex.exe 和 bison.exe 以保证编译时能够被找到,添加可执行文件的目录到 PATH 环境变量中 + +3. 安装 Boost 库 + - 下载 [Boost](https://www.boost.org/users/download/) + - 本地编译 Boost :依次执行 bootstrap.bat 和 b2.exe + - 添加 Boost 安装目录到 PATH 环境变量中,例如 `C:\Program Files (x86)\boost_1_78_0` + +4. 安装 OpenSSL + - 下载安装 [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) + - 添加 OpenSSL 下的 include 目录到 PATH 环境变量中 + + +### 2.2 执行编译 + +从 git 克隆源代码: +```shell +git clone https://github.com/apache/iotdb.git +``` + +默认的主分支是 master 分支,如果你想使用某个发布版本,请切换分支 (如 1.3.2 版本): +```shell +git checkout rc/1.3.2 +``` + +在 IoTDB 根目录下执行 maven 编译: + +- Mac 或 glibc 版本 >= 2.32 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- glibc 版本 >= 2.31 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT + ``` + +- glibc 版本 >= 2.17 的 Linux + ```shell + ./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT + ``` + +- 使用 Visual Studio 2022 的 Windows + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp + ``` + +- 使用 Visual Studio 2019 的 Windows + ```batch + .\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 16 2019" -Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT + ``` + - 如果没有将 Boost 库地址加入 PATH 环境变量,在编译命令中还需添加相关参数,例如:`-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"` + +编译成功后,打包好的库文件位于 `iotdb-client/client-cpp/target` 中,同时可以在 `example/client-cpp-example/target` 下找到编译好的示例程序。 + +### 2.3 编译 Q&A + +Q:Linux 上的环境有哪些要求呢? + +A: +- 已知依赖的 glibc (x86_64 版本) 最低版本要求为 2.17,GCC 最低版本为 5.5 +- 已知依赖的 glibc (ARM 版本) 最低版本要求为 2.31,GCC 最低版本为 10.2 +- 如果不满足上面的要求,可以尝试自己本地编译 Thrift + - 下载 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 这里的代码 + - 执行 `./mvnw clean install` + - 回到 iotdb 代码目录执行 `./mvnw clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp` + + +Q:Linux 编译报错`undefined reference to '_libc_sinle_thread'`如何处理? + +A: +- 该问题是用于默认的预编译 Thrift 依赖了过高的 glibc 版本导致的 +- 可以尝试在编译的 maven 命令中增加 `-Diotdb-tools-thrift.version=0.14.1.1-glibc223-SNAPSHOT` 或者 `-Diotdb-tools-thrift.version=0.14.1.1-old-glibc-SNAPSHOT` + +Q:如果在 Windows 上需要使用 Visual Studio 2017 或更早版本进行编译,要怎么做? + +A: +- 可以尝试自己本地编译 Thrift 后再进行客户端的编译 + - 下载 https://github.com/apache/iotdb-bin-resources/tree/iotdb-tools-thrift-v0.14.1.0/iotdb-tools-thrift 这里的代码 + - 执行 `.\mvnw.cmd clean install` + - 回到 iotdb 代码目录执行 `.\mvnw.cmd clean package -pl example/client-cpp-example -am -DskipTests -P with-cpp -Dcmake.generator="Visual Studio 15 2017"` + +Q: Windows 上使用 Visual Studio 进行编译时出现乱码,如何解决? + +A: +- 该问题是由于项目整体使用 utf-8 编码,而编译用到的一些 windows 系统文件编码不是 utf-8(系统编码默认跟随地区,在中国为 GBK) +- 可以在控制面板中更改系统区域设置,具体操作方法为:打开控制面板 -> 时钟和区域 -> 区域,切换到管理选项卡,在 "非Unicode程序的语言" 下,选择更改系统区域设置,勾选 `Beta版:使用Unicode UTF-8提供全球语言支持` 后重启电脑。(细节可能随windows版本有差异,可在网上寻找详细教程) +- 注意,修改 windows 系统编码后可能会导致一些其他使用 GBK 编码的程序出现乱码,将系统区域改回后可复原,请自行斟酌。 + +## 3. 使用方式 + +### 3.1 TableSession 类 + +C++ 客户端的操作均通过 TableSession 类进行,下面将给出 TableSession 接口中定义的方法说明。 + +#### 3.1.1 方法列表 + +1. `insert(Tablet& tablet, bool sorted = false)`,将一个包含时间序列数据的Tablet对象插入到数据库中,sorted参数指明tablet中的行是否已按时间排序。 +2. `executeNonQueryStatement(string& sql)`,执行非查询SQL语句,如DDL(数据定义语言)或DML(数据操作语言)命令。 +3. `executeQueryStatement(string& sql)`,执行查询SQL语句,并返回包含查询结果的SessionDataSet对象,可选timeoutInMs参数指示超时返回时间。 +4. `open(bool enableRPCCompression = false)`,开启连接,并决定是否启用RPC压缩(客户端状态须与服务端一致,默认不开启)。 +5. `close()`,关闭连接。 + +#### 3.1.2 接口展示 + +```cpp +class TableSession { +private: + Session* session; +public: + TableSession(Session* session) { + this->session = session; + } + void insert(Tablet& tablet, bool sorted = false); + void executeNonQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql); + unique_ptr executeQueryStatement(const std::string& sql, int64_t timeoutInMs); + string getDatabase(); //获取当前选择的database,可由executeNonQueryStatement代替 + void open(bool enableRPCCompression = false); + void close(); +}; +``` + +### 3.2 TableSessionBuilder 类 + +TableSessionBuilder类是一个构建器,用于配置和创建TableSession类的实例,通过它可以在创建实例时方便地设置连接参数、查询参数等。 + +#### 3.2.1 使用示例 + +```cpp +//设置连接的IP、端口、用户名、密码 +//设置的顺序任意,确保最后调用build()即可,创建的实例默认已进行open()连接操作 +session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->build(); +``` + +#### 3.2.2 可设置的参数列表 + +| **参数名** | **描述** | **默认值** | +| :---: | :---: |:-------------------------:| +| host | 设置连接的节点IP | "127.0.0.1" ("localhost") | +| rpcPort | 设置连接的节点端口 | 6667 | +| username | 设置连接的用户名 | "root" | +| password | 设置连接密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | +| zoneId | 设置时区相关的ZoneId | "" | +| fetchSize | 设置查询结果的获取大小 | 10000 | +| database | 设置目标数据库名称 | "" | + + +## 4. 示例代码 + +示例工程源代码: + +- `example/client-cpp-example/src/TableModelSessionExample.cpp` : [TableModelSessionExample](https://github.com/apache/iotdb/tree/rc/2.0.1/example/client-cpp-example/src/TableModelSessionExample.cpp) + +编译成功后,示例代码工程位于 `example/client-cpp-example/target` + +```cpp +#include "TableSession.h" +#include "TableSessionBuilder.h" + +using namespace std; + +TableSession *session; + +void insertRelationalTablet() { + + vector> schemaList { + make_pair("region_id", TSDataType::TEXT), + make_pair("plant_id", TSDataType::TEXT), + make_pair("device_id", TSDataType::TEXT), + make_pair("model", TSDataType::TEXT), + make_pair("temperature", TSDataType::FLOAT), + make_pair("humidity", TSDataType::DOUBLE) + }; + + vector columnTypes = { + ColumnCategory::TAG, + ColumnCategory::TAG, + ColumnCategory::TAG, + ColumnCategory::ATTRIBUTE, + ColumnCategory::FIELD, + ColumnCategory::FIELD + }; + + Tablet tablet("table1", schemaList, columnTypes, 100); + + for (int row = 0; row < 100; row++) { + int rowIndex = tablet.rowSize++; + tablet.timestamps[rowIndex] = row; + tablet.addValue("region_id", rowIndex, "1"); + tablet.addValue("plant_id", rowIndex, "5"); + tablet.addValue("device_id", rowIndex, "3"); + tablet.addValue("model", rowIndex, "A"); + tablet.addValue("temperature", rowIndex, 37.6F); + tablet.addValue("humidity", rowIndex, 111.1); + if (tablet.rowSize == tablet.maxRowNumber) { + session->insert(tablet); + tablet.reset(); + } + } + + if (tablet.rowSize != 0) { + session->insert(tablet); + tablet.reset(); + } +} + +void Output(unique_ptr &dataSet) { + for (const string &name: dataSet->getColumnNames()) { + cout << name << " "; + } + cout << endl; + while (dataSet->hasNext()) { + cout << dataSet->next()->toString(); + // 可通过 RowRecord* row = dataSet->next(); + // for(auto field: row.fields) field.intV/longV/stringV 来获取值 + } + cout << endl; +} + +void OutputWithType(unique_ptr &dataSet) { + for (const string &name: dataSet->getColumnNames()) { + cout << name << " "; + } + cout << endl; + for (const string &type: dataSet->getColumnTypeList()) { + cout << type << " "; + } + cout << endl; + while (dataSet->hasNext()) { + cout << dataSet->next()->toString(); + } + cout << endl; +} + +int main() { + try { + session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->build(); + + + cout << "[Create Database db1,db2]\n" << endl; + try { + session->executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS db1"); + session->executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Use db1 as database]\n" << endl; + try { + session->executeNonQueryStatement("USE db1"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Create Table table1,table2]\n" << endl; + try { + session->executeNonQueryStatement("create table db1.table1(region_id STRING TAG, plant_id STRING TAG, device_id STRING TAG, model STRING ATTRIBUTE, temperature FLOAT FIELD, humidity DOUBLE FIELD) with (TTL=3600000)"); + session->executeNonQueryStatement("create table db2.table2(region_id STRING TAG, plant_id STRING TAG, color STRING ATTRIBUTE, temperature FLOAT FIELD, speed DOUBLE FIELD) with (TTL=6600000)"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show Tables]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show tables from specific database]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES FROM db1"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[InsertTablet]\n" << endl; + try { + insertRelationalTablet(); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Query Table Data]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SELECT * FROM table1" + " where region_id = '1' and plant_id in ('3', '5') and device_id = '3'"); + OutputWithType(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + session->close(); + + // specify database in constructor + session = (new TableSessionBuilder()) + ->host("127.0.0.1") + ->rpcPort(6667) + ->username("root") + ->password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root + ->database("db1") + ->build(); + + cout << "[Show tables from current database(db1)]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Change database to db2]\n" << endl; + try { + session->executeNonQueryStatement("USE db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Show tables from current database(db2)]\n" << endl; + try { + unique_ptr dataSet = session->executeQueryStatement("SHOW TABLES"); + Output(dataSet); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "[Drop Database db1,db2]\n" << endl; + try { + session->executeNonQueryStatement("DROP DATABASE db1"); + session->executeNonQueryStatement("DROP DATABASE db2"); + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + + cout << "session close\n" << endl; + session->close(); + + delete session; + + cout << "finished!\n" << endl; + } catch (IoTDBConnectionException &e) { + cout << e.what() << endl; + } catch (IoTDBException &e) { + cout << e.what() << endl; + } + return 0; +} +``` + +## 5. FAQ + +### 5.1 Thrift 编译相关问题 + +1. MAC:本地 Maven 编译 Thrift 时如出现以下链接的问题,可以尝试将 xcode-commandline 版本从 12 降低到 11.5 + https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087 + + +2. Windows:Maven 编译 Thrift 时需要使用 wget 下载远端文件,可能出现以下报错: + ``` + Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser + ``` + + 解决方法: + - 尝试删除 ".m2\repository\\.cache\" 目录并重试。 + - 在添加 pom 文件对应的 download-maven-plugin 中添加 "\true\" diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API.md b/src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API.md rename to src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API_apache.md diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md new file mode 100644 index 000000000..da1533a2e --- /dev/null +++ b/src/zh/UserGuide/latest-Table/API/Programming-Go-Native-API_timecho.md @@ -0,0 +1,593 @@ + + +# Go 原生接口 + +## 1. 使用方法 +### 1.1 依赖 + +* golang >= 1.13 +* make >= 3.0 +* curl >= 7.1.1 +* thrift 0.15.0 +* Linux、Macos 或其他类 unix 系统 +* Windows+bash (下载 IoTDB Go client 需要 git ,通过 WSL、cygwin、Git Bash 任意一种方式均可) + +### 1.2 安装方法 + +* 通过 go mod + +```sh +# 切换到 GOPATH 的 HOME 路径,启用 Go Modules 功能 +export GO111MODULE=on + +# 配置 GOPROXY 环境变量 +export GOPROXY=https://goproxy.io + +# 创建命名的文件夹或目录,并切换当前目录 +mkdir session_example && cd session_example + +# 保存文件,自动跳转到新的地址 +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +# 初始化 go module 环境 +go mod init session_example + +# 下载依赖包 +go mod tidy + +# 编译并运行程序 +go run session_example.go +``` + +* 通过 GOPATH + +```sh +# get thrift 0.13.0 +go get github.com/apache/thrift@0.13.0 + +# 递归创建目录 +mkdir -p $GOPATH/src/iotdb-client-go-example/session_example + +# 切换到当前目录 +cd $GOPATH/src/iotdb-client-go-example/session_example + +# 保存文件,自动跳转到新的地址 +curl -o session_example.go -L https://github.com/apache/iotdb-client-go/raw/main/example/session_example.go + +# 初始化 go module 环境 +go mod init + +# 下载依赖包 +go mod tidy + +# 编译并运行程序 +go run session_example.go +``` + +## 2. ITableSession 接口 +### 2.1 功能描述 + +ITableSession 接口定义了与 IoTDB 交互的基本操作,可以执行数据插入、查询操作以及关闭会话等,非线程安全。 + +### 2.2 方法列表 + +以下是 ITableSession 接口中定义的方法及其详细说明: + +| **方法名** | **描述** | **参数** | **返回值** | **返回异常** | +| -------------------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------- | +| `Insert(tablet *Tablet)` | 将一个包含时间序列数据的Tablet 插入到数据库中| `tablet`: 要插入的`Tablet`| `TSStatus`:执行结果的状态,由 common 包定义。 | `errer`:操作过程中的错误(如连接失败)。 | +| `xecuteNonQueryStatement(sql string)`| 执行非查询 SQL 语句,如 DDL (数据定义语言)或 DML (数据操作语言)命令 | `sql`: 要执行的 SQL 语句。| 同上 | 同上| +| `ExecuteQueryStatement (sql string, timeoutInMs *int64)` | 执行查询 SQL 语句,并返回查询结果集 | `sql`: 要执行的查询 SQL 语句。`timeoutInMs`: 查询超时时间(毫秒) | `SessionDataSet`:查询结果数据集。 | `errer`:操作过程中的错误(如连接失败)。 | +| `Close()` | 关闭会话,释放所持有的资源 | 无 | 无 | `errer`:关闭连接过程中的错误 | + +### 2.3 接口展示 +1. ITableSession + +```go +// ITableSession defines an interface for interacting with IoTDB tables. +// It supports operations such as data insertion, executing queries, and closing the session. +// Implementations of this interface are expected to manage connections and ensure +// proper resource cleanup. +// +// Each method may return an error to indicate issues such as connection errors +// or execution failures. +// +// Since this interface includes a Close method, it is recommended to use +// defer to ensure the session is properly closed. +type ITableSession interface { + + // Insert inserts a Tablet into the database. + // + // Parameters: + // - tablet: A pointer to a Tablet containing time-series data to be inserted. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + Insert(tablet *Tablet) (r *common.TSStatus, err error) + + // ExecuteNonQueryStatement executes a non-query SQL statement, such as a DDL or DML command. + // + // Parameters: + // - sql: The SQL statement to execute. + // + // Returns: + // - r: A pointer to TSStatus indicating the execution result. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err error) + + // ExecuteQueryStatement executes a query SQL statement and returns the result set. + // + // Parameters: + // - sql: The SQL query statement to execute. + // - timeoutInMs: A pointer to the timeout duration in milliseconds for the query execution. + // + // Returns: + // - result: A pointer to SessionDataSet containing the query results. + // - err: An error if an issue occurs during the operation, such as a connection error or execution failure. + ExecuteQueryStatement(sql string, timeoutInMs *int64) (*SessionDataSet, error) + + // Close closes the session, releasing any held resources. + // + // Returns: + // - err: An error if there is an issue with closing the IoTDB connection. + Close() (err error) +} +``` + +2. 构造 TableSession + +* Config 中不需要手动设置 sqlDialect,使用时只需要使用对应的 NewSession 函数 + +```Go +type Config struct { + Host string + Port string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Version Version + Database string +} + +type ClusterConfig struct { + NodeUrls []string //ip:port + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + sqlDialect string + Database string +} + +// NewTableSession creates a new TableSession instance using the provided configuration. +// +// Parameters: +// - config: The configuration for the session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// - connectionTimeoutInMs: The timeout in milliseconds for establishing a connection. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewTableSession(config *Config, enableRPCCompression bool, connectionTimeoutInMs int) (ITableSession, error) + +// NewClusterTableSession creates a new TableSession instance for a cluster setup. +// +// Parameters: +// - clusterConfig: The configuration for the cluster session. +// - enableRPCCompression: A boolean indicating whether RPC compression is enabled. +// +// Returns: +// - An ITableSession instance if the session is successfully created. +// - An error if there is an issue during session initialization. +func NewClusterTableSession(clusterConfig *ClusterConfig, enableRPCCompression bool) (ITableSession, error) +``` + +> 注意: +> +> 通过 *NewTableSession 或 NewClusterTableSession* 得到的 TableSession,连接已经建立,不需要额外的 open 操作。 + +### 2.4 示例代码 + +```Go +package main + +import ( + "flag" + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "math/rand" + "strconv" + "time" +) + +func main() { + flag.Parse() + config := &client.Config{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_session", + } + session, err := client.NewTableSession(config, false, 0) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + checkError(session.ExecuteNonQueryStatement("create database test_db")) + checkError(session.ExecuteNonQueryStatement("use test_db")) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + insertRelationalTablet(session) + showTables(session) + query(session) +} + +func getTextValueFromDataSet(dataSet *client.SessionDataSet, columnName string) string { + if dataSet.IsNull(columnName) { + return "null" + } else { + return dataSet.GetText(columnName) + } +} + +func insertRelationalTablet(session client.ITableSession) { + tablet, err := client.NewRelationalTablet("t1", []*client.MeasurementSchema{ + { + Measurement: "id1", + DataType: client.STRING, + }, + { + Measurement: "id2", + DataType: client.STRING, + }, + { + Measurement: "s1", + DataType: client.TEXT, + }, + { + Measurement: "s2", + DataType: client.TEXT, + }, + }, []client.ColumnCategory{client.TAG, client.TAG, client.FIELD, client.FIELD}, 1024) + if err != nil { + log.Fatal("Failed to create relational tablet {}", err) + } + ts := time.Now().UTC().UnixNano() / 1000000 + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_"+strconv.Itoa(row), 0, row) + tablet.SetValueAt("id2_field_"+strconv.Itoa(row), 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) + + tablet.Reset() + + for row := 0; row < 16; row++ { + ts++ + tablet.SetTimestamp(ts, row) + tablet.SetValueAt("id1_field_1", 0, row) + tablet.SetValueAt("id2_field_1", 1, row) + tablet.SetValueAt("s1_value_"+strconv.Itoa(row), 2, row) + tablet.SetValueAt("s2_value_"+strconv.Itoa(row), 3, row) + + nullValueColumn := rand.Intn(4) + tablet.SetValueAt(nil, nullValueColumn, row) + tablet.RowSize++ + } + checkError(session.Insert(tablet)) +} + +func showTables(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("tableName is", dataSet.GetText("TableName")) + } +} + +func query(session client.ITableSession) { + timeout := int64(2000) + dataSet, err := session.ExecuteQueryStatement("select * from t1", &timeout) + if err != nil { + log.Fatal(err) + } + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Printf("%v %v %v %v", getTextValueFromDataSet(dataSet, "id1"), getTextValueFromDataSet(dataSet, "id2"), getTextValueFromDataSet(dataSet, "s1"), getTextValueFromDataSet(dataSet, "s2")) + } +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + +## 3. TableSessionPool 接口 +### 3.1 功能描述 + +TableSessionPool 是一个用于管理 ITableSession 实例的池。这个池可以帮助我们高效地重用连接,并且在不需要时正确地清理资源, 该接口定义了如何从池中获取会话以及如何关闭池的基本操作。 + +### 3.2 方法列表 + +| **方法名** | **描述** | **返回值** | **返回异常** | +| -------------------- | -------------------------------------------------------------------- | --------------------------- | --------------------------------- | +| `GetSession()` | 从池中获取一个 ITableSession 实例,用于与 IoTDB 交互。 | `ITableSession `实例| `error`:获取失败的错误原因 | +| `Close()` | 关闭会话池,释放任何持有的资源。关闭后,不能再从池中获取新的会话。 | 无 | 无 | + +### 3.3 接口展示 +1. TableSessionPool + +```Go +// TableSessionPool manages a pool of ITableSession instances, enabling efficient +// reuse and management of resources. It provides methods to acquire a session +// from the pool and to close the pool, releasing all held resources. +// +// This implementation ensures proper lifecycle management of sessions, +// including efficient reuse and cleanup of resources. + +// GetSession acquires an ITableSession instance from the pool. +// +// Returns: +// - A usable ITableSession instance for interacting with IoTDB. +// - An error if a session cannot be acquired. +func (spool *TableSessionPool) GetSession() (ITableSession, error) { + return spool.sessionPool.getTableSession() +} + +// Close closes the TableSessionPool, releasing all held resources. +// Once closed, no further sessions can be acquired from the pool. +func (spool *TableSessionPool) Close() +``` + +2. 构造 TableSessionPool + +```Go +type PoolConfig struct { + Host string + Port string + NodeUrls []string + UserName string + Password string + FetchSize int32 + TimeZone string + ConnectRetryMax int + Database string + sqlDialect string +} + +// NewTableSessionPool creates a new TableSessionPool with the specified configuration. +// +// Parameters: +// - conf: PoolConfig defining the configuration for the pool. +// - maxSize: The maximum number of sessions the pool can hold. +// - connectionTimeoutInMs: Timeout for establishing a connection in milliseconds. +// - waitToGetSessionTimeoutInMs: Timeout for waiting to acquire a session in milliseconds. +// - enableCompression: A boolean indicating whether to enable compression. +// +// Returns: +// - A TableSessionPool instance. +func NewTableSessionPool(conf *PoolConfig, maxSize, connectionTimeoutInMs, waitToGetSessionTimeoutInMs int, + enableCompression bool) TableSessionPool +``` + +> 注意: +> +> * 通过 TableSessionPool 得到的 TableSession,如果已经在创建 TableSessionPool 指定了 Database,使用时可以不再指定 Database。 +> * 如果使用过程中通过 use database 指定了其他 database,在 close 放回 TableSessionPool 时会自动恢复为 TableSessionPool 所用的 database。 + +### 3.4 示例代码 + +```go +package main + +import ( + "github.com/apache/iotdb-client-go/client" + "github.com/apache/iotdb-client-go/common" + "log" + "strconv" + "sync" + "sync/atomic" + "time" +) + +func main() { + sessionPoolWithSpecificDatabaseExample() + sessionPoolWithoutSpecificDatabaseExample() + putBackToSessionPoolExample() +} + +func putBackToSessionPoolExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 4000, false) + defer sessionPool.Close() + + num := 4 + successGetSessionNum := int32(0) + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database "+dbName+"because ", err) + return + } + atomic.AddInt32(&successGetSessionNum, 1) + defer func() { + time.Sleep(6 * time.Second) + // put back to session pool + session.Close() + }() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table table_of_" + dbName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() + log.Println("success num is", successGetSessionNum) + + log.Println("All session's database have been reset.") + // the using database will automatically reset to session pool's database after the session closed + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to get session because ", err) + } + defer session.Close() + timeout := int64(3000) + dataSet, err := session.ExecuteQueryStatement("show tables", &timeout) + for { + hasNext, err := dataSet.Next() + if err != nil { + log.Fatal(err) + } + if !hasNext { + break + } + log.Println("table is", dataSet.GetText("TableName")) + } + }() + } + wg.Wait() +} + +func sessionPoolWithSpecificDatabaseExample() { + // should create database test_db before executing + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + Database: "test_db", + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + tableName := "t" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create table "+tableName+"because ", err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create table " + tableName + " (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func sessionPoolWithoutSpecificDatabaseExample() { + config := &client.PoolConfig{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "TimechoDB@2021", //V2.0.6.x 之前默认密码是root + } + sessionPool := client.NewTableSessionPool(config, 3, 60000, 8000, false) + defer sessionPool.Close() + num := 10 + var wg sync.WaitGroup + wg.Add(num) + for i := 0; i < num; i++ { + dbName := "db" + strconv.Itoa(i) + go func() { + defer wg.Done() + session, err := sessionPool.GetSession() + if err != nil { + log.Println("Failed to create database ", dbName, err) + return + } + defer session.Close() + checkError(session.ExecuteNonQueryStatement("create database " + dbName)) + checkError(session.ExecuteNonQueryStatement("use " + dbName)) + checkError(session.ExecuteNonQueryStatement("create table t1 (id1 string tag, id2 string tag, s1 text field, s2 text field)")) + }() + } + wg.Wait() +} + +func checkError(status *common.TSStatus, err error) { + if err != nil { + log.Fatal(err) + } + + if status != nil { + if err = client.VerifySuccess(status); err != nil { + log.Println(err) + } + } +} +``` + diff --git a/src/zh/UserGuide/latest-Table/API/Programming-JDBC_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-JDBC_timecho.md index 0fd3d1840..4bc3ea2bb 100644 --- a/src/zh/UserGuide/latest-Table/API/Programming-JDBC_timecho.md +++ b/src/zh/UserGuide/latest-Table/API/Programming-JDBC_timecho.md @@ -123,7 +123,7 @@ public class TableModelJDBCExample { // don't specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667?sql_dialect=table", "root", "TimechoDB@2021"); //V2.0.6.x 之前默认密码是root Statement statement = connection.createStatement()) { statement.execute("CREATE DATABASE test1"); @@ -164,7 +164,7 @@ public class TableModelJDBCExample { // specify database in url try (Connection connection = DriverManager.getConnection( - "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "root"); + "jdbc:iotdb://127.0.0.1:6667/test1?sql_dialect=table", "root", "TimechoDB@2021"); //V2.0.6.x 之前默认密码是root Statement statement = connection.createStatement()) { // show tables from current database test1 try (ResultSet resultSet = statement.executeQuery("SHOW TABLES")) { diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md index 209421a64..cf6c935a2 100644 --- a/src/zh/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md +++ b/src/zh/UserGuide/latest-Table/API/Programming-Java-Native-API_timecho.md @@ -142,17 +142,17 @@ TableSessionBuilder类是一个构建器,用于配置和创建ITableSession接 以下是TableSessionBuilder类中可用的配置选项及其默认值: -| **配置项** | **描述** | **默认值** | -| ---------------------------------------------------- | ---------------------------------------- | ------------------------------------------- | +| **配置项** | **描述** | **默认值** | +| ---------------------------------------------------- | ---------------------------------------- |---------------------------------------------| | nodeUrls(List`` nodeUrls) | 设置IoTDB集群的节点URL列表 | Collections.singletonList("localhost:6667") | | username(String username) | 设置连接的用户名 | "root" | -| password(String password) | 设置连接的密码 | "root" | +| password(String password) | 设置连接的密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | | database(String database) | 设置目标数据库名称 | null | -| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | +| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | | fetchSize(int fetchSize) | 设置查询结果的获取大小 | 5000 | | zoneId(ZoneId zoneId) | 设置时区相关的ZoneId | ZoneId.systemDefault() | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | | enableRedirection(boolean enableRedirection) | 是否启用集群节点的重定向 | true | | enableAutoFetch(boolean enableAutoFetch) | 是否启用自动获取可用DataNodes | true | | maxRetryCount(int maxRetryCount) | 设置连接尝试的最大重试次数 | 60 | @@ -161,7 +161,7 @@ TableSessionBuilder类是一个构建器,用于配置和创建ITableSession接 | trustStore(String keyStore) | 设置SSL连接的信任库路径 | null | | trustStorePwd(String keyStorePwd) | 设置SSL连接的信任库密码 | null | | enableCompression(boolean enableCompression) | 是否启用RPC压缩 | false | -| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 0(无超时) | +| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 0(无超时) | #### 3.2.3 接口展示 @@ -198,7 +198,7 @@ public class TableSessionBuilder { * * @param username the username. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "root“ */ public TableSessionBuilder username(String username); @@ -207,7 +207,7 @@ public class TableSessionBuilder { * * @param password the password. * @return the current {@link TableSessionBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //V2.0.6.x 之前默认密码是root */ public TableSessionBuilder password(String password); @@ -404,22 +404,22 @@ TableSessionPool 的构造器,用于配置和创建 ITableSessionPool 的实 以下是 TableSessionPoolBuilder 类的可用配置选项及其默认值: -| **配置项** | **描述** | **默认值** | -| ------------------------------------------------------------ | -------------------------------------------- | ------------------------------------------- | +| **配置项** | **描述** | **默认值** | +| ------------------------------------------------------------ | -------------------------------------------- |---------------------------------------------| | nodeUrls(List`` nodeUrls) | 设置IoTDB集群的节点URL列表 | Collections.singletonList("localhost:6667") | | maxSize(int maxSize) | 设置会话池的最大大小,即池中允许的最大会话数 | 5 | | user(String user) | 设置连接的用户名 | "root" | -| password(String password) | 设置连接的密码 | "root" | +| password(String password) | 设置连接的密码 | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | | database(String database) | 设置目标数据库名称 | "root" | -| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | +| queryTimeoutInMs(long queryTimeoutInMs) | 设置查询超时时间(毫秒) | 60000(1分钟) | | fetchSize(int fetchSize) | 设置查询结果的获取大小 | 5000 | | zoneId(ZoneId zoneId) | 设置时区相关的 ZoneId | ZoneId.systemDefault() | -| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | 设置从池中获取会话的超时时间(毫秒) | 30000(30秒) | -| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | -| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | +| waitToGetSessionTimeoutInMs(long waitToGetSessionTimeoutInMs) | 设置从池中获取会话的超时时间(毫秒) | 30000(30秒) | +| thriftDefaultBufferSize(int thriftDefaultBufferSize) | 设置Thrift客户端的默认缓冲区大小(字节) | 1024(1KB) | +| thriftMaxFrameSize(int thriftMaxFrameSize) | 设置Thrift客户端的最大帧大小(字节) | 64 * 1024 * 1024(64MB) | | enableCompression(boolean enableCompression) | 是否启用连接的压缩 | false | | enableRedirection(boolean enableRedirection) | 是否启用集群节点的重定向 | true | -| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 10000(10秒) | +| connectionTimeoutInMs(int connectionTimeoutInMs) | 设置连接超时时间(毫秒) | 10000(10秒) | | enableAutoFetch(boolean enableAutoFetch) | 是否启用自动获取可用DataNodes | true | | maxRetryCount(int maxRetryCount) | 设置连接尝试的最大重试次数 | 60 | | retryIntervalInMs(long retryIntervalInMs) | 设置重试间隔时间(毫秒) | 500 | @@ -479,7 +479,7 @@ public class TableSessionPoolBuilder { * * @param password the password. * @return the current {@link TableSessionPoolBuilder} instance. - * @defaultValue "root" + * @defaultValue "TimechoDB@2021" //V2.0.6.x 之前默认密码是root */ public TableSessionPoolBuilder password(String password); @@ -686,7 +686,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码是root .maxSize(1) .build(); @@ -787,7 +787,7 @@ public class TableModelSessionPoolExample { new TableSessionPoolBuilder() .nodeUrls(Collections.singletonList(LOCAL_URL)) .user("root") - .password("root") + .password("TimechoDB@2021")//V2.0.6.x 之前默认密码是root .maxSize(1) .database("test1") .build(); diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API.md b/src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API.md rename to src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API_apache.md diff --git a/src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md b/src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..2ebecf58e --- /dev/null +++ b/src/zh/UserGuide/latest-Table/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,550 @@ + + +# Python 原生接口 + +## 1. 使用方式 + +安装依赖包: + +```shell +pip3 install apache-iotdb>=2.0 +``` + +## 2. 读写操作 + +### 2.1 TableSession + +#### 2.1.1 功能描述 + +TableSession是IoTDB的一个核心类,用于与IoTDB数据库进行交互。通过这个类,用户可以执行SQL语句、插入数据以及管理数据库会话。 + +#### 2.1.2 方法列表 + +| **方法名称** | **描述** | **参数类型** | **返回类型** | +| --------------------------- | ---------------------------------- | ---------------------------------- | -------------- | +| insert | 写入数据 | tablet: Union[Tablet, NumpyTablet] | None | +| execute_non_query_statement | 执行非查询 SQL 语句,如 DDL 和 DML | sql: str | None | +| execute_query_statement | 执行查询 SQL 语句并返回结果集 | sql: str | SessionDataSet | +| close | 关闭会话并释放资源 | None | None | + +#### 2.1.3 接口展示 + +**TableSession:** + + +```Python +class TableSession(object): +def insert(self, tablet: Union[Tablet, NumpyTablet]): + """ + Insert data into the database. + + Parameters: + tablet (Tablet | NumpyTablet): The tablet containing the data to be inserted. + Accepts either a `Tablet` or `NumpyTablet`. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_non_query_statement(self, sql: str): + """ + Execute a non-query SQL statement. + + Parameters: + sql (str): The SQL statement to execute. Typically used for commands + such as INSERT, DELETE, or UPDATE. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def execute_query_statement(self, sql: str, timeout_in_ms: int = 0) -> "SessionDataSet": + """ + Execute a query SQL statement and return the result set. + + Parameters: + sql (str): The SQL query to execute. + timeout_in_ms (int, optional): Timeout for the query in milliseconds. Defaults to 0, + which means no timeout. + + Returns: + SessionDataSet: The result set of the query. + + Raises: + IoTDBConnectionException: If there is an issue with the database connection. + """ + pass + +def close(self): + """ + Close the session and release resources. + + Raises: + IoTDBConnectionException: If there is an issue closing the connection. + """ + pass +``` + +### 2.2 TableSessionConfig + +#### 2.2.1 功能描述 + +TableSessionConfig是一个配置类,用于设置和创建TableSession 实例。它定义了连接到IoTDB数据库所需的各种参数。 + +#### 2.2.2 配置选项 + +| **配置项** | **描述** | **类型** | **默认值** | +| ------------------ | ------------------------- | -------- |-----------------------------------------| +| node_urls | 数据库连接的节点 URL 列表 | list | ["localhost:6667"] | +| username | 数据库连接用户名 | str | "root" | +| password | 数据库连接密码 | str | "TimechoDB@2021" //V2.0.6.x 之前默认密码是root | +| database | 要连接的目标数据库 | str | None | +| fetch_size | 每次查询获取的行数 | int | 5000 | +| time_zone | 会话的默认时区 | str | Session.DEFAULT_ZONE_ID | +| enable_compression | 是否启用数据压缩 | bool | False | + +#### 2.2.3 接口展示 + +```Python +class TableSessionConfig(object): + """ + Configuration class for a TableSession. + + This class defines various parameters for connecting to and interacting + with the IoTDB tables. + """ + + def __init__( + self, + node_urls: list = None, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_compression: bool = False, + ): + """ + Initialize a TableSessionConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to ["localhost:6667"]. + username (str, optional): The username for the database connection. + Defaults to "root". + password (str, optional): The password for the database connection. + Defaults to "TimechoDB@2021". //V2.0.6.x 之前默认密码是root + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session. + Defaults to Session.DEFAULT_ZONE_ID. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + """ +``` + +**注意事项:** + +在使用完 TableSession 后,务必调用 close 方法来释放资源。 + +## 3. 客户端连接池 + +### 3.1 TableSessionPool + +#### 3.1.1 功能描述 + +TableSessionPool 是一个会话池管理类,用于管理 TableSession 实例的创建和销毁。它提供了从池中获取会话和关闭会话池的功能。 + +#### 3.1.2 方法列表 + +| **方法名称** | **描述** | **返回类型** | **异常** | +| ------------ | ---------------------------------------- | ------------ | -------- | +| get_session | 从会话池中检索一个新的 TableSession 实例 | TableSession | 无 | +| close | 关闭会话池并释放所有资源 | None | 无 | + +#### 3.1.3 接口展示 + +**TableSessionPool:** + +```Python +def get_session(self) -> TableSession: + """ + Retrieve a new TableSession instance. + + Returns: + TableSession: A new session object configured with the session pool. + + Notes: + The session is initialized with the underlying session pool for managing + connections. Ensure proper usage of the session's lifecycle. + """ + +def close(self): + """ + Close the session pool and release all resources. + + This method closes the underlying session pool, ensuring that all + resources associated with it are properly released. + + Notes: + After calling this method, the session pool cannot be used to retrieve + new sessions, and any attempt to do so may raise an exception. + """ +``` + +### 3.2 TableSessionPoolConfig + +#### 3.2.1 功能描述 + +TableSessionPoolConfig是一个配置类,用于设置和创建 TableSessionPool 实例。它定义了初始化和管理 IoTDB 数据库会话池所需的参数。 + +#### 3.2.2 配置选项 + +| **配置项** | **描述** | **类型** | **默认值** | +| ------------------ | ------------------------------ | -------- | ------------------------ | +| node_urls | 数据库连接的节点 URL 列表 | list | None | +| max_pool_size | 会话池中的最大会话数 | int | 5 | +| username | 数据库连接用户名 | str | Session.DEFAULT_USER | +| password | 数据库连接密码 | str | Session.DEFAULT_PASSWORD | +| database | 要连接的目标数据库 | str | None | +| fetch_size | 每次查询获取的行数 | int | 5000 | +| time_zone | 会话池的默认时区 | str | Session.DEFAULT_ZONE_ID | +| enable_redirection | 是否启用重定向 | bool | False | +| enable_compression | 是否启用数据压缩 | bool | False | +| wait_timeout_in_ms | 等待会话可用的最大时间(毫秒) | int | 10000 | +| max_retry | 操作的最大重试次数 | int | 3 | + +#### 3.2.3 接口展示 + + +```Python +class TableSessionPoolConfig(object): + """ + Configuration class for a TableSessionPool. + + This class defines the parameters required to initialize and manage + a session pool for interacting with the IoTDB database. + """ + def __init__( + self, + node_urls: list = None, + max_pool_size: int = 5, + username: str = Session.DEFAULT_USER, + password: str = Session.DEFAULT_PASSWORD, + database: str = None, + fetch_size: int = 5000, + time_zone: str = Session.DEFAULT_ZONE_ID, + enable_redirection: bool = False, + enable_compression: bool = False, + wait_timeout_in_ms: int = 10000, + max_retry: int = 3, + ): + """ + Initialize a TableSessionPoolConfig object with the provided parameters. + + Parameters: + node_urls (list, optional): A list of node URLs for the database connection. + Defaults to None. + max_pool_size (int, optional): The maximum number of sessions in the pool. + Defaults to 5. + username (str, optional): The username for the database connection. + Defaults to Session.DEFAULT_USER. + password (str, optional): The password for the database connection. + Defaults to Session.DEFAULT_PASSWORD. + database (str, optional): The target database to connect to. Defaults to None. + fetch_size (int, optional): The number of rows to fetch per query. Defaults to 5000. + time_zone (str, optional): The default time zone for the session pool. + Defaults to Session.DEFAULT_ZONE_ID. + enable_redirection (bool, optional): Whether to enable redirection. + Defaults to False. + enable_compression (bool, optional): Whether to enable data compression. + Defaults to False. + wait_timeout_in_ms (int, optional): The maximum time (in milliseconds) to wait for a session + to become available. Defaults to 10000. + max_retry (int, optional): The maximum number of retry attempts for operations. Defaults to 3. + + """ +``` +### 3.3 SSL 连接 + +#### 3.3.1 服务器端配置证书 + +`conf/iotdb-system.properties` 配置文件中查找或添加以下配置项: + +``` +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 配置 python 客户端证书 + +- 设置 use_ssl 为 True 以启用 SSL。 +- 指定客户端证书路径,使用 ca_certs 参数。 + +``` +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**示例代码:使用 SSL 连接 IoTDB** + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前默认密码是root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. 示例代码 + +Session示例代码:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_example.py) + +SessionPool示例代码:[SessionPool Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/table_model_session_pool_example.py) + +```Python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +import threading + +import numpy as np + +from iotdb.table_session_pool import TableSessionPool, TableSessionPoolConfig +from iotdb.utils.IoTDBConstants import TSDataType +from iotdb.utils.NumpyTablet import NumpyTablet +from iotdb.utils.Tablet import ColumnType, Tablet + + +def prepare_data(): + print("create database") + # Get a session from the pool + session = session_pool.get_session() + session.execute_non_query_statement("CREATE DATABASE IF NOT EXISTS db1") + session.execute_non_query_statement('USE "db1"') + session.execute_non_query_statement( + "CREATE TABLE table0 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + session.execute_non_query_statement( + "CREATE TABLE table1 (id1 string tag, attr1 string attribute, " + + "m1 double " + + "field)" + ) + + print("now the tables are:") + # show result + res = session.execute_query_statement("SHOW TABLES") + while res.has_next(): + print(res.next()) + + session.close() + + +def insert_data(num: int): + print("insert data for table" + str(num)) + # Get a session from the pool + session = session_pool.get_session() + column_names = [ + "id1", + "attr1", + "m1", + ] + data_types = [ + TSDataType.STRING, + TSDataType.STRING, + TSDataType.DOUBLE, + ] + column_types = [ColumnType.TAG, ColumnType.ATTRIBUTE, ColumnType.FIELD] + timestamps = [] + values = [] + for row in range(15): + timestamps.append(row) + values.append(["id:" + str(row), "attr:" + str(row), row * 1.0]) + tablet = Tablet( + "table" + str(num), column_names, data_types, values, timestamps, column_types + ) + session.insert(tablet) + session.execute_non_query_statement("FLush") + + np_timestamps = np.arange(15, 30, dtype=np.dtype(">i8")) + np_values = [ + np.array(["id:{}".format(i) for i in range(15, 30)]), + np.array(["attr:{}".format(i) for i in range(15, 30)]), + np.linspace(15.0, 29.0, num=15, dtype=TSDataType.DOUBLE.np_dtype()), + ] + + np_tablet = NumpyTablet( + "table" + str(num), + column_names, + data_types, + np_values, + np_timestamps, + column_types=column_types, + ) + session.insert(np_tablet) + session.close() + + +def query_data(): + # Get a session from the pool + session = session_pool.get_session() + + print("get data from table0") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + print("get data from table1") + res = session.execute_query_statement("select * from table0") + while res.has_next(): + print(res.next()) + + session.close() + + +def delete_data(): + session = session_pool.get_session() + session.execute_non_query_statement("drop database db1") + print("data has been deleted. now the databases are:") + res = session.execute_query_statement("show databases") + while res.has_next(): + print(res.next()) + session.close() + + +# Create a session pool +username = "root" +password = "TimechoDB@2021" //V2.0.6.x 之前默认密码是root +node_urls = ["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"] +fetch_size = 1024 +database = "db1" +max_pool_size = 5 +wait_timeout_in_ms = 3000 +config = TableSessionPoolConfig( + node_urls=node_urls, + username=username, + password=password, + database=database, + max_pool_size=max_pool_size, + fetch_size=fetch_size, + wait_timeout_in_ms=wait_timeout_in_ms, +) +session_pool = TableSessionPool(config) + +prepare_data() + +insert_thread1 = threading.Thread(target=insert_data, args=(0,)) +insert_thread2 = threading.Thread(target=insert_data, args=(1,)) + +insert_thread1.start() +insert_thread2.start() + +insert_thread1.join() +insert_thread2.join() + +query_data() +delete_data() +session_pool.close() +print("example is finished!") +``` + diff --git a/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_apache.md b/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_apache.md index 78537727c..662f73e2d 100644 --- a/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_apache.md +++ b/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_apache.md @@ -66,7 +66,7 @@ - 数据同步:[数据同步](../User-Manual/Data-Sync_apache.md) -6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_apache.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_apache.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_apache.md)、[Python 原生接口](../API/Programming-Python-Native-API_apache)、[JDBC](../API/Programming-JDBC_apache.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 想了解更多技术细节? diff --git a/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md b/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md index dc5dd94c2..52b70d8e5 100644 --- a/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md +++ b/src/zh/UserGuide/latest-Table/QuickStart/QuickStart_timecho.md @@ -73,7 +73,7 @@ - 数据同步:[数据同步](../User-Manual/Data-Sync_timecho.md) -6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[JDBC](../API/Programming-JDBC_timecho.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +6. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho.md)、[Python 原生接口](../API/Programming-Python-Native-API_timecho)、[JDBC](../API/Programming-JDBC_timecho.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? diff --git a/src/zh/UserGuide/latest-Table/Tools-System/CLI.md b/src/zh/UserGuide/latest-Table/Tools-System/CLI_apache.md similarity index 80% rename from src/zh/UserGuide/latest-Table/Tools-System/CLI.md rename to src/zh/UserGuide/latest-Table/Tools-System/CLI_apache.md index 91ece8f04..37ab9452d 100644 --- a/src/zh/UserGuide/latest-Table/Tools-System/CLI.md +++ b/src/zh/UserGuide/latest-Table/Tools-System/CLI_apache.md @@ -48,32 +48,33 @@ Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect tab # V2.0.4.x 版本及之后 Shell> sbin\windows\start-cli.bat -sql_dialect table 或 +# V2.0.4.x 版本及之后 Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table ``` 其中: - -h 和-p 项是 IoTDB 所在的 IP 和 RPC 端口号(本机未修改 IP 和 RPC 端口号默认为 127.0.0.1、6667) -- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名密码均为`root`) +- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名为`root`,密码为`root`) - -sql_dialect 是登录的数据模型(表模型或树模型),此处指定为 table 代表进入表模型模式 更多参数见: | **参数名** | **参数类型** | **是否为必需参数** | **说明** | **示例** | -|:-----------------------------|:-----------|:------------| :----------------------------------------------------------- |:---------------------| -| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | -| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | -| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | -| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 root。 | -pw root | -| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | -| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | +|:-----------------------------|:-----------|:------------|:-----------------------------------------------------------|:---------------------| +| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | +| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | +| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | +| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 root。 | -pw root | +| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | +| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | | -c | 空 | 否 | 如果服务器设置了 rpc_thrift_compression_enable=true, 则 CLI 必须使用 -c | -c | -| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | -| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | -| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | -| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | -| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | -| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | +| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | +| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | +| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | +| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | +| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | +| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | 启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/latest-Table/Tools-System/CLI_timecho.md b/src/zh/UserGuide/latest-Table/Tools-System/CLI_timecho.md new file mode 100644 index 000000000..7b7bcf538 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/Tools-System/CLI_timecho.md @@ -0,0 +1,123 @@ + + +# 命令行工具 + +IoTDB 为用户提供 CLI 工具用于和服务端程序进行交互操作。在使用 CLI 工具连接 IoTDB 前,请保证 IoTDB 服务已经正常启动。下面介绍 CLI 工具的运行方式和相关参数。 + +> 本文中 $IoTDB_HOME 表示 IoTDB 的安装目录所在路径。 + +## 1. CLI 启动 + +CLI 客户端脚本是 $IoTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动命令为: + +- Linux/MacOS 系统常用启动命令为: + +```Shell +Shell> bash sbin/start-cli.sh -sql_dialect table +或 +# V2.0.6.x 版本之前 +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x 版本及之后 +Shell> bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +- Windows 系统常用启动命令为: + +```Shell +# V2.0.4.x 版本之前 +Shell> sbin\start-cli.bat -sql_dialect table +或 +Shell> sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table + +# V2.0.4.x 版本及之后 +Shell> sbin\windows\start-cli.bat -sql_dialect table +或 +# V2.0.4.x 版本及之后, V2.0.6.x 版本之前 +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -sql_dialect table +# V2.0.6.x 版本及之后 +Shell> sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -sql_dialect table +``` + +其中: + +- -h 和-p 项是 IoTDB 所在的 IP 和 RPC 端口号(本机未修改 IP 和 RPC 端口号默认为 127.0.0.1、6667) +- -u 和-pw 是 IoTDB 登录的用户名密码(安装后IoTDB有一个默认用户,用户名为`root`,密码为`TimechoDB@2021`,V2.0.6版本之前密码为`root`) +- -sql_dialect 是登录的数据模型(表模型或树模型),此处指定为 table 代表进入表模型模式 + +更多参数见: + +| **参数名** | **参数类型** | **是否为必需参数** | **说明** | **示例** | +|:-----------------------------|:-----------|:------------|:-----------------------------------------------------------|:---------------------| +| -h `` | string 类型 | 否 | IoTDB 客户端连接 IoTDB 服务器的 IP 地址, 默认使用:127.0.0.1。 | -h 127.0.0.1 | +| -p `` | int 类型 | 否 | IoTDB 客户端连接服务器的端口号,IoTDB 默认使用 6667。 | -p 6667 | +| -u `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的用户名,默认使用 root。 | -u root | +| -pw `` | string 类型 | 否 | IoTDB 客户端连接服务器所使用的密码,默认使用 TimechoDB@2021(V2.0.6版本之前为root)。 | -pw root | +| -sql_dialect `` | string 类型 | 否 | 目前可选 tree(树模型) 、table(表模型),默认 tree | -sql_dialect table | +| -e `` | string 类型 | 否 | 在不进入客户端输入模式的情况下,批量操作 IoTDB。 | -e "show databases" | +| -c | 空 | 否 | 如果服务器设置了 rpc_thrift_compression_enable=true, 则 CLI 必须使用 -c | -c | +| -disableISO8601 | 空 | 否 | 如果设置了这个参数,IoTDB 将以数字的形式打印时间戳 (timestamp)。 | -disableISO8601 | +| -usessl `` | Boolean 类型 | 否 | 否开启 ssl 连接 | -usessl true | +| -ts `` | string 类型 | 否 | ssl 证书存储路径 | -ts /path/to/truststore | +| -tpw `` | string 类型 | 否 | ssl 证书存储密码 | -tpw myTrustPassword | +| -timeout `` | int 类型 | 否 | 查询超时时间(秒)。如果未设置,则使用服务器的配置。 | -timeout 30 | +| -help | 空 | 否 | 打印 IoTDB 的帮助信息。 | -help | + +启动后出现如图提示即为启动成功。 + +![](/img/Cli-01.png) + + +## 2. 在 CLI 中执行语句 + +进入 CLI 后,用户可以直接在对话中输入 SQL 语句进行交互。如: + +- 创建数据库 + +```Java +create database test +``` + +![](/img/Cli-02.png) + + +- 查看数据库 + +```Java +show databases +``` + +![](/img/Cli-03.png) + + +## 3. CLI 退出 + +在 CLI 中输入`quit`或`exit`可退出 CLI 结束本次会话。 + +## 4. 其他说明 + +CLI中使用命令小技巧: + +(1)快速切换历史命令: 上下箭头 + +(2)历史命令自动补全:右箭头 + +(3)中断执行命令: CTRL+C \ No newline at end of file diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md b/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md similarity index 94% rename from src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md rename to src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md index 0855802c9..8aa7709d1 100644 --- a/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool.md +++ b/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_apache.md @@ -31,23 +31,23 @@ ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- | ------------------------------------------ | -| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | | -h | -- host | 主机名 | 否 | 127.0.0.1 | | -p | --port | 端口号 | 否 | 6667 | | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | -| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| -| -| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | -| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | -|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | -| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | -| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | -| -q | --query | 要执行的查询命令 | 否 | 无 | +| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| - | +| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | +| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | +|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | | -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | -| -help | --help | 显示帮助信息 | 否 | | +| -help | --help | 显示帮助信息 | 否 | | ### 2.2 CSV 格式 diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md b/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..47bab5a88 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,176 @@ +# 数据导出 + +## 1. 功能概述 + +数据导出工具 `export-data.sh/bat` 位于 `tools` 目录下,能够将指定 SQL 的查询结果导出为 CSV、SQL 及 TsFile(开源时间序列文件格式)格式。具体功能如下: + +
+ + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVexport-data.sh/bat纯文本格式,存储格式化数据,需按照下文指定 CSV 格式进行构造
SQL包含自定义 SQL 语句的文件
TsFile开源时序数据文件格式
+ + +## 2. 功能详解 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ------------ | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| -sql_dialect | --sql_dialect | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| -db | --database | ​将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。| `-sql_dialect`为 table 时必填| - | +| -table|--table | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。如果指定了`-q`参数则此参数不生效,如果导出类型为 tsfile/sql 则此参数必填。| ​ 否 | - | +| -start_time | --start_time |将要导出的数据起始时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。支持的时间类型同`-tf`参数。|否 | - | +|-end_time |--end_time | 将要导出的数据的终止时间,只有`-sql_dialect`为 table 类型时生效。如果填写了`-q`,则此参数不生效。| 否 | - | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | +| -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | +| -help | --help | 显示帮助信息 | 否 | | + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table + [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |--------------------------------------| +| -dt | --datatype | 是否在 CSV 文件的表头输出时间序列的数据类型,可以选择`true`或`false` | 否 | false | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定 CSV 文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL 文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601 | +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.2.3 运行示例: + +```Shell +# 正确示例 +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -db database1 -q "select * from table1" + +# 异常示例 +> export-data.sh -ft csv -sql_dialect table -t /path/export/dir -q "select * from table1" +Parse error: Missing required option: db +``` + +### 2.3 SQL 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------------------------------------- | +| -aligned | --use\_aligned | 是否导出为对齐的 SQL 格式 | 否 | true | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定 CSV 文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL 文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601| +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.3.3 运行示例: + +```Shell +# 正确示例 +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -db database1 -start_time 1 + +# 异常示例 +> export-data.sh -ft sql -sql_dialect table -t /path/export/dir -start_time 1 +Parse error: Missing required option: db +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-sql_dialect] -db -table
+ [-start_time] [-end_time] [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 私有参数 + +* 无 + +#### 2.4.3 运行示例: + +```Shell +# 正确示例 +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -db database1 -start_time 0 + +# 异常示例 +> /tools/export-data.sh -ft tsfile -sql_dialect table -t /path/export/dir -start_time 0 +Parse error: Missing required option: db +``` diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md b/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md similarity index 97% rename from src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md rename to src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md index 3d5d041cf..57c7217f2 100644 --- a/src/zh/UserGuide/Master/Table/Tools-System/Data-Import-Tool.md +++ b/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_apache.md @@ -51,9 +51,9 @@ IoTDB 支持三种方式进行数据导入: | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | | -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为 csv sql tsfile 这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | -|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | -| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | -|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | +|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | +| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | +|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | | -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | | -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | | -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | @@ -117,11 +117,11 @@ There are no tables or the target table table5 does not exist 1. CSV 导入规范 -- 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号`,`),需使用反斜杠(`\`)​进行转义处理。 -- 支持的时间格式:`yyyy-MM-dd'T'HH:mm:ss`, `yyy-MM-dd HH:mm:ss`, 或者 `yyyy-MM-dd'T'HH:mm:ss.SSSZ` 。 -- 时间戳列​必须作为数据文件的首列存在。 + - 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号`,`),需使用反斜杠(`\`)​进行转义处理。 + - 支持的时间格式:`yyyy-MM-dd'T'HH:mm:ss`, `yyy-MM-dd HH:mm:ss`, 或者 `yyyy-MM-dd'T'HH:mm:ss.SSSZ` 。 + - 时间戳列​必须作为数据文件的首列存在。 -2. CSV 文件示例 +2. CSV 文件示例 ```sql time,region,device,model,temperature,humidity diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md b/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..eeaabf87f --- /dev/null +++ b/src/zh/UserGuide/latest-Table/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,325 @@ +# 数据导入 + +## 1. 功能概述 + +IoTDB 支持三种方式进行数据导入: +- 数据导入工具 :`import-data.sh/bat` 位于 `tools` 目录下,可以将 `CSV`、`SQL`、及`TsFile`(开源时序文件格式)的数据导入 `IoTDB`。 +- `TsFile` 自动加载功能。 +- `Load SQL` 导入 `TsFile` 。 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVimport-data.sh/bat可用于单个或一个目录的 CSV 文件批量导入 IoTDB
SQL可用于单个或一个目录的 SQL 文件批量导入 IoTDB
TsFile可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
TsFile 自动加载可以监听指定路径下新产生的 TsFile 文件,并将其加载进 IoTDB
Load SQL可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
+ +- **表模型 TsFile 导入暂时只支持本地导入。** + +## 2. 数据导入工具 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |-------------------------------------| +| -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为 csv sql tsfile 这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | +|-sql_dialect|--sql_dialect|选择 server 是树模型还是表模型,当前支持 tree 和 table 类型| 否 | tree | +| -db |--database |数据将要导入的目标库,只在 `-sql_dialect` 为 table 类型下生效。|-sql_dialect 为 table 时必填 | - | +|-table |--table |数据将要导入的目标表,只在 `-sql_dialect` 为 table 类型且文件类型为 csv 条件下生效且必填。 | 否 | - | +| -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | + + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- |-------------------------------------------|---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -aligned | --use\_aligned | 是否导入为对齐序列 | 否 | false | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -ti | --type\_infer | 通过选项定义类型信息,例如`"boolean=text,int=long, ..."` | 否 | 无 | +| -tp | --timestamp\_precision | 时间戳精度 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms +| + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_0.csv -db database1 -table table1 + +# 异常示例 +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -table table1 +Parse error: Missing required option: db + +> tools/import-data.sh -ft csv -sql_dialect table -s ./csv/dump0_1.csv -db database1 -table table5 +There are no tables or the target table table5 does not exist +``` + +#### 2.2.4 导入说明 + +1. CSV 导入规范 + + - 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号`,`),需使用反斜杠(`\`)​进行转义处理。 + - 支持的时间格式:`yyyy-MM-dd'T'HH:mm:ss`, `yyy-MM-dd HH:mm:ss`, 或者 `yyyy-MM-dd'T'HH:mm:ss.SSSZ` 。 + - 时间戳列​必须作为数据文件的首列存在。 + +2. CSV 文件示例 + +```sql +time,region,device,model,temperature,humidity +1970-01-01T08:00:00.001+08:00,"上海","101","F",90.0,35.2 +1970-01-01T08:00:00.002+08:00,"上海","101","F",90.0,34.8 +``` + + +### 2.3 SQL 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- | -------------- |---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | + +#### 2.3.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump0_0.sql -db database1 + +# 异常示例 +> tools/import-data.sh -ft sql -sql_dialect table -s ./sql/dump1_1.sql -db database1 +Source file or directory ./sql/dump1_1.sql does not exist + +# 目标表存在但是元数据不适配/数据异常:生成.failed异常文件记录该条信息,日志打印错误信息如下 +Fail to insert measurements '[column.name]' caused by [data type is not consistent, input '[column.value]', registered '[column.DataType]'] +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` + +#### 2.4.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ------------------------ |----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------| -------------------- | +| -os| --on\_succcess| 1. none:不删除
2. mv:移动成功的文件到目标文件夹
3. cp:硬连接(拷贝)成功的文件到目标文件夹
4. delete:删除 | √ || +| -sd | --success\_dir | 当`--on_succcess`为 mv 或 cp 时,mv 或 cp 的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_succcess`为mv或cp时需要填写 | `${EXEC_DIR}/success`| +| -of| --on\_fail| 1. none:跳过
2. mv:移动失败的文件到目标文件夹
3. cp:硬连接(拷贝)失败的文件到目标文件夹
4. delete:删除 | √ || +| -fd | --fail\_dir | 当`--on_fail`指定为 mv 或 cp 时,mv 或 cp 的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_fail`指定为 mv 或 cp 时需要填写 | `${EXEC_DIR}/fail` | +| -tp | --timestamp\_precision | 时间戳精度
tsfile 非远程导入:-tp 指定 tsfile 文件的时间精度 手动校验和服务器的时间戳是否一致 不一致返回报错信息
远程导入:-tp 指定 tsfile 文件的时间精度 pipe 自动校验时间戳精度是否一致 不一致返回 pipe 报错信息 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms| + + +#### 2.4.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 -os none -of none + +# 异常示例 +> tools/import-data.sh -ft tsfile -sql_dialect table -s ./tsfile -db database1 +Parse error: Missing required options: os, of +``` + +## 3. TsFile 自动加载功能 + +本功能允许 IoTDB 主动监听指定目录下的新增 TsFile,并将 TsFile 自动加载至 IoTDB 中。通过此功能,IoTDB 能自动检测并加载 TsFile,无需手动执行任何额外的加载操作。 + +![](/img/Data-import1.png) + +### 3.1 配置参数 + +可通过从配置文件模版 `iotdb-system.properties.template` 中找到下列参数,添加到 IoTDB 配置文件 `iotdb-system.properties` 中开启 TsFile 自动加载功能。完整配置如下: + +| **配置参数** | **参数说明** | **value 取值范围** | **是否必填** | **默认值** | **加载方式** | +| --------------------------------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------------------- | -------------------- | ------------------------ | -------------------- | +| load\_active\_listening\_enable | 是否开启 DataNode 主动监听并且加载 tsfile 的功能(默认开启)。 | Boolean: true,false | 选填 | true | 热加载 | +| load\_active\_listening\_dirs | 需要监听的目录(自动包括目录中的子目录),如有多个使用 “,“ 隔开;
默认的目录为 `ext/load/pending`;
支持热装载;
**注意:表模型中,文件所在的目录名会作为 database**; | String: 一个或多个文件目录 | 选填 | `ext/load/pending` | 热加载 | +| load\_active\_listening\_fail\_dir | 执行加载 tsfile 文件失败后将文件转存的目录,只能配置一个 | String: 一个文件目录 | 选填 | `ext/load/failed` | 热加载 | +| load\_active\_listening\_max\_thread\_num | 同时执行加载 tsfile 任务的最大线程数,参数被注释掉时的默值为 max(1, CPU 核心数 / 2),当用户设置的值不在这个区间[1, CPU核心数 /2]内时,会设置为默认值 (1, CPU 核心数 / 2) | Long: [1, Long.MAX\_VALUE] | 选填 | max(1, CPU 核心数 / 2) | 重启后生效 | +| load\_active\_listening\_check\_interval\_seconds | 主动监听轮询间隔,单位秒。主动监听 tsfile 的功能是通过轮询检查文件夹实现的。该配置指定了两次检查 `load_active_listening_dirs` 的时间间隔,每次检查完成 `load_active_listening_check_interval_seconds` 秒后,会执行下一次检查。当用户设置的轮询间隔小于 1 时,会被设置为默认值 5 秒 | Long: [1, Long.MAX\_VALUE] | 选填 | 5 | 重启后生效 | + +### 3.2 示例说明 + +```bash +load_active_listening_dir/ +├─sensors/ +│ ├─temperature/ +│ │ └─temperature-table.TSFILE + +``` + +- 表模型 TsFile + - `temperature-table.TSFILE`: 会被导入到 `temperature` database 下(因为它位于`sensors/temperature/` 目录下) + +### 3.3 注意事项 + +1. 如果待加载的文件中,存在 mods 文件,应优先将 mods 文件移动到监听目录下面,然后再移动 tsfile 文件,且 mods 文件应和对应的 tsfile 文件处于同一目录。防止加载到 tsfile 文件时,加载不到对应的 mods 文件 +2. 禁止设置 Pipe 的 receiver 目录、存放数据的 data 目录等作为监听目录 +3. 禁止 `load_active_listening_fail_dir` 与 `load_active_listening_dirs` 存在相同的目录,或者互相嵌套 +4. 保证 `load_active_listening_dirs` 目录有足够的权限,在加载成功之后,文件将会被删除,如果没有删除权限,则会重复加载 + +## 4. Load SQL + +IoTDB 支持通过 CLI 执行 SQL 直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的 IoTDB 实例中。 + +### 4.1 运行命令 + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` :文件本身,或是包含若干文件的文件夹路径 +* ``:可选参数,具体如下表所示 + +| Key | Key 描述 | Value 类型 | Value 取值范围 | Value 是否必填 | Value 默认值 | +| --------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ | ----------------------------------------- | ---------------- | -------------------------- | +| `database-level` | 当 tsfile 对应的 database 不存在时,可以通过` database-level`参数的值来制定 database 的级别,默认为`iotdb-common.properties`中设置的级别。
例如当设置 level 参数为 1 时表明此 tsfile 中所有时间序列中层级为1的前缀路径是 database。 | Integer | `[1: Integer.MAX_VALUE]` | 否 | 1 | +| `on-success` | 表示对于成功载入的 tsfile 的处置方式:默认为`delete`,即tsfile 成功加载后将被删除;`none `表明 tsfile 成功加载之后依然被保留在源文件夹, | String | `delete / none` | 否 | delete | +| `model` | 指定写入的 tsfile 是表模型还是树模型 | String | `tree / table` | 否 | 与`-sql_dialect`一致 | +| `database-name` | **仅限表模型有效**: 文件导入的目标 database,不存在时会自动创建,`database-name`中不允许包括"`root.`"前缀,如果包含,将会报错。 | String | `-` | 否 | null | +| `convert-on-type-mismatch` | 加载 tsfile 时,如果数据类型不一致,是否进行转换 | Boolean | `true / false` | 否 | true | +| `verify` | 加载 tsfile 前是否校验 schema | Boolean | `true / false` | 否 | true | +| `tablet-conversion-threshold` | 转换为 tablet 形式的 tsfile 大小阈值,针对小文件 tsfile 加载,采用将其转换为 tablet 形式进行写入:默认值为 -1,即任意大小 tsfile 都不进行转换 | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | 否 | -1 | +| `async` | 是否开启异步加载 tsfile,将文件移到 active load 目录下面,所有的 tsfile 都 load 到`database-name`下. | Boolean | `true / false` | 否 | false | + +### 4.2 运行示例 + +```SQL +-- 准备目标数据库 database2 +IoTDB> create database database2 +Msg: The statement is executed successfully. + +IoTDB> use database2 +Msg: The statement is executed successfully. + +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ ++---------+-------+------+-------+ +Empty set. + +--通过执行load sql 导入tsfile +IoTDB:database2> load '/home/dump0.tsfile' with ( 'on-success'='none', 'database-name'='database2') +Msg: The statement is executed successfully. + +-- 验证数据导入成功 +IoTDB:database2> select * from table2 ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +| time|region|plant_id|device_id|temperature|humidity|status| arrival_time| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +|2024-11-30T00:00:00.000+08:00| 上海| 3002| 101| 90.0| 35.2| true| null| +|2024-11-29T00:00:00.000+08:00| 上海| 3001| 101| 85.0| 35.1| null|2024-11-29T10:00:13.000+08:00| +|2024-11-27T00:00:00.000+08:00| 北京| 1001| 101| 85.0| 35.1| true|2024-11-27T16:37:01.000+08:00| +|2024-11-29T11:00:00.000+08:00| 上海| 3002| 100| null| 45.1| true| null| +|2024-11-28T08:00:00.000+08:00| 上海| 3001| 100| 85.0| 35.2| false|2024-11-28T08:00:09.000+08:00| +|2024-11-26T13:37:00.000+08:00| 北京| 1001| 100| 90.0| 35.1| true|2024-11-26T13:37:34.000+08:00| ++-----------------------------+------+--------+---------+-----------+--------+------+-----------------------------+ +``` diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md similarity index 95% rename from src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md rename to src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md index 8243acec7..b77a6525a 100644 --- a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Export-Tool.md +++ b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | -| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | -| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | -| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | -| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | | `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..e8c65a2a6 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,108 @@ + + +# 元数据导出 + +## 1. 功能概述 + +元数据导出工具 `export-schema.sh/bat` 位于tools 目录下,能够将 IoTDB 中指定数据库下的元数据导出为脚本文件。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 运行示例 + +将 `database1` 下的元数据导出到`/home`下 + +```Bash +./export-schema.sh -sql_dialect table -t /home/ -db database1 +``` + +导出文件 `dump_database1.sql`,内容格式如下: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` diff --git a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md similarity index 91% rename from src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md rename to src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md index 26d704be3..ce053fd18 100644 --- a/src/zh/UserGuide/Master/Table/Tools-System/Schema-Import-Tool.md +++ b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_apache.md @@ -29,19 +29,19 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- | --------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | -| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | -| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-----------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | | `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md new file mode 100644 index 000000000..c96a19d7a --- /dev/null +++ b/src/zh/UserGuide/latest-Table/Tools-System/Schema-Import-Tool_timecho.md @@ -0,0 +1,163 @@ + + +# 元数据导入 + +## 1. 功能概述 + +元数据导入工具 `import-schema.sh/bat` 位于tools 目录下,能够将指定路径下创建元数据的脚本文件导入到 IoTDB 中。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# V2.0.4.x 版本之前 +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x 版本及之后 +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 运行示例 + + +将 `/home `下的文件 `dump_database1.sql` 导入到 `database2 `中,文件内容如下: + +```sql +DROP TABLE IF EXISTS table1; +CREATE TABLE table1( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +DROP TABLE IF EXISTS table2; +CREATE TABLE table2( + time TIMESTAMP TIME, + region STRING TAG, + plant_id STRING TAG, + device_id STRING TAG, + model_id STRING ATTRIBUTE, + maintenance STRING ATTRIBUTE, + temperature FLOAT FIELD, + humidity FLOAT FIELD, + status BOOLEAN FIELD, + arrival_time TIMESTAMP FIELD +); +``` + +执行脚本: + +```Bash +./import-schema.sh -sql_dialect table -s /home/dump_database1.sql -db database2 + +# database2 不存在时,提示错误信息如下 +The target database database2 does not exist + +# database2 存在时,提示成功 +Import completely! +``` + +验证导入元数据: + +```Bash +# 导入前 +IoTDB:database2> show tables ++---------+-------+ +|TableName|TTL(ms)| ++---------+-------+ ++---------+-------+ +Empty set. + +# 导入后 +IoTDB:database2> show tables details ++---------+-------+------+-------+ +|TableName|TTL(ms)|Status|Comment| ++---------+-------+------+-------+ +| table2| INF| USING| null| +| table1| INF| USING| null| ++---------+-------+------+-------+ + +IoTDB:database2> desc table1 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ + +IoTDB:database2> desc table2 ++------------+---------+---------+ +| ColumnName| DataType| Category| ++------------+---------+---------+ +| time|TIMESTAMP| TIME| +| region| STRING| TAG| +| plant_id| STRING| TAG| +| device_id| STRING| TAG| +| model_id| STRING|ATTRIBUTE| +| maintenance| STRING|ATTRIBUTE| +| temperature| FLOAT| FIELD| +| humidity| FLOAT| FIELD| +| status| BOOLEAN| FIELD| +|arrival_time|TIMESTAMP| FIELD| ++------------+---------+---------+ +``` diff --git a/src/zh/UserGuide/latest-Table/User-Manual/Authority-Management.md b/src/zh/UserGuide/latest-Table/User-Manual/Authority-Management_apache.md similarity index 100% rename from src/zh/UserGuide/latest-Table/User-Manual/Authority-Management.md rename to src/zh/UserGuide/latest-Table/User-Manual/Authority-Management_apache.md diff --git a/src/zh/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md b/src/zh/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..575243a8e --- /dev/null +++ b/src/zh/UserGuide/latest-Table/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,483 @@ + + +# 权限管理 + +IoTDB 提供了权限管理功能,用于对数据和集群系统执行精细的访问控制,保障数据与系统安全。本篇介绍了 IoTDB 表模型中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。 + +## 1. 基本概念 + +### 1.1 用户 + +用户即数据库的合法使用者。一个用户与一个唯一的用户名相对应,并且拥有密码作为身份验证的手段。一个人在使用数据库之前,必须先提供合法的(即存于数据库中的)用户名与密码。 + +### 1.2 权限 + +数据库提供多种操作,但并非所有的用户都能执行所有操作。如果一个用户可以执行某项操作,则称该用户有执行该操作的权限。 + +### 1.3 角色 + +角色是若干权限的集合,并且有一个唯一的角色名作为标识符。角色通常和一个现实身份相对应(例如交通调度员),而一个现实身份可能对应着多个用户。这些具有相同现实身份的用户往往具有相同的一些权限,角色就是为了能对这样的权限进行统一的管理的抽象。 + +### 1.4 默认用户与角色 + +安装初始化后的 IoTDB 中有一个默认用户 root,默认密码为 TimechoDB@2021(V2.0.6.x 之前为 root)。该用户为管理员用户,拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。一个新创建的用户或角色不具备任何权限。 + + +## 2. 权限列表 + +IoTDB 表模型主要有两类权限:全局权限、数据权限。 + +### 2.1 全局权限 + +全局权限包含用户管理和角色管理。 + +下表描述了全局权限的种类: + +| 权限名称 | 描述 | +| ----------------- |----------------------------------------------------------------------------------------| +| MANAGE\_USER | - 允许用户创建用户
- 允许用户删除用户
- 允许用户修改用户密码
- 允许用户查看用户的权限信息
- 允许用户列出所有用户 | +| MANAGE\_ROLE | - 允许用户创建角色
- 允许用户删除角色
- 允许用户查看角色的权限信息
- 允许用户将角色授予某个用户或撤销
- 允许用户列出所有角色 | + + +### 2.2 数据权限 + +数据权限由权限类型和范围组成。 + +* 权限类型包括:CREATE(创建权限),DROP(删除权限),ALTER(修改权限),SELECT(查询数据权限),INSERT(插入/更新数据权限),DELETE(删除数据权限)。 + +* 范围包括:ANY(系统范围内),DATABASE(数据库范围内),TABLE(单个表)。 + - 作用于 ANY 的权限会影响所有数据库和表。 + - 作用于数据库的权限会影响该数据库及其所有表。 + - 作用于表的权限仅影响该表。 + +* 范围生效说明:执行单表操作时,数据库会匹配用户权限与数据权限范围。例如,用户尝试向 DATABASE1.TABLE1 写入数据时,系统会依次检查用户是否有对 ANY、DATABASE1或 DATABASE1.TABLE1 的写入权限,直到匹配成功或者匹配失败。 + +* 权限类型、范围及效果逻辑关系如下表所示: + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
权限类型权限范围(层级)权限效果
CREATEANY允许创建任意表、创建任意数据库
数据库允许用户在该数据库下创建表;允许用户创建该名称的数据库
允许用户创建该名称的表
DROPANY允许删除任意表、删除任意数据库
数据库允许用户删除该数据库;允许用户删除该数据库下的表
D允许用户删除该表
ALTERANY允许修改任意表的定义、任意数据库的定义
数据库允许用户修改数据库的定义,允许用户修改数据库下表的定义
允许用户修改表的定义
SELECTANY允许查询系统内任意数据库中任意表的数据
数据库允许用户查询该数据库中任意表的数据
允许用户查询该表中的数据。执行多表查询时,数据库仅展示用户有权限访问的数据。
INSERTANY允许任意数据库的任意表插入/更新数据
数据库允许用户向该数据库范围内任意表插入/更新数据
允许用户向该表中插入/更新数据
DELETEANY允许删除任意表的数据
数据库允许用户删除该数据库范围内的数据
允许用户删除该表中的数据
+ +## 3. 用户、角色管理 +1. 创建用户(需 MANAGE_USER 权限) + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- 用户名约束:4~32个字符,支持使用英文大小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,用户无法创建和管理员用户同名的用户。 +- 密码约束:4~32个字符,可使用大写小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,密码默认采用 SHA-256 进行加密。 + +2. 修改密码 + +用户可以修改自己的密码,但修改其他用户密码需要具备 MANAGE_USER 权限。 + +```SQL +ALTER USER SET PASSWORD +eg: ALTER USER tempuser SET PASSWORD 'newpwd' +``` + +3. 删除用户(需 MANAGE_USER 权限) + +```SQL +DROP USER +eg: DROP USER user1 +``` + +4. 创建角色 (需 MANAGE_ROLE 权限) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +角色名约束:4~32个字符,支持使用英文大小写字母、数字、特殊字符`(!@#$%^&*()_+-=)`,用户无法创建和管理员用户同名的角色。 + +5. 删除角色 (需 MANAGE_ROLE 权限) + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +6. 赋予用户角色 (需 MANAGE_ROLE 权限) + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +7. 移除用户角色 (需 MANAGE_ROLE 权限) + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +8. 列出所有用户(需 MANAGE_USER 权限) + +```SQL +LIST USER +``` + +9. 列出所有的角色 (需 MANAGE_ROLE 权限) + +```SQL +LIST ROLE +``` + +10. 列出指定角色下所有用户(需 MANAGE_USER 权限) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +11. 列出指定用户下的所有角色 + +用户可以列出自己的角色,但列出其他用户的角色需要拥有 MANAGE_ROLE 权限。 + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +12. 列出用户所有权限 + +用户可以列出自己的权限信息,但列出其他用户的权限需要拥有 MANAGE_USER 权限。 + +```SQL +LIST PRIVILEGES OF USER +eg: LIST PRIVILEGES OF USER tempuser +``` + +13. 列出角色所有权限 + +用户可以列出自己具有的角色的权限信息,列出其他角色的权限需要有 MANAGE_ROLE 权限。 + +```SQL +LIST PRIVILEGES OF ROLE +eg: LIST PRIVILEGES OF ROLE actor +``` + +## 4. 权限管理 + +IoTDB支持通过如下三种途径进行用户授权和撤销权限: + +- 超级管理员直接授予或撤销 + +- 拥有GRANT OPTION权限的用户授予或撤销 + +- 通过角色授予或撤销(由超级管理员或具备MANAGE_ROLE权限的用户操作角色) + +在IoTDB 表模型中,授权或撤销权限时需遵循以下原则: + +- 授权/撤销全局权限时,无需指定权限的范围。 + +- 授予/撤销数据权限时,需要指定权限类型和权限范围。在撤销权限时只会撤销指定的权限范围,不会受权限范围包含关系的影响。 + +- 允许对尚未创建的数据库或表提前进行权限规划和授权。 + +- 允许重复授权/撤销权限。 + +- WITH GRANT OPTION: 允许用户在授权范围内管理权限。用户可以授予或撤销其他用户在该范围内的权限。 + +### 4.1 授予权限 + +1. 给用户授予管理用户的权限 + +```SQL +GRANT MANAGE_USER TO USER +eg: GRANT MANAGE_USER TO USER TEST_USER +``` + +2. 给用户授予创建数据库及在数据库范围内创建表的权限,且允许用户在该范围内管理权限 + +```SQL +GRANT CREATE ON DATABASE TO USER WITH GRANT OPTION +eg: GRANT CREATE ON DATABASE TESTDB TO USER TEST_USER WITH GRANT OPTION +``` + +3. 给角色授予查询数据库的权限 + +```SQL +GRANT SELECT ON DATABASE TO ROLE +eg: GRANT SELECT ON DATABASE TESTDB TO ROLE TEST_ROLE +``` + +4. 给用户授予查询表的权限 + +```SQL +GRANT SELECT ON . TO USER +eg: GRANT SELECT ON TESTDB.TESTTABLE TO USER TEST_USER +``` + +5. 给角色授予查询所有数据库及表的权限 + +```SQL +GRANT SELECT ON ANY TO ROLE +eg: GRANT SELECT ON ANY TO ROLE TEST_ROLE +``` + +6. ALL 语法糖:ALL 表示对象范围内所有权限,可以使用 ALL 字段灵活地授予权限。 + +```sql +GRANT ALL TO USER TESTUSER +-- 将用户可以获取的所有权限授予给用户,包括全局权限和 ANY 范围的所有数据权限 + +GRANT ALL ON ANY TO USER TESTUSER +-- 将 ANY 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在所有数据库上的所有数据权限 + +GRANT ALL ON DATABASE TESTDB TO USER TESTUSER +-- 将 DB 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在该数据库上的所有数据权限 + +GRANT ALL ON TABLE TESTTABLE TO USER TESTUSER +-- 将 TABLE 范围内可以获取的所有权限授予给用户,执行该语句后,用户将拥有在该表上的所有数据权限 +``` + +### 4.2 撤销权限 + +1. 取消用户管理用户的权限 + +```SQL +REVOKE MANAGE_USER FROM USER +eg: REVOKE MANAGE_USER FROM USER TEST_USER +``` + +2. 取消用户创建数据库及在数据库范围内创建表的权限 + +```SQL +REVOKE CREATE ON DATABASE FROM USER +eg: REVOKE CREATE ON DATABASE TEST_DB FROM USER TEST_USER +``` + +3. 取消用户查询表的权限 + +```SQL +REVOKE SELECT ON . FROM USER +eg: REVOKE SELECT ON TESTDB.TESTTABLE FROM USER TEST_USER +``` + +4. 取消用户查询所有数据库及表的权限 + +```SQL +REVOKE SELECT ON ANY FROM USER +eg: REVOKE SELECT ON ANY FROM USER TEST_USER +``` + +5. ALL 语法糖:ALL 表示对象范围内所有权限,可以使用 ALL 字段灵活地撤销权限。 + +```sql +REVOKE ALL FROM USER TESTUSER +-- 取消用户所有的全局权限以及 ANY 范围的所有数据权限 + +REVOKE ALL ON ANY FROM USER TESTUSER +-- 取消用户 ANY 范围的所有数据权限,不会影响 DB 范围和 TABLE 范围的权限 + +REVOKE ALL ON DATABASE TESTDB FROM USER TESTUSER +-- 取消用户在 DB 上的所有数据权限,不会影响 TABLE 权限 + +REVOKE ALL ON TABLE TESTDB FROM USER TESTUSER +-- 取消用户在 TABLE 上的所有数据权限 +``` + +### 4.3 查看用户权限 + +每个用户都有一个权限访问列表,标识其获得的所有权限。可使用 `LIST PRIVILEGES OF USER ` 语句查看某个用户或角色的权限信息,输出格式如下: + +| ROLE | SCOPE | PRIVIVLEGE | WITH GRANT OPTION | +|--------------|---------| -------------- |-------------------| +| | DB1.TB1 | SELECT | FALSE | +| | | MANAGE\_ROLE | TRUE | +| ROLE1 | DB2.TB2 | UPDATE | TRUE | +| ROLE1 | DB3.\* | DELETE | FALSE | +| ROLE1 | \*.\* | UPDATE | TRUE | + +其中: +- `ROLE` 列:如果为空,则表示为该用户的自身权限。如果不为空,则表示该权限来源于被授予的角色。 +- `SCOPE` 列:表示该用户/角色的权限范围,表范围的权限表示为`DB.TABLE`,数据库范围的权限表示为`DB.*`, ANY 范围的权限表示为`*.*`。 +- `PRIVIVLEGE` 列:列出具体的权限类型。 +- `WITH GRANT OPTION` 列:如果为 TRUE,表示用户可以将自己的权限授予他人。 +- 用户或者角色可以同时具有树模型和表模型的权限,但系统会根据当前连接的模型来显示相应的权限,另一种模型下的权限则不会显示。 + +## 5. 示例 + +以 [示例数据](../Reference/Sample-Data.md) 内容为例,两个表的数据可能分别属于 bj、sh 两个数据中心,彼此间不希望对方获取自己的数据库数据,因此我们需要将不同的数据在数据中心层进行权限隔离。 + +### 5.1 创建用户 + +使用 `CREATE USER ` 创建用户。例如,可以使用具有所有权限的root用户为 ln 和 sgcc 集团创建两个用户角色,名为 `bj_write_user`, `sh_write_user`,密码均为 `write_pwd`。SQL 语句为: + +```SQL +CREATE USER bj_write_user 'write_pwd' +CREATE USER sh_write_user 'write_pwd' +``` + +使用展示用户的 SQL 语句: + +```Plain +LIST USER +``` + +可以看到这两个已经被创建的用户,结果如下: + +```sql ++-------------+ +| User| ++-------------+ +|bj_write_user| +| root| +|sh_write_user| ++-------------+ +``` + +### 5.2 赋予用户权限 + +虽然两个用户已经创建,但是不具有任何权限,因此并不能对数据库进行操作,例如使用 `bj_write_user` 用户对 table1 中的数据进行写入,SQL 语句为: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +``` + +系统不允许用户进行此操作,会提示错误: + +```sql +IoTDB> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 701: database is not specified +IoTDB> use database1 +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: DATABASE database1 +``` + +root 用户使用 `GRANT ON TO USER ` 语句赋予用户`bj_write_user`对 table1 的写入权限,例如: + +```sql +GRANT INSERT ON database1.table1 TO USER bj_write_user +``` + +使用`bj_write_user`再尝试写入数据 + +```SQL +IoTDB> use database1 +Msg: The statement is executed successfully. +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: The statement is executed successfully. +``` + +### 5.3 撤销用户权限 + +授予用户权限后,可以使用 `REVOKE ON FROM USER `来撤销已经授予用户的权限。例如,用root用户撤销`bj_write_user`和`sh_write_user`的权限: + +```sql +REVOKE INSERT ON database1.table1 FROM USER bj_write_user +REVOKE INSERT ON database1.table2 FROM USER sh_write_user +``` + +撤销权限后,`bj_write_user`就没有向table1写入数据的权限了。 + +```sql +IoTDB:database1> INSERT INTO table1(region, plant_id, device_id, model_id, maintenance, time, temperature, humidity, status, arrival_time) VALUES ('北京', '1001', '100', 'A', '180', '2025-03-26 13:37:00', 190.0, 30.1, false, '2025-03-26 13:37:34') +Msg: org.apache.iotdb.jdbc.IoTDBSQLException: 803: Access Denied: No permissions for this operation, please add privilege INSERT ON database1.table1 +``` diff --git a/src/zh/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md b/src/zh/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md index bfcac2816..4a54464e8 100644 --- a/src/zh/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md +++ b/src/zh/UserGuide/latest-Table/User-Manual/Data-Sync_timecho.md @@ -574,20 +574,20 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| **参数** | **描述** | **value 取值范围** | **是否必填** | **默认取值** | -|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| -------- | ------------ | -| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| **参数** | **描述** | **value 取值范围** | **是否必填** | **默认取值** | +|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| -------- |---------------------------------| +| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | #### iotdb-air-gap-sink @@ -597,7 +597,7 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | | node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | | user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | | compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | | rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | @@ -611,7 +611,7 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | | node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | | user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | | batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | | batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | @@ -640,6 +640,6 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 | sink.opcua.security.dir | OPC UA 的密钥及证书目录 | String: Path,支持绝对及相对目录 | 选填 | iotdb 相关 DataNode 的 conf 目录下的 opc_security 文件夹 ``。
如无 iotdb 的 conf 目录(例如 IDEA 中启动 DataNode),则为用户主目录下的 iotdb_opc_security 文件夹 `` | | sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | | sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | -| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | root | +| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | TimechoDB@2021,V2.0.6.x之前为 root | | sink.opcua.placeholder | 当ID列的值出现null时,用于替代null映射路径的占位字符串 | String | 选填 | "null" | diff --git a/src/zh/UserGuide/latest/API/Programming-Data-Subscription.md b/src/zh/UserGuide/latest/API/Programming-Data-Subscription_apache.md similarity index 99% rename from src/zh/UserGuide/latest/API/Programming-Data-Subscription.md rename to src/zh/UserGuide/latest/API/Programming-Data-Subscription_apache.md index 8a81d432d..aa103544a 100644 --- a/src/zh/UserGuide/latest/API/Programming-Data-Subscription.md +++ b/src/zh/UserGuide/latest/API/Programming-Data-Subscription_apache.md @@ -21,7 +21,7 @@ # 数据订阅API -IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription.md) +IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription_apache) ## 1. 核心步骤 @@ -33,7 +33,7 @@ IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时 ## 2. 详细步骤 -本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API.md#_3-全量接口说明) +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_apache#_3-全量接口说明) ### 2.1 创建maven项目 diff --git a/src/zh/UserGuide/latest/API/Programming-Data-Subscription_timecho.md b/src/zh/UserGuide/latest/API/Programming-Data-Subscription_timecho.md new file mode 100644 index 000000000..a927d366c --- /dev/null +++ b/src/zh/UserGuide/latest/API/Programming-Data-Subscription_timecho.md @@ -0,0 +1,267 @@ + + + + +# 数据订阅API + +IoTDB 提供了强大的数据订阅功能,允许用户通过订阅 API 实时获取 IoTDB 新增的数据。详细的功能定义及介绍:[数据订阅](../User-Manual/Data-subscription_timecho) + +## 1. 核心步骤 + +1. 创建Topic:创建一个Topic,Topic中包含希望订阅的测点。 +2. 订阅Topic:在 consumer 订阅 topic 前,topic 必须已经被创建,否则订阅会失败。同一个 consumer group 下的 consumers 会均分数据。 +3. 消费数据:只有显式订阅了某个 topic,才会收到对应 topic 的数据。 +4. 取消订阅: consumer close 时会退出对应的 consumer group,同时取消现存的所有订阅。 + + +## 2. 详细步骤 + +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_timecho#_3-全量接口说明) + + +### 2.1 创建maven项目 + +创建一个maven项目,并导入以下依赖(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 代码案例 + +#### 2.2.1 Topic操作 + +```java +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.SubscriptionSession; +import org.apache.iotdb.session.subscription.model.Topic; + +public class DataConsumerExample { + + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + try (SubscriptionSession session = new SubscriptionSession("127.0.0.1", 6667, "root", "TimechoDB@2021", 67108864)) { //V2.0.6.x 之前默认密码为root + // 1. open session + session.open(); + + // 2. create a topic of all data + Properties sessionConfig = new Properties(); + sessionConfig.put(TopicConstant.PATH_KEY, "root.**"); + + session.createTopic("allData", sessionConfig); + + // 3. show all topics + Set topics = session.getTopics(); + System.out.println(topics); + + // 4. show a specific topic + Optional allData = session.getTopic("allData"); + System.out.println(allData.get()); + } + } +} +``` + +#### 2.2.2 数据消费 + +##### 场景-1: 订阅IoTDB中新增的实时数据(大屏或组态展示的场景) + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessageType; +import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.tsfile.read.common.RowRecord; + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + + // 5. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021"); //V2.0.6.x 之前默认密码为root + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + final short messageType = message.getMessageType(); + if (SubscriptionMessageType.isValidatedMessageType(messageType)) { + for (final SubscriptionSessionDataSet dataSet : message.getSessionDataSetsHandler()) { + while (dataSet.hasNext()) { + final RowRecord record = dataSet.next(); + System.out.println(record); + } + } + } + } + } + } + } +} + + +``` + +##### 场景-2:订阅新增的 TsFile(定期数据备份的场景) + +前提:需要被消费的topic的格式为TsfileHandler类型,举例:`create topic topic_all_tsfile with ('path'='root.**','format'='TsFileHandler')` + +```java +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; +import org.apache.iotdb.rpc.subscription.config.TopicConstant; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; + + +public class DataConsumerExample { + + public static void main(String[] args) throws IOException { + // 1. create a pull consumer, the subscription is automatically cancelled when the logic in the try resources is completed + Properties consumerConfig = new Properties(); + consumerConfig.put(ConsumerConstant.CONSUMER_ID_KEY, "c1"); + consumerConfig.put(ConsumerConstant.CONSUMER_GROUP_ID_KEY, "cg1"); + consumerConfig.put(ConsumerConstant.USERNAME_KEY, "root"); + consumerConfig.put(ConsumerConstant.PASSWORD_KEY, "TimechoDB@2021");//V2.0.6.x 之前默认密码为root + consumerConfig.put(ConsumerConstant.FILE_SAVE_DIR_KEY, "/Users/iotdb/Downloads"); + try (SubscriptionPullConsumer pullConsumer = new SubscriptionPullConsumer(consumerConfig)) { + pullConsumer.open(); + pullConsumer.subscribe("topic_all_tsfile"); + while (true) { + List messages = pullConsumer.poll(10000); + for (final SubscriptionMessage message : messages) { + message.getTsFileHandler().copyFile("/Users/iotdb/Downloads/1.tsfile"); + } + } + } + } +} +``` + + + + +## 3. 全量接口说明 + +### 3.1 参数列表 + +可通过Properties参数对象设置消费者相关参数,具体参数如下。 + +#### 3.1.1 SubscriptionConsumer + + +| 参数 | 是否必填(默认值) | 参数含义 | +| :---------------------- |:-------------------------------------------------------------------------------------| :----------------------------------------------------------- | +| host | optional: 127.0.0.1 | `String`: IoTDB 中某 DataNode 的 RPC host | +| port | optional: 6667 | `Integer`: IoTDB 中某 DataNode 的 RPC port | +| node-urls | optional: 127.0.0.1:6667 | `List`: IoTDB 中所有 DataNode 的 RPC 地址,可以是多个;host:port 和 node-urls 选填一个即可。当 host:port 和 node-urls 都填写了,则取 host:port 和 node-urls 的**并集**构成新的 node-urls 应用 | +| username | optional: root | `String`: IoTDB 中 DataNode 的用户名 | +| password | optional: TimechoDB@2021 //V2.0.6.x 之前默认密码为root | `String`: IoTDB 中 DataNode 的密码 | +| groupId | optional | `String`: consumer group id,若未指定则随机分配(新的 consumer group),保证不同的 consumer group 对应的 consumer group id 均不相同 | +| consumerId | optional | `String`: consumer client id,若未指定则随机分配,保证同一个 consumer group 中每一个 consumer client id 均不相同 | +| heartbeatIntervalMs | optional: 30000 (min: 1000) | `Long`: consumer 向 IoTDB DataNode 定期发送心跳请求的间隔 | +| endpointsSyncIntervalMs | optional: 120000 (min: 5000) | `Long`: consumer 探测 IoTDB 集群节点扩缩容情况调整订阅连接的间隔 | +| fileSaveDir | optional: Paths.get(System.getProperty("user.dir"), "iotdb-subscription").toString() | `String`: consumer 订阅出的 TsFile 文件临时存放的目录路径 | +| fileSaveFsync | optional: false | `Boolean`: consumer 订阅 TsFile 的过程中是否主动调用 fsync | + +`SubscriptionPushConsumer` 中的特殊配置: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :----------------- | :------------------------------------ | :----------------------------------------------------------- | +| ackStrategy | optional: `ACKStrategy.AFTER_CONSUME` | 消费进度的确认机制包含以下选项:`ACKStrategy.BEFORE_CONSUME`(当 consumer 收到数据时立刻提交消费进度,`onReceive` 前)`ACKStrategy.AFTER_CONSUME`(当 consumer 消费完数据再去提交消费进度,`onReceive` 后) | +| consumeListener | optional | 消费数据的回调函数,需实现 `ConsumeListener` 接口,定义消费 `SessionDataSetsHandler` 和 `TsFileHandler` 形式数据的处理逻辑 | +| autoPollIntervalMs | optional: 5000 (min: 500) | Long: consumer 自动拉取数据的时间间隔,单位为**毫秒** | +| autoPollTimeoutMs | optional: 10000 (min: 1000) | Long: consumer 每次拉取数据的超时时间,单位为**毫秒** | + +`SubscriptionPullConsumer` 中的特殊配置: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :----------------- | :------------------------ | :----------------------------------------------------------- | +| autoCommit | optional: true | Boolean: 是否自动提交消费进度如果此参数设置为 false,则需要调用 `commit` 方法来手动提交消费进度 | +| autoCommitInterval | optional: 5000 (min: 500) | Long: 自动提交消费进度的时间间隔,单位为**毫秒**仅当 autoCommit 参数为 true 的时候才会生效 | + + +### 3.2 函数列表 + +#### 3.2.1 数据订阅 + +##### SubscriptionPullConsumer + +| **函数名** | **说明** | **参数** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `open()` | 打开消费者连接,启动消息消费。如果 `autoCommit` 启用,会启动自动提交工作器。 | 无 | +| `close()` | 关闭消费者连接。如果 `autoCommit` 启用,会在关闭前提交所有未提交的消息。 | 无 | +| `poll(final Duration timeout)` | 拉取消息,指定超时时间。 | `timeout` : 拉取的超时时间。 | +| `poll(final long timeoutMs)` | 拉取消息,指定超时时间(毫秒)。 | `timeoutMs` : 超时时间,单位为毫秒。 | +| `poll(final Set topicNames, final Duration timeout)` | 拉取指定主题的消息,指定超时时间。 | `topicNames` : 要拉取的主题集合。`timeout`: 超时时间。 | +| `poll(final Set topicNames, final long timeoutMs)` | 拉取指定主题的消息,指定超时时间(毫秒)。 | `topicNames` : 要拉取的主题集合。`timeoutMs`: 超时时间,单位为毫秒。 | +| `commitSync(final SubscriptionMessage message)` | 同步提交单条消息。 | `message` : 需要提交的消息对象。 | +| `commitSync(final Iterable messages)` | 同步提交多条消息。 | `messages` : 需要提交的消息集合。 | +| `commitAsync(final SubscriptionMessage message)` | 异步提交单条消息。 | `message` : 需要提交的消息对象。 | +| `commitAsync(final Iterable messages)` | 异步提交多条消息。 | `messages` : 需要提交的消息集合。 | +| `commitAsync(final SubscriptionMessage message, final AsyncCommitCallback callback)` | 异步提交单条消息并指定回调函数。 | `message` : 需要提交的消息对象。`callback` : 异步提交完成后的回调函数。 | +| `commitAsync(final Iterable messages, final AsyncCommitCallback callback)` | 异步提交多条消息并指定回调函数。 | `messages` : 需要提交的消息集合。`callback` : 异步提交完成后的回调函数。 | + +##### SubscriptionPushConsumer + +| **函数名** | **说明** | **参数** | +| -------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------- | +| `open()` | 打开消费者连接,启动消息消费,提交自动轮询工作器。 | 无 | +| `close()` | 关闭消费者连接,停止消息消费。 | 无 | +| `toString()` | 返回消费者对象的核心配置信息。 | 无 | +| `coreReportMessage()` | 获取消费者核心配置的键值对表示形式。 | 无 | +| `allReportMessage()` | 获取消费者所有配置的键值对表示形式。 | 无 | +| `buildPushConsumer()` | 通过 `Builder` 构建 `SubscriptionPushConsumer` 实例。 | 无 | +| `ackStrategy(final AckStrategy ackStrategy)` | 配置消费者的消息确认策略。 | `ackStrategy`: 指定的消息确认策略。 | +| `consumeListener(final ConsumeListener consumeListener)` | 配置消费者的消息消费逻辑。 | `consumeListener`: 消费者接收消息时的处理逻辑。 | +| `autoPollIntervalMs(final long autoPollIntervalMs)` | 配置自动轮询的时间间隔。 | `autoPollIntervalMs` : 自动轮询的间隔时间,单位为毫秒。 | +| `autoPollTimeoutMs(final long autoPollTimeoutMs)` | 配置自动轮询的超时时间。 | `autoPollTimeoutMs`: 自动轮询的超时时间,单位为毫秒。 | + + + + + + + + + diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-JDBC.md b/src/zh/UserGuide/latest/API/Programming-JDBC_apache.md similarity index 99% rename from src/zh/UserGuide/Master/Tree/API/Programming-JDBC.md rename to src/zh/UserGuide/latest/API/Programming-JDBC_apache.md index 498800e7d..f0b6ad75c 100644 --- a/src/zh/UserGuide/Master/Tree/API/Programming-JDBC.md +++ b/src/zh/UserGuide/latest/API/Programming-JDBC_apache.md @@ -22,7 +22,8 @@ # JDBC **注意**: 目前的JDBC实现仅是为与第三方工具连接使用的。不推荐使用 JDBC (执行插入语句时),因无法提供高性能写入,查询推荐使用 JDBC。 -对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API.md)* + +对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API_apache)* ## 1. 依赖 diff --git a/src/zh/UserGuide/latest/API/Programming-JDBC_timecho.md b/src/zh/UserGuide/latest/API/Programming-JDBC_timecho.md new file mode 100644 index 000000000..d1e85f72c --- /dev/null +++ b/src/zh/UserGuide/latest/API/Programming-JDBC_timecho.md @@ -0,0 +1,293 @@ + + +# JDBC + +**注意**: 目前的JDBC实现仅是为与第三方工具连接使用的。不推荐使用 JDBC (执行插入语句时),因无法提供高性能写入,查询推荐使用 JDBC。 + +对于Java应用,我们推荐使用[Java 原生接口](./Programming-Java-Native-API_timecho)* + +## 1. 依赖 + +* JDK >= 1.8 +* Maven >= 3.6 + +## 2. 安装方法 + +在根目录下执行下面的命令: +```shell +mvn clean install -pl iotdb-client/jdbc -am -DskipTests +``` + +### 2.1 在 MAVEN 中使用 IoTDB JDBC + +```xml + + + org.apache.iotdb + iotdb-jdbc + 1.3.1 + + +``` + +### 2.2 示例代码 + +本章提供了如何建立数据库连接、执行 SQL 和显示查询结果的示例。 + +要求您已经在工程中包含了数据库编程所需引入的包和 JDBC class. + +**注意:为了更快地插入,建议使用 executeBatch()** + +```java +import java.sql.*; +import org.apache.iotdb.jdbc.IoTDBSQLException; + +public class JDBCExample { + /** + * Before executing a SQL statement with a Statement object, you need to create a Statement object using the createStatement() method of the Connection object. + * After creating a Statement object, you can use its execute() method to execute a SQL statement + * Finally, remember to close the 'statement' and 'connection' objects by using their close() method + * For statements with query results, we can use the getResultSet() method of the Statement object to get the result set. + */ + public static void main(String[] args) throws SQLException { + Connection connection = getConnection(); + if (connection == null) { + System.out.println("get connection defeat"); + return; + } + Statement statement = connection.createStatement(); + //Create database + try { + statement.execute("CREATE DATABASE root.demo"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + + //SHOW DATABASES + statement.execute("SHOW DATABASES"); + outputResult(statement.getResultSet()); + + //Create time series + //Different data type has different encoding methods. Here use INT32 as an example + try { + statement.execute("CREATE TIMESERIES root.demo.s0 WITH DATATYPE=INT32,ENCODING=RLE;"); + }catch (IoTDBSQLException e){ + System.out.println(e.getMessage()); + } + //Show time series + statement.execute("SHOW TIMESERIES root.demo"); + outputResult(statement.getResultSet()); + //Show devices + statement.execute("SHOW DEVICES"); + outputResult(statement.getResultSet()); + //Count time series + statement.execute("COUNT TIMESERIES root"); + outputResult(statement.getResultSet()); + //Count nodes at the given level + statement.execute("COUNT NODES root LEVEL=3"); + outputResult(statement.getResultSet()); + //Count timeseries group by each node at the given level + statement.execute("COUNT TIMESERIES root GROUP BY LEVEL=3"); + outputResult(statement.getResultSet()); + + + //Execute insert statements in batch + statement.addBatch("insert into root.demo(timestamp,s0) values(1,1);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(2,15);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(2,17);"); + statement.addBatch("insert into root.demo(timestamp,s0) values(4,12);"); + statement.executeBatch(); + statement.clearBatch(); + + //Full query statement + String sql = "select * from root.demo"; + ResultSet resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Exact query statement + sql = "select s0 from root.demo where time = 4;"; + resultSet= statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Time range query + sql = "select s0 from root.demo where time >= 2 and time < 5;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Aggregate query + sql = "select count(s0) from root.demo;"; + resultSet = statement.executeQuery(sql); + System.out.println("sql: " + sql); + outputResult(resultSet); + + //Delete time series + statement.execute("delete timeseries root.demo.s0"); + + //close connection + statement.close(); + connection.close(); + } + + public static Connection getConnection() { + // JDBC driver name and database URL + String driver = "org.apache.iotdb.jdbc.IoTDBDriver"; + String url = "jdbc:iotdb://127.0.0.1:6667/"; + // set rpc compress mode + // String url = "jdbc:iotdb://127.0.0.1:6667?rpc_compress=true"; + + // Database credentials + String username = "root"; + String password = "TimechoDB@2021"; // V2.0.6.x 之前默认密码是 root + + Connection connection = null; + try { + Class.forName(driver); + connection = DriverManager.getConnection(url, username, password); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return connection; + } + + /** + * This is an example of outputting the results in the ResultSet + */ + private static void outputResult(ResultSet resultSet) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print(resultSet.getString(i)); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` + +可以在 url 中指定 version 参数: +```java +String url = "jdbc:iotdb://127.0.0.1:6667?version=V_1_0"; +``` +version 表示客户端使用的 SQL 语义版本,用于升级 0.13 时兼容 0.12 的 SQL 语义,可能取值有:`V_0_12`、`V_0_13`、`V_1_0`。 + +此外,IoTDB 在 JDBC 中提供了额外的接口,供用户在连接中使用不同的字符集(例如 GB18030)读写数据库。 +IoTDB 默认的字符集为 UTF-8。当用户期望使用 UTF-8 外的字符集时,需要在 JDBC 的连接中,指定 charset 属性。例如: +1. 使用 GB18030 的 charset 创建连接: +```java +DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021") +// V2.0.6.x 之前默认密码是 root +``` +2. 调用如下 `IoTDBStatement` 接口执行 SQL 时,可以接受 `byte[]` 编码的 SQL,该 SQL 将按照被指定的 charset 解析成字符串。 +```java +public boolean execute(byte[] sql) throws SQLException; +``` +3. 查询结果输出时,可使用 `ResultSet` 的 `getBytes` 方法得到的 `byte[]`,`byte[]` 的编码使用连接指定的 charset 进行。 +```java +System.out.print(resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); +``` +以下是完整示例: +```java +public class JDBCCharsetExample { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCCharsetExample.class); + + public static void main(String[] args) throws Exception { + Class.forName("org.apache.iotdb.jdbc.IoTDBDriver"); + + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=GB18030", "root", "TimechoDB@2021"); // V2.0.6.x 之前默认密码是 root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + + final String insertSQLWithGB18030 = + "insert into root.测试(timestamp, 维语, 彝语, 繁体, 蒙文, 简体, 标点符号, 藏语) values(1, 'ئۇيغۇر تىلى', 'ꆈꌠꉙ', \"繁體\", 'ᠮᠣᠩᠭᠣᠯ ᠬᠡᠯᠡ', '简体', '——?!', \"བོད་སྐད།\");"; + final byte[] insertSQLWithGB18030Bytes = insertSQLWithGB18030.getBytes("GB18030"); + statement.execute(insertSQLWithGB18030Bytes); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + + outputResult("GB18030"); + outputResult("UTF-8"); + outputResult("UTF-16"); + outputResult("GBK"); + outputResult("ISO-8859-1"); + } + + private static void outputResult(String charset) throws SQLException { + System.out.println("[Charset: " + charset + "]"); + try (final Connection connection = + DriverManager.getConnection( + "jdbc:iotdb://127.0.0.1:6667?charset=" + charset, "root", "TimechoDB@2021"); // V2.0.6.x 之前默认密码是 root + final IoTDBStatement statement = (IoTDBStatement) connection.createStatement()) { + outputResult(statement.executeQuery("select ** from root"), Charset.forName(charset)); + } catch (IoTDBSQLException e) { + LOGGER.error("IoTDB Jdbc example error", e); + } + } + + private static void outputResult(ResultSet resultSet, Charset charset) throws SQLException { + if (resultSet != null) { + System.out.println("--------------------------"); + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + System.out.print(metaData.getColumnLabel(i + 1) + " "); + } + System.out.println(); + + while (resultSet.next()) { + for (int i = 1; ; i++) { + System.out.print( + resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")"); + if (i < columnCount) { + System.out.print(", "); + } else { + System.out.println(); + break; + } + } + } + System.out.println("--------------------------\n"); + } + } +} +``` \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API.md b/src/zh/UserGuide/latest/API/Programming-Java-Native-API_apache.md similarity index 99% rename from src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API.md rename to src/zh/UserGuide/latest/API/Programming-Java-Native-API_apache.md index c7673d125..9519ba080 100644 --- a/src/zh/UserGuide/Master/Tree/API/Programming-Java-Native-API.md +++ b/src/zh/UserGuide/latest/API/Programming-Java-Native-API_apache.md @@ -31,7 +31,7 @@ SessionPool 是 Session 的连接池,推荐使用SessionPool编程。在多线 ## 2. 详细步骤 -本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API.md#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/master/example/session/src/main/java/org/apache/iotdb) +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_apache#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) ### 2.1 创建maven项目 @@ -121,7 +121,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } @@ -223,7 +223,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } @@ -349,7 +349,7 @@ public class SessionPoolExample { new SessionPool.Builder() .nodeUrls(nodeUrls) .user("root") - .password("root") + .password("root") .maxSize(3) .build(); } diff --git a/src/zh/UserGuide/latest/API/Programming-Java-Native-API_timecho.md b/src/zh/UserGuide/latest/API/Programming-Java-Native-API_timecho.md new file mode 100644 index 000000000..c238e4fe9 --- /dev/null +++ b/src/zh/UserGuide/latest/API/Programming-Java-Native-API_timecho.md @@ -0,0 +1,499 @@ + + + +# Java原生API + +IoTDB 原生 API 中的 Session 是实现与数据库交互的核心接口,它集成了丰富的方法,支持数据写入、查询以及元数据操作等功能。通过实例化 Session,能够建立与 IoTDB 服务器的连接,在该连接所构建的环境中执行各类数据库操作。Session为非线程安全,不能被多线程同时调用。 + +SessionPool 是 Session 的连接池,推荐使用SessionPool编程。在多线程并发的情形下,SessionPool 能够合理地管理和分配连接资源,以提升系统性能与资源利用效率。 + +## 1. 步骤概览 + +1. 创建连接池实例:初始化一个SessionPool对象,用于管理多个Session实例。 +2. 执行操作:直接从SessionPool中获取Session实例,并执行数据库操作,无需每次都打开和关闭连接。 +3. 关闭连接池资源:在不再需要进行数据库操作时,关闭SessionPool,释放所有相关资源。 + +## 2. 详细步骤 + +本章节用于说明开发的核心流程,并未演示所有的参数和接口,如需了解全部功能及参数请参见: [全量接口说明](./Programming-Java-Native-API_timecho#_3-全量接口说明) 或 查阅: [源码](https://github.com/apache/iotdb/tree/rc/2.0.1/example/session/src/main/java/org/apache/iotdb) + +### 2.1 创建maven项目 + +创建一个maven项目,并在pom.xml文件中添加以下依赖(JDK >= 1.8, Maven >= 3.6) + +```xml + + + org.apache.iotdb + iotdb-session + + ${project.version} + + +``` + +### 2.2 创建连接池实例 + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.session.pool.SessionPool; + +public class IoTDBSessionPoolExample { + private static SessionPool sessionPool; + + public static void main(String[] args) { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } +} +``` + +### 2.3 执行数据库操作 + +#### 2.3.1 数据写入 + +在工业场景中,数据写入可分为以下几类:多行数据写入、单设备多行数据写入,下面按不同场景对写入接口进行介绍。 + +##### 多行数据写入接口 + +接口说明:支持一次写入多行数据,每一行对应一个设备一个时间戳的多个测点值。 + + +接口列表: + +| 接口名称 | 功能描述 | +| ------------------------------------------------------------ | ------------------------------------------ | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多行数据,适用于不同测点独立采集的场景 | + +代码案例: + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertRecordsExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + public static void insertRecordsExample() throws IoTDBConnectionException, StatementExecutionException { + String deviceId = "root.sg1.d1"; + List measurements = new ArrayList<>(); + measurements.add("s1"); + measurements.add("s2"); + measurements.add("s3"); + List deviceIds = new ArrayList<>(); + List> measurementsList = new ArrayList<>(); + List> valuesList = new ArrayList<>(); + List timestamps = new ArrayList<>(); + List> typesList = new ArrayList<>(); + + for (long time = 0; time < 500; time++) { + List values = new ArrayList<>(); + List types = new ArrayList<>(); + values.add(1L); + values.add(2L); + values.add(3L); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + types.add(TSDataType.INT64); + + deviceIds.add(deviceId); + measurementsList.add(measurements); + valuesList.add(values); + typesList.add(types); + timestamps.add(time); + if (time != 0 && time % 100 == 0) { + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + deviceIds.clear(); + measurementsList.clear(); + valuesList.clear(); + typesList.clear(); + timestamps.clear(); + } + } + try { + sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList); + } catch (IoTDBConnectionException | StatementExecutionException e) { + // solve exception + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +##### 单设备多行数据写入接口 + +接口说明:支持一次写入单个设备的多行数据,每一行对应一个时间戳的多个测点值。 + +接口列表: + +| 接口名称 | 功能描述 | +| ----------------------------- | ---------------------------------------------------- | +| `insertTablet(Tablet tablet)` | 插入单个设备的多行数据,适用于不同测点独立采集的场景 | + +代码案例: + +```java +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.write.record.Tablet; +import org.apache.tsfile.write.schema.IMeasurementSchema; +import org.apache.tsfile.write.schema.MeasurementSchema; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. execute insert data + insertTabletExample(); + // 3. close SessionPool + closeSessionPool(); + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + //nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + private static void insertTabletExample() throws IoTDBConnectionException, StatementExecutionException { + /* + * A Tablet example: + * device1 + * time s1, s2, s3 + * 1, 1, 1, 1 + * 2, 2, 2, 2 + * 3, 3, 3, 3 + */ + // The schema of measurements of one device + // only measurementId and data type in MeasurementSchema take effects in Tablet + List schemaList = new ArrayList<>(); + schemaList.add(new MeasurementSchema("s1", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s2", TSDataType.INT64)); + schemaList.add(new MeasurementSchema("s3", TSDataType.INT64)); + + Tablet tablet = new Tablet("root.sg.d1",schemaList,100); + + // Method 1 to add tablet data + long timestamp = System.currentTimeMillis(); + + Random random = new Random(); + for (long row = 0; row < 100; row++) { + int rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, timestamp); + for (int s = 0; s < 3; s++) { + long value = random.nextLong(); + tablet.addValue(schemaList.get(s).getMeasurementName(), rowIndex, value); + } + if (tablet.getRowSize() == tablet.getMaxRowNumber()) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + timestamp++; + } + if (tablet.getRowSize() != 0) { + sessionPool.insertTablet(tablet); + tablet.reset(); + } + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +#### 2.3.2 SQL操作 + +SQL操作分为查询和非查询两类操作,对应的接口为`executeQuery`和`executeNonQuery`操作,其区别为前者执行的是具体的查询语句,会返回一个结果集,后者是执行的是增、删、改操作,不返回结果集。 + +```java +import java.util.ArrayList; +import java.util.List; +import org.apache.iotdb.isession.pool.SessionDataSetWrapper; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.pool.SessionPool; + +public class SessionPoolExample { + private static SessionPool sessionPool; + public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException { + // 1. init SessionPool + constructSessionPool(); + // 2. executes a non-query SQL statement, such as a DDL or DML command. + executeQueryExample(); + // 3. executes a query SQL statement and returns the result set. + executeNonQueryExample(); + // 4. close SessionPool + closeSessionPool(); + } + + private static void executeNonQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. create a nonAligned time series + sessionPool.executeNonQueryStatement("create timeseries root.test.d1.s1 with dataType = int32"); + // 2. set ttl + sessionPool.executeNonQueryStatement("set TTL to root.test.** 10000"); + // 3. delete time series + sessionPool.executeNonQueryStatement("delete timeseries root.test.d1.s1"); + } + + private static void executeQueryExample() throws IoTDBConnectionException, StatementExecutionException { + // 1. execute normal query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select s1 from root.sg1.d1 limit 10")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + // 2. execute aggregate query + try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select count(s1) from root.sg1.d1 group by ([0, 40), 5ms) ")) { + // get DataIterator like JDBC + DataIterator dataIterator = wrapper.iterator(); + System.out.println(wrapper.getColumnNames()); + System.out.println(wrapper.getColumnTypes()); + while (dataIterator.next()) { + StringBuilder builder = new StringBuilder(); + for (String columnName : wrapper.getColumnNames()) { + builder.append(dataIterator.getString(columnName) + " "); + } + System.out.println(builder); + } + } + } + + private static void constructSessionPool() { + // Using nodeUrls ensures that when one node goes down, other nodes are automatically connected to retry + List nodeUrls = new ArrayList<>(); + nodeUrls.add("127.0.0.1:6667"); + nodeUrls.add("127.0.0.1:6668"); + sessionPool = + new SessionPool.Builder() + .nodeUrls(nodeUrls) + .user("root") + .password("TimechoDB@2021") //V2.0.6.x 之前默认密码为root + .maxSize(3) + .build(); + } + + public static void closeSessionPool(){ + sessionPool.close(); + } +} +``` + +## 3. 全量接口说明 + +### 3.1 参数列表 + +Session具有如下的字段,可以通过构造函数或Session.Builder方式设置如下参数 + +| 字段名 | 类型 | 说明 | +| -------------------------------- | ----------------------------------- | ---------------------------------------- | +| `nodeUrls` | `List` | 数据库节点的 URL 列表,支持多节点连接 | +| `username` | `String` | 用户名 | +| `password` | `String` | 密码 | +| `fetchSize` | `int` | 查询结果的默认批量返回大小 | +| `useSSL` | `boolean` | 是否启用 SSL | +| `trustStore` | `String` | 信任库路径 | +| `trustStorePwd` | `String` | 信任库密码 | +| `queryTimeoutInMs` | `long` | 查询的超时时间,单位毫秒 | +| `enableRPCCompression` | `boolean` | 是否启用 RPC 压缩 | +| `connectionTimeoutInMs` | `int` | 连接超时时间,单位毫秒 | +| `zoneId` | `ZoneId` | 会话的时区设置 | +| `thriftDefaultBufferSize` | `int` | Thrift 默认缓冲区大小 | +| `thriftMaxFrameSize` | `int` | Thrift 最大帧大小 | +| `defaultEndPoint` | `TEndPoint` | 默认的数据库端点信息 | +| `defaultSessionConnection` | `SessionConnection` | 默认的会话连接对象 | +| `isClosed` | `boolean` | 当前会话是否已关闭 | +| `enableRedirection` | `boolean` | 是否启用重定向功能 | +| `enableRecordsAutoConvertTablet` | `boolean` | 是否启用记录自动转换为 Tablet 的功能 | +| `deviceIdToEndpoint` | `Map` | 设备 ID 和数据库端点的映射关系 | +| `endPointToSessionConnection` | `Map` | 数据库端点和会话连接的映射关系 | +| `executorService` | `ScheduledExecutorService` | 用于定期更新节点列表的线程池 | +| `availableNodes` | `INodeSupplier` | 可用节点的供应器 | +| `enableQueryRedirection` | `boolean` | 是否启用查询重定向功能 | +| `version` | `Version` | 客户端的版本号,用于与服务端的兼容性判断 | +| `enableAutoFetch` | `boolean` | 是否启用自动获取功能 | +| `maxRetryCount` | `int` | 最大重试次数 | +| `retryIntervalInMs` | `long` | 重试的间隔时间,单位毫秒 | + + + +### 3.2 接口列表 + +#### 3.2.1 元数据管理 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ------------------------ | ------------------------------------------------------------ | +| `createDatabase(String database)` | 创建数据库 | `database`: 数据库名称 | +| `deleteDatabase(String database)` | 删除指定数据库 | `database`: 要删除的数据库名称 | +| `deleteDatabases(List databases)` | 批量删除数据库 | `databases`: 要删除的数据库名称列表 | +| `createTimeseries(String path, TSDataType dataType, TSEncoding encoding, CompressionType compressor)` | 创建单个时间序列 | `path`: 时间序列路径,`dataType`: 数据类型,`encoding`: 编码类型,`compressor`: 压缩类型 | +| `createAlignedTimeseries(...)` | 创建对齐时间序列 | 设备ID、测点列表、数据类型列表、编码列表、压缩类型列表 | +| `createMultiTimeseries(...)` | 批量创建时间序列 | 多个路径、数据类型、编码、压缩类型、属性、标签、别名等 | +| `deleteTimeseries(String path)` | 删除时间序列 | `path`: 要删除的时间序列路径 | +| `deleteTimeseries(List paths)` | 批量删除时间序列 | `paths`: 要删除的时间序列路径列表 | +| `setSchemaTemplate(String templateName, String prefixPath)` | 设置模式模板 | `templateName`: 模板名称,`prefixPath`: 应用模板的路径 | +| `createSchemaTemplate(Template template)` | 创建模式模板 | `template`: 模板对象 | +| `dropSchemaTemplate(String templateName)` | 删除模式模板 | `templateName`: 要删除的模板名称 | +| `addAlignedMeasurementsInTemplate(...)` | 添加对齐测点到模板 | 模板名称、测点路径列表、数据类型、编码类型、压缩类型 | +| `addUnalignedMeasurementsInTemplate(...)` | 添加非对齐测点到模板 | 同上 | +| `deleteNodeInTemplate(String templateName, String path)` | 删除模板中的节点 | `templateName`: 模板名称,`path`: 要删除的路径 | +| `countMeasurementsInTemplate(String name)` | 统计模板中测点数量 | `name`: 模板名称 | +| `isMeasurementInTemplate(String templateName, String path)` | 检查模板中是否存在某测点 | `templateName`: 模板名称,`path`: 测点路径 | +| `isPathExistInTemplate(String templateName, String path)` | 检查模板中路径是否存在 | 同上 | +| `showMeasurementsInTemplate(String templateName)` | 显示模板中的测点 | `templateName`: 模板名称 | +| `showMeasurementsInTemplate(String templateName, String pattern)` | 按模式显示模板中的测点 | `templateName`: 模板名称,`pattern`: 匹配模式 | +| `showAllTemplates()` | 显示所有模板 | 无参数 | +| `showPathsTemplateSetOn(String templateName)` | 显示模板应用的路径 | `templateName`: 模板名称 | +| `showPathsTemplateUsingOn(String templateName)` | 显示模板实际使用的路径 | 同上 | +| `unsetSchemaTemplate(String prefixPath, String templateName)` | 取消路径的模板设置 | `prefixPath`: 路径,`templateName`: 模板名称 | + + +#### 3.2.2 数据写入 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------ | +| `insertRecord(String deviceId, long time, List measurements, List types, Object... values)` | 插入单条记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`types`: 数据类型列表,`values`: 值列表 | +| `insertRecord(String deviceId, long time, List measurements, List values)` | 插入单条记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`values`: 值列表 | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | 插入多条记录 | `deviceIds`: 设备ID列表,`times`: 时间戳列表,`measurementsList`: 测点列表列表,`valuesList`: 值列表 | +| `insertRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多条记录 | 同上,增加 `typesList`: 数据类型列表 | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入单设备的多条记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表列表,`typesList`: 类型列表,`valuesList`: 值列表 | +| `insertRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | 插入排序后的单设备多条记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | 插入字符串格式的单设备记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | 插入排序的字符串格式单设备记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List types, List values)` | 插入单条对齐记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`types`: 类型列表,`values`: 值列表 | +| `insertAlignedRecord(String deviceId, long time, List measurements, List values)` | 插入字符串格式的单条对齐记录 | `deviceId`: 设备ID,`time`: 时间戳,`measurements`: 测点列表,`values`: 值列表 | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> valuesList)` | 插入多条对齐记录 | `deviceIds`: 设备ID列表,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertAlignedRecords(List deviceIds, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入多条对齐记录 | 同上,增加 `typesList`: 数据类型列表 | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList)` | 插入单设备的多条对齐记录 | 同上 | +| `insertAlignedRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> typesList, List> valuesList, boolean haveSorted)` | 插入排序的单设备多条对齐记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList)` | 插入字符串格式的单设备对齐记录 | `deviceId`: 设备ID,`times`: 时间戳列表,`measurementsList`: 测点列表,`valuesList`: 值列表 | +| `insertAlignedStringRecordsOfOneDevice(String deviceId, List times, List> measurementsList, List> valuesList, boolean haveSorted)` | 插入排序的字符串格式单设备对齐记录 | 同上,增加 `haveSorted`: 数据是否已排序 | +| `insertTablet(Tablet tablet)` | 插入单个Tablet数据 | `tablet`: 要插入的Tablet数据 | +| `insertTablet(Tablet tablet, boolean sorted)` | 插入排序的Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertAlignedTablet(Tablet tablet)` | 插入对齐的Tablet数据 | `tablet`: 要插入的Tablet数据 | +| `insertAlignedTablet(Tablet tablet, boolean sorted)` | 插入排序的对齐Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertTablets(Map tablets)` | 批量插入多个Tablet数据 | `tablets`: 设备ID到Tablet的映射表 | +| `insertTablets(Map tablets, boolean sorted)` | 批量插入排序的多个Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | +| `insertAlignedTablets(Map tablets)` | 批量插入多个对齐Tablet数据 | `tablets`: 设备ID到Tablet的映射表 | +| `insertAlignedTablets(Map tablets, boolean sorted)` | 批量插入排序的多个对齐Tablet数据 | 同上,增加 `sorted`: 数据是否已排序 | + +#### 3.2.3 数据删除 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | ---------------------------- | ---------------------------------------- | +| `deleteTimeseries(String path)` | 删除单个时间序列 | `path`: 时间序列路径 | +| `deleteTimeseries(List paths)` | 批量删除时间序列 | `paths`: 时间序列路径列表 | +| `deleteData(String path, long endTime)` | 删除指定路径的历史数据 | `path`: 路径,`endTime`: 结束时间戳 | +| `deleteData(List paths, long endTime)` | 批量删除路径的历史数据 | `paths`: 路径列表,`endTime`: 结束时间戳 | +| `deleteData(List paths, long startTime, long endTime)` | 删除路径时间范围内的历史数据 | 同上,增加 `startTime`: 起始时间戳 | + + +#### 3.2.4 数据查询 + +| 方法名 | 功能描述 | 参数解释 | +| ------------------------------------------------------------ | -------------------------------- | ------------------------------------------------------------ | +| `executeQueryStatement(String sql)` | 执行查询语句 | `sql`: 查询SQL语句 | +| `executeQueryStatement(String sql, long timeoutInMs)` | 执行带超时的查询语句 | `sql`: 查询SQL语句,`timeoutInMs`: 查询超时时间(毫秒),默认取服务器配置即60s | +| `executeRawDataQuery(List paths, long startTime, long endTime)` | 查询指定路径的原始数据 | `paths`: 查询路径列表,`startTime`: 起始时间戳,`endTime`: 结束时间戳 | +| `executeRawDataQuery(List paths, long startTime, long endTime, long timeOut)` | 查询指定路径的原始数据(带超时) | 同上,增加 `timeOut`: 超时时间 | +| `executeLastDataQuery(List paths)` | 查询最新数据 | `paths`: 查询路径列表 | +| `executeLastDataQuery(List paths, long lastTime)` | 查询指定时间的最新数据 | `paths`: 查询路径列表,`lastTime`: 指定的时间戳 | +| `executeLastDataQuery(List paths, long lastTime, long timeOut)` | 查询指定时间的最新数据(带超时) | 同上,增加 `timeOut`: 超时时间 | +| `executeLastDataQueryForOneDevice(String db, String device, List sensors, boolean isLegalPathNodes)` | 查询单个设备的最新数据 | `db`: 数据库名,`device`: 设备名,`sensors`: 传感器列表,`isLegalPathNodes`: 是否合法路径节点 | +| `executeAggregationQuery(List paths, List aggregations)` | 执行聚合查询 | `paths`: 查询路径列表,`aggregations`: 聚合类型列表 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime)` | 执行带时间范围的聚合查询 | 同上,增加 `startTime`: 起始时间戳,`endTime`: 结束时间戳 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval)` | 执行带时间间隔的聚合查询 | 同上,增加 `interval`: 时间间隔 | +| `executeAggregationQuery(List paths, List aggregations, long startTime, long endTime, long interval, long slidingStep)` | 执行滑动窗口聚合查询 | 同上,增加 `slidingStep`: 滑动步长 | +| `fetchAllConnections()` | 获取所有活动连接信息 | 无参数 | + +#### 3.2.5 系统状态与备份 + +| 方法名 | 功能描述 | 参数解释 | +| -------------------------- | ---------------------- | -------------------------------------- | +| `getBackupConfiguration()` | 获取备份配置信息 | 无参数 | +| `fetchAllConnections()` | 获取所有活动的连接信息 | 无参数 | +| `getSystemStatus()` | 获取系统状态 | 已废弃,默认返回 `SystemStatus.NORMAL` | + + + diff --git a/src/zh/UserGuide/latest/API/Programming-OPC-UA_timecho.md b/src/zh/UserGuide/latest/API/Programming-OPC-UA_timecho.md index cc9436781..f37cfc625 100644 --- a/src/zh/UserGuide/latest/API/Programming-OPC-UA_timecho.md +++ b/src/zh/UserGuide/latest/API/Programming-OPC-UA_timecho.md @@ -76,23 +76,23 @@ create pipe p1 'sink.opcua.tcp.port' = '12686', 'sink.opcua.https.port' = '8443', 'sink.user' = 'root', - 'sink.password' = 'root', + 'sink.password' = 'TimechoDB@2021', //V2.0.6.x 之前默认密码为root 'sink.opcua.security.dir' = '...' ) ``` ### 2.2 参数 -| **参数** | **描述** | **取值范围** | **是否必填** | **默认值** | -| ---------------------------------- | ------------------------------ | -------------------------------- | ------------ | ------------------------------------------------------------ | -| sink | OPC UA SINK | String: opc-ua-sink | 必填 | | -| sink.opcua.model | OPC UA 使用的模式 | String: client-server / pub-sub | 选填 | pub-sub | -| sink.opcua.tcp.port | OPC UA 的 TCP 端口 | Integer: [0, 65536] | 选填 | 12686 | -| sink.opcua.https.port | OPC UA 的 HTTPS 端口 | Integer: [0, 65536] | 选填 | 8443 | +| **参数** | **描述** | **取值范围** | **是否必填** | **默认值** | +| ---------------------------------- | ------------------------------ | -------------------------------- | ------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| sink | OPC UA SINK | String: opc-ua-sink | 必填 | | +| sink.opcua.model | OPC UA 使用的模式 | String: client-server / pub-sub | 选填 | pub-sub | +| sink.opcua.tcp.port | OPC UA 的 TCP 端口 | Integer: [0, 65536] | 选填 | 12686 | +| sink.opcua.https.port | OPC UA 的 HTTPS 端口 | Integer: [0, 65536] | 选填 | 8443 | | sink.opcua.security.dir | OPC UA 的密钥及证书目录 | String: Path,支持绝对及相对目录 | 选填 | iotdb 相关 DataNode 的 conf 目录下的 opc_security 文件夹 /
如无 iotdb 的 conf 目录(例如 IDEA 中启动 DataNode),则为用户主目录下的 iotdb_opc_security 文件夹 / | -| sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | -| sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | -| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | root | +| sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true | +| sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root | +| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | TimechoDB@2021 //V2.0.6.x 之前默认密码为root | ### 2.3 示例 @@ -100,7 +100,7 @@ create pipe p1 create pipe p1 with sink ('sink' = 'opc-ua-sink', 'sink.user' = 'root', - 'sink.password' = 'root'); + 'sink.password' = 'TimechoDB@2021'); //V2.0.6.x 之前默认密码为root start pipe p1; ``` @@ -143,7 +143,7 @@ insert into root.test.db(time, s2) values(now(), 2) ​ 此处自动创建元数据开启。 -3. 在 UAExpert 中配置 iotdb 的连接,其中 password 填写为上述参数配置中 sink.password 中设定的密码(此处以默认密码root为例): +3. 在 UAExpert 中配置 iotdb 的连接,其中 password 填写为上述参数配置中 sink.password 中设定的密码(此处以密码root为例):
diff --git a/src/zh/UserGuide/latest/API/Programming-Python-Native-API.md b/src/zh/UserGuide/latest/API/Programming-Python-Native-API_apache.md similarity index 100% rename from src/zh/UserGuide/latest/API/Programming-Python-Native-API.md rename to src/zh/UserGuide/latest/API/Programming-Python-Native-API_apache.md diff --git a/src/zh/UserGuide/latest/API/Programming-Python-Native-API_timecho.md b/src/zh/UserGuide/latest/API/Programming-Python-Native-API_timecho.md new file mode 100644 index 000000000..a36c508a0 --- /dev/null +++ b/src/zh/UserGuide/latest/API/Programming-Python-Native-API_timecho.md @@ -0,0 +1,811 @@ + + +# Python 原生接口 + +## 1. 依赖 + +在使用 Python 原生接口包前,您需要安装 thrift (>=0.13) 依赖。 + +## 2. 如何使用 (示例) + +首先下载包:`pip3 install apache-iotdb>=2.0` + +您可以从这里得到一个使用该包进行数据读写的例子:[Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_example.py) + +关于对齐时间序列读写的例子:[Aligned Timeseries Session Example](https://github.com/apache/iotdb/blob/rc/2.0.1/iotdb-client/client-py/session_aligned_timeseries_example.py) + +(您需要在文件的头部添加`import iotdb`) + +或者: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` +## 3. 基本接口说明 + +下面将给出 Session 对应的接口的简要介绍和对应参数: + +### 3.1 初始化 + +* 初始化 Session + +```python +session = Session( + ip="127.0.0.1", + port="6667", + user="root", + password="TimechoDB@2021", //V2.0.6.x 之前密码默认值为root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* 初始化可连接多节点的 Session + +```python +session = Session.init_from_node_urls( + node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], + user="root", + password="TimechoDB@2021", //V2.0.6.x 之前密码默认值为root + fetch_size=1024, + zone_id="UTC+8", + enable_redirection=True +) +``` + +* 开启 Session,并决定是否开启 RPC 压缩 + +```python +session.open(enable_rpc_compression=False) +``` + +注意: 客户端的 RPC 压缩开启状态需和服务端一致 + +* 关闭 Session + +```python +session.close() +``` +### 3.2 通过SessionPool管理session连接 + +利用SessionPool管理session,不需要再考虑如何重用session。当session连接到达pool的最大值时,获取session的请求会被阻塞,可以通过参数设置阻塞等待时间。每次session使用完需要使用putBack方法将session归还到SessionPool中管理。 + +#### 创建SessionPool + +```python +pool_config = PoolConfig(host=ip,port=port, user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 + +# 通过配置参数创建连接池 +session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) +``` +#### 通过分布式节点创建SessionPool +```python +pool_config = PoolConfig(node_urls=node_urls=["127.0.0.1:6667", "127.0.0.1:6668", "127.0.0.1:6669"], user_name=username, + password=password, fetch_size=1024, + time_zone="UTC+8", max_retry=3) +max_pool_size = 5 +wait_timeout_in_ms = 3000 +``` + +#### 通过SessionPool获取session,使用完手动调用PutBack + +```python +session = session_pool.get_session() +session.set_storage_group(STORAGE_GROUP_NAME) +session.create_time_series( + TIMESERIES_PATH, TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.SNAPPY +) +# 使用完调用putBack归还 +session_pool.put_back(session) +# 关闭sessionPool时同时关闭管理的session +session_pool.close() +``` + +### 3.3 SSL 连接 + +#### 3.3.1 服务器端配置证书 + +`conf/iotdb-system.properties` 配置文件中查找或添加以下配置项: + +```Java +enable_thrift_ssl=true +key_store_path=/path/to/your/server_keystore.jks +key_store_pwd=your_keystore_password +``` + +#### 3.3.2 配置 python 客户端证书 + +- 设置 use_ssl 为 True 以启用 SSL。 +- 指定客户端证书路径,使用 ca_certs 参数。 + +```Java +use_ssl = True +ca_certs = "/path/to/your/server.crt" # 或 ca_certs = "/path/to/your//ca_cert.pem" +``` +**示例代码:使用 SSL 连接 IoTDB** + +```Java +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +from iotdb.SessionPool import PoolConfig, SessionPool +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +# Configure SSL enabled +use_ssl = True +# Configure certificate path +ca_certs = "/path/server.crt" + + +def get_data(): + session = Session( + ip, port_, username_, password_, use_ssl=use_ssl, ca_certs=ca_certs + ) + session.open(False) + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session.close() + return df + + +def get_data2(): + pool_config = PoolConfig( + host=ip, + port=port_, + user_name=username_, + password=password_, + fetch_size=1024, + time_zone="UTC+8", + max_retry=3, + use_ssl=use_ssl, + ca_certs=ca_certs, + ) + max_pool_size = 5 + wait_timeout_in_ms = 3000 + session_pool = SessionPool(pool_config, max_pool_size, wait_timeout_in_ms) + session = session_pool.get_session() + result = session.execute_query_statement("select * from root.eg.etth") + df = result.todf() + df.rename(columns={"Time": "date"}, inplace=True) + session_pool.put_back(session) + session_pool.close() + + +if __name__ == "__main__": + df = get_data() +``` + +## 4. 数据定义接口 DDL + +### 4.1 Database 管理 + +* 设置 database + +```python +session.set_storage_group(group_name) +``` + +* 删除单个或多个 database + +```python +session.delete_storage_group(group_name) +session.delete_storage_groups(group_name_lst) +``` +### 4.2 时间序列管理 + +* 创建单个或多个时间序列 + +```python +session.create_time_series(ts_path, data_type, encoding, compressor, + props=None, tags=None, attributes=None, alias=None) + +session.create_multi_time_series( + ts_path_lst, data_type_lst, encoding_lst, compressor_lst, + props_lst=None, tags_lst=None, attributes_lst=None, alias_lst=None +) +``` + +* 创建对齐时间序列 + +```python +session.create_aligned_time_series( + device_id, measurements_lst, data_type_lst, encoding_lst, compressor_lst +) +``` + +注意:目前**暂不支持**使用传感器别名。 + +* 删除一个或多个时间序列 + +```python +session.delete_time_series(paths_list) +``` + +* 检测时间序列是否存在 + +```python +session.check_time_series_exists(path) +``` + +## 5. 数据操作接口 DML + +### 5.1 数据写入 + +推荐使用 insert_tablet 帮助提高写入效率 + +* 插入一个 Tablet,Tablet 是一个设备若干行数据块,每一行的列都相同 + * **写入效率高** + * **支持写入空值** (0.13 版本起) + +Python API 里目前有两种 Tablet 实现 + +* 普通 Tablet + +```python +values_ = [ + [False, 10, 11, 1.1, 10011.1, "test01"], + [True, 100, 11111, 1.25, 101.0, "test02"], + [False, 100, 1, 188.1, 688.25, "test03"], + [True, 0, 0, 0, 6.25, "test04"], +] +timestamps_ = [1, 2, 3, 4] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) + +values_ = [ + [None, 10, 11, 1.1, 10011.1, "test01"], + [True, None, 11111, 1.25, 101.0, "test02"], + [False, 100, None, 188.1, 688.25, "test03"], + [True, 0, 0, 0, None, None], +] +timestamps_ = [16, 17, 18, 19] +tablet_ = Tablet( + device_id, measurements_, data_types_, values_, timestamps_ +) +session.insert_tablet(tablet_) +``` +* Numpy Tablet + +相较于普通 Tablet,Numpy Tablet 使用 [numpy.ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) 来记录数值型数据。 +内存占用和序列化耗时会降低很多,写入效率也会有很大提升。 + +**注意** +1. Tablet 中的每一列时间戳和值记录为一个 ndarray +2. Numpy Tablet 只支持大端类型数据,ndarray 构建时如果不指定数据类型会使用小端,因此推荐在构建 ndarray 时指定下面例子中类型使用大端。如果不指定,IoTDB Python客户端也会进行大小端转换,不影响使用正确性。 + +```python +import numpy as np +data_types_ = [ + TSDataType.BOOLEAN, + TSDataType.INT32, + TSDataType.INT64, + TSDataType.FLOAT, + TSDataType.DOUBLE, + TSDataType.TEXT, +] +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([1, 2, 3, 4], TSDataType.INT64.np_dtype()) +np_tablet_ = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_ +) +session.insert_tablet(np_tablet_) + +# insert one numpy tablet with None into the database. +np_values_ = [ + np.array([False, True, False, True], TSDataType.BOOLEAN.np_dtype()), + np.array([10, 100, 100, 0], TSDataType.INT32.np_dtype()), + np.array([11, 11111, 1, 0], TSDataType.INT64.np_dtype()), + np.array([1.1, 1.25, 188.1, 0], TSDataType.FLOAT.np_dtype()), + np.array([10011.1, 101.0, 688.25, 6.25], TSDataType.DOUBLE.np_dtype()), + np.array(["test01", "test02", "test03", "test04"], TSDataType.TEXT.np_dtype()), +] +np_timestamps_ = np.array([98, 99, 100, 101], TSDataType.INT64.np_dtype()) +np_bitmaps_ = [] +for i in range(len(measurements_)): + np_bitmaps_.append(BitMap(len(np_timestamps_))) +np_bitmaps_[0].mark(0) +np_bitmaps_[1].mark(1) +np_bitmaps_[2].mark(2) +np_bitmaps_[4].mark(3) +np_bitmaps_[5].mark(3) +np_tablet_with_none = NumpyTablet( + device_id, measurements_, data_types_, np_values_, np_timestamps_, np_bitmaps_ +) +session.insert_tablet(np_tablet_with_none) +``` + +* 插入多个 Tablet + +```python +session.insert_tablets(tablet_lst) +``` + +* 插入一个 Record,一个 Record 是一个设备一个时间戳下多个测点的数据。 + +```python +session.insert_record(device_id, timestamp, measurements_, data_types_, values_) +``` + +* 插入多个 Record + +```python +session.insert_records( + device_ids_, time_list_, measurements_list_, data_type_list_, values_list_ + ) +``` + +* 插入同属于一个 device 的多个 Record + +```python +session.insert_records_of_one_device(device_id, time_list, measurements_list, data_types_list, values_list) +``` + +### 5.2 带有类型推断的写入 + +当数据均是 String 类型时,我们可以使用如下接口,根据 value 的值进行类型推断。例如:value 为 "true" ,就可以自动推断为布尔类型。value 为 "3.2" ,就可以自动推断为数值类型。服务器需要做类型推断,可能会有额外耗时,速度较无需类型推断的写入慢 + +```python +session.insert_str_record(device_id, timestamp, measurements, string_values) +``` + +### 5.3 对齐时间序列的写入 + +对齐时间序列的写入使用 insert_aligned_xxx 接口,其余与上述接口类似: + +* insert_aligned_record +* insert_aligned_records +* insert_aligned_records_of_one_device +* insert_aligned_tablet +* insert_aligned_tablets + + +## 6. IoTDB-SQL 接口 + +* 执行查询语句 + +```python +session.execute_query_statement(sql) +``` + +* 执行非查询语句 + +```python +session.execute_non_query_statement(sql) +``` + +* 执行语句 + +```python +session.execute_statement(sql) +``` + + +## 7. 元数据模版接口 +### 7.1 构建元数据模版 +1. 首先构建 Template 类 +2. 添加子节点 MeasurementNode +3. 调用创建元数据模版接口 + +```python +template = Template(name=template_name, share_time=True) + +m_node_x = MeasurementNode("x", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_y = MeasurementNode("y", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) +m_node_z = MeasurementNode("z", TSDataType.FLOAT, TSEncoding.RLE, Compressor.SNAPPY) + +template.add_template(m_node_x) +template.add_template(m_node_y) +template.add_template(m_node_z) + +session.create_schema_template(template) +``` +### 7.2 改模版节点信息 +修改模版节点,其中修改的模版必须已经被创建。以下函数能够在已经存在的模版中增加或者删除物理量 +* 在模版中增加实体 +```python +session.add_measurements_in_template(template_name, measurements_path, data_types, encodings, compressors, is_aligned) +``` + +* 在模版中删除物理量 +```python +session.delete_node_in_template(template_name, path) +``` + +### 7.3 挂载元数据模板 +```python +session.set_schema_template(template_name, prefix_path) +``` + +### 7.4 卸载元数据模版 +```python +session.unset_schema_template(template_name, prefix_path) +``` + +### 7.5 查看元数据模版 +* 查看所有的元数据模版 +```python +session.show_all_templates() +``` +* 查看元数据模版中的物理量个数 +```python +session.count_measurements_in_template(template_name) +``` + +* 判断某个节点是否为物理量,该节点必须已经在元数据模版中 +```python +session.count_measurements_in_template(template_name, path) +``` + +* 判断某个路径是否在元数据模版中,这个路径有可能不在元数据模版中 +```python +session.is_path_exist_in_template(template_name, path) +``` + +* 查看某个元数据模板下的物理量 +```python +session.show_measurements_in_template(template_name) +``` + +* 查看挂载了某个元数据模板的路径前缀 +```python +session.show_paths_template_set_on(template_name) +``` + +* 查看使用了某个元数据模板(即序列已创建)的路径前缀 +```python +session.show_paths_template_using_on(template_name) +``` + +### 7.6 删除元数据模版 +删除已经存在的元数据模版,不支持删除已经挂载的模版 +```python +session.drop_schema_template("template_python") +``` + + +## 8. 对 Pandas 的支持 + +我们支持将查询结果轻松地转换为 [Pandas Dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)。 + +SessionDataSet 有一个方法`.todf()`,它的作用是消费 SessionDataSet 中的数据,并将数据转换为 pandas dataframe。 + +例子: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +result = session.execute_query_statement("SELECT ** FROM root") + +# Transform to Pandas Dataset +df = result.todf() + +session.close() + +# Now you can work with the dataframe +df = ... +``` + +## 9. IoTDB Testcontainer + +Python 客户端对测试的支持是基于`testcontainers`库 (https://testcontainers-python.readthedocs.io/en/latest/index.html) 的,如果您想使用该特性,就需要将其安装到您的项目中。 + +要在 Docker 容器中启动(和停止)一个 IoTDB 数据库,只需这样做: + +```python +class MyTestCase(unittest.TestCase): + + def test_something(self): + with IoTDBContainer() as c: + session = Session("localhost", c.get_exposed_port(6667), "root", "TimechoDB@2021") //V2.0.6.x 之前密码默认值为root + session.open(False) + result = session.execute_query_statement("SHOW TIMESERIES") + print(result) + session.close() +``` + +默认情况下,它会拉取最新的 IoTDB 镜像 `apache/iotdb:latest`进行测试,如果您想指定待测 IoTDB 的版本,您只需要将版本信息像这样声明:`IoTDBContainer("apache/iotdb:0.12.0")`,此时,您就会得到一个`0.12.0`版本的 IoTDB 实例。 + +## 10. IoTDB DBAPI + +IoTDB DBAPI 遵循 Python DB API 2.0 规范 (https://peps.python.org/pep-0249/),实现了通过Python语言访问数据库的通用接口。 + +### 10.1 例子 ++ 初始化 + +初始化的参数与Session部分保持一致(sqlalchemy_mode参数除外,该参数仅在SQLAlchemy方言中使用) +```python +from iotdb.dbapi import connect + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +conn = connect(ip, port_, username_, password_,fetch_size=1024,zone_id="UTC+8",sqlalchemy_mode=False) +cursor = conn.cursor() +``` ++ 执行简单的SQL语句 +```python +cursor.execute("SELECT ** FROM root") +for row in cursor.fetchall(): + print(row) +``` + ++ 执行带有参数的SQL语句 + +IoTDB DBAPI 支持pyformat风格的参数 +```python +cursor.execute("SELECT ** FROM root WHERE time < %(time)s",{"time":"2017-11-01T00:08:00.000"}) +for row in cursor.fetchall(): + print(row) +``` + ++ 批量执行带有参数的SQL语句 +```python +seq_of_parameters = [ + {"timestamp": 1, "temperature": 1}, + {"timestamp": 2, "temperature": 2}, + {"timestamp": 3, "temperature": 3}, + {"timestamp": 4, "temperature": 4}, + {"timestamp": 5, "temperature": 5}, +] +sql = "insert into root.cursor(timestamp,temperature) values(%(timestamp)s,%(temperature)s)" +cursor.executemany(sql,seq_of_parameters) +``` + ++ 关闭连接 +```python +cursor.close() +conn.close() +``` + +## 11. IoTDB SQLAlchemy Dialect(实验性) +IoTDB的SQLAlchemy方言主要是为了适配Apache superset而编写的,该部分仍在完善中,请勿在生产环境中使用! +### 11.1 元数据模型映射 +SQLAlchemy 所使用的数据模型为关系数据模型,这种数据模型通过表格来描述不同实体之间的关系。 +而 IoTDB 的数据模型为层次数据模型,通过树状结构来对数据进行组织。 +为了使 IoTDB 能够适配 SQLAlchemy 的方言,需要对 IoTDB 中原有的数据模型进行重新组织, +把 IoTDB 的数据模型转换成 SQLAlchemy 的数据模型。 + +IoTDB 中的元数据有: + +1. Database:数据库 +2. Path:存储路径 +3. Entity:实体 +4. Measurement:物理量 + +SQLAlchemy 中的元数据有: +1. Schema:数据模式 +2. Table:数据表 +3. Column:数据列 + +它们之间的映射关系为: + +| SQLAlchemy中的元数据 | IoTDB中对应的元数据 | +| -------------------- | ---------------------------------------------- | +| Schema | Database | +| Table | Path ( from database to entity ) + Entity | +| Column | Measurement | + +下图更加清晰的展示了二者的映射关系: + +![sqlalchemy-to-iotdb](/img/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true) + +### 11.2 数据类型映射 +| IoTDB 中的数据类型 | SQLAlchemy 中的数据类型 | +|--------------|-------------------| +| BOOLEAN | Boolean | +| INT32 | Integer | +| INT64 | BigInteger | +| FLOAT | Float | +| DOUBLE | Float | +| TEXT | Text | +| LONG | BigInteger | +### 11.3 Example + ++ 执行语句 + +```python +from sqlalchemy import create_engine + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //V2.0.6.x 之前密码默认值为root +connect = engine.connect() +result = connect.execute("SELECT ** FROM root") +for row in result.fetchall(): + print(row) +``` + ++ ORM (目前只支持简单的查询) + +```python +from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +metadata = MetaData( + schema='root.factory' +) +Base = declarative_base(metadata=metadata) + + +class Device(Base): + __tablename__ = "room2.device1" + Time = Column(BigInteger, primary_key=True) + temperature = Column(Float) + status = Column(Float) + + +engine = create_engine("iotdb://root:TimechoDB@2021@127.0.0.1:6667") //V2.0.6.x 之前密码默认值为root + +DbSession = sessionmaker(bind=engine) +session = DbSession() + +res = session.query(Device.status).filter(Device.temperature > 1) + +for row in res: + print(row) +``` + +## 12. 给开发人员 + +### 12.1 介绍 + +这是一个使用 thrift rpc 接口连接到 IoTDB 的示例。在 Windows 和 Linux 上操作几乎是一样的,但要注意路径分隔符等不同之处。 + +### 12.2 依赖 + +首选 Python3.7 或更高版本。 + +必须安装 thrift(0.11.0 或更高版本)才能将 thrift 文件编译为 Python 代码。下面是官方的安装教程,最终,您应该得到一个 thrift 可执行文件。 + +``` +http://thrift.apache.org/docs/install/ +``` + +在开始之前,您还需要在 Python 环境中安装`requirements_dev.txt`中的其他依赖: +```shell +pip install -r requirements_dev.txt +``` + +### 12.3 编译 thrift 库并调试 + +在 IoTDB 源代码文件夹的根目录下,运行`mvn clean generate-sources -pl iotdb-client/client-py -am`, + +这个指令将自动删除`iotdb/thrift`中的文件,并使用新生成的 thrift 文件重新填充该文件夹。 + +这个文件夹在 git 中会被忽略,并且**永远不应该被推到 git 中!** + +**注意**不要将`iotdb/thrift`上传到 git 仓库中 ! + +### 12.4 Session 客户端 & 使用示例 + +我们将 thrift 接口打包到`client-py/src/iotdb/session.py `中(与 Java 版本类似),还提供了一个示例文件`client-py/src/SessionExample.py`来说明如何使用 Session 模块。请仔细阅读。 + +另一个简单的例子: + +```python +from iotdb.Session import Session + +ip = "127.0.0.1" +port_ = "6667" +username_ = "root" +password_ = "TimechoDB@2021" //V2.0.6.x 之前密码默认值为root +session = Session(ip, port_, username_, password_) +session.open(False) +zone = session.get_time_zone() +session.close() +``` + +### 12.5 测试 + +请在`tests`文件夹中添加自定义测试。 + +要运行所有的测试,只需在根目录中运行`pytest . `即可。 + +**注意**一些测试需要在您的系统上使用 docker,因为测试的 IoTDB 实例是使用 [testcontainers](https://testcontainers-python.readthedocs.io/en/latest/index.html) 在 docker 容器中启动的。 + +### 12.6 其他工具 + +[black](https://pypi.org/project/black/) 和 [flake8](https://pypi.org/project/flake8/) 分别用于自动格式化和 linting。 +它们可以通过 `black .` 或 `flake8 .` 分别运行。 + +## 13. 发版 + +要进行发版, + +只需确保您生成了正确的 thrift 代码, + +运行了 linting 并进行了自动格式化, + +然后,确保所有测试都正常通过(通过`pytest . `), + +最后,您就可以将包发布到 pypi 了。 + +### 13.1 准备您的环境 + +首先,通过`pip install -r requirements_dev.txt`安装所有必要的开发依赖。 + +### 13.2 发版 + +有一个脚本`release.sh`可以用来执行发版的所有步骤。 + +这些步骤包括: + +* 删除所有临时目录(如果存在) + +* (重新)通过 mvn 生成所有必须的源代码 + +* 运行 linting (flke8) + +* 通过 pytest 运行测试 + +* Build + +* 发布到 pypi diff --git a/src/zh/UserGuide/latest/API/RestServiceV1.md b/src/zh/UserGuide/latest/API/RestServiceV1_apache.md similarity index 100% rename from src/zh/UserGuide/latest/API/RestServiceV1.md rename to src/zh/UserGuide/latest/API/RestServiceV1_apache.md diff --git a/src/zh/UserGuide/latest/API/RestServiceV1_timecho.md b/src/zh/UserGuide/latest/API/RestServiceV1_timecho.md new file mode 100644 index 000000000..78859f1ba --- /dev/null +++ b/src/zh/UserGuide/latest/API/RestServiceV1_timecho.md @@ -0,0 +1,941 @@ + + +# REST API V1(不推荐) +IoTDB 的 RESTful 服务可用于查询、写入和管理操作,它使用 OpenAPI 标准来定义接口并生成框架。 + +## 1. 开启RESTful 服务 +RESTful 服务默认情况是关闭的 + + 找到IoTDB安装目录下面的`conf/iotdb-system.properties`文件,将 `enable_rest_service` 设置为 `true` 以启用该模块。 + + ```properties + enable_rest_service=true + ``` + +## 2. 鉴权 +除了检活接口 `/ping`,RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。 + +示例中使用的用户名为:`root`,密码为:`TimechoDB@2021`,对应的 Basic 鉴权 Header 格式为 + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- 若用户名密码认证失败,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- 若未设置 `Authorization`,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. 接口 + +### 3.1 ping + +ping 接口可以用于线上服务检活。 + +请求方式:`GET` + +请求路径:`http://ip:port/ping +` +请求示例: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +返回的 HTTP 状态码: + +- `200`:当前服务工作正常,可以接收外部请求。 +- `503`:当前服务出现异常,不能接收外部请求。 + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: + +- HTTP 状态码为 `200` 时: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- HTTP 状态码为 `503` 时: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` 接口访问不需要鉴权。 + +### 3.2 query + +query 接口可以用于处理数据查询和元数据查询。 + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/query` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-----------| ------------ | ------------ |------------ | +| sql | string | 是 | | +| rowLimit | integer | 否 | 一次查询能返回的结果集的最大行数。
如果不设置该参数,将使用配置文件的 `rest_query_default_row_size_limit` 作为默认值。
当返回结果集的行数超出限制时,将返回状态码 `411`。 | + +响应参数: + +| 参数名称 |参数类型 |参数描述| +|--------------| ------------ | ------------| +| expressions | array | 用于数据查询时结果集列名的数组,用于元数据查询时为`null`| +| columnNames | array | 用于元数据查询结果集列名数组,用于数据查询时为`null` | +| timestamps | array | 时间戳列,用于元数据查询时为`null` | +| values |array|二维数组,第一维与结果集列名数组的长度相同,第二维数组代表结果集的一列| + +请求示例如下所示: + +提示:为了避免OOM问题,不推荐使用select * from root.xx.** 这种查找方式。 + +1. 请求示例 表达式查询: + ```shell + curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v1/query +``` + + - 响应示例: + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +2. 请求示例 show child paths: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +3. 请求示例 show child nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +4. 请求示例 show all ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +5. 请求示例 show ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +6. 请求示例 show functions: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +7. 请求示例 show timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +8. 请求示例 show latest timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +9. 请求示例 count timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +10. 请求示例 count nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +11. 请求示例 show devices: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +12. 请求示例 show devices with database: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +13. 请求示例 list user: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +14. 请求示例 原始聚合查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +15. 请求示例 group by level: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +16. 请求示例 group by: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "columnNames": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +17. 请求示例 last: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "columnNames": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +18. 请求示例 disable align: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +19. 请求示例 align by device: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +20. 请求示例 select into: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v1/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/nonQuery` + +参数说明: + +|参数名称 |参数类型 |是否必填|参数描述| +| ------------ | ------------ | ------------ |------------ | +| sql | string | 是 | | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v1/nonQuery +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v1/insertTablet` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|--------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements | array | 是 | 测点名称 | +| dataTypes | array | 是 | 数据类型 | +| values | array | 是 | 值列,每一列中的值可以为 `null` | +| isAligned | boolean | 是 | 是否是对齐时间序列 | +| deviceId | string | 是 | 设备名称 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"dataTypes":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"isAligned":false,"deviceId":"root.sg27"}' http://127.0.0.1:18080/rest/v1/insertTablet +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. 配置 + +配置位于 `iotdb-system.properties` 中。 + + + +* 将 `enable_rest_service` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_rest_service=true +``` + +* 仅在 `enable_rest_service=true` 时生效。将 `rest_service_port `设置为数字(1025~65535),以自定义REST服务套接字端口。默认情况下,值为 `18080`。 + +```properties +rest_service_port=18080 +``` + +* 将 'enable_swagger' 设置 'true' 启用swagger来展示rest接口信息, 而设置为 'false' 关闭该功能. 默认情况下,该值为 `false`。 + +```properties +enable_swagger=false +``` + +* 一次查询能返回的结果集最大行数。当返回结果集的行数超出参数限制时,您只会得到在行数范围内的结果集,且将得到状态码`411`。 + +```properties +rest_query_default_row_size_limit=10000 +``` + +* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时) + +```properties +cache_expire=28800 +``` + +* 缓存中存储的最大用户数量(默认是100) + +```properties +cache_max_num=100 +``` + +* 缓存初始容量(默认是10) + +```properties +cache_init_num=10 +``` + +* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_https=false +``` + +* keyStore 所在路径(非必填) + +```properties +key_store_path= +``` + + +* keyStore 密码(非必填) + +```properties +key_store_pwd= +``` + + +* trustStore 所在路径(非必填) + +```properties +trust_store_path= +``` + +* trustStore 密码(非必填) + +```properties +trust_store_pwd= +``` + + +* SSL 超时时间,单位为秒 + +```properties +idle_timeout=5000 +``` diff --git a/src/zh/UserGuide/latest/API/RestServiceV2.md b/src/zh/UserGuide/latest/API/RestServiceV2_apache.md similarity index 100% rename from src/zh/UserGuide/latest/API/RestServiceV2.md rename to src/zh/UserGuide/latest/API/RestServiceV2_apache.md diff --git a/src/zh/UserGuide/latest/API/RestServiceV2_timecho.md b/src/zh/UserGuide/latest/API/RestServiceV2_timecho.md new file mode 100644 index 000000000..8b753fa68 --- /dev/null +++ b/src/zh/UserGuide/latest/API/RestServiceV2_timecho.md @@ -0,0 +1,980 @@ + + +# REST API V2 +IoTDB 的 RESTful 服务可用于查询、写入和管理操作,它使用 OpenAPI 标准来定义接口并生成框架。 + +## 1. 开启RESTful 服务 +RESTful 服务默认情况是关闭的 + + 找到IoTDB安装目录下面的`conf/iotdb-system.properties`文件,将 `enable_rest_service` 设置为 `true` 以启用该模块。 + + ```properties + enable_rest_service=true + ``` + +## 2. 鉴权 +除了检活接口 `/ping`,RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。 + +示例中使用的用户名为:`root`,密码为:`TimechoDB@2021`,对应的 Basic 鉴权 Header 格式为 + +``` +Authorization: Basic cm9vdDpyb290 +``` + +- 若用户名密码认证失败,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 600, + "message": "WRONG_LOGIN_PASSWORD_ERROR" + } + ``` + +- 若未设置 `Authorization`,则返回如下信息: + + HTTP 状态码:`401` + + 返回结构体如下 + ```json + { + "code": 603, + "message": "UNINITIALIZED_AUTH_ERROR" + } + ``` + +## 3. 接口 + +### 3.1 ping + +ping 接口可以用于线上服务检活。 + +请求方式:`GET` + +请求路径:http://ip:port/ping + +请求示例: + +```shell +$ curl http://127.0.0.1:18080/ping +``` + +返回的 HTTP 状态码: + +- `200`:当前服务工作正常,可以接收外部请求。 +- `503`:当前服务出现异常,不能接收外部请求。 + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: + +- HTTP 状态码为 `200` 时: + + ```json + { + "code": 200, + "message": "SUCCESS_STATUS" + } + ``` + +- HTTP 状态码为 `503` 时: + + ```json + { + "code": 500, + "message": "thrift service is unavailable" + } + ``` + +> `/ping` 接口访问不需要鉴权。 + +### 3.2 query + +query 接口可以用于处理数据查询和元数据查询。 + +请求方式:`POST` + +请求头:`application/json` + +请求路径: `http://ip:port/rest/v2/query` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-----------| ------------ | ------------ |------------ | +| sql | string | 是 | | +| row_limit | integer | 否 | 一次查询能返回的结果集的最大行数。
如果不设置该参数,将使用配置文件的 `rest_query_default_row_size_limit` 作为默认值。
当返回结果集的行数超出限制时,将返回状态码 `411`。 | + +响应参数: + +| 参数名称 |参数类型 |参数描述| +|--------------| ------------ | ------------| +| expressions | array | 用于数据查询时结果集列名的数组,用于元数据查询时为`null`| +| column_names | array | 用于元数据查询结果集列名数组,用于数据查询时为`null` | +| timestamps | array | 时间戳列,用于元数据查询时为`null` | +| values |array|二维数组,第一维与结果集列名数组的长度相同,第二维数组代表结果集的一列| + +请求示例如下所示: + +提示:为了避免OOM问题,不推荐使用select * from root.xx.** 这种查找方式。 + +1. 请求示例 表达式查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4, s3 + 1 from root.sg27 limit 2"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg27.s3 + 1" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232153960 + ], + "values": [ + [ + 11, + null + ], + [ + false, + true + ], + [ + 12.0, + null + ] + ] +} +``` + +2.请求示例 show child paths: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child paths root"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "child paths" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ] + ] +} +``` + +3. 请求示例 show child nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show child nodes root"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "child nodes" + ], + "timestamps": null, + "values": [ + [ + "sg27", + "sg28" + ] + ] +} +``` + +4. 请求示例 show all ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show all ttl"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + null, + null + ] + ] +} +``` + +5. 请求示例 show ttl: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show ttl on root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "database", + "ttl" + ], + "timestamps": null, + "values": [ + [ + "root.sg27" + ], + [ + null + ] + ] +} +``` + +6. 请求示例 show functions: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show functions"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "function name", + "function type", + "class name (UDF)" + ], + "timestamps": null, + "values": [ + [ + "ABS", + "ACOS", + "ASIN", + ... + ], + [ + "built-in UDTF", + "built-in UDTF", + "built-in UDTF", + ... + ], + [ + "org.apache.iotdb.db.query.udf.builtin.UDTFAbs", + "org.apache.iotdb.db.query.udf.builtin.UDTFAcos", + "org.apache.iotdb.db.query.udf.builtin.UDTFAsin", + ... + ] + ] +} +``` + +7. 请求示例 show timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg27.s3", + "root.sg27.s4", + "root.sg28.s3", + "root.sg28.s4" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg27", + "root.sg27", + "root.sg28", + "root.sg28" + ], + [ + "INT32", + "BOOLEAN", + "INT32", + "BOOLEAN" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +8. 请求示例 show latest timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show latest timeseries"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "alias", + "database", + "dataType", + "encoding", + "compression", + "tags", + "attributes" + ], + "timestamps": null, + "values": [ + [ + "root.sg28.s4", + "root.sg27.s4", + "root.sg28.s3", + "root.sg27.s3" + ], + [ + null, + null, + null, + null + ], + [ + "root.sg28", + "root.sg27", + "root.sg28", + "root.sg27" + ], + [ + "BOOLEAN", + "BOOLEAN", + "INT32", + "INT32" + ], + [ + "RLE", + "RLE", + "RLE", + "RLE" + ], + [ + "SNAPPY", + "SNAPPY", + "SNAPPY", + "SNAPPY" + ], + [ + null, + null, + null, + null + ], + [ + null, + null, + null, + null + ] + ] +} +``` + +9. 请求示例 count timeseries: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count timeseries root.**"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +10. 请求示例 count nodes: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"count nodes root.** level=2"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count" + ], + "timestamps": null, + "values": [ + [ + 4 + ] + ] +} +``` + +11. 请求示例 show devices: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +12. 请求示例 show devices with database: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"show devices with database"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "devices", + "database", + "isAligned" + ], + "timestamps": null, + "values": [ + [ + "root.sg27", + "root.sg28" + ], + [ + "root.sg27", + "root.sg28" + ], + [ + "false", + "false" + ] + ] +} +``` + +13. 请求示例 list user: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"list user"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "user" + ], + "timestamps": null, + "values": [ + [ + "root" + ] + ] +} +``` + +14. 请求示例 原始聚合查询: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 0 + ], + "values": [ + [ + 1 + ], + [ + 2 + ] + ] +} +``` + +15. 请求示例 group by level: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.** group by level = 1"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "count(root.sg27.*)", + "count(root.sg28.*)" + ], + "timestamps": null, + "values": [ + [ + 3 + ], + [ + 3 + ] + ] +} +``` + +16. 请求示例 group by: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(*) from root.sg27 group by([1635232143960,1635232153960),1s)"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": [ + "count(root.sg27.s3)", + "count(root.sg27.s4)" + ], + "column_names": null, + "timestamps": [ + 1635232143960, + 1635232144960, + 1635232145960, + 1635232146960, + 1635232147960, + 1635232148960, + 1635232149960, + 1635232150960, + 1635232151960, + 1635232152960 + ], + "values": [ + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] +} +``` + +17. 请求示例 last: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select last s3 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "expressions": null, + "column_names": [ + "timeseries", + "value", + "dataType" + ], + "timestamps": [ + 1635232143960 + ], + "values": [ + [ + "root.sg27.s3" + ], + [ + "11" + ], + [ + "INT32" + ] + ] +} +``` + +18. 请求示例 disable align: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select * from root.sg27 disable align"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "disable align clauses are not supported." +} +``` + +19. 请求示例 align by device: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select count(s3) from root.sg27 align by device"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "align by device clauses are not supported." +} +``` + +20. 请求示例 select into: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"select s3, s4 into root.sg29.s1, root.sg29.s2 from root.sg27"}' http://127.0.0.1:18080/rest/v2/query +``` + +- 响应示例: + +```json +{ + "code": 407, + "message": "select into clauses are not supported." +} +``` + +### 3.3 nonQuery + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/nonQuery` + +参数说明: + +|参数名称 |参数类型 |是否必填|参数描述| +| ------------ | ------------ | ------------ |------------ | +| sql | string | 是 | | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"sql":"CREATE DATABASE root.ln"}' http://127.0.0.1:18080/rest/v2/nonQuery +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + + +### 3.4 insertTablet + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/insertTablet` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|--------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements | array | 是 | 测点名称 | +| data_types | array | 是 | 数据类型 | +| values | array | 是 | 值列,每一列中的值可以为 `null` | +| is_aligned | boolean | 是 | 是否是对齐时间序列 | +| device | string | 是 | 设备名称 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232143960,1635232153960],"measurements":["s3","s4"],"data_types":["INT32","BOOLEAN"],"values":[[11,null],[false,true]],"is_aligned":false,"device":"root.sg27"}' http://127.0.0.1:18080/rest/v2/insertTablet +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + +### 3.5 insertRecords + +请求方式:`POST` + +请求头:`application/json` + +请求路径:`http://ip:port/rest/v2/insertRecords` + +参数说明: + +| 参数名称 |参数类型 |是否必填|参数描述| +|-------------------| ------------ | ------------ |------------ | +| timestamps | array | 是 | 时间列 | +| measurements_list | array | 是 | 测点名称 | +| data_types_list | array | 是 | 数据类型 | +| values_list | array | 是 | 值列,每一列中的值可以为 `null` | +| devices | string | 是 | 设备名称 | +| is_aligned | string | 是 | 是否是对齐时间序列 | + +请求示例: +```shell +curl -H "Content-Type:application/json" -H "Authorization:Basic cm9vdDpyb290" -X POST --data '{"timestamps":[1635232113960,1635232151960,1635232143960,1635232143960],"measurements_list":[["s33","s44"],["s55","s66"],["s77","s88"],["s771","s881"]],"data_types_list":[["INT32","INT64"],["FLOAT","DOUBLE"],["FLOAT","DOUBLE"],["BOOLEAN","TEXT"]],"values_list":[[1,11],[2.1,2],[4,6],[false,"cccccc"]],"is_aligned":false,"devices":["root.s1","root.s1","root.s1","root.s3"]}' http://127.0.0.1:18080/rest/v2/insertRecords +``` + +响应参数: + +|参数名称 |参数类型 |参数描述| +| ------------ | ------------ | ------------| +| code | integer | 状态码 | +| message | string | 信息提示 | + +响应示例: +```json +{ + "code": 200, + "message": "SUCCESS_STATUS" +} +``` + + +## 4. 配置 + +配置位于 `iotdb-system.properties` 中。 + + + +* 将 `enable_rest_service` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_rest_service=true +``` + +* 仅在 `enable_rest_service=true` 时生效。将 `rest_service_port `设置为数字(1025~65535),以自定义REST服务套接字端口。默认情况下,值为 `18080`。 + +```properties +rest_service_port=18080 +``` + +* 将 'enable_swagger' 设置 'true' 启用swagger来展示rest接口信息, 而设置为 'false' 关闭该功能. 默认情况下,该值为 `false`。 + +```properties +enable_swagger=false +``` + +* 一次查询能返回的结果集最大行数。当返回结果集的行数超出参数限制时,您只会得到在行数范围内的结果集,且将得到状态码`411`。 + +```properties +rest_query_default_row_size_limit=10000 +``` + +* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时) + +```properties +cache_expire=28800 +``` + +* 缓存中存储的最大用户数量(默认是100) + +```properties +cache_max_num=100 +``` + +* 缓存初始容量(默认是10) + +```properties +cache_init_num=10 +``` + +* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false` 设置为禁用该模块。默认情况下,该值为 `false`。 + +```properties +enable_https=false +``` + +* keyStore 所在路径(非必填) + +```properties +key_store_path= +``` + + +* keyStore 密码(非必填) + +```properties +key_store_pwd= +``` + + +* trustStore 所在路径(非必填) + +```properties +trust_store_path= +``` + +* trustStore 密码(非必填) + +```properties +trust_store_pwd= +``` + + +* SSL 超时时间,单位为秒 + +```properties +idle_timeout=5000 +``` diff --git a/src/zh/UserGuide/latest/Basic-Concept/Query-Data.md b/src/zh/UserGuide/latest/Basic-Concept/Query-Data_apache.md similarity index 99% rename from src/zh/UserGuide/latest/Basic-Concept/Query-Data.md rename to src/zh/UserGuide/latest/Basic-Concept/Query-Data_apache.md index ba97766b3..7906532dc 100644 --- a/src/zh/UserGuide/latest/Basic-Concept/Query-Data.md +++ b/src/zh/UserGuide/latest/Basic-Concept/Query-Data_apache.md @@ -279,7 +279,7 @@ It costs 0.016s - 在 SQL 命令行终端中执行查询语句:启动 SQL 命令行终端,直接输入查询语句执行即可,详见 [SQL 命令行终端](../Tools-System/CLI.md)。 -- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC.md) 。 +- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC_apache) 。 - 在 JAVA / C++ / Python / Go 等编程语言 API 中执行查询语句,详见应用编程接口一章相应文档。接口原型如下: @@ -287,7 +287,7 @@ It costs 0.016s SessionDataSet executeQueryStatement(String sql); ``` -- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1.md) 或者 [HTTP API V2](../API/RestServiceV2.md)。 +- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1_apache) 或者 [HTTP API V2](../API/RestServiceV2_apache)。 #### 常用查询的高效执行接口 @@ -3041,7 +3041,7 @@ It costs 0.375s * 所有 `SELECT` 子句中源序列的 `WRITE_SCHEMA` 权限。 * 所有 `INTO` 子句中目标序列 `WRITE_DATA` 权限。 -更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management.md)。 +更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management_apache)。 ### 10.4 相关配置参数 diff --git a/src/zh/UserGuide/latest/Basic-Concept/Query-Data_timecho.md b/src/zh/UserGuide/latest/Basic-Concept/Query-Data_timecho.md new file mode 100644 index 000000000..e1417e0a9 --- /dev/null +++ b/src/zh/UserGuide/latest/Basic-Concept/Query-Data_timecho.md @@ -0,0 +1,3055 @@ + + +# 数据查询 +## 1. 概述 + +在 IoTDB 中,使用 `SELECT` 语句从一条或多条时间序列中查询数据,IoTDB 不区分历史数据和实时数据,用户可以用统一的sql语法进行查询,通过 `WHERE` 子句中的时间过滤谓词决定查询的时间范围。 + +### 1.1 语法定义 + +```sql +SELECT [LAST] selectExpr [, selectExpr] ... + [INTO intoItem [, intoItem] ...] + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY { + ([startTime, endTime), interval [, slidingStep]) | + LEVEL = levelNum [, levelNum] ... | + TAGS(tagKey [, tagKey] ... | + VARIATION(expression[,delta][,ignoreNull=true/false]) | + CONDITION(expression,[keep>/>=/=/ 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; +``` + +其含义为: + +被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为供电状态(status)和温度传感器(temperature);该语句要求选择出 “2017-11-01T00:05:00.000” 至 “2017-11-01T00:12:00.000” 之间的所选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 6 +It costs 0.018s +``` + +#### 示例3:按照多个时间区间选择同一设备的多列数据 + +IoTDB 支持在一次查询中指定多个时间区间条件,用户可以根据需求随意组合时间区间条件。例如, + +SQL 语句为: + +```sql +select status, temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +其含义为: + +被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为“供电状态(status)”和“温度传感器(temperature)”;该语句指定了两个不同的时间区间,分别为“2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000”和“2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任一时间区间的被选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| +|2017-11-01T00:10:00.000+08:00| true| 25.52| +|2017-11-01T00:11:00.000+08:00| false| 22.91| +|2017-11-01T16:35:00.000+08:00| true| 23.44| +|2017-11-01T16:36:00.000+08:00| false| 21.98| +|2017-11-01T16:37:00.000+08:00| false| 21.93| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 9 +It costs 0.018s +``` + +#### 示例4:按照多个时间区间选择不同设备的多列数据 + +该系统支持在一次查询中选择任意列的数据,也就是说,被选择的列可以来源于不同的设备。例如,SQL 语句为: + +```sql +select wf01.wt01.status, wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000); +``` + +其含义为: + +被选择的时间序列为 “ln 集团 wf01 子站 wt01 设备的供电状态” 以及 “ln 集团 wf02 子站 wt02 设备的硬件版本”;该语句指定了两个时间区间,分别为 “2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000” 和 “2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任意时间区间的被选时间序列的值。 + +该 SQL 语句的执行结果如下: + +``` ++-----------------------------+------------------------+--------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf02.wt02.hardware| ++-----------------------------+------------------------+--------------------------+ +|2017-11-01T00:06:00.000+08:00| false| v1| +|2017-11-01T00:07:00.000+08:00| false| v1| +|2017-11-01T00:08:00.000+08:00| false| v1| +|2017-11-01T00:09:00.000+08:00| false| v1| +|2017-11-01T00:10:00.000+08:00| true| v2| +|2017-11-01T00:11:00.000+08:00| false| v1| +|2017-11-01T16:35:00.000+08:00| true| v2| +|2017-11-01T16:36:00.000+08:00| false| v1| +|2017-11-01T16:37:00.000+08:00| false| v1| ++-----------------------------+------------------------+--------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### 示例5:根据时间降序返回结果集 + +IoTDB 支持 `order by time` 语句,用于对结果按照时间进行降序展示。例如,SQL 语句为: + +```sql +select * from root.ln.** where time > 1 order by time desc limit 10; +``` + +语句执行的结果为: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-07T23:59:00.000+08:00| v1| false| 21.07| false| +|2017-11-07T23:58:00.000+08:00| v1| false| 22.93| false| +|2017-11-07T23:57:00.000+08:00| v2| true| 24.39| true| +|2017-11-07T23:56:00.000+08:00| v2| true| 24.44| true| +|2017-11-07T23:55:00.000+08:00| v2| true| 25.9| true| +|2017-11-07T23:54:00.000+08:00| v1| false| 22.52| false| +|2017-11-07T23:53:00.000+08:00| v2| true| 24.58| true| +|2017-11-07T23:52:00.000+08:00| v1| false| 20.18| false| +|2017-11-07T23:51:00.000+08:00| v1| false| 22.24| false| +|2017-11-07T23:50:00.000+08:00| v2| true| 23.7| true| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.016s +``` + +### 1.4 查询执行接口 + +在 IoTDB 中,提供两种方式执行数据查询操作: +- 使用 IoTDB-SQL 执行查询。 +- 常用查询的高效执行接口,包括时间序列原始数据范围查询、最新点查询、简单聚合查询。 + +#### 使用 IoTDB-SQL 执行查询 + +数据查询语句支持在 SQL 命令行终端、JDBC、JAVA / C++ / Python / Go 等编程语言 API、RESTful API 中使用。 + +- 在 SQL 命令行终端中执行查询语句:启动 SQL 命令行终端,直接输入查询语句执行即可,详见 [SQL 命令行终端](../Tools-System/CLI.md)。 + +- 在 JDBC 中执行查询语句,详见 [JDBC](../API/Programming-JDBC_timecho) 。 + +- 在 JAVA / C++ / Python / Go 等编程语言 API 中执行查询语句,详见应用编程接口一章相应文档。接口原型如下: + + ```java + SessionDataSet executeQueryStatement(String sql); + ``` + +- 在 RESTful API 中使用,详见 [HTTP API V1](../API/RestServiceV1_timecho) 或者 [HTTP API V2](../API/RestServiceV2_timecho)。 + +#### 常用查询的高效执行接口 + +各编程语言的 API 为常用的查询提供了高效执行接口,可以省去 SQL 解析等操作的耗时。包括: + +* 时间序列原始数据范围查询: + - 指定的查询时间范围为左闭右开区间,包含开始时间但不包含结束时间。 + +```java +SessionDataSet executeRawDataQuery(List paths, long startTime, long endTime); +``` + +* 最新点查询: + - 查询最后一条时间戳大于等于某个时间点的数据。 + +```java +SessionDataSet executeLastDataQuery(List paths, long lastTime); +``` + +* 聚合查询: + - 支持指定查询时间范围。指定的查询时间范围为左闭右开区间,包含开始时间但不包含结束时间。 + - 支持按照时间区间分段查询。 + +```java +SessionDataSet executeAggregationQuery(List paths, List aggregations); + +SessionDataSet executeAggregationQuery( + List paths, List aggregations, long startTime, long endTime); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval); + +SessionDataSet executeAggregationQuery( + List paths, + List aggregations, + long startTime, + long endTime, + long interval, + long slidingStep); +``` + +## 2. 选择表达式(SELECT FROM 子句) + +`SELECT` 子句指定查询的输出,由若干个 `selectExpr` 组成。 每个 `selectExpr` 定义了查询结果中的一列或多列。 + +**`selectExpr` 是一个由时间序列路径后缀、常量、函数和运算符组成的表达式。即 `selectExpr` 中可以包含:** +- 时间序列路径后缀(支持使用通配符) +- 运算符 + - 算数运算符 + - 比较运算符 + - 逻辑运算符 +- 函数 + - 聚合函数 + - 时间序列生成函数(包括内置函数和用户自定义函数) +- 常量 + +### 2.1 使用别名 + +由于 IoTDB 独特的数据模型,在每个传感器前都附带有设备等诸多额外信息。有时,我们只针对某个具体设备查询,而这些前缀信息频繁显示造成了冗余,影响了结果集的显示与分析。 + +IoTDB 支持使用`AS`为查询结果集中的列指定别名。 + +**示例:** + +```sql +select s1 as temperature, s2 as speed from root.ln.wf01.wt01; +``` + +结果集将显示为: + +| Time | temperature | speed | +| ---- | ----------- | ----- | +| ... | ... | ... | + +### 2.2 运算符 + +IoTDB 中支持的运算符列表见文档 [运算符和函数](../SQL-Manual/Operator-and-Expression.md)。 + +### 2.3 函数 + +#### 聚合函数 + +聚合函数是多对一函数。它们对一组值进行聚合计算,得到单个聚合结果。 + +**包含聚合函数的查询称为聚合查询**,否则称为时间序列查询。 + +**注意:聚合查询和时间序列查询不能混合使用。** 下列语句是不支持的: + +```sql +select s1, count(s1) from root.sg.d1; +select sin(s1), count(s1) from root.sg.d1; +select s1, count(s1) from root.sg.d1 group by ([10,100),10ms); +``` + +IoTDB 支持的聚合函数见文档 [聚合函数](../SQL-Manual/Operator-and-Expression.md#内置函数)。 + +#### 时间序列生成函数 + +时间序列生成函数接受若干原始时间序列作为输入,产生一列时间序列输出。与聚合函数不同的是,时间序列生成函数的结果集带有时间戳列。 + +所有的时间序列生成函数都可以接受 * 作为输入,都可以与原始时间序列查询混合进行。 + +##### 内置时间序列生成函数 + +IoTDB 中支持的内置函数列表见文档 [运算符和函数](../SQL-Manual/Operator-and-Expression.md)。 + +##### 自定义时间序列生成函数 + +IoTDB 支持通过用户自定义函数(点击查看: [用户自定义函数](../User-Manual/Database-Programming.md#用户自定义函数) )能力进行函数功能扩展。 + +### 2.4 嵌套表达式举例 + +IoTDB 支持嵌套表达式,由于聚合查询和时间序列查询不能在一条查询语句中同时出现,我们将支持的嵌套表达式分为时间序列查询嵌套表达式和聚合查询嵌套表达式两类。 + +#### 时间序列查询嵌套表达式 + +IoTDB 支持在 `SELECT` 子句中计算由**时间序列、常量、时间序列生成函数(包括用户自定义函数)和运算符**组成的任意嵌套表达式。 + +**说明:** + +- 当某个时间戳下左操作数和右操作数都不为空(`null`)时,表达式才会有结果,否则表达式值为`null`,且默认不出现在结果集中。 +- 如果表达式中某个操作数对应多条时间序列(如通配符 `*`),那么每条时间序列对应的结果都会出现在结果集中(按照笛卡尔积形式)。 + +**示例 1:** + +```sql +select a, + b, + ((a + 1) * 2 - 1) % 2 + 1.5, + sin(a + sin(a + sin(b))), + -(a + b) * (sin(a + b) * sin(a + b) + cos(a + b) * cos(a + b)) + 1 +from root.sg1; +``` + +运行结果: + +``` ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Time|root.sg1.a|root.sg1.b|((((root.sg1.a + 1) * 2) - 1) % 2) + 1.5|sin(root.sg1.a + sin(root.sg1.a + sin(root.sg1.b)))|(-root.sg1.a + root.sg1.b * ((sin(root.sg1.a + root.sg1.b) * sin(root.sg1.a + root.sg1.b)) + (cos(root.sg1.a + root.sg1.b) * cos(root.sg1.a + root.sg1.b)))) + 1| ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|1970-01-01T08:00:00.010+08:00| 1| 1| 2.5| 0.9238430524420609| -1.0| +|1970-01-01T08:00:00.020+08:00| 2| 2| 2.5| 0.7903505371876317| -3.0| +|1970-01-01T08:00:00.030+08:00| 3| 3| 2.5| 0.14065207680386618| -5.0| +|1970-01-01T08:00:00.040+08:00| 4| null| 2.5| null| null| +|1970-01-01T08:00:00.050+08:00| null| 5| null| null| null| +|1970-01-01T08:00:00.060+08:00| 6| 6| 2.5| -0.7288037411970916| -11.0| ++-----------------------------+----------+----------+----------------------------------------+---------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +Total line number = 6 +It costs 0.048s +``` + +**示例 2:** + +```sql +select (a + b) * 2 + sin(a) from root.sg +``` + +运行结果: + +``` ++-----------------------------+----------------------------------------------+ +| Time|((root.sg.a + root.sg.b) * 2) + sin(root.sg.a)| ++-----------------------------+----------------------------------------------+ +|1970-01-01T08:00:00.010+08:00| 59.45597888911063| +|1970-01-01T08:00:00.020+08:00| 100.91294525072763| +|1970-01-01T08:00:00.030+08:00| 139.01196837590714| +|1970-01-01T08:00:00.040+08:00| 180.74511316047935| +|1970-01-01T08:00:00.050+08:00| 219.73762514629607| +|1970-01-01T08:00:00.060+08:00| 259.6951893788978| +|1970-01-01T08:00:00.070+08:00| 300.7738906815579| +|1970-01-01T08:00:00.090+08:00| 39.45597888911063| +|1970-01-01T08:00:00.100+08:00| 39.45597888911063| ++-----------------------------+----------------------------------------------+ +Total line number = 9 +It costs 0.011s +``` + +**示例 3:** + +```sql +select (a + *) / 2 from root.sg1 +``` + +运行结果: + +``` ++-----------------------------+-----------------------------+-----------------------------+ +| Time|(root.sg1.a + root.sg1.a) / 2|(root.sg1.a + root.sg1.b) / 2| ++-----------------------------+-----------------------------+-----------------------------+ +|1970-01-01T08:00:00.010+08:00| 1.0| 1.0| +|1970-01-01T08:00:00.020+08:00| 2.0| 2.0| +|1970-01-01T08:00:00.030+08:00| 3.0| 3.0| +|1970-01-01T08:00:00.040+08:00| 4.0| null| +|1970-01-01T08:00:00.060+08:00| 6.0| 6.0| ++-----------------------------+-----------------------------+-----------------------------+ +Total line number = 5 +It costs 0.011s +``` + +**示例 4:** + +```sql +select (a + b) * 3 from root.sg, root.ln +``` + +运行结果: + +``` ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +| Time|(root.sg.a + root.sg.b) * 3|(root.sg.a + root.ln.b) * 3|(root.ln.a + root.sg.b) * 3|(root.ln.a + root.ln.b) * 3| ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +|1970-01-01T08:00:00.010+08:00| 90.0| 270.0| 360.0| 540.0| +|1970-01-01T08:00:00.020+08:00| 150.0| 330.0| 690.0| 870.0| +|1970-01-01T08:00:00.030+08:00| 210.0| 450.0| 570.0| 810.0| +|1970-01-01T08:00:00.040+08:00| 270.0| 240.0| 690.0| 660.0| +|1970-01-01T08:00:00.050+08:00| 330.0| null| null| null| +|1970-01-01T08:00:00.060+08:00| 390.0| null| null| null| +|1970-01-01T08:00:00.070+08:00| 450.0| null| null| null| +|1970-01-01T08:00:00.090+08:00| 60.0| null| null| null| +|1970-01-01T08:00:00.100+08:00| 60.0| null| null| null| ++-----------------------------+---------------------------+---------------------------+---------------------------+---------------------------+ +Total line number = 9 +It costs 0.014s +``` + +#### 聚合查询嵌套表达式 + +IoTDB 支持在 `SELECT` 子句中计算由**聚合函数、常量、时间序列生成函数和表达式**组成的任意嵌套表达式。 + +**说明:** +- 当某个时间戳下左操作数和右操作数都不为空(`null`)时,表达式才会有结果,否则表达式值为`null`,且默认不出现在结果集中。但在使用`GROUP BY`子句的聚合查询嵌套表达式中,我们希望保留每个时间窗口的值,所以表达式值为`null`的窗口也包含在结果集中。 +- 如果表达式中某个操作数对应多条时间序列(如通配符`*`),那么每条时间序列对应的结果都会出现在结果集中(按照笛卡尔积形式)。 + +**示例 1:** + +```sql +select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) +from root.ln.wf01.wt01; +``` + +运行结果: + +``` ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +|avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|avg(root.ln.wf01.wt01.temperature) + sum(root.ln.wf01.wt01.hardware)| ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +| 15.927999999999999| -0.21826546964855045| 16.927999999999997| -7426.0| 7441.928| ++----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ +Total line number = 1 +It costs 0.009s +``` + +**示例 2:** + +```sql +select avg(*), + (avg(*) + 1) * 3 / 2 -1 +from root.sg1 +``` + +运行结果: + +``` ++---------------+---------------+-------------------------------------+-------------------------------------+ +|avg(root.sg1.a)|avg(root.sg1.b)|(avg(root.sg1.a) + 1) * 3 / 2 - 1 |(avg(root.sg1.b) + 1) * 3 / 2 - 1 | ++---------------+---------------+-------------------------------------+-------------------------------------+ +| 3.2| 3.4| 5.300000000000001| 5.6000000000000005| ++---------------+---------------+-------------------------------------+-------------------------------------+ +Total line number = 1 +It costs 0.007s +``` + +**示例 3:** + +```sql +select avg(temperature), + sin(avg(temperature)), + avg(temperature) + 1, + -sum(hardware), + avg(temperature) + sum(hardware) as custom_sum +from root.ln.wf01.wt01 +GROUP BY([10, 90), 10ms); +``` + +运行结果: + +``` ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +| Time|avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|custom_sum| ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +|1970-01-01T08:00:00.010+08:00| 13.987499999999999| 0.9888207947857667| 14.987499999999999| -3211.0| 3224.9875| +|1970-01-01T08:00:00.020+08:00| 29.6| -0.9701057337071853| 30.6| -3720.0| 3749.6| +|1970-01-01T08:00:00.030+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.040+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.050+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.060+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.070+08:00| null| null| null| null| null| +|1970-01-01T08:00:00.080+08:00| null| null| null| null| null| ++-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ +Total line number = 8 +It costs 0.012s +``` + +### 2.5 最新点查询 + +最新点查询是时序数据库 Apache IoTDB 中提供的一种特殊查询。它返回指定时间序列中时间戳最大的数据点,即一条序列的最新状态。 + +在物联网数据分析场景中,此功能尤为重要。为了满足了用户对设备实时监控的需求,Apache IoTDB 对最新点查询进行了**缓存优化**,能够提供毫秒级的返回速度。 + +SQL 语法: + +```sql +select last [COMMA ]* from < PrefixPath > [COMMA < PrefixPath >]* [ORDER BY TIMESERIES (DESC | ASC)?] +``` + +其含义是: 查询时间序列 prefixPath.path 中最近时间戳的数据。 + +- `whereClause` 中当前只支持时间过滤条件,任何其他过滤条件都将会返回异常。当缓存的最新点不满足过滤条件时,IoTDB 需要从存储中获取结果,此时性能将会有所下降。 + +- 结果集为四列的结构: + + ``` + +----+----------+-----+--------+ + |Time|timeseries|value|dataType| + +----+----------+-----+--------+ + ``` + +- 可以使用 `ORDER BY TIME/TIMESERIES/VALUE/DATATYPE (DESC | ASC)` 指定结果集按照某一列进行降序/升序排列。当值列包含多种类型的数据时,按照字符串类型来排序。 + +**示例 1:** 查询 root.ln.wf01.wt01.status 的最新数据点 + +``` +IoTDB> select last status from root.ln.wf01.wt01 ++-----------------------------+------------------------+-----+--------+ +| Time| timeseries|value|dataType| ++-----------------------------+------------------------+-----+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.status|false| BOOLEAN| ++-----------------------------+------------------------+-----+--------+ +Total line number = 1 +It costs 0.000s +``` + +**示例 2:** 查询 root.ln.wf01.wt01 下 status,temperature 时间戳大于等于 2017-11-07T23:50:00 的最新数据点。 + +``` +IoTDB> select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 3:** 查询 root.ln.wf01.wt01 下所有序列的最新数据点,并按照序列名降序排列。 + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by timeseries desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 4:** 查询 root.ln.wf01.wt01 下所有序列的最新数据点,并按照dataType降序排列。 + +``` +IoTDB> select last * from root.ln.wf01.wt01 order by dataType desc; ++-----------------------------+-----------------------------+---------+--------+ +| Time| timeseries| value|dataType| ++-----------------------------+-----------------------------+---------+--------+ +|2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +|2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| ++-----------------------------+-----------------------------+---------+--------+ +Total line number = 2 +It costs 0.002s +``` + +**注意:** 可以通过函数组合方式实现其他过滤条件查询最新点的需求,例如 + +``` +IoTDB> select max_time(*), last_value(*) from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 and status = false align by device ++-----------------+---------------------+----------------+-----------------------+------------------+ +| Device|max_time(temperature)|max_time(status)|last_value(temperature)|last_value(status)| ++-----------------+---------------------+----------------+-----------------------+------------------+ +|root.ln.wf01.wt01| 1510077540000| 1510077540000| 21.067368| false| ++-----------------+---------------------+----------------+-----------------------+------------------+ +Total line number = 1 +It costs 0.021s +``` + + +## 3. 查询过滤条件(WHERE 子句) + +`WHERE` 子句指定了对数据行的筛选条件,由一个 `whereCondition` 组成。 + +`whereCondition` 是一个逻辑表达式,对于要选择的每一行,其计算结果为真。如果没有 `WHERE` 子句,将选择所有行。 +在 `whereCondition` 中,可以使用除聚合函数之外的任何 IOTDB 支持的函数和运算符。 + +根据过滤条件的不同,可以分为时间过滤条件和值过滤条件。时间过滤条件和值过滤条件可以混合使用。 + +### 3.1 时间过滤条件 + +使用时间过滤条件可以筛选特定时间范围的数据。对于时间戳支持的格式,请参考 [时间戳类型](../Background-knowledge/Data-Type.md) 。 + +示例如下: + +1. 选择时间戳大于 2022-01-01T00:05:00.000 的数据: + + ```sql + select s1 from root.sg1.d1 where time > 2022-01-01T00:05:00.000; + ``` + +2. 选择时间戳等于 2022-01-01T00:05:00.000 的数据: + + ```sql + select s1 from root.sg1.d1 where time = 2022-01-01T00:05:00.000; + ``` + +3. 选择时间区间 [2017-11-01T00:05:00.000, 2017-11-01T00:12:00.000) 内的数据: + + ```sql + select s1 from root.sg1.d1 where time >= 2022-01-01T00:05:00.000 and time < 2017-11-01T00:12:00.000; + ``` + +注:在上述示例中,`time` 也可写做 `timestamp`。 + +### 3.2 值过滤条件 + +使用值过滤条件可以筛选数据值满足特定条件的数据。 +**允许**使用 select 子句中未选择的时间序列作为值过滤条件。 + +示例如下: + +1. 选择值大于 36.5 的数据: + + ```sql + select temperature from root.sg1.d1 where temperature > 36.5; + ``` + +2. 选择值等于 true 的数据: + + ```sql + select status from root.sg1.d1 where status = true; + +3. 选择区间 [36.5,40] 内或之外的数据: + + ```sql + select temperature from root.sg1.d1 where temperature between 36.5 and 40; + ```` + ```sql + select temperature from root.sg1.d1 where temperature not between 36.5 and 40; + ```` + +4. 选择值在特定范围内的数据: + + ```sql + select code from root.sg1.d1 where code in ('200', '300', '400', '500'); + ``` + +5. 选择值在特定范围外的数据: + + ```sql + select code from root.sg1.d1 where code not in ('200', '300', '400', '500'); + ``` + +6. 选择值为空的数据: + + ```sql + select code from root.sg1.d1 where temperature is null; + ```` + +7. 选择值为非空的数据: + + ```sql + select code from root.sg1.d1 where temperature is not null; + ```` + +### 3.3 模糊查询 + +对于 TEXT 类型的数据,支持使用 `Like` 和 `Regexp` 运算符对数据进行模糊匹配 + +#### 使用 `Like` 进行模糊匹配 + +**匹配规则:** + +- `%` 表示任意0个或多个字符。 +- `_` 表示任意单个字符。 + +**示例 1:** 查询 `root.sg.d1` 下 `value` 含有`'cc'`的数据。 + +``` +IoTDB> select * from root.sg.d1 where value like '%cc%' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 2:** 查询 `root.sg.d1` 下 `value` 中间为 `'b'`、前后为任意单个字符的数据。 + +``` +IoTDB> select * from root.sg.device where value like '_b_' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:02.000+08:00| abc| ++-----------------------------+----------------+ +Total line number = 1 +It costs 0.002s +``` + +#### 使用 `Regexp` 进行模糊匹配 + +需要传入的过滤条件为 **Java 标准库风格的正则表达式**。 + +**常见的正则匹配举例:** + +``` +长度为3-20的所有字符:^.{3,20}$ +大写英文字符:^[A-Z]+$ +数字和英文字符:^[A-Za-z0-9]+$ +以a开头的:^a.* +``` + +**示例 1:** 查询 root.sg.d1 下 value 值为26个英文字符组成的字符串。 + +```shell +IoTDB> select * from root.sg.d1 where value regexp '^[A-Za-z]+$' ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +**示例 2:** 查询 root.sg.d1 下 value 值为26个小写英文字符组成的字符串且时间大于100的。 + +```shell +IoTDB> select * from root.sg.d1 where value regexp '^[a-z]+$' and time > 100 ++-----------------------------+----------------+ +| Time|root.sg.d1.value| ++-----------------------------+----------------+ +|2017-11-01T00:00:00.000+08:00| aabbccdd| +|2017-11-01T00:00:01.000+08:00| cc| ++-----------------------------+----------------+ +Total line number = 2 +It costs 0.002s +``` + +## 4. 分段分组聚合(GROUP BY 子句) +IoTDB支持通过`GROUP BY`子句对序列进行分段或者分组聚合。 + +分段聚合是指按照时间维度,针对同时间序列中不同数据点之间的时间关系,对数据在行的方向进行分段,每个段得到一个聚合值。目前支持**时间区间分段**、**差值分段**、**条件分段**、**会话分段**和**点数分段**,未来将支持更多分段方式。 + +分组聚合是指针对不同时间序列,在时间序列的潜在业务属性上分组,每个组包含若干条时间序列,每个组得到一个聚合值。支持**按路径层级分组**和**按序列标签分组**两种分组方式。 + +### 4.1 分段聚合 + +#### 时间区间分段聚合 + +时间区间分段聚合是一种时序数据典型的查询方式,数据以高频进行采集,需要按照一定的时间间隔进行聚合计算,如计算每天的平均气温,需要将气温的序列按天进行分段,然后计算平均值。 + +在 IoTDB 中,聚合查询可以通过 `GROUP BY` 子句指定按照时间区间分段聚合。用户可以指定聚合的时间间隔和滑动步长,相关参数如下: + +* 参数 1:时间轴显示时间窗口大小 +* 参数 2:聚合窗口的大小(必须为正数) +* 参数 3:聚合窗口的滑动步长(可选,默认与聚合窗口大小相同) + +下图中指出了这三个参数的含义: + + + +接下来,我们给出几个典型例子: + +##### 未指定滑动步长的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d); +``` +这条查询的含义是: + +由于用户没有指定滑动步长,滑动步长将会被默认设置为跟时间间隔参数相同,也就是`1d`。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1d`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[0,1d), [1d, 2d), [2d, 3d) 等等。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 1440| 26.0| +|2017-11-02T00:00:00.000+08:00| 1440| 26.0| +|2017-11-03T00:00:00.000+08:00| 1440| 25.99| +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.024s +``` + +##### 指定滑动步长的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`1d`,GROUP BY 语句执行时将会每次把时间间隔往后移动一天的步长,而不是默认的 3 小时。 + +也就意味着,我们想要取从 2017-11-01 到 2017-11-07 每一天的凌晨 0 点到凌晨 3 点的数据。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`3h`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00), [2017-11-03T00:00:00, 2017-11-03T03:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天的凌晨 0 点到凌晨 3 点) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-02T00:00:00.000+08:00| 180| 25.98| +|2017-11-03T00:00:00.000+08:00| 180| 25.96| +|2017-11-04T00:00:00.000+08:00| 180| 25.96| +|2017-11-05T00:00:00.000+08:00| 180| 26.0| +|2017-11-06T00:00:00.000+08:00| 180| 25.85| +|2017-11-07T00:00:00.000+08:00| 180| 25.99| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 7 +It costs 0.006s +``` + +滑动步长可以小于聚合窗口,此时聚合窗口之间有重叠时间(类似于一个滑动窗口)。 + +例如 SQL: +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-01 10:00:00), 4h, 2h); +``` + +SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| 25.98| +|2017-11-01T02:00:00.000+08:00| 180| 25.98| +|2017-11-01T04:00:00.000+08:00| 180| 25.96| +|2017-11-01T06:00:00.000+08:00| 180| 25.96| +|2017-11-01T08:00:00.000+08:00| 180| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 5 +It costs 0.006s +``` + +##### 按照自然月份的时间区间分段聚合查询 + +对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 where time > 2017-11-01T01:00:00 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`2mo`,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。 + +也就意味着,我们想要取从 2017-11-01 到 2019-11-07 每 2 个自然月的第一个月的数据。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2019-11-07T23:00:00)。 + +起始时间为 2017-11-01T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 1 号作为时间间隔的起始时间。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1mo`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-12-01T00:00:00), [2018-02-01T00:00:00, 2018-03-01T00:00:00), [2018-05-03T00:00:00, 2018-06-01T00:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-01T00:00:00.000+08:00| 259| +|2018-01-01T00:00:00.000+08:00| 250| +|2018-03-01T00:00:00.000+08:00| 259| +|2018-05-01T00:00:00.000+08:00| 251| +|2018-07-01T00:00:00.000+08:00| 242| +|2018-09-01T00:00:00.000+08:00| 225| +|2018-11-01T00:00:00.000+08:00| 216| +|2019-01-01T00:00:00.000+08:00| 207| +|2019-03-01T00:00:00.000+08:00| 216| +|2019-05-01T00:00:00.000+08:00| 207| +|2019-07-01T00:00:00.000+08:00| 199| +|2019-09-01T00:00:00.000+08:00| 181| +|2019-11-01T00:00:00.000+08:00| 60| ++-----------------------------+-------------------------------+ +``` + +对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo); +``` + +这条查询的含义是: + +由于用户指定了滑动步长为`2mo`,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。 + +也就意味着,我们想要取从 2017-10-31 到 2019-11-07 每 2 个自然月的第一个月的数据。 + +与上述示例不同的是起始时间为 2017-10-31T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 31 号(即最后一天)作为时间间隔的起始时间。若起始时间设置为 30 号,滑动步长会将时间间隔的起始时间设置为当月 30 号,若不存在则为最后一天。 + +上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-10-31T00:00:00, 2019-11-07T23:00:00)。 + +上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1mo`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-10-31T00:00:00, 2017-11-31T00:00:00), [2018-02-31T00:00:00, 2018-03-31T00:00:00), [2018-05-31T00:00:00, 2018-06-31T00:00:00) 等等。 + +上面这个例子的第三个参数是每次时间间隔的滑动步长。 + +然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-10-31T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-10-31T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月) + +每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-10-31T00:00:00.000+08:00| 251| +|2017-12-31T00:00:00.000+08:00| 250| +|2018-02-28T00:00:00.000+08:00| 259| +|2018-04-30T00:00:00.000+08:00| 250| +|2018-06-30T00:00:00.000+08:00| 242| +|2018-08-31T00:00:00.000+08:00| 225| +|2018-10-31T00:00:00.000+08:00| 216| +|2018-12-31T00:00:00.000+08:00| 208| +|2019-02-28T00:00:00.000+08:00| 216| +|2019-04-30T00:00:00.000+08:00| 208| +|2019-06-30T00:00:00.000+08:00| 199| +|2019-08-31T00:00:00.000+08:00| 181| +|2019-10-31T00:00:00.000+08:00| 69| ++-----------------------------+-------------------------------+ +``` + +##### 左开右闭区间 + +每个区间的结果时间戳为区间右端点,对应的 SQL 语句是: + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d); +``` + +这条查询语句的时间区间是左开右闭的,结果中不会包含时间点 2017-11-01 的数据,但是会包含时间点 2017-11-07 的数据。 + +SQL 执行后的结果集如下所示: + +``` ++-----------------------------+-------------------------------+ +| Time|count(root.ln.wf01.wt01.status)| ++-----------------------------+-------------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### 差值分段聚合 +IoTDB支持通过`GROUP BY VARIATION`语句来根据差值进行分组。`GROUP BY VARIATION`会将第一个点作为一个组的**基准点**,每个新的数据在按照给定规则与基准点进行差值运算后, +如果差值小于给定的阈值则将该新点归于同一组,否则结束当前分组,以这个新的数据为新的基准点开启新的分组。 +该分组方式不会重叠,且没有固定的开始结束时间。其子句语法如下: +```sql +group by variation(controlExpression[,delta][,ignoreNull=true/false]) +``` +不同的参数含义如下 +* controlExpression + +分组所参照的值,**可以是查询数据中的某一列或是多列的表达式 +(多列表达式计算后仍为一个值,使用多列表达式时指定的列必须都为数值列)**, 差值便是根据数据的controlExpression的差值运算。 +* delta + +分组所使用的阈值,同一分组中**每个点的controlExpression对应的值与该组中基准点对应值的差值都小于`delta`**。当`delta=0`时,相当于一个等值分组,所有连续且expression值相同的数据将被分到一组。 + +* ignoreNull + +用于指定`controlExpression`的值为null时对数据的处理方式,当`ignoreNull`为false时,该null值会被视为新的值,`ignoreNull`为true时,则直接跳过对应的点。 + +在`delta`取不同值时,`controlExpression`支持的返回数据类型以及当`ignoreNull`为false时对于null值的处理方式可以见下表: + +| delta | controlExpression支持的返回类型 | ignoreNull=false时对于Null值的处理 | +|----------|--------------------------------------|-----------------------------------------------------------------| +| delta!=0 | INT32、INT64、FLOAT、DOUBLE | 若正在维护分组的值不为null,null视为无穷大/无穷小,结束当前分组。连续的null视为差值相等的值,会被分配在同一个分组 | +| delta=0 | TEXT、BINARY、INT32、INT64、FLOAT、DOUBLE | null被视为新分组中的新值,连续的null属于相同的分组 | + +下图为差值分段的一个分段方式示意图,与组中第一个数据的控制列值的差值在delta内的控制列对应的点属于相同的分组。 + +groupByVariation + +##### 使用注意事项 +1. `controlExpression`的结果应该为唯一值,如果使用通配符拼接后出现多列,则报错。 +2. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +3. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +4. 当没有指定`delta`和`ignoreNull`时,`delta`默认为0,`ignoreNull`默认为true。 +5. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + +使用如下的原始数据,接下来会给出几个事件分段查询的使用样例 +``` ++-----------------------------+-------+-------+-------+--------+-------+-------+ +| Time| s1| s2| s3| s4| s5| s6| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +|1970-01-01T08:00:00.000+08:00| 4.5| 9.0| 0.0| 45.0| 9.0| 8.25| +|1970-01-01T08:00:00.010+08:00| null| 19.0| 10.0| 145.0| 19.0| 8.25| +|1970-01-01T08:00:00.020+08:00| 24.5| 29.0| null| 245.0| 29.0| null| +|1970-01-01T08:00:00.030+08:00| 34.5| null| 30.0| 345.0| null| null| +|1970-01-01T08:00:00.040+08:00| 44.5| 49.0| 40.0| 445.0| 49.0| 8.25| +|1970-01-01T08:00:00.050+08:00| null| 59.0| 50.0| 545.0| 59.0| 6.25| +|1970-01-01T08:00:00.060+08:00| 64.5| 69.0| 60.0| 645.0| 69.0| null| +|1970-01-01T08:00:00.070+08:00| 74.5| 79.0| null| null| 79.0| 3.25| +|1970-01-01T08:00:00.080+08:00| 84.5| 89.0| 80.0| 845.0| 89.0| 3.25| +|1970-01-01T08:00:00.090+08:00| 94.5| 99.0| 90.0| 945.0| 99.0| 3.25| +|1970-01-01T08:00:00.150+08:00| 66.5| 77.0| 90.0| 945.0| 99.0| 9.25| ++-----------------------------+-------+-------+-------+--------+-------+-------+ +``` +##### delta=0时的等值事件分段 +使用如下sql语句 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6) +``` +得到如下的查询结果,这里忽略了s6为null的行 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.040+08:00| 24.5| 3| 50.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +当指定ignoreNull为false时,会将s6为null的数据也考虑进来 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, ignoreNull=false) +``` +得到如下的结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.020+08:00|1970-01-01T08:00:00.030+08:00| 29.5| 1| 30.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.040+08:00| 44.5| 1| 40.0| +|1970-01-01T08:00:00.050+08:00|1970-01-01T08:00:00.050+08:00| null| 1| 50.0| +|1970-01-01T08:00:00.060+08:00|1970-01-01T08:00:00.060+08:00| 64.5| 1| 60.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +##### delta!=0时的差值事件分段 +使用如下sql语句 +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6, 4) +``` +得到如下的查询结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.050+08:00| 24.5| 4| 100.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.090+08:00| 84.5| 3| 170.0| +|1970-01-01T08:00:00.150+08:00|1970-01-01T08:00:00.150+08:00| 66.5| 1| 90.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +group by子句中的controlExpression同样支持列的表达式 + +```sql +select __endTime, avg(s1), count(s2), sum(s3) from root.sg.d group by variation(s6+s5, 10) +``` +得到如下的查询结果 +``` ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +| Time| __endTime|avg(root.sg.d.s1)|count(root.sg.d.s2)|sum(root.sg.d.s3)| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +|1970-01-01T08:00:00.000+08:00|1970-01-01T08:00:00.010+08:00| 4.5| 2| 10.0| +|1970-01-01T08:00:00.040+08:00|1970-01-01T08:00:00.050+08:00| 44.5| 2| 90.0| +|1970-01-01T08:00:00.070+08:00|1970-01-01T08:00:00.080+08:00| 79.5| 2| 80.0| +|1970-01-01T08:00:00.090+08:00|1970-01-01T08:00:00.150+08:00| 80.5| 2| 180.0| ++-----------------------------+-----------------------------+-----------------+-------------------+-----------------+ +``` +#### 条件分段聚合 +当需要根据指定条件对数据进行筛选,并将连续的符合条件的行分为一组进行聚合运算时,可以使用`GROUP BY CONDITION`的分段方式;不满足给定条件的行因为不属于任何分组会被直接简单忽略。 +其语法定义如下: +```sql +group by condition(predict,[keep>/>=/=/<=/<]threshold,[,ignoreNull=true/false]) +``` +* predict + +返回boolean数据类型的合法表达式,用于分组的筛选。 +* keep[>/>=/=/<=/<]threshold + +keep表达式用来指定形成分组所需要连续满足`predict`条件的数据行数,只有行数满足keep表达式的分组才会被输出。keep表达式由一个'keep'字符串和`long`类型的threshold组合或者是单独的`long`类型数据构成。 + +* ignoreNull=true/false + +用于指定遇到predict为null的数据行时的处理方式,为true则跳过该行,为false则结束当前分组。 + +##### 使用注意事项 +1. keep条件在查询中是必需的,但可以省略掉keep字符串给出一个`long`类型常数,默认为`keep=该long型常数`的等于条件。 +2. `ignoreNull`默认为true。 +3. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +4. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +5. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + + +对于如下原始数据,下面会给出几个查询样例: +``` ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +| Time|root.sg.beijing.car01.soc|root.sg.beijing.car01.charging_status|root.sg.beijing.car01.vehicle_status| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| 1| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| 1| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| 1| ++-----------------------------+-------------------------+-------------------------------------+------------------------------------+ +``` +查询至少连续两行以上的charging_status=1的数据,sql语句如下: +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoreNull=true) +``` +得到结果如下: +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 10| 5| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` +当设置`ignoreNull`为false时,遇到null值为将其视为一个不满足条件的行,会结束正在计算的分组。 +```sql +select max_time(charging_status),count(vehicle_status),last_value(soc) from root.** group by condition(charging_status=1,KEEP>=2,ignoreNull=false) +``` +得到如下结果,原先的分组被含null的行拆分: +``` ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +| Time|max_time(root.sg.beijing.car01.charging_status)|count(root.sg.beijing.car01.vehicle_status)|last_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +|1970-01-01T08:00:00.001+08:00| 2| 2| 16.0| +|1970-01-01T08:00:00.005+08:00| 7| 3| 36.0| +|1970-01-01T08:00:00.009+08:00| 10| 2| 60.0| ++-----------------------------+-----------------------------------------------+-------------------------------------------+-------------------------------------+ +``` +#### 会话分段聚合 +`GROUP BY SESSION`可以根据时间列的间隔进行分组,在结果集的时间列中,时间间隔小于等于设定阈值的数据会被分为一组。例如在工业场景中,设备并不总是连续运行,`GROUP BY SESSION`会将设备每次接入会话所产生的数据分为一组。 +其语法定义如下: +```sql +group by session(timeInterval) +``` +* timeInterval + +设定的时间差阈值,当两条数据时间列的差值大于该阈值,则会给数据创建一个新的分组。 + +下图为`group by session`下的一个分组示意图 + + + +##### 使用注意事项 +1. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +2. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +3. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 + +对于下面的原始数据,给出几个查询样例。 +``` ++-----------------------------+-----------------+-----------+--------+------+ +| Time| Device|temperature|hardware|status| ++-----------------------------+-----------------+-----------+--------+------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01| 35.7| 11| false| +|1970-01-01T08:00:02.000+08:00|root.ln.wf02.wt01| 35.8| 22| true| +|1970-01-01T08:00:03.000+08:00|root.ln.wf02.wt01| 35.4| 33| false| +|1970-01-01T08:00:04.000+08:00|root.ln.wf02.wt01| 36.4| 44| false| +|1970-01-01T08:00:05.000+08:00|root.ln.wf02.wt01| 36.8| 55| false| +|1970-01-01T08:00:10.000+08:00|root.ln.wf02.wt01| 36.8| 110| false| +|1970-01-01T08:00:20.000+08:00|root.ln.wf02.wt01| 37.8| 220| true| +|1970-01-01T08:00:30.000+08:00|root.ln.wf02.wt01| 37.5| 330| false| +|1970-01-01T08:00:40.000+08:00|root.ln.wf02.wt01| 37.4| 440| false| +|1970-01-01T08:00:50.000+08:00|root.ln.wf02.wt01| 37.9| 550| false| +|1970-01-01T08:01:40.000+08:00|root.ln.wf02.wt01| 38.0| 110| false| +|1970-01-01T08:02:30.000+08:00|root.ln.wf02.wt01| 38.8| 220| true| +|1970-01-01T08:03:20.000+08:00|root.ln.wf02.wt01| 38.6| 330| false| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01| 38.4| 440| false| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01| 38.3| 550| false| +|1970-01-01T08:06:40.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:07:50.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-01T08:08:00.000+08:00|root.ln.wf02.wt01| null| 0| null| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01| 38.2| 110| false| +|1970-01-02T08:08:02.000+08:00|root.ln.wf02.wt01| 37.5| 220| true| +|1970-01-02T08:08:03.000+08:00|root.ln.wf02.wt01| 37.4| 330| false| +|1970-01-02T08:08:04.000+08:00|root.ln.wf02.wt01| 36.8| 440| false| +|1970-01-02T08:08:05.000+08:00|root.ln.wf02.wt01| 37.4| 550| false| ++-----------------------------+-----------------+-----------+--------+------+ +``` +可以按照不同的时间单位设定时间间隔,sql语句如下: +```sql +select __endTime,count(*) from root.** group by session(1d) +``` +得到如下结果: +``` ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time| __endTime|count(root.ln.wf02.wt01.temperature)|count(root.ln.wf02.wt01.hardware)|count(root.ln.wf02.wt01.status)| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|1970-01-01T08:00:01.000+08:00|1970-01-01T08:08:00.000+08:00| 15| 18| 15| +|1970-01-02T08:08:01.000+08:00|1970-01-02T08:08:05.000+08:00| 5| 5| 5| ++-----------------------------+-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` +也可以和`HAVING`、`ALIGN BY DEVICE`共同使用 +```sql +select __endTime,sum(hardware) from root.ln.wf02.wt01 group by session(50s) having sum(hardware)>0 align by device +``` +得到如下结果,其中排除了`sum(hardware)`为0的部分 +``` ++-----------------------------+-----------------+-----------------------------+-------------+ +| Time| Device| __endTime|sum(hardware)| ++-----------------------------+-----------------+-----------------------------+-------------+ +|1970-01-01T08:00:01.000+08:00|root.ln.wf02.wt01|1970-01-01T08:03:20.000+08:00| 2475.0| +|1970-01-01T08:04:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:04:20.000+08:00| 440.0| +|1970-01-01T08:05:20.000+08:00|root.ln.wf02.wt01|1970-01-01T08:05:20.000+08:00| 550.0| +|1970-01-02T08:08:01.000+08:00|root.ln.wf02.wt01|1970-01-02T08:08:05.000+08:00| 1650.0| ++-----------------------------+-----------------+-----------------------------+-------------+ +``` +#### 点数分段聚合 +`GROUP BY COUNT`可以根据点数分组进行聚合运算,将连续的指定数量数据点分为一组,即按照固定的点数进行分组。 +其语法定义如下: +```sql +group by count(controlExpression, size[,ignoreNull=true/false]) +``` +* controlExpression + +计数参照的对象,可以是结果集的任意列或是列的表达式 + +* size + +一个组中数据点的数量,每`size`个数据点会被分到同一个组 + +* ignoreNull=true/false + +是否忽略`controlExpression`为null的数据点,当ignoreNull为true时,在计数时会跳过`controlExpression`结果为null的数据点 + +##### 使用注意事项 +1. 对于一个分组,默认Time列输出分组的开始时间,查询时可以使用select `__endTime`的方式来使得结果输出分组的结束时间。 +2. 与`ALIGN BY DEVICE`搭配使用时会对每个device进行单独的分组操作。 +3. 当前暂不支持与`GROUP BY LEVEL`搭配使用。 +4. 当一个分组内最终的点数不满足`size`的数量时,不会输出该分组的结果 + +对于下面的原始数据,给出几个查询样例。 +``` ++-----------------------------+-----------+-----------------------+ +| Time|root.sg.soc|root.sg.charging_status| ++-----------------------------+-----------+-----------------------+ +|1970-01-01T08:00:00.001+08:00| 14.0| 1| +|1970-01-01T08:00:00.002+08:00| 16.0| 1| +|1970-01-01T08:00:00.003+08:00| 16.0| 0| +|1970-01-01T08:00:00.004+08:00| 16.0| 0| +|1970-01-01T08:00:00.005+08:00| 18.0| 1| +|1970-01-01T08:00:00.006+08:00| 24.0| 1| +|1970-01-01T08:00:00.007+08:00| 36.0| 1| +|1970-01-01T08:00:00.008+08:00| 36.0| null| +|1970-01-01T08:00:00.009+08:00| 45.0| 1| +|1970-01-01T08:00:00.010+08:00| 60.0| 1| ++-----------------------------+-----------+-----------------------+ +``` +sql语句如下 +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5) +``` +得到如下结果,其中由于第二个1970-01-01T08:00:00.006+08:00到1970-01-01T08:00:00.010+08:00的窗口中包含四个点,不符合`size = 5`的条件,因此不被输出 +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` +而当使用ignoreNull将null值也考虑进来时,可以得到两个点计数为5的窗口,sql如下 +```sql +select count(charging_stauts), first_value(soc) from root.sg group by count(charging_status,5,ignoreNull=false) +``` +得到如下结果 +``` ++-----------------------------+-----------------------------+--------------------------------------+ +| Time| __endTime|first_value(root.sg.beijing.car01.soc)| ++-----------------------------+-----------------------------+--------------------------------------+ +|1970-01-01T08:00:00.001+08:00|1970-01-01T08:00:00.005+08:00| 14.0| +|1970-01-01T08:00:00.006+08:00|1970-01-01T08:00:00.010+08:00| 24.0| ++-----------------------------+-----------------------------+--------------------------------------+ +``` +### 4.2 分组聚合 + +#### 路径层级分组聚合 + +在时间序列层级结构中,路径层级分组聚合查询用于**对某一层级下同名的序列进行聚合查询**。 + +- 使用 `GROUP BY LEVEL = INT` 来指定需要聚合的层级,并约定 `ROOT` 为第 0 层。若统计 "root.ln" 下所有序列则需指定 level 为 1。 +- 路径层次分组聚合查询支持使用所有内置聚合函数。对于 `sum`,`avg`,`min_value`, `max_value`, `extreme` 五种聚合函数,需保证所有聚合的时间序列数据类型相同。其他聚合函数没有此限制。 + +**示例1:** 不同 database 下均存在名为 status 的序列, 如 "root.ln.wf01.wt01.status", "root.ln.wf02.wt02.status", 以及 "root.sgcc.wf03.wt01.status", 如果需要统计不同 database 下 status 序列的数据点个数,使用以下查询: + +```sql +select count(status) from root.** group by level = 1 +``` + +运行结果为: + +``` ++-------------------------+---------------------------+ +|count(root.ln.*.*.status)|count(root.sgcc.*.*.status)| ++-------------------------+---------------------------+ +| 20160| 10080| ++-------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**示例2:** 统计不同设备下 status 序列的数据点个数,可以规定 level = 3, + +```sql +select count(status) from root.** group by level = 3 +``` + +运行结果为: + +``` ++---------------------------+---------------------------+ +|count(root.*.*.wt01.status)|count(root.*.*.wt02.status)| ++---------------------------+---------------------------+ +| 20160| 10080| ++---------------------------+---------------------------+ +Total line number = 1 +It costs 0.003s +``` + +注意,这时会将 database `ln` 和 `sgcc` 下名为 `wt01` 的设备视为同名设备聚合在一起。 + +**示例3:** 统计不同 database 下的不同设备中 status 序列的数据点个数,可以使用以下查询: + +```sql +select count(status) from root.** group by level = 1, 3 +``` + +运行结果为: + +``` ++----------------------------+----------------------------+------------------------------+ +|count(root.ln.*.wt01.status)|count(root.ln.*.wt02.status)|count(root.sgcc.*.wt01.status)| ++----------------------------+----------------------------+------------------------------+ +| 10080| 10080| 10080| ++----------------------------+----------------------------+------------------------------+ +Total line number = 1 +It costs 0.003s +``` + +**示例4:** 查询所有序列下温度传感器 temperature 的最大值,可以使用下列查询语句: + +```sql +select max_value(temperature) from root.** group by level = 0 +``` + +运行结果: + +``` ++---------------------------------+ +|max_value(root.*.*.*.temperature)| ++---------------------------------+ +| 26.0| ++---------------------------------+ +Total line number = 1 +It costs 0.013s +``` + +**示例5:** 上面的查询都是针对某一个传感器,特别地,**如果想要查询某一层级下所有传感器拥有的总数据点数,则需要显式规定测点为 `*`** + +```sql +select count(*) from root.ln.** group by level = 2 +``` + +运行结果: + +``` ++----------------------+----------------------+ +|count(root.*.wf01.*.*)|count(root.*.wf02.*.*)| ++----------------------+----------------------+ +| 20160| 20160| ++----------------------+----------------------+ +Total line number = 1 +It costs 0.013s +``` + +##### 与时间区间分段聚合混合使用 + +通过定义 LEVEL 来统计指定层级下的数据点个数。 + +例如: + +统计降采样后的数据点个数 + +```sql +select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1; +``` + +结果: + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-02T00:00:00.000+08:00| 1440| +|2017-11-03T00:00:00.000+08:00| 1440| +|2017-11-04T00:00:00.000+08:00| 1440| +|2017-11-05T00:00:00.000+08:00| 1440| +|2017-11-06T00:00:00.000+08:00| 1440| +|2017-11-07T00:00:00.000+08:00| 1440| +|2017-11-07T23:00:00.000+08:00| 1380| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.006s +``` + +加上滑动 Step 的降采样后的结果也可以汇总 + +```sql +select count(status) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d), level=1; +``` + +``` ++-----------------------------+-------------------------+ +| Time|COUNT(root.ln.*.*.status)| ++-----------------------------+-------------------------+ +|2017-11-01T00:00:00.000+08:00| 180| +|2017-11-02T00:00:00.000+08:00| 180| +|2017-11-03T00:00:00.000+08:00| 180| +|2017-11-04T00:00:00.000+08:00| 180| +|2017-11-05T00:00:00.000+08:00| 180| +|2017-11-06T00:00:00.000+08:00| 180| +|2017-11-07T00:00:00.000+08:00| 180| ++-----------------------------+-------------------------+ +Total line number = 7 +It costs 0.004s +``` + +#### 标签分组聚合 + +IoTDB 支持通过 `GROUP BY TAGS` 语句根据时间序列中定义的标签的键值做分组聚合查询。 + +我们先在 IoTDB 中写入如下示例数据,稍后会以这些数据为例介绍标签聚合查询。 + +这些是某工厂 `factory1` 在多个城市的多个车间的设备温度数据, 时间范围为 [1000, 10000)。 + +时间序列路径中的设备一级是设备唯一标识。城市信息 `city` 和车间信息 `workshop` 则被建模在该设备时间序列的标签中。 +其中,设备 `d1`、`d2` 在 `Beijing` 的 `w1` 车间, `d3`、`d4` 在 `Beijing` 的 `w2` 车间,`d5`、`d6` 在 `Shanghai` 的 `w1` 车间,`d7` 在 `Shanghai` 的 `w2` 车间。 +`d8` 和 `d9` 设备目前处于调试阶段,还未被分配到具体的城市和车间,所以其相应的标签值为空值。 + +```SQL +create database root.factory1; +create timeseries root.factory1.d1.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d2.temperature with datatype=FLOAT tags(city=Beijing, workshop=w1); +create timeseries root.factory1.d3.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d4.temperature with datatype=FLOAT tags(city=Beijing, workshop=w2); +create timeseries root.factory1.d5.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d6.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w1); +create timeseries root.factory1.d7.temperature with datatype=FLOAT tags(city=Shanghai, workshop=w2); +create timeseries root.factory1.d8.temperature with datatype=FLOAT; +create timeseries root.factory1.d9.temperature with datatype=FLOAT; + +insert into root.factory1.d1(time, temperature) values(1000, 104.0); +insert into root.factory1.d1(time, temperature) values(3000, 104.2); +insert into root.factory1.d1(time, temperature) values(5000, 103.3); +insert into root.factory1.d1(time, temperature) values(7000, 104.1); + +insert into root.factory1.d2(time, temperature) values(1000, 104.4); +insert into root.factory1.d2(time, temperature) values(3000, 103.7); +insert into root.factory1.d2(time, temperature) values(5000, 103.3); +insert into root.factory1.d2(time, temperature) values(7000, 102.9); + +insert into root.factory1.d3(time, temperature) values(1000, 103.9); +insert into root.factory1.d3(time, temperature) values(3000, 103.8); +insert into root.factory1.d3(time, temperature) values(5000, 102.7); +insert into root.factory1.d3(time, temperature) values(7000, 106.9); + +insert into root.factory1.d4(time, temperature) values(1000, 103.9); +insert into root.factory1.d4(time, temperature) values(5000, 102.7); +insert into root.factory1.d4(time, temperature) values(7000, 106.9); + +insert into root.factory1.d5(time, temperature) values(1000, 112.9); +insert into root.factory1.d5(time, temperature) values(7000, 113.0); + +insert into root.factory1.d6(time, temperature) values(1000, 113.9); +insert into root.factory1.d6(time, temperature) values(3000, 113.3); +insert into root.factory1.d6(time, temperature) values(5000, 112.7); +insert into root.factory1.d6(time, temperature) values(7000, 112.3); + +insert into root.factory1.d7(time, temperature) values(1000, 101.2); +insert into root.factory1.d7(time, temperature) values(3000, 99.3); +insert into root.factory1.d7(time, temperature) values(5000, 100.1); +insert into root.factory1.d7(time, temperature) values(7000, 99.8); + +insert into root.factory1.d8(time, temperature) values(1000, 50.0); +insert into root.factory1.d8(time, temperature) values(3000, 52.1); +insert into root.factory1.d8(time, temperature) values(5000, 50.1); +insert into root.factory1.d8(time, temperature) values(7000, 50.5); + +insert into root.factory1.d9(time, temperature) values(1000, 50.3); +insert into root.factory1.d9(time, temperature) values(3000, 52.1); +``` + +##### 单标签聚合查询 + +用户想统计该工厂每个地区的设备的温度的平均值,可以使用如下查询语句 + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city); +``` + +该查询会将具有同一个 `city` 标签值的时间序列的所有满足查询条件的点做平均值计算,计算结果如下 + +``` ++--------+------------------+ +| city| avg(temperature)| ++--------+------------------+ +| Beijing|104.04666697184244| +|Shanghai|107.85000076293946| +| NULL| 50.84999910990397| ++--------+------------------+ +Total line number = 3 +It costs 0.231s +``` + +从结果集中可以看到,和分段聚合、按层次分组聚合相比,标签聚合的查询结果的不同点是: +1. 标签聚合查询的聚合结果不会再做去星号展开,而是将多个时间序列的数据作为一个整体进行聚合计算。 +2. 标签聚合查询除了输出聚合结果列,还会输出聚合标签的键值列。该列的列名为聚合指定的标签键,列的值则为所有查询的时间序列中出现的该标签的值。 +如果某些时间序列未设置该标签,则在键值列中有一行单独的 `NULL` ,代表未设置标签的所有时间序列数据的聚合结果。 + +##### 多标签分组聚合查询 + +除了基本的单标签聚合查询外,还可以按顺序指定多个标签进行聚合计算。 + +例如,用户想统计每个城市的每个车间内设备的平均温度。但因为各个城市的车间名称有可能相同,所以不能直接按照 `workshop` 做标签聚合。必须要先按照城市,再按照车间处理。 + +SQL 语句如下 + +```SQL +SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop); +``` + +查询结果如下 + +``` ++--------+--------+------------------+ +| city|workshop| avg(temperature)| ++--------+--------+------------------+ +| NULL| NULL| 50.84999910990397| +|Shanghai| w1|113.01666768391927| +| Beijing| w2| 104.4000004359654| +|Shanghai| w2|100.10000038146973| +| Beijing| w1|103.73750019073486| ++--------+--------+------------------+ +Total line number = 5 +It costs 0.027s +``` + +从结果集中可以看到,和单标签聚合相比,多标签聚合的查询结果会根据指定的标签顺序,输出相应标签的键值列。 + +##### 基于时间区间的标签聚合查询 + +按照时间区间聚合是时序数据库中最常用的查询需求之一。IoTDB 在基于时间区间的聚合基础上,支持进一步按照标签进行聚合查询。 + +例如,用户想统计时间 `[1000, 10000)` 范围内,每个城市每个车间中的设备每 5 秒内的平均温度。 + +SQL 语句如下 + +```SQL +SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop); +``` + +查询结果如下 + +``` ++-----------------------------+--------+--------+------------------+ +| Time| city|workshop| avg(temperature)| ++-----------------------------+--------+--------+------------------+ +|1970-01-01T08:00:01.000+08:00| NULL| NULL| 50.91999893188476| +|1970-01-01T08:00:01.000+08:00|Shanghai| w1|113.20000076293945| +|1970-01-01T08:00:01.000+08:00| Beijing| w2| 103.4| +|1970-01-01T08:00:01.000+08:00|Shanghai| w2| 100.1999994913737| +|1970-01-01T08:00:01.000+08:00| Beijing| w1|103.81666692097981| +|1970-01-01T08:00:06.000+08:00| NULL| NULL| 50.5| +|1970-01-01T08:00:06.000+08:00|Shanghai| w1| 112.6500015258789| +|1970-01-01T08:00:06.000+08:00| Beijing| w2| 106.9000015258789| +|1970-01-01T08:00:06.000+08:00|Shanghai| w2| 99.80000305175781| +|1970-01-01T08:00:06.000+08:00| Beijing| w1| 103.5| ++-----------------------------+--------+--------+------------------+ +``` + +和标签聚合相比,基于时间区间的标签聚合的查询会首先按照时间区间划定聚合范围,在时间区间内部再根据指定的标签顺序,进行相应数据的聚合计算。在输出的结果集中,会包含一列时间列,该时间列值的含义和时间区间聚合查询的相同。 + +##### 标签分组聚合的限制 + +由于标签聚合功能仍然处于开发阶段,目前有如下未实现功能。 + +> 1. 暂不支持 `HAVING` 子句过滤查询结果。 +> 2. 暂不支持结果按照标签值排序。 +> 3. 暂不支持 `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`。 +> 4. 暂不支持 `ALIGN BY DEVICE`。 +> 5. 暂不支持聚合函数内部包含表达式,例如 `count(s+1)`。 +> 6. 不支持值过滤条件聚合,和分层聚合查询行为保持一致。 + +## 5. 聚合结果过滤(HAVING 子句) + +如果想对聚合查询的结果进行过滤,可以在 `GROUP BY` 子句之后使用 `HAVING` 子句。 + +**注意:** + +1. `HAVING`子句中的过滤条件必须由聚合值构成,原始序列不能单独出现。 + + 下列使用方式是不正确的: + ```sql + select count(s1) from root.** group by ([1,3),1ms) having sum(s1) > s1 + select count(s1) from root.** group by ([1,3),1ms) having s1 > 1 + ``` + +2. 对`GROUP BY LEVEL`结果进行过滤时,`SELECT`和`HAVING`中出现的PATH只能有一级。 + + 下列使用方式是不正确的: + ```sql + select count(s1) from root.** group by ([1,3),1ms), level=1 having sum(d1.s1) > 1 + select count(d1.s1) from root.** group by ([1,3),1ms), level=1 having sum(s1) > 1 + ``` + +**SQL 示例:** + +- **示例 1:** + + 对于以下聚合结果进行过滤: + + ``` + +-----------------------------+---------------------+---------------------+ + | Time|count(root.test.*.s1)|count(root.test.*.s2)| + +-----------------------------+---------------------+---------------------+ + |1970-01-01T08:00:00.001+08:00| 4| 4| + |1970-01-01T08:00:00.003+08:00| 1| 0| + |1970-01-01T08:00:00.005+08:00| 2| 4| + |1970-01-01T08:00:00.007+08:00| 3| 2| + |1970-01-01T08:00:00.009+08:00| 4| 4| + +-----------------------------+---------------------+---------------------+ + ``` + + ```sql + select count(s1) from root.** group by ([1,11),2ms), level=1 having count(s2) > 2; + ``` + + 执行结果如下: + + ``` + +-----------------------------+---------------------+ + | Time|count(root.test.*.s1)| + +-----------------------------+---------------------+ + |1970-01-01T08:00:00.001+08:00| 4| + |1970-01-01T08:00:00.005+08:00| 2| + |1970-01-01T08:00:00.009+08:00| 4| + +-----------------------------+---------------------+ + ``` + +- **示例 2:** + + 对于以下聚合结果进行过滤: + ``` + +-----------------------------+-------------+---------+---------+ + | Time| Device|count(s1)|count(s2)| + +-----------------------------+-------------+---------+---------+ + |1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.003+08:00|root.test.sg1| 1| 0| + |1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.007+08:00|root.test.sg1| 2| 1| + |1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| + |1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| + |1970-01-01T08:00:00.003+08:00|root.test.sg2| 0| 0| + |1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| + |1970-01-01T08:00:00.007+08:00|root.test.sg2| 1| 1| + |1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| + +-----------------------------+-------------+---------+---------+ + ``` + + ```sql + select count(s1), count(s2) from root.** group by ([1,11),2ms) having count(s2) > 1 align by device; + ``` + + 执行结果如下: + + ``` + +-----------------------------+-------------+---------+---------+ + | Time| Device|count(s1)|count(s2)| + +-----------------------------+-------------+---------+---------+ + |1970-01-01T08:00:00.001+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.005+08:00|root.test.sg1| 1| 2| + |1970-01-01T08:00:00.009+08:00|root.test.sg1| 2| 2| + |1970-01-01T08:00:00.001+08:00|root.test.sg2| 2| 2| + |1970-01-01T08:00:00.005+08:00|root.test.sg2| 1| 2| + |1970-01-01T08:00:00.009+08:00|root.test.sg2| 2| 2| + +-----------------------------+-------------+---------+---------+ + ``` + + +## 6. 结果集补空值(FILL 子句) + +### 6.1 功能介绍 + +当执行一些数据查询时,结果集的某行某列可能没有数据,则此位置结果为空,但这种空值不利于进行数据可视化展示和分析,需要对空值进行填充。 + +在 IoTDB 中,用户可以使用 `FILL` 子句指定数据缺失情况下的填充模式,允许用户按照特定的方法对任何查询的结果集填充空值,如取前一个不为空的值、线性插值等。 + +### 6.2 语法定义 + +**`FILL` 子句的语法定义如下:** + +```sql +FILL '(' PREVIOUS | LINEAR | constant ')' +``` + +**注意:** +- 在 `Fill` 语句中只能指定一种填充方法,该方法作用于结果集的全部列。 +- 空值填充不兼容 0.13 版本及以前的语法(即不支持 `FILL(([(, , )?])+)`) + +### 6.3 填充方式 + +**IoTDB 目前支持以下三种空值填充方式:** + +- `PREVIOUS` 填充:使用该列前一个非空值进行填充。 +- `LINEAR` 填充:使用该列前一个非空值和下一个非空值的线性插值进行填充。 +- 常量填充:使用指定常量填充。 + +**各数据类型支持的填充方法如下表所示:** + +| 数据类型 | 支持的填充方法 | +| :------- |:------------------------| +| BOOLEAN | `PREVIOUS`、常量 | +| INT32 | `PREVIOUS`、`LINEAR`、常量 | +| INT64 | `PREVIOUS`、`LINEAR`、常量 | +| FLOAT | `PREVIOUS`、`LINEAR`、常量 | +| DOUBLE | `PREVIOUS`、`LINEAR`、常量 | +| TEXT | `PREVIOUS`、常量 | + +**注意:** 对于数据类型不支持指定填充方法的列,既不会填充它,也不会报错,只是让那一列保持原样。 + +**下面通过举例进一步说明。** + +如果我们不使用任何填充方式: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000; +``` + +查询结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### `PREVIOUS` 填充 + +**对于查询结果集中的空值,使用该列前一个非空值进行填充。** + +**注意:** 如果结果集的某一列第一个值就为空,则不会填充该值,直到遇到该列第一个非空值为止。 + +例如,使用 `PREVIOUS` 填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(previous); +``` + +`PREVIOUS` 填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 21.93| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| false| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +**在前值填充时,能够支持指定一个时间间隔,如果当前null值的时间戳与前一个非null值的时间戳的间隔,超过指定的时间间隔,则不进行填充。** + +> 1. 在线性填充和常量填充的情况下,如果指定了第二个参数,会抛出异常 +> 2. 时间超时参数仅支持整数 + 例如,原始数据如下所示: + +```sql +select s1 from root.db.d1 +``` +``` ++-----------------------------+-------------+ +| Time|root.db.d1.s1| ++-----------------------------+-------------+ +|2023-11-08T16:41:50.008+08:00| 1.0| ++-----------------------------+-------------+ +|2023-11-08T16:46:50.011+08:00| 2.0| ++-----------------------------+-------------+ +|2023-11-08T16:48:50.011+08:00| 3.0| ++-----------------------------+-------------+ +``` + +根据时间分组,每1分钟求一个平均值 + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| null| ++-----------------------------+------------------+ +``` + +根据时间分组并用前值填充 + +```sql +select avg(s1) + from root.db.d1 + group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + +根据时间分组并用前值填充,并指定超过2分钟的就不填充 + +```sql +select avg(s1) +from root.db.d1 +group by([2023-11-08T16:40:00.008+08:00, 2023-11-08T16:50:00.008+08:00), 1m) + FILL(PREVIOUS, 2m); +``` +``` ++-----------------------------+------------------+ +| Time|avg(root.db.d1.s1)| ++-----------------------------+------------------+ +|2023-11-08T16:40:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:41:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:42:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:43:00.008+08:00| 1.0| ++-----------------------------+------------------+ +|2023-11-08T16:44:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:45:00.008+08:00| null| ++-----------------------------+------------------+ +|2023-11-08T16:46:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:47:00.008+08:00| 2.0| ++-----------------------------+------------------+ +|2023-11-08T16:48:00.008+08:00| 3.0| ++-----------------------------+------------------+ +|2023-11-08T16:49:00.008+08:00| 3.0| ++-----------------------------+------------------+ +``` + + +#### `LINEAR` 填充 + +**对于查询结果集中的空值,使用该列前一个非空值和下一个非空值的线性插值进行填充。** + +**注意:** +- 如果某个值之前的所有值都为空,或者某个值之后的所有值都为空,则不会填充该值。 +- 如果某列的数据类型为boolean/text,我们既不会填充它,也不会报错,只是让那一列保持原样。 + +例如,使用 `LINEAR` 填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(linear); +``` + +`LINEAR` 填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 22.08| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +#### 常量填充 + +**对于查询结果集中的空值,使用指定常量填充。** + +**注意:** +- 如果某列数据类型与常量类型不兼容,既不填充该列,也不报错,将该列保持原样。对于常量兼容的数据类型,如下表所示: + + | 常量类型 | 能够填充的序列数据类型 | + |:------ |:------------------ | + | `BOOLEAN` | `BOOLEAN` `TEXT` | + | `INT64` | `INT32` `INT64` `FLOAT` `DOUBLE` `TEXT` | + | `DOUBLE` | `FLOAT` `DOUBLE` `TEXT` | + | `TEXT` | `TEXT` | +- 当常量值大于 `INT32` 所能表示的最大值时,对于 `INT32` 类型的列,既不填充该列,也不报错,将该列保持原样。 + +例如,使用 `FLOAT` 类型的常量填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(2.0); +``` + +`FLOAT` 类型的常量填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| 2.0| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| null| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| null| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + +再比如,使用 `BOOLEAN` 类型的常量填充,SQL 语句如下: + +```sql +select temperature, status from root.sgcc.wf03.wt01 where time >= 2017-11-01T16:37:00.000 and time <= 2017-11-01T16:40:00.000 fill(true); +``` + +`BOOLEAN` 类型的常量填充后的结果如下: + +``` ++-----------------------------+-------------------------------+--------------------------+ +| Time|root.sgcc.wf03.wt01.temperature|root.sgcc.wf03.wt01.status| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:37:00.000+08:00| 21.93| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:38:00.000+08:00| null| false| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:39:00.000+08:00| 22.23| true| ++-----------------------------+-------------------------------+--------------------------+ +|2017-11-01T16:40:00.000+08:00| 23.43| true| ++-----------------------------+-------------------------------+--------------------------+ +Total line number = 4 +``` + + +## 7. 查询结果分页(LIMIT/SLIMIT 子句) + +当查询结果集数据量很大,放在一个页面不利于显示,可以使用 `LIMIT/SLIMIT` 子句和 `OFFSET/SOFFSET `子句进行分页控制。 + +- `LIMIT` 和 `SLIMIT` 子句用于控制查询结果的行数和列数。 +- `OFFSET` 和 `SOFFSET` 子句用于控制结果显示的起始位置。 + +### 7.1 按行分页 + +用户可以通过 `LIMIT` 和 `OFFSET` 子句控制查询结果的行数,`LIMIT rowLimit` 指定查询结果的行数,`OFFSET rowOffset` 指定查询结果显示的起始行位置。 + +注意: +- 当 `rowOffset` 超过结果集的大小时,返回空结果集。 +- 当 `rowLimit` 超过结果集的大小时,返回所有查询结果。 +- 当 `rowLimit` 和 `rowOffset` 不是正整数,或超过 `INT64` 允许的最大值时,系统将提示错误。 + +我们将通过以下示例演示如何使用 `LIMIT` 和 `OFFSET` 子句。 + +- **示例 1:** 基本的 `LIMIT` 子句 + +SQL 语句: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 10 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的前 10 行。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:00:00.000+08:00| true| 25.96| +|2017-11-01T00:01:00.000+08:00| true| 24.36| +|2017-11-01T00:02:00.000+08:00| false| 20.09| +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| +|2017-11-01T00:08:00.000+08:00| false| 22.58| +|2017-11-01T00:09:00.000+08:00| false| 20.98| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 10 +It costs 0.000s +``` + +- **示例 2:** 带 `OFFSET` 的 `LIMIT` 子句 + +SQL 语句: + +```sql +select status, temperature from root.ln.wf01.wt01 limit 5 offset 3 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的第 3 至 7 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2017-11-01T00:03:00.000+08:00| false| 20.18| +|2017-11-01T00:04:00.000+08:00| false| 21.13| +|2017-11-01T00:05:00.000+08:00| false| 22.72| +|2017-11-01T00:06:00.000+08:00| false| 20.71| +|2017-11-01T00:07:00.000+08:00| false| 21.45| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.342s +``` + +- **示例 3:** `LIMIT` 子句与 `WHERE` 子句结合 + +SQL 语句: + +```sql +select status,temperature from root.ln.wf01.wt01 where time > 2024-07-07T00:05:00.000 and time< 2024-07-12T00:12:00.000 limit 5 offset 3 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回时间“ 2024-07-07T00:05:00.000”和“ 2024-07-12T00:12:00.000”之间的状态和温度传感器值的第 3 至 7 行(第一行编号为第 0 行)。 + +结果如下所示: + +``` ++-----------------------------+------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| ++-----------------------------+------------------------+-----------------------------+ +|2024-07-09T17:32:11.943+08:00| true| 24.941973| +|2024-07-09T17:32:12.944+08:00| true| 20.05108| +|2024-07-09T17:32:13.945+08:00| true| 20.541632| +|2024-07-09T17:32:14.945+08:00| null| 23.09016| +|2024-07-09T17:32:14.946+08:00| true| null| ++-----------------------------+------------------------+-----------------------------+ +Total line number = 5 +It costs 0.070s +`` + +- **示例 4:** `LIMIT` 子句与 `GROUP BY` 子句组合 + +SQL 语句: + +```sql +select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 4 offset 3 +``` + +含义: + +SQL 语句子句要求返回查询结果的第 3 至 6 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+-------------------------------+----------------------------------------+ +| Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| ++-----------------------------+-------------------------------+----------------------------------------+ +|2017-11-04T00:00:00.000+08:00| 1440| 26.0| +|2017-11-05T00:00:00.000+08:00| 1440| 26.0| +|2017-11-06T00:00:00.000+08:00| 1440| 25.99| +|2017-11-07T00:00:00.000+08:00| 1380| 26.0| ++-----------------------------+-------------------------------+----------------------------------------+ +Total line number = 4 +It costs 0.016s +``` + +### 7.2 按列分页 + +用户可以通过 `SLIMIT` 和 `SOFFSET` 子句控制查询结果的列数,`SLIMIT seriesLimit` 指定查询结果的列数,`SOFFSET seriesOffset` 指定查询结果显示的起始列位置。 + +注意: +- 仅用于控制值列,对时间列和设备列无效。 +- 当 `seriesOffset` 超过结果集的大小时,返回空结果集。 +- 当 `seriesLimit` 超过结果集的大小时,返回所有查询结果。 +- 当 `seriesLimit` 和 `seriesOffset` 不是正整数,或超过 `INT64` 允许的最大值时,系统将提示错误。 + +我们将通过以下示例演示如何使用 `SLIMIT` 和 `SOFFSET` 子句。 + +- **示例 1:** 基本的 `SLIMIT` 子句 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第二列,即温度。 SQL 语句要求在"2017-11-01T00:05:00.000"和"2017-11-01T00:12:00.000"的时间点之间选择温度传感器值。 + +结果如下所示: + +``` ++-----------------------------+-----------------------------+ +| Time|root.ln.wf01.wt01.temperature| ++-----------------------------+-----------------------------+ +|2017-11-01T00:06:00.000+08:00| 20.71| +|2017-11-01T00:07:00.000+08:00| 21.45| +|2017-11-01T00:08:00.000+08:00| 22.58| +|2017-11-01T00:09:00.000+08:00| 20.98| +|2017-11-01T00:10:00.000+08:00| 25.52| +|2017-11-01T00:11:00.000+08:00| 22.91| ++-----------------------------+-----------------------------+ +Total line number = 6 +It costs 0.000s +``` + +- **示例 2:** 带 `SOFFSET` 的 `SLIMIT` 子句 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第一列,即电源状态。 SQL 语句要求在" 2017-11-01T00:05:00.000"和"2017-11-01T00:12:00.000"的时间点之间选择状态传感器值。 + +结果如下所示: + +``` ++-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.status| ++-----------------------------+------------------------+ +|2017-11-01T00:06:00.000+08:00| false| +|2017-11-01T00:07:00.000+08:00| false| +|2017-11-01T00:08:00.000+08:00| false| +|2017-11-01T00:09:00.000+08:00| false| +|2017-11-01T00:10:00.000+08:00| true| +|2017-11-01T00:11:00.000+08:00| false| ++-----------------------------+------------------------+ +Total line number = 6 +It costs 0.003s +``` + +- **示例 3:** `SLIMIT` 子句与 `GROUP BY` 子句结合 + +SQL 语句: + +```sql +select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1 +``` + +含义: + +``` ++-----------------------------+-----------------------------------+ +| Time|max_value(root.ln.wf01.wt01.status)| ++-----------------------------+-----------------------------------+ +|2017-11-01T00:00:00.000+08:00| true| +|2017-11-02T00:00:00.000+08:00| true| +|2017-11-03T00:00:00.000+08:00| true| +|2017-11-04T00:00:00.000+08:00| true| +|2017-11-05T00:00:00.000+08:00| true| +|2017-11-06T00:00:00.000+08:00| true| +|2017-11-07T00:00:00.000+08:00| true| ++-----------------------------+-----------------------------------+ +Total line number = 7 +It costs 0.000s +``` + +- **示例 4:** `SLIMIT` 子句与 `LIMIT` 子句结合 + +SQL 语句: + +```sql +select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0 +``` + +含义: + +所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是此设备下的第 0 列至第 1 列(第一列编号为第 0 列)。 SQL 语句子句要求返回查询结果的第 100 至 109 行(第一行编号为 0 行)。 + +结果如下所示: + +``` ++-----------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+-----------------------------+------------------------+ +|2017-11-01T01:40:00.000+08:00| 21.19| false| +|2017-11-01T01:41:00.000+08:00| 22.79| false| +|2017-11-01T01:42:00.000+08:00| 22.98| false| +|2017-11-01T01:43:00.000+08:00| 21.52| false| +|2017-11-01T01:44:00.000+08:00| 23.45| true| +|2017-11-01T01:45:00.000+08:00| 24.06| true| +|2017-11-01T01:46:00.000+08:00| 22.6| false| +|2017-11-01T01:47:00.000+08:00| 23.78| true| +|2017-11-01T01:48:00.000+08:00| 24.72| true| +|2017-11-01T01:49:00.000+08:00| 24.68| true| ++-----------------------------+-----------------------------+------------------------+ +Total line number = 10 +It costs 0.009s +``` + +## 8. 结果集排序(ORDER BY 子句) + +### 8.1 时间对齐模式下的排序 +IoTDB的查询结果集默认按照时间对齐,可以使用`ORDER BY TIME`的子句指定时间戳的排列顺序。示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time desc; +``` +执行结果: + +``` ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +|2017-11-01T00:01:00.000+08:00| v2| true| 24.36| true| +|2017-11-01T00:00:00.000+08:00| v2| true| 25.96| true| +|1970-01-01T08:00:00.002+08:00| v2| false| null| null| +|1970-01-01T08:00:00.001+08:00| v1| true| null| null| ++-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ +``` +### 8.2 设备对齐模式下的排序 +当使用`ALIGN BY DEVICE`查询对齐模式下的结果集时,可以使用`ORDER BY`子句对返回的结果集顺序进行规定。 + +在设备对齐模式下支持4种排序模式的子句,其中包括两种排序键,`DEVICE`和`TIME`,靠前的排序键为主排序键,每种排序键都支持`ASC`和`DESC`两种排列顺序。 +1. ``ORDER BY DEVICE``: 按照设备名的字典序进行排序,排序方式为字典序排序,在这种情况下,相同名的设备会以组的形式进行展示。 + +2. ``ORDER BY TIME``: 按照时间戳进行排序,此时不同的设备对应的数据点会按照时间戳的优先级被打乱排序。 + +3. ``ORDER BY DEVICE,TIME``: 按照设备名的字典序进行排序,设备名相同的数据点会通过时间戳进行排序。 + +4. ``ORDER BY TIME,DEVICE``: 按照时间戳进行排序,时间戳相同的数据点会通过设备名的字典序进行排序。 + +> 为了保证结果的可观性,当不使用`ORDER BY`子句,仅使用`ALIGN BY DEVICE`时,会为设备视图提供默认的排序方式。其中默认的排序视图为``ORDER BY DEVCE,TIME``,默认的排序顺序为`ASC`, +> 即结果集默认先按照设备名升序排列,在相同设备名内再按照时间戳升序排序。 + + +当主排序键为`DEVICE`时,结果集的格式与默认情况类似:先按照设备名对结果进行排列,在相同的设备名下内按照时间戳进行排序。示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by device desc,time asc align by device; +``` +执行结果: + +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` +主排序键为`Time`时,结果集会先按照时间戳进行排序,在时间戳相等时按照设备名排序。 +示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 order by time asc,device desc align by device; +``` +执行结果: +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| ++-----------------------------+-----------------+--------+------+-----------+ +``` +当没有显式指定时,主排序键默认为`Device`,排序顺序默认为`ASC`,示例代码如下: +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` +结果如图所示,可以看出,`ORDER BY DEVICE ASC,TIME ASC`就是默认情况下的排序方式,由于`ASC`是默认排序顺序,此处可以省略。 +``` ++-----------------------------+-----------------+--------+------+-----------+ +| Time| Device|hardware|status|temperature| ++-----------------------------+-----------------+--------+------+-----------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| null| true| 25.96| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| true| 24.36| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| v1| true| null| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| v2| false| null| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| v2| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| v2| true| null| ++-----------------------------+-----------------+--------+------+-----------+ +``` +同样,可以在聚合查询中使用`ALIGN BY DEVICE`和`ORDER BY`子句,对聚合后的结果进行排序,示例代码如下所示: +```sql +select count(*) from root.ln.** group by ((2017-11-01T00:00:00.000+08:00,2017-11-01T00:03:00.000+08:00],1m) order by device asc,time asc align by device +``` +执行结果: +``` ++-----------------------------+-----------------+---------------+-------------+------------------+ +| Time| Device|count(hardware)|count(status)|count(temperature)| ++-----------------------------+-----------------+---------------+-------------+------------------+ +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| null| 1| 1| +|2017-11-01T00:02:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:03:00.000+08:00|root.ln.wf01.wt01| null| 0| 0| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| 1| 1| null| +|2017-11-01T00:02:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| +|2017-11-01T00:03:00.000+08:00|root.ln.wf02.wt02| 0| 0| null| ++-----------------------------+-----------------+---------------+-------------+------------------+ +``` + +### 8.3 任意表达式排序 +除了IoTDB中规定的Time,Device关键字外,还可以通过`ORDER BY`子句对指定时间序列中任意列的表达式进行排序。 + +排序在通过`ASC`,`DESC`指定排序顺序的同时,可以通过`NULLS`语法来指定NULL值在排序中的优先级,`NULLS FIRST`默认NULL值在结果集的最上方,`NULLS LAST`则保证NULL值在结果集的最后。如果没有在子句中指定,则默认顺序为`ASC`,`NULLS LAST`。 + +对于如下的数据,将给出几个任意表达式的查询示例供参考: +``` ++-----------------------------+-------------+-------+-------+--------+-------+ +| Time| Device| base| score| bonus| total| ++-----------------------------+-------------+-------+-------+--------+-------+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0| 107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0| 105.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0| 103.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00| root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.020+08:00| root.three| 8| null| 22.5| 30.5| +|1970-01-01T08:00:00.030+08:00| root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0| 104.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0| 102.0| ++-----------------------------+-------------+-------+-------+--------+-------+ +``` + +当需要根据基础分数score对结果进行排序时,可以直接使用 +```Sql +select score from root.** order by score desc align by device +``` +会得到如下结果 + +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +当想要根据总分对结果进行排序,可以在order by子句中使用表达式进行计算 +```Sql +select score,total from root.one order by base+score+bonus desc +``` +该sql等价于 +```Sql +select score,total from root.one order by total desc +``` +得到如下结果 + +``` ++-----------------------------+--------------+--------------+ +| Time|root.one.score|root.one.total| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.000+08:00| 50.0| 107.0| +|1970-01-02T08:00:00.000+08:00| 50.0| 105.0| +|1970-01-03T08:00:00.000+08:00| 50.0| 103.0| ++-----------------------------+--------------+--------------+ +``` +而如果要对总分进行排序,且分数相同时依次根据score, base, bonus和提交时间进行排序时,可以通过多个表达式来指定多层排序 + +```Sql +select base, score, bonus, total from root.** order by total desc NULLS Last, + score desc NULLS Last, + bonus desc NULLS Last, + time desc align by device +``` +得到如下结果 +``` ++-----------------------------+----------+----+-----+-----+-----+ +| Time| Device|base|score|bonus|total| ++-----------------------------+----------+----+-----+-----+-----+ +|1970-01-01T08:00:00.000+08:00| root.one| 12| 50.0| 45.0|107.0| +|1970-01-02T08:00:00.000+08:00| root.one| 10| 50.0| 45.0|105.0| +|1970-01-01T08:00:00.030+08:00| root.five| 7| 53.0| 44.0|104.0| +|1970-01-03T08:00:00.000+08:00| root.one| 8| 50.0| 45.0|103.0| +|1970-01-01T08:00:00.040+08:00| root.five| 6| 54.0| 42.0|102.0| +|1970-01-01T08:00:00.010+08:00| root.four| 9| 32.0| 45.0| 86.0| +|1970-01-01T08:00:00.020+08:00| root.four| 8| 32.0| 45.0| 85.0| +|1970-01-01T08:00:00.010+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.000+08:00| root.two| 9| 50.0| 15.0| 74.0| +|1970-01-01T08:00:00.020+08:00| root.two| 8| 10.0| 15.0| 33.0| +|1970-01-01T08:00:00.010+08:00|root.three| 9| null| 24.0| 33.0| +|1970-01-01T08:00:00.030+08:00|root.three| 7| null| 23.5| 30.5| +|1970-01-01T08:00:00.020+08:00|root.three| 8| null| 22.5| 30.5| ++-----------------------------+----------+----+-----+-----+-----+ +``` +在order by中同样可以使用聚合查询表达式 +```Sql +select min_value(total) from root.** order by min_value(total) asc align by device +``` +得到如下结果 +``` ++----------+----------------+ +| Device|min_value(total)| ++----------+----------------+ +|root.three| 30.5| +| root.two| 33.0| +| root.four| 85.0| +| root.five| 102.0| +| root.one| 103.0| ++----------+----------------+ +``` +当在查询中指定多列,未被排序的列会随着行和排序列一起改变顺序,当排序列相同时行的顺序和具体实现有关(没有固定顺序) +```Sql +select min_value(total),max_value(base) from root.** order by max_value(total) desc align by device +``` +得到结果如下 +· +``` ++----------+----------------+---------------+ +| Device|min_value(total)|max_value(base)| ++----------+----------------+---------------+ +| root.one| 103.0| 12| +| root.five| 102.0| 7| +| root.four| 85.0| 9| +| root.two| 33.0| 9| +|root.three| 30.5| 9| ++----------+----------------+---------------+ +``` + +Order by device, time可以和order by expression共同使用 +```Sql +select score from root.** order by device asc, score desc, time asc align by device +``` +会得到如下结果 +``` ++-----------------------------+---------+-----+ +| Time| Device|score| ++-----------------------------+---------+-----+ +|1970-01-01T08:00:00.040+08:00|root.five| 54.0| +|1970-01-01T08:00:00.030+08:00|root.five| 53.0| +|1970-01-01T08:00:00.010+08:00|root.four| 32.0| +|1970-01-01T08:00:00.020+08:00|root.four| 32.0| +|1970-01-01T08:00:00.000+08:00| root.one| 50.0| +|1970-01-02T08:00:00.000+08:00| root.one| 50.0| +|1970-01-03T08:00:00.000+08:00| root.one| 50.0| +|1970-01-01T08:00:00.000+08:00| root.two| 50.0| +|1970-01-01T08:00:00.010+08:00| root.two| 50.0| +|1970-01-01T08:00:00.020+08:00| root.two| 10.0| ++-----------------------------+---------+-----+ +``` + +## 9. 查询对齐模式(ALIGN BY DEVICE 子句) + +在 IoTDB 中,查询结果集**默认按照时间对齐**,包含一列时间列和若干个值列,每一行数据各列的时间戳相同。 + +除按照时间对齐外,还支持以下对齐模式: + +- 按设备对齐 `ALIGN BY DEVICE` + +### 9.1 按设备对齐 + +在按设备对齐模式下,设备名会单独作为一列出现,查询结果集包含一列时间列、一列设备列和若干个值列。如果 `SELECT` 子句中选择了 `N` 列,则结果集包含 `N + 2` 列(时间列和设备名字列)。 + +在默认情况下,结果集按照 `Device` 进行排列,在每个 `Device` 内按照 `Time` 列升序排序。 + +当查询多个设备时,要求设备之间同名的列数据类型相同。 + +为便于理解,可以按照关系模型进行对应。设备可以视为关系模型中的表,选择的列可以视为表中的列,`Time + Device` 看做其主键。 + +**示例:** + +```sql +select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device; +``` + +执行如下: + +``` ++-----------------------------+-----------------+-----------+------+--------+ +| Time| Device|temperature|status|hardware| ++-----------------------------+-----------------+-----------+------+--------+ +|2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| 25.96| true| null| +|2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| 24.36| true| null| +|1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| null| true| v1| +|1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| null| false| v2| +|2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| null| true| v2| +|2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| null| true| v2| ++-----------------------------+-----------------+-----------+------+--------+ +Total line number = 6 +It costs 0.012s +``` +### 9.2 设备对齐模式下的排序 +在设备对齐模式下,默认按照设备名的字典序升序排列,每个设备内部按照时间戳大小升序排列,可以通过 `ORDER BY` 子句调整设备列和时间列的排序优先级。 + +详细说明及示例见文档 [结果集排序](../SQL-Manual/Operator-and-Expression.md)。 + +## 10. 查询写回(INTO 子句) + +`SELECT INTO` 语句用于将查询结果写入一系列指定的时间序列中。 + +应用场景如下: +- **实现 IoTDB 内部 ETL**:对原始数据进行 ETL 处理后写入新序列。 +- **查询结果存储**:将查询结果进行持久化存储,起到类似物化视图的作用。 +- **非对齐序列转对齐序列**:对齐序列从0.13版本开始支持,可以通过该功能将非对齐序列的数据写入新的对齐序列中。 + +### 10.1 语法定义 + +#### 整体描述 + +```sql +selectIntoStatement + : SELECT + resultColumn [, resultColumn] ... + INTO intoItem [, intoItem] ... + FROM prefixPath [, prefixPath] ... + [WHERE whereCondition] + [GROUP BY groupByTimeClause, groupByLevelClause] + [FILL {PREVIOUS | LINEAR | constant}] + [LIMIT rowLimit OFFSET rowOffset] + [ALIGN BY DEVICE] + ; + +intoItem + : [ALIGNED] intoDevicePath '(' intoMeasurementName [',' intoMeasurementName]* ')' + ; +``` + +#### `INTO` 子句 + +`INTO` 子句由若干个 `intoItem` 构成。 + +每个 `intoItem` 由一个目标设备路径和一个包含若干目标物理量名的列表组成(与 `INSERT` 语句中的 `INTO` 子句写法类似)。 + +其中每个目标物理量名与目标设备路径组成一个目标序列,一个 `intoItem` 包含若干目标序列。例如:`root.sg_copy.d1(s1, s2)` 指定了两条目标序列 `root.sg_copy.d1.s1` 和 `root.sg_copy.d1.s2`。 + +`INTO` 子句指定的目标序列要能够与查询结果集的列一一对应。具体规则如下: + +- **按时间对齐**(默认):全部 `intoItem` 包含的目标序列数量要与查询结果集的列数(除时间列外)一致,且按照表头从左到右的顺序一一对应。 +- **按设备对齐**(使用 `ALIGN BY DEVICE`):全部 `intoItem` 中指定的目标设备数和查询的设备数(即 `FROM` 子句中路径模式匹配的设备数)一致,且按照结果集设备的输出顺序一一对应。 + 为每个目标设备指定的目标物理量数量要与查询结果集的列数(除时间和设备列外)一致,且按照表头从左到右的顺序一一对应。 + +下面通过示例进一步说明: + +- **示例 1**(按时间对齐) +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1), root.sg_copy.d2(t1, t2), root.sg_copy.d1(t2) from root.sg.d1, root.sg.d2; ++--------------+-------------------+--------+ +| source column| target timeseries| written| ++--------------+-------------------+--------+ +| root.sg.d1.s1| root.sg_copy.d1.t1| 8000| ++--------------+-------------------+--------+ +| root.sg.d2.s1| root.sg_copy.d2.t1| 10000| ++--------------+-------------------+--------+ +| root.sg.d1.s2| root.sg_copy.d2.t2| 12000| ++--------------+-------------------+--------+ +| root.sg.d2.s2| root.sg_copy.d1.t2| 10000| ++--------------+-------------------+--------+ +Total line number = 4 +It costs 0.725s +``` + +该语句将 `root.sg` database 下四条序列的查询结果写入到 `root.sg_copy` database 下指定的四条序列中。注意,`root.sg_copy.d2(t1, t2)` 也可以写做 `root.sg_copy.d2(t1), root.sg_copy.d2(t2)`。 + +可以看到,`INTO` 子句的写法非常灵活,只要满足组合出的目标序列没有重复,且与查询结果列一一对应即可。 + +> `CLI` 展示的结果集中,各列的含义如下: +> - `source column` 列表示查询结果的列名。 +> - `target timeseries` 表示对应列写入的目标序列。 +> - `written` 表示预期写入的数据量。 + +- **示例 2**(按时间对齐) +```shell +IoTDB> select count(s1 + s2), last_value(s2) into root.agg.count(s1_add_s2), root.agg.last_value(s2) from root.sg.d1 group by ([0, 100), 10ms); ++--------------------------------------+-------------------------+--------+ +| source column| target timeseries| written| ++--------------------------------------+-------------------------+--------+ +| count(root.sg.d1.s1 + root.sg.d1.s2)| root.agg.count.s1_add_s2| 10| ++--------------------------------------+-------------------------+--------+ +| last_value(root.sg.d1.s2)| root.agg.last_value.s2| 10| ++--------------------------------------+-------------------------+--------+ +Total line number = 2 +It costs 0.375s +``` + +该语句将聚合查询的结果存储到指定序列中。 + +- **示例 3**(按设备对齐) +```shell +IoTDB> select s1, s2 into root.sg_copy.d1(t1, t2), root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+-------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s1| root.sg_copy.d1.t1| 8000| ++--------------+--------------+-------------------+--------+ +| root.sg.d1| s2| root.sg_copy.d1.t2| 11000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s1| root.sg_copy.d2.t1| 12000| ++--------------+--------------+-------------------+--------+ +| root.sg.d2| s2| root.sg_copy.d2.t2| 9000| ++--------------+--------------+-------------------+--------+ +Total line number = 4 +It costs 0.625s +``` + +该语句同样是将 `root.sg` database 下四条序列的查询结果写入到 `root.sg_copy` database 下指定的四条序列中。但在按设备对齐中,`intoItem` 的数量必须和查询的设备数量一致,每个查询设备对应一个 `intoItem`。 + +> 按设备对齐查询时,`CLI` 展示的结果集多出一列 `source device` 列表示查询的设备。 + +- **示例 4**(按设备对齐) +```shell +IoTDB> select s1 + s2 into root.expr.add(d1s1_d1s2), root.expr.add(d2s1_d2s2) from root.sg.d1, root.sg.d2 align by device; ++--------------+--------------+------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+--------------+------------------------+--------+ +| root.sg.d1| s1 + s2| root.expr.add.d1s1_d1s2| 10000| ++--------------+--------------+------------------------+--------+ +| root.sg.d2| s1 + s2| root.expr.add.d2s1_d2s2| 10000| ++--------------+--------------+------------------------+--------+ +Total line number = 2 +It costs 0.532s +``` + +该语句将表达式计算的结果存储到指定序列中。 + +#### 使用变量占位符 + +特别地,可以使用变量占位符描述目标序列与查询序列之间的对应规律,简化语句书写。目前支持以下两种变量占位符: + +- 后缀复制符 `::`:复制查询设备后缀(或物理量),表示从该层开始一直到设备的最后一层(或物理量),目标设备的节点名(或物理量名)与查询的设备对应的节点名(或物理量名)相同。 +- 单层节点匹配符 `${i}`:表示目标序列当前层节点名与查询序列的第`i`层节点名相同。比如,对于路径`root.sg1.d1.s1`而言,`${1}`表示`sg1`,`${2}`表示`d1`,`${3}`表示`s1`。 + +在使用变量占位符时,`intoItem`与查询结果集列的对应关系不能存在歧义,具体情况分类讨论如下: + +##### 按时间对齐(默认) + +> 注:变量占位符**只能描述序列与序列之间的对应关系**,如果查询中包含聚合、表达式计算,此时查询结果中的列无法与某个序列对应,因此目标设备和目标物理量都不能使用变量占位符。 + +###### (1)目标设备不使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** + 1. 每个 `intoItem` 中,物理量列表的长度必须为 1。
(如果长度可以大于1,例如 `root.sg1.d1(::, s1)`,无法确定具体哪些列与`::`匹配) + 2. `intoItem` 数量为 1,或与查询结果集列数一致。
(在每个目标物理量列表长度均为 1 的情况下,若 `intoItem` 只有 1 个,此时表示全部查询序列写入相同设备;若 `intoItem` 数量与查询序列一致,则表示为每个查询序列指定一个目标设备;若 `intoItem` 大于 1 小于查询序列数,此时无法与查询序列一一对应) + +**匹配方法:** 每个查询序列指定目标设备,而目标物理量根据变量占位符生成。 + +**示例:** + +```sql +select s1, s2 +into root.sg_copy.d1(::), root.sg_copy.d2(s1), root.sg_copy.d1(${3}), root.sg_copy.d2(::) +from root.sg.d1, root.sg.d2; +``` +该语句等价于: +```sql +select s1, s2 +into root.sg_copy.d1(s1), root.sg_copy.d2(s1), root.sg_copy.d1(s2), root.sg_copy.d2(s2) +from root.sg.d1, root.sg.d2; +``` +可以看到,在这种情况下,语句并不能得到很好地简化。 + +###### (2)目标设备使用变量占位符 & 目标物理量列表不使用变量占位符 + +**限制:** 全部 `intoItem` 中目标物理量的数量与查询结果集列数一致。 + +**匹配方式:** 为每个查询序列指定了目标物理量,目标设备根据对应目标物理量所在 `intoItem` 的目标设备占位符生成。 + +**示例:** +```sql +select d1.s1, d1.s2, d2.s3, d3.s4 +into ::(s1_1, s2_2), root.sg.d2_2(s3_3), root.${2}_copy.::(s4) +from root.sg; +``` + +###### (3)目标设备使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** `intoItem` 只有一个且物理量列表的长度为 1。 + +**匹配方式:** 每个查询序列根据变量占位符可以得到一个目标序列。 + +**示例:** +```sql +select * into root.sg_bk.::(::) from root.sg.**; +``` +将 `root.sg` 下全部序列的查询结果写到 `root.sg_bk`,设备名后缀和物理量名保持不变。 + +##### 按设备对齐(使用 `ALIGN BY DEVICE`) + +> 注:变量占位符**只能描述序列与序列之间的对应关系**,如果查询中包含聚合、表达式计算,此时查询结果中的列无法与某个物理量对应,因此目标物理量不能使用变量占位符。 + +###### (1)目标设备不使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** 每个 `intoItem` 中,如果物理量列表使用了变量占位符,则列表的长度必须为 1。 + +**匹配方法:** 每个查询序列指定目标设备,而目标物理量根据变量占位符生成。 + +**示例:** +```sql +select s1, s2, s3, s4 +into root.backup_sg.d1(s1, s2, s3, s4), root.backup_sg.d2(::), root.sg.d3(backup_${4}) +from root.sg.d1, root.sg.d2, root.sg.d3 +align by device; +``` + +###### (2)目标设备使用变量占位符 & 目标物理量列表不使用变量占位符 + +**限制:** `intoItem` 只有一个。(如果出现多个带占位符的 `intoItem`,我们将无法得知每个 `intoItem` 需要匹配哪几个源设备) + +**匹配方式:** 每个查询设备根据变量占位符得到一个目标设备,每个设备下结果集各列写入的目标物理量由目标物理量列表指定。 + +**示例:** +```sql +select avg(s1), sum(s2) + sum(s3), count(s4) +into root.agg_${2}.::(avg_s1, sum_s2_add_s3, count_s4) +from root.** +align by device; +``` + +###### (3)目标设备使用变量占位符 & 目标物理量列表使用变量占位符 + +**限制:** `intoItem` 只有一个且物理量列表的长度为 1。 + +**匹配方式:** 每个查询序列根据变量占位符可以得到一个目标序列。 + +**示例:** +```sql +select * into ::(backup_${4}) from root.sg.** align by device; +``` +将 `root.sg` 下每条序列的查询结果写到相同设备下,物理量名前加`backup_`。 + +#### 指定目标序列为对齐序列 + +通过 `ALIGNED` 关键词可以指定写入的目标设备为对齐写入,每个 `intoItem` 可以独立设置。 + +**示例:** +```sql +select s1, s2 into root.sg_copy.d1(t1, t2), aligned root.sg_copy.d2(t1, t2) from root.sg.d1, root.sg.d2 align by device; +``` +该语句指定了 `root.sg_copy.d1` 是非对齐设备,`root.sg_copy.d2`是对齐设备。 + +#### 不支持使用的查询子句 + +- `SLIMIT`、`SOFFSET`:查询出来的列不确定,功能不清晰,因此不支持。 +- `LAST`查询、`GROUP BY TAGS`、`DISABLE ALIGN`:表结构和写入结构不一致,因此不支持。 + +#### 其他要注意的点 + +- 对于一般的聚合查询,时间戳是无意义的,约定使用 0 来存储。 +- 当目标序列存在时,需要保证源序列和目标时间序列的数据类型兼容。关于数据类型的兼容性,查看文档 [数据类型](../Background-knowledge/Data-Type.md#数据类型兼容性)。 +- 当目标序列不存在时,系统将自动创建目标序列(包括 database)。 +- 当查询的序列不存在或查询的序列不存在数据,则不会自动创建目标序列。 + +### 10.2 应用举例 + +#### 实现 IoTDB 内部 ETL +对原始数据进行 ETL 处理后写入新序列。 +```shell +IOTDB > SELECT preprocess_udf(s1, s2) INTO ::(preprocessed_s1, preprocessed_s2) FROM root.sg.* ALIGN BY DEIVCE; ++--------------+-------------------+---------------------------+--------+ +| source device| source column| target timeseries| written| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s1)| root.sg.d1.preprocessed_s1| 8000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d1| preprocess_udf(s2)| root.sg.d1.preprocessed_s2| 10000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s1)| root.sg.d2.preprocessed_s1| 11000| ++--------------+-------------------+---------------------------+--------+ +| root.sg.d2| preprocess_udf(s2)| root.sg.d2.preprocessed_s2| 9000| ++--------------+-------------------+---------------------------+--------+ +``` +以上语句使用自定义函数对数据进行预处理,将预处理后的结果持久化存储到新序列中。 + +#### 查询结果存储 +将查询结果进行持久化存储,起到类似物化视图的作用。 +```shell +IOTDB > SELECT count(s1), last_value(s1) INTO root.sg.agg_${2}(count_s1, last_value_s1) FROM root.sg1.d1 GROUP BY ([0, 10000), 10ms); ++--------------------------+-----------------------------+--------+ +| source column| target timeseries| written| ++--------------------------+-----------------------------+--------+ +| count(root.sg.d1.s1)| root.sg.agg_d1.count_s1| 1000| ++--------------------------+-----------------------------+--------+ +| last_value(root.sg.d1.s2)| root.sg.agg_d1.last_value_s2| 1000| ++--------------------------+-----------------------------+--------+ +Total line number = 2 +It costs 0.115s +``` +以上语句将降采样查询的结果持久化存储到新序列中。 + +#### 非对齐序列转对齐序列 +对齐序列从 0.13 版本开始支持,可以通过该功能将非对齐序列的数据写入新的对齐序列中。 + +**注意:** 建议配合使用 `LIMIT & OFFSET` 子句或 `WHERE` 子句(时间过滤条件)对数据进行分批,防止单次操作的数据量过大。 + +```shell +IOTDB > SELECT s1, s2 INTO ALIGNED root.sg1.aligned_d(s1, s2) FROM root.sg1.non_aligned_d WHERE time >= 0 and time < 10000; ++--------------------------+----------------------+--------+ +| source column| target timeseries| written| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s1| root.sg1.aligned_d.s1| 10000| ++--------------------------+----------------------+--------+ +| root.sg1.non_aligned_d.s2| root.sg1.aligned_d.s2| 10000| ++--------------------------+----------------------+--------+ +Total line number = 2 +It costs 0.375s +``` +以上语句将一组非对齐的序列的数据迁移到一组对齐序列。 + +### 10.3 相关用户权限 + +用户必须有下列权限才能正常执行查询写回语句: + +* 所有 `SELECT` 子句中源序列的 `WRITE_SCHEMA` 权限。 +* 所有 `INTO` 子句中目标序列 `WRITE_DATA` 权限。 + +更多用户权限相关的内容,请参考[权限管理语句](../User-Manual/Authority-Management_timecho)。 + +### 10.4 相关配置参数 + +* `select_into_insert_tablet_plan_row_limit` + + | 参数名 | select_into_insert_tablet_plan_row_limit | + | ---- | ---- | + | 描述 | 写入过程中每一批 `Tablet` 的最大行数 | + | 类型 | int32 | + | 默认值 | 10000 | + | 改后生效方式 | 重启后生效 | diff --git a/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data.md b/src/zh/UserGuide/latest/Basic-Concept/Write-Data_apache.md similarity index 94% rename from src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data.md rename to src/zh/UserGuide/latest/Basic-Concept/Write-Data_apache.md index e35ac1bcb..12f6dafd8 100644 --- a/src/zh/UserGuide/Master/Tree/Basic-Concept/Write-Data.md +++ b/src/zh/UserGuide/latest/Basic-Concept/Write-Data_apache.md @@ -23,7 +23,7 @@ # 数据写入 ## 1. CLI写入数据 -IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC.md) 接口)单条或批量执行插入数据的 INSERT 语句。 +IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC_apache) 接口)单条或批量执行插入数据的 INSERT 语句。 本节主要为您介绍实时数据接入的 INSERT 语句在场景中的实际使用示例,有关 INSERT SQL 语句的详细语法请参见本文 [INSERT 语句](../SQL-Manual/SQL-Manual.md#写入数据) 节。 @@ -117,11 +117,11 @@ It costs 0.004s ### 2.1 多语言接口写入 * ### Java - 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API.md)。 - 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API.md#数据写入)写入。 + 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API_apache)。 + 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API_apache#数据写入)写入。 * ### Python - 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API.md#数据写入) + 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API_apache#数据写入) * ### C++ 参考 [ C++ 数据操作接口(DML)](../API/Programming-Cpp-Native-API.md) @@ -131,7 +131,7 @@ It costs 0.004s ## 3. REST API写入 -参考 [insertTablet (v1)](../API/RestServiceV1.md#inserttablet) or [insertTablet (v2)](../API/RestServiceV2.md#inserttablet) +参考 [insertTablet (v1)](../API/RestServiceV1_apache#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_apache#inserttablet) 示例如下: ```JSON @@ -176,11 +176,11 @@ It costs 0.004s ### 5.1 TsFile批量导入 -TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool.md)。 +TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_apache)。 ### 5.2 CSV批量导入 -CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool.md)。 +CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_apache)。 ## 6. 无模式写入 在物联网场景中,由于设备的类型、数量可能随时间动态增减,不同设备可能产生不同字段的数据(如温度、湿度、状态码等),业务上又往往需要快速部署,需要灵活接入新设备且无需繁琐的预定义流程。因此,不同于传统时序数据库通常需要预先定义数据模型,IoTDB支持不提前创建元数据,在写入数据时,数据库中将自动识别并注册所需的元数据,实现自动建模。 diff --git a/src/zh/UserGuide/latest/Basic-Concept/Write-Data_timecho.md b/src/zh/UserGuide/latest/Basic-Concept/Write-Data_timecho.md new file mode 100644 index 000000000..a7f0fb2e7 --- /dev/null +++ b/src/zh/UserGuide/latest/Basic-Concept/Write-Data_timecho.md @@ -0,0 +1,188 @@ + + + +# 数据写入 +## 1. CLI写入数据 + +IoTDB 为用户提供多种插入实时数据的方式,例如在 [Cli/Shell 工具](../Tools-System/CLI.md) 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 [Java JDBC](../API/Programming-JDBC_timecho) 接口)单条或批量执行插入数据的 INSERT 语句。 + +本节主要为您介绍实时数据接入的 INSERT 语句在场景中的实际使用示例,有关 INSERT SQL 语句的详细语法请参见本文 [INSERT 语句](../SQL-Manual/SQL-Manual.md#写入数据) 节。 + +注:写入重复时间戳的数据则原时间戳数据被覆盖,可视为更新数据。 + +### 1.1 使用 INSERT 语句 + +使用 INSERT 语句可以向指定的已经创建的一条或多条时间序列中插入数据。对于每一条数据,均由一个时间戳类型的时间戳和一个数值或布尔值、字符串类型的传感器采集值组成。 + +在本节的场景实例下,以其中的两个时间序列`root.ln.wf02.wt02.status`和`root.ln.wf02.wt02.hardware`为例 ,它们的数据类型分别为 BOOLEAN 和 TEXT。 + +单列数据插入示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) +IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1') +``` + +以上示例代码将长整型的 timestamp 以及值为 true 的数据插入到时间序列`root.ln.wf02.wt02.status`中和将长整型的 timestamp 以及值为”v1”的数据插入到时间序列`root.ln.wf02.wt02.hardware`中。执行成功后会返回执行时间,代表数据插入已完成。 + +> 注意:在 IoTDB 中,TEXT 类型的数据单双引号都可以来表示,上面的插入语句是用的是双引号表示 TEXT 类型数据,下面的示例将使用单引号表示 TEXT 类型数据。 + +INSERT 语句还可以支持在同一个时间点下多列数据的插入,同时向 2 时间点插入上述两个时间序列的值,多列数据插入示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) values (2, false, 'v2') +``` + +此外,INSERT 语句支持一次性插入多行数据,同时向 2 个不同时间点插入上述时间序列的值,示例代码如下: + +```sql +IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4') +``` + +插入数据后我们可以使用 SELECT 语句简单查询已插入的数据。 + +```sql +IoTDB > select * from root.ln.wf02.wt02 where time < 5 +``` + +结果如图所示。由查询结果可以看出,单列、多列数据的插入操作正确执行。 + +``` ++-----------------------------+--------------------------+------------------------+ +| Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status| ++-----------------------------+--------------------------+------------------------+ +|1970-01-01T08:00:00.001+08:00| v1| true| +|1970-01-01T08:00:00.002+08:00| v2| false| +|1970-01-01T08:00:00.003+08:00| v3| false| +|1970-01-01T08:00:00.004+08:00| v4| true| ++-----------------------------+--------------------------+------------------------+ +Total line number = 4 +It costs 0.004s +``` + +此外,我们可以省略 timestamp 列,此时系统将使用当前的系统时间作为该数据点的时间戳,示例代码如下: +```sql +IoTDB > insert into root.ln.wf02.wt02(status, hardware) values (false, 'v2') +``` +**注意:** 当一次插入多行数据时必须指定时间戳。 + +### 1.2 向对齐时间序列插入数据 + +向对齐时间序列插入数据只需在SQL中增加`ALIGNED`关键词,其他类似。 + +示例代码如下: + +```sql +IoTDB > create aligned timeseries root.sg1.d1(s1 INT32, s2 DOUBLE) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(1, 1, 1) +IoTDB > insert into root.sg1.d1(time, s1, s2) aligned values(2, 2, 2), (3, 3, 3) +IoTDB > select * from root.sg1.d1 +``` + +结果如图所示。由查询结果可以看出,数据的插入操作正确执行。 + +``` ++-----------------------------+--------------+--------------+ +| Time|root.sg1.d1.s1|root.sg1.d1.s2| ++-----------------------------+--------------+--------------+ +|1970-01-01T08:00:00.001+08:00| 1| 1.0| +|1970-01-01T08:00:00.002+08:00| 2| 2.0| +|1970-01-01T08:00:00.003+08:00| 3| 3.0| ++-----------------------------+--------------+--------------+ +Total line number = 3 +It costs 0.004s +``` + +## 2. 原生接口写入 +原生接口 (Session) 是目前IoTDB使用最广泛的系列接口,包含多种写入接口,适配不同的数据采集场景,性能高效且支持多语言。 + +### 2.1 多语言接口写入 +* ### Java + 使用Java接口写入之前,你需要先建立连接,参考 [Java原生接口](../API/Programming-Java-Native-API_timecho)。 + 之后通过 [ JAVA 数据操作接口(DML)](../API/Programming-Java-Native-API_timecho#数据写入)写入。 + +* ### Python + 参考 [ Python 数据操作接口(DML)](../API/Programming-Python-Native-API_timecho#数据写入) + +* ### C++ + 参考 [ C++ 数据操作接口(DML)](../API/Programming-Cpp-Native-API.md) + +* ### Go + 参考 [Go 原生接口](../API/Programming-Go-Native-API.md) + +## 3. REST API写入 + +参考 [insertTablet (v1)](../API/RestServiceV1_timecho#inserttablet) or [insertTablet (v2)](../API/RestServiceV2_timecho#inserttablet) + +示例如下: +```JSON +{ +      "timestamps": [ +            1, +            2, +            3 +      ], +      "measurements": [ +            "temperature", +            "status" +      ], +      "data_types": [ +            "FLOAT", +            "BOOLEAN" +      ], +      "values": [ +            [ +                  1.1, +                  2.2, +                  3.3 +            ], +            [ +                  false, +                  true, +                  true +            ] +      ], +      "is_aligned": false, +      "device": "root.ln.wf01.wt01" +} +``` + +## 4. MQTT写入 + +参考 [内置 MQTT 服务](../API/Programming-MQTT.md#内置-mqtt-服务) + +## 5. 批量数据导入 + +针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,本章节向大家介绍最为常用的两种方式为 CSV文本形式的导入 和 TsFile文件形式的导入。 + +### 5.1 TsFile批量导入 + +TsFile 是在 IoTDB 中使用的时间序列的文件格式,您可以通过CLI等工具直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的IoTDB实例中。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_timecho)。 + +### 5.2 CSV批量导入 + +CSV 是以纯文本形式存储表格数据,您可以在CSV文件中写入多条格式化的数据,并批量的将这些数据导入到 IoTDB 中,在导入数据之前,建议在IoTDB中创建好对应的元数据信息。如果忘记创建元数据也不要担心,IoTDB 可以自动将CSV中数据推断为其对应的数据类型,前提是你每一列的数据类型必须唯一。除单个文件外,此工具还支持以文件夹的形式导入多个 CSV 文件,并且支持设置如时间精度等优化参数。具体操作方式请参考[数据导入](../Tools-System/Data-Import-Tool_timecho)。 + +## 6. 无模式写入 +在物联网场景中,由于设备的类型、数量可能随时间动态增减,不同设备可能产生不同字段的数据(如温度、湿度、状态码等),业务上又往往需要快速部署,需要灵活接入新设备且无需繁琐的预定义流程。因此,不同于传统时序数据库通常需要预先定义数据模型,IoTDB支持不提前创建元数据,在写入数据时,数据库中将自动识别并注册所需的元数据,实现自动建模。 + +用户既可以通过CLI使用insert语句或者原生接口的方式,批量或者单行实时写入一个设备或者多个设备的测点数据,也可以通过导入工具导入csv,TsFile等格式的历史数据,在导入过程中会自动创建序列,数据类型,压缩编码方式等元数据。 diff --git a/src/zh/UserGuide/latest/QuickStart/QuickStart_apache.md b/src/zh/UserGuide/latest/QuickStart/QuickStart_apache.md index f0669fb92..523ed7ad7 100644 --- a/src/zh/UserGuide/latest/QuickStart/QuickStart_apache.md +++ b/src/zh/UserGuide/latest/QuickStart/QuickStart_apache.md @@ -51,9 +51,9 @@ - SQL 语法介绍:[SQL 语法介绍](../Basic-Concept/Operate-Metadata_apache.md) -2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data) +2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data_apache) -3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data.md) +3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data_apache) 4. 其他进阶功能:除了数据库常见的写入、查询等功能外,IoTDB 还支持“数据同步、流处理框架、权限管理”等功能,具体使用方法可参见具体文档: @@ -61,9 +61,9 @@ - 流处理框架:[流处理框架](../User-Manual/Streaming_apache.md) - - 权限管理:[权限管理](../User-Manual/Authority-Management.md) + - 权限管理:[权限管理](../User-Manual/Authority-Management_apache) -5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持 [Java](../API/Programming-Java-Native-API.md)、[Python](../API/Programming-Python-Native-API.md)、[C++](../API/Programming-Cpp-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持 [Java](../API/Programming-Java-Native-API_apache)、[Python](../API/Programming-Python-Native-API_apache)、[C++](../API/Programming-Cpp-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? @@ -71,10 +71,10 @@ IoTDB 除了自身拥有丰富的功能外,其周边的工具体系包含的 - 测试工具:IoT-benchmark 是一个基于 Java 和大数据环境开发的时序数据库基准测试工具,由清华大学软件学院研发并开源。它支持多种写入和查询方式,能够存储测试信息和结果供进一步查询或分析,并支持与 Tableau 集成以可视化测试结果。具体使用介绍请查看:[测试工具](../Tools-System/Benchmark.md) - - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool.md) + - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool_apache) - - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool.md) + - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool_apache) ## 4. 想了解更多技术细节? diff --git a/src/zh/UserGuide/latest/QuickStart/QuickStart_timecho.md b/src/zh/UserGuide/latest/QuickStart/QuickStart_timecho.md index 6bcda0c34..314ad1aae 100644 --- a/src/zh/UserGuide/latest/QuickStart/QuickStart_timecho.md +++ b/src/zh/UserGuide/latest/QuickStart/QuickStart_timecho.md @@ -59,9 +59,9 @@ - SQL 语法介绍:[SQL 语法介绍](../Basic-Concept/Operate-Metadata_timecho.md) -2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data) +2. 数据写入:在数据写入方面,IoTDB 提供了多种方式来插入实时数据,基本的数据写入操作请查看 [数据写入](../Basic-Concept/Write-Data_timecho) -3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data.md) +3. 数据查询:IoTDB 提供了丰富的数据查询功能,数据查询的基本介绍请查看 [数据查询](../Basic-Concept/Query-Data_timecho) 4. 其他进阶功能:除了数据库常见的写入、查询等功能外,IoTDB 还支持“数据同步、流处理框架、安全控制、权限管理、AI 分析”等功能,具体使用方法可参见具体文档: @@ -71,11 +71,11 @@ - 安全控制:[安全控制](../User-Manual/White-List_timecho.md) - - 权限管理:[权限管理](../User-Manual/Authority-Management.md) + - 权限管理:[权限管理](../User-Manual/Authority-Management_timecho) - AI 分析:[AI 能力](../AI-capability/AINode_timecho.md) -5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API.md)、[Python 原生接口](../API/Programming-Python-Native-API.md)、[C++原生接口](../API/Programming-Cpp-Native-API.md)、[Go 原生接口](../API/Programming-Go-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 +5. 应用编程接口: IoTDB 提供了多种应用编程接口(API),以便于开发者在应用程序中与 IoTDB 进行交互,目前支持[ Java 原生接口](../API/Programming-Java-Native-API_timecho)、[Python 原生接口](../API/Programming-Python-Native-API_timecho)、[C++原生接口](../API/Programming-Cpp-Native-API.md)、[Go 原生接口](../API/Programming-Go-Native-API.md)等,更多编程接口可参见官网【应用编程接口】其他章节 ## 3. 还有哪些便捷的周边工具? @@ -87,10 +87,10 @@ IoTDB 除了自身拥有丰富的功能外,其周边的工具体系包含的 - 测试工具:IoT-benchmark 是一个基于 Java 和大数据环境开发的时序数据库基准测试工具,由清华大学软件学院研发并开源。它支持多种写入和查询方式,能够存储测试信息和结果供进一步查询或分析,并支持与 Tableau 集成以可视化测试结果。具体使用介绍请查看:[测试工具](../Tools-System/Benchmark.md) - - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool.md) + - 数据导入脚本:针对于不同场景,IoTDB 为用户提供多种批量导入数据的操作方式,具体使用介绍请查看:[数据导入](../Tools-System/Data-Import-Tool_timecho) - - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool.md) + - 数据导出脚本:针对于不同场景,IoTDB 为用户提供多种批量导出数据的操作方式,具体使用介绍请查看:[数据导出](../Tools-System/Data-Export-Tool_timecho) ## 4. 想了解更多技术细节? diff --git a/src/zh/UserGuide/latest/Tools-System/CLI_apache.md b/src/zh/UserGuide/latest/Tools-System/CLI_apache.md index d69e49e06..62320a0e6 100644 --- a/src/zh/UserGuide/latest/Tools-System/CLI_apache.md +++ b/src/zh/UserGuide/latest/Tools-System/CLI_apache.md @@ -38,7 +38,7 @@ IOTDB 为用户提供 cli/Shell 工具用于启动客户端和服务端程序。 ## 2. 运行 ### 2.1 Cli 运行方式 -安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
+安装后的 IoTDB 中有一个默认用户:`root`,默认密码为 `root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
用户也可以在启动脚本的最前方设置自己的环境变量,如 JAVA_HOME 等。 Linux 系统与 MacOS 系统启动命令如下: @@ -49,10 +49,10 @@ Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root Windows 系统启动命令如下: ```shell -# V2.0.4.x 版本之前 +# V2.0.4 版本之前 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x 版本及之后 +# V2.0.4 版本及之后, Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root ``` 回车后即可成功启动客户端。启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/latest/Tools-System/CLI_timecho.md b/src/zh/UserGuide/latest/Tools-System/CLI_timecho.md index 2ec16f94c..e102cd6be 100644 --- a/src/zh/UserGuide/latest/Tools-System/CLI_timecho.md +++ b/src/zh/UserGuide/latest/Tools-System/CLI_timecho.md @@ -25,13 +25,17 @@ IOTDB 为用户提供 cli/Shell 工具用于启动客户端和服务端程序。 > \$IOTDB\_HOME 表示 IoTDB 的安装目录所在路径。 ## 1. Cli 运行方式 -安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`root`。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
+安装后的 IoTDB 中有一个默认用户:`root`,默认密码为`TimechoDB@2021`(V2.0.6.x 版本之前为`root`)。用户可以使用该用户尝试运行 IoTDB 客户端以测试服务器是否正常启动。客户端启动脚本为$IOTDB_HOME/sbin 文件夹下的`start-cli`脚本。启动脚本时需要指定运行 IP 和 RPC PORT。以下为服务器在本机启动,且用户未更改运行端口号的示例,默认端口为 6667。若用户尝试连接远程服务器或更改了服务器运行的端口号,请在-h 和-p 项处使用服务器的 IP 和 RPC PORT。
用户也可以在启动脚本的最前方设置自己的环境变量,如 JAVA_HOME 等。 Linux 系统与 MacOS 系统启动命令如下: ```shell +# V2.0.6.x 版本之前 Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x 版本及之后 +Shell > bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` Windows 系统启动命令如下: @@ -39,8 +43,11 @@ Windows 系统启动命令如下: # V2.0.4.x 版本之前 Shell > sbin\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root -# V2.0.4.x 版本及之后 +# V2.0.4.x 版本及之后, V2.0.6.x 版本之前 Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw root + +# V2.0.6.x 版本及之后 +Shell > sbin\windows\start-cli.bat -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 ``` 回车后即可成功启动客户端。启动后出现如图提示即为启动成功。 diff --git a/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool.md b/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md similarity index 95% rename from src/zh/UserGuide/latest/Tools-System/Data-Export-Tool.md rename to src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md index cfc3b5105..d8827ad35 100644 --- a/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool.md +++ b/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_apache.md @@ -31,18 +31,18 @@ ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- | ------------------------------------------ | -| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | | -h | -- host | 主机名 | 否 | 127.0.0.1 | | -p | --port | 端口号 | 否 | 6667 | | -u | --username | 用户名 | 否 | root | | -pw | --password | 密码 | 否 | root | -| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | -| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | -| -q | --query | 要执行的查询命令 | 否 | 无 | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | | -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | -| -help | --help | 显示帮助信息 | 否 | | +| -help | --help | 显示帮助信息 | 否 | | ### 2.2 Csv 格式 @@ -84,7 +84,7 @@ # 异常示例 > tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.3 Sql 格式 @@ -128,7 +128,7 @@ Parse error: Missing required option: t # 异常示例 > tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` ### 2.4 TsFile 格式 @@ -163,5 +163,5 @@ Parse error: Missing required option: t # 异常示例 > tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw root -Parse error: Missing required option: t +Parse error: Missing required option: t ``` diff --git a/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md b/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md new file mode 100644 index 000000000..e060fe818 --- /dev/null +++ b/src/zh/UserGuide/latest/Tools-System/Data-Export-Tool_timecho.md @@ -0,0 +1,173 @@ +# 数据导出 + +## 1. 功能概述 + +数据导出工具 export-data.sh/bat 位于 tools 目录下,能够将指定 SQL 的查询结果导出为 CSV、SQL 及 TsFile(开源时间序列文件格式)格式。具体功能如下: + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVexport-data.sh/bat纯文本格式,存储格式化数据,需按照下文指定 CSV 格式进行构造
SQL包含自定义 SQL 语句的文件
TsFile开源时序数据文件格式
+ + +## 2. 功能详解 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------- | ---------------------------------------------------------------------- | -------------- |------------------------------------------| +| -ft | --file\_type | 导出文件的类型,可以选择:csv、sql、tsfile | √ | | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| -t | --target | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | √ | | +| -pfn | --prefix\_file\_name | 指定导出文件的名称。例如:abc,生成的文件是abc\_0.tsfile、abc\_1.tsfile | 否 | dump\_0.tsfile | +| -q | --query | 要执行的查询命令 | 否 | 无 | +| -timeout | --query\_timeout | 会话查询的超时时间(ms) | 否 | -1
范围:-1~Long max=9223372036854775807 | +| -help | --help | 显示帮助信息 | 否 | | + +### 2.2 Csv 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] -t + [-pfn ] [-dt ] [-lpf ] [-tf ] + [-tz ] [-q ] [-timeout ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |--------------------------------------| +| -dt | --datatype | 是否在CSV文件的表头输出时间序列的数据类型,可以选择`true`或`false` | 否 | false | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定CSV文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601 | +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.2.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -dt true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# 异常示例 +> tools/export-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.3 Sql 格式 + +#### 2.3.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-aligned ] + -lpf - [-tf ] [-tz ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h -p -u -pw ] + -t [-pfn -aligned + -lpf -tf -tz -q -timeout ] +``` + +#### 2.3.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------------------------------------- | +| -aligned | --use\_aligned | 是否导出为对齐的SQL格式 | 否 | true | +| -lpf | --lines\_per\_file | 每个转储文件的行数 | 否 | 10000
范围:0~Integer.Max=2147483647 | +| -tf | --time\_format | 指定CSV文件中的时间格式。可以选择:1) 时间戳(数字、长整型);2) ISO8601(默认);3) 用户自定义模式,如`yyyy-MM-dd HH:mm:ss`(默认为ISO8601)。SQL文件中的时间戳输出不受时间格式设置影响 | 否| ISO8601| +| -tz | --timezone | 设置时区,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | + +#### 2.3.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn exported-data.csv -aligned true -lpf 1000 -tf "yyyy-MM-dd HH:mm:ss" + -tz +08:00 -q "SELECT * FROM root.ln" -timeout 20000 + +# 异常示例 +> tools/export-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/export-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# Windows +# V2.0.4.x 版本之前 +> tools\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\export-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -t [-pfn ] [-q ] [-timeout ] +``` + +#### 2.4.2 私有参数 + +* 无 + +#### 2.4.3 运行示例: + +```Shell +# 正确示例 +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -t /path/export/dir + -pfn export-data.tsfile -q "SELECT * FROM root.ln" -timeout 10000 + +# 异常示例 +> tools/export-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 +Parse error: Missing required option: t + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` diff --git a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md b/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md similarity index 98% rename from src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md rename to src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md index 57e843a33..be01c58c4 100644 --- a/src/zh/UserGuide/Master/Tree/Tools-System/Data-Import-Tool.md +++ b/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_apache.md @@ -41,18 +41,18 @@ IoTDB 支持三种方式进行数据导入: ### 2.1 公共参数 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |----------------------------------| +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |---------------------------| | -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | | -| -h | -- host | 主机名 | 否 | 127.0.0.1 | -| -p | --port | 端口号 | 否 | 6667 | -| -u | --username | 用户名 | 否 | root | -| -pw | --password | 密码 | 否 | root | +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | root | | -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为csv sql tsfile这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | | | -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | -| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | | -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | | @@ -106,7 +106,7 @@ IoTDB 支持三种方式进行数据导入: error: Source file or directory /non_path does not exist > tools/import-data.sh -ft csv -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` #### 2.3.4 导入说明 @@ -196,7 +196,7 @@ error: Source file or directory /path/sql does not exist > tools/import-data.sh -ft sql -s /path/sql -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ### 2.4 TsFile 格式 @@ -247,7 +247,7 @@ error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' > tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir -tn 0 -error: Invalid thread number '0'. Please set a positive integer. +error: Invalid thread number '0'. Please set a positive integer. ``` ## 3. TsFile 自动加载功能 diff --git a/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md b/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md new file mode 100644 index 000000000..136c026fc --- /dev/null +++ b/src/zh/UserGuide/latest/Tools-System/Data-Import-Tool_timecho.md @@ -0,0 +1,332 @@ +# 数据导入 + +## 1. 功能概述 + +IoTDB 支持三种方式进行数据导入: +- 数据导入工具 :`import-data.sh/bat` 位于 `tools` 目录下,可以将 `CSV`、`SQL`、及`TsFile`(开源时序文件格式)的数据导入 `IoTDB`。 +- `TsFile` 自动加载功能。 +- `Load SQL` 导入 `TsFile` 。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
文件格式IoTDB工具具体介绍
CSVimport-data.sh/bat可用于单个或一个目录的 CSV 文件批量导入 IoTDB
SQL可用于单个或一个目录的 SQL 文件批量导入 IoTDB
TsFile可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
TsFile 自动加载可以监听指定路径下新产生的 TsFile 文件,并将其加载进 IoTDB
Load SQL可用于单个或一个目录的 TsFile 文件批量导入 IoTDB
+ +## 2. 数据导入工具 + +### 2.1 公共参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | --------------- |-----------------------------------------------------------------------------------------------------------------------------------------| -------------- |--------------------------------------| +| -ft | --file\_type | 导入文件的类型,可以选择:csv、sql、tsfile | √ | +| +| -h | -- host | 主机名 | 否 | 127.0.0.1 | +| -p | --port | 端口号 | 否 | 6667 | +| -u | --username | 用户名 | 否 | root | +| -pw | --password | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| -s | --source | 待加载的脚本文件(夹)的本地目录路径
如果为csv sql tsfile这三个支持的格式,直接导入
不支持的格式,报错提示`The file name must end with "csv" or "sql"or "tsfile"!` | √ | +| +| -tn | --thread\_num | 最大并行线程数 | 否 | 8
范围:0~Integer.Max=2147483647 | +| -tz | --timezone | 时区设置,例如`+08:00`或`-01:00` | 否 | 本机系统时间 | +| -help | --help | 显示帮助信息,支持分开展示和全部展示`-help`或`-help csv` | 否 | +| + +### 2.2 CSV 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-aligned ] + [-ti ] [-tp ] [-tz ] [-batch ] + [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- |-------------------------------------------|---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -aligned | --use\_aligned | 是否导入为对齐序列 | 否 | false | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -ti | --type\_infer | 通过选项定义类型信息,例如`"boolean=text,int=long, ..."` | 否 | 无 | +| -tp | --timestamp\_precision | 时间戳精度 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms +| + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft csv -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 100 -aligned true -ti "BOOLEAN=text,INT=long,FLOAT=double" + -tp ms -tz +08:00 -batch 5000 -tn 4 + +# 异常示例 +> tools/import-data.sh -ft csv -s /non_path +error: Source file or directory /non_path does not exist + +> tools/import-data.sh -ft csv -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +#### 2.3.4 导入说明 + +1. CSV 导入规范 + +- 特殊字符转义规则:若Text类型的字段中包含特殊字符(例如逗号,),需使用反斜杠(\)​进行转义处理。 +- 支持的时间格式:yyyy-MM-dd'T'HH:mm:ss, yyy-MM-dd HH:mm:ss, 或者 yyyy-MM-dd'T'HH:mm:ss.SSSZ。 +- 时间戳列​必须作为数据文件的首列存在。 + +2. CSV 文件示例 + +- 时间对齐 + +```sql +-- header 中不包含数据类型 + Time,root.test.t1.str,root.test.t2.str,root.test.t2.var + 1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 + 1970-01-01T08:00:00.002+08:00,"123",, + +-- header 中包含数据类型(Text 类型数据支持加双引号和不加双引号) +Time,root.test.t1.str(TEXT),root.test.t2.str(TEXT),root.test.t2.var(INT32) +1970-01-01T08:00:00.001+08:00,"123hello world","123\,abc",100 +1970-01-01T08:00:00.002+08:00,123,hello world,123 +1970-01-01T08:00:00.003+08:00,"123",, +1970-01-01T08:00:00.004+08:00,123,,12 +``` + +- 设备对齐 + +```sql +-- header 中不包含数据类型 + Time,Device,str,var + 1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", + 1970-01-01T08:00:00.002+08:00,root.test.t1,"123", + 1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 + +-- header 中包含数据类型(Text 类型数据支持加双引号和不加双引号) +Time,Device,str(TEXT),var(INT32) +1970-01-01T08:00:00.001+08:00,root.test.t1,"123hello world", +1970-01-01T08:00:00.002+08:00,root.test.t1,"123", +1970-01-01T08:00:00.001+08:00,root.test.t2,"123\,abc",100 +1970-01-01T08:00:00.002+08:00,root.test.t1,hello world,123 +``` + +### 2.3 SQL 格式 + +#### 2.2.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] + +# V2.0.4.x 版本及之后 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] [-tz ] + [-batch ] [-tn ] +``` + +#### 2.2.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ---------------------------- | ----------------------------------------------------------------------------------- | -------------- |---------------------------------------| +| -fd | --fail\_dir | 指定保存失败文件的目录 | 否 | YOUR\_CSV\_FILE\_PATH | +| -lpf | --lines\_per\_failed\_file | 指定失败文件最大写入数据的行数 | 否 | 100000
范围:0~Integer.Max=2147483647 | +| -batch | --batch\_size | 指定每调用一次接口处理的数据行数(最小值为1,最大值为Integer.​*MAX\_VALUE*​) | 否 | 100000
范围:0~Integer.Max=2147483647 | + +#### 2.2.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft sql -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 -s /path/sql + -fd /path/failure/dir -lpf 500 -tz +08:00 + -batch 100000 -tn 4 + +# 异常示例 +> tools/import-data.sh -ft sql -s /path/sql -fd /non_path +error: Source file or directory /path/sql does not exist + + +> tools/import-data.sh -ft sql -s /path/sql -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` + +### 2.4 TsFile 格式 + +#### 2.4.1 运行命令 + +```Shell +# Unix/OS X +> tools/import-data.sh -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# Windows +# V2.0.4.x 版本之前 +> tools\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] + +# V2.0.4.x 版本及之后 +> tools\windows\import-data.bat -ft [-h ] [-p ] [-u ] [-pw ] + -s -os [-sd ] -of [-fd ] + [-tn ] [-tz ] [-tp ] +``` + +#### 2.4.2 私有参数 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| ---------- | ------------------------ |----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------| -------------------- | +| -os| --on\_succcess| 1. none:不删除
2. mv:移动成功的文件到目标文件夹
3. cp:硬连接(拷贝)成功的文件到目标文件夹
4. delete:删除 | √ || +| -sd | --success\_dir | 当`--on_succcess`为mv或cp时,mv或cp的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_succcess`为mv或cp时需要填写 | `${EXEC_DIR}/success`| +| -of| --on\_fail| 1. none:跳过
2. mv:移动失败的文件到目标文件夹
3. cp:硬连接(拷贝)失败的文件到目标文件夹
4. delete:删除 | √ || +| -fd | --fail\_dir | 当`--on_fail`指定为mv或cp时,mv或cp的目标文件夹。文件的文件名变为文件夹打平后拼接原有文件名 | 当`--on_fail`指定为mv或cp时需要填写 | `${EXEC_DIR}/fail` | +| -tp | --timestamp\_precision | 时间戳精度
tsfile非远程导入:-tp 指定tsfile文件的时间精度 手动校验和服务器的时间戳是否一致 不一致返回报错信息
远程导入:-tp 指定tsfile文件的时间精度 pipe自动校验时间戳精度是否一致 不一致返回pipe报错信息 | 否:
1. ms(毫秒)
2. us(微秒)
3. ns(纳秒) | ms| + + +#### 2.4.3 运行示例 + +```Shell +# 正确示例 +> tools/import-data.sh -ft tsfile -h 127.0.0.1 -p 6667 -u root -pw TimechoDB@2021 + -s /path/sql -os mv -of cp -sd /path/success/dir -fd /path/failure/dir + -tn 8 -tz +08:00 -tp ms + +# 异常示例 +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -fd /path/failure/dir -tn 8 +error: Missing option --success_dir (or -sd) when --on_success is 'mv' or 'cp' + +> tools/import-data.sh -ft tsfile -s /path/sql -os mv -of cp + -sd /path/success/dir -fd /path/failure/dir -tn 0 +error: Invalid thread number '0'. Please set a positive integer. + +# 注意:V2.0.6.x 版本之前 -pw 参数值默认值为 root +``` +## 3. TsFile 自动加载功能 + +本功能允许 IoTDB 主动监听指定目录下的新增 TsFile,并将 TsFile 自动加载至 IoTDB 中。通过此功能,IoTDB 能自动检测并加载 TsFile,无需手动执行任何额外的加载操作。 + +![](/img/Data-import1.png) + +### 3.1 配置参数 + +可通过从配置文件模版 `iotdb-system.properties.template` 中找到下列参数,添加到 IoTDB 配置文件 `iotdb-system.properties` 中开启 TsFile 自动加载功能。完整配置如下: + +| **配置参数** | **参数说明** | **value 取值范围** | **是否必填** | **默认值** | **加载方式** | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------- | ------------------------ | -------------------- | +| load\_active\_listening\_enable | 是否开启 DataNode 主动监听并且加载 tsfile 的功能(默认开启)。 | Boolean: true,false | 选填 | true | 热加载 | +| load\_active\_listening\_dirs | 需要监听的目录(自动包括目录中的子目录),如有多个使用 “,“ 隔开默认的目录为 `ext/load/pending`(支持热装载) | String: 一个或多个文件目录 | 选填 | `ext/load/pending` | 热加载 | +| load\_active\_listening\_fail\_dir | 执行加载 tsfile 文件失败后将文件转存的目录,只能配置一个 | String: 一个文件目录 | 选填 | `ext/load/failed` | 热加载 | +| load\_active\_listening\_max\_thread\_num | 同时执行加载 tsfile 任务的最大线程数,参数被注释掉时的默值为 max(1, CPU 核心数 / 2),当用户设置的值不在这个区间[1, CPU核心数 /2]内时,会设置为默认值 (1, CPU 核心数 / 2) | Long: [1, Long.MAX\_VALUE] | 选填 | max(1, CPU 核心数 / 2) | 重启后生效 | +| load\_active\_listening\_check\_interval\_seconds | 主动监听轮询间隔,单位秒。主动监听 tsfile 的功能是通过轮询检查文件夹实现的。该配置指定了两次检查 `load_active_listening_dirs` 的时间间隔,每次检查完成 `load_active_listening_check_interval_seconds` 秒后,会执行下一次检查。当用户设置的轮询间隔小于 1 时,会被设置为默认值 5 秒 | Long: [1, Long.MAX\_VALUE] | 选填 | 5 | 重启后生效 | + +### 3.2 注意事项 + +1. 如果待加载的文件中,存在 mods 文件,应优先将 mods 文件移动到监听目录下面,然后再移动 tsfile 文件,且 mods 文件应和对应的 tsfile 文件处于同一目录。防止加载到 tsfile 文件时,加载不到对应的 mods 文件 +2. 禁止设置 Pipe 的 receiver 目录、存放数据的 data 目录等作为监听目录 +3. 禁止 `load_active_listening_fail_dir` 与 `load_active_listening_dirs` 存在相同的目录,或者互相嵌套 +4. 保证 `load_active_listening_dirs` 目录有足够的权限,在加载成功之后,文件将会被删除,如果没有删除权限,则会重复加载 + +## 4. Load SQL + +IoTDB 支持通过 CLI 执行 SQL 直接将存有时间序列的一个或多个 TsFile 文件导入到另外一个正在运行的 IoTDB 实例中。 + +### 4.1 运行命令 + +```SQL +load '' with ( + 'attribute-key1'='attribute-value1', + 'attribute-key2'='attribute-value2', +) +``` + +* `` :文件本身,或是包含若干文件的文件夹路径 +* ``:可选参数,具体如下表所示 + +| Key | Key 描述 | Value 类型 | Value 取值范围 | Value 是否必填 | Value 默认值 | +| --------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ | ----------------------------------------- | ---------------- | -------------------------- | +| `database-level` | 当 tsfile 对应的 database 不存在时,可以通过` database-level`参数的值来制定 database 的级别,默认为`iotdb-common.properties`中设置的级别。
例如当设置 level 参数为 1 时表明此 tsfile 中所有时间序列中层级为1的前缀路径是 database。 | Integer | `[1: Integer.MAX_VALUE]` | 否 | 1 | +| `on-success` | 表示对于成功载入的 tsfile 的处置方式:默认为`delete`,即tsfile 成功加载后将被删除;`none `表明 tsfile 成功加载之后依然被保留在源文件夹, | String | `delete / none` | 否 | delete | +| `model` | 指定写入的 tsfile 是表模型还是树模型 | String | `tree / table` | 否 | 与`-sql_dialect`一致 | +| `database-name` | **仅限表模型有效**: 文件导入的目标 database,不存在时会自动创建,`database-name`中不允许包括"`root.`"前缀,如果包含,将会报错。 | String | `-` | 否 | null | +| `convert-on-type-mismatch` | 加载 tsfile 时,如果数据类型不一致,是否进行转换 | Boolean | `true / false` | 否 | true | +| `verify` | 加载 tsfile 前是否校验 schema | Boolean | `true / false` | 否 | true | +| `tablet-conversion-threshold` | 转换为 tablet 形式的 tsfile 大小阈值,针对小文件 tsfile 加载,采用将其转换为 tablet 形式进行写入:默认值为 -1,即任意大小 tsfile 都不进行转换 | Integer | `[-1,0 :`​`Integer.MAX_VALUE]` | 否 | -1 | +| `async` | 是否开启异步加载 tsfile,将文件移到 active load 目录下面,所有的 tsfile 都 load 到`database-name`下. | Boolean | `true / false` | 否 | false | + +### 4.2 运行示例 + +```SQL +-- 准备待导入环境 +IoTDB> show databases ++-------------+-----------------------+---------------------+-------------------+---------------------+ +| Database|SchemaReplicationFactor|DataReplicationFactor|TimePartitionOrigin|TimePartitionInterval| ++-------------+-----------------------+---------------------+-------------------+---------------------+ +|root.__system| 1| 1| 0| 604800000| ++-------------+-----------------------+---------------------+-------------------+---------------------+ + +-- 通过load sql 导入 tsfile +IoTDB> load '/home/dump1.tsfile' with ( 'on-success'='none') +Msg: The statement is executed successfully. + +-- 验证数据导入成功 +IoTDB> select * from root.testdb.** ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +| Time|root.testdb.device.model.temperature|root.testdb.device.model.humidity|root.testdb.device.model.status| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +|2025-04-17T10:35:47.218+08:00| 22.3| 19.4| true| ++-----------------------------+------------------------------------+---------------------------------+-------------------------------+ +``` \ No newline at end of file diff --git a/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool.md b/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md similarity index 94% rename from src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool.md rename to src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md index ec7298763..feaac6100 100644 --- a/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool.md +++ b/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_apache.md @@ -29,21 +29,21 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | -| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | -| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | -| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | -| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | -| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | | `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | -| `-help` | `--help` | 显示帮助信息 | 否 | | +| `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md b/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md new file mode 100644 index 000000000..bc035727b --- /dev/null +++ b/src/zh/UserGuide/latest/Tools-System/Schema-Export-Tool_timecho.md @@ -0,0 +1,81 @@ + + +# 元数据导出 + +## 1. 功能概述 + +元数据导出工具 `export-schema.sh/bat` 位于tools 目录下,能够将 IoTDB 中指定数据库下的元数据导出为脚本文件。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | -------------------------- | ------------------------------------------------------------------------ | ----------------------------------- |---------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导出的目标数据库,只在`-sql_dialect`为 table 类型下生效。 | `-sql_dialect`为 table 时必填 | - | +| `-table` | `--table` | 将要导出的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-t` | `--target` | 指定输出文件的目标文件夹,如果路径不存在新建文件夹 | 是 | | +| `-path` | `--path_pattern` | 指定导出元数据的path pattern | `-sql_dialect`为 tree 时必填 | | +| `-pfn` | `--prefix_file_name` | 指定导出文件的名称。 | 否 | dump\_dbname.sql | +| `-lpf` | `--lines_per_file` | 指定导出的dump文件最大行数,只在`-sql_dialect`为 tree 类型下生效。 | 否 | `10000` | +| `-timeout` | `--query_timeout` | 会话查询的超时时间(ms) | 否 | -1范围:-1~Long. max=9223372036854775807 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +Shell +# Unix/OS X +> tools/export-schema.sh [-sql_dialect] -db -table + [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +# Windows +# V2.0.4.x 版本之前 +> tools\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] + +# V2.0.4.x 版本及之后 +> tools\windows\schema\export-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -t [-path ] [-pfn ] + [-lpf ] [-timeout ] +``` + +### 2.3 运行示例 + +```Bash +# 导出 root.treedb路径下的元数据 +./export-schema.sh -sql_dialect tree -t /home/ -path "root.treedb.**" + +# 导出结果内容格式如下 +Timeseries,Alias,DataType,Encoding,Compression +root.treedb.device.temperature,,DOUBLE,GORILLA,LZ4 +root.treedb.device.humidity,,DOUBLE,GORILLA,LZ4 +``` diff --git a/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md b/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md new file mode 100644 index 000000000..855e27003 --- /dev/null +++ b/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_apache.md @@ -0,0 +1,87 @@ + + +# 元数据导入 + +## 1. 功能概述 + +元数据导入工具 `import-schema.sh/bat` 位于tools 目录下,能够将指定路径下创建元数据的脚本文件导入到 IoTDB 中。 + +## 2. 功能详解 + +### 2.1 参数介绍 + +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |-----------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | root | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | +| `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-help` | `--help` | 显示帮助信息 | 否 | | + +### 2.2 运行命令 + +```Bash +# Unix/OS X +tools/import-schema.sh [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# Windows +# V2.0.4.x 版本之前 +tools\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] + +# V2.0.4.x 版本及之后 +tools\windows\schema\import-schema.bat [-sql_dialect] -db -table
+ [-h ] [-p ] [-u ] [-pw ] + -s [-fd ] [-lpf ] +``` + +### 2.3 运行示例 + +```Bash +# 导入前 +IoTDB> show timeseries root.treedb.** ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ ++----------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+--------+ + +# 执行导入命令 +./import-schema.sh -sql_dialect tree -s /home/dump0_0.csv -db root.treedb + +# 导入成功后验证 +IoTDB> show timeseries root.treedb.** ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +| Timeseries|Alias| Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +|root.treedb.device.temperature| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| +| root.treedb.device.humidity| null|root.treedb| DOUBLE| GORILLA| LZ4|null| null| null| null| BASE| ++------------------------------+-----+-----------+--------+--------+-----------+----+----------+--------+------------------+--------+ +``` diff --git a/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool.md b/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md similarity index 93% rename from src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool.md rename to src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md index 7d398cccf..2e3cc9a8f 100644 --- a/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool.md +++ b/src/zh/UserGuide/latest/Tools-System/Schema-Import-Tool_timecho.md @@ -29,18 +29,18 @@ ### 2.1 参数介绍 -| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | -| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- | --------------------------------------- | -| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | -| `-p` | `--port` | 端口号 | 否 | 6667 | -| `-u` | `--username` | 用户名 | 否 | root | -| `-pw` | `--password` | 密码 | 否 | root | -| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | -| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | -| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | +| 参数缩写 | 参数全称 | 参数含义 | 是否为必填项 | 默认值 | +| --------------------- | ------------------------------- | ----------------------------------------------------------------------------- | -------------- |--------------------------------------| +| `-h` | `-- host` | 主机名 | 否 | 127.0.0.1 | +| `-p` | `--port` | 端口号 | 否 | 6667 | +| `-u` | `--username` | 用户名 | 否 | root | +| `-pw` | `--password` | 密码 | 否 | TimechoDB@2021 (V2.0.6.x 版本之前为 root) | +| `-sql_dialect` | `--sql_dialect` | 选择 server 是树模型还是表模型,当前支持 tree 和 table 类型 | 否 | tree | +| `-db` | `--database` | 将要导入的目标数据库 | `是` | - | +| `-table` | `--table` | 将要导入的目标表,只在`-sql_dialect`为 table 类型下生效。 | 否 | - | | `-s` | `--source` | 待加载的脚本文件(夹)的本地目录路径。 | 是 | | | `-fd` | `--fail_dir` | 指定保存失败文件的目录 | 否 | | -| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | +| `-lpf` | `--lines_per_failed_file` | 指定失败文件最大写入数据的行数,只在`-sql_dialect`为 table 类型下生效。 | 否 | 100000范围:0~Integer.Max=2147483647 | | `-help` | `--help` | 显示帮助信息 | 否 | | ### 2.2 运行命令 diff --git a/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management.md b/src/zh/UserGuide/latest/User-Manual/Authority-Management_apache.md similarity index 98% rename from src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management.md rename to src/zh/UserGuide/latest/User-Manual/Authority-Management_apache.md index 8427d8b28..d1295fa2d 100644 --- a/src/zh/UserGuide/Master/Tree/User-Manual/Authority-Management.md +++ b/src/zh/UserGuide/latest/User-Manual/Authority-Management_apache.md @@ -22,7 +22,7 @@ # 权限管理 IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群系统的权限管理功能,保障数据与系统安全。 -本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC.md) 单条或批量执行权限管理类语句。 +本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC_apache) 单条或批量执行权限管理类语句。 ## 1. 基本概念 @@ -40,7 +40,7 @@ IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群 ### 1.4 默认用户与角色 -安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为 root。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 +安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为`root`。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 一个新创建的用户或角色不具备任何权限。 diff --git a/src/zh/UserGuide/latest/User-Manual/Authority-Management_timecho.md b/src/zh/UserGuide/latest/User-Manual/Authority-Management_timecho.md new file mode 100644 index 000000000..507082a87 --- /dev/null +++ b/src/zh/UserGuide/latest/User-Manual/Authority-Management_timecho.md @@ -0,0 +1,510 @@ + + +# 权限管理 + +IoTDB 为用户提供了权限管理操作,为用户提供对数据与集群系统的权限管理功能,保障数据与系统安全。 +本篇介绍IoTDB 中权限模块的基本概念、用户定义、权限管理、鉴权逻辑与功能用例。在 JAVA 编程环境中,您可以使用 [JDBC API](../API/Programming-JDBC_timecho) 单条或批量执行权限管理类语句。 + +## 1. 基本概念 + +### 1.1 用户 + +用户即数据库的合法使用者。一个用户与一个唯一的用户名相对应,并且拥有密码作为身份验证的手段。一个人在使用数据库之前,必须先提供合法的(即存于数据库中的)用户名与密码,作为用户成功登录。 + +### 1.2 权限 + +数据库提供多种操作,但并非所有的用户都能执行所有操作。如果一个用户可以执行某项操作,则称该用户有执行该操作的权限。权限通常需要一个路径来限定其生效范围,可以使用[路径模式](../Basic-Concept/Operate-Metadata.md)灵活管理权限。 + +### 1.3 角色 + +角色是若干权限的集合,并且有一个唯一的角色名作为标识符。角色通常和一个现实身份相对应(例如交通调度员),而一个现实身份可能对应着多个用户。这些具有相同现实身份的用户往往具有相同的一些权限,角色就是为了能对这样的权限进行统一的管理的抽象。 + +### 1.4 默认用户与角色 + +安装初始化后的 IoTDB 中有一个默认用户:root,默认密码为`TimechoDB@2021`(V2.0.6.x 版本之前为`root`)。该用户为管理员用户,固定拥有所有权限,无法被赋予、撤销权限,也无法被删除,数据库内仅有一个管理员用户。 + +一个新创建的用户或角色不具备任何权限。 + +## 2. 用户定义 + +拥有 MANAGE_USER、MANAGE_ROLE 的用户或者管理员可以创建用户或者角色,需要满足以下约束: + +### 2.1 用户名限制 + +4~32个字符,支持使用英文大小写字母、数字、特殊字符(`!@#$%^&*()_+-=`) + +用户无法创建和管理员用户同名的用户。 + +### 2.2 密码限制 + +4~32个字符,可使用大写小写字母、数字、特殊字符(`!@#$%^&*()_+-=`),密码默认采用 SHA-256 进行加密。 + +### 2.3 角色名限制 + +4~32个字符,支持使用英文大小写字母、数字、特殊字符(`!@#$%^&*()_+-=`) + +用户无法创建和管理员用户同名的角色。 + +## 3. 权限管理 + +IoTDB 主要有两类权限:序列权限、全局权限。 + +### 3.1 序列权限 + +序列权限约束了用户访问数据的范围与方式,支持对绝对路径与前缀匹配路径授权,可对timeseries 粒度生效。 + +下表描述了这类权限的种类与范围: + +| 权限名称 | 描述 | +|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| READ_DATA | 允许读取授权路径下的序列数据。 | +| WRITE_DATA | 允许读取授权路径下的序列数据。
允许插入、删除授权路径下的的序列数据。
允许在授权路径下导入、加载数据,在导入数据时,需要拥有对应路径的 WRITE_DATA 权限,在自动创建数据库与序列时,需要有 MANAGE_DATABASE 与 WRITE_SCHEMA 权限。 | +| READ_SCHEMA | 允许获取授权路径下元数据树的详细信息:
包括:路径下的数据库、子路径、子节点、设备、序列、模版、视图等。 | +| WRITE_SCHEMA | 允许获取授权路径下元数据树的详细信息。
允许在授权路径下对序列、模版、视图等进行创建、删除、修改操作。
在创建或修改 view 的时候,会检查 view 路径的 WRITE_SCHEMA 权限、数据源的 READ_SCHEMA 权限。
在对 view 进行查询、插入时,会检查 view 路径的 READ_DATA 权限、WRITE_DATA 权限。
允许在授权路径下设置、取消、查看TTL。
允许在授权路径下挂载或者接触挂载模板。 | + +### 3.2 全局权限 + +全局权限约束了用户使用的数据库功能、限制了用户执行改变系统状态与任务状态的命令,用户获得全局授权后,可对数据库进行管理。 + +下表描述了系统权限的种类: + +| 权限名称 | 描述 | +|:---------------:|:------------------------------------------------------------------| +| MANAGE_DATABASE | - 允许用户创建、删除数据库. | +| MANAGE_USER | - 允许用户创建、删除、修改、查看用户。 | +| MANAGE_ROLE | - 允许用户创建、删除、查看角色。
允许用户将角色授予给其他用户,或取消其他用户的角色。 | +| USE_TRIGGER | - 允许用户创建、删除、查看触发器。
与触发器的数据源权限检查相独立。 | +| USE_UDF | - 允许用户创建、删除、查看用户自定义函数。
与自定义函数的数据源权限检查相独立。 | +| USE_CQ | - 允许用户创建、开始、停止、删除、查看管道。
允许用户创建、删除、查看管道插件。
与管道的数据源权限检查相独立。 | +| USE_PIPE | - 允许用户注册、开始、停止、卸载、查询流处理任务。
- 允许用户注册、卸载、查询注册流处理任务插件。 | +| EXTEND_TEMPLATE | - 允许自动扩展模板。 | +| MAINTAIN | - 允许用户查询、取消查询。
允许用户查看变量。
允许用户查看集群状态。 | +| USE_MODEL | - 允许用户创建、删除、查询深度学习模型 | + +关于模板权限: + +1. 模板的创建、删除、修改、查询、挂载、卸载仅允许管理员操作。 +2. 激活模板需要拥有激活路径的 WRITE_SCHEMA 权限 +3. 若开启了自动创建,在向挂载了模板的不存在路径写入时,数据库会自动扩展模板并写入数据,因此需要有 EXTEND_TEMPLATE 权限与写入序列的 WRITE_DATA 权限。 +4. 解除模板,需要拥有挂载模板路径的 WRITE_SCHEMA 权限。 +5. 查询使用了某个元数据模板的路径,需要有路径的 READ_SCHEMA 权限,否则将返回为空。 + +### 3.3 权限授予与取消 + +在 IoTDB 中,用户可以由三种途径获得权限: + +1. 由超级管理员授予,超级管理员可以控制其他用户的权限。 +2. 由允许权限授权的用户授予,该用户获得权限时被指定了 grant option 关键字。 +3. 由超级管理员或者有 MANAGE_ROLE 的用户授予某个角色进而获取权限。 + +取消用户的权限,可以由以下几种途径: + +1. 由超级管理员取消用户的权限。 +2. 由允许权限授权的用户取消权限,该用户获得权限时被指定了 grant option 关键字。 +3. 由超级管理员或者MANAGE_ROLE 的用户取消用户的某个角色进而取消权限。 + +- 在授权时,必须指定路径。全局权限需要指定为 root.**, 而序列相关权限必须为绝对路径或者以双通配符结尾的前缀路径。 +- 当授予角色权限时,可以为该权限指定 with grant option 关键字,意味着用户可以转授其授权路径上的权限,也可以取消其他用户的授权路径上的权限。例如用户 A 在被授予`集团1.公司1.**`的读权限时制定了 grant option 关键字,那么 A 可以将`集团1.公司1`以下的任意节点、序列的读权限转授给他人, 同样也可以取消其他用户 `集团1.公司1` 下任意节点的读权限。 +- 在取消授权时,取消授权语句会与用户所有的权限路径进行匹配,将匹配到的权限路径进行清理,例如用户A 具有 `集团1.公司1.工厂1 `的读权限, 在取消 `集团1.公司1.** `的读权限时,会清除用户A 的 `集团1.公司1.工厂1` 的读权限。 + + + +## 4. 鉴权 + +用户权限主要由三部分组成:权限生效范围(路径), 权限类型, with grant option 标记: + +``` +userTest1 : + root.t1.** - read_schema, read_data - with grant option + root.** - write_schema, write_data - with grant option +``` + +每个用户都有一个这样的权限访问列表,标识他们获得的所有权限,可以通过 `LIST PRIVILEGES OF USER ` 查看他们的权限。 + +在对一个路径进行鉴权时,数据库会进行路径与权限的匹配。例如检查 `root.t1.t2` 的 read_schema 权限时,首先会与权限访问列表的 `root.t1.**`进行匹配,匹配成功,则检查该路径是否包含待鉴权的权限,否则继续下一条路径-权限的匹配,直到匹配成功或者匹配结束。 + +在进行多路径鉴权时,对于多路径查询任务,数据库只会将有权限的数据呈现出来,无权限的数据不会包含在结果中;对于多路径写入任务,数据库要求必须所有的目标序列都获得了对应的权限,才能进行写入。 + +请注意,下面的操作需要检查多重权限 +1. 开启了自动创建序列功能,在用户将数据插入到不存在的序列中时,不仅需要对应序列的写入权限,还需要序列的元数据修改权限。 +2. 执行 select into 语句时,需要检查源序列的读权限与目标序列的写权限。需要注意的是源序列数据可能因为权限不足而仅能获取部分数据,目标序列写入权限不足时会报错终止任务。 +3. View 权限与数据源的权限是独立的,向 view 执行读写操作仅会检查 view 的权限,而不再对源路径进行权限校验。 + + + +## 5. 功能语法与示例 + +IoTDB 提供了组合权限,方便用户授权: + +| 权限名称 | 权限范围 | +|-------|-------------------------| +| ALL | 所有权限 | +| READ | READ_SCHEMA、READ_DATA | +| WRITE | WRITE_SCHEMA、WRITE_DATA | + +组合权限并不是一种具体的权限,而是一种简写方式,与直接书写对应的权限名称没有差异。 + +下面将通过一系列具体的用例展示权限语句的用法,非管理员执行下列语句需要提前获取权限,所需的权限标记在操作描述后。 + +### 5.1 用户与角色相关 + +- 创建用户(需 MANAGE_USER 权限) + + +```SQL +CREATE USER +eg: CREATE USER user1 'passwd' +``` + +- 删除用户 (需 MANEGE_USER 权限) + + +```SQL +DROP USER +eg: DROP USER user1 +``` + +- 创建角色 (需 MANAGE_ROLE 权限) + +```SQL +CREATE ROLE +eg: CREATE ROLE role1 +``` + +- 删除角色 (需 MANAGE_ROLE 权限) + + +```SQL +DROP ROLE +eg: DROP ROLE role1 +``` + +- 赋予用户角色 (需 MANAGE_ROLE 权限) + + +```SQL +GRANT ROLE TO +eg: GRANT ROLE admin TO user1 +``` + +- 移除用户角色 (需 MANAGE_ROLE 权限) + + +```SQL +REVOKE ROLE FROM +eg: REVOKE ROLE admin FROM user1 +``` + +- 列出所有用户 (需 MANEGE_USER 权限) + +```SQL +LIST USER +``` + +- 列出所有角色 (需 MANAGE_ROLE 权限) + +```SQL +LIST ROLE +``` + +- 列出指定角色下所有用户 (需 MANEGE_USER 权限) + +```SQL +LIST USER OF ROLE +eg: LIST USER OF ROLE roleuser +``` + +- 列出指定用户下所有角色 + +用户可以列出自己的角色,但列出其他用户的角色需要拥有 MANAGE_ROLE 权限。 + +```SQL +LIST ROLE OF USER +eg: LIST ROLE OF USER tempuser +``` + +- 列出用户所有权限 + +用户可以列出自己的权限信息,但列出其他用户的权限需要拥有 MANAGE_USER 权限。 + +```SQL +LIST PRIVILEGES OF USER ; +eg: LIST PRIVILEGES OF USER tempuser; + +``` + +- 列出角色所有权限 + +用户可以列出自己具有的角色的权限信息,列出其他角色的权限需要有 MANAGE_ROLE 权限。 + +```SQL +LIST PRIVILEGES OF ROLE ; +eg: LIST PRIVILEGES OF ROLE actor; +``` + +- 修改密码 + +用户可以修改自己的密码,但修改其他用户密码需要具备MANAGE_USER 权限。 + +```SQL +ALTER USER SET PASSWORD ; +eg: ALTER USER tempuser SET PASSWORD 'newpwd'; +``` + +### 5.2 授权与取消授权 + +用户使用授权语句对赋予其他用户权限,语法如下: + +```SQL +GRANT ON TO ROLE/USER [WITH GRANT OPTION]; +eg: GRANT READ ON root.** TO ROLE role1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.** TO USER user1; +eg: GRANT READ_DATA, WRITE_DATA ON root.t1.**,root.t2.** TO USER user1; +eg: GRANT MANAGE_ROLE ON root.** TO USER user1 WITH GRANT OPTION; +eg: GRANT ALL ON root.** TO USER user1 WITH GRANT OPTION; +``` + +用户使用取消授权语句可以将其他的权限取消,语法如下: + +```SQL +REVOKE ON FROM ROLE/USER ; +eg: REVOKE READ ON root.** FROM ROLE role1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.** FROM USER user1; +eg: REVOKE READ_DATA, WRITE_DATA ON root.t1.**, root.t2.** FROM USER user1; +eg: REVOKE MANAGE_ROLE ON root.** FROM USER user1; +eg: REVOKE ALL ON ROOT.** FROM USER user1; +``` + +- **非管理员用户执行授权/取消授权语句时,需要对\ 有\ 权限,并且该权限是被标记带有 WITH GRANT OPTION 的。** + +- 在授予取消全局权限时,或者语句中包含全局权限时(ALL 展开会包含全局权限),须指定 path 为 root.**。 例如,以下授权/取消授权语句是合法的: + + ```SQL + GRANT MANAGE_USER ON root.** TO USER user1; + GRANT MANAGE_ROLE ON root.** TO ROLE role1 WITH GRANT OPTION; + GRANT ALL ON root.** TO role role1 WITH GRANT OPTION; + REVOKE MANAGE_USER ON root.** FROM USER user1; + REVOKE MANAGE_ROLE ON root.** FROM ROLE role1; + REVOKE ALL ON root.** FROM ROLE role1; + ``` + 下面的语句是非法的: + + ```SQL + GRANT READ, MANAGE_ROLE ON root.t1.** TO USER user1; + GRANT ALL ON root.t1.t2 TO USER user1 WITH GRANT OPTION; + REVOKE ALL ON root.t1.t2 FROM USER user1; + REVOKE READ, MANAGE_ROLE ON root.t1.t2 FROM ROLE ROLE1; + ``` + +- \ 必须为全路径或者以双通配符结尾的匹配路径,以下路径是合法的: + + ```SQL + root.** + root.t1.t2.** + root.t1.t2.t3 + ``` + + 以下的路径是非法的: + + ```SQL + root.t1.* + root.t1.**.t2 + root.t1*.t2.t3 + ``` + +## 6. 示例 + +根据本文中描述的 [样例数据](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt) 内容,IoTDB 的样例数据可能同时属于 ln, sgcc 等不同发电集团,不同的发电集团不希望其他发电集团获取自己的数据库数据,因此我们需要将不同的数据在集团层进行权限隔离。 + +### 6.1 创建用户 + +使用 `CREATE USER ` 创建用户。例如,我们可以使用具有所有权限的root用户为 ln 和 sgcc 集团创建两个用户角色,名为 ln_write_user, sgcc_write_user,密码均为 write_pwd。建议使用反引号(`)包裹用户名。SQL 语句为: + +```SQL +CREATE USER `ln_write_user` 'write_pwd' +CREATE USER `sgcc_write_user` 'write_pwd' +``` +此时使用展示用户的 SQL 语句: + +```SQL +LIST USER +``` + +我们可以看到这两个已经被创建的用户,结果如下: + +```SQL +IoTDB> CREATE USER `ln_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> CREATE USER `sgcc_write_user` 'write_pwd' +Msg: The statement is executed successfully. +IoTDB> LIST USER; ++---------------+ +| user| ++---------------+ +| ln_write_user| +| root| +|sgcc_write_user| ++---------------+ +Total line number = 3 +It costs 0.012s +``` + +### 6.2 赋予用户权限 + +此时,虽然两个用户已经创建,但是他们不具有任何权限,因此他们并不能对数据库进行操作,例如我们使用 ln_write_user 用户对数据库中的数据进行写入,SQL 语句为: + +```SQL +INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +``` + +此时,系统不允许用户进行此操作,会提示错误: + +```SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,status) values(1509465600000,true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +现在,我们用 root 用户分别赋予他们向对应路径的写入权限. + +我们使用 `GRANT ON TO USER ` 语句赋予用户权限,例如: +```SQL +GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +``` + +执行状态如下所示: + +```SQL +IoTDB> GRANT WRITE_DATA ON root.ln.** TO USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> GRANT WRITE_DATA ON root.sgcc1.**, root.sgcc2.** TO USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +接着使用ln_write_user再尝试写入数据 + +```SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: The statement is executed successfully. +``` + +### 6.3 撤销用户权限 +授予用户权限后,我们可以使用 `REVOKE ON FROM USER `来撤销已经授予用户的权限。例如,用root用户撤销ln_write_user和sgcc_write_user的权限: + +``` SQL +REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +``` + +执行状态如下所示: +``` SQL +IoTDB> REVOKE WRITE_DATA ON root.ln.** FROM USER `ln_write_user` +Msg: The statement is executed successfully. +IoTDB> REVOKE WRITE_DATA ON root.sgcc1.**, root.sgcc2.** FROM USER `sgcc_write_user` +Msg: The statement is executed successfully. +``` + +撤销权限后,ln_write_user就没有向root.ln.**写入数据的权限了。 + +``` SQL +IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true) +Msg: 803: No permissions for this operation, please add privilege WRITE_DATA on [root.ln.wf01.wt01.status] +``` + +## 7. 其他说明 + +角色是权限的集合,而权限和角色都是用户的一种属性。即一个角色可以拥有若干权限。一个用户可以拥有若干角色与权限(称为用户自身权限)。 + +目前在 IoTDB 中并不存在相互冲突的权限,因此一个用户真正具有的权限是用户自身权限与其所有的角色的权限的并集。即要判定用户是否能执行某一项操作,就要看用户自身权限或用户的角色的所有权限中是否有一条允许了该操作。用户自身权限与其角色权限,他的多个角色的权限之间可能存在相同的权限,但这并不会产生影响。 + +需要注意的是:如果一个用户自身有某种权限(对应操作 A),而他的某个角色有相同的权限。那么如果仅从该用户撤销该权限无法达到禁止该用户执行操作 A 的目的,还需要从这个角色中也撤销对应的权限,或者从这个用户将该角色撤销。同样,如果仅从上述角色将权限撤销,也不能禁止该用户执行操作 A。 + +同时,对角色的修改会立即反映到所有拥有该角色的用户上,例如对角色增加某种权限将立即使所有拥有该角色的用户都拥有对应权限,删除某种权限也将使对应用户失去该权限(除非用户本身有该权限)。 + +## 8. 升级说明 + +在 1.3 版本前,权限类型较多,在这一版实现中,权限类型做了精简,并且添加了对权限路径的约束。 + +数据库 1.3 版本的权限路径必须为全路径或者以双通配符结尾的匹配路径,在系统升级时,会自动转换不合法的权限路径和权限类型。 +路径上首个非法节点会被替换为`**`, 不在支持的权限类型也会映射到当前系统支持的权限上。 + +例如: + +| 权限类型 | 权限路径 | 映射之后的权限类型 | 权限路径 | +| ----------------- | --------------- |-----------------| ------------- | +| CREATE_DATBASE | root.db.t1.* | MANAGE_DATABASE | root.** | +| INSERT_TIMESERIES | root.db.t2.*.t3 | WRITE_DATA | root.db.t2.** | +| CREATE_TIMESERIES | root.db.t2*c.t3 | WRITE_SCHEMA | root.db.** | +| LIST_ROLE | root.** | (忽略) | | + + +新旧版本的权限类型对照可以参照下面的表格(--IGNORE 表示新版本忽略该权限): + +| 权限名称 | 是否路径相关 | 新权限名称 | 是否路径相关 | +|---------------------------|--------|-----------------|--------| +| CREATE_DATABASE | 是 | MANAGE_DATABASE | 否 | +| INSERT_TIMESERIES | 是 | WRITE_DATA | 是 | +| UPDATE_TIMESERIES | 是 | WRITE_DATA | 是 | +| READ_TIMESERIES | 是 | READ_DATA | 是 | +| CREATE_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| DELETE_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| CREATE_USER | 否 | MANAGE_USER | 否 | +| DELETE_USER | 否 | MANAGE_USER | 否 | +| MODIFY_PASSWORD | 否 | -- IGNORE | | +| LIST_USER | 否 | -- IGNORE | | +| GRANT_USER_PRIVILEGE | 否 | -- IGNORE | | +| REVOKE_USER_PRIVILEGE | 否 | -- IGNORE | | +| GRANT_USER_ROLE | 否 | MANAGE_ROLE | 否 | +| REVOKE_USER_ROLE | 否 | MANAGE_ROLE | 否 | +| CREATE_ROLE | 否 | MANAGE_ROLE | 否 | +| DELETE_ROLE | 否 | MANAGE_ROLE | 否 | +| LIST_ROLE | 否 | -- IGNORE | | +| GRANT_ROLE_PRIVILEGE | 否 | -- IGNORE | | +| REVOKE_ROLE_PRIVILEGE | 否 | -- IGNORE | | +| CREATE_FUNCTION | 否 | USE_UDF | 否 | +| DROP_FUNCTION | 否 | USE_UDF | 否 | +| CREATE_TRIGGER | 是 | USE_TRIGGER | 否 | +| DROP_TRIGGER | 是 | USE_TRIGGER | 否 | +| START_TRIGGER | 是 | USE_TRIGGER | 否 | +| STOP_TRIGGER | 是 | USE_TRIGGER | 否 | +| CREATE_CONTINUOUS_QUERY | 否 | USE_CQ | 否 | +| DROP_CONTINUOUS_QUERY | 否 | USE_CQ | 否 | +| ALL | 否 | All privilegs | | +| DELETE_DATABASE | 是 | MANAGE_DATABASE | 否 | +| ALTER_TIMESERIES | 是 | WRITE_SCHEMA | 是 | +| UPDATE_TEMPLATE | 否 | -- IGNORE | | +| READ_TEMPLATE | 否 | -- IGNORE | | +| APPLY_TEMPLATE | 是 | WRITE_SCHEMA | 是 | +| READ_TEMPLATE_APPLICATION | 否 | -- IGNORE | | +| SHOW_CONTINUOUS_QUERIES | 否 | -- IGNORE | | +| CREATE_PIPEPLUGIN | 否 | USE_PIPE | 否 | +| DROP_PIPEPLUGINS | 否 | USE_PIPE | 否 | +| SHOW_PIPEPLUGINS | 否 | -- IGNORE | | +| CREATE_PIPE | 否 | USE_PIPE | 否 | +| START_PIPE | 否 | USE_PIPE | 否 | +| STOP_PIPE | 否 | USE_PIPE | 否 | +| DROP_PIPE | 否 | USE_PIPE | 否 | +| SHOW_PIPES | 否 | -- IGNORE | | +| CREATE_VIEW | 是 | WRITE_SCHEMA | 是 | +| ALTER_VIEW | 是 | WRITE_SCHEMA | 是 | +| RENAME_VIEW | 是 | WRITE_SCHEMA | 是 | +| DELETE_VIEW | 是 | WRITE_SCHEMA | 是 | diff --git a/src/zh/UserGuide/latest/User-Manual/Data-Sync_timecho.md b/src/zh/UserGuide/latest/User-Manual/Data-Sync_timecho.md index 1c30b63db..0326faf02 100644 --- a/src/zh/UserGuide/latest/User-Manual/Data-Sync_timecho.md +++ b/src/zh/UserGuide/latest/User-Manual/Data-Sync_timecho.md @@ -585,50 +585,50 @@ pipe_all_sinks_rate_limit_bytes_per_second=-1 #### iotdb-thrift-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -|-----------------------------| ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | ------------ | -| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +|-----------------------------| ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |----------------------------------| +| sink | iotdb-thrift-sink 或 iotdb-thrift-async-sink | String: iotdb-thrift-sink 或 iotdb-thrift-async-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | #### iotdb-air-gap-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -| ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | -------- | -| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| air-gap.handshake-timeout-ms | 发送端与接收端在首次尝试建立连接时握手请求的超时时长,单位:毫秒 | Integer | 选填 | 5000 | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +| ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |-----------------------------------| +| sink | iotdb-air-gap-sink | String: iotdb-air-gap-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| air-gap.handshake-timeout-ms | 发送端与接收端在首次尝试建立连接时握手请求的超时时长,单位:毫秒 | Integer | 选填 | 5000 | #### iotdb-thrift-ssl-sink -| key | value | value 取值范围 | 是否必填 | 默认取值 | -| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | ------------ | -| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | -| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | root | -| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | -| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | -| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | -| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | -| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | -| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | -| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | -| ssl.trust-store-path | 连接目标端 DataNode 所需的 trust store 证书路径 | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | -| ssl.trust-store-pwd | 连接目标端 DataNode 所需的 trust store 证书密码 | Integer | 必填 | - | -| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | +| key | value | value 取值范围 | 是否必填 | 默认取值 | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |-----------------------------------| +| sink | iotdb-thrift-ssl-sink | String: iotdb-thrift-ssl-sink | 必填 | - | +| node-urls | 目标端 IoTDB 任意多个 DataNode 节点的数据服务端口的 url(请注意同步任务不支持向自身服务进行转发) | String. 例:'127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| user/username | 连接接收端使用的用户名,同步要求该用户具备相应的操作权限 | String | 选填 | root | +| password | 连接接收端使用的用户名对应的密码,同步要求该用户具备相应的操作权限 | String | 选填 | TimechoDB@2021, V2.0.6.x 之前为root | +| batch.enable | 是否开启日志攒批发送模式,用于提高传输吞吐,降低 IOPS | Boolean: true, false | 选填 | true | +| batch.max-delay-seconds | 在开启日志攒批发送模式时生效,表示一批数据在发送前的最长等待时间(单位:s) | Integer | 选填 | 1 | +| batch.size-bytes | 在开启日志攒批发送模式时生效,表示一批数据最大的攒批大小(单位:byte) | Long | 选填 | 16*1024*1024 | +| compressor | 所选取的 rpc 压缩算法,可配置多个,对每个请求顺序采用 | String: snappy / gzip / lz4 / zstd / lzma2 | 选填 | "" | +| compressor.zstd.level | 所选取的 rpc 压缩算法为 zstd 时,可使用该参数额外配置 zstd 算法的压缩等级 | Int: [-131072, 22] | 选填 | 3 | +| rate-limit-bytes-per-second | 每秒最大允许传输的 byte 数,计算压缩后的 byte(如压缩),若小于 0 则不限制 | Double: [Double.MIN_VALUE, Double.MAX_VALUE] | 选填 | -1 | +| load-tsfile-strategy | 文件同步数据时,接收端请求返回发送端前,是否等待接收端本地的 load tsfile 执行结果返回。
sync:等待本地的 load tsfile 执行结果返回;
async:不等待本地的 load tsfile 执行结果返回。 | String: sync / async | 选填 | sync | +| ssl.trust-store-path | 连接目标端 DataNode 所需的 trust store 证书路径 | String.Example: '127.0.0.1:6667,127.0.0.1:6668,127.0.0.1:6669', '127.0.0.1:6667' | 必填 | - | +| ssl.trust-store-pwd | 连接目标端 DataNode 所需的 trust store 证书密码 | Integer | 必填 | - | +| format | 数据传输的payload格式, 可选项包括:
- hybrid: 取决于 processor 传递过来的格式(tsfile或tablet),sink不做任何转换。
- tsfile:强制转换成tsfile发送,可用于数据文件备份等场景。
- tablet:强制转换成tsfile发送,可用于发送端/接收端数据类型不完全兼容时的数据同步(以减少报错)。 | String: hybrid / tsfile / tablet | 选填 | hybrid | diff --git a/src/zh/UserGuide/latest/User-Manual/Data-subscription.md b/src/zh/UserGuide/latest/User-Manual/Data-subscription_apache.md similarity index 99% rename from src/zh/UserGuide/latest/User-Manual/Data-subscription.md rename to src/zh/UserGuide/latest/User-Manual/Data-subscription_apache.md index cb46617a5..8c95f84f8 100644 --- a/src/zh/UserGuide/latest/User-Manual/Data-subscription.md +++ b/src/zh/UserGuide/latest/User-Manual/Data-subscription_apache.md @@ -127,7 +127,7 @@ SHOW SUBSCRIPTIONS ON ## 4. API 接口 -除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API.md))。 +除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API_apache))。 ## 5. 常见问题 diff --git a/src/zh/UserGuide/latest/User-Manual/Data-subscription_timecho.md b/src/zh/UserGuide/latest/User-Manual/Data-subscription_timecho.md new file mode 100644 index 000000000..77267b8e7 --- /dev/null +++ b/src/zh/UserGuide/latest/User-Manual/Data-subscription_timecho.md @@ -0,0 +1,144 @@ +# 数据订阅 + +## 1. 功能介绍 + +IoTDB 数据订阅模块(又称 IoTDB 订阅客户端)是IoTDB V1.3.3 版本后支持的功能,它为用户提供了一种区别于数据查询的流式数据消费方式。它参考了 Kafka 等消息队列产品的基本概念和逻辑,**提供数据订阅和消费接口**,但并不是为了完全替代这些消费队列的产品,更多的是在简单流式获取数据的场景为用户提供更加便捷的数据订阅服务。 + +在下面应用场景中,使用 IoTDB 订阅客户端消费数据会有显著的优势: + +1. **持续获取最新数据**:使用订阅的方式,比定时查询更实时、应用编程更简单、系统负担更小; +2. **简化数据推送至第三方系统**:无需在 IoTDB 内部开发不同系统的数据推送组件,可以在第三方系统内实现数据的流式获取,更方便将数据发送至 Flink、Kafka、DataX、Camel、MySQL、PG 等系统。 + +## 2. 主要概念 + +IoTDB 订阅客户端包含 3 个核心概念:Topic、Consumer、Consumer Group,具体关系如下图 + +
+ +
+ +1. **Topic(主题)**: Topic 是 IoTDB 的数据空间,由路径和时间范围表示(如 root.** 的全时间范围)。消费者可以订阅这些主题的数据(当前已有的和未来写入的)。不同于 Kafka,IoTDB 可在数据入库后再创建 Topic,且输出格式可选择 Message 或 TsFile 两种。 + +2. **Consumer(消费者)**: Consumer 是 IoTDB 的订阅客户端,负责接收和处理发布到特定 Topic 的数据。Consumer 从队列中获取数据并进行相应的处理。在 IoTDB 订阅客户端中提供了两种类型的 Consumers: + - 一种是 `SubscriptionPullConsumer`,对应的是消息队列中的 pull 消费模式,用户代码需要主动调用数据获取逻辑 + - 一种是 `SubscriptionPushConsumer`,对应的是消息队列中的 push 消费模式,用户代码由新到达的数据事件触发 + +3. **Consumer Group(消费者组)**: Consumer Group 是一组 Consumers 的集合,拥有相同 Consumer Group ID 的消费者属于同一个消费者组。Consumer Group 有以下特点: + - Consumer Group 与 Consumer 为一对多的关系。即一个 consumer group 中的 consumers 可以有任意多个,但不允许一个 consumer 同时加入多个 consumer groups + - 允许一个 Consumer Group 中有不同类型的 Consumer(`SubscriptionPullConsumer` 和 `SubscriptionPushConsumer`) + - 一个 topic 不需要被一个 consumer group 中的所有 consumer 订阅 + - 当同一个 Consumer Group 中不同的 Consumers 订阅了相同的 Topic 时,该 Topic 下的每条数据只会被组内的一个 Consumer 处理,确保数据不会被重复处理 + +## 3. SQL 语句 + +### 3.1 Topic 管理 + +IoTDB 支持通过 SQL 语句对 Topic 进行创建、删除、查看操作。Topic状态变化如下图所示: + +
+ +
+ +#### 3.1.1 创建 Topic + +SQL 语句为: + +```SQL + CREATE TOPIC [IF NOT EXISTS] + WITH ( + [ = ,], + ); +``` +**IF NOT EXISTS 语义**:用于创建操作中,确保当指定 Topic 不存在时,执行创建命令,防止因尝试创建已存在的 Topic 而导致报错。 + +各参数详细解释如下: + +| 参数 | 是否必填(默认值) | 参数含义 | +| :-------------------------------------------- | :--------------------------------- | :----------------------------------------------------------- | +| **path** | optional: `root.**` | topic 对应订阅数据时间序列的路径 path,表示一组需要订阅的时间序列集合 | +| **start-time** | optional: `MIN_VALUE` | topic 对应订阅数据时间序列的开始时间(event time)可以为 ISO 格式,例如 2011-12-03T10:15:30 或 2011-12-03T10:15:30+01:00也可以为 long 值,含义为裸时间戳,单位与数据库时间戳精度一致支持特殊 value **`now`**,含义为 topic 的创建时间,当 start-time 为 `now` 且 end-time 为 MAX_VALUE 时表示只订阅实时数据 | +| **end-time** | optional: `MAX_VALUE` | topic 对应订阅数据时间序列的结束时间(event time)可以为 ISO 格式,例如 2011-12-03T10:15:30 或 2011-12-03T10:15:30+01:00也可以为 long 值,含义为裸时间戳,单位与数据库时间戳精度一致支持特殊 value `now`,含义为 topic 的创建时间,当 end-time 为 `now` 且 start-time 为 MIN_VALUE 时表示只订阅历史数据 | +| **processor** | optional: `do-nothing-processor` | processor 插件名及其参数配置,表示对原始订阅数据应用的自定义处理逻辑,可以通过类似 pipe processor 插件的方式指定 | +| **format** | optional: `SessionDataSetsHandler` | 表示从该主题订阅出的数据呈现形式,目前支持下述两种数据形式:`SessionDataSetsHandler`:使用 `SubscriptionSessionDataSetsHandler` 获取从该主题订阅出的数据,消费者可以按行消费每条数据`TsFileHandler`:使用 `SubscriptionTsFileHandler` 获取从该主题订阅出的数据,消费者可以直接订阅到存储相应数据的 TsFile | +| **mode** **(v1.3.3.2 及之后版本支持)** | option: `live` | topic 对应的订阅模式,有两个选项:`live`:订阅该主题时,订阅的数据集模式为动态数据集,即可以不断消费到最新的数据`snapshot`:consumer 订阅该主题时,订阅的数据集模式为静态数据集,即 consumer group 订阅该主题的时刻(不是创建主题的时刻)数据的 snapshot;形成订阅后的静态数据集不支持 TTL | +| **loose-range** **(v1.3.3.2 及之后版本支持)** | option: `""` | String: 是否严格按照 path 和 time range 来筛选该 topic 对应的数据,例如:`""`:严格按照 path 和 time range 来筛选该 topic 对应的数据`"time"`:不严格按照 time range 来筛选该 topic 对应的数据(粗筛);严格按照 path 来筛选该 topic 对应的数据`"path"`:不严格按照 path 来筛选该 topic 对应的数据(粗筛);严格按照 time range 来筛选该 topic 对应的数据`"time, path"` / `"path, time"` / `"all"`:不严格按照 path 和 time range 来筛选该 topic 对应的数据(粗筛) | + +示例如下: + +```SQL +-- 全量订阅 +CREATE TOPIC root_all; + +-- 自定义订阅 +CREATE TOPIC IF NOT EXISTS db_timerange +WITH ( + 'path' = 'root.db.**', + 'start-time' = '2023-01-01', + 'end-time' = '2023-12-31' +); +``` + +#### 3.1.2 删除 Topic + +Topic 在没有被订阅的情况下,才能被删除,Topic 被删除时,其相关的消费进度都会被清理 + +```SQL +DROP TOPIC [IF EXISTS] ; +``` + +**IF EXISTS 语义**:用于删除操作中,确保当指定 Topic 存在时,执行删除命令,防止因尝试删除不存在的 Topic 而导致报错。 + +#### 3.1.3 查看 Topic + +```SQL +SHOW TOPICS; +SHOW TOPIC ; +``` + +结果集: + +```SQL +[TopicName|TopicConfigs] +``` + +- TopicName:主题 ID +- TopicConfigs:主题配置 + +### 3.2 查看订阅状态 + +查看所有订阅关系: + +```SQL +-- 查询所有的 topics 与 consumer group 的订阅关系 +SHOW SUBSCRIPTIONS +-- 查询某个 topic 下所有的 subscriptions +SHOW SUBSCRIPTIONS ON +``` + +结果集: + +```SQL +[TopicName|ConsumerGroupName|SubscribedConsumers] +``` + +- TopicName:主题 ID +- ConsumerGroupName:用户代码中指定的消费者组 ID +- SubscribedConsumers:该消费者组中订阅了该主题的所有客户端 ID + +## 4. API 接口 + +除 SQL 语句外,IoTDB 还支持通过 Java 原生接口使用数据订阅功能。详细语法参见页面:Java 原生接口([链接](../API/Programming-Java-Native-API_timecho))。 + +## 5. 常见问题 + +### 5.1 IoTDB 数据订阅与 Kafka 的区别是什么? + +1. 消费有序性 + +- **Kafka 保证消息在单个 partition 内是有序的**,当某个 topic 仅对应一个 partition 且只有一个 consumer 订阅了这个 topic,即可保证该 consumer(单线程) 消费该 topic 数据的顺序即为数据写入的顺序。 +- IoTDB 订阅客户端**不保证** consumer 消费数据的顺序即为数据写入的顺序,但会尽量反映数据写入的顺序。 + +2. 消息送达语义 + +- Kafka 可以通过配置实现 Producer 和 Consumer 的 Exactly once 语义。 +- IoTDB 订阅客户端目前无法提供 Consumer 的 Exactly once 语义。 \ No newline at end of file diff --git a/src/zh/UserGuide/latest/User-Manual/IoTDB-View_timecho.md b/src/zh/UserGuide/latest/User-Manual/IoTDB-View_timecho.md index e5dc7c08f..6d86293d2 100644 --- a/src/zh/UserGuide/latest/User-Manual/IoTDB-View_timecho.md +++ b/src/zh/UserGuide/latest/User-Manual/IoTDB-View_timecho.md @@ -308,7 +308,7 @@ AS SELECT temperature FROM root.db.* ``` -这里仿照了查询写回(`SELECT INTO`)对命名规则的约定,使用变量占位符来指定命名规则。可以参考:[查询写回(SELECT INTO)](../Basic-Concept/Query-Data.md#查询写回(INTO-子句)) +这里仿照了查询写回(`SELECT INTO`)对命名规则的约定,使用变量占位符来指定命名规则。可以参考:[查询写回(SELECT INTO)](../Basic-Concept/Query-Data_timecho#查询写回(INTO-子句)) 这里`root.db.*.temperature`指定了有哪些时间序列会被包含在视图中;`${2}`则指定了从时间序列中的哪个节点提取出名字来命名序列视图。 diff --git a/src/zh/UserGuide/latest/User-Manual/User-defined-function_apache.md b/src/zh/UserGuide/latest/User-Manual/User-defined-function_apache.md index 7e6bef172..5101840d2 100644 --- a/src/zh/UserGuide/latest/User-Manual/User-defined-function_apache.md +++ b/src/zh/UserGuide/latest/User-Manual/User-defined-function_apache.md @@ -184,7 +184,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 用户在使用 UDF 时会涉及到 `USE_UDF` 权限,具备该权限的用户才被允许执行 UDF 注册、卸载和查询操作。 -更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management.md##权限管理)。 +更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management_apache##权限管理)。 ## 3. UDF 函数库 diff --git a/src/zh/UserGuide/latest/User-Manual/User-defined-function_timecho.md b/src/zh/UserGuide/latest/User-Manual/User-defined-function_timecho.md index b71338c08..885f31322 100644 --- a/src/zh/UserGuide/latest/User-Manual/User-defined-function_timecho.md +++ b/src/zh/UserGuide/latest/User-Manual/User-defined-function_timecho.md @@ -185,7 +185,7 @@ udf_reader_transformer_collector_memory_proportion=1:1:1 用户在使用 UDF 时会涉及到 `USE_UDF` 权限,具备该权限的用户才被允许执行 UDF 注册、卸载和查询操作。 -更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management.md##权限管理)。 +更多用户权限相关的内容,请参考 [权限管理语句](../User-Manual/Authority-Management_timecho##权限管理)。 ## 3. UDF 函数库