大数据开发工程师-第十八周 直播平台三度关系推荐v1.0-1


第十八周 直播平台三度关系推荐v1.0-1

项目

1
2
3
4
5
6
7
8
9
10
11
12
大家好,下面我们开始正式学习直播平台三度关系推荐系统这个项目,这个项目分为1.0和2.0这两个版本。本周我们先学习1.0这个版本。首先我们来看一下项目效果。大家呢,可以在这里面扫码体验。这个就是我们直播平台的首页,当我们点击某一个主播,会进入到主播的详情页,我们在点击这个follow关注按钮的时候。这里面呢,会插入一个模块,它里面显示的是关注了此主播的人,也关注了哪些主播。这就是三度关系推进的效果。这页面上看起来只是把数据展现出来,很简单,但是具体这些数据是怎么来的,如何保证推荐的主播也是用户感兴趣的,这才是我们这个项目的核心内容。下面我们来看一下针对这个项目官方一点的介绍。

在直播平台中,用户在主播页面关注该主播时。粉丝状态栏下方插入三度关系推荐模块,显示该主播的粉丝同时又关注了哪些主播。按照推荐重合度且满足一定的筛选条件进行择优展示,这样推荐的主播才是用户最可能喜欢的,可以帮助用户发现更多他喜欢的主播,促进用户活跃,进而挖掘用户消费潜力。这就是我们这个项目最终想要达到的效果。

想要实现我们前面所说的三种关系推荐是需要由数据来支撑的,那么这些数据从哪里来呢?
这就涉及到我们的第一块内容,数据采集。我们需要将项目中需要用的所有数据全部采集过来,包括离线数据和实时数据。

这些数据采集过来以后,就需要涉及第二块内容了,数据存储,离线数据一般存储到分布式文件系统中,实时数据一般存储到消息队列中,数据存储起来以后,就需要涉及到数据计算了。

数据计算模块,对前面存储起来的数据进行计算,分为离线计算和实时计算,计算之后的结果数据还会进行存储。

那计算出来结果之后呢,就会涉及到数据展示了。将数据在页面中展示,查看最终的一个推荐效果。所以这个项目中的四大模块,它们之间的关系就是这样。在这里我们先从整体上对这个项目进行一个划分,后面还会有更详细的划分。

image-20230424154642727

技术选型之数据采集

image-20230424154922323

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
练好。接下来我们先针对这四个模块分析一下他们里面是需要用到的具体的技术框架,俗称技术选型。我们首先来看一下数据采集工具的选择。针对日志数据,目前业内常用的采集工具有下面这些。

首先是这个apache开源的这个顶级项目flume。还有这个elastic公司开源logstash以及filebeat。那在这呢,我们把这个kafka也列出来了,但是kafka并不算是日志采集工具。只是说呢,它一般会和采集工具一块使用,所以呢,在这就一块列出。以及呢,这个sqoop组件。

下面呢,我们来详细分析一下这个flume、logstash,还有filebeat这几个日志采集工具。
首先呢,是flume。如果它是基于Java语言实现的。flume主要由source、channel、sink这三个组件组成。针对这三个组件中提供了很多实现。针对source,有基于文件的,基于socket的,基于kafka的等等,还有很多我们常用的数据源,flume几乎都提供了支持。这个channel提供了有常见的基于文件的,基于内存的。这个sink有基于hdfs的,基于kafka的等等,还有很多我们常用的存储系统几乎都提供了支持。就算是部分特殊的source和sink,flume没有提供支持,那么也没有关系,flume允许我们自定义这些组件。由于它也是基于Java的,所以开发这些自定义的组件也没有多大问题,我们都是Java程序员对吧?所以目前啊,在企业中,针对日志数据采集这一块,flume占据了主要地位。

那接下来我们来看一下logstash。那是基于Jruby实现的。Jruby是ruby语言的Java实现。logstash的架构有点类似于flume,主要由输入、输出和过滤组成。这里的输入和输出类似于中的S和。那也提供了很多输入和输出的组件支持。常见的数据源和存储系统也都是支持的。并且带中还提供了强大的过滤功能,可以将采集到的数据进行一些处理之后再写出去。flume中的拦截器也可以实现类似的功能。logstash可以和elasticsearch、kibana轻松的实现一个日志收集检索、展现平台,非常方便。俗称ELK全家桶。

那其实分析到这儿,我们会发现flume和那logstash还是非常相似的。但是呢,他们两个的典型应用场景是有一些区别的。logstash常用的场景是帮助运维人员采集服务器自身的运行日志,方便运维人员排查服务器的问题。这种场景下,对于数据的完整性和安全性要求不是特别高。因为logstash内部没有一个持久化的队列,所以在异常情况下是可能出现数据丢失的问题。而flume内部呢,是有自己的ack机制来去确保这个问题。所以说呢,它可以用于一些更重要的业务日志台词。

那接下来我们再来看一下这个filebeat采集工具。是采用这个go语言开发的。它只支持文件数据采集。它可以将文件中的数据采集到,kafka,ES等等这些常见的存储系统。它会记录文件采集到的offset信息。就算filebeat的采集进程挂掉,也不会导致数据丢失,它下一次重新启动之后,还会延续之前的offset,继续往下面采。并且呢,这个filebeat呢,它还是一个轻量级的采集工具。咱们前面分析的这个flume,还有这个logstash,它们都是一些重量级的产品。在某些特定场景下,这个轻量级的组件可能会更加合适。filebeat和logstash同属于elastic这个公司,这些公司呢,提供了很多的这种Beat组件。filebeat的只是其中一个。因为我们的数据采集呢,主要是基于文件的,所以在这呢,我就只分析了这个filebeat。

那到目前为止,这三个采集工具啊,我们都分析了一遍。logstash、flume属于重量级的组件。它们都是基于JVM虚拟机运行的。filebeat的呢是一个轻量级的组件,它是基于go语言。从语言层面来分析。go语言开发的程序,性能消耗是比那个基于JVM虚拟机运行的程序要小的。并且我们也在实际的服务器上进行了测试。相同数据规模下,filebeat的内存和CPU消耗是flume和logstash低的。

那我们就直接选择filebeat了吗?并不是因为它的优点是性能消耗低,但是它的功能是有点弱的。所以我们在实际过程中会这样做。在前端业务机器上部署Filebeat的,将日志数据采集到消息队列里面。因为这个时候的要求是尽可能少的占用服务器资源,保证服务器上面的其他业务正常运行。数据到消息队列以后,后面我们可能还需要对数据进行一些简单的预处理,之后再存储到不同的地方。那所以在这个地方就可以使用flume了,因为提供了丰富的source和sink,并且也可以使用拦截器对数据进行一些简单的处理。这个时候就不需要太纠结性能消耗了,因为flume是部署在单独的服务器上面,不会对其他应用程序造成影响。在这呢,我们先简单画图看一下。

image-20230517155827983

