# displays all 'post'-type verticesCREATE QUERY printAllPosts() FOR GRAPH socialNet{start= {post.*}; # startis initialized with all vertices of type'post' results = SELECT s FROM start:s; # select these vertices PRINT results;}
resultSet1 = SELECT s FROM Source:s-(eType:e)->tType:t; //Selectfrom the source setresultSet2 = SELECT t FROM Source:s-(eType:e)->tType:t; //Selectfrom the targetset
resultSet3 = SELECT v FROM Source:v-(eType:e)->(V1|V2):t;resultSet4 = SELECT v FROM Source:v-(eType:e)->:t;resultSet5 = SELECT v FROM Source:v-(eType:e)->ANY:t;resultSet6 = SELECT v FROM Source:v-(eType:e)->_:t;
resultSet7 = SELECT v FROM Source:v-((E1|E2|E3):e)->tType:t;resultSet8 = SELECT v FROM Source:v-(:e)->tType:t;resultSet9 = SELECT v FROM Source:v-(_:e)->tType:t;resultSet10 = SELECT v FROM Source:v-(ANY:e)->tType:t;
# uses various SELECT statements (some of which are equivalent) toprintout# either the posts made by the given user, the posts liked by the given# user, or the posts made or liked by the given user.CREATE QUERY printAllPosts2(vertex<person> seed) FOR GRAPH socialNet{start= {seed}; # initialize starting set of vertices# --- statements produce equivalent results# select all'post' vertices which can be reached from'start'in one hop# using an edge of type'liked'allPostsLiked = SELECT targetVertex FROM start-(liked:e)-> post:targetVertex;# select all vertices of any type which can be reached from'start'in one hop# using an edge of type'liked'allPostsLiked = SELECT targetVertex FROM start-(liked:e)-> :targetVertex;# ----# --- statements produce equivalent results# startwith the vertex setfrom above, and traverse all edges of type"posted" # (locally those edges are just given a name'e'incase they need accessed) # andreturn all vertices of type'post' which can be reached within one-hop of 'start' verticesallPostsMade = SELECT targetVertex FROM start-(posted:e)-> post:targetVertex;# startwith the vertex setfrom above, and traverse all edges of type"posted" # (locally those edges are just given a name'e'incase they need accessed) # andreturn all vertices of any type which can be reached within one-hop of 'start' verticesallPostsMade = SELECT targetVertex FROM start-(posted:e)-> :targetVertex;# ----# --- statements produce equivalent results# select all vertices of type'post' which can be reached from'start'in one hop# using an edge of any type# not equivalent to any statement. because it doesn't restrict the edge type,# this will include any vertex connected by 'liked' or 'posted' edge typesallPostsLikedOrMade = SELECT t FROM start -(:e)-> t;# select all vertices of type 'post' which can be reached from 'start' in one hop#using an edge of type either 'posted' or 'liked'allPostsLikedOrMade = SELECT t FROM start -((posted|liked):e)-> post:t;# select all vertices of any type which can be reached from 'start' in one hop#using an edge of type either 'posted' or 'liked/allPostsLikedOrMade = SELECT t FROM start-((posted|liked):e)-> :t;# ----PRINT allPostsLiked; PRINT allPostsMade; PRINT allPostsLikedOrMade;}
# uses a SELECT statementtoprintout everything related to a given user# this includes posts that the user liked, posts that the user made, and friends# of the userCREATE QUERY printAllRelatedItems(vertex<person> seed) FOR GRAPH socialNet{sourceVertex = {seed};# -- statements produce equivalent output# returns all vertices of type either 'person'or'post' that can be reached# from the sourceVertex setusing one edge of any typeeverythingRelated = SELECT v FROM sourceVertex -(:e)-> (person|post):v;# returns all vertices of any type that can be reached from the sourceVertex# using one edge of any type# this statementis equivalent to the above one because the graph schema only#has vertex types of either 'person'or'post'. if there were more vertex#types present, these would not be equivalent.everythingRelated = SELECT v FROM sourceVertex -(:e)-> :v;# --PRINT everythingRelated;}
sampleClause := SAMPLE ( expr | expr "%" ) EDGE WHEN condition # Sample an absolutenumber (or a percentage) of edges for each source vertex. | SAMPLE expr TARGET WHEN condition # Sample an absolutenumber of edges incident to each target vertex. | SAMPLE expr "%" TARGET PINNED WHEN condition # Sample a percentage of edges incident to each target vertex.
CREATE QUERY sampleEx3() FOR GRAPH computerNet{ MapAccum<STRING,ListAccum<STRING>> @@absEdges; // record each selected edge as (src->tgt) SumAccum<INT> @@totalAbs; MapAccum<STRING,ListAccum<STRING>> @@pctEdges; // record each selected edge as (src->tgt) SumAccum<INT> @@totalPct;start= {computer.*};# Sample one outgoing edge per source vertex = Random Walk absSample = SELECT v FROM start:s -(:e)-> :v SAMPLE 1 EDGE WHEN s.outdegree() >=1 # sample1target vertex from each source vertex ACCUM @@absEdges += (s.id -> v.id), @@totalAbs +=1; PRINT @@totalAbs, @@absEdges; pctSample = SELECT v FROM start:s -(:e)-> :v SAMPLE 33% EDGE WHEN s.outdegree() >=3 # select ~1/3 of edges when outdegree >=3 ACCUM @@pctEdges += (s.id -> v.id), @@totalPct +=1; PRINT @@totalPct, @@pctEdges;}
CREATE QUERY sampleEx1() FOR GRAPH workNet{SumAccum<INT> @timesTraversedNoSample;SumAccum<INT> @timesTraversedWithSample;workers = {person.*};# The 'beforeSample' result set encapsulates the normal functionality of# a SELECT statement, where'timesTraversedNoSample' vertex accumulator is increased for# each edge incident to the vertex.beforeSample = SELECT v FROM workers:t -(:e)-> :v ACCUM v.@timesTraversedNoSample +=1;# The 'afterSample' result setis formed by those vertices which can be# reached whenfor each source vertex, only one edge is used for traversal.# This is demonstrated by the values of 'timesTraversedWithSample' vertex accumulator, which# is increased for each edge incident to the vertex which is used in the# sample.afterSample = SELECT v FROM workers:t -(:e)-> :v SAMPLE 1 EDGE WHEN t.outdegree() >=1# only use1 edge from the source vertex ACCUM v.@timesTraversedWithSample +=1;PRINT beforeSample;PRINT afterSample;}
resultSet1 = SELECT v FROM S:v-((E1|E2|E3):e)->(V1|V2):t;resultSet2 = SELECT v FROM S:v-(:e)->:t WHERE t.type IN ("V1", "V2") AND t IN v.neighbors("E1|E2|E3")
下面的示例中,WHERE子句根据顶点属性限定了对应输出的结果集的内容
基本的SELECT WHERE语法
CREATE QUERY printCatPosts() FOR GRAPH socialNet {posts = {post.*};catPosts = SELECT v FROM posts:v# select only those post vertices WHERE v.subject =="cats"; # which have a subset of 'cats'PRINT catPosts;}
CREATE QUERY findGraphFocusedPosts() FOR GRAPH socialNet{posts = {post.*};results = SELECT v FROM posts:v# select only post verticesWHERE v.subject IN ("Graph", "tigergraph");# which have a subject of either 'Graph'or'tigergraph'PRINT results;}
# finds female person in the social network. all of the following statements# are equivalent (i.e., produce the same results)CREATE QUERY findFemaleMembers() FOR GRAPH socialNet{allVertices = {ANY}; # includes all posts and personfemales = SELECT v FROM allVertices:v WHERE v.type =="person" AND v.gender !="Male";females = SELECT v FROM allVertices:v WHERE v.type =="person" AND v.gender =="Female";females = SELECT v FROM allVertices:v WHERE v.type =="person" AND NOT v.gender =="Male";females = SELECT v FROM allVertices:v WHERE v.type !="post" AND NOT v.gender =="Male"; # does not compile. cannot use NOT operator in combination withtype attribute#females = SELECT v FROM allVertices:v# WHERE NOT v.type !="person" AND# NOT v.gender =="Male"; # does not compile. cannot use NOT operator in combination withtype attribute#females = SELECT v FROM allVertices:v# WHERE NOT v.type =="post" AND# NOT v.gender =="Male";personVertices = {person.*};females = SELECT v FROM personVertices:v WHERE NOT v.gender =="Male";females = SELECT v FROM personVertices:v WHERE v.gender !="Male";females = SELECT v FROM personVertices:v WHERE v.gender !="Male" AND true;females = SELECT v FROM personVertices:v WHERE v.gender !="Male"OR false;PRINT females;}
# find all workers who are full timeat some companyCREATE QUERY fullTimeWorkers() FOR GRAPH workNet{start= {person.*};fullTimeWorkers = SELECT v FROM start:v -(worksFor:e)-> company:tWHERE e.fullTime;# fullTime is a boolean attribute on the edgePRINT fullTimeWorkers;}
CREATE QUERY multipleEdgeTypeCheckEx2(vertex<person> m1) FOR GRAPH socialNet { ListAccum<STRING> @@testList1; allUser = {m1}; allUser = SELECT s FROM allUser:s - ((posted|liked|friend):e) -> (post|person):t ACCUM CASE WHEN e.type =="liked" THEN # for liked edges @@testList1 += to_string(datetime_to_epoch(e.actionTime)) WHEN e.type =="friend" THEN # for friend edges @@testList1 += t.gender ELSE # For the remained edge type, which is posted edges @@testList1 += to_string(datetime_to_epoch(t.postTime)) END ; PRINT @@testList1;}
CREATE QUERY vUpdateIndirectAccum() FOR GRAPH socialNet { SetAccum<VERTEX<person>> @posters; SetAccum<VERTEX<person>> @fellows; Persons = {person.*};# To each post, attach a list of persons who liked the post likedPosts = SELECT p FROM Persons:src -(liked:e)-> post:p ACCUM p.@posters += src;# To each person who liked a post, attach a list of everyone# who also liked one of this person's liked posts.likedPosts = SELECT srcFROM likedPosts:srcACCUM FOREACH v IN src.@posters DO v.@fellows += src.@posters END ORDER BY src.subject; PRINT Persons[Persons.@fellows];}
#Show Accum PostAccum BehaviorCREATE QUERY accumPostAccumSemantics() FOR GRAPH workNet { SumAccum<INT> @@vertexOnlyAccum; SumAccum<INT> @@vertexOnlyPostAccum; SumAccum<INT> @@vertexOnlyWhereAccum; SumAccum<INT> @@vertexOnlyWherePostAccum; SumAccum<INT> @@sourceWithEdgeAccum; SumAccum<INT> @@sourceWithEdgePostAccum; SumAccum<INT> @@targetWithEdgeAccum; SumAccum<INT> @@targetWithEdgePostAccum;#Seed startsetwith all company verticesstart= {company.*};#Select all vertices in source setstart selectVertexSet = SELECT v fromstart:v#Happens once for each vertex discoveredACCUM @@vertexOnlyAccum +=1#Happens once for each vertex in the result set"v"POST-ACCUM @@vertexOnlyPostAccum +=1;#Select all vertices in source setstartwith a whereconstraint selectVertexSetWhere = SELECT v fromstart:v WHERE (v.country =="us")#Happens once for each vertex discovered that also# meets the constraint conditionACCUM @@vertexOnlyWhereAccum +=1#Happens once for each vertex in the result set"v"POST-ACCUM @@vertexOnlyWherePostAccum +=1;#Select all source "s" vertices insetstartand explore all "worksFor" edge paths selectSourceWithEdge = SELECT s fromstart:s -(worksFor)-> :t #Happens once for each "worksFor" edge discovered ACCUM @@sourceWithEdgeAccum +=1#Happens once for each vertex in result set"s" (source)POST-ACCUM @@sourceWithEdgePostAccum +=1;#Select all target"t" vertices found from exploring all "worksFor" edge paths fromsetstart selectTargetWithEdge = SELECT t fromstart:s -(worksFor)-> :t #Happens once for each "worksFor" edge discovered ACCUM @@targetWithEdgeAccum +=1 #Happens once for each vertex in result set"t" (target) POST-ACCUM @@targetWithEdgePostAccum +=1; PRINT @@vertexOnlyAccum; PRINT @@vertexOnlyPostAccum; PRINT @@vertexOnlyWhereAccum; PRINT @@vertexOnlyWherePostAccum; PRINT @@sourceWithEdgeAccum; PRINT @@sourceWithEdgePostAccum; PRINT @@targetWithEdgeAccum; PRINT @@targetWithEdgePostAccum;}
# For each person, make a list of all their post subjectsCREATE QUERY userPosts() FOR GRAPH socialNet { ListAccum<STRING> @personPosts;start= {person.*};# Find all user post topics andappend them to the vertex list accum userPostings = SELECT s FROM start:s -(posted)-> :g ACCUM s.@personPosts += g.subject; PRINT userPostings;}
# Show each user's post and liked post timeCREATE QUERY userPosts2() FOR GRAPH socialNet { ListAccum<VERTEX> @personPosts; ListAccum<EDGE> @personLikedInfo; start = {person.*}; # Find all user post topics and append them to the vertex list accum userPostings = SELECT s FROM start:s -(posted)-> :g ACCUM s.@personPosts += g; userPostings = SELECT s from start:s -(liked:e)-> :g ACCUM s.@personLikedInfo += e; PRINT start;}
# Show number of total posts by topicCREATE QUERY userPostsByTopic() FOR GRAPH socialNet { MapAccum<STRING, INT> @@postTopicCounts;start= {person.*};# Appendsubjectandupdate the appearance count in the global map accum posts = SELECT g FROM start-(posted)-> :g ACCUM @@postTopicCounts += (g.subject ->1); PRINT @@postTopicCounts;}
#Show all person who both work and live in the same countryCREATE QUERY residentEmployees() FOR GRAPH workNet { ListAccum<STRING> @company; OrAccum @worksAndLives;start= {person.*}; employees = SELECT s FROM start:s -(worksFor)-> :c#If a person works for a company in the same country where they live# add the company to the list ACCUM CASE WHEN (s.locationId == c.country) THEN s.@company += c.id END#Check each vertex and see if a person works where they live POST-ACCUM CASE WHEN (s.@company.size() >0) THEN s.@worksAndLives += True ELSE s.@worksAndLives += False END; PRINT employees WHERE (employees.@worksAndLives == True);}
#Count the number of person ofa givengenderCREATE QUERY personGender(STRING gender) FOR GRAPH socialNet { SumAccum<INT> @@genderCount;start= {ANY};# Select all person vertices andcheck the gender attribute friends = SELECT v FROM start:v WHERE v.type =="person" POST-ACCUM CASE WHEN (start.gender == gender) THEN @@genderCount +=1 END; PRINT @@genderCount;}
# find all persons meeting a given activityThreshold, based on how many posts or likes a person has madeCREATE QUERY activeMembers(int activityThreshold) FOR GRAPH socialNet{ SumAccum<int> @activityAmount;start= {person.*}; result = SELECT v FROM start:v -(:e)-> post:tgt ACCUM v.@activityAmount +=1 HAVING v.@activityAmount >= activityThreshold; PRINT result;}
# find all person meeting a given activityThreshold, based on how many posts or likes a person has madeCREATE QUERY printMemberActivity() FOR GRAPH socialNet{ SumAccum<int> @activityAmount;start= {person.*};### --- equivalent statements ----- result = SELECT v FROM start:v -(:e)-> post:tgt ACCUM v.@activityAmount +=1 HAVING true;result = SELECT v FROM start:v -(:e)-> post:tgt ACCUM v.@activityAmount +=1;### ----- PRINT result;}
# Compute the total post activity for each male person.# Because the gender of the vertex does not change, evaluating whether the person vertex# is male before (WHERE) the ACCUM clause orafter (HAVING) the ACCUM clause does not# change the result. However, if the condition in the HAVING clause could change within# the ACCUM clause, these statements would produce different results.CREATE QUERY activeMaleMembers() FOR GRAPH socialNet{ SumAccum<INT> @activityAmount;start= {person.*};### --- statements produce equivalent results result1 = SELECT v FROM start:v -(:e)-> post:tgt WHERE v.gender =="Male" ACCUM v.@activityAmount +=1; result2 = SELECT v FROM start:v -(:e)-> post:tgt ACCUM v.@activityAmount +=1 HAVING v.gender =="Male"; PRINT result2[result2.@activityAmount]; PRINT result2[result2.@activityAmount];}
# find all person having a post subject about cats# This query is illegal because the having condition is testing the wrong vertex setCREATE QUERY printMemberAboutCats() FOR GRAPH socialNet{start= {person.*}; result = SELECT v FROM start:v -(:e)-> post:tgt HAVING tgt.subject =="cats"; PRINT result;}
printMemberAboutCats的编译错误
> gsql printMemberAboutCats.gsqlSemantic Check Error in query printMemberAboutCats (SEM-50): line8, col 33The SELECT block selects src, but the HAVING clause uses tgt
排序子句(ORDER BY)
排序子句是可选的,通过它可以对结果集进行排序。
排序子句的EBNF范式
orderClause := ORDER BY expr [ASC | DESC]["," expr [ASC | DESC]]*
# find the most popular people, sorting first based on the numberas friends# andthenincase of a tie by the number of coworkersCREATE QUERY topPopular() FOR GRAPH friendNet{SumAccum<INT> @numFriends;SumAccum<INT> @numCoworkers;start= {person.*};result = SELECT v FROM start-((friend|coworker):e)-> person:v ACCUM CASE WHEN e.type =="friend" THEN v.@numFriends +=1 WHEN e.type =="coworker" THEN v.@numCoworkers +=1 END ORDER BY v.@numFriends DESC, v.@numCoworkers DESC;PRINT result;}
result = SELECT v FROM S -(:e)-> :v LIMIT k; # case1: k = Countresult = SELECT v FROM S -(:e)-> :v LIMIT j, k; # case2: j = Offset from the start of the list, k = Countresult = SELECT v FROM S -(:e)-> :v LIMIT k OFFSET j; # case3: k = Count, j = Offset from the start of the list
CREATE QUERY limitEx1(INT k) FOR GRAPH friendNet{start= {person.*}; result1 = SELECT v FROM start:v ORDER BY v.id LIMIT k;PRINT result1[result1.id]; // api v2}
CREATE QUERY limitEx2(INT j, INT k) FOR GRAPH friendNet{start= {person.*}; result2 = SELECT v FROM start:v ORDER BY v.id LIMIT j, k; PRINT result2[result2.id]; // api v2}
CREATE QUERY limitEx3(INT j, INT k) FOR GRAPH friendNet{start= {person.*}; result3 = SELECT v FROM start:v ORDER BY v.id LIMIT k OFFSET j; PRINT result3[result3.id]; // api v2}