什么是 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 9 | nGQL |
Schema | 弱 Schema | 强 Schema |
相等运算符 |
|
|
数学求幂 |
| 使用 |
边 Rank | 无此概念 | 用 |
语句 | - | 不支持 openCypher 9 的所有 DML 语句(如 |
语句文本换行 | 换行符 |
|
Label 与 Tag 是不同的概念 | Label 用于寻找点(点的索引)。 | Tag 用于定义点的一种类型及相应的属性,无索引功能。 |
预编译与参数化查询 | 支持 | 仅支持参数化查询。 |
Compatibility
请注意 openCypher 9 和 Cypher 在语法和许可上有不同:
- Cypher 要求所有 Cypher 语句必须“显式地在一个事务中”执行,而 openCypher 没有这样的要求。另外,nGQL 没有事务及隔离性。
- 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)。
- 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 | | |
示例中的关键字说明如下。
关键字 | 说明 |
| 描述当前文档的主题。 |
| 描述当前文档的背景信息。 |
| 描述执行示例语句的前提条件。 |
| 描述具体场景。如果场景之前有 |
| 描述要执行的 nGQL 示例语句。可以是 |
| 描述执行 |
| 描述执行 |
| 跳过这个示例。通常表示测试代码还没有准备好。 |
欢迎增加更多 tck case,在 CI/CD 中自动回归所使用的语句。
是否支持 TinkerPop Gremlin?¶
不支持。也没有计划。
是否支持 W3C 的 RDF(SPARQL) 或 GraphQL 等?¶
不支持。也没有计划。
Nebula Graph 的数据模型是属性图,是一个强 Schema 系统,不支持 RDF 标准。
nGQL 也不支持 SPARQL 和 GraphQL。
模式¶
模式(pattern)和图模式匹配,是图查询语言的核心功能,本文介绍 Nebula Graph 设计的各种模式,部分还未实现。
单点模式¶
点用一对括号来描述,通常包含一个名称。例如:
(a)
示例为一个简单的模式,描述了单个点,并使用变量a
命名该点。
多点关联模式¶
多个点通过边相连是常见的结构,模式用箭头来描述两个点之间的边。例如:
(a)-[]->(b)
示例为一个简单的数据结构:两个点和一条连接两个点的边,两个点分别为a
和b
,边是有方向的,从a
到b
。
这种描述点和边的方式可以扩展到任意数量的点和边,例如:
(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_space
和MY_SPACE
是两个不同的图空间。
nebula> CREATE SPACE IF NOT EXISTS my_space (vid_type=FIXED_STRING(30));
nebula> use MY_SPACE;
[ERROR (-1005)]: SpaceNotFound:
关键字不区分大小写¶
以下语句是等价的,因为show
和spaces
是关键字。
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 不同。
换行¶
- 换行写子句。
不推荐:
GO FROM "player100" OVER follow REVERSELY YIELD src(edge) AS id;
推荐:
GO FROM "player100" \
OVER follow REVERSELY \
YIELD src(edge) AS id;
- 换行写复合语句中的不同语句。
不推荐:
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;
- 子句长度超过 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 语句中,关键字、标点符号、空格以外的字符内容都是标识符。推荐的标识符命名方式如下。
- 使用单数名词命名 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);
- 标识符用蛇形命名法,以下划线(_)连接单词,且所有字母小写。
不推荐:
MATCH (v:basketballTeam) \
RETURN v;
推荐:
MATCH (v:basketball_team) \
RETURN v;
- 语法关键词大写,变量小写。
不推荐:
go from "player100" over Follow
推荐:
GO FROM "player100" OVER follow
Pattern¶
- 分行写 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;
- 将无需查询的点和边匿名化。
不推荐:
MATCH (v:player)-[e:follow]->(v2) \
RETURN v;
推荐:
MATCH (v:player)-[:follow]->() \
RETURN v;
(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"}) |
- 将非匿名点放在匿名点的前面。
不推荐:
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.";
结束语句¶
- 用英文分号(;)结束 nGQL 语句。
不推荐:
FETCH PROP ON player "player100"
推荐:
FETCH PROP ON player "player100";
- 使用管道符(|)分隔的复合语句,仅在最后一行末用英文分号结尾。在管道符前使用英文分号会导致语句执行失败。
不支持:
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;
- 在包含自定义变量的复合语句中,用英文分号结束定义变量的语句。不按规则加分号或使用管道符结束该语句会导致执行失败。
不支持:
$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
,用户也可以设置属性值不允许为NULL
(NOT NULL
),即插入点或边时必须设置该属性的值,除非创建属性时已经设置默认值。
示例¶
使用 NOT NULL¶
创建 Tag,名称为player
,指定属性name
为NOT NULL
。
nebula> CREATE TAG IF NOT EXISTS player(name string NOT NULL, age int);
使用SHOW
命令查看创建 Tag 语句,属性name
为NOT 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
,指定属性age
为NOT 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
- 越界的下标返回为空,未越界的可以正常返回。
-
M
≥N
时,返回为空。 - 查询单个元素时,如果
M
为 null,返回报错BAD_TYPE
;范围查询时,M
或N
为 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 兼容语句(
MATCH
、RETURN
、WITH
等),请不要使用管道符或分号组合子句。 - 如果使用原生 nGQL 语句(
FETCH
、GO
、LOOKUP
等),必须使用管道符或分号组合子句。
行为未定义
不要混用 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
为例,体现在以下几个方面:
- 管道是同步操作。也即需要管道之前的子句
A
执行完毕后,数据才能整体进入管道子句。 - 管道本身是需要序列化和反序列化的,这个是单线程执行的。
- 如果
A
发大量数据给|
,整个查询请求的总体时延可能会非常大。此时可以尝试拆分这个语句:
- 应用程序发送
A
, - 将收到的返回结果在应用程序拆分,
- 并发发送给多个 graphd,
- 每个 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_name
,var_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" |
+-----------+-----------------+
引用属性¶
用户可以在WHERE
和YIELD
子句中引用点或边的属性。
Note
本功能仅适用于原生 nGQL 的 GO 语句。
引用点的属性¶
起始点¶
$^.<tag_name>.<prop_name>
参数 | 说明 |
| 起始点 |
| 点的 Tag 名称 |
| Tag 内的属性名称 |
目的点¶
$$.<tag_name>.<prop_name>
参数 | 说明 |
| 目的点 |
| 点的 Tag 名称 |
| Tag 内的属性名称 |
引用边的属性¶
引用自定义的边属性¶
<edge_type>.<prop_name>
参数 | 说明 |
| Edge type |
| Edge type 的属性名称 |
引用内置的边属性¶
除了自定义的边属性,每条边还有如下四种内置属性:
参数 | 说明 |
| 边的起始点 |
| 边的目的点 |
| 边的类型内部编码,正负号表示方向:正数为正向边,负数为逆向边 |
| 边的 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 |
+-------------+-------------+--------------+--------------+
集合运算符¶
合并多个请求时,可以使用集合运算符,包括UNION
、UNION ALL
、INTERSECT
和MINUS
。
所有集合运算符的优先级相同,如果一个 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 的并集,包含重复的元素。
-
left
和right
必须有相同数量的列和数据类型。如果需要转换数据类型,请参见类型转换。
示例¶
# 返回两个查询结果的并集,不包含重复的元素。 ==》注意: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 的交集。
-
left
和right
必须有相同数量的列和数据类型。如果需要转换数据类型,请参见类型转换。
示例¶
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
。请注意left
和right
的顺序,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" |
+-------------+
该查询会先执行红框内的语句,然后执行绿框的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"}) |
+----------------------------------------------------+----------------------------------+