1
然后这个呢,是前端业务机器啊。那如果说我们想采集这个机器上面的一个日志数据的话,最好呢,是部署一个性能消耗低的一个采集工具。因为这上面除此还有其他进程。所以说我们在这里面部署于一个filebeat的性能消耗比较低。还是有那么两台吧。好,那我们在每一台上面都部署一个Bo的,让他呢去采集当前机器里面的人数数据。采集到之后呢,把这个日志数据啊,放到我们的消息队列里面。这个数据进到这个消息页之后呢,后面我们其实就可以使用去对这些数据做一些简单的预处理,预处理之后呢,再把数据写到其他地方。所以接着呢就可以接一个flume,这个时候就不需要去考虑这个性能消耗。这个有可能,它可以直接去读它里面的数据,然后呢,再把数据再写进去,都是有可能的啊。类似于如果从第一个topic上面就是消费数据。把数据拿出来之后呢,对数据做一些处理,处理之后呢,再放到第二个topic都是OK的。以及呢,flume可以直接消费这个消息队列里面这个数据,然后呢,直接把数据呢,写到我们的hdfs分布式文件系统里面也是可以的。
1
2
3
4
5
6
7
8
所以在这里我们就需要选择Filebeat和flume了,

这里的消息队列我们就直接使用kafka了,因为kafka是大数据领域中最常用的消息队列了。

所以 我们最终的选择就是FileBeat+Kafka+Flume,这就是针对日志数据采集工具的选择。

后面我们也会涉及到数据库数据的采集,在我们这个项目中,需要从数据库中采集的数据量比较小,可以选择使用sqoop,或者我们使用mysql -e命令直接导出数据也是可以的,上一个项目我们已经使用过sqoop采集mysql中的数据了,在这我们就使用一个不一样的,自己开发脚本使用mysql的命令导出数据。
不过我们在最后是需要把HDFS中的结果数据导出到MySQL中,这个时候还是需要用到Sqoop的。

技术选型之数据存储

image-20230424161849176

1
2
3
4
5
前面我们把数据采集工具分析完了,下面我们来分析一下数据存储系统的选择。我们采集到的数据最终会存储到分布式文件系统中,这个分布式文件系统一般就直接选择hadoop中的hdfs,这个就不需要额外的对比啊,因为我们在搭建大数据平台的时候,hdfs已经安装好了。并且它也可以和很多采集工具以及计算框架无缝衔接,所以大数据领域的分布式存储系统一般都直接使用hdfs。目前一些大的厂商也有分布式存储的一些服务,例如亚马逊的s3。我们也可以选择使用这些服务,但是这样的话,针对数据计算就不太友好了。分布式计算框架无法实现本地计算,因为数据和计算节点不在一块儿。所以在这呢,离线数据我们就使用HDFS来求我们的计算框架,计算的结果数据有一些是需要和前端交互的。这些数据呢,前期可以选择存储到MYSQL里。

那我们在维护这个用户三度关系数据的时候呢,如果使用普通的关系型数据库进行存储的话,会造成很多数据冗余,并且查询起来也非常麻烦,所以一般啊会使用一些图数据库。这里面这个Graphx或者Gelly。Graphx是spark中的图计算。gelly属于flink中的图计算,它们只能实现分布式图计算,不能保存图数据,所以说呢,并不满足我们的需求。

下面这几个neo4j、orientDB、JanusGraph这几个都是图数据库,它们几个又有什么区别呢?我们来看一下。在这里面,我通过这些层面。对这三个图数据库做了一些对比分析啊。其中这个neo4j啊,它是目前人气最高的图数据库,它可以支持高度扩展,完全支持acid acid是数据库里面的一个特性啊,neo4j啊,它提供的Cypher查询语言是比较人性化的,非常容易上手使用,并且 它支持社区版和商业版,社区版是开源的。社区版呢,不支持分布式,商业版支持分布式。neo4j入门,相当简单,学习成本比较低,并且比较稳定。还有就是neo4j,它对各种语言的支持也比较好,Java呀,python啊,这些语言它都支持,并且官方提供的还有一个connector插件,可以实现Spark直接操作neo4j非常方便,那在这呢,我们主要考虑到应用性以及快速上线这些特性,所以说neo4j是我们目前最优的选择。所以说呢,针对这些存储系统啊,我们最后的选择就是hdfs加上MYSQL加上neo4j。

image-20230424162131164

技术选型之数据计算+数据展现

1
2
3
4
5
6
7
8
9
接下来我们来看一下数据计算框架的选择。目前啊,大数据领域最常用的几种计算框架包括mapreduce、storm、spark、flink。其中mapreduce是第一代计算引擎,它主要针对离线数据进行计算。由于mapreduce计算框架的模型啊是固定的,针对复杂的计算,需要开发多个mapreduce任务,代码量比较多,也比较麻烦,并且它的计算是基于磁盘的,计算效率也比较低,所以现在已经很少使用。

接下来看一下storm这个计算框架,是一个比较早的实时计算框架,可以实现真正意义上的实时处理。在前期的数据计算领域立下了汗马功劳,但是由于此框架太过于独立,没有自己的生态圈,所以最近这几年呢,日渐没落。

那接下来看一下spark的这个计算框架,它是一个分布式的内存计算框架,支持离线和实时数据计算,由于它是基于内存的,所以说呢,它的计算性能非常高。但是在这需要注意一下,虽然spark支持实时计算,但是它的实时计算并不是真正意义上的实时。这是由于它底层的计算模型决定。spark最快只能支持到秒级别的实时计算,相当于一秒执行一个小型的批处任务。

最后我们来看一下flink这个计算框架,flink属于最近新兴起的一个流式计算框架,它侧重于的是实时计算。flink在支持实时计算的基础上,也可以实现离线数据计算,所以说flink也是支持离线和实时数据计算的。在我们这个项目中,既需要离线计算,也需要实时计算,所以单纯的使用mapreduce或者storm都不合适,并且呢,他们两个现在几乎呢已经快被淘汰了。用的非常少啊,所以说我们需要在Spark和flink中进行选择,当时我们在开发这个项目的时候,flink才刚出来。还不是很稳定,并且我们团队内部也是刚开始接触flink,之前我们一直是使用Spark,所以说为了保证项目快速稳定上线,我们当时决定先使用spark,等后期对项目进行迭代优化的时候再考虑使用flink。所以在这针对数据计算,我们选择Spark

最后是这个数据展现模块,数据展现模块不需要我们实现。这块是由安卓开发组还有iOS开发组负责的,我们只需要把结果数据计算好,存储起来就可以。好,最后我们做一个总结啊,就我们前面啊,针对各个模块进行技术选型的时候,大家不要盲目的追星,我们要根据具体的业务场景和不同框架的特点进行选择,同时还要考虑已经在使用的成熟的框架,不要盲目追求一些所谓的好的新的框架,因为技术成本也要考虑。所以说,技术选型不单单是选技术,是要在结合业务场景的前提下进行选择。

项目整体架构

image-20230424172738182

1
2
3
4
5
6
7
大家好,前面我们把技术选型搞定了,下面我们来看一下项目的整体架构设计。在这里,我把这个项目分为了三个模块,数据采集、数据计算、存储以及数据展现。因为这个计算以后啊,就涉及到存储了,所以说呢,我把这两个划分到一块儿,那接下来我们来详细分析一下这个项目的整体流程。

首先呢,看这个数据采集模块。数据采集模块的数据啊,包含两大类,一个是服端数据,还有一个是客户端数据。其中服务端数据啊,它里面包含服务器中接口调用时记录的日志数据和数据库中的数据。在这里需要注意一下,针对服务端日志数据的采集,是在提供接口服务的机器上部署filebeat来采集。这样机器会有上百台,在这里我们先用一台server01来表示。这里面DB呢,表示的就是MYSQL数据库。

