# displays all 'post'-type vertices
CREATE QUERY printAllPosts() FOR GRAPH socialNet
{
start = {post.*}; # start is 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; //Select from the source set
resultSet2 = SELECT t FROM Source:s-(eType:e)->tType:t; //Select from the target set
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) to print out
# 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
# start with the vertex set from above, and traverse all edges of type "posted"
# (locally those edges are just given a name 'e' in case they need accessed)
# and return all vertices of type 'post' which can be reached within one-hop of 'start' vertices
allPostsMade = SELECT targetVertex FROM start -(posted:e)-> post:targetVertex;
# start with the vertex set from above, and traverse all edges of type "posted"
# (locally those edges are just given a name 'e' in case they need accessed)
# and return all vertices of any type which can be reached within one-hop of 'start' vertices
allPostsMade = 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 types
allPostsLikedOrMade = 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 statement to print out everything related to a given user
# this includes posts that the user liked, posts that the user made, and friends
# of the user
CREATE 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 set using one edge of any type
everythingRelated = 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 statement is 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 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 set is formed by those vertices which can be
# reached when for 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 use 1 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 vertices
WHERE 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 person
females = 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 with type 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 with type 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 time at some company
CREATE QUERY fullTimeWorkers() FOR GRAPH workNet
{
start = {person.*};
fullTimeWorkers = SELECT v FROM start:v -(worksFor:e)-> company:t
WHERE e.fullTime;# fullTime is a boolean attribute on the edge
PRINT 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 src
FROM likedPosts:src
ACCUM
FOREACH v IN src.@posters DO
v.@fellows += src.@posters
END
ORDER BY src.subject;
PRINT Persons[Persons.@fellows];
}
#Show Accum PostAccum Behavior
CREATE 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 start set with all company vertices
start = {company.*};
#Select all vertices in source set start
selectVertexSet = SELECT v from start:v
#Happens once for each vertex discovered
ACCUM @@vertexOnlyAccum += 1
#Happens once for each vertex in the result set "v"
POST-ACCUM @@vertexOnlyPostAccum += 1;
#Select all vertices in source set start with a where constraint
selectVertexSetWhere = SELECT v from start:v WHERE (v.country == "us")
#Happens once for each vertex discovered that also
# meets the constraint condition
ACCUM @@vertexOnlyWhereAccum += 1
#Happens once for each vertex in the result set "v"
POST-ACCUM @@vertexOnlyWherePostAccum += 1;
#Select all source "s" vertices in set start and explore all "worksFor" edge paths
selectSourceWithEdge = SELECT s from start: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 from set start
selectTargetWithEdge = SELECT t from start: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 subjects
CREATE QUERY userPosts() FOR GRAPH socialNet {
ListAccum<STRING> @personPosts;
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.subject;
PRINT userPostings;
}
# Show each user's post and liked post time
CREATE 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 topic
CREATE QUERY userPostsByTopic() FOR GRAPH socialNet {
MapAccum<STRING, INT> @@postTopicCounts;
start = {person.*};
# Append subject and update 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 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
}