Nebula入门学习——day3 nGQL指南

什么是 nGQL

nGQL(Nebula Graph Query Language)是 Nebula Graph 使用的的声明式图查询语言,支持灵活高效的图模式,而且 nGQL 是为开发和运维人员设计的类 SQL 查询语言,易于学习。

nGQL 是一个进行中的项目,会持续发布新特性和优化,因此可能会出现语法和实际操作不一致的问题,如果遇到此类问题,请提交 issue 通知 Nebula Graph 团队。Nebula Graph 3.0 及更新版本正在支持 openCypher 9

nGQL 可以做什么

  • 支持图遍历
  • 支持模式匹配
  • 支持聚合
  • 支持修改图
  • 支持访问控制
  • 支持聚合查询
  • 支持索引
  • 支持大部分 openCypher 9 图查询语法(不支持修改和控制语法)

示例数据 Basketballplayer

用户可以下载 Nebula Graph 示例数据 basketballplayer 文件,然后使用 Nebula Graph Console,使用选项-f执行脚本。

看下该gql脚本内容:

drop space basketballplayer;
create space basketballplayer(partition_num=10,replica_factor=1,vid_type=fixed_string(32));
:sleep 20
use basketballplayer;
create tag player(name string,age int);
create tag team(name string);
create edge serve(start_year int,end_year int);
create edge follow(degree int);
:sleep 20
create tag index player_index_0 on player();
create tag index player_index_1 on player(name(20));
:sleep 20
insert vertex player(name,age) values "player100":("Tim Duncan", 42);
insert vertex player(name,age) values "player101":("Tony Parker", 36);
insert vertex player(name,age) values "player102":("LaMarcus Aldridge", 33);
insert vertex player(name,age) values "player103":("Rudy Gay", 32);
insert vertex player(name,age) values "player104":("Marco Belinelli", 32);
insert vertex player(name,age) values "player105":("Danny Green", 31);
insert vertex player(name,age) values "player106":("Kyle Anderson", 25);
insert vertex player(name,age) values "player107":("Aron Baynes", 32);
insert vertex player(name,age) values "player108":("Boris Diaw", 36);
insert vertex player(name,age) values "player109":("Tiago Splitter", 34);
insert vertex player(name,age) values "player110":("Cory Joseph", 27);
insert vertex player(name,age) values "player111":("David West", 38);
insert vertex player(name,age) values "player112":("Jonathon Simmons", 29);
insert vertex player(name,age) values "player113":("Dejounte Murray", 29);
insert vertex player(name,age) values "player114":("Tracy McGrady", 39);
insert vertex player(name,age) values "player115":("Kobe Bryant", 40);
insert vertex player(name,age) values "player116":("LeBron James", 34);
insert vertex player(name,age) values "player117":("Stephen Curry", 31);
insert vertex player(name,age) values "player118":("Russell Westbrook", 30);
insert vertex player(name,age) values "player119":("Kevin Durant", 30);
insert vertex player(name,age) values "player120":("James Harden", 29);
insert vertex player(name,age) values "player121":("Chris Paul", 33);
insert vertex player(name,age) values "player122":("DeAndre Jordan", 30);
insert vertex player(name,age) values "player123":("Ricky Rubio", 28);
insert vertex player(name,age) values "player124":("Rajon Rondo", 33);
insert vertex player(name,age) values "player125":("Manu Ginobili", 41);
insert vertex player(name,age) values "player126":("Kyrie Irving", 26);
insert vertex player(name,age) values "player127":("Vince Carter", 42);
insert vertex player(name,age) values "player128":("Carmelo Anthony", 34);
insert vertex player(name,age) values "player129":("Dwyane Wade", 37);
insert vertex player(name,age) values "player130":("Joel Embiid", 25);
insert vertex player(name,age) values "player131":("Paul George", 28);
insert vertex player(name,age) values "player132":("Giannis Antetokounmpo", 24);
insert vertex player(name,age) values "player133":("Yao Ming", 38);
insert vertex player(name,age) values "player134":("Blake Griffin", 30);
insert vertex player(name,age) values "player135":("Damian Lillard", 28);
insert vertex player(name,age) values "player136":("Steve Nash", 45);
insert vertex player(name,age) values "player137":("Dirk Nowitzki", 40);
insert vertex player(name,age) values "player138":("Paul Gasol", 38);
insert vertex player(name,age) values "player139":("Marc Gasol", 34);
insert vertex player(name,age) values "player140":("Grant Hill", 46);
insert vertex player(name,age) values "player141":("Ray Allen", 43);
insert vertex player(name,age) values "player142":("Klay Thompson", 29);
insert vertex player(name,age) values "player143":("Kristaps Porzingis", 23);
insert vertex player(name,age) values "player144":("Shaquille O'Neal", 47);
insert vertex player(name,age) values "player145":("JaVale McGee", 31);
insert vertex player(name,age) values "player146":("Dwight Howard", 33);
insert vertex player(name,age) values "player147":("Amar'e Stoudemire", 36);
insert vertex player(name,age) values "player148":("Jason Kidd", 45);
insert vertex player(name,age) values "player149":("Ben Simmons", 22);
insert vertex player(name,age) values "player150":("Luka Doncic", 20);
insert vertex team(name) values "team200":("Warriors");
insert vertex team(name) values "team201":("Nuggets");
insert vertex team(name) values "team202":("Rockets");
insert vertex team(name) values "team203":("Trail Blazers");
insert vertex team(name) values "team204":("Spurs");
insert vertex team(name) values "team205":("Thunders");
insert vertex team(name) values "team206":("Jazz");
insert vertex team(name) values "team207":("Clippers");
insert vertex team(name) values "team208":("Kings");
insert vertex team(name) values "team209":("Timberwolves");
insert vertex team(name) values "team210":("Lakers");
insert vertex team(name) values "team211":("Pelicans");
insert vertex team(name) values "team212":("Grizzlies");
insert vertex team(name) values "team213":("Mavericks");
insert vertex team(name) values "team214":("Suns");
insert vertex team(name) values "team215":("Hornets");
insert vertex team(name) values "team216":("Cavaliers");
insert vertex team(name) values "team217":("Celtics");
insert vertex team(name) values "team218":("Raptors");
insert vertex team(name) values "team219":("76ers");
insert vertex team(name) values "team220":("Pacers");
insert vertex team(name) values "team221":("Bulls");
insert vertex team(name) values "team222":("Hawks");
insert vertex team(name) values "team223":("Knicks");
insert vertex team(name) values "team224":("Pistons");
insert vertex team(name) values "team225":("Bucks");
insert vertex team(name) values "team226":("Magic");
insert vertex team(name) values "team227":("Nets");
insert vertex team(name) values "team228":("Wizards");
insert vertex team(name) values "team229":("Heat");
insert edge follow(degree) values "player100"->"player101":(95);
insert edge follow(degree) values "player100"->"player125":(95);
insert edge follow(degree) values "player101"->"player100":(95);
insert edge follow(degree) values "player101"->"player125":(95);
insert edge follow(degree) values "player101"->"player102":(90);
insert edge follow(degree) values "player125"->"player100":(90);
insert edge follow(degree) values "player102"->"player101":(75);
insert edge follow(degree) values "player102"->"player100":(75);
insert edge follow(degree) values "player103"->"player102":(70);
insert edge follow(degree) values "player104"->"player101":(50);
insert edge follow(degree) values "player104"->"player100":(55);
insert edge follow(degree) values "player104"->"player105":(60);
insert edge follow(degree) values "player105"->"player104":(83);
insert edge follow(degree) values "player105"->"player100":(70);
insert edge follow(degree) values "player105"->"player116":(80);
insert edge follow(degree) values "player107"->"player100":(80);
insert edge follow(degree) values "player108"->"player101":(80);
insert edge follow(degree) values "player108"->"player100":(80);
insert edge follow(degree) values "player109"->"player100":(80);
insert edge follow(degree) values "player109"->"player125":(90);
insert edge follow(degree) values "player113"->"player100":(99);
insert edge follow(degree) values "player113"->"player101":(99);
insert edge follow(degree) values "player113"->"player125":(99);
insert edge follow(degree) values "player113"->"player104":(99);
insert edge follow(degree) values "player113"->"player105":(99);
insert edge follow(degree) values "player113"->"player116":(99);
insert edge follow(degree) values "player113"->"player118":(99);
insert edge follow(degree) values "player113"->"player121":(99);
insert edge follow(degree) values "player113"->"player106":(99);
insert edge follow(degree) values "player113"->"player119":(99);
insert edge follow(degree) values "player113"->"player120":(99);
insert edge follow(degree) values "player114"->"player115":(90);
insert edge follow(degree) values "player114"->"player140":(90);
insert edge follow(degree) values "player114"->"player103":(90);
insert edge follow(degree) values "player116"->"player141":(100);
insert edge follow(degree) values "player118"->"player131":(90);
insert edge follow(degree) values "player118"->"player120":(90);
insert edge follow(degree) values "player120"->"player118":(80);
insert edge follow(degree) values "player121"->"player116":(90);
insert edge follow(degree) values "player121"->"player128":(90);
insert edge follow(degree) values "player121"->"player129":(90);
insert edge follow(degree) values "player124"->"player141":(-1);
insert edge follow(degree) values "player126"->"player116":(13);
insert edge follow(degree) values "player127"->"player114":(90);
insert edge follow(degree) values "player127"->"player148":(70);
insert edge follow(degree) values "player128"->"player116":(90);
insert edge follow(degree) values "player128"->"player121":(90);
insert edge follow(degree) values "player128"->"player129":(90);
insert edge follow(degree) values "player129"->"player116":(90);
insert edge follow(degree) values "player129"->"player121":(90);
insert edge follow(degree) values "player129"->"player128":(90);
insert edge follow(degree) values "player130"->"player149":(80);
insert edge follow(degree) values "player131"->"player118":(95);
insert edge follow(degree) values "player133"->"player114":(90);
insert edge follow(degree) values "player133"->"player144":(90);
insert edge follow(degree) values "player134"->"player121":(-1);
insert edge follow(degree) values "player135"->"player102":(80);
insert edge follow(degree) values "player136"->"player147":(90);
insert edge follow(degree) values "player136"->"player137":(88);
insert edge follow(degree) values "player136"->"player117":(90);
insert edge follow(degree) values "player136"->"player148":(85);
insert edge follow(degree) values "player137"->"player136":(80);
insert edge follow(degree) values "player137"->"player148":(80);
insert edge follow(degree) values "player137"->"player129":(10);
insert edge follow(degree) values "player138"->"player115":(90);
insert edge follow(degree) values "player138"->"player139":(99);
insert edge follow(degree) values "player139"->"player138":(99);
insert edge follow(degree) values "player140"->"player114":(90);
insert edge follow(degree) values "player141"->"player124":(9);
insert edge follow(degree) values "player142"->"player117":(90);
insert edge follow(degree) values "player143"->"player150":(90);
insert edge follow(degree) values "player144"->"player145":(100);
insert edge follow(degree) values "player144"->"player100":(80);
insert edge follow(degree) values "player147"->"player136":(90);
insert edge follow(degree) values "player148"->"player127":(80);
insert edge follow(degree) values "player148"->"player136":(90);
insert edge follow(degree) values "player148"->"player137":(85);
insert edge follow(degree) values "player149"->"player130":(80);
insert edge follow(degree) values "player150"->"player137":(90);
insert edge follow(degree) values "player150"->"player143":(90);
insert edge follow(degree) values "player150"->"player120":(80);
insert edge serve(start_year,end_year) values "player100"->"team204":(1997, 2016);
insert edge serve(start_year,end_year) values "player101"->"team204":(1999, 2018);
insert edge serve(start_year,end_year) values "player101"->"team215":(2018, 2019);
insert edge serve(start_year,end_year) values "player102"->"team203":(2006, 2015);
insert edge serve(start_year,end_year) values "player102"->"team204":(2015, 2019);
insert edge serve(start_year,end_year) values "player103"->"team212":(2006, 2013);
insert edge serve(start_year,end_year) values "player103"->"team218":(2013, 2013);
insert edge serve(start_year,end_year) values "player103"->"team208":(2013, 2017);
insert edge serve(start_year,end_year) values "player103"->"team204":(2017, 2019);
insert edge serve(start_year,end_year) values "player104"->"team200":(2007, 2009);
insert edge serve(start_year,end_year) values "player104"->"team218":(2009, 2010);
insert edge serve(start_year,end_year) values "player104"->"team215"@20102012:(2010, 2012);
insert edge serve(start_year,end_year) values "player104"->"team221":(2012, 2013);
insert edge serve(start_year,end_year) values "player104"->"team204"@20132015:(2013, 2015);
insert edge serve(start_year,end_year) values "player104"->"team208":(2015, 2016);
insert edge serve(start_year,end_year) values "player104"->"team215"@20162017:(2016, 2017);
insert edge serve(start_year,end_year) values "player104"->"team222":(2017, 2018);
insert edge serve(start_year,end_year) values "player104"->"team219":(2018, 2018);
insert edge serve(start_year,end_year) values "player104"->"team204"@20182019:(2018, 2019);
insert edge serve(start_year,end_year) values "player105"->"team216":(2009, 2010);
insert edge serve(start_year,end_year) values "player105"->"team204":(2010, 2018);
insert edge serve(start_year,end_year) values "player105"->"team218":(2018, 2019);
insert edge serve(start_year,end_year) values "player106"->"team204":(2014, 2018);
insert edge serve(start_year,end_year) values "player106"->"team212":(2018, 2019);
insert edge serve(start_year,end_year) values "player107"->"team204":(2013, 2015);
insert edge serve(start_year,end_year) values "player107"->"team224":(2015, 2017);
insert edge serve(start_year,end_year) values "player107"->"team217":(2017, 2019);
insert edge serve(start_year,end_year) values "player108"->"team222":(2003, 2005);
insert edge serve(start_year,end_year) values "player108"->"team214":(2005, 2008);
insert edge serve(start_year,end_year) values "player108"->"team215":(2008, 2012);
insert edge serve(start_year,end_year) values "player108"->"team204":(2012, 2016);
insert edge serve(start_year,end_year) values "player108"->"team206":(2016, 2017);
insert edge serve(start_year,end_year) values "player109"->"team204":(2010, 2015);
insert edge serve(start_year,end_year) values "player109"->"team222":(2015, 2017);
insert edge serve(start_year,end_year) values "player109"->"team219":(2017, 2017);
insert edge serve(start_year,end_year) values "player110"->"team204":(2011, 2015);
insert edge serve(start_year,end_year) values "player110"->"team218":(2015, 2017);
insert edge serve(start_year,end_year) values "player110"->"team220":(2017, 2019);
insert edge serve(start_year,end_year) values "player111"->"team215":(2003, 2011);
insert edge serve(start_year,end_year) values "player111"->"team220":(2011, 2015);
insert edge serve(start_year,end_year) values "player111"->"team204":(2015, 2016);
insert edge serve(start_year,end_year) values "player111"->"team200":(2016, 2018);
insert edge serve(start_year,end_year) values "player112"->"team204":(2015, 2017);
insert edge serve(start_year,end_year) values "player112"->"team226":(2017, 2019);
insert edge serve(start_year,end_year) values "player112"->"team219":(2019, 2019);
insert edge serve(start_year,end_year) values "player113"->"team204":(2016, 2019);
insert edge serve(start_year,end_year) values "player114"->"team218":(1997, 2000);
insert edge serve(start_year,end_year) values "player114"->"team226":(2000, 2004);
insert edge serve(start_year,end_year) values "player114"->"team202":(2004, 2010);
insert edge serve(start_year,end_year) values "player114"->"team204":(2013, 2013);
insert edge serve(start_year,end_year) values "player115"->"team210":(1996, 2016);
insert edge serve(start_year,end_year) values "player116"->"team216"@20032010:(2003, 2010);
insert edge serve(start_year,end_year) values "player116"->"team229":(2010, 2014);
insert edge serve(start_year,end_year) values "player116"->"team216"@20142018:(2014, 2018);
insert edge serve(start_year,end_year) values "player116"->"team210":(2018, 2019);
insert edge serve(start_year,end_year) values "player117"->"team200":(2009, 2019);;
insert edge serve(start_year,end_year) values "player118"->"team205":(2008, 2019);
insert edge serve(start_year,end_year) values "player119"->"team205":(2007, 2016);
insert edge serve(start_year,end_year) values "player119"->"team200":(2016, 2019);
insert edge serve(start_year,end_year) values "player120"->"team205":(2009, 2012);
insert edge serve(start_year,end_year) values "player120"->"team202":(2012, 2019);
insert edge serve(start_year,end_year) values "player121"->"team215":(2005, 2011);
insert edge serve(start_year,end_year) values "player121"->"team207":(2011, 2017);
insert edge serve(start_year,end_year) values "player121"->"team202":(2017, 2021);
insert edge serve(start_year,end_year) values "player122"->"team207":(2008, 2018);
insert edge serve(start_year,end_year) values "player122"->"team213":(2018, 2019);
insert edge serve(start_year,end_year) values "player122"->"team223":(2019, 2019);
insert edge serve(start_year,end_year) values "player123"->"team209":(2011, 2017);
insert edge serve(start_year,end_year) values "player123"->"team206":(2017, 2019);
insert edge serve(start_year,end_year) values "player124"->"team217":(2006, 2014);
insert edge serve(start_year,end_year) values "player124"->"team213":(2014, 2015);
insert edge serve(start_year,end_year) values "player124"->"team208":(2015, 2016);
insert edge serve(start_year,end_year) values "player124"->"team221":(2016, 2017);
insert edge serve(start_year,end_year) values "player124"->"team211":(2017, 2018);
insert edge serve(start_year,end_year) values "player124"->"team210":(2018, 2019);
insert edge serve(start_year,end_year) values "player125"->"team204":(2002, 2018);
insert edge serve(start_year,end_year) values "player126"->"team216":(2011, 2017);
insert edge serve(start_year,end_year) values "player126"->"team217":(2017, 2019);
insert edge serve(start_year,end_year) values "player127"->"team218":(1998, 2004);
insert edge serve(start_year,end_year) values "player127"->"team227":(2004, 2009);
insert edge serve(start_year,end_year) values "player127"->"team226":(2009, 2010);
insert edge serve(start_year,end_year) values "player127"->"team214":(2010, 2011);
insert edge serve(start_year,end_year) values "player127"->"team213":(2011, 2014);
insert edge serve(start_year,end_year) values "player127"->"team212":(2014, 2017);
insert edge serve(start_year,end_year) values "player127"->"team208":(2017, 2018);
insert edge serve(start_year,end_year) values "player127"->"team222":(2018, 2019);
insert edge serve(start_year,end_year) values "player128"->"team201":(2003, 2011);
insert edge serve(start_year,end_year) values "player128"->"team223":(2011, 2017);
insert edge serve(start_year,end_year) values "player128"->"team205":(2017, 2018);
insert edge serve(start_year,end_year) values "player128"->"team202":(2018, 2019);
insert edge serve(start_year,end_year) values "player129"->"team229"@20032016:(2003, 2016);
insert edge serve(start_year,end_year) values "player129"->"team221":(2016, 2017);
insert edge serve(start_year,end_year) values "player129"->"team216":(2017, 2018);
insert edge serve(start_year,end_year) values "player129"->"team229"@20182019:(2018, 2019);
insert edge serve(start_year,end_year) values "player130"->"team219":(2014, 2019);
insert edge serve(start_year,end_year) values "player131"->"team220":(2010, 2017);
insert edge serve(start_year,end_year) values "player131"->"team205":(2017, 2019);
insert edge serve(start_year,end_year) values "player132"->"team225":(2013, 2019);
insert edge serve(start_year,end_year) values "player133"->"team202":(2002, 2011);
insert edge serve(start_year,end_year) values "player134"->"team207":(2009, 2018);
insert edge serve(start_year,end_year) values "player134"->"team224":(2018, 2019);
insert edge serve(start_year,end_year) values "player135"->"team203":(2012, 2019);
insert edge serve(start_year,end_year) values "player136"->"team214"@19961998:(1996, 1998);
insert edge serve(start_year,end_year) values "player136"->"team213":(1998, 2004);
insert edge serve(start_year,end_year) values "player136"->"team214"@20042012:(2004, 2012);
insert edge serve(start_year,end_year) values "player136"->"team210":(2012, 2015);
insert edge serve(start_year,end_year) values "player137"->"team213":(1998, 2019);
insert edge serve(start_year,end_year) values "player138"->"team212":(2001, 2008);
insert edge serve(start_year,end_year) values "player138"->"team210":(2008, 2014);
insert edge serve(start_year,end_year) values "player138"->"team221":(2014, 2016);
insert edge serve(start_year,end_year) values "player138"->"team204":(2016, 2019);
insert edge serve(start_year,end_year) values "player138"->"team225":(2019, 2020);
insert edge serve(start_year,end_year) values "player139"->"team212":(2008, 2019);
insert edge serve(start_year,end_year) values "player139"->"team218":(2019, 2019);
insert edge serve(start_year,end_year) values "player140"->"team224":(1994, 2000);
insert edge serve(start_year,end_year) values "player140"->"team226":(2000, 2007);
insert edge serve(start_year,end_year) values "player140"->"team214":(2007, 2012);
insert edge serve(start_year,end_year) values "player140"->"team207":(2012, 2013);
insert edge serve(start_year,end_year) values "player141"->"team225":(1996, 2003);
insert edge serve(start_year,end_year) values "player141"->"team205":(2003, 2007);
insert edge serve(start_year,end_year) values "player141"->"team217":(2007, 2012);
insert edge serve(start_year,end_year) values "player141"->"team229":(2012, 2014);
insert edge serve(start_year,end_year) values "player142"->"team200":(2011, 2019);
insert edge serve(start_year,end_year) values "player143"->"team223":(2015, 2019);
insert edge serve(start_year,end_year) values "player143"->"team213":(2019, 2020);
insert edge serve(start_year,end_year) values "player144"->"team226":(1992, 1996);
insert edge serve(start_year,end_year) values "player144"->"team210":(1996, 2004);
insert edge serve(start_year,end_year) values "player144"->"team229":(2004, 2008);
insert edge serve(start_year,end_year) values "player144"->"team214":(2008, 2009);
insert edge serve(start_year,end_year) values "player144"->"team216":(2009, 2010);
insert edge serve(start_year,end_year) values "player144"->"team217":(2010, 2011);
insert edge serve(start_year,end_year) values "player145"->"team228":(2008, 2012);
insert edge serve(start_year,end_year) values "player145"->"team201":(2012, 2015);
insert edge serve(start_year,end_year) values "player145"->"team213":(2015, 2016);
insert edge serve(start_year,end_year) values "player145"->"team200":(2016, 2018);
insert edge serve(start_year,end_year) values "player145"->"team210":(2018, 2019);
insert edge serve(start_year,end_year) values "player146"->"team226":(2004, 2012);
insert edge serve(start_year,end_year) values "player146"->"team210":(2012, 2013);
insert edge serve(start_year,end_year) values "player146"->"team202":(2013, 2016);
insert edge serve(start_year,end_year) values "player146"->"team222":(2016, 2017);
insert edge serve(start_year,end_year) values "player146"->"team215":(2017, 2018);
insert edge serve(start_year,end_year) values "player146"->"team228":(2018, 2019);
insert edge serve(start_year,end_year) values "player147"->"team214":(2002, 2010);
insert edge serve(start_year,end_year) values "player147"->"team223":(2010, 2015);
insert edge serve(start_year,end_year) values "player147"->"team229":(2015, 2016);
insert edge serve(start_year,end_year) values "player148"->"team213"@19941996:(1994, 1996);
insert edge serve(start_year,end_year) values "player148"->"team214":(1996, 2001);
insert edge serve(start_year,end_year) values "player148"->"team227":(2001, 2008);
insert edge serve(start_year,end_year) values "player148"->"team213"@20082012:(2008, 2012);
insert edge serve(start_year,end_year) values "player148"->"team223":(2012, 2013);
insert edge serve(start_year,end_year) values "player149"->"team219":(2016, 2019);
insert edge serve(start_year,end_year) values "player150"->"team213":(2018, 2019);

