Graph query languages: Cypher vs. Gremlin vs. nGQL

栏目: IT技术 · 发布时间: 4年前

内容简介: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. 

Graph query languages: Cypher vs. Gremlin vs. nGQL

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

Graph query languages: Cypher vs. Gremlin vs. nGQL

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 .

Graph query languages: Cypher vs. Gremlin vs. nGQL

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.

Graph query languages: Cypher vs. Gremlin vs. nGQL

# 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.

Graph query languages: Cypher vs. Gremlin vs. nGQL

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!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大数据之路

大数据之路

阿里巴巴数据技术及产品部 / 电子工业出版社 / 2017-7-1 / CNY 79.00

在阿里巴巴集团内,数据人员面临的现实情况是:集团数据存储已经达到EB级别,部分单张表每天的数据记录数高达几千亿条;在2016年“双11购物狂欢节”的24小时中,支付金额达到了1207亿元人民币,支付峰值高达12万笔/秒,下单峰值达17.5万笔/秒,媒体直播大屏处理的总数据量高达百亿级别且所有数据都需要做到实时、准确地对外披露……巨大的信息量给数据采集、存储和计算都带来了极大的挑战。 《大数据......一起来看看 《大数据之路》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码