当前位置: 首页 > news >正文

使用秘籍|如何实现图数据库 NebulaGraph 的高效建模、快速导入、性能优化

本文整理自 NebulaGraph PD 方扬在「NebulaGraph x KubeBlocks」meetup 上的演讲,主要包括以下内容:

  • NebulaGraph 3.x 发展历程
  • NebulaGraph 最佳实践
    • 建模篇
    • 导入篇
    • 查询篇

NebulaGraph 3.x 的发展历程

NebulaGraph 自 2019 年 5 月开源发布第一个 alpha 版本以来,陆陆续续发布了 2.0 GA,到现在 v3.6.0,已经是 v3.x 版本中比较后期的版本了。从 3.x 开始,基本上保持了三个月(一个季度)发一个 y 版本的节奏,从 v3.1 到 v3.2,到现在的 v3.6。(演讲时 v3.6 尚未发布,所以没有相关内容展示)

而这几个版本主要是在完备性、性能,稳定性以及易用性上的优化。从 NebulaGraph 作为一款图数据库的产品定位上来说,核心应用场景是 TP 场景,而对 TP 型数据库产品来说,有几个特性是非常重要的:

  • 稳定:数据库作为底层的基础设施,许多业务是基于数据库运行的,是在线的系统,因此稳定性是一个非常重要的特性。在 NebulaGraph v3.4 版本,包括最新版本的 v3.6 版本中,系统的稳定性得到了非常大的提升和改善;
  • 性能:因为 NebulaGraph 定位是一个 TP 的数据库产品,因此性能,包括高吞吐量是至关重要的;
  • 易用:一个好的产品要如何让用户更好地用起来,降低用户的学习成本,也是需要考虑到的;

针对这些特性,我们在 v3.x 这 5 个版本中做了这些尝试:

稳定性

在 v3.x 开始,NebulaGraph 引入 fuzzer,极大提升测试效率。fuzzer 可基于 nGQL(NebulaGraph 的查询语言)的语法进行灵活组合,生成人为不能拟定的查询语句,由此让测试更加完善,从而提高了稳定性。

此外,版本新特性部分还新增 Memory Tracker。图数据库不同于其他数据库,数据一直处于持续地遍历、迭代中,因为即便是数据量不大的情况下,数据的迭代会导致它的结果异常大,这就造成了内存的管理压力。在 v3.4 版本中,NebulaGraph 引入了 Memory Tracker 机制,从论坛的用户反馈上,可以看得出来相关的 OOM 问题大幅度减少了。这里可以阅读下《内存管理实践之 Memory Tracker》;

性能提升

图的经典查询一般包括 K 跳(K-hop)、子图和路径查询。K 跳就是从一个点出发,比如说从我出发,去找寻我好友(一跳)的好友(两跳),这种查询,可能社交或者反欺诈的场景中使用会比较多。此外,就是子图,比如说我现在从一个点出发,找到他的周围的关联的一群人,以及这一群人关联的另外一群人,这时候就可能会用到子图的功能。还有就是路径查询,像是企业和企业之间的关联关系之类的,就比较适合用路径,来找寻二者的关联。在 v3.x 中,这几个图的经典查询性能都有大幅度的提升的,具体大家可以看论坛的性能报告:自测和他测报告合集;

上面提到过内存管理的难点,除了 Memory Tracker 机制之外,属性裁剪能提升内存的利用率,在 NebulaGraph 中如果查询不需要用到某个属性,就会将其裁剪掉,从而提升内存利用率。

易用性

NebulaGraph 在 v2.x 开始支持 openCypher,一开始是比较基础的 openCypher 语法;在 v3.x 开始,NebulaGrpah 做了一个语法完善,像是 OPTIONAL MATCH、多 MATCH 等语法支持,全面覆盖了国际图基准测试之一的 LDBC-SNB 支持的图查询。

此外,在 v3.5 开始支持了 UDF 功能,这个功能是由社区用户 zhaojunnan 提供支持的,它可以用来帮助实现一些内核暂时不支持的功能。这里就不详细展开 UDF 的说明了,具体大家可以看《NebulaGraph UDF 功能的设计与背后的思考》;

最后一点是全文索引优化,这个在后面章节会详细讲述。

NebulaGraph 的最佳实践

在这个部分主要分为:建模、数据导入、查询等三大内容。

数据建模

数据膨胀

这是社区用户在交流群里反馈的一个问题:

  1. 数据导入之后占用硬盘空间极大,60 MB 的文件导入之后,Storage 占用了 3.5 G;
  2. Storage 服务占用内存很高
  3. 并发量大的时候,会出现 ConnectionPool 不够的情况;
  4. 3 跳查询本来就很慢么?我看官方的 Benchmark 数据规模大的时候会慢,但是当前我们数据量也不是很大;

目前的数据情况:点 594,952,边 798,826。同时,边和点均建了 1 个索引:

所以它有什么问题呢?

在图数据库 NebulaGraph 中,有个概念叫做 Space,Space里有一个概念是 VID type,VID 是 NebulaGraph 中非常关键、重要的概念,所有的数据字段都是通过 VID 来进行唯一索引,类似主键的概念。比如上图的中间部分:点结构和边结构,可以看到结构中都有 VID,用来进行字段查询;边结构还分起点 srcId 和终点 dstId,就是上图的两处 VertexID。

如上图所示,这个 Space 中配置的 VID 类型是 String,而 NebulaGraph 支持的 VID 类型有两种:一种是 INT,数值类型,像手机号之类的可以用 INT 来存储;一种是 String,比如说人名之类的,当然你要用 String 来存储像是身份证号之类的数值信息也可以。但是,用 VID 的查询效率从经验看是 INT 类型是远高于用 String 作为 VID 类型的。

回到上面的这个例子,一开始用户创建 VID 时,直接选取了 FIXED_STRING 类型,设定为了 256 位的定长 String。但是这里会导致一个问题:

  • 594,952(点数)*256 (VID 大小)* (1 + 1) + 798,826(边数)* 256(VID 大小) * (2 + 2 + 2 + 2) = 1.80 GB

上面的例子是数据存储的大小计算过程,点的数量乘以定长的长度(这里是 256),再乘以占据的字节大小,以及边的数量乘以对应 VID 的长度,再乘以对应边 VID 占据的空间大小,算出来是 1.8 GB。由此,我们可以想到一个事情:是不是可以精简下 VID 的定长长度,设置一个合理的数值,比如说是 32,那它空间占据量就是:

  • 594,952(点数)*32(VID 大小)* (1 + 1) + 798,826(边数)* 32(VID 大小)* (2 + 2 + 2 + 2) = 0.23 GB

修改 VID 的定长长度之后,整个空间使用量就是之前的 1/8,还是非常可观的一个磁盘容量优化。如果是更多的点和边数据量的话,缩减的磁盘空间会更客观。由此,我们有个建议:VID 的定长长度尽可能短,同理,属性类型设置亦如是

超级节点

图数据库实践中,超级节点是一个比较常遇到的性能问题。那么,什么是超级节点(稠密点)呢?图论给出的解释是:一个点有着超级多的相邻边,相邻边就是出边(从这个点指向另外一个点)或者是入边(某个点指向这个点)。像是社交网络中 KOL、网红大V 之类的人,或是证券市场的热门股票,交通网络中的枢纽站、银行系统中的四大行、互联网中的高流量站点,或者是电商平台的爆款商品,等等都是整个关系网络中的超级节点。一旦查询中有超级节点,查询速率就会变得异常的缓慢,甚至有时候内存都耗尽了,查询结果还没跑出来。

下面就来讲讲,现阶段你要用 NebulaGraph 可以如何解决或是绕开超级节点:

要在建模环节规避掉超级节点的问题,“拆点”是可行的方式之一。如上图左侧所示,在未优化建模之前,A 通过 transfer 边关系连接到 B1、B2,如果 A 频繁的转账,势必会导致它成为一个超级节点。这时候,你可以将 A 拆分成 A1 和 A2,按照某种约定的方式,比如说转账的日期,或者是由单一客户拆分成对公客户、对私客户,从而达到拆点、避开超级节点形成的目的。不过,这里会涉及到一个 VID 变更的问题,将 A 拆分成 A1 和 A2,会导致对应的 VID 发生变化,当然你可以命名 A1 为 A0721,A2 为 A0722,加上日期数字来标识它们。

相对应拆点,还有拆/合边的方式。在两个点之间,有许多同一类型的边,比如说转账关系,这时候,可以根据业务的逻辑来进行判断,比如取最短边、最新边、最大边、最小边等,在一些不需要明细的场景里,只体现关系出来,这样就能提升查询效率。除了合并之外,拆边也是一种方式,如上图右侧所示,两个点之前有非常多的关系,它们都是交易类型,可能有一部分是发红包,有一部分是转账,这时候,你就可以按照拆点的逻辑,将边进行拆解。

此外,还有截断,NebulaGraph 有个配置参数是 max_edge_returned_per_vertex,用来应对多邻边的超级节点问题。比如我现在 max_edge_returned_per_vertex 设置成 1,000,那系统从点 A 出发,遍历 1,000 个点之后就不再遍历了,便将结果返回给系统。这里会存在一个问题,加入 A 和 B1 之间存在 1 千多条边,A 和 B2 存在 3 条边,按照这种遍历 1,000 条边之后就不再遍历的设定,可能返回结果中 A 和 B2 的关系边就不会返回了,因为这个遍历返回是随机的。

其他的话,同相关的社区用户交流,我发现在许多业务场景中,超级节点并没有太大的实际业务价值。这里就要提下“超级节点的检测”,比如:通过度中心性算法(DegreeCentrality)计算出出入度大小,这个图算法 nebula-algorithm 和 nebula-analytics 都支持。当这个算法跑完之后,得到的二维表就能告诉你哪些是超级节点,提早让用户知道哪些点会影响查询效率。

此外,假如现在你有一个已知的超级节点,且不方便处理,那查询的时候就要尽量避免逆向查询,即从这个超级节点出发,查询其他节点。

数据导入

社区用户经常遇到的还有一类问题:数据导入慢的问题。一般新的社区用户都会问:你们的导入性能如何?这时候我们一般会说:导入性能老牛逼了,而且我们是直接用 INSERT 方式导入的,速度贼快,之前遇到最快的是 600MB/s。

这时候用户一般会反问:为什么我测试出来,导入速度没有官方说的那么快。

这里就展开说说如何提升你的数据导入性能。

熟悉 NebulaGraph 的小伙伴都知道,它的底层存储是基于 RocksDB 实现的,而 RocksDB 有 wal_ttl 这么一个配置项,如果你的导入数据量非常大,对应的 wal 日志也会相对应的变大。因此,建议在进行数据导入时,将 wal_ttl 时间设短一点,以防止膨胀的 wal 日志过度地占用磁盘,可以得到及时的清理。此外,就是 Compaction 相关的配置项,主要是 max_subcompactionsmax_background_jobs 这两个参数项,一般建议将其设置为 CPU 核数的一半。而这个一半的参数建议,主要来源于用户的反馈以及一些经验数据,不同的场景还是需要不同的配置,HDD 和 SSD 的配置也有所不同,大家可以后面看着情况进行调试。

