DolphinDB 编程进阶:掌握这十个细节,让你的代码更出色

news2024/11/15 14:08:58

众所周知,编程细节不仅关乎代码的美观与整洁,更是确保软件质量、提升开发效率、减少维护成本以及保障系统稳定性的基石。

今天和大家分享的内容是:使用 DolphinDB 编程时,十个常被忽略但至关重要的细节。本文涵盖了元编程技巧、数据类型处理技巧以及分区策略优化等方面,旨在帮助大家有效避免分区冲突计算错误性能瓶颈堆栈溢出等问题,从而在数据处理的征途上更加游刃有余。

1. 使用 mr 函数写入分布式表时注意避免分区冲突

mr 函数,即 Map-Reduce,是在 DolphinDB 分布式计算中最常用的函数之一。通常,数据表会被划分为多个分区,每个分区表被视作一个数据源(ds)。mapFunc 参数负责在每个 ds 内部处理数据,可选参数 reduceFunc 会将 mapFunc 的返回值合并或汇总。若未使用 reduceFunc,就会直接返回 mapFunc 的结果,也就是由所有返回值组合成的元组。

在进行复杂计算时,我们通常在分区内计算数据,并在映射过程中直接将其写入另一个数据库表。但是,如果 mapFunc 中包含写入另一个表的操作,且原库表和结果库表的分区不一致,就可能会遇到写入冲突的报错。

1.1 错误代码

下面使用 mr 对一个时间和标的均为 value 分区的库表做计算,完成后将结果写入一个仅按时间 value 分区的库表中:

def myMapFunc(table){
	minReturn = select `dayReturnSkew as factorname, skew(ratios(close)) as val from loadTable("dfs://k_minute_level","k_minute") group by date(tradetime) as tradetime, securityid
	loadTable("dfs://K_FACTOR_VERTICAL","factor_k").append!(minReturn)
}
ds = sqlDS(<select * from  loadTable("dfs://k_minute_level","k_minute")>)
mr(ds,myMapFunc)

运行这段代码会报错:1 map call(s) failed. The error message for the first failed call is: <ChunkInTransaction>filepath '/K_FAC/TOR_VERTICAL/202001M_202101M/dayReturnSkew/a' has been owned by transaction 27 RefId: S00002

这是因为上述例子中,mr 数据源的分区方式和目标写入库表的分区方式是冲突的,即多个数据源中的计算结果对应了待写入库表的同一个分区。例子中的数据源涉及到三个分区,而计算结果对应的待写入库表只写入一个分区,在三个并行计算完成后,同时往同一个分区写入,会发生分区冲突,抛出异常,写入失败。

这种情况下,每一个 map 的结果写入结果表时,最好是串行写入。串行写入的方法有很多,包括:

  • 在 mr 中不做写入,只做计算。拿到返回的结果后,使用 unionAll 将多个结果表进行合并,再一次性写入目标库表。
  • 在 mr 的 finalFunc 中完成合并结果和写入目标库表的操作。
  • 如果 mr 的计算结果很大,在内存中无法合并结果,则可以将结果写入流表,由流表的 handler 来串行写入目标库表。

1.2 解决方案

下列代码中,我们在 finalFunc 里对各个 ds 的计算结果进行了合并,再将合并结果写入目标库表,可以有效避免分区冲突。

def myMapFuncCorrect(table){
	minReturn = select `dayReturnSkew as factorname, skew(ratios(close))	 as val from loadTable("dfs://k_minute_level","k_minute") group by date(tradetime) as tradetime, securityid
	return minReturn
	}
def unionAndWrite(result){
	multi_result = unionAll(result,false)
	return tableInsert(loadTable("dfs://K_FACTOR_VERTICAL","factor_k"), multi_result)
	}
mr(ds, myMapFuncCorrect, , unionAndWrite)

2. 留意空值的数据类型

在 DolphinDB 中,空值既可以是无特定类型的(如 NULL),也可以是特定类型的(如 int(NULL)double(NULL)string(NULL) 等)。在向强类型的向量或表中填充或更新空值时,必须确保空值的数据类型与向量类型或表中对应列的类型相匹配。

2.1 错误代码

下面这段代码试图更新表中的空值:

id = `a`b`c
val = 1 2 3
t1 = table(id, val)
t2 = select NULL as type, * from t1
update t2 set type = "S"

这段代码将会报错:The data type of the new values does not match the data type of column type.

这是因为在生成 t2 时,没有指定空值的数据类型,生成了 VOID 类型的空值,从而导致 type 列的类型为 VOID。在更新(update) t2 时,由于 “S” 是 STRING 类型,与 type 列的类型不匹配,便无法将其更新到 type 列中。

2.2 解决方案

下列代码中,我们在生成 t2 时,显式指定了 type 列空值的类型为 STRING 类型,因此可以正常 update t2,不会报错。

id = `a`b`c
val = 1 2 3
t1 = table(id, val)
t2 = select string(NULL) as type, * from t1
update t2 set type = "S"

3. 注意矩阵与表之间的转换

在做计算的时候,经常会遇到要转换数据结构的情况,譬如将表转为矩阵。但是由于矩阵和表的性质不同,普通转换的时候可能会缺失一些信息(如表的列名、矩阵的行列标签等)。因此,在转换过程中,我们需要注意补充这些缺失的信息。

3.1 错误代码

t = table(stretch(2020.01.01..2020.01.05, 10) as Date,take(`AAPL`BABA,10) as sym, take(`alpha1,10) as factorName, 0.1 0.2 0.11 0.22 0.13 0.5 0.6 0.4 0.44 0.12 as factorValue)
m = exec factorValue from t pivot by Date,sym
m

输出结果为:

           AAPL BABA
           ---- ----
2020.01.01|0.1  0.2 
2020.01.02|0.11 0.22
2020.01.03|0.13 0.5 
2020.01.04|0.6  0.4 
2020.01.05|0.44 0.12

随后,将矩阵 m 转换为表:

table(m)

预期的输出为:

Date       AAPL BABA
---------- ---- ----
2020.01.01 0.1  0.2 
2020.01.02 0.11 0.22
2020.01.03 0.13 0.5 
2020.01.04 0.6  0.4 
2020.01.05 0.44 0.12

实际输出如下,其中 matrix 的 label 列丢失:

AAPL BABA
---- ----
0.1  0.2 
0.11 0.22
0.13 0.5 
0.6  0.4 
0.44 0.12

由于矩阵的值不包括矩阵的行标签,因此在矩阵转换为表时,只会把矩阵的值转成表的列。如果需要保证矩阵中的标签列不丢失,并且转成表中的首列,则需要手动添加。反之亦然,如果要将表的内容转为矩阵,那么需要先剔除目标矩阵中的标签列,把目标值的列先转成矩阵,再将标签列手动添加进矩阵。

3.2 解决方案

//将矩阵转成正确的表
correctT = table(m.rowNames()) join table(m)
//将表转换成正确的矩阵
correctM = matrix(correctT[,1:]).rename!(correctT.Date,correctT.colNames()[1:])

矩阵转表时,将矩阵的行标签通过rowNames()函数取出,拼接到转换后的表中。表转矩阵时,将值所在的列转成矩阵,接着用rename!()函数给矩阵列和行添加标签。

4. 表连接时注意键值冗余

表连接是通过连接谓词来合并两张或者多张表的数据,从而创建新表的函数。在进行表连接时,如果连接列存在多条匹配记录,通常会返回所有匹配记录。因此,如果关联列有大量重复值,可能会导致结果表规模急剧膨胀,甚至引发内存溢出(OOM)等问题。

4.1 错误代码

下面这段代码将两个表做左连接:

t1 = table(`a`b`c as id, 1 2 3 as val1)
t2 = table(`a`a`a`b`b`b`c`c`c as id, 4..12 as val2)
t1.lj(t2,`id)

将会得到结果:

id val1 val2
-- ---- ----
a  1    4   
a  1    5   
a  1    6   
b  2    7   
b  2    8   
b  2    9   
c  3    10  
c  3    11  
c  3    12

这是因为,左连接(lj)会返回左表中所有与右表匹配的记录。如果右表中没有匹配的记录,将会返回 NULL;如果右表中有多条匹配记录,将会返回所有的匹配记录。因此,由于右表中的 id 列有很多重复值,实际结果会比左表行数多得多。想要保证返回结果的行数与左表的行数相等,可以使用左半连接 lsj 函数,如果右表中有多条匹配记录,lsj 将会取第一条的匹配记录。

4.2 解决方案

t1 = table(`a`b`c as id, 1 2 3 as val1)
t2 = table(`a`a`a`b`b`b`c`c`c as id, 4..12 as val2)
t1.lsj(t2,`id)

如上,我们使用左半连接 lsj 来连接两个表,就不会出现匹配多次的冗余情况。

5. SQL 中避免变量名与列名同名

DolphinDB 支持多范式编程,包括 SQL 编程、命令式编程和函数式编程。在 SQL 语句中,列名可能与函数名或变量名相同。当三者产生歧义时,DolphinDB 会将其视为列名。若想表示函数的含义,可以在变量名称前加地址符 &。然而,当列名与变量名产生歧义时,就无法通过语法来消除歧义了。

注意,在 DolphinDB 中的 SQL 中,列名是大小写不敏感的。因此,取变量名时尽量不要与表中字段重名,以免出现不符合预期的返回结果。

5.1 错误代码

下面这段代码试图删除指定日期的数据:

t = table(2020.01.01..2020.01.05 as Date)

date = 2020.01.01
delete from t where Date = date
t.Date

正常情况下,这段代码预期会返回向量 [2020.01.02,2020.01.03,2020.01.04,2020.01.05],但实际会返回空值,表示表 t 中已无数据。

在这个 where 语句中,由于列名具有最高优先级, "=" 右边的 "date" 会优先查找是否存在名为 "date" 的列。由于列名不区分大小写,"=" 右边的 "date" 会被识别为表 t 中的 "Date" 列。因此,在 where 条件中,这样的写法会被解释为 "列date = 列date",意味着每一条记录都符合 where 条件,从而导致表 t 被清空。

5.2 解决方案

避免变量名与列名同名,例如把 date 变量改成 date1 即可。

t = table(2020.01.01..2020.01.05 as Date)
date1 = 2020.01.01
delete from t where Date = date1

6. 利用元编程简化多列数据计算

在使用 SQL 对表的多列进行计算时,手写 SQL 不仅繁琐,而且容易出错。因此,在对表内多列进行计算时,我们可以利用元编程来简化代码逻辑并提高准确性。如果想学习元编程相关的更多内容,可以阅读教程:元编程。

6.1 繁琐代码

手写 SQL 十分繁琐:

date = 2023.01.01..2023.01.10
code = take(`SH0001,10)
price = rand(10.0,10)
t = table(date,code,price)

res = select date, price, code, mmax(price,2) as mmax_2d, mmax(price,5) as mmax_5d, 
mmax(price,7) as mmax_7d, mmin(price,2) as mmin_2d, mmin(price,5) as mmin_5d, 
mmax(price,7) as mmin_7d, mavg(price,2) as mavg_2d, mavg(price,5) as mavg_5d, 
mavg(price,7) as mavg_7d, mstd(price,2) as mstd_2d, mstd(price,5) as mstd_5d, 
mstd(price,7) as mstd_7d from t context by code

6.2 优化方案

如下所示,我们使用 cross 函数结合匿名函数,生成了所有需要计算的因子的源代码,并加入到一个 metrics 向量中,即可用元编程函数 sql 方便地计算得到结果。

date = 2023.01.01..2023.01.10
code = take(`SH0001,10)
price = rand(10.0,10)
t = table(date,code,price)

factor = `mmax`mmin`mavg`mstd
windowSize = 2 5 7
metrics=[<date>,<code>,<price>]

f = def (x, y){return sqlCol(`price, partial(funcByName(x),,y),
		x + "_" + string(y) + "d")}