执行方法:./nebula-console-linux-amd64-v3.0.0 -addr localhost -P 9669 -u root -p root -f basketball.ngql

 

Note

导入示例数据前,确保已执行ADD HOSTS命令将 Storage 主机增加至集群中。更多信息,请参见管理 Storage 主机

占位标识符和占位符值

Nebula Graph 查询语言 nGQL 参照以下标准设计:

  • (Draft) ISO/IEC JTC1 N14279 SC 32 - Database_Languages - GQL
  • (Draft) ISO/IEC JTC1 SC32 N3228 - SQL_Property_Graph_Queries - SQLPGQ
  • OpenCypher 9

在模板代码中,任何非关键字、字面值或标点符号的标记都是占位符标识符或占位符值。

本文中 nGQL 语法符号的说明如下。

符号含义
< > 语法元素的名称。
: 定义元素的公式。
[ ] 可选元素。
{ } 显式的指定元素。
| 所有可选的元素。
... 可以重复多次。

例如创建点的 nGQL 语法:

 
INSERT VERTEX [IF NOT EXISTS] [tag_props, [tag_props] ...]
VALUES <vid>: ([prop_value_list])

tag_props:
  tag_name ([prop_name_list])

prop_name_list:
   [prop_name [, prop_name] ...]

prop_value_list:
   [prop_value [, prop_value] ...]  