除了配置参数之外,在做数据导入之前,建议大家执行下 SHOW HOSTS 操作,查看 leader 是否分布均匀:NebulaGraph 会将数据分为若干个 partition,每个 partition 会随机分布在节点上,理想状态自然是 partition 的 leader 是均匀地分布在各个节点的。假如 leader 分布不均的话,可以执行 BALANCE LEADER 操作,确保其均匀分布。

在工具配置方面,可能就是数据导入的重头戏了,配置你的数据导入工具参数:

  • 配置项 concurrency,表示导入工具连接多少个 graphd(查询)节点,一般设置为导入工具 nebula-importer 所在机器的 CPU 核数;
  • manager.batch,虽然 NebulaGraph 支持你通过 INSERT 来一个个点插入到数据库中,但是这个有些低效。因此,设立了 batch 字段用来将一批数据导入到数据库中,默认参数设置是 128,不过这里要根据你自身的数据特性来进行优化。假如你的属性值很多,那么建议将 batch 调小;反之,将 batch 值调大即可。整个 batch 的大小,建议小于 4MB;
  • manager.readerConcurrency 是数据读取的并发数,即,从数据源读取数据的并发数。默认参数是 50,一般建议设置为 30-50 即可;
  • manager.importerConcurrency,数据读取之后,会根据一定的规则拼接成 batch 块,这里就涉及到这个参数项。manager.importerConcurrency 指的是生成待执行的 nGQL 语句的协程数,一般来说它会设置成 manager.readerConcurrency 字段的 10 倍,默认值是 512;

软件说完了,来说下硬件方面的配置。NebulaGrpah 优先推荐使用 SSD,当然 HDD 也是可以的,不过性能相对会差点。此外,在 data_path 下多配置几块盘,每个路径配置一个盘,这个也是之前的实践经验总结出来的。而机器和机器之间,推荐使用万兆网卡。最后一点是,nebula-importer 之类的导入工具有条件的话尽量单独部署,和集群隔离开,不然的话在一台机器人会存在资源抢占的问题。

软硬件都说完了,剩下就是数据本身的问题。图数据库的定位是关系分析,同此无关的事情,例如:全文搜索(ES 擅长的场景),要看情况是否将该部分数据放入到 NebulaGraph 中。由于 NebulaGraph 进行数据导入时,不存在导入的先后顺序,即点和边一起混合导入,这样设计的好处是,数据无需做预处理,坏处是数据导入之后可能会产生悬挂边,不利于后续的查询。最后要留意起点,或终点为空的数据,或者是异常数据,这些数据在异常处理时很容易一不小心形成超级节点。

查询指南

下面来讲讲如何搞定 NebulaGraph 的查询篇。这里是一些 tips:

  • MATCH 性能比 GO 略慢,但 MATCH 是我们优化的重点。如果没有强性能需求的话,推荐还是尽量使用 MATCH,表达能加丰富之外,它同将要出炉的 ISO GQL(图查询语言)是匹配的;
  • 慎用函数(无法下推),在 NebulaGraph 中并没有将函数下推到 storage。因此,像 src(edge)dst(edge)rank(edge)properties($$) 之类的函数,性能都不如 edge_.srcedge._dstedge._rank$$.tag.prop 这些下推到 storage 的表达;
  • 遇到聚合且需要取属性的情况,先聚合再取属性,因为取属性耗时较长;
  • MATCH 如果只是最后需要返回 count,那么对于 count 的变量最好采用 count(id(v)) 类似的形式,这样会应用到属性裁剪,减少内存消耗;
  • 能不带路径尽量不要带路径,带路径需要进行路径构造,属性裁剪会失效,此外,还会增加很多额外的内存开销。

总的来说,减少模糊、增加确定,越早越好

内存保护试试 Memory Tracker

在 v3.4 版本中,引入的一个大功能是:Memory Tracker,用来保护内存,防止内存占用过大导致的 OOM 问题。

  • 预留内存:memory_tracker_untracked_reserved_memory_mb(默认 50 MB)。Memory Tracker 机制会管理通过 new/delete 申请内存,但进程除了通过此种方式申请内存外,还可能存在其他方式占用的内存;比如通过调用底层的 malloc/free 申请,这些内存通过此 flag 控制,在计算时会扣除此部分未被 track 的内存,所以这里预留了 50 MB;
  • 内存比例:memory_tracker_limit_ratio,就是实际可用内存的比例占用多少的情况下,会限制它再申请使用内存。一般默认是 0.8,就是这个内存占用小于 0.8 的情况下,是可以随意使用内存的;当系统内存占用超过 80% 时,系统便会拒绝掉新的查询语句;
    • 数值范围:(0,1],默认 0.8 且为开启状态。大多数的用户的 storage 和 graph 节点都存在混部情况,这时候就会建议调低 memory_tracker_limit_ratio,顺便说一句,这个参数项是支持在线调整的;
    • 数值配置成 2,则会对其进行动态调整,这个动态分配的内存占用比例可能会不大精准;
    • 数值配置成 3,则关闭 Memory Tracker 功能;

此外,你如果要调试 Memory Tracker 的话,可以开启 memory_tracker_detail_log 来获得调试日志,这个参数项默认是关闭的。