接下来呢,是客户端数据,就是用户使用APP的时候上报的一些用户行为日志。例如打开关闭APP以及呢在APP中的滑动点击等行为,其实呢都会记录日志。这些数据呢,客户端会通过接口定时上报。那接口收到这个请求之后呀,会把请求中包含的日志信息呢,记录到本地文件中,然后使用filebeat进行采集。也就是说呢,我们会在server02上去部署一个接口服务,接收客户端上报的日志数据。那这样其实就可以统一流程了。针对服务端日志和客户端日志,最终啊,都是通过这个filebeat的来进行采集。那filebeat呢,最终把这个数据啊,都采集到这个卡夫卡里面。那针对服务端数据库里面的一个数据啊,我们会通过脚本直接呢,把它导入到hdfs里面。

那filebeat的采集的实时数据啊,导入到卡夫卡里面之后呢,还会通过flume。对这个数据进行一些分发处理,以及落盘到hdfs的操作。落盘就是存储的意思。那针对这里面我们刚才所说这个数据分发的一个详细内容,我们在后面开发数据采集模块的时候,会详细分析它的架构。这就是数据采集模块的主要内容。
1
那接下来我们来看一下数据计算,还有存储这个模块。计算模块主要呢是利用spark。针对卡夫卡中的数据呢,进行实时计算,针对hdfs中的数据啊,进行离线计算。那在计算的时候呢,它还会和这个noe4j这个图数据库进行交互。既会向里面写数据,也会从里面读数据。最终呢,会把这个spark计算的结果呀,使用sqoop导出到MYSQL里面。针对数据计算这一块,一共有六七种计算指标,具体直接计算指标我们在开发数据计算模块的时候会详细分析。这就是这块的一个流程。
1
最后一个呢,是这个数据展现。那在这个模块里面,我们可以看到最终的一个项目效果,这里面其实就是一个手机端的一个项目。这个不是我们的重点。这就是我们这个项目的一个整体架构设计。注意,在这个架构里面其实存在三个主要的问题,第一个针对实时计算,Spark其实不是最优的选择,最好是使用flink。针对这个结果,数据的存储mysql也不是最优的选择。最好是使用redis。针对数据展现这一块,直接查mysql中的数据也不是最优的选择。最好是开发接口。对外提供接口查询数据。不过我们为了快速迭代上线,所以前期呢会使用相对来说比较简洁的架构,先把功能快速上线,后面再迭代优化。

Neo4j介绍及安装部署

1
2
3
4
5
6
7
大家好,针对我们前面分析的这些技术组件,只有filebeat和neo4j我们没有使用过。不过非呢比较简单,它类似于在使用的时候主要是写配置文件,所以在后面用的时候我们再具体分析。下面我们就来学习一下neo4j的使用,让大家快速了解它,并掌握它的常见用。

neo4j,它是一个高性能的图数据库。它和普通的关系型数据库是不一样的,它里面侧重于存储关系数据。针对各种明星之间错综复杂的关系,如果我们使用mysql这种数据库存储,在查询所有人之间的关系的时候是非常复杂的。但是使用neo4j这种数据库只需要一条命令就可以了。neo4j,它是一个嵌入式的基于磁盘的、具备完全的事物特性的持久化引擎。它将结构化数据存储在网络上,而不是表中。注意这块,这个网络,从数学角度我们可以把它称之为是图。这个并不是我们所说的4G网络,5G网络,不是这个意思。

目前这个neo4j有两种发行版。一个呢是商业版,它是支持集群的,另一个是社区版。这个只支持单机。目前我们这个平台用户量啊,在三四千万这个规模,这个时候呢,我们使用单机也是足够用的。等后期单机无法支撑之后呢,再考虑使用商业版。那接下来我们来看一下neo4j的一个安装部署。用它支持在Windows以及Linux中进行安装,由于在实际过程中肯定是要在Linux中进行安装,所以说在这呢,我们就直接使用Linux环境。

那下面呢,我们首先来下载一下。在这我已经起先打开了,因为它这个打开比较慢啊,你在这搜new,就这个new.com,这是它官网。接下之后把鼠标放在这个product上面,然后到这看到没有下载new,点那个。进入这个界面之后,注意。点这个。大陆的用户g serve。记下之后,注意,这呢是商业版。我们要用那个社区版的,就是这个。这是免费的。往下面走,你看他现在最新的版本呢,是4.1的,建议的话呢,我们可以往上面走一走,使用它之前比较稳定的是3.5的那个版本。往下边你看。3.5.21建议使用这个版本。看到没有,这是针对linknux或者麦克对吧?下这个是一个table包,如果想在Windows里面运行,你选那个Z。那我们在实际工作中,开发环境肯定是要用这个基于Linux的,所以说我就直接下载这个啊,你点这个就可以了,但是注意。你直接使用这个链接下载啊,很大概率可能会由于网络原因导致你下载失败。

image-20230424174708992

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
呃,建议的话不要用这个链接下怎么办。现在呢,还有一个链接。这个。点,建议大家使用这个链接下载。你直接把这个复制到你的那个浏览器里面,打开就可以,它就会自动开始下载。这个现在呢是比较快。sentence。我在这呢已经卸载过了,到时候呢也会把去的安装包发给大家,所以说你想下的话就去下一下,不想下就算了。

那这个呢,我们就需要把这个安装包啊,上传到我们的bigdata04机器上面。我呢,提前已经上传过了。到这看一下。我放到对soft这个下面。有这个文件对吧,已经有了。那下面呢,我们呢,先解压。解压之后我们来吸到里面。接下来我们需要修改配置。注意它下面有一个conf目录。嗯。在看下面有一个neo4j.conf这个文件,我们就要改这个配置文件。这里面呢,其实也比较简单,我们只需要改两个地方。[root@bigdata04 soft]# cd neo4j-community-3.5.21/conf
[root@bigdata04 conf]# vi neo4j.conf
...
dbms.connectors.default_listen_address=bigdata04
dbms.connectors.default_advertised_address=bigdata04
...

注意:这里的bigdata04是当前机器的主机名

那接下来我们就可以去启动了。
[root@bigdata04 ~]# cd /data/soft/neo4j-community-3.5.21
[root@bigdata04 neo4j-community-3.5.21]# bin/neo4j start

起来之后呢,你可以通过JPS验证一下。看到没有,它确实有一个进程。
访问neo4j的web界面:http://bigdata04:7474/
默认用户名和密码都是neo4j。
你默认进来之后啊,你看它默认呢,会连那个bigdata04,这时候这个端口是7687,注意这个是真正连接neo4j这个服务的。
注意:第一次访问的时候会提示修改密码,建议改为admin,因为那个默认的密码不安全。
那如果说我们想把它停止掉,怎么停呢?很简单,你启动传一个start,那停止了就传一个stop。
[root@bigdata04 neo4j-community-3.5.21]# bin/neo4j stop
1
bin/neo4j stop

Neo4j之添加数据

1
使用neo4j可以很方便的展示一些人物或者事物之间的错综复杂的关系。下面我们来看一张图。

image-20230424211116004