metrics.appendTuple!(cross(f, factor, windowSize).flatten())

res = sql(select=metrics, from = t, groupBy=sqlCol(`code), groupFlag=0).eval()

7. 注意元组的追加行为

在 DolphinDB 中,元组 (ANY VECTOR) 是一种特殊的向量类型,它允许元素类型不一致,其类型可以是表、矩阵、字符串向量、数值向量等。因此,在向元组中添加元素时,我们需要明确是将整个目标添加到元组中,还是将目标中的元素分别添加到元组中。

例如,在元编程中拼接元代码时,直接拼接可能会得到不符合预期的结果。

7.1 错误代码

比如一个表中有这些字段:"dDate", "symbol", "open", "close", "high", "low"。目标是对除了日期和 symbol 字段外的其他字段做 demean 操作(原值-平均值)。在用元编程写 select 参数的时候可能会这样写:

colName = ["dDate", "symbol", "open", "close", "high", "low"]
colNoCal = sqlCol(colName[0:2])
colCal = each(makeUnifiedCall{demean}, sqlCol(colName[2:]))
selects = colNoCal join colCal
//预期的行为:(< dDate >,< symbol >,< demean(open) >,< demean(close) >,< demean(high) >,< demean(low) >)
//实际的输出:(< dDate >,< symbol >,(< demean(open) >,< demean(close) >,< demean(high) >,< demean(low) >))

可以看到实际输出中的元组只有三个元素,第三个元素是一个包含4个元素的元组。由于元组类型可以接受任何类型,因此在将 colCal 这个变量使用 join 添加到 colNoCal 时,colCal 将会被整体添加到 colNoCal 中。在元编程中,我们需要将 colCal 中的元素铺开加入到 colNoCal 中,因此需要逐个调用 join,将其一个个加进元组中。

7.2 解决方案

metrics = colNoCal
metrics.appendTuple!(colCal, wholistic = false)
metrics

如上所示,我们使用 appendTuple! 函数,当 wholistic 参数为 false 时,就能够将 colCal 中的每一个元素依次追加到 metrics 中,得到符合预期的结果。

8. 正确使用 WHERE 子句进行分区剪枝

在查询分布式表时,我们往往只需要查询部分分区的数据。当数据量较大时,过滤条件的不同写法会造成查询耗时的巨大差异。查询分布式表时,当 WHERE 子句中的过滤条件满足以下要求时,可以进行分区剪枝,加快查询速率。

  • 当对采用 VALUE 分区、RANGE 分区或 LIST 分区的分布式表做查询时,若 where 子句中某个过滤条件同时满足以下条件,则系统只加载与查询相关的分区,以节省查询耗时:
    • 仅包含分布式表的原始分区字段、使用关系运算符(<, <=, =, ==, >, >=, in, between)或逻辑运算符(or, and),以及常量(包括常量与常量的运算)
    • 非链式条件(例如100<x<200)
    • 过滤逻辑可以缩窄相关分区范围

  • 当对采用 HASH 分区的分布式表做查询时,若 where 子句中某个过滤条件满足以下条件,系统会进行分区剪枝:
    • 包含分布式表的原始分区字段,使用关系运算符(=, ==, in, between)或逻辑运算符(or, and),以及常量(包括常量与常量的运算)。注意:当分区字段是 STRING 类型时,使用 between 运算符不能进行剪枝。

若 WHERE 子句中的过滤条件不满足以上要求,则会遍历所有分区进行查询。因此,在 WHERE 条件中,需要正确进行分区剪枝。如果想了解 DolphinDB 中关于时间类型的比较和分区剪枝的更多细节,可以阅读:DolphinDB 时间类型比较规则 。

8.1 错误代码

snapshot 是一个分区表,该表按天做了 VALUE 分区,分区字段为 DateTime。下面是错误的查询方式:

t1 = select count(*) from snapshot 
		   where temporalFormat(DateTime, "yyyy.MM.dd") >= "2020.06.01" and temporalFormat(DateTime, "yyyy.MM.dd") <= "2020.06.02" 
		   group by SecurityID

// 耗时 4145 ms

运行如下代码,使用 sqlDS 查看该查询涉及的分区数:

sqlDS(<select count(*) from snapshot 
		   where temporalFormat(DateTime, "yyyy.MM.dd") >= "2020.06.01" and temporalFormat(DateTime, "yyyy.MM.dd") <= "2020.06.02" 
		   group by SecurityID>).size()

>> 752

显然,对于按天分区的 snapshot,查询两天的数据并不应该涉及 752 个分区,说明该查询没有做分区剪枝。这是因为在该查询中,对分区字段套用了 temporalFormat 函数,先对所有日期进行转换,再去和对应日期比较,导致系统需要扫描所有分区,耗时大大增加。

8.2 解决方案

使用 between 谓词来指定分区字段所在的查询区间,能够正确做到分区剪枝。我们可以看到正确的查询仅涉及了两个分区,耗时大大减少,仅为 92ms。

sqlDS(<select count(*) from snapshot 
		   where date(DateTime) between 2020.06.01 : 2020.06.02 group by SecurityID>).size()

t2 = select count(*) from snapshot 
		   where date(DateTime) between 2020.06.01 : 2020.06.02 group by SecurityID

9. 灵活使用字典和元编程

在进行计算时,我们经常会遇到一些通用的公式,这些公式往往以字符串的形式生成。同时,我们希望公式中的变量能够引用会话(session)中已存在的变量。然而 DolphinDB 中没有全局变量,那么如何能实现公式中变量的转换与输出呢?

9.1 错误代码

比如期望在函数内部对变量做计算,例如:”B+C“,得到的结果并不符合预期。

a = 1
b = 2
def funcA(a,b){
	B = a+1
	C = b+2
	funcExpr = "B+C"
	return parseExpr(funcExpr).eval()
	}
funcA(a,b)	
//期望的输出:6
//实际的输出:SQL context is not initialized yet.

这是因为,parseExpr 函数解析变量时,首先搜索会话中的局部变量,再搜索共享变量,但不会搜索函数体内定义的局部变量。因此,需要的变量 B 和 C 均找不到,最终保存。想要找到需要的变量,则应当通过字典传入。

9.2 解决方案

如下所示,我们创建了一个字典 d,作为 parseExpr 的参数,即可完成计算。

a = 1
b = 2
def funcA(a, b){
	funcExpr = "B+C"
	d = dict(`B`C, [a+1, b+2])
	return parseExpr(funcExpr, d).eval()
}
funcA(a, b)	

10. 避免将大结果集直接返回客户端

在使用 SQL 查询数据时,如果直接将结果返回给客户端而不赋值给变量,不仅会导致结果无法修改和参与后续计算,还可能因为结果集过大而导致 GUI 或 Web 集群管理界面等终端堆栈溢出并抛出异常。因此,在查询数据时,我们应该尽量将结果赋值给一个变量而不是直接返回给客户端。

10.1 错误代码

下述代码将会在 GUI 抛出异常:Java heap space,在 Web 集群管理界面抛出异常:Out of Memory

select * from loadTable("dfs://StockData","ORDER")

这是因为如果直接进行查询,数据将会返回到终端,过大的数据量会导致客户端的堆栈溢出。

10.2 解决方案

t = select * from loadTable("dfs://StockData", "ORDER")

将查询结果赋值给一个变量,能够正常看到结果:

总结

本文介绍了使用 DolphinDB 进行编程时,最容易忽略的 10 个细节,涵盖了分区冲突、数据类型处理、元编程、分区剪枝、SQL 查询等多个方面。编程时忽略这些细节,可能导致程序运行报错或运算结果不符合预期。若提前了解这些细节,则可以提升脚本的质量,提高编程效率。

了解更多关于 DolphinDB 的编程细节,请参考阅读:编程教程 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1981483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防演练号角吹响,聚铭铭察高级威胁检测系统助您零失分打赢重保攻坚战

在数字化浪潮中&#xff0c;攻防演练成为了衡量网络安全防御力的核心标尺&#xff0c;其重要性与日俱增。这项由政府、行业监管或企业内部主导的安全活动&#xff0c;随着互联网普及而兴起&#xff0c;现已发展成为全球公认的检验网络安全体系效能的标准。它不仅关乎技术实力的…

JaCoCo - Java Code Coverage Library

概述 JaCoCo&#xff08;Java Code Coverage&#xff09;是一个开源的Java代码覆盖率库。它可以帮助开发人员测量单元测试和集成测试中代码的覆盖情况。通过使用JaCoCo&#xff0c;开发人员可以识别哪些代码没有被测试覆盖&#xff0c;从而提高代码的质量和可靠性。 功能 1.…

C语言宠物系统

功能有增加宠物信息&#xff0c;显示宠物信息&#xff0c;删除宠物信息&#xff0c;修改功能和排序功能&#xff0c;可以选择姓名排序&#xff0c;年龄排序&#xff0c;价格排序。进阶的功能有文件操作&#xff0c;动态内存开辟。。 test.c源文件 #include "Pet.h"v…

角色管理功能助你打造精准智慧校园系统

在智慧校园的信息化架构中&#xff0c;角色管理功能犹如一把精细的钥匙&#xff0c;开启着系统安全与高效运作的大门。它不仅关乎信息的访问权限&#xff0c;更深层次地影响着校园内各类活动的顺畅进行。 智慧校园的角色管理&#xff0c;首先体现在对用户群体的细致划分上。系统…

【Linux】进程间通信:详解 VSCode使用 | 匿名管道

目录 0. 引入&#xff1a;vscode 的使用 下载 推荐插件 连接云服务器 1. 进程间通信 1.1 是什么 1.2 为什么 1.3 怎么办 介绍 &#xff1a; 2. 匿名管道 2.1 引入 2.2 原理 3. 建立管道的系统调用pipe 3.1 介绍 形参 返回值 3.2 代码 3.3 站在内核的角度 编…

通俗易懂的告诉你大模型如何微调!

如今&#xff0c;大模型&#xff08;Large Language Models&#xff09;在人工智能领域可是炙手可热的话题。它们拥有庞大的参数和广泛的知识&#xff0c;能够处理各种复杂的任务。然而&#xff0c;就像一把锋利的刀需要经过磨砺才能更贴合手型一样&#xff0c;大模型也需要经过…

鸿道Intewell操作系统X86生态之:Intel J1900

在当今数字化转型的浪潮中&#xff0c;工业自动化和智能制造的需求日益增长&#xff0c;对实时操作系统的性能和可靠性提出了更高的要求。鸿道Intewell操作系统正是聚焦于如何将高性能的处理器与先进的操作系统相结合&#xff0c;以构建一个强大且稳定的工业控制系统。 鸿道I…

【算法系列】双指针

双指针算法 1. 双指针算法概述2 经典双指针算法题目分享1. **复写零**2. 快乐数&#xff08;medium&#xff09;3. 11. 盛最多水的容器4. 有效三⻆形的个数&#xff08;medium&#xff09;5. 四数之和 1. 双指针算法概述 常⻅的双指针有两种形式&#xff0c;⼀种是对撞指针&…

MMC和eMMC的区别

MMC 和 eMMC 的区别 1. MMC MMC&#xff08;MultiMediaCard&#xff09;是一种接口协议&#xff0c;定义了符合这一接口的内存器&#xff0c;称为 MMC 储存体或 MMC 卡。它是一种非易失性存储器件&#xff0c;广泛应用于消费类电子产品中。 1.1 外观及引脚定义 MMC卡共有七个…

文件解析漏洞合集

IIS 解析漏洞 IIS6 目录解析 打开windows——server2003&#xff0c;在 wwwroot 目录下创建 1.asp &#xff0c;在其中创建的所有文件都会在访问时以 asp 解析出来 畸形文件解析 在wwwroot目录下创建 2.asp;.jpg &#xff0c;此文件上传时是 .jpg 后缀,但解析时由于 iis6 文…

transformer死亡9问

transformer死亡20问 1. Transformer为何使用多头注意力机制&#xff1f;2. Transformer为什么Q和K使用不同的权重矩阵生成&#xff0c;为何不能使用同一个值进行自身的点乘3. Transformer计算attention的时候为何选择点乘而不是加法&#xff1f;两者计算复杂度和效果上有什么区…

C#桌面开发(那些年你总走进误区的技术):异步多线程、异步事务与递归技术

1. 异步多线程 (Asynchronous Multithreading) 在C#桌面开发中&#xff0c;异步多线程是提高应用程序响应速度和性能的关键技术之一。以下是几个深入的技术点和示例代码。 1.1 使用async和await实现异步操作 C#的async和await关键字使得编写异步代码变得更加简单。以下是一个…

老司机也会翻车?通过自动建模技术轻松实现工程机械翻滚保护分析

什么是ROPS分析&#xff1f; ROPS分析&#xff0c;指的是"Roll-Over Protective Structure"&#xff08;翻滚保护结构&#xff09;的简称&#xff0c;这是一种用于评估和设计特殊设备&#xff08;如前装载机、各种挖掘机、履带式推土机&#xff09;的被动安全标准&am…

slam过程中每一帧的gt位姿如何计算

一般得到的每一帧数据类似如下&#xff1a; 4*4的变化矩阵&#xff0c;都属于相机到世界坐标系下的变化矩阵&#xff0c;如果是x,y,z和四元数也可以转换为这种4*4的矩阵。 第一帧为世界坐标系的原点&#xff0c;后续的位姿都基于这个原点进行变化。 def load_poses(path, n_im…

HCIA概述

一、OSI七层模型 1.物理层&#xff08;七层&#xff09; 定义物理设备的标准&#xff0c;主要对物理连接方式&#xff0c;电气特性&#xff0c;机械特性等制定统一标准&#xff0c;传输比特流&#xff0c;因此最小的传输单位——位&#xff08;比特流&#xff09;。 2.数据链…

差分专题的练习

神经&#xff0c;树状数组做多了一开始还想着用树状数组来查询差分数组&#xff0c;但是我们要进行所有元素的查询&#xff0c;直接过一遍就好啦 class Solution { public:int numberOfPoints(vector<vector<int>>& nums) {vector<int> c(105, 0);for (i…

Hadoop的安装和使用-2024年08月01日

Hadoop的安装和使用-2024年08月01日 1.创建Hadoop用户2.SSH登陆权限设置3.java的安装4.Hadoop单机安装配置5.Hadoop伪分布式安装配置 1.创建Hadoop用户 如果安装Ubuntu的时候不是用的“hadoop”用户&#xff0c;那么需要增加一个名为 hadoop的用户首先按ctrlaltt打开终端窗口&…

源代码加密防泄漏如何做?

源代码开发环境复杂&#xff0c;涉及的开发软件、文件类型庞杂多变&#xff0c;究竟有什么源代码加密防泄漏软件能够适应众多开发软件而不影响原有的工作效率&#xff1f; 相信这是很多IT管理员或者老板们都想要了解的问题&#xff0c;今天和行业内专业人士讨论&#xff0c;将…

【docker】虚拟化与docker基础

一、虚拟化 1.虚拟化概述 什么是虚拟化&#xff1f; 虚拟化&#xff1a;将应用程序和系统内核资源进行解耦&#xff0c;以操作系统级别进行隔离&#xff0c;目的是提高资源利用率 2、虚拟化的功能 将虚拟化的性能优化趋近于物理资源的性能&#xff0c;主要用于提高资源利用…

浏览器被360劫持了的解决办法

所有浏览器一打开就是360界面&#xff0c;查询资料解决 以谷歌浏览器为例&#xff1a;打开其exe的位置&#xff0c;将exe文件重命名&#xff0c;再次创建快捷方式即可