示例语句:

 
nebula> CREATE TAG IF NOT EXISTS player(name string, age int);==》tag就类似对象,比如人这个对象,实例就是张三李四,也就是说图里具体的点和边是实例。

关于 openCypher 兼容性

原生 nGQL 和 openCypher 的关系

原生 nGQL 是由 Nebula Graph 自行创造和实现的图查询语言。openCypher 是由 openCypher Implementers Group 组织所开源和维护的图查询语言,最新版本为 openCypher 9。

由于 nGQL 语言部分兼容了 openCypher,这个部分在本文中称为 openCypher 兼容语句。

Note

nGQL 语言 = 原生 nGQL 语句 + openCypher 兼容语句 ==》所以未来切平台的话,也会有一些兼容性问题!

行为未定义

不要在同一个复合语句中,同时使用原生 nGQL 语句openCypher 兼容语句,其行为是未定义的。

nGQL 完全兼容 openCypher 9 吗?

不。

openCypher 兼容性

nGQL 设计目标仅为兼容部分的 DQL 语句(match, optional match, with等)。

不计划兼容任何 DDL,DML,DCL;

不计划兼容 Bolt 协议;

不计划兼容 APOC 与 GDS。

在本文搜索 "compatibility" 或者 “兼容性” 查看具体不兼容的细节。

Nebula Graph Issues 中已经列出已知的兼容错误。如果发现这种类型的新问题,请提交问题并附带incompatible标签。

nGQL 和 openCypher 9 的 主要差异有哪些?

类别openCypher 9nGQL
Schema 弱 Schema 强 Schema
相等运算符 = ==
数学求幂 ^ 使用pow(x, y)替代^
边 Rank 无此概念 @rank设置。
语句 - 不支持 openCypher 9 的所有 DML 语句(如CREATEMERGE等),不支持所有的 DCL,和支持部分 MATCH, OPTIONAL MATCH 语法和函数。
语句文本换行 换行符 \ + 换行符
Label 与 Tag 是不同的概念 Label 用于寻找点(点的索引)。 Tag 用于定义点的一种类型及相应的属性,无索引功能。
预编译与参数化查询 支持 仅支持参数化查询。

Compatibility

请注意 openCypher 9Cypher 在语法和许可上有不同:

  1. Cypher 要求所有 Cypher 语句必须“显式地在一个事务中”执行,而 openCypher 没有这样的要求。另外,nGQL 没有事务及隔离性。

  2. Cypher 企业版功能有多种的约束(constraints),包括 Unique node property constraints、Node property existence constraints、Relationship property existence constraints、Node key constraints。 OpenCypher 标准中没有约束。 而 nGQL 是强 Schema 系统,前述的约束大多通过 Schema 定义可实现(包括 NOT NULL),唯一不能支持的功能是“属性值唯一性”(UNIQUE constraint)。

  3. Cypher 有 APoC,openCypher 9 没有 APoC。Cypher 有 Blot 协议支持要求, openCypher 9 没有。

哪里可以找到更多 nGQL 的示例?

用户可以在 Nebula Graph GitHub 的 features 目录内查看超过 2500 条 nGQL 示例。

看了下,的确是有一些用法可参考该文件,例如yield语句的使用:

Feature: Yield Sentence

  Background: Prepare space
    Given a graph with space named "nba"

  Scenario: Base
    When executing query:
      """
      YIELD [1, 1.1, 1e2, 1.1e2, .3e4, 1.e4, 1234E-10, true] AS basic_value
      """
    Then the result should be, in any order, with relax comparison:
      | basic_value                                                 |
      | [1, 1.1, 100.0, 110.0, 3000.0, 10000.0, 0.0000001234, true] |
    When executing query:
      """
      YIELD 1+1, (int)3.14, (string)(1+1), (string)true,"1+1"
      """
    Then the result should be, in any order, with relax comparison:
      | (1+1) | (INT)3.14 | (STRING)(1+1) | (STRING)true | "1+1" |
      | 2     | 3         | "2"           | "true"       | "1+1" |
    When executing query:
      """
      YIELD "Hello", hash("Hello")
      """
    Then the result should be, in any order, with relax comparison:
      | "Hello" | hash("Hello")       |
      | "Hello" | 2275118702903107253 |

 

 

