图数据库 | 24、如何进行正确性验证?

图数据库计算和查询结果的正确性,这个重要性当然是不言而喻的!

老夫之前也写文章讲过,今天再手书一篇,旨在向大家系统地介绍一下图数据库查询与计算到底如何进行正确性验证!!!

图数据库中的操作分为以下2类:

· 面向元数据的操作:即面向顶点、边或它们之上的属性字段的操作,具体可以分为增、删、改、查4类。

·  面向高维数据的操作:这也是本书关注的重点,例如面向全图或子图数据的查询结果返回多个顶点、边组合而成的高维数据结构,可能是多顶点的集合、点边构成的路径、子图(子网)甚至是全图遍历结果。

面向高维数据的查询有以下3类:

· K邻查询:即返回某顶点的全部K度(跳)邻居顶点集合。K邻查询可以有很多变种,包括按照某个特定方向、点边属性字段进行过滤。还有全图K邻查询,也被视作一种高计算复杂度的图算法。

· 路径查询:常见的有最短路径、模板路径、环路路径、组网查询、自动展开查询等。

· 图算法:图算法在本质上是面向元数据、K邻、路径等查询方式的组合。

无论以何种方式进行高维查询,图数据库中的操作无外乎遵循如下3种遍历模式:

· 广度优先:如K邻查询、最短路径等。·深度优先:如环路查询、组网查询、模板路径查询、图嵌入随机游走等。

· 深度优先与广度优先兼而有之:以最短路径方式遍历的模板路径或组网查询、带方向或条件过滤的模板K邻查询、定制化的图算法等。

注意:
面向元数据的图数据库操作和关系型数据库有相似的地方,正确性验证方法在此就不再赘述了。本文老夫着重介绍图数据库特有的高维数据查询正确性验证。

我们以图数据库基准性能评测中常用的Twitter-2010数据集为例来说明如何进行图查询的正确性验证。

Twitter数据集(其中顶点数量为4200万,边数量为14.7亿,原始数据占24.6GB)的下载链接为:http://an.kaist.ac.kr/traces/WWW2010.html。

在开始验证前,以Twitter数据集为例,了解一下图数据模型的特征。

(1)有向图

由顶点(人)和边(关注关系)组成,其中关注关系为有向边。

Twitter源数据中有两列,对应每一行是由Tab键分隔的两个数字,例如12与13,代表两个用户的ID,表示两者间的有向的关注关系:12关注13。在图数据建模中应该构建为两条边,一条表示从12到13的正向边,另一条则是从13到12的反向边,缺一不可。后面的验证细节中很多正确性的问题都与此相关——没有构建反向边,查询结果不可避免会出错。

(2)简单图与多边图

如果一对顶点间存在超过(含)2条边,则其为多边图,否则为简单图。

在简单图中任意顶点间最多只有1条边,因此简单图也称作“单边图”​。

Twitter数据实际上是一种特殊的多边图,当两个用户互相关注对方时,他们之间可以形成两条边。在金融场景中,如果用户账户为顶点,转账交易为边,那么两个账户之间可以存在多笔转账关系,即多条边。

很多系统只能支持简单的单边图,这样就会带来很多图上查询与计算的结果错误的问题。

(3)点、边属性

Twitter数据本身除了隐含的边的方向可以作为一种特殊的边属性外,并不存在其他点边属性。这个特征区别于金融行业中的交易流水图——无论是顶点还是边都可能存在多个属性,可以被用来对实体或关系进行精准的查询过滤、筛选、排序、聚合运算、下钻、归因分析等。不支持点边属性过滤的图数据库可以认为功能没有实现闭环,也不具备商业化价值。

我们以K邻查询为例来验证图数据库查询结果的正确性!!

首先,我们要明确K邻查询的定义,事实上K-Hop查询有两种含义,分别是:第K度(跳)邻居、从第1跳到第K跳的全部邻居。

其中第K跳邻居指的是全部距离原点最短路径距离为K的邻居数量。这两种含义的区别仅仅在于到底K-Hop的邻居是只包含当前步幅(跳、层)的邻居,还是包含前面所有层的邻居。无论是哪种定义,有两个要点直接影响“正确性”​:

· K邻查询的正确实现方式默认应基于广度优先搜索。

· 结果集去重:即第K层的邻居集合中不会有重复的顶点,也不会有在其他层出现的邻居(已知的多款图数据库系统都存在数据结果没有去重的错误)​。

有的图数据库(或图计算引擎)会用深度优先搜索(DFS)方式,通过穷举全部可能的深度为K跳的路径来试图找到全部路径和最终能抵达的终点。但是,DFS方式实现K邻查询有2个致命的缺点:

·效率低下:在体量稍大的图中,不可能遍历完全,例如Twitter数据集中常见的有超过百万邻居的顶点,如果以深度遍历,复杂度是天文数字级的(百万的11次方以上)​;

·结果大概率错误:即便是可以通过DFS完成遍历,也没有对结果进行分层,即无法判断某个邻居到底是位于第1跳还是第N跳。

我们先从验证1度(1跳)邻居开始,以Twitter数据集的顶点27960125为例。在源数据集中,如图1所示,返回了8行(对应图数据库中的8条边)​,但是它的1度邻居到底是几个呢?

图1:Twitter源数据中顶点关联的边


正确答案是7个,注意图1中顶点27960125的一个邻居27498091出现了2次,它们之间存在两条相互的关系(对应源数据集中的2行)​。但是作为去重后的1度邻居集合,只有7个。

在图2中,我们以无向图(即双向边遍历)的方式对顶点27960125进行1度邻居查询,得到全部邻居顶点为7个。

图2:在命令行工具中验证顶点的邻居结果集:嬴图-CLI)


为了更精准地验证结果正确性,对K邻查询还可以按照边的方向来进行过滤,例如只查询顶点2796015的出边、入边或双向边(默认是查询双向边关联的全部邻居)​。图3展示了如何通过图查询语言来完成相应的工作。注意,该顶点有6条出边对应的1跳邻居、2条入边对应的1跳邻居,其中有1个邻居27498091是重叠的。

图3::从嬴图-CLI命令行工具操作K邻——3种遍历模式


如果参考美国图数据库厂家Tigergraph在Github网站上公开的性能测试结果数据文件,其K邻查询的结果存在明显的错误,例如图7-14中顶点27960125的1-Hop结果仅返回6个邻居。

图4:Tigergraph的性能评测结果中的数据(Github.com)

Tigergraph的查询结果错误有3个可能,并且具有典型性。

·构图错误:只存储了单向边,没有存储反向边,无法进行反向边遍历;

·查询方式错误:只进行了单向查询,没有进行双向遍历查询;

·图查询代码实现错误:即没有对结果进行有效的去重,这个在多跳K-Hop查询中再继续分析。

其中,构图错误代表数据建模错误,这意味着业务逻辑不能在数据建模层面被准确反映。例如在反欺诈、反洗钱场景中,账户A收到了一笔来自账户B的转账,但是却因为没有存储一条从A至B的反向边而无法追踪该笔交易,这显然是不能容忍的。

查询方式和查询代码逻辑错误同样也会对结果造成严重影响——每一跳查询双向边,在多跳情况下查询复杂度指数级高于单向边查询,这也意味着Tigergraph如果正确地实现图数据建模、存储与查询,其性能会指数级降低,并且存储空间的占用也会成倍增加(存储正向和反向边的数据结构要比仅存储单向边复杂2倍以上)​,数据加载时间也会成倍增加。

如果我们继续追溯顶点27960125的2-Hop结果集,就会发现结果的错误更加隐蔽,例如Tigergraph的2-Hop实际上仅仅返回了沿出边遍历的第2度邻居结果(图5)​,并且没有对结果去重。其第2度邻居数1128中含有重复的顶点,按照只进行出边查询得到的去重结果应该是1127——但是2-Hop的正确结果应该是533108(图6)​,这两者间有473倍的差异,即47300%的误差!在2-Hop的结果中,就可以看到Tigergraph的查询结果同时存在以上所述的3种错误——构图错误、查询方式错误、结果未去重错误。

