内容简介:In September 2019,In this post, we’ve selected some mainstream graph query languages and compared the CRUD usage in these languages respectively.
Graph Query Language Comparison Series - Gremlin vs Cypher vs nGQL
In September 2019, Graph Query Language is accepted as a new database query language in a vote by the International SQL Standards Committee, the unification of GQL takes time.
In this post, we’ve selected some mainstream graph query languages and compared the CRUD usage in these languages respectively.
Which Graph Query Languages to Be Compared
Gremlin
Gremlin is a graph traversal language developed by Apache TinkerPop and has been adopted by a lot of graph database solutions. It can be either declarative or imperative .
Gremlin is Groovy-based, but has many language variants that allow developers to write Gremlin queries natively in many modern programming languages such as Java, JavaScript, Python, Scala, Clojure and Groovy.
Supported graph databases: Janus Graph, InfiniteGraph, Cosmos DB, DataStax Enterprise(5.0+) and Amazon Neptune.
Cypher
Cypher is a declarative graph query language that allows expressive and efficient data querying in a property graph.
The language was designed with the power and capability of SQL. The keywords of the Cypher language are not case sensitive, but attributes, labels, relationship types and variables are case sensitive.
Supported graph databases: Neo4j and RedisGraph
nGQL
Nebula Graphintroduces its own query language, nGQL , which is a declarative, textual query language like SQL, but designed for graphs.
The keywords of the nGQL language are case sensitive and it support statement composition so that there’s no need for statement embedding.
**Support graph databases: **Nebula Graph
Terms Comparison
Before comparing the three graph query languages, let’s take a look at their terms and concepts first. The table below explains how these languages define nodes and edges:
Graph Terms | Gremlin | Cypher | nGQL |
---|---|---|---|
Vertex | Vertex | Node | Vertex |
Edge | Edge | Relationship | Edge |
Vertex Type | Label | Label | Tag |
Edge Type | label | RelationshipType | edge type |
Vertex ID | vid | id(n) | vid |
Edge ID | eid | id(r) | \ |
Insert | add | create | insert |
Delete | drop | delete | delete / drop |
Update | setProperty | set | update |
Syntax Comparison - CRUD
After understanding the common terms in Gremlin, Cypher, and nGQL, let’s take a look at the general syntax of these graph query languages.
This section will walk you through the basic CRUD syntax for Gremlin, Cypher and nGQL respectively.
Graph
Refer to the following example on how to create a graph space. We omitted Cypher since you don’t need to create a graph space before you can add any data to the graph databases.
# Create a graph that Gremlin can traverse g = TinkerGraph.open().traversal() # Create a graph space in nGQL CREATE SPACE gods
Vertex
We all know that graph consists of nodes and edges. A node in Cypher is called a vertex in Gremlin and nGQL. And an edge is the connection among two nodes.
Refer to the following example on inserting new vertex in these query languages respectively.
# Insert vertex in Gremlin g.addV(vertexLabel).property() # Insert vertex in Cypher CREATE (:nodeLabel {property}) # Insert vertex in nGQL INSERT VERTEX tagName (propNameList) VALUES vid:(tagKey propValue)
Vertex Type
The nodes/vertices can have types. They are called labels
in Gremlin and Cypher , and tags
in nGQL.
A vertex type can have multiple properties. For example, vertex type Person have two properties, i.e. name and age .
Create Vertex Type
Refer to the following example on vertex type creation. We omitted Cypher since you don’t need a label before inserting data.
# Create vertex type in Gremlin g.addV(vertexLabel).property() # Create vertex type in nGQL CREATE tagName(PropNameList)
Note that Gremlin and nGQL both support IF NOT EXISTS
. This keyword automatically detects if the corresponding vertex type exists. If it does not exist, a new one is created. Otherwise, no vertex type is created.
Show Vertex Types
When the vertex types are created, you can show them with the following queries. They will list all the labels/tags rather than certain labels/tags.
# Show vertex types in Gremlin g.V().label().dedup(); # Show vertex types in Cypher method 1 MATCH (n) RETURN DISTINCT labels(n) # Show vertex types in Cypher method 2 CALL db.labels(); # Show vertex types in nGQL SHOW TAGS
CRUD on Vertices
This section introduces the basic CRUD operations on vertices using the three query languages.
Insert Vertices
# Insert vertex of certain type in Gremlin g.addV(String vertexLabel).property() # Insert vertex of certain type in Cypher CREATE (node:label) # Insert vertex of certain type in nGQL INSERT VERTEX <tag_name> (prop_name_list) VALUES <vid>:(prop_value_list)
Get Vertices
# Fetch vertices in Gremlin g.V(<vid>) # Fetch vertices in Cypher MATCH (n) WHERE condition RETURN properties(n) # Fetch vertices in nGQL FETCH PROP ON <tag_name> <vid>
Delete Vertices
# Delete vertex in Gremlin g.V(<vid>).drop() # Delete a vertex in Cypher MATCH (node:label) DETACH DELETE node # Delete vertex in nGQL DELETE VERTEX <vid>
Update a Vertex’s Property
This section shows you how to update properties for vertex.
# Update vertex in Gremlin g.V(<vid>).property() # Update vertex in Cypher SET n.prop = V # Update vertex in nGQL UPDATE VERTEX <vid> SET <update_columns>
Both Cypher and nGQL use keyword SET
to set the vertex type, except that the UPDATE
keyword is added in nGQL to identify the operation. The operation of Gremlin is similar to the above-mentioned fetching vertex, except that it adds operations for changing property.
Edges
This section introduces the basic CRUD operations on edges.
Edge Types
Like vertices, edges can also have types.
# Create an edge type in Gremlin g.edgeLabel() # Create an edge type in nGQL CREATE EDGE edgeTypeName(propNameList)
CRUD on Edges
Insert Edges of Certain Types
Inserting an edge is similar to inserting vertices. Cypher uses -[]->
and and nGQL uses ->
to represent edges respectively. Gremlin uses the keyword to()
to indicate edge direction.
Edges are by default directed in the three languages. The chart on the left below is a directed edge while the one on the right is an undirected edge.
# Insert edge of certain type in Gremlin g.addE(String edgeLabel).from(v1).to(v2).property() # Insert edge of certain type in Cypher CREATE (<node1-name>:<label1-name>)- [(<relationship-name>:<relationship-label-name>)] ->(<node2-name>:<label2-name>) # Insert edge of certain type in nGQL INSERT EDGE <edge_name> ( <prop_name_list> ) VALUES <src_vid> -> <dst_vid>: ( <prop_value_list> )
Delete Edges
# Delete edge in Gremlin g.E(<eid>).drop() # Delete edge in Cypher MATCH (<node1-name>:<label1-name>)-[r:relationship-label-name]->() DELETE r # Delete edge in nGQL DELETE EDGE <edge_type> <src_vid> -> <dst_vid>
Fetch Edges
# Fetch edges in Gremlin g.E(<eid>) # Fetch edges in Cypher MATCH (n)-[r:label]->() WHERE condition RETURN properties(r) # Fetch edges in nGQL FETCH PROP ON <edge_name> <src_vid> -> <dst_vid>
Other Operations
In addition to the common CRUD on vertices and edges, we will also show you some combined queries in the three graph query languages.
Traverse edges
# Traverse edges with specified vertices in Gremlin g.V(<vid>).outE(<edge>) # Traverse edges with specified vertices in Cypher Match (n)->[r:label]->[] WHERE id(n) = vid RETURN r # Traverse edges with specified vertices in nGQL GO FROM <vid> OVER <edge>
Traverse edges reversely
In reverse traverse, Gremlin uses in
to indicate reversion, Cypher uses <-
. nGQL uses keyword REVERSELY
.
# Traverse edges reversely with specified vertices Gremlin g.V(<vid>).in(<edge>) # Traverse edges reversely with specified vertices Cypher MATCH (n)<-[r:label]-() # Traverse edges reversely with specified vertices nGQL GO FROM <vid> OVER <edge> REVERSELY
Traverse edges bidirectionally
If the edge direction is irrelevant (either direction is acceptable), Gremlin uses bothE()
, Cypher use -[]-
, and nGQL use keyward BIDIRECT
.
# Traverse edges reversely with specified vertices Gremlin g.V(<vid>).bothE(<edge>) # Traverse edges reversely with specified vertices Cypher MATCH (n)-[r:label]-() # Traverse edges reversely with specified vertices nGQL GO FROM <vid> OVER <edge> BIDIRECT
Query N hops along specified edge
Gremlin and nGQL use times
and STEP
respectively to represent N hops. Cypher uses relationship*N
.
# Query N hops along specified edge in Gremlin g.V(<vid>).repeat(out(<edge>)).times(N) # Query N hops along specified edge in Cypher MATCH (n)-[r:label*N]->() WHERE condition RETURN r # Query N hops along specified edge in nGQL GO N STEPS FROM <vid> OVER <edge>
Find paths between two vertices
# Find paths between two vertices in Gremlin g.V(<vid>).repeat(out()).until(<vid>).path() # Find paths between two vertices in Cypher MATCH p =(a)-[.*]->(b) WHERE condition RETURN p # Find paths between two vertices in nGQL FIND ALL PATH FROM <vid> TO <vid> OVER *
Example queries
This section introduces some demonstration queries.
Demo model: The Graphs of Gods
The examples in this section make extensive use of the toy graph distributed withJanus Graphcalled The Graphs of Gods , as diagrammed below .
This example describes the relationships between the beings and places of the Roman pantheon.
Inserting data
# Inserting vertices ## nGQL nebula> INSERT VERTEX character(name, age, type) VALUES hash("saturn"):("saturn", 10000, "titan"), hash("jupiter"):("jupiter", 5000, "god"); ## Gremlin gremlin> 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] ## Cypher cypher> CREATE (src:character {name:"saturn", age: 10000, type:"titan"}) cypher> CREATE (dst:character {name:"jupiter", age: 5000, type:"god"}) # Inserting edges ## nGQL nebula> INSERT EDGE father() VALUES hash("jupiter")->hash("saturn"):(); ## Gremlin gremlin> g.addE("father").from(jupiter).to(saturn).property(T.id, 13); ==>e[13][2-father->1] ## Cypher cypher> CREATE (src)-[rel:father]->(dst)
Deleting
# nGQL nebula> DELETE VERTEX hash("prometheus"); # Gremlin gremlin> g.V(prometheus).drop(); # Cypher cypher> MATCH (n:character {name:"prometheus"}) DETACH DELETE n
Updating
# nGQL nebula> UPDATE VERTEX hash("jesus") SET character.type = 'titan'; # Gremlin gremlin> g.V(jesus).property('age', 6000); ==>v[32] # Cypher cypher> MATCH (n:character {name:"jesus"}) SET n.type = 'titan';
Fetching/Reading
# nGQL nebula> FETCH PROP ON character hash("saturn"); =================================================== | character.name | character.age | character.type | =================================================== | saturn | 10000 | titan | --------------------------------------------------- # Gremlin gremlin> g.V(saturn).valueMap(); ==>[name:[saturn],type:[titan],age:[10000]] # Cypher cypher> MATCH (n:character {name:"saturn"}) RETURN properties(n) ╒════════════════════════════════════════════╕ │"properties(n)" │ ╞════════════════════════════════════════════╡ │{"name":"saturn","type":"titan","age":10000}│ └────────────────────────────────────────────┘
Finding the name of Hercules’s Father
# nGQL nebula> LOOKUP ON character WHERE character.name == 'hercules' | \ -> GO FROM $-.VertexID OVER father YIELD $$.character.name; ===================== | $$.character.name | ===================== | jupiter | --------------------- # Gremlin gremlin> g.V().hasLabel('character').has('name','hercules').out('father').values('name'); ==>jupiter # Cypher cypher> MATCH (src:character{name:"hercules"})-[:father]->(dst:character) RETURN dst.name ╒══════════╕ │"dst.name"│ ╞══════════╡ │"jupiter" │ └──────────┘
Finding the name of Hercules’s Grandfather
# nGQL nebula> LOOKUP ON character WHERE character.name == 'hercules' | \ -> GO 2 STEPS FROM $-.VertexID OVER father YIELD $$.character.name; ===================== | $$.character.name | ===================== | saturn | --------------------- # Gremlin gremlin> g.V().hasLabel('character').has('name','hercules').out('father').out('father').values('name'); ==>saturn # Cypher cypher> MATCH (src:character{name:"hercules"})-[:father*2]->(dst:character) RETURN dst.name ╒══════════╕ │"dst.name"│ ╞══════════╡ │"saturn" │ └──────────┘
Find the characters with age > 100
# nGQL nebula> LOOKUP ON character WHERE character.age > 100 YIELD character.name, character.age; ========================================================= | VertexID | character.name | character.age | ========================================================= | 6761447489613431910 | pluto | 4000 | --------------------------------------------------------- | -5860788569139907963 | neptune | 4500 | --------------------------------------------------------- | 4863977009196259577 | jupiter | 5000 | --------------------------------------------------------- | -4316810810681305233 | saturn | 10000 | --------------------------------------------------------- # Gremlin gremlin> g.V().hasLabel('character').has('age',gt(100)).values('name'); ==>saturn ==>jupiter ==>neptune ==>pluto # Cypher cypher> MATCH (src:character) WHERE src.age > 100 RETURN src.name ╒═══════════╕ │"src.name" │ ╞═══════════╡ │ "saturn" │ ├───────────┤ │ "jupiter" │ ├───────────┤ │ "neptune" │ │───────────│ │ "pluto" │ └───────────┘
Find who are pluto’s cohabitants, excluding pluto himself
# nGQL nebula> GO FROM hash("pluto") OVER lives YIELD lives._dst AS place | GO FROM $-.place OVER lives REVERSELY WHERE \ $$.character.name != "pluto" YIELD $$.character.name AS cohabitants; =============== | cohabitants | =============== | cerberus | --------------- # Gremlin gremlin> g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name'); ==>cerberus # Cypher cypher> MATCH (src:character{name:"pluto"})-[:lives]->()<-[:lives]-(dst:character) RETURN dst.name ╒══════════╕ │"dst.name"│ ╞══════════╡ │"cerberus"│ └──────────┘
Pluto’s Brothers
# which brother lives in which place? ## nGQL nebula> GO FROM hash("pluto") OVER brother YIELD brother._dst AS god | \ GO FROM $-.god OVER lives YIELD $^.character.name AS Brother, $$.location.name AS Habitations; ========================= | Brother | Habitations | ========================= | jupiter | sky | ------------------------- | neptune | sea | ------------------------- ## Gremlin gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place').by('name'); ==>[god:jupiter, place:sky] ==>[god:neptune, place:sea] ## Cypher cypher> MATCH (src:Character{name:"pluto"})-[:brother]->(bro:Character)-[:lives]->(dst) RETURN bro.name, dst.name ╒═════════════════════════╕ │"bro.name" │"dst.name"│ ╞═════════════════════════╡ │ "jupiter" │ "sky" │ ├─────────────────────────┤ │ "neptune" │ "sea" │ └─────────────────────────┘
In addition to the basic operations in the three graph query languages, we will work on another piece of comparison of advanced operations in these languages. Stay tuned!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。