可视化探索开源项目的 contributor 关系

news2024/12/24 8:45:07

引语:作为国内外最大的代码托管平台,根据最新的 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。

用来进行数据探索的工具有了,现在就是数据哪里来的问题了。

简单建模

在采集数据之前,我们需要简单建模(我从未见过如此简单的图模型)了解需要采集的数据。下图为图模型:

这个图模型中有两种点类型:repocontributor,它们之间由 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_linedes_code_linefile_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 time

def main():
# 你的 GitHub ID
    GH_USER = 'xxx'
# 你的个人 token,可以前往 GitHub 设置中的 Developer settings 生成自己的 token
    GH_PAT = 'xxx'
    github = Github(GH_PAT)
# 你需要爬取的开源组织的组织名
    org = github.get_organization('vesoft-inc')
    repos = org.get_repos(type='all', sort='full_name', direction='asc')
# 命名存放爬下来的 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, fieldnames=fieldnames)
        writer.writeheader()


        for repo in repos:
            print(repo)
            Apulls = repo.get_pulls(state='all', sort='created')
            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-inc(NebulaGraph 开发商)组织下的所有仓,这里并没有区分仓库状态,这就意味着它也会将私有仓的数据爬取下来。因此,我们要对数据进行二次处理。这里略过我简单处理数据的过程,处理完的 pr 数据中可以抽取相关的 contributor 数据。

上面提到过每个点都有 vid,因此将 contributor 的 vid 设定为他/她的 GitHub ID,repo 的 vid 则采用缩写,而边的数据中起点和终点就为上面的 contributor vid 和 repo vid。

现在我们有了,contributor.csv,pr.csv,repo.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 列,仔细看,上面的 ranknumber 都是读取的同一列 Column 2 数据。

可视化图探索

现在我们有数据了,可以进入到可视化图探索模式了。

在“Visual Query”菜单下,拖拽两个 tag:contributor 和 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 e

match (v0:contributor) -[e:pr]-> (v1:repo) where (v1.repo.language == "Python") return e

match (v0:contributor) -[e:pr]-> (v1:repo) where (v1.repo.language == "Go") return e

