相关文章推荐
乖乖的电池  ·  jQuery is out of date ...·  1 年前    · 
睡不着的抽屉  ·  VBScript - 找到 Excel ...·  1 年前    · 

1.Neo4j 概述

Neo4j是一个本机图形数据库,它使用属性图模型来建模数据,并使用Cypher查询语言与数据库进行交互。Neo4j是一个具有完全ACID保证的事务性数据库,也可以用于图形分析。Neo4j等图数据库针对处理高度连接的数据和遍历图的查询进行了优化(想象一下关系数据库中的多个连接),因此是GraphQL api的完美后端,它描述连接的数据,并经常导致复杂的嵌套查询。开始阅读前需要确保 已经下载了 Neo4j桌面版

接下来将学习如何在Neo4j中 创建 查询 数据

2.Neo4j的图数据模型

其他使用表或文档建模数据的数据库不同,图数据库(如Neo4j)建模、存储并允许用户以图的形式查询数据。在图中,节点是实体和连接它们的关系。在关系数据库中,我们用外键和连接表表示关系。在文档数据库中,我们使用id引用其他实体,甚至在单个文档中对其他实体进行反规范化和嵌入。

使用数据库时的第一步是确定将使用的数据模型。我们创建出白板模型

白板模型:我们将使用术语“白板模型”来指在第一次对一个域进行推理时通常创建的图,它通常是绘制在白板上的实体及其关系的图。

我们如何将构想的模型从“白板”模型转换为数据库使用的物理数据模型?在其他系统中,这可能涉及创建ER图或定义数据库的模式。Neo4j被称为“可选的schema”。虽然我们可以创建数据库约束来强制数据完整性,例如属性惟一性,但我们也可以使用没有这些约束或模式的Neo4j。但是,第一步是使用Property Graph数据模型定义一个模型,这是Neo4j和其他图形数据库使用的模型。让我们将简单的白板模型转换成图

2.1 属性图模型