图5 :Tigergraph仅进行单向遍历的错误的2-Hop结果(Github)

图6:K-Hop查询的4种遍历查询方式(嬴图-CLI)


遗憾的是,类似的查询结果错误问题在今天的图数据库市场并不是个例,我们在Neo4j、ArangoDB等系统中也发现因底层算法实现或接口调用等问题而出现的错误。

更为遗憾的是,有多个厂家的“自研图数据库”实际上是对Neo4j社区版或ArangoDB的封装,姑且不论这么操作是否涉嫌违规商用,暴力封装几乎注定了它们的查询结果也是错误的。例如Neo4j默认并不对K邻查询结果集进行去重,而一旦开启去重,它的运行效率会指数级下降;而ArangoDB有一种最短路径查询模式,只返回一条路径,这种模式本身就是对最短路径的错误理解与实现。

图数据库配套的可视化工具可以帮助我们更直观、便捷地查询结果的正确性。

上面介绍了图上的基础查询K邻查询的正确性验证方法,以及可能出现的错误情形。还有很多其他图操作同样也涉及结果错误的问题,但是都能通过一些基础的方法来验证。下面再举2个有代表性的例子:最短路径和图算法。

最短路径可以看作K邻查询的一个自然延展,区别在于它需要返回的结果有2个特征:

·高维结果:最短路径需要返回多条由顶点、边按遍历顺序组合而成的路径;

·全部路径:任意两个顶点间可能存在多条最短路径,如果是转账网络、反洗钱网络、归因分析等查询,只计算一条路径显然是无法反映全貌的。

以Twitter数据集中的顶点12、13之间的最短路径为例,它们之间存在两条最短路径(图7)​,其中一条由12指向13,另一条由13指向12(图8)​,这个在源数据中也可以通过grep操作得到快速验证。在更复杂(更深度)的查询中,可以用类似的逻辑,通过层层的抽丝剥茧来验证结果的正确性。

图7:最短路径结果示意(嬴图 - CLI)
图8:最短路径查询操作结果验证——3种遍历模式(嬴图 - CLI)


下面以杰卡德相似度算法为例来说明如何验证图算法的正确性。以图9为例,计算A、B两个顶点间的相似度,计算公式如下:

图9:小图集


在图9中,A、B节点的共同邻居数为2,全部邻居数为5,我们可以手工推算出这两个节点的杰卡德相似度为2/5=0.4。直接调用杰卡德相似度算法的结果也应该是0.4(40%)​。如果用图查询语言来白盒化实现,代码逻辑如图10所示。

图10:杰卡德相似度的图查询语言实现(嬴图-GQL查询语言)

在Twitter数据集中,任意两个顶点间的杰卡德相似度计算的复杂度和被查询顶点的1度邻居的个数直接相关,以顶点12、13为例,它们都是典型的有百万邻居的“超级节点”​,在这种情况下,手工验证结果的准确性并不现实。但是可以通过多组查询来校验结果是否正确,逻辑分为如下5步:

1)运行杰卡德相似度算法,如图11所示:

图11:直接运行杰卡德相似度算法

2)​(验证方法一)通过多句查询计算杰卡德相似度,如图12所示:

图12:杰卡德相似度算法——验证方法一

3)​(验证方法二)查询顶点12的1跳邻居个数(图13)​。

4)​(验证方法二)查询顶点13的1跳邻居个数(图13)​。

图13 :杰卡德相似度算法——验证方法二第1部分

5)​(验证方法二)查询顶点12到13之间的全部深度为2的路径(图14)​,这一结果就是两个顶点之间的全部共有邻居。

图14 杰卡德相似度算法——验证方法二第2部分

 6)​(验证方法二)用以上第5步的结果除以(第3步结果+第4步结果–第5步结果)=0.15362638。如果以上两种验证方法结果均一致,则图算法计算结果正确。