match (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:07(timestamp 类型上限)。如果你要使用该数据集,记得留意 datetime 属性值的处理。

数据集下载地址:nebula-contributor-dataset

最后,以此文感谢所有 nebula 社区的 contributor 们 lol


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

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

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

相关文章

用arcgis for javascript 开发一个三维地图(入门案例)

效果如图&#xff1a; 详细的步骤就不啰嗦介绍了&#xff0c;大家可以参考上一篇文章二维地图入门案例&#xff0c;这里只是改了一点引用和属性而已。 核心代码&#xff1a; SceneView 用于创建三维地图 require([“esri/Map”, “esri/views/SceneView”] 这里提一句有两种…

vue项目中的环境变量的应用

vue项目中的环境变量的应用 在Vue项目中使用环境变量可以方便地在开发、测试、生产等不同环境中进行配置&#xff0c;而无需修改代码。 项目根目录下创建一个.env文件或者.env.[mode]文件&#xff0c;其中mode表示开发、测试、生产等不同的环境&#xff0c;文件名的后缀部分指…

Python的分布式网络爬虫

分布式爬虫其实就是指利用多台计算机分布式地从互联网上采集数据的一种爬虫。它可以把大规模的任务分解成若干小规模的&#xff0c;由多台计算机并行进行处理&#xff0c;大大提高了效率和速度。 分布式爬虫有很多优势&#xff1a;解决单机爬虫效率低的问题&#xff0c;分布式…

【UR3系统升级到CB3.12附带URcap1.05】

【UR3系统升级到CB3.12附带URcap1.05】 1. 前言1.1 Polyscope 3.12更新须知1.2 更新步骤 2. 对 PSU 电压进行控制的步骤2.1 启动机器人电源2.2 启动机器人程序2.3 查看PSU 电压 3. Polyscope 3.12 软件下载3.1 CB 系列机器人3.2 下载软件包URUP 4. CB3 软件安装的指导4.1 连接示…

Kohl‘s百货的EDI需求详解

Kohls是一家美国的连锁百货公司&#xff0c;成立于1962年&#xff0c;总部位于美国威斯康星州的门多西。该公司经营各种商品&#xff0c;包括服装、鞋子、家居用品、电子产品、化妆品等&#xff0c;并拥有超过1,100家门店&#xff0c;分布在美国各地。本文将为大家介绍Kohls的E…

SDK接口远程调试【内网穿透】

文章目录 1.测试环境2.本地配置3. 内网穿透3.1 下载安装cpolar内网穿透3.2 创建隧道 4. 测试公网访问5. 配置固定二级子域名5.1 保留一个二级子域名5.2 配置二级子域名 6. 使用固定二级子域名进行访问 转发自cpolar内网穿透的文章&#xff1a;Java支付宝沙箱环境支付&#xff0…

stable diffusion使用入门

目录 1、stable diffusion简要说明 2、安装stable-diffusion-webui &#xff08;1&#xff09;下载地址 &#xff08;2&#xff09;执行启动命令 3、Lora模型介绍 4、模型下载 &#xff08;1&#xff09;Lora模型使用 &#xff08;2&#xff09;底座模型使用 1、stable…

初识开源接口测试工具——Postcat

Postcat 是一个强大的开源、跨平台&#xff08;Windows、Mac、Linux、Browsers...&#xff09;的 API 开发测试工具&#xff0c;支持 REST、Websocket 等协议&#xff08;即将支持 GraphQL、gRPC、TCP、UDP&#xff09;&#xff0c;帮助你加速完成 API 开发和测试工作。 它适合…

OLAP和OLTP

1&#xff1a;OLAP和OLTP对比 数据库系统可以在广义上分为联机事务处理&#xff08;Online Transaction Process&#xff0c;OLTP&#xff09;和联机分析处理&#xff08;Online Analyze Process&#xff0c;OLAP&#xff09;两种面向不同领域的数据库&#xff0c;OLAP数据库也…

vue-cli的使用

什么是单页面应用程序? ​ 单页面应用程序(Single Page Application)简称SPA。指的是一个web网站中只有唯一的一个html页面,所有的功能与交互都在这个唯一的页面内完成。 什么是vue-cli? ​ vue-cli是Vue.js开发的标准工具。它简化了基于webpack创建工程化的vue项目过程。…

刷题常用算法模板(持续更新)

目录 1、二分查找2、线段树3、树状数组4、差分数组5、前缀树6、并查集7、AC自动机8、Morris遍历9、二叉树非递归遍历10、KMP11、Manacher12、快速选择 bfprt13、滑动窗口14、加强堆15、有序表16、单调栈 1、二分查找 需求&#xff1a;在一个有序数组中&#xff0c;快速查询某一…

chatgpt赋能python:Python中画笔放下:掌握Python图形编程

Python 中画笔放下&#xff1a;掌握 Python 图形编程 Python 是一种高级编程语言&#xff0c;广泛应用于数据处理、人工智能、Web 应用程序等领域。除了这些应用外&#xff0c;Python 还可以用于图形编程&#xff0c;包括绘制 2D 和 3D 图形、创建游戏和交互式应用程序等。在 …

Vue的基本使用

文章目录 Vue简介Vue的使用1.Vue指令2.过滤器3.侦听器4.计算属性 Vue简介 ​ Vue是一套用于构建用户界面的前端框架。 vue的两个特性 (1)数据驱动视图 在使用vue的页面中,vue会监听数据的变化,从而自动重新渲染页面的结构。当页面数据发生变化的时候,会自动重新渲染(数据的…

GUI JFrame实战:六一节,爱她就给她画个哆啦A梦吧

文章目录 前言技术积累容器分类主要APIGraphics图像 绘画方法实战演示1、创建哆啦A梦渲染类2、创建测试方法3、查看渲染结果 写在最后 前言 相信很多使用JAVA高级语言的同学都知道GUI图形用户界面&#xff0c;开发人员可以使用java.awt、javax.swing两个API绘画想要的图形并通…

蓝牙规范系列--基础篇(第一篇)

一、前言 玩过物联网的小伙伴肯定知道ESP32&#xff08;一款WiFi/BT SoC&#xff09;&#xff0c;那肯定也知道蓝牙这个东西&#xff0c;蓝牙技术最近几年由于蓝牙耳机很火&#xff0c;那蓝牙技术到底是怎样的呢&#xff1f; 蓝牙无线技术是一种短距离的通信系统旨在替换便携式…

c++学习——友元、全局友元函数、友元类

友元 类的主要特点之一是数据隐藏&#xff0c;即类的私有成员无法在类的外部(作用域之外)访问。但是&#xff0c;有时候需要在类的外部访问类的私有成员&#xff0c;怎么办? 解决方法是使用友元函数&#xff0c;友元函数是一种特权函数&#xff0c;c允许这个特权函数访问私有…

python 自动编译VS项目

目录 一、python自动编译项目 1、环境变量 1) CMAKE 2&#xff09;VS 2、CMAKE 生成VS项目 1) cmake 命令介绍 2&#xff09;python 调用cmake 命令 3、devenv编译VS项目 1) devenv介绍 2&#xff09;devenv命令行开关 3) 自动编译VS项目 一、python自动编译项目 …

04 布隆过滤器BloomFilter

是什么 布隆过滤器&#xff08;英语&#xff1a;Bloom Filter&#xff09;是 1970 年由布隆提出的。它实际上是一个很长的二进制数组一系列随机hash算法映射函数&#xff0c;主要用于判断一个元素是否在集合中。通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景&a…

C++ 和机器学习:使用 C++ 执行 ML 任务的简介

C 和机器学习&#xff1a;使用 C 执行 ML 任务的简介 介绍 C 是一种高性能编程语言&#xff0c;非常适合机器学习( ML ) 任务。尽管它在 ML 中可能不像 Python 或 R 那样流行&#xff0c;但它在速度和内存效率方面具有优势。 在本文中&#xff0c;我们将概述使用 C 执行 ML 任务…

“双碳同行者大会”成功举办,绿色家居企业参与其中

2023年5月27日 &#xff0c;由万科集团创始人、深石集团创始人王石先生创立的碳中和社区品牌“生物圈三号”在深圳大梅沙成功举办了“回归未来双碳同行——生物圈三号双碳同行者大会暨全球运河穿越新书发布会”。 生物圈三号作为社区碳中和综合解决方案平台&#xff0c;为建筑、…