1
2
3
这张图里面展示了这些人物之间的关系。使用这种展示形式看起来是很清晰的。也方便理解,后期如果说我们想查询某一个人的一个关系链,也是很方便的。这些数据如果让你去使用MY数据存储是很繁琐的,并且呢,查询起来也很烦。那这在这里面呢,有几个概念我们需要明确一下。因为neo4j,它是一个图数据库。我们可以认为它里面存储的呢,都是图数据。这个图到底是一个什么东西呢?注意图呢,它是由点边和属性组成的。我们这个图里面这个圆圈呢,它就是一个点。这里面这个线呢,它就是一个边圆圈中的这个姓名呢,就是属性。以及这个边里面这个值呢,也是属性。就是点和边上面都可以设置属性。对,这个点呢,你还可以把它称为是节点。这个边的话,可以把它称为是关系。就类似于这两个人之间的一个关系。每个节点和关系,它都可以有一个或者是多个属性。比如这上面呢,可以保存多属性。

那在这里面大家啊,先对这个neo4j有一个整体的认识,下面呢,我们开始具体学习neo4j中的具体使用。在这儿我们主要学习neo4j的以下操作。添加数据、查询数据、更新数据、建立索引、批量导入数据。主要是这五种。那下面呢,我们把这个neo4j给它起来

添加数据

create

1
2
创建一个点
create (p1:Person {name:"zs"})
1
create (p2:Person {name:"ls"})
1
create (p1:Person {name:"zs"}) -[:like]-> (p2:Person {name:"ls"})

image-20230424212534229

image-20230424212513916

image-20230424212950366

1
p1,p2并不会实际存储,用create创建关系,不会检查之前是否存在待创建关系同名的节点
1
表示每次都创建新的点或者边。第二个表示每次创建点或者编之前呢,会先查询一下,如果存在则不创建。那下面我们就来演示一下。由于在这儿我们需要挑一些密径,所以说呢,在这儿我简单记录一下,这样看起来会更加清晰。a。每次都创建新的点。左边。那我们来在这先创建一个点。嗯。我先把meeting在这写一下,create。注意后面怎么写呢?注意先写一个小括号。英文的啊。冒号后面呢,表示你要创建这个点,你要给它起一个类型,它是什么类型的,表示一个person。还是那些。那你这个person的话,你可以给它设置一些属性,就相当于你在这出现点的时候呢,可以里面给它加些属性,属性怎么加呢?括号括号。我们给它加一个name属性。冒号。后面是这个属性的值,叫张三。那我们在这呢,还可以给它起一个别名P,就类似呢,我们在这创建了一个判对象。判断对象里面有一个内部属性,它的值呢是张三,最终呢,给它起了一个变量的名称叫P。我们来执行一下。放到这里面,点了一个play去执行就可以。添加成功看到没有,创建一个note,创建一个节点,然后设置一个属性。OK,那接下来我们再来创建一个节点。还使用这个。改一下。P2吧。第。把这个拿过来执行一下。那现在的话呢,我们就有两个点了。但是这两个点之间呢,还没有什么关系。那我们想他们两个之间有关系的话,就需要给它们设置一个边了。这个边的话呢,同样可以使用这个create命令来创业。注意,看我怎么实现啊。VISA。对前面的话呢,就类似是这个对吧,把它拿过来。注意,我们想给他设置一个边。就是一个关系。我们想让这个PE啊,这个张三,让他去喜欢李四。表示它们间的关系吗?后面一个横杠中括号冒号,这是固定格式。后面给他写个like,表示呢,张三喜欢李四。一个横杠,一个右键轴。对,这个表示呢,是张三喜欢李四,所以说李四是在后面。对,它这个箭头是往右边指啊,比如他喜欢它,所以呢,在这两个点之间呢,给它设置一个关系叫like。比如张三喜欢的,我们来执行一下。成功了对吧,两个基点。是这两个属性。以及呢,创建了一个关系,或者说呢,是一个边都可以啊。注意,这条命令执行之后,我们可以到这个界面上点这个device。来看一下,你看这是节点,这是关系,这个呢是属性。这是我们创建的person,以及这个like的关系,以及你person里面name的一个属性,在这都可以查看。我们接着可以点那个like。看到没有?张三like李四。这样的话,就可以很清晰的看到他们两个之间的一个关系了。但是呢,这时候呢,你回到这儿来看一下。你看点了一个person。你发现啊,它有四个person。你看两个张三,两个李四。然后你往这个位置看,你看这是内幕李四对吧,所以我们现在啊,选中这个李四和ID,你看是一,那这个呢。李四,它ID是21,看到没有,这个ID是它自动生成的,是唯一的。你看他们两个还不一样,那就意味着这是两个节点,对吧,不是同一个,虽然说他们两个名字一样,但是他们不是同一个极点。那这是什么原因呢?注意,因为这个create呀,它每次呢都会创建新的激烈或者关系。所以说呢,最开始啊,我们使用这个create,你看创建了两个节点,P1还有P2,对这个P1还有P2这个东西它不会扯到就里面。这个以及这个name对应的值是会存储到里面的,这个相当于你给它起了一个别名而已,这个东西不会存进去。那我们之前你看在这创建了一个P1,又创建一个P2,现在我们出现了两个P对象。这是新建的。那接着呢,我们使用这条命令,看到没有。它相当于又创建了两个,这个杠三和离子。所以说呢,你这时候在你的纽扣针里面就有四个。那其实啊,我们在这是想给最开始创建的这两个机制增加一个这个like关系的。因为在实际过程中也会有这种需求,就是节点已经存在了,需要我们后期给他们指定关系。你这种写法,它相当会重新生成。那肯定是不满足我们需求的。这个时候该怎么做呢?咱们前面说了,谬杯里面除了有这个create meaning,它还有一个me meaning。这个命令呢,表示啊,在创建几点之前都会先查询一下,如果存在则不创建。我。这个命令。在创建节点之前都会。先查询一下。如果存在。则不创建。所以说这个默认命令啊,你就算是重复执行,他也不会产生重复的结果。注意你这个奎的命令。你重复执行,你执行一次,他就给你创建一个这个person这个节点。这个需要注意一下啊。那我们看一下me的话,后面的写法是一样的。后面这种写法是一样的。现在我要看起来清晰一些,我给它起个别名叫P3吧。其实都无所谓啊。注意那下面呢,我再写一个,这是P4对吧。这个名字给他改一下吧,这个叫Jack。同时呢,我们想要这个Jack呢,去like to。这样写much。第三。like。kiss。这样写就可以了。现在呢,我先复制这一行,拿过来来执行一下。拖延成功了对吧,创建一个节点,设置一个属性,那你说进行明我再执行一下,你可以直接点那个。再执行一下。看到没有,没有改变。点着来确认一下。看到没有,还是一个,所以说这个默认命令啊,你重复执行,它是不会重新创建的,因为在这的话,它呢,会根据你在这使用的这个名称去查一下,看看有没有重复的,如果有的话,他就不再创建了。所以说呢,在工作中啊,建议使用这个墨。可以避免重复。注意。这条命令你说我单独执行行不行啊不行,你必须要保证这条命令和前面两个一块来执行,因为在这这个变量,我前面说变量它是不会存到u里面的。他呢,只在当前绘画有效,所以说呢,这三条命令需要一块儿来执行。把它们放到一块儿,这样来执行就可以。来确认一下。看到没有,Tom Jack。你点那个也是OK的啊,一样的。这个。like to。对吧,我们记住那个person的话,等于之前我们是四个,现在又加了两个,一共是六个,没有问题。在这里其实还有另外一种写法,如果节点已经存在了,我们只需要创建关系,我们还可以使用那个match来实现。再让我们先简单用一下。那。那么可以查询之前。已有的。节点或者关系。那其实就是电或者是编了嘛。一样的意思啊。那接着呢,我们就想要这个Tom和这个也产生一个like关系。对,你看之前的话呢,是这个。Jack like Tom,那现在的话,我们想让Tom也去like Jack一下,互相习惯,这样的话就不是单相思了嘛,对吧。单相思最难受。所以说我们在这呢这样来做,使用ma先查询那个节点,因为那个节点之前已经创建过了,对吧。可以这样,那我们要给他起个名字叫a吧,还一个person。他的name呢?the Tom。对吧,我们要查两个人啊,要把这个汤还有这个都得查出来,对吧,要找到这两个人,重新再给他们加一个关系。B。name。Jack。把他们两个都查出来,注意,查出来之后注意。a。然后a就是Tom,然后Tom呢去like。B注意这里面这个a还有B,只是为了在这去使用,没有其他含义,你给它起个什么XY也是可以的。来我们来执行一下,注意他们两个也需要一起来执行,要不然那你这个a他是找不到他的。好,执行成功,你看创建了一个关系。这个还是六对吧,没有变。只不过这时候你看没有,汤姆也喜欢Jack克,Jack克也喜欢汤姆,他们两个就互相喜欢了。所以说呢,我们就可以通过match呢,去查询之前已有的机械信息,然后再通过墨创建关系就行。这样也不会额外产生重复的节点。所以说呢,这两种方式啊都可以,你使用这种方式也行,使用这种方式也行。按需选择即可。效果是一样的。

