# displays all 'post'-type verticesCREATE QUERY printAllPosts() FOR GRAPH socialNet{start= {post.*}; # startis initialized with all vertices of type'post' results =SELECT s FROMstart:s; # select these verticesPRINT 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 FROMstart-(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 FROMstart-(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 FROMstart-(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 FROMstart-(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 FROMstart-((posted|liked):e)-> :t;# ----PRINT allPostsLiked;PRINT allPostsMade;PRINT allPostsLikedOrMade;}
# uses a SELECTstatementtoprintout 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 absolute number (or a percentage) of edges for each source vertex.
| SAMPLE expr TARGET WHEN condition # Sample an absolute number 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 FROMstart:s -(:e)-> :vSAMPLE1 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 FROMstart:s -(:e)-> :vSAMPLE33% 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 SELECTstatement, 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 SAMPLE1 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 verticesWHERE 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 useNOT operator in combination withtype attribute#females =SELECT v FROM allVertices:v# WHERENOT v.type !="person"AND# NOT v.gender =="Male"; # does not compile. cannot useNOT operator in combination withtype attribute#females =SELECT v FROM allVertices:v# WHERENOT v.type =="post"AND# NOT v.gender =="Male";personVertices = {person.*};females =SELECT v FROM personVertices:v WHERENOT 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 FROMstart:v -(worksFor:e)-> company:tWHERE e.fullTime;# fullTime is a boolean attribute on the edgePRINT fullTimeWorkers;}
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 pFROM 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 alltarget"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 FROMstart: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 FROMstart-(posted)-> :g ACCUM @@postTopicCounts += (g.subject ->1);PRINT @@postTopicCounts;}
#Show all person who both work and live in the same country
CREATE 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 givengender
CREATE QUERY personGender(STRING gender) FOR GRAPH socialNet {
SumAccum<INT> @@genderCount;
start = {ANY};
# Select all person vertices and check 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 made
CREATE 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 made
CREATE 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 or after (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 set
CREATE 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.gsql
Semantic Check Error in query printMemberAboutCats (SEM-50): line 8, col 33
The 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 number as friends
# and then in case of a tie by the number of coworkers
CREATE 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; # case 1: k = Count
result = SELECT v FROM S -(:e)-> :v LIMIT j, k; # case 2: j = Offset from the start of the list, k = Count
result = SELECT v FROM S -(:e)-> :v LIMIT k OFFSET j; # case 3: 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
}