diff --git a/ACL_and_Security.md b/ACL_and_Security.md index 1626c739..2f1fa08d 100644 --- a/ACL_and_Security.md +++ b/ACL_and_Security.md @@ -1,4 +1,4 @@ -# DolphinDB 权限和安全 +# 权限管理和安全 DolphinDB database 提供了强大、灵活、安全的权限控制系统。控制节点(controller)作为权限管理中心,使用RSA加密方式对用户关键信息进行加密。 diff --git a/ARM_standalone_deploy.md b/ARM_standalone_deploy.md index 91b29b52..b53dc3bd 100644 --- a/ARM_standalone_deploy.md +++ b/ARM_standalone_deploy.md @@ -1,4 +1,4 @@ -# DolphinDB ARM单板部署 +# 单节点部署(嵌入式ARM版本) ## 1. 系统要求 diff --git a/README.md b/README.md index 72b0f4f2..867811ba 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ - 流计算 - [流数据教程](https://github.com/dolphindb/Tutorials_CN/blob/master/streaming_tutorial.md) - [流数据聚合引擎](https://github.com/dolphindb/Tutorials_CN/blob/master/stream_aggregator.md) - - [流数据横截面引擎](https://github.com/dolphindb/Tutorials_CN/blob/master/streaming_crossSectionalAggregator.md) - [流数据回放教程](https://github.com/dolphindb/Tutorials_CN/blob/master/historical_data_replay.md) - 系统管理 - [权限管理和安全](https://github.com/dolphindb/Tutorials_CN/blob/master/ACL_and_Security.md) @@ -32,14 +31,13 @@ - [Java API使用教程](https://github.com/dolphindb/api-java/blob/master/README_CN.md) - [C# API使用教程](https://github.com/dolphindb/api-csharp/blob/master/README_CN.md) - [C++ API使用教程](https://github.com/dolphindb/api-cplusplus/blob/master/README_CN.md) - - [C++ API 数据读写指南](https://github.com/dolphindb/Tutorials_CN/blob/master/c++api.md) - [Go API使用教程](https://github.com/dolphindb/api-go/blob/master/README.md) - [R API使用教程](https://github.com/dolphindb/api-r/blob/master/README_CN.md) - [Json API使用教程](https://github.com/dolphindb/api-json/blob/master/README_CN.md) - [redash连接DolphinDB数据源的教程](https://github.com/dolphindb/Tutorials_CN/blob/master/data_interface_for_redash.md) - [DolphinDB整合前端chart组件展示数据教程](https://github.com/dolphindb/Tutorials_CN/blob/master/web_chart_integration.md) - [Grafana连接DolphinDB数据源](https://github.com/dolphindb/grafana-datasource/blob/master/README_CN.md) - - [API协议](https://github.com/dolphindb/Tutorials_CN/blob/master/api_protocol.md) + - [API交互协议](https://github.com/dolphindb/Tutorials_CN/blob/master/api_protocol.md) - 插件 - [ODBC](https://github.com/dolphindb/DolphinDBPlugin/blob/master/odbc/README.md) - [MySQL](https://github.com/dolphindb/DolphinDBPlugin/blob/master/mysql/README_CN.md) @@ -56,7 +54,4 @@ - 应用场景示例 - [DolphinDB在工业物联网的应用](https://github.com/dolphindb/Tutorials_CN/blob/master/iot_demo.md) - [加密货币逐笔交易数据回放](https://github.com/dolphindb/applications/blob/master/cryptocurr_replay/README.md) - - [流数据高频因子计算教程](https://github.com/dolphindb/Tutorials_CN/blob/master/hf_factor_streaming.md) - [在DolphinDB中计算K线](https://github.com/dolphindb/Tutorials_CN/blob/master/OHLC.md) - - diff --git a/add_column.md b/add_column.md index 58354f70..051ed36d 100644 --- a/add_column.md +++ b/add_column.md @@ -1,3 +1,5 @@ +# 动态增加字段和计算指标 + 工业物联网采集的数据和金融交易数据具有相同的特点:频率高、维度多、数据一旦生成就不会改变、数据量庞大,并且工业物联网数据采集的维度和实时计算的指标会随着业务扩展和设备增加而不断增加,金融领域的数据分析和监控需要不断增加风控监测指标。因此,工业物联网和金融领域的数据平台必须能够满足动态增加字段和计算指标的需求。 DolphinDB database 为工业物联网和金融提供了一站式解决方案。数据处理流程如下图所示: diff --git a/api_protocol.md b/api_protocol.md index 8f53f63e..157c0028 100644 --- a/api_protocol.md +++ b/api_protocol.md @@ -1,4 +1,4 @@ -# DolphinDB API 交互协议 +# API交互协议 DolphinDB API有以下三个交互阶段: * 连接 diff --git a/c++api.md b/c++api.md index e56d55d0..00cabc11 100644 --- a/c++api.md +++ b/c++api.md @@ -1,4 +1,4 @@ -# DolphinDB C++ API 数据读写指南 +# C++ API 数据读写指南 DolphinDB C++ API是由DolphinDB提供的应用程序接口,可以用来与DolphinDB server进行交互。 @@ -218,4 +218,4 @@ while (start < N) { } start += len; } -``` +``` \ No newline at end of file diff --git a/docker_deployment.md b/docker_deployment.md index 66b3190f..aec884fc 100644 --- a/docker_deployment.md +++ b/docker_deployment.md @@ -1,4 +1,4 @@ -## 基于Docker的DolphinDB集群部署教程 +## 基于Docker的集群部署教程 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。DolphinDB database提供了基于docker的分布式集群部署包,可以让用户方便快捷的部署DolphinDB分布式集群。 diff --git a/hf_factor_streaming.md b/hf_factor_streaming.md index ad27159f..5c461449 100644 --- a/hf_factor_streaming.md +++ b/hf_factor_streaming.md @@ -1,8 +1,22 @@ ### 高频因子的实时计算 +本示例通过DolphinDB实现市场行情数据实时计算因子,本例中使用到了DolphinDB以下功能: + +* 流数据发布 + + 用户通过API将实时的市场数据写入到DolphinDB的流数据表中,流数据表的数据可在DolphinDB中通过订阅的方式进行实时处理。 + +* 流数据订阅 + + 当实时市场数据进入流数据表之后,通过订阅函数`subscribeTable`可以将实时数据和数据处理函数之间建立关联,使得进入流数据表的数据被即时处理。 + +* 并行计算 + + 当需要使用同一份流数据计算多个因子时,通过使用`ploop`高阶函数结合`call`函数,在同一个订阅处理函数中实现并行多因子计算,提高数据的处理效率。 + #### 1. 系统配置 -本次示例程序的服务器程序采用单机模式启动,启用流数据发布和订阅,配置文件的配置建议如下(默认配置文件为dolphindb.cfg): +本次示例程序的服务器程序采用单机模式启动,启用流数据发布和订阅。配置文件(默认为dolphindb.cfg)的内容建议如下: ``` mode=single maxPubConnections=8 @@ -13,105 +27,158 @@ maxMemSize=24 单机模式启动后,默认端口为8848. -#### 2. 模拟产生高频数据 +#### 2. 模拟产生高频交易数据 -模拟产生100只股票的数据。symbol从1到100,总共100,000,000条记录,22列:symbol, time, ap1..ap5, bp1..bp5, av1..av5, bv1..bv5。 限制:ap1bp2>bp3>bp4>bp5, 均为小数点后两位。 +模拟产生100只股票的数据。symbol从000001到000100,总共100,000,000条记录,22列:symbol, time, ap1..ap5, bp1..bp5, av1..av5, bv1..bv5。其中ap1..ap5代表前5档卖方出价,av1..av5代表卖方出价对应的量,bp1..bp5以及bv1..bv5为前5档买方出价以及对应的量。我们对模拟数据做如下限制:ap1bp2>bp3>bp4>bp5, 均为小数点后两位。 * 创建流数据表tick,以存放高频数据。 ``` def createTickTable(){ - share(streamTable(1000:0, `symbol`time`ap1`ap2`ap3`ap4`ap5`bp1`bp2`bp3`bp4`bp5`av1`av2`av3`av4`av5`bv1`bv2`bv3`bv4`bv5, [SYMBOL,TIME,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE]), `tick) + share(streamTable(1000:0, `symbol`time`ap1`ap2`ap3`ap4`ap5`bp1`bp2`bp3`bp4`bp5`av1`av2`av3`av4`av5`bv1`bv2`bv3`bv4`bv5`mp, [SYMBOL,TIME,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,INT]), `tick) + clearTablePersistence(objByName(`tick)) + enableTablePersistence(table=objByName(`tick), cacheSize=100000) } createTickTable() ``` -* 定义generateData函数,在每个时间戳生成1-10笔随机数据,并写入tick表。此函数将在任务提交时执行。 +* 定义generateData函数,循环生成100,000,000笔成交记录,并写入tick表。此函数将在任务提交时执行。 ``` def generateData(times){ for(j in 0..times){ - batchSize = rand(1..10,1)[0] - for(i in 0..batchSize){ - sym = rand(symbol(string(1..100)), batchSize) - tim = take(time(now()),batchSize) - ap1= rand(100..150, batchSize)/100.0 - ap2= rand(151..200, batchSize)/100.0 - ap3= rand(201..250, batchSize)/100.0 - ap4= rand(251..300, batchSize)/100.0 - ap5= rand(301..350, batchSize)/100.0 - bp1= rand(100..150, batchSize)/100.0 - bp2= rand(151..200, batchSize)/100.0 - bp3= rand(201..250, batchSize)/100.0 - bp4= rand(251..300, batchSize)/100.0 - bp5= rand(301..350, batchSize)/100.0 - av1= rand(100..500, batchSize) - av2= rand(100..500, batchSize) - av3= rand(100..500, batchSize) - av4= rand(100..500, batchSize) - av5= rand(100..500, batchSize) - bv1= rand(100..500, batchSize) - bv2= rand(100..500, batchSize) - bv3= rand(100..500, batchSize) - bv4= rand(100..500, batchSize) - bv5= rand(100..500, batchSize) - data = table(sym as symbol,tim as time,ap1,ap2,ap3,ap4,ap5,bp1,bp2,bp3,bp4,bp5,av1,av2,av3,av4,av5,bv1,bv2,bv3,bv4,bv5) - objByName(`tick).tableInsert(data) - } + batchSize = 1 + sym = rand(symbol(lpad(string(1..100),6,"0")), batchSize) + tim = take(time(now()),batchSize) + ap1= rand(100..105, batchSize)/100.0 + ap2= rand(100..105, batchSize)/100.0 + ap3= rand(100..105, batchSize)/100.0 + ap4= rand(100..105, batchSize)/100.0 + ap5= rand(100..105, batchSize)/100.0 + bp1= rand(100..107, batchSize)/100.0 + bp2= rand(100..107, batchSize)/100.0 + bp3= rand(100..107, batchSize)/100.0 + bp4= rand(100..107, batchSize)/100.0 + bp5= rand(100..107, batchSize)/100.0 + av1= rand(100..500, batchSize) + av2= rand(100..500, batchSize) + av3= rand(100..500, batchSize) + av4= rand(100..500, batchSize) + av5= rand(100..500, batchSize) + bv1= rand(100..500, batchSize) + bv2= rand(100..500, batchSize) + bv3= rand(100..500, batchSize) + bv4= rand(100..500, batchSize) + bv5= rand(100..500, batchSize) + mp= rand(1..10, batchSize) + data = table(sym as symbol,tim as time,ap1,ap2,ap3,ap4,ap5,bp1,bp2,bp3,bp4,bp5,av1,av2,av3,av4,av5,bv1,bv2,bv3,bv4,bv5,mp) + objByName(`tick).tableInsert(data) } } ``` -#### 3. DolphinDB订阅高频数据并实时计算2个因子 +#### 3. DolphinDB订阅高频数据,实时计算因子 + +本示例中需要计算5个因子factor1~5。 +* 其中1~3号因子使用当前数据计算得到 +* 4~5号时序数据相关因子,需要结合历史数据计算,所以需要传入完整的tick表。在满足因子计算的前提下,tick表设置在内存中保留不超过100000行记录。 + +实现思路如下 -本例中,需要计算以下两个因子: +* 实现各因子的计算函数。 +* 在流数据订阅处理函数中,将订阅到的流数据作为参数传递给因子计算函数。 +* 在需要计算较多的因子的情况下,可以使用并行方式调用计算函数。在示例中用 `ploop` + `call`函数的结合即可实现。 +* 并行计算得到的结果合并保存到factor表中,factor结构如下: + + symbol | time | factorValue | factorType + ---|---|---|--- + 000001 | 17:38:41.894 | 0.024329 | factor1 + +具体的实现脚本如下: + +* 因子的实现函数 ``` -factor1 = (av1-bv1)/(av1+bv1) -factor2 = (av1+av2+av3+av4+av5-bv1-bv2-bv3-bv4-bv5)/(av1+av2+av3+av4+av5+bv1+bv2+bv3+bv4+bv5) +def factor1(t){ + return select symbol,time(now()) as time, (av1-bv1)/(av1+bv1) as factorValue, "factor1" as factorType from t +} + +def factor2(t){ + return select symbol,time(now()) as time, (av1+av2+av3+av4+av5-bv1-bv2-bv3-bv4-bv5)/ (av1+av2+av3+av4+av5+bv1+bv2+bv3+bv4+bv5) as factorValue, "factor2" as factorType from t +} +def factor3(t){ + w = exp(-10 * 0..4/t.mp[0]) + return select symbol, time(now()) as time, 0.5*log(rowSum([bv1,bv2,bv3,bv4,bv5]*w)/rowSum([av1,av2,av3,av4,av5]*w)) as factorValue, "factor3" as factorType from t +} +def factor4(tickTable, t){ + sym = exec distinct(symbol) from t + t1 = select symbol,ap1/mavg(ap1, 30)-1 as factorValue from tickTable where symbol in sym context by symbol + return select symbol,time(now()) as time, factorValue, "factor4" as factorType from t1 where !isNull(factorValue) +} +def factor5(tickTable, t){ + sym = exec distinct(symbol) from t + t1 = select symbol, ap1/move(ap1, 30)-1 as factorValue from tickTable where symbol in sym context by symbol + return select symbol,time(now()) as time, factorValue, "factor5" as factorType from t1 where !isNull(factorValue) +} ``` -* 创建因子表factor,以存放因子计算结果。 +* 创建数据表factor,以存放因子计算结果。 ``` def createFactorTable(){ - t=streamTable(100:0, `symbol`time`factor1`factor2, [SYMBOL,TIME,DOUBLE,DOUBLE]); - share(t,`factor) + t = streamTable(100:0, `symbol`time`factorValue`factorType, [SYMBOL,TIME, DOUBLE, SYMBOL]); + share(t,`factor ) } createFactorTable() ``` -* 定义函数factorHandler,以计算因子。 +* 定义函数factorHandler作为流数据的处理函数,多个因子通过`ploop`结合`call`并行计算。 ``` -def factorHandler(mutable dst, msg){ - data = select symbol, time(now()) as time, (av1-bv1)/(av1+bv1) as factor1, (av1+av2+av3+av4+av5-bv1-bv2-bv3-bv4-bv5)/(av1+av2+av3+av4+av5+bv1+bv2+bv3+bv4+bv5) as factor2 from msg - dst.tableInsert(data) +def factorHandler(mutable factorTable, tickTable, msg){ + funcs = [factor1{msg}, factor2{msg}, factor3{msg}, factor4{tickTable,msg}, factor5{tickTable,msg}] + factorTable.tableInsert(ploop(call, funcs).unionAll(false)) } ``` -* 订阅Level 2 行情数据数据,并实时计算因子。 - +* 设置市场实时数据的订阅,将实时数据和因子计算函数相关联。 +本示例中除了必要参数,其他订阅参数都采用默认值。若实时数据流入速度非常快,而因子计算相对较慢,可能会导致处理滞后。此时可以调整batchSize和throttle等参数,使得实时数据的处理速度匹配流入速度。具体的参数含义以及流数据性能调优可以参考[DolphinDB流数据教程](https://github.com/dolphindb/Tutorials_CN/blob/master/streaming_tutorial.md)。 + + ``` +subscribeTable(tableName=`tick, actionName=`createFactor, handler=factorHandler{objByName(`factor), objByName(`tick)}, msgAsTable=true) ``` -//msgAsTable参数为true,订阅收到的数据会以table方式传递给factorHandler,方便在factorHandler内部使用sql进行数据操作。 -subscribeTable(tableName=`tick, actionName=`createFactor, handler=factorHandler{objByName(`factor)}, msgAsTable=true) -``` +以上代码中,msgAsTable参数设为true,订阅收到的数据会以table的形式传递给factorHandler,方便在factorHandler内部使用SQL语句进行数据操作。 -* 提交产生模拟数据的任务,数据生成后即写入流数据表tick中,并触发流数据计算任务。计算结果写入factor表中。 +* 提交产生模拟数据的任务,模拟数据每次随机提交1到10行数据写入流数据表tick中,每次提因子计算函数都会被触发。 ``` -submitJob("gendata", "generate data", generateData, 5000000) +submitJob("gendata", "generate data", generateData, 100000000) ``` #### 4.观察结果 +* 在GUI中运行如下代码,查看因子的线性趋势图: + ``` -//观察最新计算的10条记录 -select top 10 * from objByName(`factor) order by time desc +t = select last(factorValue) as factorValue from factor where symbol = `000001,factorType=`factor1 group by time +plot(t.factorValue, t.time) +``` + +* 可以通过 pivot by 关键字,对不同因子进行行列转置,得到按不同因子横向排列的最新计算结果: ``` -#### 5.通过Api订阅和处理因子数据 +select factorValue from factor pivot by symbol, factorType +``` -##### 5.1 Java Api订阅例子 +symbol | factor1 | factor2 | factor3 |factor4 | factor5 +---|---|---|---|---|--- +1 |0.192389|0.015152|-0.184673|-0.184673|-0.184673 +2 |-0.300448|0.01182|0.273232|-0.184673|-0.184673 +3 |0.165049|-0.002542|-0.101841|-0.184673|-0.184673 -* 主程序代码 +#### 5.通过API订阅和处理因子数据 -``` -import com.xxdb.streaming.client.ThreadedClient; +在上述示例中,因子的计算结果保存到流数据表中,当第三方程序需要实时获取因子的计算结果并进行后续处理或者显示时,可以通过流数据API来订阅结果表。以下代码展示了Java和Python使用API订阅流数据的例子。本示例中统一使用了本地端口20002来进行数据订阅。 + +##### 5.1 Java API订阅例子 + +* Java 订阅因子表 +```java +import com.xxdb.streaming.client.ThreadedClient; import java.io.IOException; public class main { @@ -124,7 +191,7 @@ public class main { ``` * 订阅处理FactorHandler代码 -``` +```java import com.xxdb.data.BasicDouble; import com.xxdb.data.BasicString; @@ -143,20 +210,19 @@ public class FactorHandler implements MessageHandler { System.out.println(symbol.getString() + " | " + time.getString() + " | " + factor1.getString() + " | " + factor2.getString()); } } - ``` -##### 5.2 Python Api订阅例子 +##### 5.2 Python API订阅例子 * Python订阅代码 ```python import dolphindb as ddb import numpy as np s = ddb.session() -s.enableStreaming(18819) +s.enableStreaming(20002) def myHandler(lst): print(lst) -s.subscribe("localhost",8848,handler,"factor","sub_factor",-1,False,None) +s.subscribe("localhost", 8848, myHandler, "factor", "sub_factor", -1,False, None) ``` diff --git a/historical_data_replay.md b/historical_data_replay.md index c83d67a3..016c1aa3 100644 --- a/historical_data_replay.md +++ b/historical_data_replay.md @@ -1,4 +1,4 @@ -# DolphinDB历史数据回放教程 +# 流数据回放教程 一个量化策略在用于实际交易时,处理实时数据的程序通常为事件驱动。而研发量化策略时,需要使用历史数据进行回测,这时的程序通常不是事件驱动。因此同一个策略需要编写两套代码,不仅耗时而且容易出错。在DolphinDB中,用户可将历史数据按照时间顺序以“实时数据”的方式导入流数据表中,这样就可以使用同一套代码进行回测和实盘交易。 diff --git a/hybrid_programming_paradigms.md b/hybrid_programming_paradigms.md index 161d7b91..482789b0 100644 --- a/hybrid_programming_paradigms.md +++ b/hybrid_programming_paradigms.md @@ -1,19 +1,19 @@ -# DolphinDB脚本语言的混合范式编程 +# 脚本语言的混合范式编程 开发大数据应用,不仅需要一个能支撑海量数据的分布式数据库,一个能高效利用多核多节点的分布式计算框架,更需要一门能与分布式数据库和分布式计算有机融合,高性能易扩展,表达能力强,满足快速开发和建模需要的编程语言。DolphinDB从流行的SQL和Python语言汲取了灵感,设计了大数据处理脚本语言。本教程讲解如何通过混合范式编程,快速开发大数据分析的应用。从中你也可以了解DolpinDB的编程语言(以下简称DolphinDB)如何与数据库和分布式计算融合。 ## 1. 向量化编程(Vector Programming) -向量化编程是DolphinDB中最基本的编程范式。DolphinDB中绝大部分函数支持向量作为函数的输入参数。函数的返回值一般为两种,一种是标量(scalar),这类函数称为聚合函数(aggregate function)。另一种返回与输入向量等长的向量,称之为向量函数。 +向量化编程是DolphinDB中最基本的编程范式。DolphinDB中绝大部分函数支持向量作为函数的输入参数。根据函数的返回值的不同,函数可分为两种:一种是聚合函数(aggregate function),返回标量(scalar);另一种是向量函数,返回与输入向量等长的向量。 向量化操作有三个主要优点: - 代码简洁 - 大幅降低脚本语言的解释成本 - 可对很多算法进行优化 -时间序列数据通常可以用一个向量来表示,用于数据分析的列式数据库的每一个列也都可以用向量来表示。DolphinDB作为一个内存计算引擎或者作为一个分析型的数据仓库,在进行时间序列数据分析的时候,特别适合使用向量化编程。 +时间序列数据通常可以用一个向量来表示,用于数据分析的列式数据库的每一个列也都可以用向量来表示。DolphinDB作为一个内存计算引擎或者作为一个分析型的数据仓库,在进行时间序列数据分析时,特别适合使用向量化编程。 -下面的例子为两个长度为一千万的向量相加。用命令式编程的for语句,不仅语句冗长,而且耗时是向量化编程的百倍以上。 +以两个长度为一千万的向量相加作为一个简单例子。用命令式编程的for语句,不仅语句冗长,而且耗时是向量化编程的百倍以上。 ``` n = 10000000 @@ -29,11 +29,7 @@ for(i in 0 : n) c = a + b ``` -向量化编程实际上是对一组同质数据的批处理,不仅在编译阶段可以利用vectorization对指令进行优化,在很多算法上也可以优化。 -以经常使用的时间序列数据滑动窗口(sliding window)指标之一的移动平均(moving average)为例。假设总的数据量是n,窗口大小为k,如果不采用批量计算,时间复杂度是O(nk)。 -但是因为计算完一个窗口的移动平均后,计算下一个窗口时,只有一个数据点发生了变化,所以只要调整这一个点的值,就可以算出新窗口的移动平均,所以批量计算的时间复杂度是O(n)。DolphinDB中,大部分计算滑动窗口指标的函数都经过了优化,性能近似于O(n)。 -这些函数包括`mmax`, `mmin`, `mimax`, `mimin`, `mavg`, `msum`, `mcount`, `mstd`, `mvar`, `mrank`, `mcorr`, `mcovar`, `mbeta` 和 `mmed`。 -在下例中,经过优化的`mavg`函数的性能超过对每一个窗口使用`avg`函数300倍。 +向量化编程实际上是对一组同质数据的批处理,不仅在编译阶段可以利用vectorization对指令进行优化,在很多算法上也可以优化。以经常使用的时间序列数据滑动窗口(sliding window)指标之一的移动平均(moving average)为例。假设总的数据量是n,窗口大小为k,如果不采用批量计算,时间复杂度是O(nk)。但是因为计算完一个窗口的移动平均后,计算下一个窗口时,只有一个数据点发生了变化,所以只要调整这一个点的值,就可以算出新窗口的移动平均,所以批量计算的时间复杂度是O(n)。DolphinDB中,大部分计算滑动窗口指标的函数都经过了优化,性能近似于O(n)。这些函数包括`mmax`, `mmin`, `mimax`, `mimin`, `mavg`, `msum`, `mcount`, `mstd`, `mvar`, `mrank`, `mcorr`, `mcovar`, `mbeta` 和 `mmed`。在下例中,经过优化的`mavg`函数的性能超过对每一个窗口使用`avg`函数300倍。 ``` n = 10000000 @@ -51,13 +47,13 @@ timer mavg(a, window); Time elapsed: 12.968 ms ``` -向量化编程也有其局限性。首先,不是所有的操作都可以用向量化计算来完成。在机器学习和统计分析中,有不少场景,我们只能对逐行数据进行迭代处理,无法向量化计算。针对这种场景,DolphinDB计划在后续的版本中推出即时编译技术(JIT),能将用for语句编写的逐行处理代码在运行时动态编译成机器码来执行,显著提升性能。 +向量化编程也有其局限性。首先,不是所有的操作都可以用向量化计算来完成。在机器学习和统计分析中,在某些场景下,我们只能对逐行数据进行迭代处理,无法向量化计算。针对这种场景,DolphinDB计划在后续的版本中推出即时编译技术(JIT),能将用for语句编写的逐行处理代码在运行时动态编译成机器码来执行,显著提升性能。 其次,向量化计算通常要将整个向量全部加载到一段连续内存中,Matlab和R都有这样的要求。有时候因为内存碎片原因,无法找到大段的连续内存。DolphinDB针对内存碎片,特别引入了`big array`,可以将物理上不连续的内存块组成一个逻辑上连续的向量。系统是否采用big array是动态决定的,对用户透明。通常,对big array进行扫描,性能损耗对于连续内存而言,在1%~5%之间;对big array进行随机访问,性能损耗在20%~30%左右。在此方面,DolphinDB是以可以接受的少量性能损失来换取系统的更高可用性。 ## 2. SQL编程 (SQL Programming) -SQL是一个面向问题的语言。用户只需要给出问题的描述,由SQL引擎给出结果。通常SQL引擎属于数据库的一部分,其它系统通过JDBC,ODBC或Native API 与数据库交流。DolphinDB脚本语言的SQL语句不仅支持SQL的标准功能,而且为大数据的分析,尤其是时间序列大数据的分析做了很多扩展,可极大简化代码,方便用户使用。 +SQL是一个面向问题的语言。用户只需要给出问题的描述,SQL引擎会产生结果。通常SQL引擎属于数据库的一部分,其它系统通过JDBC,ODBC或Native API 与数据库交流。DolphinDB脚本语言的SQL语句不仅支持SQL的标准功能,而且为大数据的分析,尤其是时间序列大数据的分析做了很多扩展,可极大简化代码,方便用户使用。 ### 2.1 SQL与编程语言的融合 @@ -67,7 +63,7 @@ SQL是一个面向问题的语言。用户只需要给出问题的描述,由SQ - SQL语句不再是一个简单的字符串,而是可以动态生成的代码。 - SQL语句不仅可以对数据表(table)进行操作,也可对其它数据结构如scalar,vector,matrix,set,dictionary进行操作。数据表可以与其它数据结构进行转换。 -请注意,DolphinDB编程语言区分大小写。在DolphinDB中所有的SQL关键词均`必须`使用小写。 +请注意,DolphinDB编程语言区分大小写。在DolphinDB中所有的SQL关键词均必须使用小写。 下面例子中,首先生成一个员工工资表: @@ -103,7 +99,7 @@ id name avg_wage 9 Kevin 5500 ``` -上面的两个例子中,SQL语句的where子句和select子句分别用到了上下文中定义的数组和字典,使得本来需要通过子查询和多表联结来解决的问题,通过简单的hash table解决了。如果SQL涉及到分布式数据库,这些上下文变量会自动序列化到相应的节点。这不仅让代码看上去更简洁,有更好的可读性,而且提升了性能。即使SQL优化器做了很多优化,在大数据分析中很多数据表关联的操作仍然存在性能问题。 +上面的两个例子中,SQL语句的where子句和select子句分别用到了上下文中定义的数组和字典,使得本来需要通过子查询和多表联结来解决的问题,通过简单的hash table就解决了。如果SQL涉及到分布式数据库,这些上下文变量会自动序列化到相应的节点。这不仅让代码看上去更简洁,有更好的可读性,而且提升了性能。 SQL的select语句返回的数据表可以直接赋给一个本地变量,做进一步的处理分析。DolphinDB还引入了exec关键词,与select相比,EXEC语句返回的结果可以是一个matrix,vector或scalar,更便于数据分析。下面的例子中,exec与pivot by配合使用,直接返回一个矩阵。 @@ -126,14 +122,16 @@ exec first(wage) from emp_wage pivot by month, id; ### 2.2 对面板数据(Panel Data)的友好支持 -SQL的group by子句将数据分成多组,每组产生一个值,也就是一行。因此使用group by子句后,行数一般会大大减少。在对面板数据进行分组后,每一组数据通常是时间序列数据,譬如按股票分组,每一个组内的数据是一个股票的价格序列。处理面板数据时,有时候希望保持每一个组的数据行数,也就是为组内的每一行数据生成一个值。例如,根据一个股票的价格序列生成回报序列,或者根据价格序列生成一个移动平均价格序列。其它数据库系统(例如SQL Server,PostGreSQL),用window function来解决这个问题。DolpinDB引入了context by子句来处理面板数据。context by与window function相比,除了语法更简洁,设计更系统(与group by和pivot by一起组成对分组数据处理的三个子句)外,表达能力上也更强大,具体表现在下面三个方面 -: +SQL的group by子句将数据分成多组,每组产生一个值,也就是一行。因此使用group by子句后,行数一般会大大减少。 + +在对面板数据进行分组后,每一组数据通常是时间序列数据,譬如按股票分组,每一个组内的数据是一个股票的价格序列。处理面板数据时,有时候希望保持每个组的数据行数,也就是为组内的每一行数据生成一个值。例如,根据一个股票的价格序列生成回报序列,或者根据价格序列生成一个移动平均价格序列。其它数据库系统(例如SQL Server,PostGreSQL),用窗口函数(window function)来解决这个问题。DolpinDB引入了context by子句来处理面板数据。context by与窗口函数相比,除了语法更简洁,设计更系统化(与group by和pivot by一起组成对分组数据处理的三个子句)以外,表达能力上也更强大,具体表现在下面三个方面: + - 不仅能与select配合在查询中使用,也可以与update配合更新数据。 -- 绝大多数数据库系统在window function中只能使用表中现有的字段分组。context by子句可以使用任何现有字段和计算字段。 -- window function仅限于少数几个函数。context by不仅不限制使用的函数,而且可以使用任意表达式,譬如多个函数的组合。 +- 绝大多数数据库系统在窗口函数中只能使用表中现有的字段分组。context by子句可以使用任何现有字段和计算字段。 +- 窗口函数仅限于少数几个函数。context by不仅不限制使用的函数,而且可以使用任意表达式,譬如多个函数的组合。 - context by可以与having子句配合使用,以过滤每个组内部的行。 -假定trades数据表记录了每个股票每天的日终价格,我们可以用context by方便的计算每个股票每天的回报以及每天的排名。首先按股票代码进行分组,计算每个股票每天的回报。假设数据是时间顺序排列的。 +假定trades数据表记录了每个股票每天的日终价格,我们可以用context by方便的计算每个股票每天的回报以及每天的排名。首先按股票代码进行分组,计算每个股票每天的回报。我们这里假设数据是时间顺序排列的。 ``` update trades set ret = ratios(price) - 1.0 context by sym; @@ -185,7 +183,7 @@ id month avg_wage ``` -上面的问题,在其它数据库系统中,可以使用equal join(id字段)和 non-equal join(month字段),以及group by子句来解决。但除了写法更为复杂外,与DolphinDB window join相比,其它系统性能落后两个数量级以上。 +上面的问题,在其它数据库系统中,可以使用equal join(id字段)和 non-equal join(month字段),以及group by子句来解决。但除了写法更为复杂外,与DolphinDB的window join相比,其它系统性能落后两个数量级以上。 window join在金融领分析领域有着广泛的应用。一个经典的应用就是将交易(trades)表和报价(quotes)表进行关联,计算交易成本。 @@ -198,7 +196,7 @@ IBM 2018.06.01 10:01:01.005 143.19 100 MSFT 2018.06.01 10:01:04.006 107.94 200 ``` -以下为报价表(Quotes),不分区或者按日期和股票代码分区: +以下为报价表(quotes),不分区或者按日期和股票代码分区: ``` sym date time bid ask bidSize askSize @@ -277,7 +275,7 @@ x, y = y, x //swap the value of x and y x, y =1 2 3, 4 5 ``` -DolphinDB目前支持的循环语句包括`for`语句和`do..while`语句。for语句的循环体可以包括数据对(pair)(左闭右开区间)、数组(vector)、矩阵(matrix)和表(table)。 +DolphinDB目前支持的循环语句包括for语句和do..while语句。for语句的循环体可以包括数据对(pair)(左闭右开区间)、数组(vector)、矩阵(matrix)和表(table)。 1到100累加求和: @@ -309,7 +307,7 @@ t= table(["TV set", "Phone", "PC"] as productId, 1200 600 800 as price, 10 20 7 for(row in t) print row.productId + ": " + row.price * row.qty ``` -DolphinDB的分支语句`if..else`与其它语言一致。 +DolphinDB的分支语句if..else与其它语言一致。 ``` if(condition){ @@ -323,7 +321,7 @@ else{ ## 4. 函数化编程(Functional Programming) -DolphinDB支持函数式编程的大部分功能,包括 +DolphinDB支持函数式编程的大部分功能,包括: - 纯函数(pure function) - 自定义函数(user-defined function,或简称udf) - lambda函数 diff --git a/import_data.md b/import_data.md index 36ebfd01..52f47fe5 100644 --- a/import_data.md +++ b/import_data.md @@ -1,4 +1,4 @@ -# DolphinDB数据导入教程 +# 数据导入教程 DolphinDB提供了多种灵活的数据导入方法,来帮助用户方便的把海量数据从多个数据源导入。具体有如下三种途径: diff --git a/job_management_tutorial.md b/job_management_tutorial.md index febcdf88..a396b9e4 100644 --- a/job_management_tutorial.md +++ b/job_management_tutorial.md @@ -1,4 +1,4 @@ -# DolphinDB作业管理 +# 作业管理 作业(Job)是DolphinDB中最基本的执行单位,可以简单理解为一段DolphinDB脚本代码在DolphinDB系统中的一次执行。作业根据阻塞与否可分成同步作业和异步作业。 diff --git a/memory_management.md b/memory_management.md index d254f167..cdb481b6 100644 --- a/memory_management.md +++ b/memory_management.md @@ -1,4 +1,4 @@ -# DolphinDB 内存管理 +# 内存管理 DolphinDB是一款支持多用户多任务并发操作的高性能分布式时序数据库软件(Distributed Time Series Database)。针对大数据的高效的内存管理是其性能优异的基础之一。DolphinDB通过向操作系统申请大块内存,然后自行管理。本教程涉及的内存管理包括以下方面: * __变量的内存管理__ ,为用户提供和回收编程环境所需内存; * __分布式表的缓存管理__ ,Session间共享分区表数据,以提高内存使用率; @@ -122,14 +122,14 @@ for(d in days){ } ``` 内存随着加载分区数的增加变化规律如下图所示: -![image](https://github.com/dolphindb/Tutorials_CN/raw/master/images/memory_managment/partition9.png) +![image](https://2xdb.net/dolphindb/tutorials_cn/raw/master/images/memory_managment/partition9.png?inline=false) 当遍历每个分区数据时,在内存使用量不超过maxMemSize的情况下,分区数据会全部缓存到内存中,以在用户下次访问时,直接从内存中提供数据,而不需要再次从磁盘加载。 ### 3.5 节点内存使用达到maxMemSize时,系统自动回收 如果DolphinDB server使用的内存,没有超过用户设置的maxMemSize,则不会回收内存。当总的内存使用达到maxMemSize时,DolphinDB 会采用LRU的内存回收策略, 来腾出足够的内存给用户。 示例10,上面用例中我们只加载了8天的数据,此时我们继续共遍历15天数据,查看缓存达到maxMemSize时,内存的占用情况。如下图所示: -![image](https://github.com/dolphindb/Tutorials_CN/raw/master/images/memory_managment/partiton15.png) +![image](https://2xdb.net/dolphindb/tutorials_cn/raw/master/images/memory_managment/partiton15.png?inline=false) 如上图所示,当缓存的数据超过maxMemSize时,系统自动回收内存,总的内存使用量仍然小于用户设置的最大内存量8GB。 @@ -147,7 +147,7 @@ sum(mem().blockSize - mem().freeSize) ## 4 作为流数据消息缓存队列 当数据进入流数据系统时,首先写入流表,然后写入持久化队列和发送队列(假设用户设置为异步持久化),持久化队列异步写入磁盘,发送队列发送到订阅端。 当订阅端收到数据后,先放入接受队列,然后用户定义的handler从接收队列中取数据并处理。如果handler处理缓慢,会导致接收队列有数据堆积,占用内存。如下图所示: -![image](https://github.com/dolphindb/Tutorials_CN/raw/master/images/memory_managment/streaming.png) +![image](https://2xdb.net/dolphindb/tutorials_cn/raw/master/images/memory_managment/streaming.png?inline=false) 流数据内存相关的配置选项: * __maxPersistenceQueueDepth__ : 流表持久化队列的最大消息数。对于异步持久化的发布流表,先将数据放到持久化队列中,再异步持久化到磁盘上。该选项默认设置为1000万。在磁盘写入成为瓶颈时,队列会堆积数据。 @@ -164,7 +164,7 @@ sum(mem().blockSize - mem().freeSize) DolphinDB为了提高读写的吞吐量和降低读写的延迟,采用先写入WAL和缓存的通用做法,等累积到一定数量时,批量写入。这样减少和磁盘文件的交互次数,提升写入性能,可提升30%+的写入速度。因此,也需要一定的内存空间来临时缓存这些数据,如下图所示: -![image](https://github.com/dolphindb/Tutorials_CN/raw/master/images/memory_managment/cacheEngine.png) +![image](https://2xdb.net/dolphindb/tutorials_cn/raw/master/images/memory_managment/cacheEngine.png?inline=false) 当事务t1,t2,t3都完成时,将三个事务的数据一次性写入到DFS的数据库磁盘上。Cache Engine空间一般推荐为maxMemSize的1/8~1/4,可根据最大内存和写入数据量适当调整。CacheEngine的大小可以通过chunkCacheEngineMemSize来配置。 diff --git a/module_tutorial.md b/module_tutorial.md index 61140fda..405bc032 100644 --- a/module_tutorial.md +++ b/module_tutorial.md @@ -124,6 +124,28 @@ DolphinDB GUI从0.99.2版本开始提供了远程同步模块的功能,具体 ``` Modules [Module1] and [Module2] contain function [functionName]. Please use module name to qualify the function. ``` +* 如果已导入模块中与自定义函数重名,系统会默认使用模块中的函数。如果要调用自定义函数,需要声明命名空间。自定义函数和内置函数的默认命名空间为根目录,用两个冒号表示。比如: + +``` +//定义模块 +module sys +def myfunc(){ + return 3 +} + +//自定义函数 +login("admin","123456") +def myfunc(){ + return 1 +} +addFunctionView(myfunc) + +//调用 +use sys +sys::myfunc() //调用模块的函数 +myfunc() //调用模块的函数 +::myfunc() //调用自定义函数 +``` * 如果已导入的模块中不包含该函数,DolphinDB会在系统内置函数中搜索该函数。如果内置函数中也没有该函数,将抛出函数为定义的异常。 diff --git a/multi_machine_cluster_deploy.md b/multi_machine_cluster_deploy.md index ccec4016..67953fc2 100644 --- a/multi_machine_cluster_deploy.md +++ b/multi_machine_cluster_deploy.md @@ -1,4 +1,4 @@ -# DolphinDB 多物理节点集群部署 +# 多服务器集群部署 DolphinDB Cluster包括三种类型节点:数据节点(data node),代理节点(agent)和控制节点(controller)。 diff --git a/partitioned_in_memory_table.md b/partitioned_in_memory_table.md index ceb7b398..dbfc5c52 100644 --- a/partitioned_in_memory_table.md +++ b/partitioned_in_memory_table.md @@ -1,4 +1,4 @@ -# 内存数据表使用指南 +# 内存分区表加载和操作 DolphinDB的内存数据表可以是非分区的,也可以是分区的。除了组合分区以外的所有分区方式都适用于内存数据表。使用分区内存表进行运算能充分发挥多核CPU并行计算的优势。 diff --git a/restore-backup.md b/restore-backup.md index a36fa5c4..4c3e88a0 100644 --- a/restore-backup.md +++ b/restore-backup.md @@ -1,4 +1,4 @@ -# DolphinDB数据备份恢复教程 +# 数据备份恢复教程 DolphinDB database 提供了一系列函数,用于数据备份与恢复。数据备份和回复时均以表的分区为单位 diff --git a/single_machine_cluster_deploy.md b/single_machine_cluster_deploy.md index bc0ab4ed..19b51d93 100644 --- a/single_machine_cluster_deploy.md +++ b/single_machine_cluster_deploy.md @@ -1,4 +1,4 @@ -# DolphinDB 单物理节点集群部署 +# 单服务器集群部署 DolphinDB集群包括三种类型节点:数据节点(data node),代理节点(agent)和控制节点(controller)。 diff --git a/standalone_server.md b/standalone_server.md index cd91801f..b616f579 100644 --- a/standalone_server.md +++ b/standalone_server.md @@ -1,4 +1,4 @@ -# DolphinDB 单节点部署 +# 单节点部署 在单节点运行DolphinDB,可以帮助用户快速上手DolphinDB。用户只需下载DolphinDB程序包,下载地址:[http://www.dolphindb.cn/downloads.html](http://www.dolphindb.cn/downloads.html) diff --git a/stream_aggregator.md b/stream_aggregator.md index 71ef024c..e970b7bb 100644 --- a/stream_aggregator.md +++ b/stream_aggregator.md @@ -1,4 +1,4 @@ -## DolphinDB流数据聚合引擎 +## 流数据聚合引擎 流数据是指随时间延续而增长的动态数据集合。金融机构的交易数据、物联网的传感器数据和互联网的运营数据都属于流数据的范畴。流数据的特性决定了它的数据集一直是动态变化的。传统的面向静态数据表的计算引擎无法胜任流数据领域的分析和计算任务,所以流数据场景需要一套针对性的计算引擎。 diff --git a/streaming_crossSectionalAggregator.md b/streaming_crossSectionalAggregator.md index 81809c78..0bdc69f3 100644 --- a/streaming_crossSectionalAggregator.md +++ b/streaming_crossSectionalAggregator.md @@ -1,4 +1,4 @@ -### 横截面引擎 +### 流数据横截面引擎 在处理实时流数据时,不仅需要使用时序聚合引擎按时间做纵向聚合计算,也需要对所有分组最新的截面数据做计算。DolphinDB已经提供了对应的流数据聚合引擎:横截面聚合引擎。 diff --git a/streaming_tutorial.md b/streaming_tutorial.md index f977af67..eb179a38 100644 --- a/streaming_tutorial.md +++ b/streaming_tutorial.md @@ -1,4 +1,4 @@ -# DolphinDB流数据教程 +# 流数据教程 实时流处理是指将业务系统产生的持续增长的动态数据进行实时的收集、清洗、统计、入库,并对结果进行实时的展示。在金融交易、物联网、互联网/移动互联网等应用场景中,复杂的业务需求对大数据处理的实时性提出了极高的要求。面向静态数据表的传统计算引擎无法胜任流数据领域的分析和计算任务。 DolphinDB内置的流数据框架支持流数据的发布、订阅、预处理、实时内存计算、复杂指标的滚动窗口计算等,是一个运行高效,使用便捷的流数据处理框架。 diff --git a/table_engine_tutorial.md b/table_engine_tutorial.md index 8e93f3ef..e5613b86 100644 --- a/table_engine_tutorial.md +++ b/table_engine_tutorial.md @@ -1,8 +1,10 @@ -### DolphinDB数据表详解 +# DolphinDB数据表详解 DolphinDB database 按照存储介质的不同,支持三种类型的数据表,内存表(in-memory table)、磁盘表(disk table)和分布式表(DFS table)。磁盘表将数据表存储在本地磁盘上。分布式表将表存储在分布式文件系统上。按照分区与否,数据表又可以分成分区表(在系统中称为 partitioned table 或 segmented table) 和未分区表。下面我们将详细介绍这些表在创建,读写数据,是否支持事务,是否支持并发等方面的异同之处。 -### 1. 三种数据表的不同之处 +本文的例子中使用了两个数据文件:[sample.csv](data/sample.csv)和[sample.bin](data/sample.bin)。 + +## 1. 三种数据表的不同之处 内存表只存在于内存中,写入和查询速度很快,但是数据并不会持久化。通常它在系统运行时作为临时数据载体使用,它使用简单方便,也适合作为新手学习入门使用。内存表支持分区,将内存表进行分区可以更充分的利用计算机并行多线程特性。 @@ -11,145 +13,505 @@ DolphinDB database 按照存储介质的不同,支持三种类型的数据表 分布式表的数据分布在不同的节点的磁盘上,通过DolphinDB的分布式文件系统仍然可以像本地表一样做统一查询。要将数据保存在分布式系统中,将数据进行切分是一个前提,所以分布式表必须进行分区,系统不支持创建未分区的分布式数据库。分布式表的优点是支持集群,支持横向扩展。通过DolphinDB的分布式文件系统,分布式计算引擎将多机器多节点上的数据进行统一的协调调度和分析计算,使得整个系统可以处理的数据量可以无限扩展,而不会受限于单服务器磁盘容量和内存容量的限制。 下表列出这三种类型的数据表的适用场景 + 表类型 | 适用场景 ---|--- 内存表| 临时数据载体,学习入门 磁盘表| 单用户静态数据集分析 分布式表| 团队开发,多用户并发读写 -### 2. 创建数据表 +## 2. 创建数据表 + 创建数据表,会涉及到分区概念(具体分区概念请参考[数据分区教程](https://github.com/dolphindb/Tutorials_CN/blob/master/database.md)),分区会影响到数据的存储分布和处理的并行度,下面按照三种类型的表结合分区和未分区的情况来做示例: ### 2.1 创建内存表 -- 未分区内存表 +#### 2.1.1 未分区内存表 + +未分区内存表(以下简称内存表)通常在系统运行时作为临时数据载体使用,各种查询语句与计算函数返回的结果都以内存表的形式返回,因此在DolphinDB中,创建内存表的方式也相对丰富,主要可以通过以下3种方式创建内存表: + +- `table`函数创建内存表 +- `loadText`和`loadRecord`方法返回内存表 +- SQL查询返回内存表 + +下面分别给出通过这3种方式创建内存表的示例。 + +**(1) `table`函数创建内存表** + +在DolphinDB中,使用[table](https://www.dolphindb.cn/cn/help/table.html)函数可以创建一个未分区的内存表。`table`函数主要有两种用法,具体示例如下。 + +- 使用向量、矩阵或者元组创建表 + + 如下所示,使用向量x,矩阵y和元组z创建一个内存表。 + + ``` + >x=1..6 + y=11..22$6:2 + z=(101..106, 201..206) + t=table(x,y,z) + t.rename!(`x`y1`y2`z1`z2); + >t; + x y1 y2 z1 z2 + - -- -- --- --- + 1 11 17 101 201 + 2 12 18 102 202 + 3 13 19 103 203 + 4 14 20 104 204 + 5 15 21 105 205 + 6 16 22 106 206 + ``` + + > 请注意,创建表时所使用的元素(向量、矩阵或元组)长度都必须相同。 + +- 指定表的结构创建表 + + 如下所示,通过指定表的容量、初始大小、列名以及列的数据类型来初始化表。例子使用`table`函数创建表,指定列名为id和name,列的数据类型分别是INT和STRING。其中,第一个参数取值为“1000:0”,代表初始空间和初始下标。初始空间表示创建表时的预留空间,当数据行数少于预留空间时,新增数据不需要重新分配空间,执行会非常高效。直到数据行数超出初始空间后,系统会为每次新增数据动态分配空间。 + + ``` + >t=table(1000:0, `id`name, [INT,STRING]); + ``` + +**(2) `loadText`和`loadRecord`方法返回内存表** + +在DolphinDB中,可以通过[loadText](https://www.dolphindb.cn/cn/help/loadText.html),[loadRecord](https://www.dolphindb.cn/cn/help/loadRecord.html)等方法导入数据文件,数据导入到DolphinDB后,以内存表的形式存储。 + +下面的例子使用了两个文件:sample.csv和sample.bin。例子中的"YOUR_DIR"为存放数据文件的路径。 + +sample.csv包含id和price两个字段,下面通过`loadText`函数将该文件导入到DolphinDB,存放在t_csv表中。下例中,t_csv表就是一个内存表。 -要创建一个内存表,需要使用table函数创建,比如下面的脚本创建一个表,包含两个字段id,name,第一个参数`1000:0`代表初始空间和初始下标。初始空间表示创建表时的预留空间,当数据行数少于预留空间时,新增数据不需要重新分配空间,执行会非常高效。直到数据行数超出初始空间后,系统会为每次新增数据动态分配空间。 ``` -t = table(1000:0, `id`name, [INT,STRING]) +>t_csv=loadText(YOUR_DIR+"sample.csv"); +>t_csv; +id price +-- --------- +1 38.959012 +2 30.2263 +3 58.125723 +4 59.340818 +5 36.449339 +6 81.542495 +7 82.127893 +8 41.231077 +9 35.615633 +10 83.113151 +... ``` -- 内存分区表 -要对数据表进行分区,必须将表纳入某一个分区数据库中,示例如下,将表按照id进行分区,按照1到100,每个id值分一个区。`database`的第一个路径参数留空表示内存分区数据库: + +sample.bin为一个二进制文件,包含id和price两个字段。下面通过`loadRecord`函数将该二进制文件导入到DolphinDB,存放在t_bin中。下例中,t_bin也是一个内存表。 + +``` +>schema=[("id", INT),("price",DOUBLE)]; +t_bin=loadRecord(YOUR_DIR+"sample.bin",schema); +>t_bin; +id price +-- --------- +1 38.959012 +2 30.2263 +3 58.125723 +4 59.340818 +5 36.449339 +6 81.542495 +7 82.127893 +8 41.231077 +9 35.615633 +10 83.113151 +... ``` -t = table(1000:0, `id`name, [INT,STRING]) + +**(3) SQL查询返回内存表** + +在DolphinDB中,所有涉及对表(包括内存表、磁盘表和分布式表)进行的查询操作,返回的查询结果均是内存表。 + +例如,使用SQL语句查询[分布式表](#23-创建分布式表)的数据,符合查询条件的记录会被加载到内存,保存在内存表中。 + +> 请注意,只有启用enableDFS=1的集群环境或者DolphinDB单例模式才能使用分布式表。 + +首先创建一个分布式数据库"dfs://dolphindbDatabase"和表"partitionedTable1",并向分布式表中追加tdata中的数据。 + +``` +>login(`admin, `123456) +dbPath="dfs://dolphindbDatabase" +n=5000 +tdata=table(take(1..100,n) as id, rand(`Alice`Betty`Cargo, n) as name, rand(100.5,n) as price) +db=database(dbPath, VALUE, 1..100) +tb=db.createPartitionedTable(tdata,`partitionedTable1,`id) +tb.append!(tdata); +``` + +查询名为Alice的所有记录,查询返回一个内存表,使用t_result来保存该内存表。由于数据是随机生成的,以下输出结果仅供参考。 + +``` +>t_result=select * from loadTable("dfs://dolphindbDatabase", `partitionedTable1) where name="Alice"; +>t_result; +id name price +-- ----- --------- +1 Alice 15.622302 +1 Alice 61.98541 +1 Alice 19.394159 +1 Alice 92.481627 +1 Alice 12.179253 +1 Alice 36.858704 +1 Alice 26.014262 +1 Alice 50.697725 +1 Alice 31.491535 +1 Alice 74.167275 +``` + +#### 2.1.2 内存分区表 + +在DolphinDB中,主要可以通过`createPartitionedTable`函数和`ploadText`函数创建内存分区表。 + +- `createPartitionedTable`函数创建内存分区表 + +要对数据表进行分区,必须将表纳入某一个分区数据库中,在使用`database`函数创建数据库时,第一个路径参数留空表示内存分区数据库。下面给出使用`createPartitionedTable`函数创建内存分区表的2个例子。 + +**示例1** + +使用一个内存表创建内存分区表:首先创建内存分区数据库,分区方案为值分区,取值范围为从1至100,然后调用`createPartitionedTable`函数创建内存分区表,按照字段id进行分区,每个id值分一个区。 + +``` +>t=table(1000:0, `id`name, [INT,STRING]) db=database(,VALUE,1..100) -db.createPartitionedTable(t,`partitionedTable1,`id) +tb=createPartitionedTable(db, t,`partitionedTable1,`id); +``` + +**示例2** + +使用一系列内存表创建内存分区表:首先创建内存分区数据库,分区方案为范围分区,范围包含下限不包含上限。然后创建两个表tdata1和tdata2,最后调用`createPartitionedTable`函数创建内存分区表t_global,按照字段name进行分区,一共分为2个分区。 ``` +>n=4 +db=database(, RANGE, `A`C`E) +tdata1=table(take(1..4,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name, rand(100.5,n) as price) +tdata2=table(take(1..4,n) as id, rand(`Alice`Bob`Catty`Daniel, n) as name, rand(100.5,n) as price) +tb=createPartitionedTable(db, [tdata1, tdata2], `partitionedTable1, `name); +>select * from tb; +id name price +-- ----- --------- +1 Betty 68.287133 +2 Alice 22.588541 +3 Betty 76.211358 +4 Betty 61.07317 +1 Alice 85.087942 +2 Bob 22.76464 +3 Bob 97.104663 +4 Catty 44.58062 +``` + +> 请注意,使用一系列内存表创建内存分区表时,一系列表的个数需要与分区数相同,且这些表的结构也应一致。 + +- `ploadText`函数导入数据到内存分区表 + +通过`ploadText`函数导入数据,数据将并行导入到内存中,返回的是一个内存分区表。下面的例子使用`ploadText`函数导入sample.csv文件,例子中的"YOUR_DIR"为存放数据文件的路径。 + +``` +>tb=ploadText(YOUR_DIR+"sample.csv") +``` + ### 2.2 创建磁盘表 + - 未分区磁盘表 磁盘表的建立也需要依赖于数据库,首先创建磁盘数据库,然后将表加入到数据库中,示例代码如下: ``` -dbPath = "/home/user1/mydb" -t = table(1000:0, `id`name, [INT,STRING]) +>dbPath="/home/dolphindb/database/mydbd" +n=10000 +t=table(take(1..100,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name) db=database(dbPath) -db.saveTable(t,`diskTable1) - +db.saveTable(t,`diskTable1); ``` - 磁盘分区表 创建磁盘分区表与创建内存分区表的唯一区别是指定一个磁盘路径。 ``` -dbPath = "/home/user1/mydb" -t = table(1000:0, `id`name, [INT,STRING]) +>login(`admin, `123456) +dbPath="/home/dolphindb/database/mydbp" +n=10000 +tdata=table(take(1..100,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name) db=database(dbPath, VALUE, 1..100) -db.createPartitionedTable(t,`partitionedTable1,`id) - +db.createPartitionedTable(t,`partitionedTable1,`id).append!(tdata); ``` + ### 2.3 创建分布式表 -创建分布式分区表与磁盘分区表基本方式是一致的,区别在于分布式表需要指定分布式路径`dfs://`。 +- 创建维度表 + +维度表是分布式数据库中没有分区的表,一般用于存储不频繁更新的小数据集。我们可以使用`createTable`函数来创建维度表。 + +下面的例子中,使用`database`函数创建数据库,指定数据库路径为"dfs://dimensionDB"。需要注意的是,维度表的数据不以分区方式存储,因此这里与分区相关的参数partitionType和partitionScheme无效。然后调用`createTable`函数创建维度表,并追加数据。 ``` -dbPath = "dfs://mydb" -t = table(1000:0, `id`name, [INT,STRING]) -db=database(dbPath, VALUE, 1..100) -db.createPartitionedTable(t,`partitionedTable1,`id) +>login(`admin, `123456) +db=database("dfs://dimensionDB",RANGE, 1 2) +n=10000 +tdata=table(take(1..4,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name, rand(100.5,n) as price) +dt=db.createTable(tdata,`dt).append!(tdata); +``` + +- 创建分布式表 +创建分布式分区表与磁盘分区表基本方式是一致的,区别在于分布式表需要指定分布式路径"dfs://"。 ``` -### 3. 操作数据 +>login(`admin, `123456) +dbPath="dfs://dolphindbDatabase" +n=10000 +tdata=table(take(1..4,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name, rand(100.5,n) as price) +db=database(dbPath, VALUE, 1..100) +tb=db.createPartitionedTable(tdata,`partitionedTable1,`id).append!(tdata); +``` + +## 3. 操作数据 ### 3.1 读取数据 -系统提供了`loadTable`来加载表数据,针对磁盘表或分布式表,根据分区或不分区的情况,loadTable的表现有少许不同。 + +#### 3.1.1 使用`loadTable`加载表数据 + +系统提供了[loadTable](https://www.dolphindb.cn/cn/help/loadTable.html)来加载表数据,针对磁盘表或分布式表,根据分区或不分区的情况,`loadTable`的表现有少许不同。 + - 未分区磁盘表:未分区磁盘表是用于学习演练或小数据量分析使用,所以当使用`loadTable`来加载未分区磁盘表时,会全量加载到内存。 -- 分区磁盘表:分区磁盘表通常是针对大数据量的单用户分析场景,工作机内存是无法一次性加载所有数据的,所以直接调用`loadTable`来加载数据并不会直接加载所有数据,只会加载数据表结构元数据到内存中,后续根据具体的Query语句按需加载分区数据。虽然说分区表 + +- 分区磁盘表:分区磁盘表通常是针对大数据量的单用户分析场景,工作机内存是无法一次性加载所有数据的,所以直接调用`loadTable`来加载数据并不会直接加载所有数据,只会加载数据表结构元数据到内存中,后续根据具体的Query语句按需加载分区数据。 + - 分区分布式表:分布式表是为多用户同时分析大数据集场景而设计的,所以`loadTable`也只会加载数据表结构元数据,与磁盘分区表不同的是,系统会缓存已加载的表结构元数据,供多用户使用。 + +- 维度表:维度表是分布式数据库中没有分区的表,一般用于存储不频繁更新的小数据集。由于维度表也是分布式表,因此调用`loadTable`来加载数据并不会直接加载所有数据,只会加载数据表结构元数据到内存中。 + 加载数据脚本示例 + +- 加载磁盘表 + +加载[第2节](#22-创建磁盘表)中创建的未分区磁盘表: + +``` +//未分区磁盘表 +>tb=loadTable("/home/dolphindb/database/mydbd", `diskTable1); +>tb; +id name +-- ----- +1 Cargo +2 Cargo +3 Cargo +4 Alice +5 Alice +... + +>select count(*) from tb; +count +----- +10000 +``` + +加载[第2节](#22-创建磁盘表)中创建的磁盘分区表,由于是按照id进行分区,因此在加载磁盘分区的数据时,数据按照id的取值递增输出: + +``` +//磁盘分区表 +>tb=loadTable("/home/dolphindb/database/mydbp", `partitionedTable1); +>tb; +id name +-- ----- +1 Danny +1 Betty +1 Betty +1 Betty +1 Danny +... + +>select count(*) from tb; +count +----- +10000 +``` + +- 加载分布式表 + +加载[第2节](#23-创建分布式表)中创建的分布式分区表,由于分布式表不允许直接访问,因此需要通过SQL语句选择数据: + ``` -//本地磁盘表 -tb = loadTable("/home/diskDB",`table1) -//分布式表 -tb = loadTable("dfs://dfsDB",`table1) +//分布式分区表 +>tb=loadTable("dfs://dolphindbDatabase", `partitionedTable1); +>select * from tb; +id name price +-- ----- --------- +1 Cargo 89.770549 +1 Danny 17.467475 +1 Alice 49.183698 +1 Danny 18.397749 +1 Cargo 67.743099 +... + +>select count(*) from tb; +count +----- +10000 +``` + +加载[第2节](#23-创建分布式表)中创建的维度表: + +``` +//维度表 +>tb=loadTable("dfs://dimensionDB", `dt); +>select * from tb; +id name price +-- ----- --------- +1 Alice 64.557855 +2 Alice 20.694495 +3 Cargo 28.921734 +4 Betty 82.949798 +1 Danny 98.370399 + +>select count(*) from tb; +count +----- +10000 +``` + +#### 3.1.2 使用`loadTableBySQL`加载表数据 + +DolphinDB还提供了[loadTableBySQL](https://www.dolphindb.cn/cn/help/loadTableBySQL.html)函数,用于将分区表中满足SQL查询的记录行加载到内存中。返回的是分区的内存表。需要注意的是,`loadTableBySQL`函数只能对分区表使用,且对于磁盘分区表和分布式表,需要先通过`loadTable`函数获得分区表结构的元数据,再使用`loadTableBySQL`函数进行查询。 + +- 加载内存分区表 + +``` +>n=1000 +t=table(take(1..100,n) as id, rand(`Alice`Betty`Cargo`Danny, n) as name, rand(100.5,n) as price) +db=database(,VALUE,1..100) +tb=createPartitionedTable(db, t,`partitionedTable1,`id).append!(t); +sample=select * from loadTableBySQL(); +>sample; +id name +-- ----- +50 Alice +50 Cargo +50 Betty +50 Alice +50 Betty +... +``` + +- 加载分布式表 + +下面的例子使用[sql](https://www.dolphindb.cn/cn/help/sql1.html)函数创建SQL语句,再通过`loadTableBySQL`函数加载[第2节](#23-创建分布式表)中创建的分布式表。 + +``` +>tb=loadTable("dfs://dolphindbDatabase", `partitionedTable1) +st=sql(