属性图模型由以下几部分组成:

  • 节点标签:节点是数据模型中的实体或对象。节点可以有一个或多个标签来描述节点是如何分组的(想想类型或类)。
  • 关系:关系连接两个节点,并且具有单一类型和方向。
  • 属性:存储在任意节点或关系上的任意键-值对属性。
  • 节点表示白板模型中的对象。每个节点可以有一个或多个标签,这是对节点进行分组的一种方式。向白板模型添加节点标签(图3.3)通常是一个简单的过程,因为在白板过程中已经定义了分组。在这里,我们将用于引用节点的描述符规范化为节点标签(稍后我们将添加节点别名和多个标签,因此我们使用冒号作为分隔符来表示标签)。

    节点可以有多个标签,并允许我们表示类型层次结构、不同上下文中的角色。

    一旦确定了节点标签,下一步就是确定数据模型中的关系。关系只有一个类型和方向,但是可以在任意一个方向上查询。

    虽然每个关系都有一个方向,但我们可以在查询时不指定方向,将关系视为双向。

    好的关系命名能够帮助理解整个图模型,例如“用户写评论”,“评论点评商业”,查看更多 命名规范和实践

    属性是存储在节点和关系上的任意键值对。这些是数据模型中实体的属性或字段。这里,我们将userId和name存储为User节点上的字符串属性,以及Review和Business节点上的其他相关属性。

    2.2 数据库约束和索引

    既然已经定义了数据模型,那么如何在数据库中使用它呢?正如前面提到的,与其他需要我们在插入数据之前定义完整模式的数据库不同,Neo4j的schema是可变的,不需要使用预定义的模式。我们可以定义数据库约束,以确保数据遵守域的规则。我们可以创建唯一性约束,以确保属性值在节点标签之间是唯一的(例如,确保没有两个用户具有重复的id属性值)、属性存在性约束(确保在创建或修改节点或关系时存在一组属性),以及类似于复合键的节点键约束。

    数据库约束由索引支持,索引也可以单独创建。在图形数据库中,索引用于查找遍历的起点,而不是遍历整个图。

    3.数据建模方面的考虑

    图数据建模可以是一个迭代过程。一般来说,这是以下的过程:

  • 实体是什么?他们是如何分组的?这些作为节点和节点标签
  • 这些实体是如何联系在一起的? 这些作为关系。
  • 节点和关系的属性是什么?这些作为属性。
  • 然而,这种通用方法通常没有涵盖一些细微差别。在接下来的章节中,我们将讨论几个常见的图数据建模问题

    3.1 Node vs Property

    有时很难确定一个值应该建模为节点还是作为节点上的属性。这里要遵循的一个很好的指导原则是问自己这样一个问题:“如果它是一个节点,通过遍历它,我能发现一些有用的东西吗?”如果答案是肯定的,那么应该将其建模为节点;如果不是,那么将其视为一个属性。例如,考虑是否要将业务类别添加到模型中。如果将类别建模为节点,那么查找具有重叠类别的业务可能会很有用,并且更容易发现。

    3.2 Node vs Relationship

    在这种情况下,我们有一段数据似乎连接了两个节点(例如用户编写的业务评论),我们应该将该数据建模为节点还是关系? 乍一看,我们似乎想要创建一个连接用户和业务的 点评 关系,存储评论信息,例如星号和文本作为关系属性。但是,我们可能希望从评论中提取数据,比如通过一些自然语言处理技术提到的关键词,并将提取的数据与评论连接起来。或者也许我们想要使用评论节点作为遍历查询的起点?这两种情况就应该定义为节点而不是边。

    3.3 索引

    索引在图数据库中用于查找遍历的起点,而不是在实际遍历期间使用。这是Neo4j等图数据库的一个重要性能特征,即无索引邻接。仅为用于查找遍历起始点的属性(如用户名或业务id)创建索引。

    3.4 选择关系的方向

    属性图模型中的所有关系都只有一个方向,但可以在任意一个方向上查询,也可以在查询时不考虑方向。不需要创建重复的关系来建模双向性。通常,应该选择允许对数据模型进行一致读取的关系方向。

    4. Neo4j Desktop

    现在,我们已经理解了属性图数据模型,并定义了将用于业务审查应用程序的模型的简单版本,让我们创建一个Neo4j数据库并开始执行Cypher查询。为此,我们将使用Neo4j Desktop,它是Neo4j的任务控制中心。在Neo4j Desktop中,我们可以创建Neo4j的项目和实例。我们可以在Neo4j Desktop中启动、停止和配置Neo4j数据库实例,还可以安装可选的数据库插件,如GraphQL Algorithms和APOC(neo4j的预处理标准库)

    5. Cypher 的基本用法

    Cypher是一种声明式图查询语言,其特性可能与SQL类似。事实上,我们可以将Cypher理解为“图的SQL”。Cypher使用模式匹配,使用类似ascii符号来描述图形模式。我们将研究用于创建和查询数据的基本Cypher功能,包括使用判断和聚合。 r.neo4j.com/refcard 查看更多的语法细节

    5.1 模式匹配

    作为一种声明式图查询语言,模式匹配是Cypher中用于创建和查询数据的基本工具。我们不是告诉数据库确切的操作,而是希望它采取(命令式方法);使用Cypher,我们描述我们正在寻找或希望创建的模式,数据库以最有效的方式找出满足语句的一系列操作。使用类似ascii的表示法(也称为主题)来描述图形模式是这种声明性功能的核心。

    节点在圆括号()中定义。还可以使用冒号作为分隔符指定节点标签,例如(:User)。

    关系在方括号[]中定义。我们还可以指定类型和方向:(:Review)-[:REVIEWS]->(:Business)

    5.2 属性

    属性用大括号“{}”内用逗号分隔的name: value对指定

    图元素可以绑定到别名,稍后可以在查询中引用:(r:Review)-[a:REVIEWS]->(b:Business). r,a,b就是对应的别名

    5.3 CREATE

    创建node的基本语法为

    CREATE(B:Business{name:"Bob's Pizza"})
    

    打开你的neo4j执行这些命令查看效果

    这个命令与上面的是等价的

    CREATE (b:Business)
    SET b.name = "Bob's Pizza"
    

    通过return 可视化数据

    CREATE (b:Business)
    SET b.name = "Bob's Pizza"
    RETURN b
    

    你能看到这样的结果

    还可以使用更复杂的CREATE命令

    CREATE (b:Business {name: "Bob's Pizza"})<-[:REVIEWS]-(r:Review {stars: 4, text: "Great pizza"})
    RETURN b, r
    
    CREATE p=(b:Business {name: "Bob's Pizza"})<-[:REVIEWS]-(r:Review {stars: 4,
         text: "Great pizza"})<-[:WROTE]-(u:User {name: "Willie"})
    RETURN p
    

    到目前为止,我们只返回在每个Cypher语句中创建的数据。我们如何查询和可视化数据库中的其他数据?为此,我们使用MATCH关键字。让我们匹配数据库中的所有节点并返回它们:

    MATCH (a) RETURN a
    

    你可能会认为你讲得到这样的结果

    可是实际上显示的结果会是这样(如果你执行了上面所有的命令)

    我们创建了很多重复的节点

    使用DETACH删掉所有的节点吧!

    MATCH (a) DETACH DELETE a
    

    避免出现这种情况我们就需要使用到MERGE命令

    5.4 MERGE

    为了避免创建副本,我们可以使用MERGE命令。MERGE的作用是破坏:仅在数据库中不存在模式中指定的数据时创建该数据。在使用MERGE时,最好在标识唯一性的属性(通常是id字段)上创建唯一性约束。通过创建惟一约束,这也将在数据库中创建一个索引。

    将命令替换为如下

    MERGE (b:Business {name: "Bob's Pizza"})
    MERGE (r:Review {stars: 4, text: "Great pizza!"})
    MERGE (u:User {name: "Willie"})
    MERGE (b)<-[:REVIEWS]-(r)<-[:WROTE]-(u)
    RETURN *
    

    就得到了我们想要的结果

    这个Cypher语句的结果看起来与使用CREATE语句的版本相同;无论如何,有一个重要的区别:这个查询现在是idempotent。无论我们运行查询多少次,我们都不会创建重复的节点,因为我们使用MERGE而不是CREATE

    Neo4j中的索引:理解如何在Neo4j这样的图形数据库中使用索引是很重要的。我们之前说过,Neo4j有一个称为无索引邻接的属性,这意味着从一个节点遍历到任何其他连接的节点不需要索引查找。Neo4j中是如何使用索引的?索引只用于寻找遍历的起点,不像关系数据库使用索引来计算集(表)重叠,图数据库只是在文件存储中计算偏移量,主要是追踪指针,我们知道计算机擅长于快速完成这一点。

    5.5 使用Cypher定义数据库约束

    在本章前面建立数据模型时,我们提到了数据库约束以及它们如何(可选地)与Neo4j中定义的schema相关。这里,我们展示了用于创建与数据模型相关的数据库约束的Cypher语法。 唯一性约束用于断言数据库不会包含多个具有特定标签和属性值的节点。在本例中,我们创建了惟一约束,确保标记为Business的节点上的businessessId属性的值是惟一的。

    CREATE CONSTRAINT ON (b:Business) ASSERT b.businessId IS UNIQUE;
    

    属性存在约束确保具有某个标签的所有节点都具有某个属性。在这里,我们创建了一个约束,以确保所有Business节点都有一个name属性,但是该属性的值在所有Business节点上不需要唯一。

    CREATE CONSTRAINT ON (b:Business) ASSERT exists(b.name);
    

    节点键约束确保具有某个标签的所有节点都具有一组已定义的属性,这些属性的组合值是唯一的,并且该集合中的所有属性都存在于节点上。这里我们创建一个节点键约束,确保firstNamelastName 组合对于Person节点是唯一的,并且每个Person节点都有firstNamelastName 属性

    CREATE CONSTRAINT ON (p:Person) ASSERT (p.firstName, p.lastName) IS NODE KEY;
    

    5.6 MATCH

    现在我们已经在图中创建了数据,我们可以开始编写查询来满足应用程序的几个业务需求。 MATCH子句与CREATE类似,它采用一个图模式;但是,我们也可以使用WHERE子句来指定要在模式中应用的判断。

    MATCH (u:User)
    RETURN u
    

    当然,我们可以在MATCH子句中使用更复杂的图模式:

    MATCH (u:User)-[:WROTE]->(r:Review)-[:REVIEWS]->(b:Business)
    RETURN u, r, b
    

    前面的查询匹配对任何企业写过评论的所有用户。如果我们只是想查询某个企业的评论呢?在这种情况下,我们需要在查询中引入判断。注意这里的关系箭头是如何颠倒的

    WHERE

    WHERE子句可用于向MATCH语句添加谓词。要搜索名为“Bob’s Pizza”的企业:

    MATCH (b:Business)
    WHERE b.name = "Bob's Pizza"
    RETURN b
    

    对于相等比较,可以使用等价的简写符号:

    MATCH (b:Business {name: "Bob's Pizza"})
    RETURN b
    

    5.7 Aggregations

    通常,我们希望跨一组结果计算一个聚合。例如,我们可能想要计算Bob 's Pizza所有评论的平均评分。为此,我们使用avg聚合函数:

    MATCH (b:Business {name: "Bob's Pizza"})<-[:REVIEWS]-(r:Review)
    RETURN avg(r.stars)
    

    现在,在Neo4j Browser中,因为我们返回的不是图形数据,而是表格数据,而不是图形可视化,我们呈现的是一个显示查询结果的表格:

    对于Cypher,当返回聚合函数的结果和非聚合结果时,会有一个隐式的group by。例如,计算每个企业的平均排名:

    MATCH (b:Business)<-[:REVIEWS]-(r:Review)
    RETURN b.name, avg(r.stars)
    

    6.使用程序驱动

    到目前为止,我们一直使用Neo4j Browser来执行我们的Cypher查询,这通常用于专门的分析或原型设计;但是,我们通常希望创建与数据库交互的应用程序。为此,我们使用Neo4j客户端驱动程序。这些客户端驱动程序可用于许多语言,如JavaScript、Java、Python、. net和Go,并允许开发人员使用该语言惯用的一致API对Neo4j实例执行Cypher查询。在第一章中,我们看到了一个使用Neo4j JavaScript驱动程序执行Cypher查询并处理结果的示例。Neo4j客户端驱动程序还提供了一个基本的构建模块,用于构建与Neo4j特定于工作的集成框架,例如Neo4j -graphql.js,我们将在以后的章节中探讨。有关Neo4j客户端驱动程序的更多信息,请参阅驱动程序和语言指南:neo4j.com/developer/l….

    分类:
    后端
    标签: