兜兜零元 发表于 2024-12-20 10:37:32

读图数据库实战笔记08遍历与子图

https://img2024.cnblogs.com/blog/3076680/202412/3076680-20241219234631428-1569840999.png
1. 使用熟路构建遍历

1.1. 为了制止把开发遍历和构建应用程序肴杂

[*]1.1.1. 把遍历的编写和测试与应用程序的开发拆分成了两个独立的操作
[*]1.1.2. 在Java代码之外独立开发遍历,然后把它们加入应用程序中
[*]1.1.3. 现原形况是,大多数开发人员会同时完成两者,不管使用的是哪种数据库引擎
1.2. 开发熟路遍历要识别模式的有关部分,寻找遍历的出发点和终点,识别从出发点到终点遍历所需的一系列顶点和边,最后循序渐进、迭代式地增加操作来组成遍历,并通过测试数据验证每一步的结果
1.3. 好的遍历出发点可以最小化开始顶点,最理想的情况是只有一个顶点
2. 开发遍历的准备工作

2.1. 用例的需求

[*]2.1.1. 为用例开发遍历要从识别回答业务疑问所需的顶点和边开始
2.2. 图数据模型
2.3. 在把业务疑问转换为技能需求与实现时,代词很容易被忽略,这会隐藏额外的、更眇小的需求
2.4. 识别所需的元素

[*]2.4.1. 检视每一个需求,并将其拆分成回答该疑问所需的组件
[*]2.4.2. 识别所需的顶点标签
[*]2.4.2.1. 最好的出发点就是寻找需求中的名词
[*]2.4.2.2. 在数据模型中寻找这些名词对应的顶点标签
[*]2.4.2.3. 定位出发点是为了寻找和疑问有关的部分,从而把遍历收缩到数量最少的开始顶点
[*]2.4.3. 识别所需的边标签
[*]2.4.3.1. 一旦识别了需求中的动词,就可以查找数据模型中相应的边名了,就像找名词那样
2.5. 选择出发点

[*]2.5.1. 选择我们认为最具挑战性的问题,并从它入手
[*]2.5.1.1. 这个方式适合有大量未知因素或大量项目风险的情况
>2.5.1.1.1. 向开发生态系统引入新技术或新流程

[*]2.5.1.2. 这个方式能让我们快速失败,也是需要快速决策时的正确选择
>2.5.1.2.1. 需要决定是否继续

>2.5.1.2.2. 确定某项技术是否是解决某个问题的正确选择

[*]2.5.2. 从最直接或最不复杂的疑问开始,并以此作为之后工作的基石
[*]2.5.2.1. 这条道路倡导代码的渐进式开发,也很好地制止了囫囵吞枣
[*]2.5.2.2. 该方式的意义在于快速获取成功,大概在处理更复杂的问题之前,从更小、更简单的问题中获得成就感
[*]2.5.2.3. 从最不复杂的疑问开始,我们就能在解决更复杂的问题之前从更小、更简单的问题那边获得成功
2.6. 准备测试数据

[*]2.6.1. 加载测试数据
[*]2.6.2. 在对数据有错误假设的其他情景中,增加样本数据大概是最佳方式
[*]2.6.3. 在排查此类错误的时间,你手上还有其他资源
[*]2.6.3.1. 和同事讨论问题能帮助你获得解决方案
[*]2.6.3.2. 另一种可行的方式是尝试以更受控的方式复制相干条件,也许是使用更小的数据集
[*]2.6.4. 采用一步接一步的系统性方式构建遍历可以使遇到错误时的排查变得更容易
3. 编写第一个遍历

3.1. 设计遍历

[*]3.1.1. 布丁好欠好,吃过才知道
3.2. 开发遍历代码

[*]3.2.1. 在Gremlin Server里,日期是以天下协调时(Coordinated Universal Time,UTC)的格式生存的
[*]3.2.1.1. 为了显示,Gremlin Console会自动将其转换成本地时区的日期
[*]3.2.2. 通过ID扩展遍历
[*]3.2.3. 开发熟路遍历所需的功夫确实比开发交际网络需要的多,但最困难的任务已经完成了
[*]3.2.4. mean():聚合一组值来盘算均匀值,常用与group().by().by()操作搭配使用
[*]3.2.5. has()操作是首要的筛选操作,也是基于属性实现筛选逻辑的首选
[*]3.2.6. where()操作通常用于其他情况的筛选——基于比简单属性匹配更复杂的逻辑组合的筛选
[*]3.2.7. identity():获取进入该操作的元素并原封不动地返回
[*]3.2.8. optional(traversal):尝试遍历,如果返回结果,则发出结果;否则,发出传入元素(与identity()操作一样)​
[*]3.2.9. lues标识和values()操作是不一样的
[*]3.2.9.1. values标识指向键-值对的值部分
[*]3.2.9.2. values()指定从元素中返回的属性
3.3. 对遍历进行分组和排序会创建键-值对形式的结果

[*]3.3.1. 对键-值对的进一步处剖析采用select()操作的一个特殊重载,分别对键-值对中键的部分和值的部分进行处理
3.4. 在遍历过程中越早进行筛选,意味着在图中移动的遍历器越少,因此要做的总体工作也越少
4. 分页和图数据库

4.1. offset(偏移值)​

[*]4.1.1. 要跳过的纪录数量
[*]4.1.2. 在数据集的出发点,offset =0
[*]4.1.3. 偏移值是分页大小的倍数
[*]4.1.3.1. 如果分页大小是10,偏移值则大概是0、10、20、30等
4.2. limit(限制值)

[*]4.2.1. 分页大小或要返回项的最大数量
[*]4.2.2. 限制值是要返回项的最大数量,是因为结果集并不总是分页大小
[*]4.2.2.1. 最后一页所含的项比分页大小要少
4.3. range(startNumber, endNumber)

[*]4.3.1. 穿过各个对象,从startNumber开始(包含该索引位置的对象)​,直到endNumber(不包含该索引位置的对象)​
[*]4.3.2. startNumber是包含在返回结果中的
[*]4.3.2.1. startNumber和offset一样
[*]4.3.3. endNumber被清除在返回结果以外
[*]4.3.3.1. endNumber则不是关系数据库中使用的limit,而是startNumber +limit
[*]4.3.3.2. 分页功能要以offset和limit作为常规输入,盘算endNumber
[*]4.3.4. 调用range()前为输入排序的重要性
[*]4.3.4.1. 数据库引擎基于其内部逻辑决定结果的次序
[*]4.3.4.2. 要给用户提供一致的体验,就必须在调用range()操作前进行排序
[*]4.3.5. 排序是昂贵的操作
[*]4.3.5.1. 对结果进行排序在任何数据库中都是昂贵的操作,特别是对于大型数据集来说
[*]4.3.5.2. 键-值对很容易使用,条件是能以它们的值来排序
4.4. 在关系数据库中处理分页的通用模式和在图数据库里是一样的

[*]4.4.1. 获取遍历的结果
[*]4.4.2. 找到offset索引指定的纪录
[*]4.4.3. 返回结果的limit数
[*]4.4.4. 根据新的偏移值offset + limit重复以上过程
4.5. 方式1是一直运行遍历,递增offset,直到它返回空的结果集为止

[*]4.5.1. 适应的场景是:预期的结果数量很大,而且不需要知道总数;大概想制止提前为所有结果计数的开销
4.6. 方式2是预设大概的结果总数,并把它作为offset + limit值的上限

[*]4.6.1. 对于应用程序需要知道显示结果总数的场景特别有用
4.7. 在图遍历中对结果进行分页需要以排序后的结果集作为输入,并运用限制值和偏移值指定期望的结果子集
5. 五个通用操作

5.1. general step​
5.2. map、flatMap、filter、branch、sideEffect

[*]5.2.1. 这五个通用操作是编程的焦点概念
5.3. 所有的Gremlin操作,除了调整或配置其他操作的操作之外,本质上都是这五个通用操作之一的优化版本
6. 子图

6.1. 个性化是基于数据中的毗连关系筛选数据以提供最相干内容的过程

[*]6.1.1. 只专注于数据的一个子集​,而忽略另一个子集​
[*]6.1.2. 子图自然适合个性化问题
6.2. 因为只就图中明确定义的部分数据提出疑问,所以我们只想处理这个数据子集

[*]6.2.1. 做到这一点的最有效方法是从全局图中提取该数据子集
[*]6.2.2. 这是一个常见的操作,该数据子集称为子图
[*]6.2.3. 就是顶点和边的子集,通常根据某种规则或对业务范畴的理解而精密相连
6.3. 子图是图数据的子集,包含用来表现图的顶点和边

[*]6.3.1. 子图本身就是图
[*]6.3.2. 意味着我们可以在子图上运行遍历,但是因为子图被限制在一小部分顶点和边上,所以只需要更少的内存和盘算能力
7. 使用子图

7.1. 并不是所有的图数据库产品都有显式的子图支持
7.2. 子图也是图,只是其中的所有顶点和边都是一个更大的图的子集