最后要说的是,本文等于非常详细地介绍了如何在图数据库上进行查询正确性验证的方法,希望可以为聪明的朋友们以开阔思路,以达到举一反三、去伪存真的效果!!! 好了,洋洋洒洒有一大篇,就此打住。88!

· END ·


(文/Ricky - HPC高性能计算与存储专家、大数据专家、数据库专家及学者)

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

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

相关文章

Rust ~ Vec<u8>和[u8]

Vec<u8> 和 &[u8] 是两种不同的数据类型&#xff0c;它们都与字节序列相关&#xff0c;但在所有权、内存管理、使用场景等方面存在明显区别 类型本质 Vec<u8>&#xff1a;Rust 中的动态数组类型&#xff0c;即向量&#xff08;vector&#xff09;。它是一个拥…

MYSQL学习笔记(十):约束介绍(如:非空、唯一、主键、外键、级联、默认、检查约束)

前言&#xff1a; 学习和使用数据库可以说是程序员必须具备能力&#xff0c;这里将更新关于MYSQL的使用讲解&#xff0c;大概应该会更新30篇&#xff0c;涵盖入门、进阶、高级(一些原理分析);这一篇讲解“约束”&#xff0c;如&#xff1a;非空、唯一、主键、外键、级联、默认…

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…

Halcon 学习之路 set_grayval 算子