经测试,Memory Tracker 对性能有 1% 左右的影响,但是对于上层为平台类产品或者交互式分析类产品,强烈建议打开。为什么呢?因为上层的业务同学不大了解 NebulaGrpah 运行机制的情况下,容易将服务打满,导致内存爆炸,因此开启这个功能之后,至少能保证系统的稳定运行。

最后,如果动态申请内存时,返回报错 GRAPH_MEMORY_EXCEEDED/STORAGE_MEMORY_EXCEEDED 说明这个内存已经不够用,这条查询语句将不会执行(被杀掉)。

语句调试得用 PROFILE

在任意一条 nGQL 查询语句前面加入 PROFILE,并能得到这条语句的执行计划。

上图一条语句的整个生命周期,Planner 是执行计划(Execution Plan)生成器,它会根据 Validator 校验过、语义合法的查询语法树生成可供执行器(Executor)执行的未经优化的执行计划,而该执行计划会在之后交由 Optimizer 生成一个优化的执行计划,并最终交给 Executor 执行。执行计划由一系列节点(PlanNode)组成。而下图则是一些常见的算子,上图每一个 Plan 节点对应了一个算子:

算子介绍
GetNeighbor根据指定的 vid ,从存储层获取起始点和边的属性
Traverse仅用于 MATCH 匹配 ()-[e:0..n]-() 模式,获取拓展过程中的起始点和边的属性
AppendVerticesMATCH 使用,同算子 Traverse 配合获取点的属性
GetEdge获取边的属性
GetVertices获取点的属性,FETCH PROP 或者 GO 语句中。
ScanEdge全表扫描边,例如 MATCH ()-[e]->() RETURN e LIMIT 3
ScanVertices全表扫描点,例如 MATCH (v) return v LIMIT 3
IndexScanMATCH 语句中找到起始点的索引查询
TagIndexPrefixScanLOOKUP 语句中前缀扫描 LOOKUP ON player where player.name == "Steve Nash" YIELD player.name
TagIndexRangeScanLOOKUP 语句中范围扫描 LOOKUP ON player where player.name > "S" YIELD player.name
TagIndexFullScanLOOKUP 语句中全扫描 LOOKUP ON player YIELD player.name
Filter按条件过滤,例如 WHERE 语句
Project获取上一步算子的列
Dedup去重
LeftJoin合并结果
LIMIT限制输出行数

下面这个是一个例子,我们可以结合例子讲解下。一般来说 PROFILE 会生成一个执行计划,同 EXPLAIN 生成执行计划不同,PROFILE 生成的执行计划中会有相对应的执行时间在里面,比如说下面这张图:

一般来说,我们看执行计划不只是看上下的调用关系,还需要去看里面的具体执行细节:

  • execTime:graphd 的处理时间;
  • totalTime:graphd 算子起到到算子退出时间;
  • total_rpc_time:graphd 调用 storage client 发出请求到接收到请求时间;
  • exec:storaged 的处理时间,同上面的 graphd 处理时间的 execTime
  • total:storage client 接收到 graphd 请求到 storage client 发送请求的时间,即 storaged 本身的处理时间加上序列化和反序列化的时间;

除了查看时间之外,我们还要查看 row 就能看到 graphd 和 storaged 的具体通信量大小。上图有 3 个 Partition,每个 Partition 返回 1 个 limit 1,总共就 3 条数据。

此外,还得查看执行计划中是否包含计算下推:

上面两条查询语句的差异,上面提到过,就是将函数改成其他调用方式,将 properties(edge).degree 改为 follow.degree,很明显地看到计算下推了。

某个功能不支持array

因为产品规划的问题,NebulaGraph 可能有些功能没法直接支持。比如用户反馈的:

当前属性仅支持基本类型 long、string,来构建索引。是否可以支持多值,比如:long[]string[] 来构建索引?

的确目前不支持 array,有什么曲线救国的法子?这里提供一些方法,仅供参考:

  1. 把数组放到 string 里,进行查询时,将数据读取出来进行解析,虽然有点不优雅,但是能解决问题;
  2. 转化成 bitmap,将不同的类型组成 bitmap,虽然导致代码会复杂点,但可以获得比较快的过滤;
  3. 边上的 array 转换成两点之间的平行边,相当于一条边就是一个属性,可以方便地进行属性过滤,当然它会带了额外的边数量增加问题;
  4. 点上的 array 转化成自环边,弊端第 3 种方式,会产生大量自己指向自己的平行边;
  5. 把属性作为 tag,比如我现在有个商品,它在北京、上海、杭州都有仓库,这时候可以将这个货点变成一个 tag 属性,从而方便地对其进行查询。这里需要注意的是,这个方式容易产生超级节点,这里就需要注意避免超级节点的产生。

功能更强了 UDF

用户自定义函数(User-defined Function,UDF),用户可以在 nGQL 中调用函数。与从 nGQL 中调用的内置函数一样,UDF 的逻辑通常扩展或增强了 nGQL 的功能,使其具有 nGQL 没有或不擅长处理的功能。UDF 被定义后可以重复使用。

这里简述下 UDF 的使用过程:

  1. 准备编译环境 & 下载源码:https://docs.nebula-graph.com.cn/3.5.0/4.deployment-and-installation/1.resource-preparations/

  2. 进入到 NebulaGraph 代码仓库,创建 UDF 相关源码文件。当前有两个示意文件 standard_deviation.cpp / standard_deviation.h 可以参考

  3. 编译 UDF

g++ -c -I ../src/ -I ../build/third-party/install/include/ -fPIC standard_deviation.cpp -o standard_deviation.o
g++ -shared -o standard_deviation.so standard_deviation.o
  1. 加载 UDF 至 graphd 服务