[*]7.2.1. 子图本身就是一张图的究竟是子图如此有用的原因之一:它们的工作原理与更大的图一样,但内存占用更少
[*]7.2.2. 子图是以图的形式返回的,所以一旦为子图创建了图遍历源,就可以遍历这些子图并执行你学到的所有操作
7.3. 提取子图

[*]7.3.1. 按顶点归纳子图是通过一组顶点及其之间的边来定义的
[*]7.3.1.1. 按顶点归纳子图包括顶点之间的所有边
[*]7.3.2. 按边归纳子图是通过一组边及其相邻顶点来定义的
[*]7.3.2.1. 按边归纳子图只包括那些被定义的边
[*]7.3.2.2. 使用边来定义范围似乎有违直觉
>7.3.2.2.1. 从历史上看,我们在考虑数据时总是抱着一种实体第一(甚至是实体唯一)的思维方式

[*]7.3.2.3. 图的实体关系答应我们使用边作为“一等公民”来定义子图的限度
[*]7.3.2.4. Gremlin Server的TinkerPop实现支持按边归纳子图,因此按边归纳子图将是个性化用例的重点
[*]7.3.3. 两种方法的结果并非总是不同
[*]7.3.3.1. 子图的组成取决于你使用的方法以及在选择过程中使用的规则
[*]7.3.4. subgraph(sideEffectKey):在一组较大的图数据中定义一个按边归纳子图
[*]7.3.4.1. sideEffectKey是对副作用完整结果的引用
[*]7.3.4.2. 副作用是我们改变状态的方式
[*]7.3.4.3. subgraph()操作的重要作用是返回作为其输入的边
[*]7.3.4.4. 该操作的副作用部分将这些相同的边及其相邻顶点添加到了由标签标识的内部集合中
[*]7.3.4.5. TinkerPop的subgraph()操作有一个关键的限制:Gremlin语言变体(GLV)不支持它
>7.3.4.5.1. GLV没有包括局部图的概念,这意味着我们不能返回子图,然后将其用于进一步的遍历

>7.3.4.5.2. GLV不支持子图,因此必须使用脚本提交方法来参数化并拼接字符串以编写遍历

[*]7.3.4.6. subgraph变量只存在于会话中的服务器上
[*]7.3.5. cap(sideEffectKey):向上迭代遍历到自身,并发出sideEffectKey引用的副作用结果
7.4. 遍历子图

[*]7.4.1. Graph是一个数据存储
[*]7.4.1.1. 只是存放数据的地方,除了最简单的查找操作以外,没有访问数据的其他能力
[*]7.4.2. GraphTraversalSource是编写所有遍历的底子(遍历中的g)​
[*]7.4.2.1. 没有GraphTraversalSource的图对象就相称于没有任何范例文件管理器的文件系统及其文件
[*]7.4.2.2. 没有任何范例的工具来导航文件系统、读取文件及其属性大概移动文件
>7.4.2.2.1. 在使用子图之前,需要获得遍历源7.5. 将子图用于串行隔离

[*]7.5.1. 可以将其视为使用可序列化隔离模式与图数据交互的方式
[*]7.5.2. 子图是在图数据库中创建可序列化隔离的一种无奈方式
[*]7.5.3. 子图是没有磁盘缓存功能的内存结构,因此创建整个原始图的子图大概会造成内存压力,甚至会引发内存不足错误
[*]7.5.4. 根据可串行隔离的定义,子图中发生的任何变化都不会反映在原始图中,反之亦然
[*]7.5.4.1. 要依赖应用程序开发人员来协调两者之间的变化
[*]7.5.5. 子图可以被复用甚至修改,但所做的任何更改都是与原始图隔离的
[*]7.5.5.1. 意味着任何更改都不会传回原始图数据
7.6. 遍历末尾还包含了文本; null

[*]7.6.1. 分号(;)用于结束第一个语句,即子图变量的赋值
[*]7.6.2. null用于将整个操作返回给客户端
8. 反转遍历方向

8.1. 在大多数关系数据库建模中,特别是使用第三范式时,外键被设计为只在一个方向上使用

[*]8.1.1. 如果要支持相反方向的毗连,通常代价很高
8.2. 对于大多数图数据库来说,支持相反方向的毗连不会产生额外的性能成本
8.3. 在关系数据库天下中,简单地改变关系的方向险些是闻所未闻的,但对于图数据库来说,这险些是一个微不足道的变化

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 读图数据库实战笔记08遍历与子图