merge

1
2
3
4
这个命令在创建节点前都会先查询一下,如果存在则不创建

merge (p3:Person {name:"jack"})
merge (p4:Person {name:"tom"})
1
merge (p3) -[:like]-> (p4)

image-20230424213515502

image-20230424213535288

1
把上述三条命令一起执行

match

1
2
3
4
5
6
可以查询之前已有的节点(点)或者关系(边)

match(a:Person {name:"tom"}),(b:Person {name:"jack"})
merge (a) -[:like]-> (b)

这种a,b只是别名,只在当前会话有效;这两个要一起执行,不然第二个命令找不到a,b

image-20230424214333671

image-20230424214401568

1
2
3
4
之前jack->tom
现在jack<->tom

等同于之前的三条merge命令

Neo4j之查询数据

1
下面我们来看一下用户类中如何查询数据。针对这块我们主要学习以下内容,首先呢,学习一下这个match和return的用法,它们呢可以实现查看满足条件的数据,并且返回。以及最后我们会讲两个案例,如何查询二度关系和三度关系。

match+return

1
match(p:Person {name:"tom"}) return p
1
2
咱们前面呢说过这个match啊,它可以进行一个查询,下面咱们就来继续使用一下。这个呢,其实有点类似于mysql中的select。在这需要注意一下,match不能单独存在。咱们前面在使用的时候,那后面跟着也是有一个merge命令的。如果我们只想查询一些数据,并且把这个数据返回过去,呃,如何实现呢?
就可以使那个match加return。就是查看满足条件数据,并且返回,那下面呢,我们就来查询一条数据。现在我们想查询一下这个Tom这条数据。nice。PAR。指定属性name。对吧,我们就想查他,那查出来之后呢,想要把这个结果啊给返回,怎么返回呢,后面加个return。这样这样就可来我们来执行一下。没问题吧,查出来了对吧,把那个汤姆查出来。

image-20230424215018223

1
那下面呢,我们来查询一些复杂一点的内容。首先呢,在这我们来初始化一些数据。好,这些数据呢,刚才我已经把它复制过来了,就这些数据,注意这里面创建点的这些操作和创建边的操作需要在一个会话里面一起执行啊。否则它是无法识别这些变量的。

image-20230424215221280

1
在这你看其实相当于我们初始化ABCXYZ是吧,这几个用户。在他们之间呢,给他加了一些关注关系,其实就类似于直播平台里面用户和主播之间的一个关注关系。好在这把这批数据给他做一下初始化,直接复制过来。好创建成功对吧,六个节点六个属性六个关系。那首先呢,现在我们要做一个查询。假设呢,这些都是主播,你看a follow了B对吧,a关注了B,那B的话,我们可以认为它是一个主播对吧?那所以说呢,这样我们要查询某个主播的粉丝信息。我们就查询这哥们儿,你看有这个a和C都关注了他对吧,他的名字呢叫B。B。好,那这时候怎么实现注意。查询嘛,使用。name。我们要查询这个用户,他的一些粉丝。注意看我下面怎么写,相当于啊,是别人关注了他,按照我们之前教的这种写法,就类似于这种,你说把这个拿过来,注意这个箭头是往右指的,也就是说呢,是他操作了别人,他关注了别人。我们现在要查的是谁关注了它,所以说了这个方向不是往右的往左。对吧?我们要查询哪些人关注到这个user b。所以后边的话呢,零。有的。这时候它后面呢,就不需要加这个括,括号里面也不需要指定什么属性了。相当于我们就要查询到底是谁关注了这个user b。这个人具体是谁,我们现在还不知道呢,所以说呢,后面也不需要加一些具体的限定。OK。那个范围就可以。来,我们来执行一下。看到没有a和C。你回过头来看一下。AC对吧,你看。a的话,它这个名字就是大a嘛,对吧,这是大C没问题。所以说呢,我们是可以查出来的。那其实这种写法呀,它还有一种写法。还有一种写法,矢量。mass。把他们反过来。把它放到前面。这个不是注意改一下。对吧。就是谁去follow了这个user。这样写也是可以的。如果说你感觉这种写法比较别扭,你可以用这种写,对吧,谁关着B。这样把它返回过来就可以,效果是一样。11下午啊。如果说我们只想返回满足条件的那个粉丝的一个name值,你看这个相当于它整个把这个几点都给返回来,如果说我们只想返回它里面这个内的属性的值怎么办呢?也简单。值返为零。没问题吧,也是可以的。好,这个其实啊,就是我们要查询的那个主播的二度关系。为什么这样说呢?我们来分析一下啊。你看这个时候呢,是这样的我。这个呢,是这个主播B。后面呢,是主播B的一个粉丝。那这个时候我和这个主播B的粉丝,我们之间是不是就属于一个二度关系呢?因为我和主播B我们之间呢,是一度关系。主币和粉丝之间呢,也是一度关系,但是我和这些粉丝之间就属于二度关系,我们是通过这个主币来认识。好,那我们在这个项目中呢,是想实现三个关系推荐。也就是说呀,当我要关注某个主播的时候,你呢,要给我推荐这个主播的粉丝,又关注了哪些主播,你把那些主播推荐给我。因为我和那些主播之间才属于三种关系。二的关系。三度关系。看到没有,这个时候我和主播N之间就属于三种关系。看到没有,我和他是一组,和它是二度,和它呢也是三组。那这个三的关系该如何查询呢?其实咱们刚才这个呀,查询的就是二楼关系,其实你只需要把这个主播币的粉丝查出来就行了,后期谁去关注主播币,那这个粉丝和那个人,他们之间是不是就是二度关系。