features 目录内包含很多。features 格式的文件,每个文件都记录了使用 nGQL 的场景和示例。例如:

 
Feature: Basic match

  Background:
    Given a graph with space named "basketballplayer"

  Scenario: Single node
    When executing query:
      """
      MATCH (v:player {name: "Yao Ming"}) RETURN v;
      """
    Then the result should be, in any order, with relax comparison:
      | v                                                |
      | ("player133" :player{age: 38, name: "Yao Ming"}) |

  Scenario: One step
    When executing query: 
      """
      MATCH (v1:player{name: "LeBron James"}) -[r]-> (v2)
      RETURN type(r) AS Type, v2.player.name AS Name
      """
    Then the result should be, in any order:

      | Type     | Name        |
      | "follow" | "Ray Allen" |
      | "serve"  | "Lakers"    |
      | "serve"  | "Heat"      |
      | "serve"  | "Cavaliers" |

Feature:  Comparison of where clause

  Background:
    Given a graph with space named "basketballplayer"

    Scenario: push edge props filter down
      When profiling query:
        """
        GO FROM "player100" OVER follow 
        WHERE properties(edge).degree IN [v IN [95,99] WHERE v > 0] 
        YIELD dst(edge), properties(edge).degree
        """
      Then the result should be, in any order:
        | follow._dst | follow.degree |
        | "player101" | 95            |
        | "player125" | 95            |
      And the execution plan should be:
        | id | name         | dependencies | operator info                                                         |
        | 0  | Project      | 1            |                                                                       |
        | 1  | GetNeighbors | 2            | {"filter": "(properties(edge).degree IN [v IN [95,99] WHERE (v>0)])"} |
        | 2  | Start        |              |                                                                       |

示例中的关键字说明如下。

关键字说明
Feature 描述当前文档的主题。
Background 描述当前文档的背景信息。
Given 描述执行示例语句的前提条件。
Scenario 描述具体场景。如果场景之前有@skip标识,表示这个场景下示例语句可能无法正常工作,请不要在生产环境中使用该示例语句。
When 描述要执行的 nGQL 示例语句。可以是executing queryprofiling query
Then 描述执行When内语句的预期返回结果。如果返回结果和文档不同,请提交 issue 通知 Nebula Graph 团队。
And 描述执行When内语句的副作用或执行计划。
@skip 跳过这个示例。通常表示测试代码还没有准备好。

欢迎增加更多 tck case,在 CI/CD 中自动回归所使用的语句。

是否支持 TinkerPop Gremlin?

不支持。也没有计划。

是否支持 W3C 的 RDF(SPARQL) 或 GraphQL 等?

不支持。也没有计划。

Nebula Graph 的数据模型是属性图,是一个强 Schema 系统,不支持 RDF 标准。

nGQL 也不支持 SPARQL 和 GraphQL。

模式

模式(pattern)和图模式匹配,是图查询语言的核心功能,本文介绍 Nebula Graph 设计的各种模式,部分还未实现。

单点模式

点用一对括号来描述,通常包含一个名称。例如:

(a)

示例为一个简单的模式,描述了单个点,并使用变量a命名该点。

多点关联模式

多个点通过边相连是常见的结构,模式用箭头来描述两个点之间的边。例如:

(a)-[]->(b)

示例为一个简单的数据结构:两个点和一条连接两个点的边,两个点分别为ab,边是有方向的,从ab

这种描述点和边的方式可以扩展到任意数量的点和边,例如:

(a)-[]->(b)<-[]-(c)

这样的一系列点和边称为路径(path)。

只有在涉及某个点时,才需要命名这个点。如果不涉及这个点,则可以省略名称,例如:

(a)-[]->()<-[]-(c)

Tag 模式

Note

nGQL 中的Tag概念与 openCypher 中的Label有一些不同。例如,必须创建一个Tag之后才能使用它,而且Tag还定义了属性的类型。

模式除了简单地描述图中的点之外,还可以描述点的 Tag。例如:

(a:User)-[]->(b)

模式也可以描述有多个 Tag 的点,例如:

(a:User:Admin)-[]->(b)

属性模式

点和边是图的基本结构。nGQL 在这两种结构上都可以增加属性,方便实现更丰富的模型。

在模式中,属性的表示方式为:用花括号括起一些键值对,用英文逗号分隔。例如一个点有两个属性:

(a {name: 'Andres', sport: 'Brazilian Ju-Jitsu'})

在这个点上可以有一条边是:

(a)-[{blocked: false}]->(b)

边模式

描述一条边最简单的方法是使用箭头连接两个点。

可以用以下方式描述边以及它的方向性。如果不关心边的方向,可以省略箭头,例如:

(a)-[]-(b)

和点一样,边也可以命名。一对方括号用于分隔箭头,变量放在两者之间。例如:

(a)-[r]->(b)

和点上的 Tag 一样,边也可以有类型。描述边的类型,例如:

(a)-[r:REL_TYPE]->(b)

和点上的 Tag 不同,一条边只能有一种 Edge type。但是如果我们想描述多个可选 Edge type,可以用管道符号(|)将可选值分开,例如:

(a)-[r:TYPE1|TYPE2]->(b)

和点一样,边的名称可以省略,例如:

(a)-[:REL_TYPE]->(b)

变长模式

在图中指定边的长度来描述多条边(以及中间的点)组成的一条长路径,不需要使用多个点和边来描述。例如:

(a)-[*2]->(b)

该模式描述了 3 点 2 边组成的图,它们都在一条路径上(长度为 2),等价于:

(a)-[]->()-[]->(b)

也可以指定长度范围,这样的边模式称为variable-length edges,例如:

(a)-[*3..5]->(b)

*3..5表示最小长度为 3,最大长度为 5。

该模式描述了 4 点 3 边、5 点 4 边或 6 点 5 边组成的图。

也可以忽略最小长度,只指定最大长度,例如:

(a)-[*..5]->(b)

Note

必须指定最大长度,不支持仅指定最小长度((a)-[*3..]->(b))或都不指定((a)-[*]->(b))。

路径变量

一系列连接的点和边称为路径。nGQL 允许使用变量来命名路径,例如:

p = (a)-[*3..5]->(b)

可以在 MATCH 语句中使用路径变量。


 

注释

本文介绍 nGQL 中的注释方式。

历史版本兼容性

  • Nebula Graph 1.x 支持四种注释方式:#--///* */
  • Nebula Graph 2.x 中,--不再是注释符。

Examples

 
nebula> # 这行什么都不做。
nebula> RETURN 1+1;     # 这条注释延续到行尾。
nebula> RETURN 1+1;     // 这条注释延续到行尾。
nebula> RETURN 1 /* 这是一条行内注释 */ + 1 == 2;
nebula> RETURN 11 +            \
/* 多行注释       \
用反斜线来换行。   \
*/ 12;

nGQL 语句中的反斜线(\)代表换行。

OpenCypher 兼容性

  • 在 nGQL 中,用户必须在行末使用反斜线(\)来换行,即使是在使用/* */符号的多行注释内。
  • 在 openCypher 中不需要使用反斜线换行。
 
/* openCypher 风格:
这条注释
延续了不止
一行 */
MATCH (n:label)
RETURN n;
 
/* 原生 nGQL 风格:  \
这条注释       \
延续了不止     \
一行 */       \
MATCH (n:tag) \
RETURN n;

大小写区分

标识符区分大小写

以下语句会出现错误,因为my_spaceMY_SPACE是两个不同的图空间。

nebula> CREATE SPACE IF NOT EXISTS my_space (vid_type=FIXED_STRING(30));
nebula> use MY_SPACE;
[ERROR (-1005)]: SpaceNotFound: 

关键字不区分大小写

以下语句是等价的,因为showspaces是关键字。

nebula> show spaces;  
nebula> SHOW SPACES;
nebula> SHOW spaces;
nebula> show SPACES;

函数不区分大小写

函数名称不区分大小写,例如count()COUNT()couNT()是等价的。

nebula> WITH [NULL, 1, 1, 2, 2] As a \
        UNWIND a AS b \
        RETURN count(b), COUNT(*), couNT(DISTINCT b);
+----------+----------+-------------------+
| count(b) | COUNT(*) | couNT(distinct b) |
+----------+----------+-------------------+
| 4        | 5        | 2                 |
+----------+----------+-------------------+

关键字

关键字在 nGQL 中有重要意义,分为保留关键字和非保留关键字。建议不要在 Schema 中使用关键字。