编辑 graphd 服务配置文件:打开 /usr/local/nebula/etc/nebula-graphd.conf 文件,添加或修改以下配置项:

#  UDF  C++
--enable_udf=true
#  UDF .so
--udf_path=/home/foobar/dev/nebula/udf/
  1. 重启 graphd
udo /usr/local/nebula/scripts/nebula.service restart graphd
  1. 连接到 graphd 后验证
GO 1 TO 2 STEPS FROM “player100” OVER follow YIELD properties(edge).degree AS d | yield collect($-.d) AS d | yield standard_deviation($-.d)

不过,目前 UDF 有些问题:

  1. so 包位置只支持扫描本地,也就是如果你是分布式集群的话,每个机器上都得有个包;
  2. 函数只在 graphd 层,无法下推到存储;
  3. 暂不支持 Java(性能考虑),未来版本会支持;

待解决的问题

这里罗列下未来的产品可优化点:

  1. 全文索引:v3.4 之前的全文索引功能都不太好用,约束比较多,且有些 bug。v3.4 版本做了精简和优化,更加稳定。但实际上,v3.4 及之前的全文索引功能准确讲并不是真正意义的全文索引,主要是支持前缀搜索、通配符搜索、正则表达式搜索和模糊搜索等。并不支持分词、以及查询的分数,v3.6 版本(即将发布)做了全文索引的优化,重新设计了全文索引功能(可以更好的支持 Neo4j 替换)。不过与原有的全文索引不兼容,需要重建索引;
  2. 关于悬挂边的产生:设计理念,不隐式的对数据进行变更导致(删除点的时候不隐式删除边),当然由此会带来悬挂边和孤儿点的问题,后面这块会考虑进行相关的优化;
  3. 事务的支持,大多数人对 NebulaGraph 的事务需求来源于,他认为 NebulaGraph 是一款 TP 产品,TP 产品是一定具备事务性的,这并非是业务场景的需求。当然,事务这块撇开这种某款产品必须具备的特性之外这点,一些生产链路上面,事务还是一个强需求,因此在后续的开发中也会新增事务特性。

其他问题交流

下面问题整理自本次分享的 QA 部分:

Q:上文提到 VID 的设定,是越短越好。短的 VID 会带来什么后果么?

方扬:VID 理论上是越短越好,没有任何的副作用。不过它的设定是在满足你既有的业务需求,不要出现重复的 VID 情况下,尽可能的短即可;

Q:截断的话,是对返回的数据量做限制,这个返回的话是有序的么?

训焘:目前数据的返回是 random,随即返回的,随机根据你的 range 来返回一些数据量。