image-20230424215318019

1
2
3
4
5
查询某个人的粉丝
match (:User {name:"B"}) <-[:follow]- (n:User) return n

另一种写法
match (n:User) -[:follow]-> (:User {name:"B"}) return n

image-20230424215640635

1
2
3
4
5
查询某个人的粉丝只返回name(属性)值
match (:User {name:"B"}) <-[:follow]- (n:User) return n.name

另一种写法
match (n:User) -[:follow]-> (:User {name:"B"}) return n.name

image-20230424215940138)image-20230424215940184

1
2
这些属于二度关系(查询我关注的人的粉丝的信息)
我->主播->粉丝
1
2
3
4
三度关系(给我推荐我关注的主播的粉丝关注的人)
我->主播->粉丝->主播N

match (a:User {name:"B"}) <-[:follow]- (b:User) -[:follow]->(c:User) return a.name as aname,b.name as bname,c.name as cname

image-20230424221314630

1
2
3
那我们现在想查三度关系,那其实就是查出来主播B的粉丝又关注了哪些主播。只要把这些数据查出来就可以了。我们返回一下。看到没有?这是主播B,有这么几个粉丝啊,A和C看到没有?他有a和C这两个粉丝,分别关注了XYZ这三个主播,其中呢,A和C这两个粉丝呢,都关注了Y这个主播。那这个时候你再给我推荐深度关系的时候呢,就应该从这里面去挑了,那这个时候是不是应该把这个B的粉丝关注比较多的主播推荐给我呢?你看a和C都关注了Y,你是不是应该把它推荐给我呢?在这里,理论上来说,Y这个主播最有可能是我喜欢。这个Z和X呢,它那个可能性啊,就没那么大,所以说呢,在这里面啊,我们在获取这个三度关系的时候呢,针对这个c.name里面这个结果呀,最好呢是做一下过滤。我们统计一下c.name里面相同主播出现的次数。然后呢,按照倒序排序。最终再取一个topN是不是就可以了?重合度越多的说明了越有可能是我喜欢的。因为相当于我去关注这个主播B了,相当于我喜欢主播B。你看a和C这两个粉丝也关注他了,说明他们两个也喜欢他,那有可能我和这个a还有C这两个粉丝这个口味是一样的。那他们两个同时呢,又都关注了Y这个主播,所以说呢,Y这个主播也是最有可能是我喜欢的。所以说呢,这个其实就是三的关系,最终想要达到一个效果。

好,那根据我们刚才分析,你在这儿还想对它做一个什么聚合,对吧,再做个排序,这东西怎么实现呢?我们来看一下。其实这个麦呀,后面。也支持什么抗就是抗函数。奥特曼。排序的以及呢,这个厘米上对吧,取多少条这些命令啊,都是支持的。那所以说呢,在这个基础之上,我们可以做一些调整。所以这时候你要把这个去掉。只保留这个a name,还有c name就行。然后后面注意你后面返回多个列的话,中间有多少个开啊。抗的星。也是做一个求和啊,后面order by。some。DSC倒序排序。那我们再做一个厘米。倒序排序之后呢,我们取前几条,这样不就是top n了吗,对吧。来,我们在这儿实现一下。看到没有?他最终统计的这个数量,你看对不对。这个Y西里Y嘛,是吧,两次。Z是一次,X是一次对吧,没问题吧。没问题,那所以说这个时候你其实可以把这个稍微改一下,你改成厘米则点一吧,因为这两个值都是一样的,我们就厘米的一就取了一条。没问题吧,是可以的。注意你这里面啊,你用康兴也行,或者说呢,你用那个什么呀,这种写法。对吧,这样也可以啊,都是一样的效果。要消毒一下。可以使用。它或者它效果是一样的。OK。那其实这里面啊,你看这里面就相当于我们根据这个a,还有这个c name去做一些分组。然后呢,使用抗的。去做了一个求和统计,每组的一个数据行数。好把这个加个a是吧,少了一个a啊。这是一样,这只是一个变量名称啊,无所谓。改过来之后呢,看起来顺眼一些对吧,有强迫症的话,感觉这里面少一个字母,感觉很难受对吧。好,这就是二度关系,还有三度关系的一个查询了。对,这里面呢,其实啊,我们还可以使用where去加一些过滤条件。就实现一下过滤。注意。你想使用where也可以啊。这个where需要放在。return前面因为你这个return啊,就直接返回了呀,你这个where啊,肯定是要放到return之前的,先过滤再返回嘛,对吧。把这个复制过来。注意现在前面加一个外过滤。我们过一下,where name。对,你在这还不能用那个C里,C里姆是在后面定义对吧,我们前面的话还只能用C点内。不等于X吗?把X这个过滤掉行吗?你先回到这儿。对吧,还是0.3。你看现在这个C里是不是有一个X呀。好,我们在它基础上加列过滤。对吧,C点内就是不等于X对吧。看到没有,只有Y和Z啊。OK,所以说呢,这里面也是可以用这个where或者条件的。OK,这个其实就是我们这个没忽略里面的一个查询操作啊。注意这里面这个查询语法呀,其实啊,就是用户这里面的S法语法,这个塞法语法呀,在查询的时候,你看其实有些地方它和circle那个查询还是有点类似啊。所以说呢,这种写法还是比较简单易用的,最起码看起来是比较清晰的。很直啊,所以说呢,我们学起来上手也很快。这就是我们当时为什么选择这个newd啊,这个查询语言确实用起来比较方便。

函数

1
2
其实match后面也支持count()、order by、limit等命令
match (a:User {name:"B"}) <-[:follow]- (b:User) -[:follow]->(c:User) return a.name as aname,c.name as cname,count(*) as sum order by sum desc limit 3

image-20230424222424329

1
2
3
注意:这里count(*)等同于count(cname)

相当于对aname,和cname做了分组,在操作

where

1
注意:where放到return之前
1
2
其实match后面也支持count()、order by、limit等命令
match (a:User {name:"B"}) <-[:follow]- (b:User) -[:follow]->(c:User) where c.name <> "X" return a.name as aname,c.name as cname,count(*) as sum order by sum desc limit 3

image-20230424223142375

Neo4j之更新数据