如果必须使用关键字:

  • 非保留关键字作为标识符时可以不使用引号。
  • 保留关键字或特殊字符作为标识符时,需要用反引号(`)包围,例如 `AND`。

Note

关键字不区分大小写。

 
nebula> CREATE TAG TAG(name string);
[ERROR (-1004)]: SyntaxError: syntax error near `TAG'

nebula> CREATE TAG `TAG` (name string);
Execution succeeded

nebula> CREATE TAG SPACE(name string);
Execution succeeded

nebula> CREATE TAG 中文(简体 string);
Execution succeeded

nebula> CREATE TAG `¥%特殊 字符&*+-*/` (`q~!()=  wer` string);
Execution succeeded

保留关键字

 
ACROSS
ADD
ALTER
AND

。。。

nGQL 风格指南

nGQL 没有严格的构建格式要求,但根据恰当而统一的风格创建 nGQL 语句有利于提高可读性、避免歧义。在同一组织或项目中使用相同的 nGQL 风格有利于降低维护成本,规避因格式混乱或误解造成的问题。本文为写作 nGQL 语句提供了风格参考。

Compatibility

nGQL 风格与 Cypher Style Guide 不同。

换行

  1. 换行写子句。

    不推荐:

    GO FROM "player100" OVER follow REVERSELY YIELD src(edge) AS id;
    

    推荐:

    GO FROM "player100" \
    OVER follow REVERSELY \
    YIELD src(edge) AS id;
    
  2. 换行写复合语句中的不同语句。

    不推荐:

    GO FROM "player100" OVER follow REVERSELY YIELD src(edge) AS id | GO FROM $-.id \
    OVER serve WHERE properties($^).age > 20 YIELD properties($^).name AS FriendOf, properties($$).name AS Team;
    

    推荐:

    GO FROM "player100" \
    OVER follow REVERSELY \
    YIELD src(edge) AS id | \
    GO FROM $-.id OVER serve \
    WHERE properties($^).age > 20 \
    YIELD properties($^).name AS FriendOf, properties($$).name AS Team;
    
  3. 子句长度超过 80 个字符时,在合适的位置换行。

    不推荐:

    MATCH (v:player{name:"Tim Duncan"})-[e]->(v2) \
    WHERE (v2.player.name STARTS WITH "Y" AND v2.player.age > 35 AND v2.player.age < v.player.age) OR (v2.player.name STARTS WITH "T" AND v2.player.age < 45 AND v2.player.age > v.player.age) \
    RETURN v2;
    

    推荐:

    MATCH (v:player{name:"Tim Duncan"})-[e]->(v2) \  ==》这就是前面提到的模式
    WHERE (v2.player.name STARTS WITH "Y" AND v2.player.age > 35 AND v2.player.age < v.player.age) \
    OR (v2.player.name STARTS WITH "T" AND v2.player.age < 45 AND v2.player.age > v.player.age) \
    RETURN v2;
    

Note

即使子句不超过 80 个字符,如需换行后有助于理解,也可将子句再次分行。

标识符命名

在 nGQL 语句中,关键字、标点符号、空格以外的字符内容都是标识符。推荐的标识符命名方式如下。

  1. 使用单数名词命名 Tag,用原型动词或动词短语构成 Edge type。

    不推荐:

    MATCH p=(v:players)-[e:are_following]-(v2) \
    RETURN nodes(p);
    

    推荐:

    MATCH p=(v:player)-[e:follow]-(v2) \ ==》表示节点类型(tag)是player
    RETURN nodes(p);
    
  2. 标识符用蛇形命名法,以下划线(_)连接单词,且所有字母小写。

    不推荐:

    MATCH (v:basketballTeam) \
    RETURN v;
    

    推荐:

    MATCH (v:basketball_team) \
    RETURN v;
    
  3. 语法关键词大写,变量小写。

    不推荐:

    go from "player100" over Follow
    

    推荐:

    GO FROM "player100" OVER follow
    

Pattern

  1. 分行写 Pattern 时,在表示边的箭头右侧换行,而不是左侧。

    不推荐:

    MATCH (v:player{name: "Tim Duncan", age: 42}) \
    -[e:follow]->()-[e2:serve]->()<--(v2) \
    RETURN v, e, v2;
    

    推荐:

    MATCH (v:player{name: "Tim Duncan", age: 42})-[e:follow]-> \
    ()-[e2:serve]->()<--(v2) \
    RETURN v, e, v2;
    
  2. 将无需查询的点和边匿名化。

    不推荐:

    MATCH (v:player)-[e:follow]->(v2) \
    RETURN v;
    

    推荐:

    MATCH (v:player)-[:follow]->() \
    RETURN v;
    
  3. (root@nebula) [basketballplayer]> MATCH (v:player)-[:follow]->() \
                                   -> RETURN v;
    +------------------------------------------------------------+
    | v                                                          |
    +------------------------------------------------------------+
    | ("player144" :player{age: 47, name: "Shaquille O'Neal"})   |
    | ("player133" :player{age: 38, name: "Yao Ming"})           |
    | ("player148" :player{age: 45, name: "Jason Kidd"})         |
    | ("player147" :player{age: 36, name: "Amar'e Stoudemire"})  |
    | ("player148" :player{age: 45, name: "Jason Kidd"})         |
    | ("player137" :player{age: 40, name: "Dirk Nowitzki"})      |
    | ("player114" :player{age: 39, name: "Tracy McGrady"})      |
    | ("player127" :player{age: 42, name: "Vince Carter"})       |
    | ("player133" :player{age: 38, name: "Yao Ming"})           |
    | ("player140" :player{age: 46, name: "Grant Hill"})         |
    | ("player114" :player{age: 39, name: "Tracy McGrady"})      |
    | ("player143" :player{age: 23, name: "Kristaps Porzingis"}) |
    | ("player113" :player{age: 29, name: "Dejounte Murray"})    |
    

     

  4. 将非匿名点放在匿名点的前面。

    不推荐:

    MATCH ()-[:follow]->(v) \
    RETURN v;
    

    推荐:

    MATCH (v)<-[:follow]-() \
    RETURN v;
     ==》涉及到性能优化???

字符串

字符串用双引号包围。

不推荐:

RETURN 'Hello Nebula!';

推荐:

RETURN "Hello Nebula!\"123\"";

Note

字符串中需要嵌套单引号或双引号时,用反斜线(\)转义。例如:

RETURN "\"Nebula Graph is amazing,\" the user says.";

结束语句

  1. 用英文分号(;)结束 nGQL 语句。

    不推荐:

    FETCH PROP ON player "player100"
    

    推荐:

    FETCH PROP ON player "player100";
    
  2. 使用管道符(|)分隔的复合语句,仅在最后一行末用英文分号结尾。在管道符前使用英文分号会导致语句执行失败。

    不支持:

    GO FROM "player100" \
    OVER follow \
    YIELD dst(edge) AS id; | \
    GO FROM $-.id \
    OVER serve \
    YIELD properties($$).name AS Team, properties($^).name AS Player;
    

    支持:

    GO FROM "player100" \
    OVER follow \
    YIELD dst(edge) AS id | \
    GO FROM $-.id \
    OVER serve \
    YIELD properties($$).name AS Team, properties($^).name AS Player;
    
  3. 在包含自定义变量的复合语句中,用英文分号结束定义变量的语句。不按规则加分号或使用管道符结束该语句会导致执行失败。

    不支持:

    $var = GO FROM "player100" \
    OVER follow \
    YIELD dst(edge) AS id \
    GO FROM $var.id \
    OVER serve \
    YIELD properties($$).name AS Team, properties($^).name AS Player;
    

    也不支持:

    $var = GO FROM "player100" \
    OVER follow \
    YIELD dst(edge) AS id | \
    GO FROM $var.id \
    OVER serve \
    YIELD properties($$).name AS Team, properties($^).name AS Player;
    

    支持:

    $var = GO FROM "player100" \
    OVER follow \
    YIELD dst(edge) AS id; \
    GO FROM $var.id \
    OVER serve \
    YIELD properties($$).name AS Team, properties($^).name AS Player;
    

NULL

默认情况下,插入点或边时,属性值可以为NULL,用户也可以设置属性值不允许为NULLNOT NULL),即插入点或边时必须设置该属性的值,除非创建属性时已经设置默认值。

示例

使用 NOT NULL

创建 Tag,名称为player,指定属性nameNOT NULL

 
nebula> CREATE TAG IF NOT EXISTS player(name string NOT NULL, age int);