gen_imag_const 创建灰度图像 gen_image_const(Image&#xff0c;Type&#xff0c;Width&#xff0c;Height) 算子gen_image_const创建指定大小的图像&#xff0c;图像的宽度和高度由Width和Height决定 Type 像素类型 byte :每像素1字节&#xff0c;无符号&#xff08;0-255&…

03_pyqt5 + vlc 实现视频播放器

1.功能需求如图 按钮: 播放/暂停, 前进/后退, 视频上一个/下一个, 打开视频进度条: 视频进度条显示, 进度条拖拽, 音量控制按键控制: 1,2,3,4缩放画面大小, 2.方案选择 开发语言: python UI界面: pyqt5 qt_designed 设计ui布局 视频编码: python-vlc 方案说明: 视频解码可…

使用vscode导出Markdown的PDF无法显示数学公式的问题

我的硬件环境是M2的MacBook air&#xff0c;在vscode中使用了Markdown PDF来导出md文件对应的PDF。但不管导出html还是PDF文件&#xff0c;数学公式都是显示的源代码。 我看了许多教程&#xff0c;给的是这个方法&#xff1a;在md文件对应的html文件中加上以下代码&#xff1a…

Java 网络编程(二)—— TCP流套接字编程

TCP 和 UDP 的区别 在传输层&#xff0c;TCP 协议是有连接的&#xff0c;可靠传输&#xff0c;面向字节流&#xff0c;全双工 而UDP 协议是无连接的&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 有连接和无连接的区别是在进行网络通信的时候&#xff0c;…

MySQL 事务笔记

MySQL 事务笔记 目录 事务简介事务操作事务四大特性并发事务问题事务隔离级别总结 事务简介 事务&#xff08;Transaction&#xff09;是数据库操作的逻辑单元&#xff0c;由一组不可分割的SQL操作组成。主要用于保证&#xff1a; 多个操作的原子性&#xff08;要么全部成功…

GPT1 与 GPT2 的异同

1.什么是GPT1&#xff1a; GPT1介绍了一种通过生成式预训练&#xff08;Generative Pre-Training&#xff09;来提升语言理解能力的方法。这种方法首先在一个大型的未标注文本语料库上进行语言模型的预训练&#xff0c;然后针对具体的任务进行判别式微调&#xff08;discrimin…

Android Audio其他——数字音频接口(附)

数字音频接口 DAI,即 Digital Audio Interfaces,顾名思义,DAI 表示在板级或板间传输数字音频信号的方式。相比于模拟接口,数字音频接口抗干扰能力更强,硬件设计简单,DAI 在音频电路设计中得到越来越广泛的应用。 一、音频链路 1、模拟音频信号 可以看到在传统的…

kafka-leader -1问题解决

一. 问题&#xff1a; 在 Kafka 中&#xff0c;leader -1 通常表示分区的领导者副本尚未被选举出来&#xff0c;或者在获取领导者信息时出现了问题。以下是可能导致出现 kafka leader -1 的一些常见原因及相关分析&#xff1a; 1. 副本同步问题&#xff1a; 在 Kafka 集群中&…

DeepSeek基础之机器学习

文章目录 一、核心概念总结&#xff08;一&#xff09;机器学习基本定义&#xff08;二&#xff09;基本术语&#xff08;三&#xff09;假设空间&#xff08;四&#xff09;归纳偏好&#xff08;五&#xff09;“没有免费的午餐”定理&#xff08;NFL 定理&#xff09; 二、重…

【jira】用到几张表

jira用到的几张表 测试计划&#xff0c;测试周期&#xff0c;测试用例&#xff0c;问题记录 1. 测试计划 # 记录表&#xff0c;查计划详情 SELECT ID,issuenum,SUMMARY FROM jiraissue where issuenum 22871# 测试计划下&#xff0c;测试周期&#xff0c;查测试周期id&…

Mysql 死锁场景及解决方案

一、常见死锁场景 1. 不同顺序的锁获取 场景&#xff1a;事务A按顺序更新 行1 → 行2&#xff0c;事务B按 行2 → 行1 顺序更新。 原因&#xff1a;双方各持有一把锁&#xff0c;同时请求对方持有的锁&#xff0c;形成循环等待。 2. 索引缺失导致锁升级 场景&#xff1a;更…

Spring Boot从入门到精通:一站式掌握企业级开发

前言 Spring Boot作为Java领域最流行的微服务框架&#xff0c;凭借其约定优于配置的理念和快速启动的特性&#xff0c;极大简化了Spring应用的初始搭建和开发过程。本文将带你从零开始系统学习Spring Boot&#xff0c;最终实现精通级应用开发&#xff0c;涵盖核心原理、实战技…

【Go】十六、protobuf构建基础服务信息、grpc服务启动的基础信息

商品服务 服务结构 创建 goods 服务&#xff0c;将之前 user 服务的基本结构迁移到 goods 服务上&#xff0c;完整目录是&#xff1a; mxshop_srvs user_srv … tmp … goods_srv config config.go 配置的读取表 global global.go 数据库、日志初始化、全局变量定义 handler …

Redis 持久化方式:RDB(Redis Database)和 AOF(Append Only File)

本部分内容是关于博主在学习 Redis 时关于持久化部分的记录&#xff0c;介绍了 RDB 和 AOF 两种持久化方式&#xff0c;详细介绍了持久化的原理、配置、使用方式、优缺点和使用场景。并对两种持久化方式做了对比。文章最后介绍了 Redis 持久化的意义并与其他常见的缓存技术做了…

Linux中lshw相关的命令

​ lshw&#xff08;List Hardware&#xff09;是一个在 Linux 系统中用于显示硬件详细信息的强大工具。以下是一些常见的 lshw 相关命令及其用法&#xff1a; 1. 安装 lshw 在使用 lshw 之前&#xff0c;你可能需要先安装它。不同的 Linux 发行版安装方式有所不同&#xff1…

爬虫第九篇-结束爬虫循环

最近在学习Python爬虫的过程中&#xff0c;遇到了一个很有趣的问题&#xff1a;如何优雅地结束爬虫循环&#xff1f;今天&#xff0c;我想和大家分享一下我的发现和心得。 一、爬虫循环结束的常见问题 在写爬虫时&#xff0c;我们经常会遇到这样的情况&#xff1a;当爬取到的…

Vue3状态管理新选择:Pinia使用完全指南

一、为什么需要状态管理&#xff1f; 在Vue应用开发中&#xff0c;当我们的组件树变得复杂时&#xff0c;组件间的数据传递会成为棘手的问题。传统方案&#xff08;如props/$emit&#xff09;在多层嵌套组件中会变得笨拙&#xff0c;这时状态管理工具应运而生。Vue3带来了全新…