长春建设厅官方网站,建设银行如何进行网站冻结,建设部勘察设计网站,apache wordpress配置文件引语#xff1a;作为国内外最大的代码托管平台#xff0c;根据最新的 GitHub 数据#xff0c;它拥有超 372,000,000 个仓库#xff0c;其中有 28,000,000 是公开仓。分布式图数据库 NebulaGraph 便是其中之一#xff0c;同其他开源项目一样#xff0c;NebulaGrpah 也有自… 引语作为国内外最大的代码托管平台根据最新的 GitHub 数据它拥有超 372,000,000 个仓库其中有 28,000,000 是公开仓。分布式图数据库 NebulaGraph 便是其中之一同其他开源项目一样NebulaGrpah 也有自己的 contributor 们他们是何时通过哪个 pr 与 NebulaGraph 产生联系的呢本文尝试用可视化方式来探索这些 contributor 的痕迹。 世界上有两种需求一种是能做的另外一种是不能做的当然按照合理不合理角度大多数的需求都是合理但能做的就像本文的需求一样——用可视化的方式来“窥探” nebula 开源社区中 contributor 同项目的关系及他们留下的 pr 痕迹。
故事从两个月前讲起有一天我司研发 liuyu 同学装了一款名叫 ClickHouse 的数据库他发现 CK 有一个感人的 contributor 系统表这不得让我们的运营来“借鉴”下么
现在我们来看看感动我司研发的 ClickHouse 是怎么样的存在。
让人感动的 ClickHouse Contributor 系统表
简单来说只要你装了 CK 数据库不需要连接任何数据库系统自带一个数据表你可以执行以下 SQL
select count() from system.contributors就能得到一个现有的 CK contributor 总量下面数据存在一定滞后性 也可以按照下列方式随机获得 20 位 contributor 名单
select * from system.contributors limit 20;这种用 SQL 方式查看 contributor 的方式还挺 cool 的毕竟 contributor 是一群通过提交 pr 来完善、迭代产品的人其中很大一部分的 contributor 是工程师SQL 更是信手拈来。
现在问题来了作为一个不会写 SQL 的运营如何满足我司研发提出的让他感动一下的 contributor 系统表冷静下ClickHouse 的这个 SQL 看 contributor 的方式固然很酷但是终归到底是要查看贡献者同开源项目的关系。说到“搞关系”还不得是我们的图数据库。巧的是NebulaGraph 就是一款图数据库虽然在本文的数据集过于简单用也不是什么大规模数据用图数据库有点“杀鸡用牛刀”但不妨一试。看看不会写 SQL 的运营怎么用可视化的方式来查看 contributor 和项目关系。
看得见的 contributor 和 pr 关系
效果先行在这个章节我们来看下 NebulaGraph 开源社区的 contributor 和 pr 情况而这些数据是如何生成、展示的实操部分在后面。
开源社区全览
这里收录了所有 NebulaGraph 相关的公开仓的贡献情况大概是这样的 加上时序之后能看到一个个 contributor方形图出现在画布上同各个 repo圆形图连接在一起。这里仅仅展示了所有 contributor 第一次提交 pr更多的查询在后面的「可视化图探索」部分。
下面的章节为实操内容一起看看如何生成可视化的 contributor 和开源项目的关系图吧。
手把手带你可视化探索数据
下面着重介绍下本文的可视化工具——NebulaGraph Explorer具体介绍看文档https://docs.nebula-graph.com.cn/3.4.1/nebula-explorer/about-explorer/ex-ug-what-is-explorer/。对我而言Explorer 有两大特点易上手、所见即所得。我可以白嫖我司线上 Explorer 环境不用搭建自己的数据库就能直接用当然你如果想和我一样有个免费的线上环境估计得用 NebulaGraph Cloud它配有可视化图探索工具 NebulaGrpah Explorer。
用来进行数据探索的工具有了现在就是数据哪里来的问题了。
简单建模
在采集数据之前我们需要简单建模我从未见过如此简单的图模型了解需要采集的数据。下图为图模型 这个图模型中有两种点类型repo 和 contributor它们之间由 pr 这个边联系在一起构成了最基础的点边图模型。在分布式图数据库 NebulaGraph 中点的类型用 tag 来表示边类型有 edgetype一个点可以有若干种 tag点的 ID 为 vid像是你的身份证一样为唯一标识。
tag repo拥有仓库名 name主要编程语言 language 以及仓库路径 path 等三种属性contributor拥有贡献者名 name贡献者编号 number诞生日 anniversary是否为 NebulaGraph 开发商雇员 is_vesoft第一个被合并 pr 所属仓 first_repo。加入了判断“是否为 NebulaGraph 开发商雇员”的属性是为了避免超大节点因为一个企业雇员的 pr 产量不同于其他的非雇员贡献者。这点会在后面的可视化展示中体现 edgetype pr拥有 pr 编号 number提交时间 created_time关闭时间 closed_time合并时间 merged_time是否被合并 is_merged变更情况ins_code_line、des_code_line、file_number。上面的时间字段可以用来筛选出某个时间区间里的 pr 边
contributor 数据采集
下面这段代码是拜托我司优秀的 IT 工程师乔治编写的那些需要配置、填上你自己信息的地方我用注释进行了标注
# Copyright Shinji-IkariG
from github import Github
from datetime import datetime
import sh
from sh import curl
import csv
import requests
import timedef main():
# 你的 GitHub IDGH_USER xxx
# 你的个人 token可以前往 GitHub 设置中的 Developer settings 生成自己的 tokenGH_PAT xxxgithub Github(GH_PAT)
# 你需要爬取的开源组织的组织名org github.get_organization(vesoft-inc)repos org.get_repos(typeall, sortfull_name, directionasc)
# 命名存放爬下来的 pr 数据的文件with open(all-prs.csv, w, newline) as csvfile:
# 爬取哪些数据fieldnames [pr num,repo,author, create date,close date,merged date,version,labels1,state,branch,assignee,reviewed(commented),reviewd(approved),request reviewer,code line(),code line(-),files number]writer csv.DictWriter(csvfile, fieldnamesfieldnames)writer.writeheader()for repo in repos:print(repo)Apulls repo.get_pulls(stateall, sortcreated)prs []for a in Apulls:prs.append(a)for i in prs:github Github(GH_PAT)print(rate_limite , github.rate_limiting[0])if github.rate_limiting[0] 500:if github.rate_limiting_resettime - time.time() 0:time.sleep(github.rate_limiting_resettime - time.time()900)else:time.sleep(3700)else:print(i.number)prUrl https://api.github.com/repos/ str(repo.full_name) /pulls/ str(i.number)pr requests.get(prUrl, auth(GH_USER, GH_PAT))assigneesList []if pr.json().get(assignees):for assignee in pr.json().get(assignees):assigneesList.append(assignee.get(login))else: reviewerCList []reviewerAList []reviewers requests.get(prUrl /reviews, auth(GH_USER, GH_PAT))if reviewers.json():for reviewer in reviewers.json():if reviewer.get(state) COMMENTED:if reviewer.get(user): reviewerCList.append(reviewer.get(user).get(login))else: reviewerCList.append(GHOST USER)elif reviewer.get(state) APPROVED:if reviewer.get(user): reviewerAList.append(reviewer.get(user).get(login))else: reviewerAList.append(GHOST USER)else : print(reviewer.get(state), TYPE REVIEWS)else: reqReviewersList []reqReviewers requests.get(prUrl /requested_reviewers, auth(GH_USER, GH_PAT))if reqReviewers.json().get(users):for reqReviewer in reqReviewers.json().get(users):reqReviewersList.append(reqReviewer.get(login))print(reqReviewersList)else: labelList []if pr.json().get(labels):for label in pr.json().get(labels):labelList.append(label.get(name))else: milestone pr.json().get(milestone).get(title) if pr.json().get(milestone) else writer.writerow({pr num: i.number,repo: repo.full_name,author: pr.json().get(user).get(login), create date: pr.json().get(created_at),close date: pr.json().get(closed_at),merged date: pr.json().get(merged_at),version: milestone,labels1: ,.join(labelList),state: pr.json().get(state),branch: pr.json().get(base).get(ref),assignee: ,.join(assigneesList),reviewed(commented): ,.join(reviewerCList),reviewd(approved): ,.join(reviewerAList),request reviewer: ,.join(reqReviewersList),code line(): pr.json().get(additions),code line(-): pr.json().get(deletions),files number: pr.json().get(changed_files)})if __name__ __main__:main()#pip3 install sh pygithub等你运行完上面代码便能得到一个名叫 “all-prs.csv”。脚本爬取的是 vesoft-incNebulaGraph 开发商组织下的所有仓这里并没有区分仓库状态这就意味着它也会将私有仓的数据爬取下来。因此我们要对数据进行二次处理。这里略过我简单处理数据的过程处理完的 pr 数据中可以抽取相关的 contributor 数据。
上面提到过每个点都有 vid因此将 contributor 的 vid 设定为他/她的 GitHub IDrepo 的 vid 则采用缩写而边的数据中起点和终点就为上面的 contributor vid 和 repo vid。
现在我们有了contributor.csvpr.csvrepo.csv 三个文件格式类似
# contributor.csv
wenhaocs,haowen,148,2021-09-24 16:53:33,1,nebula
lopn,lopn,149,2021-09-26 06:02:11,0,nebula-docs-cn
liwenhui-soul,liwenhui-soul,150,2021-09-26 13:38:20,1,nebula
Reid00,Reid00,151,2021-10-08 06:20:24,0,nebula-http-gateway
...# pr.csv
nevermore3,nebula,4095,2022-03-29 11:23:15,2022-04-13 03:29:44,2022-04-13 03:29:44,1,2310,3979,31
cooper-lzy,docs_cn,1614,2022-03-30 03:21:35,2022-04-07 07:28:31,2022-04-07 07:28:31,1,107,2,4
wuxiaobai24,nebula,4098,2022-03-30 05:51:14,2022-04-11 10:54:04,2022-04-11 10:54:03,1,53,0,3
NicolaCage,website,876,2022-03-30 06:08:02,2022-03-30 06:09:21,2022-03-30 06:09:21,1,4,2,1
...#repo.csv
clients,nebula-clients,vesoft-inc/nebula-clients,Java
common,nebula-common,vesoft-inc/nebula-common,C
community,nebula-community,vesoft-inc/nebula-community,Markdown
console,nebula-console,vesoft-inc/nebula-console,Go
...
数据导入
数据导入之前需要创建相关的 Schema 进行数据映射。
创建 Schema
现在我们需要把图结构模型变成 NebulaGraph 能识别的 Schema有两种方式来创建 Schema一是用查询语言 nGQL 来编写 Schama另外一种则是用可视化图探索工具 NebulaGraph Explorer 提供的可视化界面填写信息完成。和我一样对查询语言不熟悉的小伙伴建议首选后者。
登陆到 NebulaGraph Explorer 之后先创建一个图空间类似 MySQL 中的 Table 效果同下面的 nGQL 语言
# nebula-contributor-2023 是这个图空间名字其他默认
CREATE SPACE nebula-contributor-2023(partition_num 10, vid_type FIXED_STRING(32))创建完图空间之后再创建两个点类型和一个边类型二者创建方式类似。
下面以创建相对复杂的 contributor 点类型为例 同效于这条 nGQL 语句
CREATE tag contributor (name string NULL, number int16 NULL, anniversary datetime NULL, is_vesoft bool NULL, first_merged string NULL) COMMENT 贡献者同样的 repo 和 pr 边可以用下面的 nGQL 或同上图一样用 Explorer。
# 创建 repo tag
CREATE tag repo (repo_name string NULL, language string NULL, path string NULL) COMMENT 仓库# 创建 pr edge
CREATE edge pr (number int NULL, created_time datetime NULL, closed_time datetime NULL DEFAULT NULL, merged_time datetime NULL DEFAULT NULL, is_merged bool NULL, ins_code_line int NULL, des_code_line int NULL, file_changed_num int NULL)导入数据
因为用了可视化工具 Explorer所以上传数据也可以用“看得见的方法”。在创建完 Schema 之后点击这个右上角的菜单栏“Import”开始数据导入。
数据源选择本地找到上面准备的 3 个 csv 文件所在路径把文件上传之后。开始【导入】过程在这个步骤主要是完成本地数据文件同 Schema 的关联。类似下图 在整个数据集中我们有两种点vertices 1 关联 repo 的 csv 数据vertices 2 关联 contributor 数据指定各自的 VID 和相关属性的所在列之后就可以导入数据了。在边数据关联这块因为我们之前已经在 csv 中加入了 repo 和 contributor 的各自 VID所以这里同点的关联一样简单勾选哪列是起点Column 0、哪列是终点对应上图的 Column 1。
需要进行特殊说明的是因为一个 contributor 和一个 repo 会存在多次提交 pr 记录即多条同 pr 边类型的边。而对同一类型边的处理问题图数据库 NebulaGraph 引入了 rank 字段来表示两个点之间多条同一类型但边属性不同的边。如果你不设定 rank插入多条同一类型边则会进行数据覆盖操作以最后成功插入的边数据为准。
为了偷懒这里 rank 我直接用了 pr 编号 number 列仔细看上面的 rank 和 number 都是读取的同一列 Column 2 数据。
可视化图探索
现在我们有数据了可以进入到可视化图探索模式了。 在“Visual Query”菜单下拖拽两个 tagcontributor 和 repos选择 pr 边【运行】就能看到所有 contributor 提交的 pr 数据。它的效果等同于下面这句 nGQL 查询语言
match (v0:contributor) -[e:pr]- (v1:repo) return e limit 15000我们随意加入一点像是下面这种小细节 我们把点的头像全部换下这里为了节省时间找研发小哥龙仔开了个绿色通道批量上传了 contributor 和 repo 点的头像。现在整图的效果展示是这样的 因为 nebula 最大的贡献来源于其雇员员工所以这里我们除去雇员查看下非雇员的贡献情况效果同查询语言
match (v0:contributor) -[e:pr]- (v1:repo) where (v0.contributor.is_vesoft false) return e limit 15000上图是将 nGQL 查询结果导入到画布对应的 NebulaGraph Explorer 操作为点击【导入图探索】再进行同类型边合并放大 contributor 点的大小选择辐射模式就呈现了最终效果 看看仓库编程语言为 C、Python、Go、Java 各自的贡献者情况 可以看到内核仓 nebula 采用了 C不少相关的周边工具也用了 C。因此整个开源项目中 C 的贡献者点还是比较多的。反之目前只有 Python 客户端 nebula-python、同步工具 auto_sync 和安装工具 nebula-ansible 使用 Python 语言开发因此相较于其他编程语言contributor 数量并不多。
说到内核仓我们来看看内核仓 nebula 的非雇员贡献者情况 通过合并同类型 pr 边根据边的粗细我们可以看到核心仓的活跃贡献者。留意上面那个 Java logo 的图像并非是 nebula 同 Java 联谊了而是 2020 年的 Committer ChenXU 用了 Java 的 logo 作为头像狗头。
再来看看 2021 年诞生的非雇员 contributor 他们的贡献情况 最后来看看有哪些 pr 还没被 merge这里需要用到 pr 边的 is_merged 属性记得创建个索引哦~) 祝上面所有未被 merged 的 pr 都能被合并虽然这是不可能的。
nGQL 合集
这里是上面所有查询结果的对应 nGQL 查询语句
# 查看各个查询语言的开源仓库贡献情况
match (v0:contributor) -[e:pr]- (v1:repo) where (v1.repo.language C) return ematch (v0:contributor) -[e:pr]- (v1:repo) where (v1.repo.language Python) return ematch (v0:contributor) -[e:pr]- (v1:repo) where (v1.repo.language Go) return ematch (v0:contributor) -[e:pr]- (v1:repo) where (v1.repo.language Java) return e# 内核仓 nebula 的非雇员贡献者match (v0:contributor) -[e:pr]- (v1:repo) where (v1.repo.repo_name nebula and v0.contributor.is_vesoft false) return e# 2021 年诞生的非雇员 contributor
match (v0:contributor) -[e:pr]- (v1:repo) where (v0.contributor.anniversary datetime(2021-01-01T00:00:00) and v0.contributor.anniversary datetime(2022-01-01T00:00:00) ) and v0.contributor.is_vesoft false return e# 目前未被合并的 pr
match (v0:contributor) -[e:pr]- (v1:repo) where (e.is_merged false) return e
数据集
本数据集为 NebulaGraph 公开仓数据统计截止时间为 2023.03.20。因为部分 datetime 属性不能为空为空字段人为填充了为 2038-01-19 03:14:07timestamp 类型上限。如果你要使用该数据集记得留意 datetime 属性值的处理。
数据集下载地址nebula-contributor-dataset
最后以此文感谢所有 nebula 社区的 contributor 们 lol 谢谢你读完本文 (///▽///)