使用SHOW命令查看创建 Tag 语句,属性nameNOT NULL,属性age为默认的NULL

 
nebula> SHOW CREATE TAG player;
+-----------+-----------------------------------+
| Tag       | Create Tag                        |
+-----------+-----------------------------------+
| "student" | "CREATE TAG `player` (           |
|           |  `name` string NOT NULL,          |
|           |  `age` int64 NULL                 |
|           | ) ttl_duration = 0, ttl_col = """ |
+-----------+-----------------------------------+

插入点Kobe,属性age可以为NULL

 
nebula> INSERT VERTEX player(name, age) VALUES "Kobe":("Kobe",null);

使用 NOT NULL 并设置默认值

创建 Tag,名称为player,指定属性ageNOT NULL,并设置默认值18

 
nebula> CREATE TAG IF NOT EXISTS player(name string, age int NOT NULL DEFAULT 18);

插入点Kobe,只设置属性name

 
nebula> INSERT VERTEX player(name) VALUES "Kobe":("Kobe");

查询点Kobe,属性age为默认值18

 
nebula> FETCH PROP ON player "Kobe" YIELD properties(vertex);
+--------------------------+
| properties(VERTEX)       |
+--------------------------+
| {age: 18, name: "Kobe"}  |
+--------------------------+

列表

列表(List)是复合数据类型,一个列表是一组元素的序列,可以通过元素在序列中的位置访问列表中的元素。

列表用左方括号([)和右方括号(])包裹多个元素,各个元素之间用英文逗号(,)隔开。元素前后的空格在列表中被忽略,因此可以使用换行符、制表符和空格调整格式。

OpenCypher 兼容性

复合数据类型(例如 List、Set、Map)不能存储为点或边的属性。

列表操作

对列表进行操作可以使用预设的列表函数,也可以使用下标表达式过滤列表内的元素。

下标表达式语法

 
[M]
[M..N]
[M..]
[..N]

nGQL 的下标支持从前往后查询,从 0 开始,0 表示第一个元素,1 表示第二个元素,以此类推;也支持从后往前查询,从-1 开始,-1 表示最后一个元素,-2 表示倒数第二个元素,以此类推。

  • [M]:表示下标为 M 的元素。
  • [M..N]:表示M ≤ 下标 < N的元素。N为 0 时,返回为空。
  • [M..]:表示M ≤ 下标的元素。
  • [..N]:表示下标 < N的元素。N为 0 时,返回为空。

Note

  • 越界的下标返回为空,未越界的可以正常返回。
  • MN时,返回为空。
  • 查询单个元素时,如果M为 null,返回报错BAD_TYPE;范围查询时,MN为 null,返回为null

示例

 
# 返回列表 [1,2,3]
nebula> RETURN list[1, 2, 3] AS a;
+-----------+
| a         |
+-----------+
| [1, 2, 3] |
+-----------+

# 返回列表 [1,2,3,4,5] 中位置下标为 3 的元素。列表的位置下标是从 0 开始,因此返回的元素为 4。
nebula> RETURN range(1,5)[3];
+---------------+
| range(1,5)[3] |
+---------------+
| 4             |
+---------------+

# 返回列表 [1,2,3,4,5] 中位置下标为-2 的元素。列表的最后一个元素的位置下标是-1,因此-2 是指倒数第二个元素,即 4。
nebula> RETURN range(1,5)[-2];
+------------------+
| range(1,5)[-(2)] |
+------------------+
| 4                |
+------------------+

# 返回列表 [1,2,3,4,5] 中下标位置从 0 到 3(不包括 3)的元素。
nebula> RETURN range(1,5)[0..3];
+------------------+
| range(1,5)[0..3] |
+------------------+
| [1, 2, 3]        |
+------------------+

# 返回列表 [1,2,3,4,5] 中位置下标大于 2 的元素。
nebula> RETURN range(1,5)[3..] AS a;
+--------+
| a      |
+--------+
| [4, 5] |
+--------+

# 返回列表内下标小于 3 的元素。
nebula> WITH list[1, 2, 3, 4, 5] AS a \
        RETURN a[..3] AS r;
+-----------+
| r         |
+-----------+
| [1, 2, 3] |
+-----------+

# 筛选列表 [1,2,3,4,5] 中大于 2 的元素,将这些元素分别做运算并返回。
nebula> RETURN [n IN range(1,5) WHERE n > 2 | n + 10] AS a;  ==》其中|表示管道运算 将一个list元素作为管道返回 这个表达还是挺灵活的
+--------------+
| a            |
+--------------+
| [13, 14, 15] |
+--------------+

# 返回列表内第一个至倒数第二个(包括)的元素。
nebula> YIELD list[1, 2, 3][0..-1] AS a;
+--------+
| a      |
+--------+
| [1, 2] |
+--------+

# 返回列表内倒数第三个至倒数第一个(不包括)的元素。
nebula> YIELD list[1, 2, 3, 4, 5][-3..-1] AS a;
+--------+
| a      |
+--------+
| [3, 4] |
+--------+

# 设置变量,返回列表内下标为 1、2 的元素。
nebula> $var = YIELD 1 AS f, 3 AS t; \
        YIELD list[1, 2, 3][$var.f..$var.t] AS a;
+--------+
| a      |
+--------+
| [2, 3] |
+--------+

# 越界的下标返回为空,未越界的可以正常返回。
nebula> RETURN list[1, 2, 3, 4, 5] [0..10] AS a;
+-----------------+
| a               |
+-----------------+
| [1, 2, 3, 4, 5] |
+-----------------+

nebula> RETURN list[1, 2, 3] [-5..5] AS a;
+-----------+
| a         |
+-----------+
| [1, 2, 3] |
+-----------+

# [0..0] 时返回为空。
nebula> RETURN list[1, 2, 3, 4, 5] [0..0] AS a;
+----+
| a  |
+----+
| [] |
+----+

# M ≥ N 时,返回为空。
nebula> RETURN list[1, 2, 3, 4, 5] [3..1] AS a;
+----+
| a  |
+----+
| [] |
+----+

# 范围查询时,下标有 null 时,返回为 null。
nebula> WITH list[1,2,3] AS a \
        RETURN a[0..null] as r;
+----------+
| r        |
+----------+
| __NULL__ |
+----------+

# 将列表 [1,2,3,4,5] 中的元素分别做运算,然后将列表去掉表头并返回。
nebula> RETURN tail([n IN range(1, 5) | 2 * n - 10]) AS a;
+-----------------+
| a               |
+-----------------+
| [-6, -4, -2, 0] |
+-----------------+

# 将列表 [1,2,3] 中的元素判断为真,然后返回。
nebula> RETURN [n IN range(1, 3) WHERE true | n] AS r;
+-----------+
| r         |
+-----------+
| [1, 2, 3] |
+-----------+

# 返回列表 [1,2,3] 的长度。
nebula> RETURN size(list[1,2,3]);
+---------------+
| size([1,2,3]) |
+---------------+
| 3             |
+---------------+

# 将列表 [92,90] 中的元素做运算,然后在 where 子句中进行条件判断。
nebula> GO FROM "player100" OVER follow WHERE properties(edge).degree NOT IN [x IN [92, 90] | x + $$.player.age] \
        YIELD dst(edge) AS id, properties(edge).degree AS degree;
+-------------+--------+
| id          | degree |
+-------------+--------+
| "player101" | 95     |
| "player102" | 90     |
+-------------+--------+

# 将 MATCH 语句的查询结果作为列表中的元素进行运算并返回。
nebula> MATCH p = (n:player{name:"Tim Duncan"})-[:follow]->(m) \
        RETURN [n IN nodes(p) | n.age + 100] AS r;
+------------+
| r          |
+------------+
| [142, 136] |
| [142, 133] |
+------------+

OpenCypher 兼容性

  • 在 openCypher 中,查询越界元素时返回null,而在 nGQL 中,查询单个越界元素时返回OUT_OF_RANGE
     
  • nebula> RETURN range(0,5)[-12];
    +-------------------+
    | range(0,5)[-(12)] |
    +-------------------+
    | OUT_OF_RANGE      |
    +-------------------+
    
  • 复合数据类型(例如 set、map、list)不能存储为点或边的属性。

    • 建议修改图建模方式:将复合数据类型建模为点的邻边,而不是该点的自身属性,每条邻边可以动态增删,并且可以设置邻边的 Rank 值来控制邻边的顺序。
  • List 中不支持 pattern,例如 [(src)-[]->(m) | m.name]

 

 

集合

集合(Set)是复合数据类型,集合中是一组元素,与列表(List)不同的是,集合中的元素是无序的,且不允许重复。

集合用左花括号({)和右花括号(})包裹多个元素,各个元素之间用英文逗号(,)隔开。元素前后的空格在集合中被忽略,因此可以使用换行符、制表符和空格调整格式。

OpenCypher 兼容性

  • 复合数据类型(例如 List、Set、Map)不能存储为点或边的属性。
  • 在 OpenCypher 中,集合不是一个数据类型,而在 nGQL 中,用户可以使用集合。

示例

 
# 返回集合 {1,2,3}。
nebula> RETURN set{1, 2, 3} AS a;
+-----------+
| a         |
+-----------+
| {3, 2, 1} |
+-----------+

# 返回集合 {1,2,1},因为集合不允许重复元素,会返回 {1,2},且顺序是无序的。
nebula> RETURN set{1, 2, 1} AS a;
+--------+
| a      |
+--------+
| {2, 1} |
+--------+

# 判断集合中是否有指定元素 1。
nebula> RETURN 1 IN set{1, 2} AS a;
+------+
| a    |
+------+
| true |
+------+

# 计算集合中的元素数量。
nebula> YIELD size(set{1, 2, 1}) AS a;
+---+
| a |
+---+
| 2 |
+---+

# 返回目标点属性值组成的集合。
nebula> GO FROM "player100" OVER follow \
        YIELD set{properties($$).name,properties($$).age} as a;
+-----------------------+
| a                     |
+-----------------------+
| {36, "Tony Parker"}   |
| {41, "Manu Ginobili"} |
+-----------------------+


映射

映射(Map)是复合数据类型。一个映射是一组键值对(Key-Value)的无序集合。在映射中,Key 是字符串类型,Value 可以是任何数据类型。用户可以通过map['<key>']的方法获取映射中的元素。

映射用左花括号({)和右花括号(})包裹多个键值对,各个键值对之间用英文逗号(,)隔开。键值对前后的空格在映射中被忽略,因此可以使用换行符、制表符和空格调整格式。

OpenCypher 兼容性

  • 复合数据类型(例如 List、Set、Map)不能存储为点或边的属性。
  • 不支持映射投影(map projection)。

示例

 
# 返回简单的映射。
nebula> YIELD map{key1: 'Value1', Key2: 'Value2'} as a;
+----------------------------------+
| a                                |
+----------------------------------+
| {Key2: "Value2", key1: "Value1"} |
+----------------------------------+

# 返回列表类型的映射。
nebula> YIELD map{listKey: [{inner: 'Map1'}, {inner: 'Map2'}]} as a;
+-----------------------------------------------+
| a                                             |
+-----------------------------------------------+
| {listKey: [{inner: "Map1"}, {inner: "Map2"}]} |
+-----------------------------------------------+

# 返回混合类型的映射。
nebula> RETURN map{a: LIST[1,2], b: SET{1,2,1}, c: "hee"} as a;
+----------------------------------+
| a                                |
+----------------------------------+
| {a: [1, 2], b: {2, 1}, c: "hee"} |
+----------------------------------+

# 返回映射中的指定元素。
nebula> RETURN map{a: LIST[1,2], b: SET{1,2,1}, c: "hee"}["b"] AS b;
+--------+
| b      |
+--------+
| {2, 1} |
+--------+

# 判断映射中是否有指定key,暂不支持判断value。
nebula> RETURN "a" IN MAP{a:1, b:2} AS a;
+------+
| a    |
+------+
| true |
+------+

 

类型转换

类型转换是指将表达式的类型转换为另一个类型。

类型强制转换函数

函数说明
toBoolean() 将字符串转换为布尔。
toFloat() 将整数或字符串转换为浮点数。
toInteger() 将浮点或字符串转换为整数。
toSet() 将列表或集合转换为集合。
type() 返回字符串格式的关系类型。

示例

 
nebula> UNWIND [true, false, 'true', 'false', NULL] AS b \
        RETURN toBoolean(b) AS b;
+----------+
| b        |
+----------+
| true     |
+----------+
| false    |
+----------+
| true     |
+----------+
| false    |
+----------+
| __NULL__ |
+----------+

nebula> RETURN toFloat(1), toFloat('1.3'), toFloat('1e3'), toFloat('not a number');
+------------+----------------+----------------+-------------------------+
| toFloat(1) | toFloat("1.3") | toFloat("1e3") | toFloat("not a number") |
+------------+----------------+----------------+-------------------------+
| 1.0        | 1.3            | 1000.0         | __NULL__                |
+------------+----------------+----------------+-------------------------+

nebula> RETURN toInteger(1), toInteger('1'), toInteger('1e3'), toInteger('not a number');
+--------------+----------------+------------------+---------------------------+
| toInteger(1) | toInteger("1") | toInteger("1e3") | toInteger("not a number") |
+--------------+----------------+------------------+---------------------------+
| 1            | 1              | 1000             | __NULL__                  |
+--------------+----------------+------------------+---------------------------+

nebula> MATCH (a:player)-[e]-() \
        RETURN type(e);
+----------+
| type(e)  |
+----------+
| "follow" |
+----------+
| "follow" |

nebula> MATCH (a:player {name: "Tim Duncan"}) \
        WHERE toInteger(right(id(a),3)) == 100 \
        RETURN a;
+----------------------------------------------------+
| a                                                  |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+

nebula> MATCH (n:player) \
        WITH n LIMIT toInteger(ceil(1.8)) \
        RETURN count(*) AS count;
+-------+
| count |
+-------+
| 2     |
+-------+

nebula> RETURN toSet(list[1,2,3,1,2]) AS list2set;
+-----------+
| list2set  |
+-----------+
| {3, 1, 2} |
+-----------+

nebula> RETURN toSet(set{1,2,3,1,2}) AS set2set;
+-----------+
| set2set   |
+-----------+
| {3, 2, 1} |
+-----------+

复合查询(子句结构)

复合查询将来自不同请求的数据放在一起,然后进行过滤、分组或者排序等,最后返回结果。

Nebula Graph 支持三种方式进行复合查询(或子查询):

  • (opencypher 兼容语句)连接各个子句,让它们在彼此之间提供中间结果集。
  • (原生 nGQL)多个查询可以合并处理,以英文分号(;)分隔,返回最后一个查询的结果。
  • (原生 nGQL)可以用管道符(|)将多个查询连接起来,上一个查询的结果可以作为下一个查询的输入。

OpenCypher 兼容性

在复合查询中,请不要混用 opencypher 兼容语句和原生 nGQL 语句,例如MATCH ... | GO ... | YIELD ...,混用两种语句,行为是未定义的。

  • 如果使用 openCypher 兼容语句(MATCHRETURNWITH等),请不要使用管道符或分号组合子句。
  • 如果使用原生 nGQL 语句(FETCHGOLOOKUP等),必须使用管道符或分号组合子句。

行为未定义

不要混用 openCypher 兼容语句和原生 nGQL 语句,行为是未定义的。

复合查询不支持事务

例如一个查询由三个子查询 A、B、C 组成,A 是一个读操作,B 是一个计算操作,C 是一个写操作,如果在执行过程中,任何一个操作执行失败,则整个结果是未定义的:没有回滚,而且写入的内容取决于执行程序。

Note

openCypher 没有事务要求。

示例

  • opencypher 兼容语句
     
  • # 子句连接多个查询。
    nebula> MATCH p=(v:player{name:"Tim Duncan"})--() \
            WITH nodes(p) AS n \
            UNWIND n AS n1 \
            RETURN DISTINCT n1;

    (root@nebula) [basketballplayer]> MATCH p=(v:player{name:"Tim Duncan"})--() \
                                   ->         WITH nodes(p) AS n \
                                   ->         UNWIND n AS n1 \
                                   ->         RETURN DISTINCT n1;
    +-----------------------------------------------------------+
    | n1                                                        |
    +-----------------------------------------------------------+
    | ("player100" :player{age: 42, name: "Tim Duncan"})        |
    | ("player125" :player{age: 41, name: "Manu Ginobili"})     |
    | ("player105" :player{age: 31, name: "Danny Green"})       |
    | ("player108" :player{age: 36, name: "Boris Diaw"})        |
    | ("player144" :player{age: 47, name: "Shaquille O'Neal"})  |
    | ("team204" :team{name: "Spurs"})                          |
    | ("player107" :player{age: 32, name: "Aron Baynes"})       |
    | ("player113" :player{age: 29, name: "Dejounte Murray"})   |
    | ("player109" :player{age: 34, name: "Tiago Splitter"})    |
    | ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
    | ("player104" :player{age: 32, name: "Marco Belinelli"})   |
    | ("player101" :player{age: 36, name: "Tony Parker"})       |
    +-----------------------------------------------------------+
    Got 12 rows (time spent 19899/20370 us)
    

     

  • 原生 nGQL(分号)
     
  • # 只返回边。
    nebula> SHOW TAGS; SHOW EDGES;
    
    # 插入多个点。
    nebula> INSERT VERTEX player(name, age) VALUES "player100":("Tim Duncan", 42); \
            INSERT VERTEX player(name, age) VALUES "player101":("Tony Parker", 36); \
            INSERT VERTEX player(name, age) VALUES "player102":("LaMarcus Aldridge", 33);
    
  • 原生 nGQL(管道符)
     
  • # 管道符连接多个查询。
    nebula> GO FROM "player100" OVER follow YIELD dst(edge) AS id | \
            GO FROM $-.id OVER serve YIELD properties($$).name AS Team, \
            properties($^).name AS Player;
    +-----------+-----------------+
    | Team      | Player          |
    +-----------+-----------------+
    | "Spurs"   | "Tony Parker"   |
    | "Hornets" | "Tony Parker"   |
    | "Spurs"   | "Manu Ginobili" |
    +-----------+-----------------+

    性能提示

    Nebula Graph 中的管道对性能有影响,以A | B为例,体现在以下几个方面:

    1. 管道是同步操作。也即需要管道之前的子句A执行完毕后,数据才能整体进入管道子句。

    2. 管道本身是需要序列化和反序列化的,这个是单线程执行的。

    3. 如果A发大量数据给 |,整个查询请求的总体时延可能会非常大。此时可以尝试拆分这个语句:

      1. 应用程序发送A

      2. 将收到的返回结果在应用程序拆分,

      3. 并发发送给多个 graphd,

      4. 每个 graphd 执行部分 B。

      这样通常比单个 graphd 执行完整地A | B要快很多。


     

    自定义变量

    Nebula Graph 允许将一条语句的结果作为自定义变量传递给另一条语句。

    OpenCypher 兼容性

    当引用一个变量的点、边或路径,需要先给它命名。例如:

     
    nebula> MATCH (v:player{name:"Tim Duncan"}) RETURN v;
    +----------------------------------------------------+
    | v                                                  |
    +----------------------------------------------------+
    | ("player100" :player{name: "Tim Duncan", age: 42}) |
    +----------------------------------------------------+
    

    示例中的v就是自定义变量。

    原生 nGQL

    nGQL 扩展的自定义变量可以表示为$var_namevar_name由字母、数字或下划线(_)构成,不允许使用其他字符。

    自定义变量仅在当前执行(本复合查询中)有效,执行结束后变量也会释放,不能在其他客户端、执行、session 中使用之前的自定义变量。

    用户可以在复合查询中使用自定义变量。复合查询的详细信息请参见复合查询

    Note

    自定义变量区分大小写。

    示例

     
    nebula> $var = GO FROM "player100" OVER follow YIELD dst(edge) AS id; \
            GO FROM $var.id OVER serve YIELD properties($$).name AS Team, \
            properties($^).name AS Player;
    +-----------+-----------------+
    | Team      | Player          |
    +-----------+-----------------+
    | "Spurs"   | "Tony Parker"   |
    | "Hornets" | "Tony Parker"   |
    | "Spurs"   | "Manu Ginobili" |
    +-----------+-----------------+

    引用属性

    用户可以在WHEREYIELD子句中引用点或边的属性。

    Note

    本功能仅适用于原生 nGQL 的 GO 语句。

    引用点的属性

    起始点

     
    $^.<tag_name>.<prop_name>
    
    参数说明
    $^ 起始点
    tag_name 点的 Tag 名称
    prop_name Tag 内的属性名称

    目的点

     
    $$.<tag_name>.<prop_name>
    
    参数说明
    $$ 目的点
    tag_name 点的 Tag 名称
    prop_name Tag 内的属性名称

    引用边的属性

    引用自定义的边属性

     
    <edge_type>.<prop_name>
    
    参数说明
    edge_type Edge type
    prop_name Edge type 的属性名称

    引用内置的边属性

    除了自定义的边属性,每条边还有如下四种内置属性:

    参数说明
    _src 边的起始点
    _dst 边的目的点
    _type 边的类型内部编码,正负号表示方向:正数为正向边,负数为逆向边
    _rank 边的 rank 值
     

    示例

     
    # 返回起始点的 Tag player 的 name 属性值和目的点的 Tag player 的 age 属性值。
    nebula> GO FROM "player100" OVER follow YIELD $^.player.name AS startName, $$.player.age AS endAge;
    +--------------+--------+
    | startName    | endAge |
    +--------------+--------+
    | "Tim Duncan" | 36     |
    | "Tim Duncan" | 41     |
    +--------------+--------+
    
    # 返回 Edge type follow 的 degree 属性值。
    nebula> GO FROM "player100" OVER follow YIELD follow.degree;
    +---------------+
    | follow.degree |
    +---------------+
    | 95            |
    +---------------+
    
    # 返回 EdgeType 是 follow 的起始点 VID、目的点 VID、EdgeType 编码(正数为正向边,负数为逆向边),和边的 rank 值。
    nebula> GO FROM "player100" OVER follow YIELD follow._src, follow._dst, follow._type, follow._rank;
    +-------------+-------------+--------------+--------------+
    | follow._src | follow._dst | follow._type | follow._rank |
    +-------------+-------------+--------------+--------------+
    | "player100" | "player101" | 17           | 0            |
    | "player100" | "player125" | 17           | 0            |
    +-------------+-------------+--------------+--------------+


    集合运算符

    合并多个请求时,可以使用集合运算符,包括UNIONUNION ALLINTERSECTMINUS

    所有集合运算符的优先级相同,如果一个 nGQL 语句中有多个集合运算符,Nebula Graph 会从左到右进行计算,除非用括号指定顺序。

    openCypher 兼容性

    集合运算符仅适用于原生 nGQL。

    UNION、UNION DISTINCT、UNION ALL

     
    <left> UNION [DISTINCT | ALL] <right> [ UNION [DISTINCT | ALL] <right> ...]
    
    • 运算符UNION DISTINCT(或使用缩写UNION)返回两个集合 A 和 B 的并集,不包含重复的元素。==》大数据???支持MR???不知道结果集如果1亿会怎么样?
    • 运算符UNION ALL返回两个集合 A 和 B 的并集,包含重复的元素。
    • leftright必须有相同数量的列和数据类型。如果需要转换数据类型,请参见类型转换

    示例

     
    # 返回两个查询结果的并集,不包含重复的元素。 ==》注意:dst表示目的节点,src表示源节点。
    nebula> GO FROM "player102" OVER follow YIELD dst(edge) \
            UNION \
            GO FROM "player100" OVER follow YIELD dst(edge);
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player100" |
    | "player101" |
    | "player125" |
    +-------------+
    
    # 返回两个查询结果的并集,包含重复的元素。
    nebula> GO FROM "player102" OVER follow YIELD dst(edge) \
            UNION ALL \
            GO FROM "player100" OVER follow YIELD dst(edge);
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player100" |
    | "player101" |
    | "player101" |
    | "player125" |
    +-------------+
    
    (root@nebula) [basketballplayer]>  GO FROM "player102" OVER follow YIELD dst(edge)
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player100" |
    | "player101" |
    +-------------+
    Got 2 rows (time spent 762/1013 us)
    
    Tue, 24 May 2022 15:37:02 CST
    
    (root@nebula) [basketballplayer]> GO FROM "player100" OVER follow YIELD dst(edge);
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player101" |
    | "player125" |
    +-------------+
    Got 2 rows (time spent 643/989 us)
    
    Tue, 24 May 2022 15:37:10 CST
    
    
    # UNION 也可以和 YIELD 语句一起使用,去重时会检查每一行的所有列,每列都相同时才会去重。
    nebula> GO FROM "player102" OVER follow \
            YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age \
            UNION /* DISTINCT */ \
            GO FROM "player100" OVER follow \
            YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age;
    +-------------+--------+-----+
    | id          | Degree | Age |
    +-------------+--------+-----+
    | "player100" | 75     | 42  |
    | "player101" | 75     | 36  |
    | "player101" | 95     | 36  |
    | "player125" | 95     | 41  |
    +-------------+--------+-----+

    补充:
    root@nebula) [basketballplayer]> GO FROM "player102" OVER follow \
                                   ->         YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age
    +-------------+--------+-----+
    | id          | Degree | Age |
    +-------------+--------+-----+
    | "player100" | 75     | 42  |
    | "player101" | 75     | 36  |
    +-------------+--------+-----+
    Got 2 rows (time spent 8448/8789 us)
    
    Tue, 24 May 2022 15:36:10 CST
    
    (root@nebula) [basketballplayer]>  GO FROM "player100" OVER follow \
                                   ->         YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age;
    +-------------+--------+-----+
    | id          | Degree | Age |
    +-------------+--------+-----+
    | "player101" | 95     | 36  |
    | "player125" | 95     | 41  |
    +-------------+--------+-----+
    Got 2 rows (time spent 1239/1517 us)
    
    Tue, 24 May 2022 15:36:19 CST
    

     

    INTERSECT

     
    <left> INTERSECT <right>
    
    • 运算符INTERSECT返回两个集合 A 和 B 的交集。
    • leftright必须有相同数量的列和数据类型。如果需要转换数据类型,请参见类型转换

    示例

     
    nebula> GO FROM "player102" OVER follow \
            YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age \
            INTERSECT \
            GO FROM "player100" OVER follow \
            YIELD dst(edge) AS id, properties(edge).degree AS Degree, properties($$).age AS Age;
    +----+--------+-----+
    | id | Degree | Age |
    +----+--------+-----+
    +----+--------+-----+
    

    MINUS

     
    <left> MINUS <right>
    

    运算符MINUS返回两个集合 A 和 B 的差异,即A-B。请注意leftright的顺序,A-B表示在集合 A 中,但是不在集合 B 中的元素。

    示例

     
    nebula> GO FROM "player100" OVER follow YIELD dst(edge) \
            MINUS \
            GO FROM "player102" OVER follow YIELD dst(edge);
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player125" |
    +-------------+
    
    nebula> GO FROM "player102" OVER follow YIELD dst(edge) \
            MINUS \
            GO FROM "player100" OVER follow YIELD dst(edge);
    +-------------+
    | dst(EDGE)   |
    +-------------+
    | "player100" |
    +-------------+
    

    集合运算符和管道符的优先级

    当查询包含集合运算符和管道符(|)时,管道符的优先级高。例如GO FROM 1 UNION GO FROM 2 | GO FROM 3相当于GO FROM 1 UNION (GO FROM 2 | GO FROM 3)

    示例

     
    nebula> GO FROM "player102" OVER follow \
            YIELD dst(edge) AS play_dst  \
            UNION \
            GO FROM "team200" OVER serve REVERSELY \
            YIELD src(edge) AS play_src \
            | GO FROM $-.play_src OVER follow YIELD dst(edge) AS play_dst;
    
    +-------------+
    | play_dst    |
    +-------------+
    | "player100" |
    | "player101" |
    | "player117" |
    | "player105" |
    +-------------+
    

    image

    该查询会先执行红框内的语句,然后执行绿框的UNION操作。

    圆括号可以修改执行的优先级,例如:

     
    nebula> (GO FROM "player102" OVER follow \
            YIELD dst(edge) AS play_dst  \
            UNION \
            GO FROM "team200" OVER serve REVERSELY \
            YIELD src(edge) AS play_dst) \
            | GO FROM $-.play_dst OVER follow YIELD dst(edge) AS play_dst;
    

    该查询中,圆括号包裹的部分先执行,即先执行UNION操作,再将结果结合管道符进行下一步操作。

     

    Schema 函数

    Nebula Graph 支持以下 Schema 函数。

    原生 nGQL 语句适用

    Note

    YIELD 和 WHERE 子句中可以使用如下函数。

    函数说明
    id(vertex) 返回点 ID。数据类型和点 ID 的类型保持一致。
    map properties(vertex) 返回点的所有属性。
    map properties(edge) 返回边的所有属性。
    string type(edge) 返回边的 Edge type。
    src(edge) 返回边的起始点 ID。数据类型和点 ID 的类型保持一致。
    dst(edge) 返回边的目的点 ID。数据类型和点 ID 的类型保持一致。
    int rank(edge) 返回边的 rank。
    vertex 返回点的信息。包括点 ID、Tag、属性和值。
    edge 返回边的信息。包括 Edge type、起始点 ID、目的点 ID、rank、属性和值。
    vertices 返回子图中的点的信息。详情参见 GET SUBGRAPH
    edges 返回子图中的边的信息。详情参见 GET SUBGRAPH
    path 返回路径信息。详情参见 FIND PATH

    Note

    由于 vertex、edge、vertices、edges、path 属于关键字,使用时需要用AS <alias>设置别名才能正常使用。例如GO FROM "player100" OVER follow YIELD edge AS e;

    openCypher 兼容语句适用

    函数说明
    id(<vertex>) 返回点 ID。数据类型和点 ID 的类型保持一致。
    list tags(<vertex>) 返回点的 Tag,与 labels() 作用相同。
    list labels(<vertex>) 返回点的 Tag,与 tags() 作用相同,用于兼容 openCypher 语法。
    map properties(<vertex_or_edge>) 返回点或边的所有属性。
    string type(<edge>) 返回边的 Edge type。
    src(<edge>) 返回边的起始点 ID。数据类型和点 ID 的类型保持一致。
    dst(<edge>) 返回边的目的点 ID。数据类型和点 ID 的类型保持一致。
    vertex startNode(<path>) 获取一条边或一条路径并返回它的起始点 ID。
    string endNode(<path>) 获取一条边或一条路径并返回它的目的点 ID。
    int rank(<edge>) 返回边的 rank。

    示例

     
    nebula> GO FROM "player100" OVER follow REVERSELY \
            YIELD src(edge) AS destination;
    +-------------+
    | destination |
    +-------------+
    | "player101" |
    | "player102" |
    ...
    
    nebula> LOOKUP ON player WHERE player.age  > 45 YIELD id(vertex);
    +-------------+
    | id(VERTEX)  |
    +-------------+
    | "player144" |
    | "player140" |
    +-------------+
    
    nebula> MATCH (a:player) WHERE id(a) == "player100" \
            RETURN tags(a), labels(a), properties(a); ==》这个应该是最常用的吧!有时候觉得这种语法,看得懂,自己闭着眼写还是很蛋疼的!
    +------------+------------+-------------------------------+
    | tags(a)    | labels(a)  | properties(a)                 |
    +------------+------------+-------------------------------+
    | ["player"] | ["player"] | {age: 42, name: "Tim Duncan"} |
    +------------+------------+-------------------------------+
    
    nebula> MATCH p = (a :player {name : "Tim Duncan"})-[r:serve]-(t) \
            RETURN type(r), rank(r);
    +---------+---------+
    | type(r) | rank(r) |
    +---------+---------+
    | "serve" | 0       |
    +---------+---------+
    
    nebula> MATCH p = (a :player {name : "Tim Duncan"})-[r:serve]-(t) \
            RETURN startNode(p), endNode(p);
    +----------------------------------------------------+----------------------------------+
    | startNode(p)                                       | endNode(p)                       |
    +----------------------------------------------------+----------------------------------+
    | ("player100" :player{age: 42, name: "Tim Duncan"}) | ("team204" :team{name: "Spurs"}) |
    +----------------------------------------------------+----------------------------------+
    

     

     

     

     
 
posted @ 2022-05-24 12:00  bonelee  阅读(1177)  评论(2编辑  收藏  举报