Transcription
好的。那么我们开始吧。嗯,你们现在都来到了这个偏僻的、不知名地方的房间里,希望是来看一场关于 Neo4j 的演讲。如果你们不是在找 Neo4j 的演讲,那么你们确实找到了一个奇怪的房间,但你们来错地方了。
所以,我们将要看一看 Neo4j。嗯,主要是 Neo4j,但最后会有一点 .NET 的内容。嗯,是的,我叫 Chris Clo。我是一名软件开发人员/公开演讲者/姑且称我为顾问,在一家公司工作,这意味着我在技术领域里做任何我能拿到报酬的事情,对吧?嗯,但我也会去参加各种会议,谈论我喜欢做的不同事情。嗯,但我大部分的日常工作是在斯德哥尔摩的 Active Solution 公司。嗯,因此,是的,我认为我已经拥有 MVP 称号 15 年了,但这对我们今天将要看的大部分内容关系不大,因为我已经冒险走出了微软的舒适区,开始研究 Neo4j,而我说的“开始研究”是指我们目前正在将它大规模地构建到我当前的应用程序中。嗯,我大约在一年前发现了 Neo4j,然后我们开始尝试它,看看我们能用它做什么。嗯,这很有趣,因为我以前从未接触过图数据库。嗯,而 Neo4j 很好。基本上,我的个人感觉是,它拥有我一生中希望数据库拥有的所有东西。它以我想要的方式拥有我需要的一切。所以,这很有道理。
但让我们回顾一下,图数据库到底意味着什么?当我们考虑数据结构时,它对我们开发者意味着什么?而不是,让我们从这里开始,今天有多少人正在处理基于 SQL 的工作负载?好的。今天有多少人正在处理基于图的工作负载或图数据库?没有人?好的,所以我们大多数人都熟悉 SQL,因为作为一名 .NET 开发者,如果你在微软生态系统中,并且你需要一个数据库,你最终会选择 Microsoft SQL,或者现在有一些其他选择,但它基本上是一些关系型数据库,因为大多数人都是从那里开始的。我也是,很多年前。嗯,但使用 Neo4j,我们不谈论表和类似结构化数据的东西。我们谈论节点和关系。所以我们谈论两种与数据库截然不同的东西。但你有节点,节点包含数据。节点之间有关系,关系也可以包含数据,这就是你拥有的所有东西。没有像外键之类的东西。这就是我们拥有的全部。你有节点和关系,这很不错,非常容易使用。
但让我们也开始一些实际的东西。嗯,入门,安装它。你如何开始使用它?因为我讨厌在新技术上花费四周时间来弄清楚如何在你机器上安装它,或者它需要一堆其他东西。或者,如果你在 Windows 上运行,有些东西根本就很难开始,因为它们不是为在 Windows 上运行而设计的。如果你在 Mac 上运行,那里也有一些问题,等等。Neo4j 在这方面很有趣,因为它字面意义上花了 3 分钟就让我弄清楚了如何运行它。嗯,然后我就可以开始我的 Neo4j 之旅了,因为我想要一个本地安装。我希望它在我的机器上,因为它使用起来很方便。但实际的本地安装,真正地在你的机器上安装 Neo4j 是可以的。它基于 Java 构建。嗯,所以它可以在 Linux、Mac、Windows 上运行。这没问题。你可以下载,你可以安装它。问题是,当你下载安装程序并点击它时,它会说:“嘿,你需要安装 JDK,Java Development Kit。”如果你像我一样老,你已经看过这个小弹出窗口太多次了,不想再按“是”了。出于某些原因,我不想让 Java 靠近我的机器。所以,我走到那一步,然后基本上就想,“哦,它需要一个 JDK。不干了。让我们退一步。我还有什么选择?”
我们可以去云端。云很棒。我们真的很喜欢云。我喜欢云。嗯,Neo4j 确实有一个云功能。它叫做 Aura DB。完全托管。你什么都不用做。如果我们去看看它的成本,它非常方便易用。它就像“嘿,免费的甜心零”,这是你需要开始的。然后有一个非常简单的定价模型,我实际上很喜欢。每 GB 每月 65 美元,这很不错。我认为这不是问题。如果你需要更多,还有企业版。所以这很酷。
现在,我没有提到如果你想在本地机器上安装它的成本。我没有提的原因是,如果你去我刚才展示的截图的同一个页面,然后询问在本地机器上运行它的成本,它会说社区版免费,企业版请联系销售。那部分让我害怕。我还没有走到需要联系销售的那一步,因为我们运行的是社区版。它实际上能满足我们目前的需求。嗯,但本地部署的定价有点复杂。所以,如果你要使用 Neo4j,我建议先看看 Aura DB,因为它是一个非常简单的入门方式,并且它拥有你所需的大部分功能。
所以,云。嗯,我喜欢云。它让一切都变得简单。但再次,我们都知道没有云,它只是别人的电脑。所以有人设法安装了它。我仍然想在我的本地机器上运行它,因为在云端让我很难在飞机上工作。这听起来像是一个奇怪的需求,当我安装代码时,但就像昨天一样,我坐在飞机座位上,在我的机器上写代码,如果我连接到云端,那是不可能的,对吧?所以它需要在我机器上。所以我们又回到了我需要本地运行,但又不想安装它。那么我该怎么做呢?嗯,你必须选择两个选项之一。你可以选择 Docker,我就是从那里开始的。我真的很喜欢它。我的机器上有 Docker。今天大多数开发者都有。你去写那个小东西。`docker run --restart always neo4j:<version>`。发布。你发布两个端口,镜像的名称是 neo4j。然后是你想要的那个版本,你就好了。你可能想添加一个持久化数据卷。就这样。它就运行起来了。你什么都不用做。
这样做的优点是,当你这样做时,第一个端口 7474 是一个网站。所以,如果你浏览到 `localhost:7474`,你实际上会得到你在 SQL 中使用的 SQL Server Management Studio (SSMS) 的东西,对吧?所以你可以通过运行容器来完成你的查询和维护,所有这些都是基于 Web 的工具,这很不错。我做过。那很好。然后我开始研究,他们实际上有一个叫做 Neo4j Desktop 的东西,看到那个之后我就转向了它,因为 Neo4j Desktop 是一个小东西,它是你安装在你机器上的一个工具。所以它是一个在你机器上的应用程序,当你启动它时,你会看到这个 UI,你可以运行实例。所以基本上,它是一个带有窗口的应用程序,就像一个 UI 应用,但它也为你运行数据库。它打开了所有需要的端口等等。所以只要这个应用程序在运行,你就可以从你的代码连接到它,而且每当你想要在这里玩耍并测试你的查询时,所有这些都内置了。
所以,在这个工具里面,你得到的就是你的数据库,你有一个浏览器,你可以在里面写查询,并且实际上以一种 nice 的方式从你的数据库中获取数据,而不必等待四分钟来启动 SQL Server Management Studio,因为这是你数据库的一部分。你有一个数据导入器。所以,如果你需要将数据导入到你的 Neo4j 实例中,有一个导入工具可以让你导入 CSV 等等。它实际上相当不错。你只需要给它一个 CSV,它就会告诉你,“哦,在这个 CSV 中,我实际上发现了这些不同的字段。你想如何映射它们?你想拥有关系之类的东西吗?”导入工具会为你处理这一切。还有一个叫做 Bloom 的东西,是给数据分析师用的,用来弄清楚数据是如何关联的等等。我不知道它是如何工作的。嗯,我不是数据科学家,所以我根本不使用它的那部分,但里面有一个工具供你对你的图数据进行数据分析,而且所有这些都来自那个工具。
所以,让我们来看看它是什么样的。我有一个,不,我不想往那个方向走。让我们去那里。嗯,我在这里有一个非暗黑模式的版本,因为它在投影仪上更容易阅读。所以,这是弹出的工具。你只需要启动它,打开应用程序,按下这个小播放按钮,它就会启动你的实例。你可以有多个实例,每个实例可以有多个数据库。所以,在这个例子中,我有一个叫做 test 的实例。我有两个数据库。默认的 Neo4j 数据库。还有一个系统数据库。如果你想创建一个可以玩的东西,你只需要说,“嘿,我想要一个新数据库。”Neo,我们称之为 Neo4j。嗯,我没有在打字,对吧?我还需要进入这个东西。我将称之为 Neo4j。Neo4j。应该是 demo,就这样。现在我有一个新的 Neo4j 数据库正在运行。我可以进去,比如说我想连接,我想查询它。我进入这个查询界面。我可以切换到说我想使用我刚刚创建的数据库。我得到一些小的指南。所以,我们得到一些关于如何做以及类似的信息。但最重要的是上面,你可以在那里开始写你的查询。
所以,我们可以说 `match p`。嗯,实际上,让我们只做 `p return p`。我马上会解释这意味着什么,但基本上,如果我运行它,它会说,“嘿,数据库里什么都没有。”它是空的。是的,我刚启动它,所以它当然是空的。但这真的就是你开始使用 Neo4j 的难度。下载它,双击 EXA 文件,或者在 Mac 上做任何你做的事情。嗯,然后你就有了一个数据库,你可以开始玩了。现在你可以开始运行你的查询,并且你可以验证你的查询是否真的按你想要的方式工作。嗯,所以入门非常简单。
这里有一个小提示,我想提一下,我展示了你的本地版本中的每个实例都可以有多个数据库。这是一个企业版功能。如果你运行的是社区版,每个实例只能有一个数据库。嗯,所以 Neo4j Desktop 运行的是企业版。它拥有所有你需要考虑的功能和所有花哨的东西,如果你不想在生产环境中部署它,并且你将在开发、测试或生产环境中使用社区版,那么你需要知道从桌面版迁移到其他版本时会出现一些限制。
现在,这可以非常非常容易地解决,因为你可以运行 Docker 容器。如果你需要多个数据库,你只需要运行多个容器,你就好了。如果它们在同一台机器上,你只需要更改它们的端口,然后就可以使用了。
所以,让我们回到我之前谈到的基本元素:节点和关系,而不是我们在普通关系型数据中的表和外键。我喜欢它们被称为关系型数据库。嗯,但关系实际上并不是一个东西。基本上是这里的 ID 指向那里的 ID,我们验证它们是相同的。嗯,而在 Neo4j 和图数据库中,关系是一个东西。它是一个一流的公民,这是一个我真的很喜欢的东西。
所以,在你的节点上,你可以有标签,这就像一组有限的标签。它基本上是一个键值对的东西,或者在这种情况下,它更像是一个抱歉,它是一个列表,在这种情况下,基本上是一个值的数组。你通常使用标签来定义节点的类型。我将人们存储在我的数据库中。所以我有一个叫做 person 的标签。我有一个叫做 movie 的标签。我有一个叫做任何我想要的标签。所以,基本上标签通常用于我们想要查询的高级事物。就像我想获取居住在这个地区的所有人一样,或者其他什么。然后你说,我想要一个标签,我可能想要一个叫做 person 的标签,因为那是我将要处理的一种类型。
但你的节点也可以有属性,就像你期望的那样。所以你可以添加一个键值对存储,它实际上是 JSON。嗯,你有一个有限的类型集,但你可以做任何你想做的事情。它不像 SQL 那样有严格的模式。所以你不需要去说,“哦,现在我要创建一个具有这个名称的新节点类型,它将具有这些属性。”它实际上就是,它是一个节点。你可以添加任何你想要的标签,并且你可以添加任何你想要的属性,系统并不真正关心。你可以添加限制。你可以添加约束,但默认情况下,它就像一个文档数据库。它基本上就是 JSON,对吧?
然后你有关系。每个关系都有一个名称,你也可以为你的关系添加属性。所以你可以添加关于事物之间关系的信息。所以,我们将要看我将要使用的演示代码,或者抱歉,演示数据将是电影和人或演员。如果你有一个演员作为第一个节点,它将具有 actor 标签。它将是 acted in,这是关系的标签。然后另一边是一个电影。然后,在 acted in 上,我们可以添加角色。我们可以添加一个数组,说明这个演员在这部电影中扮演了什么角色,这比在 SQL 中要容易,在 SQL 中你必须有一个 actor 表和一个 roles 表,以及所有这些中间的映射东西,对吧?
所以,这里是。显然,我有代码。所以,这是你将看到的实现。Person、movie、acted in,以及有限的信息。就像名字,他们出生的年份,以及电影的一些小东西。
所以我提到你只有有限的属性类型。嗯,你可以放在你的属性里的基本上是这个。你可以使用字符串、布尔值、浮点数、整数、点,这与图形或地理事物有很多关系。所以点可能很有用。日期、日期时间、持续时间。然后你也可以使用所有这些东西的列表或数组。有一件缺失的事情,它没有小数。所以,如果你存储任何需要精确精度的东西,你将不得不自己以不同的方式存储它并管理它,因为在大多数情况下,浮点数是不够的。但它很不错。嗯,如果我们去看看关系型数据库的等价物,标签就是你的表之类的。唯一的区别是你可以有多个标签。所以,理论上你可以把你的数据放到关系型数据库的多个表中。节点就是你的行,因为那是你存储数据的地方。但不是存储一行有很多列,而是存储一行,然后里面有一个数据块。节点属性就是你行中的列值。而你的关系可以算是你的外键,对吧?但外键可能有很多对多,但它们总是定向的,并且它们也可以有值或属性。所以你可以比仅使用外键做更多的事情,除非你想为你自己的关系构建一堆东西。
那是你的查询语法。这是我真正喜欢的东西,因为当你开始和人们谈论使用图数据库时,我通常会得到这样的问题:“哦,我必须写 Gremlin 吗?”有人用过 Gremlin 吗?好的,Gremlin 是一种查询语言,例如 Azure Cosmos DB 使用。我从未用过它,原因很简单,每当有人谈论 Gremlin 时,他们都会谈论它有多糟糕,以及他们有多不喜欢它。这个东西是,查询语言实际上是我选择使用 Neo4j 的原因之一,因为你像一个艺术品一样查询它。说什么?是的。如果你想象括号是一个球,那么它基本上就是一个节点,对吧?然后中间有一个箭头,然后是另一个球或圆圈,这是另一个节点。所以,如果你能画出你想查询的东西,你就把你的画变成你想要查询的东西的 ASCII 版本,这就是你查询的方式。
所以,在这种情况下,我们说,“嘿,获取一个 person,它有一个到 movie 的关系,并返回 person 和 movie。”让我们从处理节点开始,因为我们将从添加、读取、更新数据开始。节点是我们开始的地方,因为我们需要有东西来添加关系。所以,查找节点就是我刚才展示的,当我设置新数据库时。你做 `match (n)`,这基本上是说,“嘿,你能找到任何匹配这个的东西吗?”这基本上是,“你能找到任何节点吗?”我没有任何过滤条件,或者其他什么。只是在我数据库里找任何节点,然后返回那个节点。
而 `n` 是什么?它是一个变量。你可以把它看作一个变量。所以,我们说的是,“嘿,去找到任何节点,括号的语法,然后把每一个节点放到一个叫做 `n` 的变量里。”然后你可以对 `n` 进行查询或过滤,最后你说 `return n`,这基本上意味着返回你找到的那个节点的所有实例。所以,它很容易使用,因为一旦你知道了这个,你就可以进去说,“嘿,返回 `n.name`,只返回那个,或者返回 `n.name` 和 `n.description`。”所以你得到名字和描述。
你可以做过滤。所以你可以进去说,“嘿,你能给我所有 `n` 标签的节点吗?”要定义一个标签,你这样做冒号和标签名。所以,任何,我想获取任何带有 person 标签的节点。你可以说,我想获取任何带有 person 和 actor 标签的节点,这也是我喜欢的另一件事,你可以拥有多个标签,就像这样。所以,不必在数据库中有一个 type 变量或 type 属性之类的东西,你只需要说,“嘿,这是一个 person。这个人碰巧是一个 actor。这个人是一个 director。哦,顺便说一句,那个人既是 actor 又是 director。让我们添加我们需要的标签。”然后我们可以根据它进行查询。你也可以做 OR,当然。
你可以使用简写语法。这就是我将要写的,因为我更喜欢它,而不是你只是说 `match (i)`,我想看一个节点,我想让你验证它有 person 标签,或者我想验证它有 person 和 actor 标签,或者最后一个,给我所有有 person 或 movie 标签的节点。
在做 person 和 movie 或者抱歉,在这种情况下是 movie,这有点吓人,基本上意味着你得到两种不同类型的数据。所以,当你读取返回的东西时,你必须去查看你得到的节点,然后说,“嘿,这个节点有 person 标签吗?那么我可以使用这些属性,或者它是一个 movie 吗?那么我可能有一些其他属性,除非它们实际上共享一些你想要使用的属性。”
最后,你显然也可以匹配属性。所以,你可以按属性过滤。你可以做 `where`,我猜我们大多数人都习惯了。你做 `match` 一个东西,然后 `where` 就像你在 SQL 中一样。或者你做简写的东西,你说,“嘿,匹配任何节点,然后 `where`,然后你做花括号来说明我要匹配的模式。”在这种情况下,我想匹配名字为 Keanu Reeves。然后它只返回 Keanu Reeves 节点。你可以做多件事情。所以,你可以匹配标签和属性。所以,`match` 任何名字为 Keanu Reeves 的 person 节点,或者 `match` 任何 person,person 标签且名字为 Keanu Reeves 的 person,用简写语法。
这个东西的酷之处在于,一旦你学会了这个,并且理解了如何过滤你的节点,这就是你所需要的一切,因为你用同样的方式来过滤你的关系。嗯,这就是你需要知道的全部。你需要知道如何过滤关系。你需要知道如何过滤节点。你已经知道如何用节点来做,过滤关系也是一样的。一旦你做到了这一点,你就可以开始做诸如返回那个节点,或者删除那个关系,或者删除我找到的那个节点之类的操作。所以,这使得查询非常非常容易。
现在,我们需要一些数据来玩。嗯,如果你想……嗯,我们大多数人都需要从某种数据集开始,对吧?所以,我们有一些数据,需要放进去。当你到达那里时,有一个流程图,说明如何将数据导入 Neo4j。所以,它是语义的还是应用配置,还是只是数据?然后,它是大量数据吗?是,否。它是用于科学的图数据,还是批处理的东西,还是流式传输,等等,等等。是的,不干了。嗯,我只是不看那个东西,说这是一个演示。我将做得很简单。但有简单的工具可以进行导入。老实说,在我的应用程序中,我们的数据格式不适合使用任何这些工具。所以我实际上写了一个小控制台应用程序,查询 SQL 并将其转换为 Neo4j 插入,这花了我一个小时,我们迁移了所有数据。数据量不大,但工具非常简单,迁移花费的时间也不多。所以,如果这不适合你,而你又是真正的开发者,写一个小东西来为你做这件事,用一个小定制工具,花不了多长时间。
但是,我将使用电影图,因为 Neo4j 的另一件我喜欢的事情是,它们有一个不错的数据集,你可以直接索取。电影图就是你可以直接说,“嘿,我想要一个图数据,我可以玩,这样我就可以尝试我的查询。”它看起来是这样的。所以,基本上它有两种类型的节点。它有电影,还有人或 person。嗯,一个人可以关注另一个人,一个人可以出演、评论、制作、编写或导演一部电影。这就是你所需要的一切。而这个小图,实际上 Neo4j 中有一个命令,一旦你导入了所有数据,你就可以在 Neo4j 中运行一个小的可视化工具,它就会显示出来,说:“这里是所有我找到的不同节点标签,以及它们是如何连接的。”所以,你实际上可以把今天拥有的任何数据放进去,它就会显示出它目前是如何连接的,以及哪些东西属于一起,这很不错。
所以,让我们继续添加电影数据的东西,这样我们就可以查询它了。讲台不幸地非常低。所以,我将写得很差,因为我几乎够不到键盘。嗯,所以当你进来的时候,这里有一个东西说,“嗯,尝试 Neo4j 和电影图。”如果你点击它,它会在这里打开一个小窗格。你实际上会在这里。但如果你,它只是解释了电影图是什么。你进去。这里是所有数据。你只需要运行它,或者你可以按下那个东西,它会给你所有的 cipher 数据或 cipher 代码。所以,如果我们去这里,这就是它创建数据的方式。所以,如果你对它们是如何做的感到好奇,那么,这就是整个数据集。如果我们运行它,它就会插入我需要的所有数据。就这样。我只需要这些。让我们关闭那个窗口。
所以,现在里面应该有数据了。我知道里面有数据,因为现在左边,我们可以看到 movie 和 person。这些是我们数据库中找到的标签类型。所以,我可以点击它们,我可以提取数据库中的所有电影。然后我可以点击这些。我显然可以缩放和四处看看,玩玩数据。这里是所有不同的关系。如果我点击其中一个,我就会得到所有使用该关系的东西。所以,我们可以很好地玩数据。我实际上喜欢我可以把我的数据可视化成一个图,而不是去 SQL 写一堆查询。在这里,我只需要点击一下,展开节点等等。
所以,这意味着我们有数据了。嗯,让我们写一个简单的查询。所以,我们将做 `match`,意思是我想找到一些东西。所以,去找到一些东西,我想找到一个节点。我将把它添加到变量 `p` 中。我将说,我正在寻找的东西将是一个 person。所以,给我任何节点,它是一个 person 节点,或者抱歉,我称之为 person 节点。实际上,它意味着任何带有 person 标签的节点,对吧?如果这是更准确的说法。然后我在这里添加一个箭头来告诉你,“嘿,我想要一个关系,它应该是从 person 指向其他东西的。”然后在另一端,我们可以说,“嘿,你能给我任何电影,它的标题是 the matrix 吗?”它是区分大小写的,这有点烦人,当你从 SQL 来的时候,但它就是这样。然后我们必须返回一些东西,所以我们返回 `p`。这真的就是我需要说的,“请给我任何与电影有某种关系的人,然后把那些人还给我。”
我们运行这个,如果我们折叠这个,我们可以放大,我们可以看到我们有 Lily Wachowski,Lana Wachowski,Hugo Weaving,Amil Aphram,如果你对 Matrix 有任何了解的话,他不是 Matrix 中的人,因为他是 Neo4j 的创造者,所以他把自己作为一个角色添加到 Matrix 中,当你导入时。但这只是你所需要的,就像导入它一样。你写一些 SQL 或一些查询的东西或一些 cipher 的东西。你运行它,或者你运行工具,然后一旦你有了它,你就可以开始玩数据了。你开始查询。嗯,实际上,我,是的,我知道我很宅。但实际上,这是我很久以来第一次开始一项技术,我最终只是坐在笔记本电脑前写一些愚蠢的查询。我想知道我能不能做到。我想知道我能不能沿着图走,弄清楚这些是如何连接的。Lana Wachowski 和 Ed Harris 之间的最短路径是什么,等等。然后突然你有一个小数据集,然后突然用一个小数据集做这些事情很有趣,因为这很酷。
所以,我刚才展示的 cipher 的一部分,它创建了一堆节点。然而,它没有使用 `create` 关键字,我将解释原因。但这是默认创建节点的方式。你进去说 `create ()`,我想创建一个节点。它应该有一个 person 标签,在这种情况下,这些是我想要设置的属性,这基本上就是我的节点的定义。当你运行它时,它会将其添加到数据库中。现在,这里一个烦人的小事情是,它总是创建一个新节点,除非数据库中有一个约束,说任何,而电影数据库中确实有一个约束,说名字必须是唯一的,然后这就会失败。但如果它没有那个约束,它就会不断地添加更多,即使数据库中已经有一个叫做 Charlie Sheen 的 person。
所以,`create` 不是最好的,因为它总是会创建一个新的。这可能是你想要的,但我发现还有另一种更好的方法。你可以用 `create` 创建多个节点。你只需要做一个节点,然后逗号,然后另一个节点,你就好了。嗯,你可以创建带有多个标签的节点,并且你可以添加属性。所以,语法上总是相同的。没有,无论是创建还是匹配还是合并,语法都是一样的。这就是我想处理的东西的样子。嗯,它拥有你从查询语言中期望的所有东西,比如“按名字排序”和“跳过”和“限制”,所以你只得到两个行,它跳过了前五个。顺便说一句,这听起来是一种非常有趣的页面分页方式。但有点危险,因为 `skip` 和 `limit` 不适用于你选择的节点。所以,当你执行这个查询时,它会起作用,因为只有,它将返回每人一行。但如果你连接了所有电影,它将作为每个人的每一部电影的每一行出现。所以,如果你有一个人有四部电影,它就变成四行。所以,当你做 `skip` 和 `limit` 时,它看的是行而不是初始节点。所以,它实际上并没有说,“我想基于第一个节点进行分页。”它说,“我想基于行进行分页”,这可能会很复杂。重写它以正确获取它相当容易,但请记住,不要这样做,因为它会咬你。
嗯,更新。再次,你使用你的 `match`。这是我想找到的节点。然后你做 `set`。`set n.birthYear = ...` `set n.hairColor = ...` `set n.birthYear = null`。如果你这样做 `null`,顺便说一句,属性就会消失。所以,它根本不可用。它从对象中消失了。所以,属性不存在。它不会变成一个值为 null 的属性。你也可以使用 `remove`,如果你想更明确的话,但它实际上和设置为 null 一样。嗯,还有设置标签。再次,相同的 `match`。然后你做 `set`,然后你使用冒号,你想要的标签。如果你想删除它,你这样做 `n: <label_name>` 或者冒号和你的标签名,你就好了。再次,相同的语法。
嗯,更新有点意思。嗯,这里有一个组合。所以,你匹配这个 person。所以,你得到数据库,但然后你可以做,而不是做多个 `set`,你实际上可以创建一个新的节点,下面是你想要它看起来的样子。然后你做所谓的 `merge`,它将把这个东西合并到上面。所以,如果 person 上已经有一个出生年份,它将被覆盖。如果它不存在,它将被添加。所以,这是一种在不连续设置的情况下进行多次更新的好方法。
而 `merge` 我喜欢,因为它也有 `on create` 和 `on match` 的能力。所以,在这种情况下,它总是会这样做。但如果你做 `merge on create` 并使用这个语法,你可以说,“嘿,如果你在数据库中没有找到它,我想做这个。”如果你找到了它,我想做那个。”这意味着更新修改字段和创建字段非常方便,因为你可以在这里设置创建日期,在那里设置更新日期,但它仍然是同一个查询。所以,你不需要去,“它是更新还是什么?”只需要一个查询就可以解决。
所以,那是节点。嗯,但如果没有关系或路径穿过你的系统,节点就没什么用处了。所以,这就是你用那个新的其他语法来定义路径的地方,它至少是一个节点、一个关系和一个节点。但路径也可以是一个节点,以及任意数量的关系和节点,直到最终节点。所以,每条路径总是以节点开始和结束,但如果你愿意,中间可以有无限数量的节点。
嗯,查询它。我之前展示过,你添加那个小箭头的东西。现在重要的是要注意,它是 `-->` 或 `->`。原因是,当你想要查询特定内容时,你添加小括号。再次,如果你看 ASCII 部分,小括号看起来就像你放在小箭头顶部的标签,对吧?告诉你它是什么。所以,要匹配任何出演了电影《黑客帝国》的 person,你写,“嘿,给我 person,它有一个叫做 `acted in` 的关系,指向一个 movie,并且 movie 的标题是 `The Matrix`。”这给了我 Matrix 中的所有人。
你也可以把它反过来,如果你想搜索。这和之前的查询完全一样。这两者之间的唯一区别是,我想告诉你,你有关系的方向。每个关系总是定向的。如果你想有一个双向关系,你需要设置两个关系。所以,你让它们都朝两个方向都走。但这也意味着,如果你让它们朝两个方向都走,然后你用那种语法去搜索,你说,“嘿,我想要一个关系,但我不关心方向,”然后你就会得到这两种关系。所以,你可以添加箭头来定义方向,或者你可以说,“嘿,我不在乎方向,给我所有东西。”所以,这将获取任何 person,它与任何 movie 之间有任何关系。所以,在这种情况下,它会给我任何既出演过又导演过电影的人,因为我不在乎方向。
现在,在这里,我用 `p` 和 `m` 作为不同事物的变量,然后我返回它们。你也可以说 `p` 等于整个东西。在这种情况下,`p` 是愚蠢的,因为它已经被使用了。在这种情况下,`p` 变成了一个路径。所以,当你做 `return p` 时,它实际上返回的是整个路径,而不仅仅是实例对象,它说,“这里是 person,这里是 movie。”这将给我 person、关系和 movie。所以,我可以根据需要遍历它。这非常非常强大。然后你可以把这个东西拿过来,加上它,说,“嘿,我不在乎方向,但我想获取任何出演过或被导演过的人,以及 person 和 movie 之间的关系。”这将给我完整的路径。然后你可以匹配更多的关系,你会得到这样的查询,它非常易读,对吧?它实际上非常易读,当你把它分解时。我们有我们熟悉的 `match`,获取任何叫做 Charlie Sheen 的 person。我想看看 Charlie Sheen 出演了什么,或者他出演了什么电影。然后我想获取那部电影,然后我想沿着一个反向关系去获取任何导演了他出演的电影的人。然后我想返回电影标题和导演名字。这样我就可以很容易地获得 Charlie Sheen 参与过的所有导演和电影。嗯,当你把它画出来时,它就变成了那样。所以,这个东西,它在 PowerPoint 幻灯片上很难读,我不得不换行。但如果你只看它那个 ASCII 的样子,它就有点道理,对吧?
创建关系。再次,你可以做你的 `create`。所以,你可以做 `create`。这是我的节点。这是我想要的关系。这是节点。我不建议这样做,因为是的,它创建了一个节点。它查看关系,然后创建一个 movie。现在,它实际上创建了所有这些东西。所以,如果你运行那个命令,它就会创建一个全新的节点和关系集。所以,如果你需要设置几个这样的关系,你就会得到多个 Charlie Sheen 或者其他什么,因为它为每个都创建一个实例。
相反,你应该做的是,“嘿,匹配那个东西。”所以,你在系统中找到 Charlie Sheen,然后找到你想要的电影,然后你去 `create`,然后它就知道节点了,然后它就创建了它们之间的关系。但再次,它总是创建。所以,如果你做 `create`,它会添加另一个关系,可能还会添加另一个关系。所以,你想要的是再次 `merge`。`merge` 就像,我几乎从未使用过 `create`。我合并一切,因为它以同样的方式处理更新和创建。所以,这里是你 `merge`,你找到那个节点,找到那个节点,然后我想你把它合并成这个东西。所以,如果它们之间没有 `acted in`,就添加它。如果已经有一个了,那就什么都不做,因为它已经存在了。
那么,我们如何查询路径,或者抱歉,添加和查询路径和关系呢?所以,我将去找出我想去哪里。我将去这里。我们将去 Neo4j。我将首先将我自己添加到数据库中。所以,我将去 `merge`。所以,正如我所说的,我总是 `merge`。我将是一个 person。所以,我有一个 person 标签。我将有一个名字。嗯,下拉的东西还可以,但它们实际上不正确。它们不会总是给你正确的属性。所以,你仍然需要知道你在输入什么,但这没关系。所以,我们输入名字 Chris Clug,就这样。让我们用大写 K。嗯,如果我运行它,它会说创建一个节点,添加一个属性,添加一个标签。然后如果我再运行一次,什么都不会发生,因为它是 `merge`。所以,它只运行一次,对吧?所以,[鼻息声] 这很不错。
如果我想看看它,我只需要说 `match`,我们基本上用同样的东西来匹配它。所以,让我们拿那个。哎呀,那根本不是我想要的。够不到键盘没用。手动打出来。所以,我们将做 `p` person name Chris。那也没出来。嗯,然后返回 `p` 来确认我在这里。如果我们运行它,我就在这里,这里有我的属性。所以,正如预期的那样,它在那里。
现在,我确实忘了设置 born 属性,因为所有 person 或 people 都应该有一个 born。所以,让我们来处理这个。我们将用一个 `merge` 来替换它,然后我将去 `merge` 一个 person,名字是 Chris。然后我们将在这里说 `set p.born =`。现在你会看到我确切的年龄。设置它。运行。设置了一个属性。所以,这看起来不错。为了确认我在这里,我们可以回到我的 `match`。我们可以看到我在这里,并且我现在有一个出生年份,对吧?正如预期的那样。
现在,如果我想把自己添加为 Matrix 的演员,因为我一直想成为 Matrix 中的一员,我们将做 `match`。所以,我将在这里复制匹配。所以,我们将做 `match`。我想找到一个标题为 the matrix 的 movie。然后我们将做另一个 `merge`。在这种情况下,我想 `merge` person `p`。然后我想用一个标签来 `merge` 它,如果我能输入正确的东西,叫做 `acted in`。嗯,`acted in`。在这里。嗯,然后我们想把它 `merge` 到 `m`,那个 movie。我们运行它。它会说创建一个关系。如果我们去,然后做我在这里的同一个查询,找到任何 person,但我们将选择 `acted in`。有很多复杂的字符要在瑞典键盘上写。好了,我们找到 Matrix 中的所有演员,我们试着在这个小分辨率上让它可读。我们应该能看到,这里有我,Chris Clug,还有 Hugo,Lawrence,Kerianne,以及我所有在电影中和我一起演出的朋友。嗯,所以这个关系似乎起作用了。嗯,现在这里有一个东西,实际上我可以给自己一个角色,但让我们忽略它。
有一件事要记住,当你开始研究 Neo4j 时,你会很快获得这些信息:查询性能可能很复杂。所以,做查询比在 SQL 中做查询要奇怪一些,因为即使你可以为你的列添加索引,它也只会使用一个索引。它只会为它找到的第一个节点使用索引。所以,在这种情况下,它很可能……
这样说吧,嘿,你正在寻找一部电影,并且你给这部电影加上了筛选条件。那么我可能会从那个端点开始处理你的查询,因为那很可能是它找到的节点数量最少的地方。然后,一旦它发现没有更多的索引和相关内容了,它就会获取那个节点,然后说,嘿,你能给我所有名为“acted in”的关系,然后我想获取另一端的节点。然后它会去找到所有那些节点,以此类推。所以它基本上是从你的第一个锚点节点开始,对你的整个图进行深度优先遍历,这意味着你必须比平时更仔细地考虑如何编写你的查询。
现在,好的一点是,你可以进入 Neo4j。我将在这里做一个小小的改动,让它稍微不那么高效,以向你展示一些差异。所以,我将移除这里的标签,然后说,嘿,任何标题为“The Matrix”的节点,然后去查找“acted in”以及所有这些。如果我们在这里执行 explain,运行它,实际上,让我们关闭这个。我们现在可以看到,当你执行一个查询时,你会在 SQL 中看到类似的东西,一个查询计划。所以你可以看到它实际上做了什么。它确实说它基本上在这里进行,然后说,嘿,我想对每个节点进行一次完整的节点扫描,然后我将得到 172 行。然后我将去过滤那些节点,这将给我估计的 9 行。然后我将展开所有的关系,再 9 行。然后它将去找到那里的所有节点。然后一旦我到达那个点,我就可以继续生成一个结果并将其返回。你可以在这里获取关于有多少行它预计会出来的以及其他类似信息。
如果我们更改这个查询,然后让它变得更智能一些,然后说,嘿,我们知道这里的东西是一部像那样的电影。然后我们再次运行同样的东西。它现在足够智能,可以去说,嘿,我可以使用一个基于电影名称的唯一查询,我得到一行,然后当我展开“acted in”时,它会变成五行,然后我得到我的演员等等,我就可以获取这些信息,所以现在我知道这是一个好得多的查询。而且,你还可以继续说,嘿,explain 只是一个查询计划,这就是我认为会发生的事情。如果你去执行 profile,它实际上会运行你的查询并返回所有东西。
如果你运行它,你就可以进去,这会很难看清楚,但如果我们放大它,它实际上会进去并准确地告诉你它使用了多少字节的内存,它做了多少次页面缓存命中,估计的行数,以及它访问数据库的次数以及所有这些东西。所以,你现在可以开始调整你的查询了。而且说实话,根据 Neo4j 的说法,他们应该关注调整,或者你应该关注的不仅仅是调整你的查询,而是实际将你的数据库数据存储在你的数据库中,以一种对应你最大的查询批量的方式,使它们变得便宜,然后你可能需要为使用较少的查询做更复杂的事情。所以,根据你查询的方式来查看你的数据存储,而不是根据你的关系型思维如何用外键来做一个表,对吧?一开始这是一个很难弄清楚的事情。我仍然在这方面做一些工作,到目前为止,我们还没有发现我们拥有的东西有什么太大的问题,但它可能会发生。
运行计划很有趣,因为偶尔你会说,“哦,我没想到那个。”然后一个小小的调整就可以产生巨大的差异。嗯,现在让我们再回到这里。删除数据和添加数据一样,非常相似。所以,再一次,你进行匹配。你将你想操作的任何东西放入一个变量,在这种情况下是 P,然后你执行 delete P。就是这样。这将删除带有 person 标签和 Charlie Sheen 名字的节点。嗯,如果存在关系,这实际上会中断。所以,如果存在关系,它将以与 SQL 不允许你删除有外键的东西相同的方式失败。所以,你所做的是,你执行 detach delete,它说,嘿,删除这个节点,以及任何传入或传出的关系,也删除它们。所以,我们可以删除节点而不必担心任何关系,这很好。嗯,也比在 SQL 中容易得多,因为在 SQL 中你必须开始遍历东西,这很烦人。
你也可以做 match n detach delete n,它会遍历你数据库中的每个节点并删除它以及所有到这些节点的关系。所以,这基本上是对你的整个数据库进行 rmrf 操作。它被清空了,消失了,当你运行那个命令时,没有一个警告。在 SQL 中,在大多数情况下,你最多只能一次删除一个表。这会清空你的整个数据库,而且速度很快。当你在开发环境中,事情不太对齐时,这真的很好。你只需要运行它,然后重新导入数据。非常非常顺畅。
删除关系也是同样的事情。你进行你的路径匹配,然后你将你的关系分配给变量,然后你执行 delete R,然后它会删除那个关系。你也可以通过说,嘿,获取 Charlie Sheen 与任何节点之间的任何关系,然后执行 delete R 来删除任何关系,它将删除那个关系。所以,只要你弄清楚如何编写这些基本的筛选器或匹配,你就可以处理所有的创建、删除和更新,因为它们都以同样的方式工作。
所以,移除数据嗯,我将快速地从数据库中移除我和埃米尔。所以,如果我想从数据库中移除我和埃米尔,我会这样写。让我们从 match p person 开始。嗯,我们将直接去,实际上,让我们这样做。然后我们去 acted in,因为我知道我和埃米尔都出演了名为“The Matrix”的电影。这将给我一切。如果我们看一下,然后我们执行 return。所以,这将给我“The Matrix”中的所有人物。我们有我和埃米尔在那里。所以我们进去说,“嘿,我实际上想做一个 where p.name equals clo 或者 p.name equals 实际上只有一个等号字符 C uh a m l a a 像这样。那应该给我一个埃米尔。我们在这里。然后要删除它们,我们基本上只需要,如果我们想首先从数据库中移除它们,或者说,从关系中移除它们,我们可以说,给我关系,然后我们可以执行 delete r。我们运行这个,它会移除两个关系。如果我再次询问人物,我们像这样,那将什么都没有,因为我不再在 Neo4j 中,也不在那部电影中了。但如果我这样做,我们可以看到我们仍然在数据库中。最后,我可以说,如果我想删除它们,我们可以只执行 delete P。
而且,如果我想一开始就删除我们,我可以更容易地去执行 detach delete P,它也会移除关系。但是语法,再说一遍,我喜欢它,因为它是一样的匹配。它是一样的东西。只是将其分配给变量,然后告诉系统你想用那个变量做什么。嗯,我我我只是,我已经删除了。是的,这很好。嗯,现在还有一些事情要讲。我还有大约 10 分钟。这会很紧张。我将稍微加快一点速度来完成所有内容。
遍历图是它变得酷的地方,因为现在我们可以询问多个层级。我们不仅仅是节点关系节点。在这种情况下,我想找到所有曾经和嗯,基努·里维斯合作过的演员。所以,这很不错。我所要做的就是说,这是我想要的匹配。我想获取人物,我想获取他合作过的人物。所以,这是我想要的两个端点。我想要连接它们的方式是“acted in”,并且我想要做两次。所以,基本上,第一次“acted in”将是从基努·里维斯到电影“acted in”,第二次“acted in”将是从那部电影到在那部电影中出演的其他人物,这将给我他所有的联合主演。
一旦你有了那个,你就可以在其中使用 return,使用两种称为 helper 的方法,就像其中的小函数一样,称为 nodes 和 relationships,你可以在其中说,因为在这种情况下,我们将得到整个路径。我不是只要求联合主演。我实际上要求的是整个路径,因为我想获取他们扮演的角色。所以,我们可以说,对于这个路径,去获取所有节点,获取数组中的第一个节点,然后获取名字,那将是演员。然后获取这个路径的关系,然后获取第一个关系以及该关系上的角色,然后将其作为 role 和 that 输出。基本上,它允许我们遍历它,最终说,这将是基努·里维斯,以及他在那部电影中扮演的角色,在那部电影中,他与那个扮演这些角色的演员合作,在一个巨大的查询中,这相当容易阅读,对吧?
但真正酷的是最短路径,因为我希望我有一个更好的数据集。因为你可以去,你像往常一样进行你的路径匹配。所以,这是人物,这是我想匹配的人物。显然,从基努·里维斯到汤姆·汉克斯的最短路径,而且我真的不在乎你使用什么类型的关系,只要存在某种形式的“某人认识某人”的说法。所以,基本上,如果基努·里维斯需要和汤姆·汉克斯交谈,找到直接联系他的最快方式是什么?通过添加加号,我允许尽可能多的关系,或者根据需要,我想要最短的那个。你也可以在那里添加逻辑,好的,我也想给它加权。所以,如果你知道关系有像成本或时间或距离,我就可以去找到那些,但让它基于最短的旅行时间,例如,或者最便宜的机票,或者沿途的任何东西。
当你运行它时,你最终会得到这个,在这种情况下,因为我要求最短的那个。所以,汤姆·汉克斯到那个东西,你到查理·唐,到“魔鬼的代言人”,到基努·里维斯。但如果我们把它变成最短的三个,我得到三个选项,然后它实际上给了我相同的想法。不,在这种情况下,它会是基努·里维斯,《黑客帝国:重装上阵》,雨果·维文,《云图》,汤姆·汉克斯,或者它通过《黑客帝国》到雨果·维文,或者它通过“魔鬼的代言人”和查理·斯特朗。所以,这种任意长的搜索在 SQL 中真的很难做到,但在 Neo4j 或图数据库中却非常非常简单。
所以,这就是我将要看看我是否能写一些代码的地方。我有一个这个小小的应用程序。嗯,我实际上认为它已经运行起来了。它看起来是这样的。所以,你选择你想从谁开始,你想去谁那里,然后你点击提交,它会显示你来回的各种路径。现在只有我,而且只有我编造的一部电影,那是因为我还没有构建它。代码看起来是这样的。所以,我们真正关心的只有 on get 和 on post。在 get 中,我需要去获取数据库中的所有人物。而我们做到这一点的方式是,首先,我们需要进去说,我需要一个 Nougat 包。所以,我们将执行 manage nougat packages。我将安装 Neo4j driver。与 Neo4j 对话时的语法与 SQL 有点不同,但你很快就会习惯它。
一旦我们有了驱动程序,我们就可以说我需要一些配置。我们将去说我需要配置 config 来获取注入。一旦我有了配置,哦,我需要去 app settings 并填充它。我在哪里可以找到数据库?嗯,如果我们回到这里,然后我们看 local instances,这里有一个 connection URI。所以,我把它复制粘贴到这里。我想和哪个数据库对话?它叫做 Neo4j demo。哪个用户?它将是 Neo4j,因为用户是硬编码的。然后这将是我的非常秘密的密码,像这样。所以,现在我在这里有了我的配置。现在要创建驱动程序,那个与数据库对话的 n4j,为什么这个没有弹出,这让我害怕,现在,在那里,我像这样创建一个驱动程序,通过说 graph driver graph database.driverd driver。它将是异步任务。在这里面,我需要说,这是配置,这是 URI,这是用户名和密码来与之对话。这就是我创建驱动程序所需要的一切。
一旦我有了驱动程序,我就可以编写我的查询。所以,我们将执行 var people result。我希望我有一个小东西来做这个,这样我就不必看我输入这个,但让我们试试这个。嗯,await driver doexecutable query。我将在里面写我的查询,然后在我的新行上,我将说,因为我使用的是一个单独的数据库,我实际上需要去说,嘿,有一个 query config,我想对话的数据库的数据库名称将是 config nej database,这看起来是正确的。然后我们去说 execute async,像这样。我想运行的查询将是这样的。所以,我们将稍微移动一下。我们说 match p person。这就是我需要的一切。我需要 person,然后我们执行 return pname as,它需要是 capital n。所以,我将执行 as name,然后 order by P name,像这样。这应该给我所有的人物。
一旦我在这里有了结果,我就可以将我的 people 变成 people result.result.select。然后在我们的 select 里面,我们说对于这些行中的每一个,我想去,我想去说 x. dot。再试一次。X. as OB。为什么东西会乱飞?你能,好的,我们再试一次。As object,然后我可以,或者它有内置的非常简单的映射逻辑,允许我去说,嘿,映射到 to array。为什么这个在抱怨 as 哦,好的,我缺少一个导入。好了。它基本上将其映射到一个名为 person 的小类。而我之所以将其大写 N 是因为它是区分大小写的。一旦我有了这个,它就会获取我所有的朋友并将它们放入我的列表中。
接下来我想做的是 on post,基本上是弄清楚如何,什么是关系?什么是我们可以找到的路径?所以,我将开始说,嗯,我将再次创建一个驱动程序,它将是异步任务。然后在这里,我们去说我们添加我们的查询。我将向你展示查询,但它基本上和我之前做的一样。然后是查询。嗯,我通常喜欢去这里并尝试我的查询。所以,我将去我的查询工具这里,然后我将写一个小的查询。而且不幸的是,它并不小。所以,让我们试试这个,看看我是否能在最后两分钟内输入它。让我们说 shortest。让我们提取五个。然后我们将执行 actually match P equals shortest five。我想从 person 开始,然后让我们试试 for our,在这种情况下,我们将尝试 Tom Hanks。我想通过任何关系,acted in 或 or or directed,然后我想找到另一个人,它将是,在这种情况下,名字是 Kean Reeves。Kean Reeves 像这样。然后我们执行 return pay。什么?哦,谢谢。看那个。注意,我在这里错过了什么?哦,那不应该是,它应该是 start。我想让你跟着你想要的程度。这里是角色。这看起来不错。所以,这个查询看起来是我们想要的。
让我们回到这里。让我们把那个查询粘贴到这里。硬编码 Tom Hanks 和嗯,Kean Reeves 是个坏主意。所以,让我们在这里添加几个变量。我们将说 ROM。我们将把它命名为 two。然后我们需要添加几个参数。所以,我们执行 nope there with parameters。我只是会这样做语法。所以,我们将说 two 将是 two,from 将是 from。所以,to 和 from 只是我从前端发布回来的属性。然后我需要做一点查询匹配的东西来让它工作。所以,我们将做,在 Neo4j 中,这不是很重要。它只需要在那里。它使用这个 p parse path ext 方法,看起来是这样的,所有代码都将提供给你,如果你想看的话,但它基本上遍历路径,弄清楚什么用户,什么电影,什么人物在沿途,并将它们变成我可以很好地渲染到屏幕上的东西。
现在,如果我把它拿出来,然后我点击一些有用的东西,然后我把正确的 PE 东西献给了演示神。我们可以从 Anthony Edwards 开始,我不知道是谁,到 Keanu Moss,我实际上知道是谁,然后我们点击提交,这里是所有你可以找到他们连接在一起的东西。所以,你可以从 Anthony Matthew Edwards 到《壮志凌云》到 Tom Cruise 到《好家伙》到 Jack Nicholson 到《爱是妥协》到 Keanu Reeves 到《黑客帝国》到 Keanu Moss,这几乎不需要任何时间来编写。这里有一个 bug,在你将看到的代码中已经修复了,因为如果你去说 Tom Hanks,然后你说 Ed Harris,我想强调这一点。我知道代码中有一个 bug。你得到 Tom Hanks 到那个东西,你到 Tom Hanks 到《阿波罗 13 号》到 Ed Harris,这有点愚蠢。所以,你实际上需要写一点额外的代码来去说,移除所有有重复相同节点多次的东西。所以,你不想去 Tom Hanks 到 Tom Hanks。你想去 Tom Hanks,《阿波罗 13 号》到 Ed Harris,而你已经有了。所以,那应该消失。但这就是我们使用 C# 与它互动的方式。嗯,它很容易使用。嗯,嗯,非常容易。我实际上认为它非常容易。
与 Entity Framework 提供的事务边界和处理工作单元等所有功能相比,它有点复杂。你必须自己构建那些。它仍然有事务工作,但它非常小。所以,你做一件事,那个命令在一个事务中运行,然后你做另一件事,它在一个事务中运行,但你实际上不能说,我想有一个围绕所有事情的事务。嗯,快速地嗯,一些需要考虑的事情,约束,系统中有约束,所以你可以去说它们必须是唯一的,它们必须存在,它们必须是这种类型,它们是键,但如果你没有运行企业版,你只能使用那个。所以,如果你做社区的东西,就坚持那个。建模问题,你可以考虑你将开始查询什么,你如何尽可能地缩小起点,这样你之后的深度搜索就会尽可能少。嗯,这非常非常重要。你必须考虑你是否想将其作为标签或属性。标签是自动索引的。你也可以为属性添加索引,但标签易于搜索,并且通常适用于类别或类型之类的内容。你还可以考虑标签与关系。你是否真的需要关系,就像你在关系型的东西中一样,你想指向一个标签可能就足够了的东西?对吧?所以,有时标签比关系更好。就像我说的那样,优化你的查询,并使用 profile 和 explain 来查看你的查询性能。
嗯,我有一个小小的东西,我们将跳过,但它基本上是有一个小命令,你可以运行,它获取所有数据并将其转换为我之前展示的节点类型或标签以及它们如何相互连接,当你有大量数据时,这会非常有用。你只需要运行它,它就会说系统是如何连接的。
感谢大家的聆听。抱歉我超时了两分钟。所有代码都可以在那个 bit.ly 链接上找到,无论是二维码还是上面的那个。嗯,我老了,一个中年白人。所以,嗯,我在 X 上,抱歉。我还在 LinkedIn 上,如果你有任何问题,我将在会议的其余时间不时出现。所以,如果你有任何问题,随时可以过来问,我很乐意向你展示并讲一些故事。谢谢。