1
下面呢,我们来看一下如何在应用中去更新数据。更新数据这块啊,其实总结一下有两种情况。第一种呢,就是更新节点的属性,使用match和set实现,你把它先查出来,然后呢使用set命令去修改。第二种啊,就是更新节点之间的关系,也就是边。这个其实就是删除边。我们使用那个ma和D的视线把它查出来,把它删掉。其实呢,你使用这个match和吉delete也可以实现删除节点。对吧,我们把这个节点查出来,然后把它删掉。那下面呢,我们就来演示一下。首先我们看一下就是如何修改节点中的属性。那。有了。name。我使用那个X这个用户吧,行吧。把它查出来之后呢,后面sa.H。等于八,注意如果说它里面没有这个属性,那就把这个属性给加上去,如果有这个属性了,那把这个属性值改成18。看到没有添加一个属性。现在我们可以查一下它。你看a。看到没有,它里面一个name是XH是什么?具有刚才我们给他加了一个属性啊。那接下来我们看一下如何删除关系。match。然后呢?name。a,对,你前面这个变量呢,你能用到了,那你就给它起个变量,如果你用不到,那你就不用起。我们在这呢用不到,所以说就不给它起变量,变成清不洗都无所谓啊。follow。我们看一下之前那个数据这个a。你看它其实呢,关注了BXY对吧,那我们随便找一个吧。name。X吧,对吧,它对它呢也有一个分关系。注意,我们最终啊,想把他们两个之间那个follow关系给它删掉。那怎么办,这时候啊,你要给这个合作关系啊,也起一个别名。起个名称,这样的话在后面呢,使用第一层。这样就可以把它给删掉。看到没有,删除了一个关系。点包。这时候这个a是不是就没有关注那个X了呀。你可以到这儿来查一下。看到没有对吧,X它现在就没有人去follow。就变成一个孤家寡人了,对吧,又没有连到这里面。OK,这就是用户内容针对更新数据的相关操作。如果说你想去删除一条数据啊,就删除一个节点,那你把它查出来对吧,把它查出来后面呢,直接给它就类似这种。前面呢写这个,后面呢加上一个a,就可以把这个name等于X的这个user给它删掉。这个呢,给大家留一个作业,下一周我们自己操作一下行吧,我这个呢就不再演示这个。

更新节点属性

1
2
3
match (a:User {name:"X"}) set a.age = 18

有更新,无则添加

image-20230424224750421

image-20230424224819117

更新节点之间的关系(边)

1
match (:User {name:"A"}) -[r:follow]-> (:User {name:"X"}) delete r

image-20230424225000475

image-20230424225026098

1
2
注意:删除节点
match (a:User {name:"A"}) delete a

Neo4j之建立索引+批量导入数据

1
2
3
下面我们来看一下neo4j中的索引

neo4j中的索引可以细分为两种

普通索引

1
2
3
4
普通索引 CREATE INDEX ON :User(name)

第一种是普通索引,使用create index 可以实现,指定给节点中的某个属性建立索引,
具体建立索引的依据是后期我们在查询的时候是否需要在where中根据这个属性进行过滤,如果需要则建立索引,如果不需要则不建立索引。

唯一索引

1
2
3
4
5
唯一约束 CREATE CONSTRAINT ON (u:User) ASSERT u.id IS UNIQUE

第二种索引称之为唯一约束,类似于mysql数据库中主键的唯一约束。
使用CREATE CONSTRAINT可以实现
CREATE CONSTRAINT ON (u:User) ASSERT u.id IS UNIQUE
1
2
3
那这两种在使用的时候具体该如何选择呢?

如果某个字段的值是唯一的,并且后期也需要根据这个字段进行过滤操作,那么就可以建立唯一约束,唯一约束的查询性能比索引更快

批量导入数据

1
2
3
4
5
6
7
8
9
10
11
那接下来我们将学习一下neo4j如何批量导入数据
针对项目一开始的时候有一批海量数据需要导入,我们就不能使用前面讲的那种命令一条一条导入了,性能太差,我们需要有一个批量导入的方式来快速导入这一批数据。
neo4j批量导入数据有两种方式,一种是这个batch import的,还有一种呢是load csv

第一种这个batch import,它呢需要组装三个文件,导入性能呢比较快,但是呢比较麻烦。

第二种这个load csv呢,它呢只需要把数据组装到一个CSV文件即可。导入性能没有batch import快,但是也没有我们想象中的那么慢,还是可以接受的啊,它的优点呢,就说使用起来很方便,直接把所有需要的数据直接都组装到一个CSV文件即可。

那在这里啊,我们考虑到一个易用性。由于我们的原始数据都在MYSQL中,我们可以通过MYSQL命令直接把数据导出为一个文件。所以接着呢,我们直接使用load CSV会更加的方便。

但是在这有一点需要注意。在load csv中啊,我们如果使用到了merge或者match这些命令的时候,我们需要确认关键字段是否有索引,否则呢,性能会很差,怎么理解呢?来看一下。就针对这种match,或者咱们前面讲的那种merge。你这个merge,它在执行的时候,其实呢,它会根据这个name看看有没有这条数据,对吧,如果没有的话,它才会新增,如果有的话,他就不会再新增了,所以说呢,它需要根据name这个字段去查询数据,那所以说呢,你就需要根据name了。去建立索引,如果你没有建立索引,后期用户内容数据量大之后,这块平行效率会很差。以及这个match也是一样的,match里面你看没有,你这个其实是根据那个name去查的。所以这时候的话,这个name字段对吧,它也是需要有索引。以及这个where后面这些过滤条件,对吧,也是需要有索引。如果这些关键字段没有建立索引的话,那其实这些操作它就相当于是一个全表扫描了,所以说呢,你数据量越多,它的查询性能会越差。
1
例如:merge(a:User {name:“A”}),此时就需要提前对User中的name字段建立索引,否则在进行初始化的时候,数据量大了之后,初始化的性能会很差,因为merge在执行的时候会查询name等于A的数据在不在neo4j中,如果name字段没有建立索引,则会执行全表扫描。
1
那接着啊,我们先把这个neo4j的数据啊给它清空了,那如何清空数据呢。接着呢,就给大家一种暴力的方式啊。你把它的data目录给删了。因为他的所有数据啊,都放到那个date目录里面。然后呢,重启一下neo4j。stop一下。再启动一下,那接着呢,我们来看一下,我准备了一个测试的一个数据文件。

image-20230518165227850

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fuid	uid
1001 1000
1001 1004
1001 1005
1001 2001
1002 1000
1002 1004
1002 2001
1003 1000
1003 1004
1006 1000
1006 1005
2002 1004
2002 1005
2002 2004
2003 1000
2003 1005
2003 2004
1
这个文件里面一共有两列。fuid是关注者。uid是被关注者。你可以把它认为是主播,这是观众对吧。那我们需要把这个数据啊,给他做一下初始化。那怎么初始化呢,注意。你想要对这个数据做初始化的话,你首先啊,需要把这个文件上传到NEO4J_HOME的import目录下才可以使用。注意你必须要放在这个目录下面才能使用啊,否则neo4j会找不到。这个需要注意一下,那下面呢,我们就把这个批量导入命令啊,先给他写一下。
1
2
3
4
5
[root@bigdata04 neo4j-community-3.5.21]# bin/cypher-shell -a bolt://bigdata04:7687 -u neo4j -p admin
Connected to Neo4j 3.5.21 at bolt://bigdata04:7687 as user neo4j.
Type :help for a list of available commands or :exit to exit the shell.
Note that Cypher queries must end with a semicolon.
neo4j>
1
2
3
4
首先针对关键字段建立索引
neo4j> CREATE CONSTRAINT ON (user:User) ASSERT user.uid IS UNIQUE;
0 rows available after 281 ms, consumed after another 0 ms
Added 1 constraints
1
2
3
4
5
6
7
8
然后批量导入数据
neo4j> USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM 'file:///follower_demo.log' AS line FIELDTERMINATOR '\t'
MERGE (viewer:User { uid: toString(line.fuid)})
MERGE (anchor:User { uid: toString(line.uid)})
MERGE (viewer)-[:follow]->(anchor);
0 rows available after 791 ms, consumed after another 0 ms
Added 11 nodes, Created 17 relationships, Set 11 properties, Added 11 labels
1
2
3
4
5
6
7
在neo4j的web界面上也可以执行,需要添加:auto命令。
解释:

PERIODIC COMMIT 1000:每1000条提交一次,这个参数非常关键,如果在数据量很大的情况下内存无法同时加载很多数据,所以需要批量提交事务,这样可以减小任务失败的风险,并且也可以提高数据导入的速度,当然这需要设置一个合适的数量。
WITH HEADERS:是否使用列名,如果文件中有列名,则可以加这个参数,这样在读取数据的时候就会忽略第一行
FIELDTERMINATOR ‘\t’:指定文件中的字段分隔符
然后我们到页面上看一下导入的数据。

image-20230518165932413

1
2
3
4
注意:此时我们会发现在页面中的圆圈中没有显示数据的具体内容,之前我在用3.2版本的时候是没有这个问题的,现在使用新的3.5版本之后会发现页面显示的时候会出现这种问题,这个问题倒没什么影响,就是在页面中看起来不太方便而已。

通过我的测试发现
如果我们在添加节点数据的时候,给节点指定一个name属性,那么name属性的值默认会显示在这个圆圈里面,如果不是name字段,则不显示。这个应该是新版本的一些特性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
批量初始化数据

针对关键字段建立索引
create constraint on (user:User) assert user.uid is unique;

批量导入语句
using periodic commit 1000
这什么意思呢?注意这个表示呀,可以是每1000条起交一次,这个表示设置一个事物提交的一个大小啊。这个参数呢非常关键,如果说你这个数据量非常大,那你把这个全量的数据全部都读出来,全部都放到内存里面,这样的话内存可能扛不住,所以说呢,建议呢批量去提交事务。这样可以减小任务失败的风险,并且呢,也可以提高数据导入的速度。当然,这需要设置一个合适的数量,这个数量太大或者太小其实都不合适啊,就类似于我们平时往mysql里面批量提交数据一样,提交数据也是一批一批的。
load csv with headers from 'file:///follower_demo.log' as line fieldterminator '\t'
注意这个其实呢,就相当于从本地这个根目录下面读取了。我们之前把这个文件放到那个neo4j的import目录下了,注意你只要放到了import目录下面,那其实呢就是相当于是从根目录读取,这个是neo4j来设定的。他就会读取这个文件里面内容,一次读一行,一行数据这个字段之间是分隔符这指定一下。那这样的话,其实前面这两行呢,基本就把这个功能属性设置好了,

merge (viewer:User {uid: toString(line.fuid)})
把那个第一列取出来,注意外面这个呢,我们使用的是一个tostring,它是一个函数啊,你本来一读出来之后呢,这个是一个数字,我们要把它转成一个字符串啊,因为本身我们这个UID就是一个字符串。

merge (anchor:User {uid: toString(line.uid)})
下面这个呢,是一个主播anchor。

merge (viewer) -[:follow]-> (anchor);
那下面把他们之间的关系给watch。V。WS。安。这样就可,那我们来执行一下这个命令,注意这个命令呢,你可以在这个外部界面去执行。在这执行也可以啊,但是在这执行的时候呢。你执行这条命令可以直接执行,但是你在执行这个时候,它会提示让你在前面加一个什么auto,有一个自动提交事务。这是一种方式,这个给大家留个作业,下一周呢自己实验一下,我呢先不用这种方式。我用哪种方式呢?我就直接在我们的雷命令行里面去做。注意咱们之前不是把这个六库率给它重新删了相,那重新启动了吗?现在于是一个新的六扣率了,那所以说你在这啊。还需要去修改一下密码。相当于我们把那个对的目录删了之后,它就是一套新的东西。
1
bin/cypher-shell -a bolt://bigdata04:7687 -u neo4j -p admin

image-20230424233404885

image-20230424233420853

image-20230424233527600

image-20230424233725604

1
那这个大家有没有感觉到有一些看起来不太一样的地方?咱们前面在创建这个节点的时候,你看节点上面是不是显示的那个内蒙的一个值啊。那你说我现在其实也有一个UID的值啊,你为什么这边没显示出来呢。注意了啊,之前啊,我在用这个纽破利的3.2那个版本的时候呢,是没有这个问题的,那现在呢,使用新的这个3.5这个版本之后啊,发现它这个页面显示的时候呢。会出现这种现象。这种现象啊,倒也没什么影响啊,就说了我们在页面中看起来啊,不太方便而已。那通过我的测试发现呀。我们在添加节点数据的时候呢,如果说你给这个节点啊,指定的一个内部属性,那么内部属性的值默认会显示在这个圆圈里面。如果不是内部的一个字段。就不显示你现在有这个UID字段,不显示这个呢,相当于是这个新版本的一些特性啊。不过这倒不影响啊,只不过说在这看起来啊,有点不太习惯,它这个数据呢,你看它其实存点对吧,UID这个值都是有的啊。好。下面呢,我们来验证一下,我们把UID这个属性的一个名称啊,给它改一下,把它改成name,看看这个值啊,会不会显示到这个圆圈里面。那个只是一个显示形式而已啊,我们来验证一下。验证呢很简单,把这个复制出来一份。对吧,然后在这呢改一下。看了什么?这个测试的。这块呢,这个属性名称改成name。这个也是name对吧。好,这个时候呢,我就在这里面来执行,注意我直接拿过来执行啊,它其实呢会报错。先看一下。看到没有?我搞错了。它下面有个提示。就说啊,你需要加一个什么呀,冒号凹凸。这样才行。所以说呢,也就意味着在它前面啊,加一个冒号。而是自行提交。这就可以了。该成功了,你看这又有了。这样的一个test。看到没有,这样就显示了。是什么?遇到这个问题啊,也不要太感到惊讶,这个只是在新版本上做一些改动,之前那个老版本是没有问题的,就是我们之前线上那个版本是OK的啊。后来呢,给大家在这讲的时候,我们用了一个新的版本,稍微新一点就有一些变化啊。其实两个效果是完全一样的啊,这个只是在这显示而已啊。就是看起来清晰一些,这样可能看起来不太清晰啊,有点B。那这样的话,我们现在就实现了一个批量数据的一个初始化,其实就很简单了,现在呢,我们后期啊,可以把我们想要初始化那些数据啊呃,提前导成这种文件。然后在这写一个这个P,触发一个脚本就OK。所以说呢,那CSV这种方式还是比较方便的,你直接把你需要的数据全部都组装到这一个文件里。

本文标题:大数据开发工程师-第十八周 直播平台三度关系推荐v1.0-1

文章作者:TTYONG

发布时间:2023年04月24日 - 15:04

最后更新:2023年05月25日 - 11:05

原始链接:http://tianyong.fun/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88-%E7%AC%AC%E5%8D%81%E5%85%AB%E5%91%A8-%E7%9B%B4%E6%92%AD%E5%B9%B3%E5%8F%B0%E4%B8%89%E5%BA%A6%E5%85%B3%E7%B3%BB%E6%8E%A8%E8%8D%90v1-0-1.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%