谢谢你读完本文 (///▽///)

如果你想尝鲜图数据库 NebulaGraph,记得去 GitHub 下载、使用、(з)-☆ star 它 -> GitHub;和其他的 NebulaGraph 用户一起交流图数据库技术和应用技能,留下「你的名片」一起玩耍呀~

相关文章:

使用秘籍|如何实现图数据库 NebulaGraph 的高效建模、快速导入、性能优化

本文整理自 NebulaGraph PD 方扬在「NebulaGraph x KubeBlocks」meetup 上的演讲,主要包括以下内容: NebulaGraph 3.x 发展历程NebulaGraph 最佳实践 建模篇导入篇查询篇 NebulaGraph 3.x 的发展历程 NebulaGraph 自 2019 年 5 月开源发布第一个 alp…...

对于pycharm 运行的时候不在cmd中运行,而是在python控制台运行的情况,如何处理?

对于pycharm 运行的时候不在cmd中运行,而是在python控制台运行的情况,如何处理? 比如,你在运行你的代码的时候 它总在python控制台运行,十分难受 解决方法 在pycharm中设置下即可,很简单 选择运行点击…...

Spring MVC 二 :基于xml配置

创建一个基于xml配置的Spring MVC项目。 Idea创建新项目&#xff0c;pom文件引入依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.12.RELEASE</version>…...

springboot aop方式实现接口入参校验

一、前言 在实际开发项目中&#xff0c;我们常常需要对接口入参进行校验&#xff0c;如果直接在业务代码中进行校验&#xff0c;则会显得代码非常冗余&#xff0c;也不够优雅&#xff0c;那么我们可以使用aop的方式校验&#xff0c;这样则会显得更优雅。 二、如何实现&#xf…...

解决git上传远程仓库时的大文件提交

在git中超过100M的文件会上传失败&#xff0c;而当一个文件超过50M时会给你警告&#xff0c;如下 warning: File XXXXXX is 51.42 MB; this is larger than GitHubs recommended maximum file size of 50.00 MB 解决这种问题&#xff0c;首先在项目的.git文件夹中找到.gitigno…...

HTML学习笔记02

HTML笔记02 页面结构分析 元素名描述header标题头部区域的内容&#xff08;用于页面或页面中的一块区域&#xff09;footer标记脚部区域的内容&#xff08;用于整个页面或页面的一块区域&#xff09;sectionWeb页面中的一块独立区域article独立的文章内容aside相关内容或应用…...

<C++> 内存管理

1.C/C内存分布 让我们先来看看下面这段代码 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char *pChar3 "abcd";int *ptr1 (int *) mal…...

【Java】ByteBuffer类的arrayOffset方法详解+示例

arrayOffset功能详解;arrayOffset在position等于0和非0两种场景下的demo。使用类java.nio.ByteBuffer中的arrayOffset()方法可以获得这个缓冲区的第一个元素在底层支持(backing)数组中的偏移量。 如果这个buffer底层是由数组支持的,那么buffer的postion p对应于数组的index…...

【C++】C++ 引用详解 ⑤ ( 函数 “ 引用类型返回值 “ 当左值被赋值 )

文章目录 一、函数返回值不能是 " 局部变量 " 的引用或指针1、函数返回值常用用法2、分析函数 " 普通返回值 " 做左值的情况3、分析函数 " 引用返回值 " 做左值的情况 函数返回值 能作为 左值 , 是很重要的概念 , 这是实现 " 链式编程 &quo…...

Git,分布式版本控制工具

1.为常用指令配置别名&#xff08;可选&#xff09; 打开用户目录&#xff0c;创建.bashrc文件 &#xff08;touch ~/.bashrc&#xff09; 2.往其输入内容 #用于输出git提交日志 alias git-loggit log --prettyoneline --all --graph --abbrev-commit #用于输出当前目录所有文…...

LeetCode 面试题 02.02. 返回倒数第 k 个节点

文章目录 一、题目二、C# 题解 一、题目 实现一种算法&#xff0c;找出单向链表中倒数第 k 个节点。返回该节点的值。 注意&#xff1a;本题相对原题稍作改动 点击此处跳转题目。 示例&#xff1a; 输入&#xff1a; 1->2->3->4->5 和 k 2 输出&#xff1a; 4 说…...

SpeedBI数据可视化工具:丰富图表,提高报表易读性

数据可视化工具一大作用就是能把复杂数据可视化、直观化&#xff0c;更容易看懂&#xff0c;也就更容易实现以数据驱动业务管理升级&#xff0c;因此一般的数据可视化工具都会提供大量图形化的数据可视化图表&#xff0c;以提高报表的易懂性&#xff0c;更好地服务企业运营决策…...

编写Dockerfile制作Web应用系统nginx镜像

文章目录 题目要求&#xff1a;一、创建文档&#xff0c;编写Dockerfile文件可以将harbor仓库去启动先起来 二、运行Dockerfile&#xff0c;构建nginx镜像三、推送导私有仓库&#xff0c;也就是我们的harbor仓库 题目要求&#xff1a; 编写Dockerfile制作Web应用系统nginx镜像…...

记录一次微服务连接Nacos异常-errorMsg: Illegal character in authority at index 7:

组件信息 Nacos 2.2.3 SpringCloud微服务 部署环境&#xff1a;centerOS 部署方式&#xff1a;k8s 前言 nacos开启鉴权&#xff0c;nacos地址通过变量方式传入服务中 PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", "${NACO…...

【Java】反射 之 调用构造方法

调用构造方法 我们通常使用new操作符创建新的实例&#xff1a; Person p new Person();如果通过反射来创建新的实例&#xff0c;可以调用Class提供的newInstance()方法&#xff1a; Person p Person.class.newInstance();调用Class.newInstance()的局限是&#xff0c;它只…...

Hightopo 使用心得(6)- 3D场景环境配置(天空球,雾化,辉光,景深)

在前一篇文章《Hightopo 使用心得&#xff08;5&#xff09;- 动画的实现》中&#xff0c;我们将一个直升机模型放到了3D场景中。同时&#xff0c;还利用动画实现了让该直升机围绕山体巡逻。在这篇文章中&#xff0c;我们将对上一篇的场景进行一些环境上的丰富与美化。让场景更…...

【Python PEP 笔记】201 - 同步迭代 / zip() 函数的使用方法

原文地址&#xff1a;https://peps.python.org/pep-0201/ PDF 地址&#xff1a; 什么是同步迭代 同步迭代就是用 for 一次循环多个序列。 类似于这样的东西&#xff1a; arr1 [1, 2, 3, 4] arr2 [a, b, c, d] for a, b in arr1, arr2:print(a, b)使用 map 实现 for a, b …...

远程控制:用了向日葵控控A2后,我买了BliKVM v4

远程控制电脑的场景很多&#xff0c;比如把办公室电脑的文件发到家里电脑上&#xff0c;但是办公室电脑旁边没人。比如当生产力用的电脑一般都比较重&#xff0c;不可能随时带在身边&#xff0c;偶尔远程操作一下也是很有必要的。比如你的设备在工况恶劣的环境中&#xff0c;你…...

基于swing的火车站订票系统java jsp车票购票管理mysql源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的火车站订票系统 系统有2权限&#xff1a;…...

MAVEN利器:一文带你了解IDEA中如何使用Maven

前言&#xff1a; 强大的构建工具——Maven。作为Java生态系统中的重要组成部分&#xff0c;Maven为开发人员提供了一种简单而高效的方式来构建、管理和发布Java项目。无论是小型项目还是大型企业级应用&#xff0c;Maven都能帮助开发人员轻松处理依赖管理、编译、测试和部署等…...

R语言15-R语言中的列的分裂与合并长宽数据转换

列的分裂与合并 列的分裂&#xff1a; 使用 separate() 函数将一个包含多个值的列分裂成多个列。 install.packages("tidyr") # 安装 tidyr 包&#xff08;如果尚未安装&#xff09; library(tidyr)data <- data %>%separate(col_name, into c("part1…...

使用Pytorch和OpenCV实现视频人脸替换

“DeepFaceLab”项目已经发布了很长时间了&#xff0c;作为研究的目的&#xff0c;本文将介绍他的原理&#xff0c;并使用Pytorch和OpenCV创建一个简化版本。 本文将分成3个部分&#xff0c;第一部分从两个视频中提取人脸并构建标准人脸数据集。第二部分使用数据集与神经网络一…...

【力扣】202. 快乐数 <哈希>

【力扣】202. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 【快乐数】 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 如果这个过程…...

深度学习4. 循环神经网络 – Recurrent Neural Network | RNN

目录 循环神经网络 – Recurrent Neural Network | RNN 为什么需要 RNN &#xff1f;独特价值是什么&#xff1f; RNN 的基本原理 RNN 的优化算法 RNN 到 LSTM – 长短期记忆网络 从 LSTM 到 GRU RNN 的应用和使用场景 总结 百度百科维基百科 循环神经网络 – Recurre…...

自动驾驶感知传感器标定安装说明

1. 概述 本标定程序为整合现开发的高速车所有标定模块,可实现相机内参标定和激光、相机、前向毫米波 至车辆后轴中心标定,标定参数串联传递并提供可视化工具验证各个模块标定精度。整体标定流程如下,标定顺序为下图前标0-->1-->2-->3,相同编号标定顺序没有强制要求…...

基于JAYA算法优化的BP神经网络(预测应用) - 附代码

基于JAYA算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于JAYA算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.JAYA优化BP神经网络2.1 BP神经网络参数设置2.2 JAYA算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…...

基于单片机串口控制直流电机调速

一、系统方案 (2)本设计采用STC89C5单片机作为主控器&#xff0c;串口控制直流电机调速&#xff0c;串口助手发送1-8&#xff0c;改变电机速度&#xff0c;数码管显示对应速度。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 TMOD0x21;//定…...

Linux(基础篇一)

Linux基础篇 Linux基础篇一1. Linux文件系统与目录结构1.1 Linux文件系统1.2 Linux目录结构 2. VI/VIM编辑器2.1 vi/vim是什么2.2 模式间的转换2.3 一般模式2.4 插入模式2.4.1 进入编辑模式2.4.2 退出编辑模式 2.5 命令模式 3. 网络配置3.1 网络连接模式3.2 修改静态ip3.3 配置…...

小程序如何手动变更会员卡等级

有时候需要商家手动变更会员卡等级&#xff0c;以让会员获取更多的福利和特权。下面就介绍一些小程序手动变更会员卡等级的常见方法和策略。 1. 找到指定的会员卡。在管理员后台->会员管理处&#xff0c;找到需要更改等级的会员卡。也支持对会员卡按卡号、手机号和等级进行…...

Tensorflow2.0搭建网络八股

目录 引言&#xff1a;keras与Tensorflow2.0结合 一、六步法 1.导入头文件&#xff1a;import 2.收集处理训练集和测试集&#xff1a;train, test&#xff1a; 3.描述各层网model tf.keras.models.Sequential&#xff1a; 4.描述使用什么优化反向传播&#xff1a;model.c…...

【安装GPU版本pytorch,torch.cuda.is_available()仍然返回False问题】

TOC 第一步 检查cuda是否安装&#xff0c;CUDA环境变量是否正确设置&#xff0c;比如linux需要设置在PATH&#xff0c;window下环境变量编辑看看&#xff0c;是否有CUDA 第二步&#xff0c;核查python中torch版本 首先查看你环境里的pytorch是否是cuda版本&#xff0c;我这…...

Git 版本控制系统

git相关代码 0、清屏幕&#xff1a;clear 1、查看版本号 git -v2、暂存、更改、提交 3、当前项目下暂存区中有哪些文件 git ls-files4、查看文件状态 git status -s5、暂时存储&#xff0c;可以临时恢复代码内容 git restore 目标文件 //&#xff08;注意&#xff1a;完全…...

70吨服务区生活污水处理设备加工厂家电话

70吨服务区生活污水处理设备加工厂家电话 设备简单说明 调节池 由于来水标高低&#xff0c;无法直接流入地埋式生活污水处理设备&#xff0c;在生化一体化设备前增加集水调节池一座。集水提升池内装有两台潜水提升泵&#xff0c;将集水提升池内的废水提升至一体化污水处理设备。…...

十一、hadoop应用

1.上传数据集 27.19.74.143,2015/3/30 17:38,/static/image/common/faq.gif 110.52.250.126,2015/3/30 17:38,/data/cache/style_1_widthauto.css?y7a 27.19.74.143,2015/3/30 17:38,/static/image/common/hot_1.gif 27.19.74.143,2015/3/30 17:38,/static/image/common/hot_2…...

Pytorch06-复杂模型构建

https://github.com/ExpressGit/Pytorch_Study_Demo 1、PyTorch 复杂模型构建 1、模型截图2、模型部件实现3、模型组装 2、模型定义 2.1、Sequential 1、当模型的前向计算为简单串联各个层的计算时&#xff0c; Sequential 类可以通过更加简单的方式定义模型。2、可以接收…...

iPhone 15 Pro与谷歌Pixel 7 Pro:哪款相机手机更好?

考虑到苹果最近将更多高级功能转移到iPhone Pro设备上的趋势,今年秋天iPhone 15 Pro与谷歌Pixel 7 Pro的对决将是一场特别有趣的对决。去年发布的iPhone 14 Pro确实发生了这种情况,有传言称iPhone 15 Pro再次受到了苹果的大部分关注。 预计iPhone 15系列会有一些变化,例如切…...

react通过ref获取函数子组件实例方法

在react16之后带来了hooks之后&#xff0c;确实方便了很多组件开发&#xff0c;也加快了函数式编程的速度&#xff0c;但是当你通过useRef获取子组件的时候&#xff0c;又恰好子组件是一个函数组件&#xff0c;那么将会报一个错误&#xff1a;报这个错误的主要原因是函数组件没…...

MathType7MAC中文版数学公式编辑器下载安装教程

如今许多之前需要手写的内容都可以在计算机中完成了。以前我们可以通过word输入一些简单的数学公式&#xff0c;但现在通过数学公式编辑器便可以完成几乎所有数学公式的写作。许多简单的数学公式&#xff0c;我们可以使用输入法一个个找到特殊符号并输入&#xff0c;但是对于高…...

python项目实战

文章 项目1&#xff1a;外星人入侵项目2&#xff1a;数据可视化2.a matplotlib2.b csv文件格式2.c json文件格式2.d 使用Web API2.e 使用Pygal可视化仓库 项目3&#xff1a;Web应用程序3.1 Django入门3.1.1 建立项目3.1.2 创建应用程序3.1.3 创建网页 3.2 用户账户3.2.1 让用户…...

网络渗透day03-Windows Server相关知识

1.在Windows Server中&#xff0c;以下哪个工具用于实时监视系统资源使用情况&#xff1f; A.Event Viewer B.Task Manager C.Performance Monitor D.Resource Monitor 正确答案&#xff1a;D 答案解析&#xff1a;Resource Monitor用于实时监视系统资源使用情况。 2.在Wi…...

关于述职答辩的一点思考和总结

公众号&#xff1a;赵侠客 侠客说&#xff1a;优秀人才的四个特征&#xff1a;格局、思路、实干、写作 一、前言 1.1 述职答辩的重要性 公司都会有晋升通道&#xff0c;述职答辩是你想升职加薪除了跳槽以外的必由之路&#xff0c;其重要性对个人发展来说不言而喻&#xff0c…...

远程调试环境配置

远程调试环境配置 前期准备ssh连接 前期准备 安装vscode中的两个扩展包php-debug和remote-ssh 然后安装与PHP版本对应的xdebug 访问xdebug的官方网页&#xff0c;复制自己的phpinfo源码到方框中&#xff0c;再点击Analyse ssh连接 输入&#xff0c;你想要远程连接的主机i…...

C++:构造方法(函数);拷贝(复制)构造函数:浅拷贝、深拷贝;析构函数。

1.构造方法(函数) 构造方法是一种特殊的成员方法&#xff0c;与其他成员方法不同: 构造方法的名字必须与类名相同&#xff1b; 无类型、可有参数、可重载 会自动生成&#xff0c;可自定义 一般形式:类名(形参)&#xff1b; 例: Stu(int age); 当用户没自定义构造方法时&…...

vr内容编辑软件降低了虚拟现实项目开发门槛

VR虚拟场景编辑器是一种专门用于创建、修改和设计虚拟场景的工具。它利用vr虚拟现实技术&#xff0c;让用户可以在三维空间中直接对场景进行操作和编辑。这种编辑器的出现&#xff0c;使得用户可以更加直观、自由地进行场景设计和制作&#xff0c;为诸多领域带来了新的可能性。…...

【水平垂直居中布局】CSS实现水平垂直居中的5种方法(附源码)

文章目录 写在前面涉及知识点1、子绝对定位父相对定位&#xff0c;子节点设置位移实现1.1效果1.2实现源码 2、子绝对定位父相对定位&#xff0c;子节点设置上下边距2.1 效果2.2 实现源码 3、利用flex布局实现3.1 效果3.2 实现源码 4、利用行高和文本水平居中设置4.1 效果4.2 实…...

原生js插入HTML元素

原生js插入HTML元素方法&#xff1a;insertAdjacentHTML insertAdjacentHTML语法格式 element.insertAdjacentHTML(position, text); 1&#xff09;position 是相对于 element 元素的位置&#xff0c;并且只能是以下的字符串之一&#xff1a; 1.beforebegin&#xff1a;在 ele…...

腾讯云V265/TXAV1直播场景下的编码优化和应用

// 编者按&#xff1a;随着视频直播不断向着超高清、低延时、高码率的方向发展&#xff0c; Apple Vision的出现又进一步拓展了对3D, 8K 120FPS的视频编码需求&#xff0c;视频的编码优化也变得越来越具有挑战性。LiveVideoStackCon 2023上海站邀请到腾讯云的姜骜杰老师分享腾…...

牛客练习赛114 G-图上异或难题(线性基)

题目要求把点涂成白和黑两种颜色&#xff0c;如果一条边左右两端是不同的颜色的话&#xff0c;结果就异或这跳边的权值&#xff0c;求结果最大是多少 把边的贡献转换成点的贡献 我们只考虑白色点的情况下&#xff0c;如果一个点A是白色&#xff0c;就把结果异或上这一个点A周…...

Neo4j之ORDER BY基础

ORDER BY 语句用于对查询结果进行排序。以下是一些常用的示例和解释&#xff1a; 按属性值排序&#xff1a; MATCH (p:Person) RETURN p.name, p.age ORDER BY p.age DESC这个示例返回所有人节点的姓名和年龄属性&#xff0c;并按年龄降序排序。 按多个属性排序&#xff1a;…...

【C++杂货铺】探索vector的底层实现

文章目录 一、STL1.1 什么是STL?1.2 STL的版本1.3 STL的六大组件 二、vector的介绍及使用2.1 vector的介绍2.2 vector的使用2.2.1 vector的定义2.2.2 vector iterator2.2.3 vector空间增长问题2.2.4 vector增删查改 2.3 vector\<char\> 可以替代 string 嘛&#xff1f; …...