图数据库查询语言Gremlin vs Cypher vs nGQL的操作入门是怎样的
图数据库查询语言Gremlin vs Cypher vs nGQL的操作入门是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
文章的开头我们先来看下什么是图数据库,根据维基百科的定义:图数据库是使用图结构进行语义查询的数据库,它使用节点、边和属性来表示和存储数据。
虽然和关系型数据库存储的结构不同(关系型数据库为表结构,图数据库为图结构),但不计各自的性能问题,关系型数据库可以通过递归查询或者组合其他 SQL 语句(Join)完成图查询语言查询节点关系操作。得益于 1987 年 SQL 成为国际标准化组织(ISO)标准,关系型数据库行业得到了很好的发展。同 60、70 年代的关系型数据库类似,图数据库这个领域的查询语言目前也没有统一标准,虽然 19 年 9 月经过国际 SQL 标准委员会投票表决,决定将图查询语言(Graph Query Language)纳为一种新的数据库查询语言,但 GQL 的制定仍需要一段时间。
介于市面上没有统一的图查询语言标准,在本文中我们选取市面上主流的几款图查询语言来分析一波用法,由于篇幅原因本文旨在简单介绍图查询语言和常规用法,更详细的内容将在进阶篇中讲述。
图查询语言·介绍图查询语言 GremlinGremlin 是 Apache ThinkerPop 框架下的图遍历语言。Gremlin 可以是声明性的也可以是命令性的。虽然 Gremlin 是基于 Groovy 的,但具有许多语言变体,允许开发人员以 Java、JavaScript、Python、Scala、Clojure 和 Groovy 等许多现代编程语言原生编写 Gremlin 查询。
支持图数据库:Janus Graph、InfiniteGraph、Cosmos DB、DataStax Enterprise(5.0+) 、Amazon Neptune
图查询语言 CypherCypher 是一个描述性的图形查询语言,允许不必编写图形结构的遍历代码对图形存储有表现力和效率的查询,和 SQL 很相似,Cypher 语言的关键字不区分大小写,但是属性值,标签,关系类型和变量是区分大小写的。
支持图数据库: Neo4j、RedisGraph、AgensGraph
图查询语言 nGQLnGQL 是一种类 SQL 的声明型的文本查询语言,nGQL 同样是关键词大小写不敏感的查询语言,目前支持模式匹配、聚合运算、图计算,可无嵌入组合语句。
支持图数据库:Nebula Graph
图查询语言·术语篇在比较这 3 个图查询语言之前,我们先来看看他们各自的术语,如果你翻阅他们的文档会经常见到下面这些“关键字”,在这里我们不讲用法,只看这些图数据库常用概念在这 3 个图数据库文档中的叫法。
我们可以看到大体上对点和边的叫法类似,只不过 Cypher 中直接使用了 Relationship 关系一词代表边。其他的术语基本都非常直观。
图查询语言·语法篇了解过 Gremlin、Cypher、nGQL 中常见的术语之后,我们来看看使用这 3 个图查询语言过程中会需要了解的常规语法。
图#Gremlin创建图g=TinkerGraph.open().traversal()#nGQL创建图空间CREATESPACEgods点
图结构由点和边组成,一条边连接两个点。在 Gremlin 和 nGQL 中称之为 Vertex,Cypher 则称之为 Node。如何在图数据库中新建一个点呢?可以参考下面的语法
#Gremlin创建/插入点g.addV(vertexLabel).property()#Cypher创建点CREATE(:nodeLabel{property})#nGQL创建/插入点INSERTVERTEXtagName(propNameList)VALUESvid:(tagKeypropValue)点类型
点允许有对应的类型,在 Gremlin 和 Cypher 叫 label
,在 nGQL 中为 tag
。点类型可对应有多种属性(Property),例如 Person 可以有 name、age 等属性。
点类型相关的语法示例如下:
#Gremlin创建点类型g.addV(vertexLabel).property()#nGQL创建点类型CREATEtagName(PropNameList)
这里说明下,无论在 Gremlin 和 nGQL 中存在类似 IF NOT EXISTS
用法,即:如果不存在则创建,存在则直接返回。
创建好点之后如何查看点类型呢,可以参考以下方式。
#Gremlin查看(获取)点类型g.V().label().dedup();#Cypher查看点类型方法1MATCH(n)RETURNDISTINCTlabels(n)#Cypher查看点类型方法2CALLdb.labels();#nGQL查看点类型SHOWTAGS点的 CRUD
上面简单介绍了点、点类型,下面进入数据库基本 DML——CRUD,在上文介绍点时顺便介绍了点的创建和插入,这里说下如何插入特定类型的点,和点的获取、删除和更新。
插入特定类型点和插入点的操作类似,只不过需要指定某种点类型。语法参考:
#Gremlin插入特定类型点g.addV(StringvertexLabel).property()#Cypher插入特定类型点CREATE(node:label)#nGQL插入特定类型点INSERTVERTEX<tag_name>(prop_name_list)VALUES<vid>:(prop_value_list)查看点
#Gremlin查看点g.V(<vid>)#Cypher查看点MATCH(n)WHEREconditionRETURNproperties(n)#nGQL查看点FETCHPROPON<tag_name><vid>删除点
术语篇中提过 nGQL 中删除操作对应单词有 Delete
和 Drop
,在 nGQL 中 Delete 一般用于点边,Drop 用于 Schema 删除,这点和 SQL 的设计思路是一样的。
#Gremlin删除点g.V(<vid>).drop()#Cypher删除点MATCH(node:label)DETACHDELETEnode#nGQL删除点DELETEVERTEX<vid>更新点
用数据库的小伙伴都知道数据的常态是数据变更,来瞅瞅这 3 个图查询是使用什么语法来更新点数据的吧
#Gremlin更新点g.V(<vid>).property()#Cypher更新点SETn.prop=V#nGQL更新点UPDATEVERTEX<vid>SET<update_columns>
可以看到 Cypher 和 nGQL 都使用 SET 关键词来设置点对应的类型值,只不过 nGQL 中多了 UPDATE 关键词来标识操作,Gremlin 的操作和上文提到的查看点类似,只不过增加了变更 property 值操作。
边在 Gremlin 和 nGQL 称呼边为 Edge,而 Cypher 称之为 Relationship。下面进入到边相关的语法内容
边类型和点一样,边也可以有对应的类型
#Gremlin创建边类型g.edgeLabel()#nGQL创建边类型CREATEEDGEedgeTypeName(propNameList)边的 CRUD
说完边类型应该进入到边的常规操作部分了
插入指定边类型的边可以看到和点的使用语法类似,只不过在 Cypher 和 nGQL 中分别使用 -[]->
和 ->
来表示关系,而 Gremlin 则用 to()
关键词来标识指向关系,在使用这 3 种图查询语言的图数据库中的边均为有向边,下图左边为有向边,右边为无向边。
#Gremlin插入指定边类型的边g.addE(StringedgeLabel).from(v1).to(v2).property()#Cypher插入指定边类型的边CREATE(<node1-name>:<label1-name>)-[(<relationship-name>:<relationship-label-name>)]->(<node2-name>:<label2-name>)#nGQL插入指定边类型的边INSERTEDGE<edge_name>(<prop_name_list>)VALUES<src_vid>-><dst_vid>:\(<prop_value_list>)删除边
#Gremlin删除边g.E(<eid>).drop()#Cypher删除边MATCH(<node1-name>:<label1-name>)-[r:relationship-label-name]->()DELETEr#nGQL删除边DELETEEDGE<edge_type><src_vid>-><dst_vid>查看指定边
#Gremlin查看指定边g.E(<eid>)#Cypher查看指定边MATCH(n)-[r:label]->()WHEREconditionRETURNproperties(r)#nGQL查看指定边FETCHPROPON<edge_name><src_vid>-><dst_vid>其他操作
除了常规的点、边 CRUD 外,我们可以简单看看这 3 种图查询语言的组合查询。
指定点查指定边#Gremlin指定点查指定边g.V(<vid>).outE(<edge>)#Cypher指定点查指定边Match(n)->[r:label]->[]WHEREid(n)=vidRETURNr#nGQL指定点查指定边GOFROM<vid>OVER<edge>沿指定点反向查询指定边
在反向查询中,Gremlin 使用了 in 来表示反向关系,而 Cypher 则更直观的将指向箭头反向变成 <-
来表示反向关系,nGQL 则用关键词 REVERSELY
来标识反向关系。
#Gremlin沿指定点反向查询指定边g.V(<vid>).inE(<edge>)#Cypher沿指定点反向查询指定边MATCH(n)<-[r:label]-()#nGQL沿指定点反向查询指定边GOFROM<vid>OVER<edge>REVERSELY无向遍历
如果在图中,边的方向不重要(正向、反向都可以),那 Gremlin 使用 both()
,Cypher 使用 -[]-
,nGQL使用关键词 BIDIRECT
。
#TraverseedgeswithspecifiedverticesGremling.V(<vid>).bothE(<edge>)#TraverseedgeswithspecifiedverticesCypherMATCH(n)-[r:label]-()#TraverseedgeswithspecifiedverticesnGQLGOFROM<vid>OVER<edge>BIDIRECT沿指定点查询指定边 N 跳
Gremlin 和 nGQL 分别用 times 和 step 来表示 N 跳关系,而 Cypher 用 relationship*1..N
来表示 N 跳关系。
#Gremlin沿指定点查询指定边N跳g.V(<vid>).repeat(out(<edge>)).times(N)#Cypher沿指定点查询指定边N跳MATCH(n)-[r:label*N]->()WHEREconditionRETURNr#nGQL沿指定点查询指定边N跳GONSTEPSFROM<vid>OVER<edge>返回指定两点路径
#Gremlin返回指定两点路径g.V(<vid>).repeat(out()).until(<vid>).path()#Cypher返回指定两点路径MATCHp=(a)-[.*]->(b)WHEREconditionRETURNp#nGQL返回指定两点路径FINDALLPATHFROM<vid>TO<vid>OVER*图查询语言·实操篇
说了一通语法之后,是时候展示真正的技术了——来个具体一点的例子。
示例图:The Graphs of Gods实操示例使用了 Janus Graph 的示例图 The Graphs of Gods。该图结构如下图所示,描述了罗马万神话中诸神关系。
插入数据#插入点##nGQLnebula>INSERTVERTEXcharacter(name,age,type)VALUEShash("saturn"):("saturn",10000,"titan"),hash("jupiter"):("jupiter",5000,"god");##Gremlingremlin>saturn=g.addV("character").property(T.id,1).property('name','saturn').property('age',10000).property('type','titan').next();==>v[1]gremlin>jupiter=g.addV("character").property(T.id,2).property('name','jupiter').property('age',5000).property('type','god').next();==>v[2]gremlin>prometheus=g.addV("character").property(T.id,31).property('name','prometheus').property('age',1000).property('type','god').next();==>v[31]gremlin>jesus=g.addV("character").property(T.id,32).property('name','jesus').property('age',5000).property('type','god').next();==>v[32]##Cyphercypher>CREATE(src:character{name:"saturn",age:10000,type:"titan"})cypher>CREATE(dst:character{name:"jupiter",age:5000,type:"god"})#插入边##nGQLnebula>INSERTEDGEfather()VALUEShash("jupiter")->hash("saturn"):();##Gremlingremlin>g.addE("father").from(jupiter).to(saturn).property(T.id,13);==>e[13][2-father->1]##Cyphercypher>CREATE(src)-[rel:father]->(dst)删除数据
#nGQLnebula>DELETEVERTEXhash("prometheus");#Gremlingremlin>g.V(prometheus).drop();#Cyphercypher>MATCH(n:character{name:"prometheus"})DETACHDELETEn更新数据
#nGQLnebula>UPDATEVERTEXhash("jesus")SETcharacter.type='titan';#Gremlingremlin>g.V(jesus).property('age',6000);==>v[32]#Cyphercypher>MATCH(n:character{name:"jesus"})SETn.type='titan';查看数据
#nGQLnebula>FETCHPROPONcharacterhash("saturn");===================================================|character.name|character.age|character.type|===================================================|saturn|10000|titan|---------------------------------------------------#Gremlingremlin>g.V(saturn).valueMap();==>[name:[saturn],type:[titan],age:[10000]]#Cyphercypher>MATCH(n:character{name:"saturn"})RETURNproperties(n)╒════════════════════════════════════════════╕│"properties(n)"│╞════════════════════════════════════════════╡│{"name":"saturn","type":"titan","age":10000}│└────────────────────────────────────────────┘查询 hercules 的父亲
#nGQLnebula>LOOKUPONcharacterWHEREcharacter.name=='hercules'|\->GOFROM$-.VertexIDOVERfatherYIELD$$.character.name;=====================|$$.character.name|=====================|jupiter|---------------------#Gremlingremlin>g.V().hasLabel('character').has('name','hercules').out('father').values('name');==>jupiter#Cyphercypher>MATCH(src:character{name:"hercules"})-[:father]->(dst:character)RETURNdst.name╒══════════╕│"dst.name"│╞══════════╡│"jupiter"│└──────────┘查询 hercules 的祖父
#nGQLnebula>LOOKUPONcharacterWHEREcharacter.name=='hercules'|\->GO2STEPSFROM$-.VertexIDOVERfatherYIELD$$.character.name;=====================|$$.character.name|=====================|saturn|---------------------#Gremlingremlin>g.V().hasLabel('character').has('name','hercules').out('father').out('father').values('name');==>saturn#Cyphercypher>MATCH(src:character{name:"hercules"})-[:father*2]->(dst:character)RETURNdst.name╒══════════╕│"dst.name"│╞══════════╡│"saturn"│└──────────┘查询年龄大于 100 的人物
#nGQLnebula>LOOKUPONcharacterWHEREcharacter.age>100YIELDcharacter.name,character.age;=========================================================|VertexID|character.name|character.age|=========================================================|6761447489613431910|pluto|4000|---------------------------------------------------------|-5860788569139907963|neptune|4500|---------------------------------------------------------|4863977009196259577|jupiter|5000|---------------------------------------------------------|-4316810810681305233|saturn|10000|---------------------------------------------------------#Gremlingremlin>g.V().hasLabel('character').has('age',gt(100)).values('name');==>saturn==>jupiter==>neptune==>pluto#Cyphercypher>MATCH(src:character)WHEREsrc.age>100RETURNsrc.name╒═══════════╕│"src.name"│╞═══════════╡│"saturn"│├───────────┤│"jupiter"│├───────────┤│"neptune"││───────────││"pluto"│└───────────┘从一起居住的人物中排除 pluto 本人
#nGQLnebula>GOFROMhash("pluto")OVERlivesYIELDlives._dstASplace|GOFROM$-.placeOVERlivesREVERSELYWHERE\$$.character.name!="pluto"YIELD$$.character.nameAScohabitants;===============|cohabitants|===============|cerberus|---------------#Gremlingremlin>g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name');==>cerberus#Cyphercypher>MATCH(src:character{name:"pluto"})-[:lives]->()<-[:lives]-(dst:character)RETURNdst.name╒══════════╕│"dst.name"│╞══════════╡│"cerberus"│└──────────┘Pluto 的兄弟们
#whichbrotherlivesinwhichplace?##nGQLnebula>GOFROMhash("pluto")OVERbrotherYIELDbrother._dstASgod|\GOFROM$-.godOVERlivesYIELD$^.character.nameASBrother,$$.location.nameASHabitations;=========================|Brother|Habitations|=========================|jupiter|sky|-------------------------|neptune|sea|-------------------------##Gremlingremlin>g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place').by('name');==>[god:jupiter,place:sky]==>[god:neptune,place:sea]##Cyphercypher>MATCH(src:Character{name:"pluto"})-[:brother]->(bro:Character)-[:lives]->(dst)RETURNbro.name,dst.name╒═════════════════════════╕│"bro.name"│"dst.name"│╞═════════════════════════╡│"jupiter"│"sky"│├─────────────────────────┤│"neptune"│"sea"│└─────────────────────────┘
关于图数据库查询语言Gremlin vs Cypher vs nGQL的操作入门是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。