国产多维数据库 NeuralCube!中国人自己的大数据底层核心技术!
商业转载请联系作者获得授权,非商业转载请注明出处。
提到‘数据库’,首先被想到的肯定是Oracle、DB2、SQL Server、MySql这些传统的关系型数据库。数据库的概念是非常宽泛的,除了上述的关系数据库,还有NoSQL(Not Only SQL)数据库,还有一些基于分布式技术框架(Hadoop、Spark)的大数据存储和处理体系也被称为数据库,以及基于逻辑多维结构的多维数据库(Multi Dimensional Database,MDD)。今天这里要介绍的就是这个多维数据库。
如果您做过数据分析相关的工作,那应该对多维结构和多维数据分析不陌生。
关系数据库中的ROLAP星型表结构是较为常见的“数据分析模型”,但从严格意义上来讲,它并不具备多维分析的能力,ROLAP之所以被广泛认知,是因为它易于被理解,只要是接触过关系数据库,就能很快搞懂ROLAP的套路。
ROLAP有两个比较明显的问题,难以优化和模型抽象程度低。
难以优化。对关系型数据库来说,如果一套表结构模型具有非常复杂的关联关系,但是这些表的数据量并不大,那么在进行复杂逻辑的查询时并不需要过多考虑性能优化问题,把精力专注在查询逻辑即可。另外一种情况,如果一个数据库表有大量的数据,但是其结构和查询逻辑很简单,那么是可以对其进行一些通用的优化,使其能够满足大部分查询的效率要求。
对ROLAP体系来说,它的复杂逻辑查询与对海量数据的运算是严重耦合的。
如果是对一套星型结构的查询,要处理的情况相对还是简单些的;如果是对多套星型结构进行跨业务的查询,那么情况会非常复杂。
即使是能对某一个复杂查询进行很好的优化,而对于并不可预知的其他查询逻辑,并没有办法进行通用的优化。
模型抽象程度低。由于ROLAP是基于关系数据库表结构的,所以其描述的模型始终摆脱不了‘表、字段、数据行’等概念,这些概念都是关系数据路中技术相关的概念,而真正的多维数据分析要求维度描述的是纯粹的业务角度,不应该暴露任何技术细节。
这里并不是说ROLAP跟多维数据分析完全不沾边,只是如果没有在其上进行更高级模型的抽象,ROLAP本身的数据分析能力是很弱的。
如何构建真正的多维数据模型?要真把这个事情的全部细节说清楚,小编也不知道需要多长时间,下图是一本讲解多维数据结构的书籍,800多页,各位可以自己估算一下时间。
ROLAP本身是不能等同于多维数据模型的,而且其本身的数据分析能力也是很弱的。
小编几年前曾经接触过一个开源的ROLAP系统Mondrian,虽然它也是将数据以星型结构存储,但在星型结构之上做了大量的模型映射工作,其提供给上层应用的数据模型已经是屏蔽了技术细节的逻辑维度模型。目前Mondrian与其属主项目Pentaho貌似被收购并商业化了,对开源的支持也降低了。
对比一下传统报表,ROLAP体系除了星型结构使数据更加规整和采用分布式等手段处理大体量数据之外,和传统报表几乎没有本质的区别。
目前流行的Hadoop、Spark等开源大数据框架可以被视为ROLAP的延伸,但是这种数据分析体系同样存在抽象程度低的问题,基于Hadoop和Spark等框架可以建立起解决某种特定需求的数据分析体系,这种面向特定需求的项目型系统的通用化和移植性并不会很好(BAT内部建立的很多类似系统就属于这种情况),而且只能面向技术人员,想要在商业信息等更高层面体现价值的话必须依赖IT部门的大力支持。
ROLAP说的够多了,下面言归正传,讲解真正的多维数据库。
以Oracle Essbase和IBM Cogons为例,多维数据库向上提供的是以维度(Dimension)和Cube(数据立方体)为基本结构的逻辑模型。维度类似于坐标轴,Cube则相当于这个N维空间中的一个结构体。
- 在0维空间中,Cube没有可关联的维度,可以将Cube想象成一个点,确定一个度量值不需要任何维度信息。
- 在1维空间中,Cube结构是一条线。
- 在2维空间中,Cube结构是一个平面。
- 在3维空间中,Cube是一个立方体结构。
- N(N > 3)维空间中的Cube则可以被想象成一个超立方体结构。
相当一部分BI行业从业者认为ROLAP的星型结构与逻辑多维结构是等同的,实际上这是对多维数据库及多维数据模型的最大误解。
从表面来看,星型结构与多维数据库在数据持久化方面提供的能力是相当的,甚至基于关系数据库的ROLAP会更方便一些,但一旦涉及对数据的多维分析,ROLAP相对于多维数据库来说基本可以被视为传统报表。
多维数据模型的标准查询语言是多维表达式(MDX,Mutil Dimensional Expressions),MDX是微软公司发明的面向多维数据模型的结构化查询语言,在语法结构和长相上MDX和SQL是很类似的。
对于多维逻辑模型,可以使用MDX进行查询;对于ROLAP,则使用SQL查询。人们很容易将ROLAP星型结构等同于多维结构,同样也容易将MDX想象成SQL的简单变体。实际情况是这两种数据分析套路的差别是非常大的,多维数据库可以支持100%面向业务式的数据分析,而基于ROLAP则始终无法摆脱关系数据库表与字段的查询思路。
现在我们来假设一个多维数据模型,以此为例来探究一下传统多维数据库的内部原理。
此模型是全国各个地区各种服装的销售数据集,有三个维度:地区、日期、服装类别,两个度量:销售额和售卖数量。
多维数据库从接收MDX到返回查询结果大致要经过MDX解析、中间结构处理、度量聚集计算、返回结果等几个步骤。
- MDX解析步骤负责对输入的MDX语句进行词法和语法分析,然后生成中间表示结构。
- 中间结构处理步骤的工作是对多维查询的复杂逻辑和函数进行处理、确定查询结果的结构和调用度量聚集计算对结构进行填充,这个步骤的工作非常复杂,是由多维数据库内核调用各个组件来完成的。
- 度量聚集计算负责将明细级度量汇总成非明细度量,是多维数据库底层的原子级运算。
- 返回结果将一个M维(M <= N)的结构进行填充并返回,0维Cube的查询结果只能是标量值,1维Cube的查询结果可以是一个标量也可以是一个1维结构,2维Cube可以返回标量值、1维结构和2维结构作为结果,大于等于3的N维Cube返回结果形态可以以此类推。
在大多数情况下,查询Cube返回的结构都是2维的,因为这是最容易被人们直观理解的。
多维数据库的优点之一是查询速度非常快,这就要着重说一下度量聚集计算这个步骤。
多维数据库对数据的管理主要由两部分组成,概要文件(Profile)和数据块(Data Blocks)。概要文件负责对维度、维度成员、Cube与维度的关联关系等信息进行管理,把它想象成一个迷你的主数据管理系统即可。数据块则负责管理度量数据。
以前文提到的那个服装销售Cube为例,它的度量数据可以被想象成是存放在一个 192×2 的二维数组中。
一个N维Cube模型的数据可以直接被映射为N + 1维数组,这个多出来的1代表的是度量,度量本身也可以被看做一个维度,后文会进行说明。此文中会将N + 1维数组的N维展开成1维,这意味着N + 1维数组将变成一个2维数组,2维数组看起来会比较直观。2维数组本身也是逻辑结构,它可以很清晰的将代表业务角度的维度和度量维区分开。实际上,在操作系统级别的存储结构上,任意维数的数组都是以一维数组的形态存在的,您应该对此有清晰的了解。
计算规则:
二维数组长度 = 全部非度量维度明细级成员数量的笛卡尔积
二维数组中包含的一维数组长度 = 度量值数量(销售额和售卖数量)
如果Cube只包含一个度量,那么二维数组就变成了一维数组,可以把这种情况看成一种特例。
这个二维数组存储的是各维度明细成员组合所指向的度量值,如:【10月份北京地区夹克的售卖数量为80000条】
另一些非明细维度成员指向的度量值并没有直接存放在这个二维数组里,它们可以通过对上面二维数组中的数据进行聚集运算而得出。
正是由于二维数组中的数据是依照各个维度明细成员的顺序排列而来的,所以在进行聚集计算的时候,只需要给定聚集数据范围的首位坐标即可,程序将以直接寻址的方式进行汇总计算,相比于关系型数据库的索引,速度明显要快得多。
多维数据的度量完全可以被视为一个维度,同样,维度也可以变换成度量,以下两种Cube在逻辑上是完全等同的。
这种二维数组的结构存在两个比较严重的问题,数据膨胀和数据空洞。
数据膨胀,这个不难理解,由于二维数组的长度是各维度明细成员数量的笛卡尔积,所以一旦维度的明细成员增加,就有可能导致二维数组体积的几何增长。
当前示例中地区、时间、服装类别维度明细成员数量分别是 4、12、4,对应的二维数组长度即为 4×12×4=192。如果每个维度明细成员数量增加一倍,二维数组的长度就变为了1536,体积变成了原来的8倍。
数据空洞问题。不存在的度量值会产生数据空洞,假设在海南地区一件羽绒服都没有卖出去(实际情况是在海南确实能将羽绒服卖出去),那么在二维数组中同时关联海南和羽绒服的度量将都没有意义。
如果数据空洞很多,将会使得二维数组变得非常稀疏,造成存储空间的极大浪费。
为了解决上述两个问题,传统多维数据库引入了索引结构。
索引是由那些导致数组变得稀疏的若干个维度变化而来的,地区维度和服装类别维度就可以变化为索引。
当地区和服装类别变为索引后,每个索引将指向一个小的数据块。
可以计算出,每个小数据块的容量是12×2=24,总共有8个小数据块,在不计索引本身所占存储的情况下,整体数据存储量降到了原来的 1/2。
另一种情况,如果只有某几个月份的销售数据,那么日期维度本身也可以变成索引,如下图所示。
在其他介绍多维数据库的文章中经常会出现“稀疏维”这个概念,这非常容易对读者产生误导,按某个维度本身来说是不存在稀疏还是密集这种说法的,稀疏指的是某些维度组合产生了很多不存在的数据,产生的大量数据空洞将导致数据集整体有效数据密度的降低。
传统多维数据库的索引结构就是为了解决数据稀疏问题而引入的,但是带来的问题是一旦Cube数据密度重心发生变化,那么应该组成索引的维度也可能随之改变,这种变化会导致整个索引以及数据块结构的完全重新构建,计算代价非常昂贵,而且,到底应该由哪些维度组成索引并没有非常明确的判定标准。
LookUpCube函数问题。
LookUpCube是MDX中用于进行多Cube关联查询的函数,不过目前貌似只有Microsoft SSAS支持此函数,小编并没有在Essbase、Cogons、Mondrian中找到LookUpCube的痕迹。
LookUpCube可以非常方便的进行跨业务、跨领域分析,但是在微软的官方文档中却明确指出不建议使用此函数,因为它会导致严重的性能问题。如果把关联多个Cube的查询想象成在ROLAP中对多张事实数据表进行Join查询,就不难理解了。
如果您理解了Essbase、Cogons等多维数据库的索引和数据块结构,以及为了得到非明细维度成员所对应度量值的原子性聚集计算,那么应该能够理解在这种数据架构上并不会存在类似于关系型数据库中多表Join的查询。由此我们可以进行一下推测,微软SSAS和Oracle Essbase、IBM Cogons的底层架构并不一样,SSAS采用的是像Mondrian一样在ROLAP上进行高度抽象的方式来实现多维分析的(确切的说应该是Mondrian模仿了Microsoft SSAS)。Mondrian没有实现LookUpCube函数可能是因为(在ROLAP架构中)这确实会造成很大的性能问题,而在Essbase和Cogons的稀疏维组合索引和数据块的架构下实现LookUpCube应该不会造成很大的性能问题,但Oracle和IBM(Hyperion和Cogons)为何没有实现此函数,小编也不知道。
Essbase是Hyperion公司的产品,Hyperion被Oracle收购了。Cogons是Cogons公司的产品,别疑惑,公司名和产品名是相同的,Cogons后被IBM收购。
NeuralCube
NeuralCube是邦格科技研发的具有自主知识产权的国产多维数据库,在整体架构上看,它可以被视为传统多维数据库Essbase、Cogons的进化版本,它是一个基于分布式数据存储的多维数据库,也是一个开放的数据分析引擎。
NeuralCube主要包括三个部分:内核、模型管理服务和矢量计算引擎。
- 内核是NeuralCube的核心逻辑处理程序,与传统多维数据库一样,内核的工作是对多维查询的复杂逻辑和函数进行处理、确定查询结果的结构和调用度量聚集计算对结构进行填充,它会调用模型管理服务和矢量计算引擎来完成这些工作。
- 模型管理服务类似于Essbase和Cogons的概要文件,前边已经说过传统多维数据库的概要文件相当于一个迷你的主数据管理系统。在NeuralCube中,模型管理服务是一个独立运行的真正的主数据管理系统。
- 矢量计算引擎是用C实现的分布式数据存储体系,类似于传统多维数据库的索引和数据块,它的作用是存储数据和对非明细维度成员对应的度量进行聚集计算。矢量引擎的数据量非常庞大,但是数据结构非常简单,而且其本身的聚集计算逻辑也非常简单,所以其具有更高的稳定性和更快的运算效率。
NeuralCube的整体逻辑处理流程如下。
NeuralCube接收一个MDX,最后会返回一个多维结果集。NeuralCube对标准MDX进行了扩展,用以对上层应用可能提出的特定化需求提供最大的支持,同时增加了一些更直观的函数。MDX是由美国人发明的,在思维方式上老外跟国人还是有些差异的,就拿常见的同比、环比分析来说,在标准MDX下只能通过嵌套好几个函数以一种非常奇怪的方式实现,而NeuralCube中则增加了大量贴近中国人思维方式的函数。
多维查询能力提升的必要条件之一是对逻辑模型处理能力的增强,这离不开模型管理服务的支持。
传统多维数据库概要文件所管理的模型是Cube、Dimension、Member、Hierarchy、Level、Measure等,这在处理某个维度扮演多个角色的情况时会带来麻烦,如:对中国全部省份的人口迁徙情况做一个统计,会涉及到户籍迁出省和户籍迁入省,按业务含义来说,户籍迁出省和迁入省维度是100%相同的,如果无法以另外一种方式对省份维度进行识别,就会对分析造成混淆。
NeuralCube解决以上问题,是通过在模型管理服务中引入Role模型来解决的。在NeuralCube中,Cube和Dimension不会直接关联,而是通过Dimension Role(维度角色)产生联系,顾名思义,维度角色就是维度所扮演的角色。由于Hierarchy、Level、Member对象都是挂靠在Dimension上的,所以其也自带有角色属性(Hierarchy Role、Level Role、Member Role)。前文已经讲过,度量完全可以被视为一个普通的维度,但这里并没有将度量维的角色属性进行过多的处理,因为在大多数Cube中,其度量基本都是独占的。
相对于Essbase、Cogons等传统多维数据库,NeuralCube在多维模型的关联能力方面进行了增强。维度是多维数据模型的核心,在底层概念上它可以被看做是一个坐标轴,在抽象程度更高的业务角度,维度代表的就是现实中存在的对象,现实中各种实体及概念往往存在错综复杂的关联关系。例如表示客户的维度,每个客户都有其所属的地区,那么所属地区就是客户的属性之一,在正常认知层面,这些作为属性的地区和地区维度中的地区应该是完全相同的。在传统多维数据库中,只能将地区名称或编码以属性的方式存储,而在NeuralCube中地区维度成员本身就具备属性的性质,完全可以将客户维度和地区维度进行关联,这种关联的意义会体现在更加深层次的数据挖掘能力。
NeuralCube中对大数据的存储和运算是由矢量计算引擎来完成的,它的核心思想非常简单,就是将海量数据的聚集运算分而治之。
在前文中已经提到过传统多维数据库的原子性运算是通过明细维度成员对应的度量值去汇总计算非明细成员对应的度量值,如果将每个维度成员都视为维度坐标轴的一个刻度的话,那么度量值可以被直观的理解为一个矢量值。矢量计算引擎的功能就是通过明细矢量值汇总去计算非明细矢量值。
Essbase、Cogons等产品将事实数据存储在索引和数据块结构中,ROLAP存储事实数据的则是事实表,NeuralCube的矢量计算引擎原理跟这两者都有一些类似,但不完全一样。
NeuralCube矢量计算引擎的存储结构类似于ROLAP的事实表,但采用分布式存储。关系数据库的表如果很大也会被进行分片、分库处理,但会有分片字段将这些子表在逻辑上整合成一张完整的大表,NeuralCube矢量计算引擎采取的方式就不一样了,它将一个大的数据块简单的切分成若干的小的数据块,每个小数据块彼此之间是完全孤立的,并不需要产生任何关联。
矢量引擎的运算方式类似于传统多维数据库的原子级运算,就是将明细级度量汇总成非明细度量。传统多维数据库和矢量计算引擎中都有数据块的概念,但区别在于前者对数据块的规划是在将稀疏维组合变换为索引的前提下实现的,索引和数据块的结构关联紧密,还有可能因为数据重构而产生较大变化,可以说是处于一种不稳定的状态,后者的数据块则是将一个大的数据集简单进行切分,然后形成多个完全孤立的数据块。
传统多维数据库的‘索引和数据块结构’、‘ROLAP事实表’、‘矢量计算引擎的数据存储结构’经过变换是可以互通的。
多维数据库索引有一种特殊情况,就是所有维度的组合都是稀疏的,那么数据块中就只存在度量值信息了,维度全部变换成索引,这就与ROLAP事实表中的维度表外键索引完全一样了。
将ROLAP事实表切分成多个子表,会近似于矢量计算引擎的分布式存储结构。
矢量计算引擎的数据块虽然可以被想象成ROLAP事实表的分片表,但却不像事实表那样需要关联维度表进行查询,它更像传统多维数据库的原子运算,是基于每个小数据块之上独立运行的。
我们现在将传统多维数据库、ROLAP、NeuralCube的架构做一个整体的对比,系统的看一下这三者之间的关联与区别。
- 传统多维数据库的概要文件、ROLAP维度表、NeuralCube的模型管理服务负责的工作是对元数据模型的管理,NeuralCube的模型管理服务更是一个完全独立的元数据图谱。
- 传统多维数据库的索引和数据块、ROLAP事实表、NeuralCube矢量计算引擎的任务是存储事实数据并进行运算。ROLAP事实表需要跟维度表进行关联查询,而传统多维数据库和NeuralCube则是基于被切分的数据块进行原子性汇总运算。
- 传统多维数据库和NeuralCube都有内核处理逻辑,ROLAP没有内核,但也可以将关系数据库本身的SQL解析与处理想象成ROLAP的核心逻辑。
另外,NeuralCube很好的支持了LookUpCube函数,很大程度上增强了跨行业、跨领域数据分析能力,并且不会造成很大的性能问题。
由于分布式多维数据库NeuralCube的逻辑运算和聚集运算是解耦的,所以可以很好的支持即席查询能力,对于随机的查询无需做特定的优化便可获得很高的查询效率,这也是NeuralCube能支持“探索式分析”和“零试错成本”的前提。
多维数据库属于底层基础软件,想要进行系统的数据分析当然不能缺少面向最终用户的上层应用,Phoenix Analytics就是基于NeuralCube的高易用性数据分析平台,可以让业务人员像打游戏一样非常轻松的进行数据分析,并且可以免费下载哦。
了解更多,请访问www.bgotech.cn
国产多维数据库 NeuralCube!中国人自己的大数据底层核心技术!的更多相关文章
- noSQL数据库相关软件介绍(大数据存储时候,必须使用)
目前图数据库软件七种较为流行:Neo4J, Infinite Graph, DEX,InfoGrid, HyperGraphDB, Trinity, AllegroGraph(http://tech. ...
- 一脸懵逼学习HBase---基于HDFS实现的。(Hadoop的数据库,分布式的,大数据量的,随机的,实时的,非关系型数据库)
1:HBase官网网址:http://hbase.apache.org/ 2:HBase表结构:建表时,不需要指定表中的字段,只需要指定若干个列族,插入数据时,列族中可以存储任意多个列(即KEY-VA ...
- 多维数据库 Oracle Essbase 和 IBM Cogons 底层原理
多维数据库(Multi Dimensional Database,MDD)使用Dimension(维度)和Cube(数据立方体.数据集市)模型描述数据. 多维数据模型 关系型数据库(Relationa ...
- 大数据学习资料之SQL与NOSQL数据库
这几年的大数据热潮带动了一激活了一大批hadoop学习爱好者.有自学hadoop的,有报名培训班学习的.所有接触过hadoop的人都知道,单独搭建hadoop里每个组建都需要运行环境.修改配置文件测试 ...
- 大数据运维尖刀班 | 集群_监控_CDH_Docker_K8S_两项目_腾讯云服务器
说明:大数据时代,传统运维向大数据运维升级换代很常见,也是个不错的机会.如果想系统学习大数据运维,个人比较推荐通信巨头运维大咖的分享课:https://url.cn/5HIqOOr,主要是实战强.含金 ...
- 大数据技术体系 && NoSQL数据库的基本原理
1.NoSQL产生的原因 目前关系型数据库难以应对日益增多的海量数据,横向的分布式扩展能力比较弱,因此构建出非关系型数据库(所谓的NoSQL),其目的是为了构建一种结构简单.分布式.易扩展.效率高且使 ...
- DB 查询分析器 6.03 如何灵活、快捷地操作国产达梦数据库
DB 查询分析器 6.03 如何灵活.快捷地操作国产达梦数据库 马根峰 (广东联合电子服务股份有限公司, 广州 510300) 摘要 本文详细地介绍了"万能数据库查询分析器&qu ...
- .NETCore 访问国产达梦数据库
前言 武汉达梦数据库有限公司成立于2000年,为中国电子信息产业集团(CEC)旗下基础软件企业,专业从事数据库管理系统的研发.销售与服务,同时可为用户提供大数据平台架构咨询.数据技术方案规划.产品部署 ...
- 基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作
由于一个客户朋友的需求,需要我的Winform开发框架支持国产达梦数据库的操作,这个数据库很早就听过,但是真正一般项目用的很少,一般在一些特殊的项目可能需要用到.由于我的Winform开发框架,是基于 ...
随机推荐
- A项目轶事之加入项目2个月
A项目轶事之加入项目2个月 4月18号是我入A项目整整2个月的日子. 加入项目第一天,就发现A项目是一个大规模的SAP ERP项目. SAP各大模块,Salesforce, MES等各个系统相关的顾问 ...
- cesium 之地图贴地量算工具效果篇(附源码下载)
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...
- 安卓开发笔记(十三):SQLite数据库储存(下)数据的增添,更改,删除,查询
SQLite数据库存储(下) 1.增添数据 对于添加数据的话我们只需要在主活动当中import新的包以及在主活动当中写上适当的代码就可以了,不需要在我们之前创建新的类当中书写新的代码.现在的主活动 ...
- 读懂 Gradle 的 DSL
现在 Android 开发免不了要和 Gradle 打交道,所有的 Android 开发肯定都知道这么在 build.gradle 中添加依赖,或者添加配置批量打包,但是真正理解这些脚本的人恐怕很少. ...
- 工程实践:给函数取一个"好"的名字
工程实践:给函数取一个"好"的名字 早在2013年,国外有个程序员做了一个有意思的投票统计(原始链接请见:<程序员:你认为最难做的事情是什么?>),该投票是让程序员从以 ...
- scrapy-redis 分布式爬虫
为什么要学? Scrapy_redis在scrapy的基础上实现了更多,更强大的功能. 有哪些功能体现? request去重.爬虫持久化.实现分布式爬虫.断点续爬(带爬取的request存在redis ...
- #Java学习之路——基础阶段二(第七篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- python列表的交、并、差集
#!/usr/bin/env python3 l1 = ['] l2 = ['] # 交集 result1 = [i for i in l1 if i in l2] result2 = list(se ...
- RecyclerView实现一个页面有多种item,每个item有多个view,并且可以让任意item的任意view自定义监听,通过接口方法进行触发操作
百度了很多贴子,看着大佬的博客,模仿尝试,最终都是以失败告终,api可能版本不一样, 毕竟博客大佬都是7~8前写的,日期新点的都是好几年前了,多次尝试,还是报出莫名其妙的错. 哎,忧伤. 翻阅各种资料 ...
- GoLand2019 激活码
此教程对最新2019版本GoLand有效!!! 本教程对windows.mac.ubuntu全系统可用 此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: goland官网下载地址 ...