表达式是将常数,变量,运算符,函数调用和分组进行整合后的一种形式。表达式定 义了计算方法,并从而使得运算可以得到结果。 “规范”一节详述了 GSQL 图形查询 语言中可用的文字表述(常数),运算符和函数。 它涵盖了下面的定义。 但是,与 “规范”一章中的其他部分相比,该语法述本身并不够充分。 特定运算符和函数的 语义(功能)是该语法的必要补充。
Copy constant := numeric | stringLiteral | TRUE | FALSE | GSQL_UINT_MAX | GSQL_INT_MAX | GSQL_INT_MIN | TO_DATETIME "(" stringLiteral ")"
mathOperator : = "*" | "/" | "%" | "+" | "-" | "<<" | ">>" | "&" | "|"
comparisonOperator : = "<" | "<=" | ">" | ">=" | "==" | "!=" condition : = expr
expr : =
|
| | | |
condition | |
name ]
| expr comparisonOperator expr | expr [ NOT ] IN setBagExpr
| expr IS [ NOT ] NULL
| expr BETWEEN expr AND expr
| "(" condition ")"
| NOT condition
| condition ( AND | OR ) condition | (TRUE | FALSE)
["@@"] name
name "." "type"
name "." ["@"] name
name "." "@" name ["\'"]
name "." name "." name "(" [argList] ")"
name "." name "(" [argList] ")" [ ".".FILTER "(" ")" ]
name ["<" type ["," type"] * ">" ] "(" [argList] ")" name "." "@" name ( "." name "(" [argList] ")" ) + [ "."
"@@" name ( "." name "(" [argList] ")" ) + ["." name] COALESCE "(" [argList] ")"
( COUNT | ISEMPTY | MAX | MIN | AVG | SUM ) "("
| | |
setBagExpr ")"
| expr mathOperator expr
| "-" expr
| "(" expr ")"
| "(" argList "->" argList ")"
| "[" argList "]"
| constant
| setBagExpr
| name "(" argList ")"
setBagExpr : = ["@@"] name
| name "." ["@"] name
// key value pair for // a list
MapAccum
| name "." "@" name ( "." name "(" [argList] ")" ) +
| name "." name "(" [argList] ")" [ ".".FILTER "(" condition ")" ]
| "@@" name ( "." name "(" [argList] ")" ) +
| setBagExpr ( UNION | INTERSECT | MINUS) setBagExpr | "(" argList ")"
| "(" setBagExpr ")"
argList : = expr ["," expr] *
Microsoft Word - [Tran]Part-2---Querying-(FINAL-c)_RV20181120.docx
常数
Copy constant := numeric | stringLiteral | TRUE | FALSE | GSQL_UINT_MAX | GSQL_INT_MAX | GSQL_INT_MIN | TO_DATETIME "(" stringLiteral ")"
常数的基本数据类型:
GSL_UINT_MAX = 2 ^ 64 - 1 = 18446744073709551615
GSQL_INT_MAX = 2 ^ 63 - 1 = 9223372036854775807
GSQL_INT_MIN = -2 ^ 63 = -9223372036854775808
运算符
运算符是一种关键词的标记。它将相邻的表达式(其操作数)作为输入值,运行特定的计算并返回结果。 运算符与函数类似,因为它们都根据输入的数据计算结果,但在语法上它们是不同的。 我们最熟悉的运算符是加号和减号。
提示:本节中列出的运算符与MySQL的运算符相似。
数学运算符和表达式
本语言支持以下标准的数学运算符和及其定义。 后四个(“<<”|“>>”|“&”|“|”)用于逐位运算。 详见之后的“比特运算符”一节。
Copy mathOperator : = "*" | "/" | "%" | "+" | "-" | "<<" | ">>" | "&" | "|"
下表列出了运算符的优先级,从高到低。 同一行中的运算符具有相同的优先级:
Copy * , / , %
- , +
<< , >>
&
|
== , >= , > , <= , < , !=
Copy CREATE QUERY mathOperators() FOR GRAPH minimalNet api( "v2" )
{
int x,y;
int z1,z2,z3,z4,z5;
float f1,f2,f3,f4;
x = 7 ;
y = 3 ;
z1 = x * y; # z = 21
z2 = x - y; # z = 4
z3 = x + y; # z = 10
z4 = x / y; # z = 2
z5 = x / 4 . 0 ; # z = 1
f1 = x / y; # v = 2
f2 = x / 4 . 0 ; # v = 1 . 75
f3 = x % 3 ; # v = 1
f4 = x % y; # z = 1
PRINT x,y;
PRINT z1 AS xTIMESy, z2 AS xMINUSy, z3 AS xPLUSy, z4 AS xDIVy, z5 AS xDIV4f;
PRINT f1 AS xDIVy, f2 AS xDIV4f, f3 AS xMOD3, f4 AS xMODy;
}
Copy GSQL > RUN QUERY mathOperators()
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{
"x" : 7 ,
"y" : 3
},
{
"xTIMESy" : 21 ,
"xPLUSy" : 10 ,
"xMINUSy" : 4 ,
"xDIVy" : 2 ,
"xDIV4f" : 1
},
{
"xMODy" : 1 ,
"xMOD3" : 1 ,
"xDIVy" : 2 ,
"xDIV4f" : 1 . 75
}
]
}
布尔运算符
我们支持标准布尔运算符和标准优先顺序:AND,OR,NOT
比特运算符
比特运算符(<<,>>,&和|)对整数进行操作并返回整数。
Copy CREATE QUERY bitOperationTest() FOR GRAPH minimalNet{
PRINT 80 >> 2 ; # 20
PRINT 80 << 2 ; # 320
PRINT 2 + 80 >> 4 ; # 5
PRINT 2 | 3 ; # 3
PRINT 2 & 3 ; # 2
PRINT 2 | 3 + 2 ; # 7
PRINT 2 & 3 - 2 ; # 0
}
字符串运算符
运算符加号(+)可以被用于串联字符串
元组字段
元组的字段可以通过使用点运算符获取
比较运算符和条件
条件是一种表达式,其值为布尔值true或false。各种类型的条件都使用其常用的比较运算符。比较运算符用于比较两个条件值。
Copy comparisonOperator : = "<" | "<=" | ">" | ">=" | "==" | "!="
condition : = expr
| expr comparisonOperator expr
| expr [ NOT ] IN setBagExpr
| expr IS [ NOT ] NULL
| expr BETWEEN expr AND expr
| "(" condition ")"
| NOT condition
| condition ( AND | OR ) condition
| (TRUE | FALSE)
| expr NOT ? LIKE expr (ESCAPE ESCAPE_CHAR)?
BETWEEN AND范围表达式
如果值expr1位于expr2~expr3的范围之内,则表达式expr1 BETWEEN expr2 AND expr3的运算结果为true(包含端点值)。 其中每个expr都必须是数字类型。
“expr1 BETWEEN expr2 AND expr3”等效于“expr1 <= expr3 AND expr1> = expr2”。
Copy CREATE QUERY mathOperatorBetween() FOR GRAPH minimalNet
{
int x;
bool b;
x = 1 ;
b = (x BETWEEN 0 AND 100 ); PRINT b; # True
b = (x BETWEEN 1 AND 2 ); PRINT b; # True
b = (x BETWEEN 0 AND 1 ); PRINT b; # True
}
IS NULL和 IS NOT NULL
IS NULL和IS NOT NULL可用于检查可选参数是否被赋值。
Copy CREATE QUERY parameterIsNULL ( INT p) FOR GRAPH minimalNet {
IF p IS NULL THEN
PRINT "p is null" ;
ELSE
PRINT "p is not null" ;
END ;
}
Copy GSQL > RUN QUERY parameterIsNULL(_)
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{"p is null": "p is null"}]
}
GSQL > RUN QUERY parameterIsNULL( 3 )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{"p is not null": "p is not null"}]
}
在GSQL中存储的每个属性值都是有效的,因此IS NULL和IS NOT NULL仅用于每个查询操作的参数。
LIKE运算符
LIKE运算符用于检查字符串是否与某个模式匹配。 表达方式为:
Copy string1 LIKE string_pattern
如果string1与string_pattern中的模式相匹配,则返回结果值为布尔值true; 反之为false。 前后两个值必须都是字符串。 LIKE只能在WHERE子句中使用。 此外,string_pattern支持以下通配符和其他符号:
数学函数
系统包含许多内置函数。他们可以用于累加器,基本类或顶点变量。 累加器函数的调用在“累加器”一章中详述。
下面是一个内置函数列表,它们对INT,FLOAT或DOUBLE类型的值起作用。
字符串函数
以下内置函数用于处理文本。 请注意,这些函数不会修改输入的文本,而是输出一个全新的字符串。
关于使用trim()函数的注意事项:
在trim()中的粗体字(LEADING,TRAILING,BOTH和FROM)是关键字,不能省略。
STRING只表示此处参数的数据类型; 它不是一个关键字。
trim()函数具有以下选项:
通过使用LEADING,TRAILING或BOTH之一关键字,用户可以指定分别从字符串的左端,右端或两端删除字符。 如果未使用这些关键字,则默认从两端删除。
removal_char是一个单个字符。 该函数将按顺序按照removed_char的内容来删除字符串,直到遇到与之不同的字符。 如果未指定removed_char,则trim()将删除空白字符(包括空格,制表符和换行符)。
日期时间函数
下面的函数将其它类型的值转换成时间日期,或将时间日期转换成其它格式。
以下函数将DATETIME值转换为用户自定义格式:
Copy # Show all posts 's post time
CREATE QUERY allPostTime() FOR GRAPH socialNet api("v2") {
start = {post.*};
#PRINT datetime_format(start.postTime, "a message was posted at %H:%M:%S on %Y/%m/%d");
PRINT start[datetime_format(start.postTime, "a message was posted at %H:%M:%S on %Y/%m/%d") as postTimeMsg]; // api v2
}
JSONOBJECT 和JSONARRAY 函数
JSONOBJECT和JSONARRAY是基本类,这意味着它们可以是参数类型,或大多数累加器的元素类型,或一个返回值类型。 这使得用户能够输入和输出更加复杂的自定义数据结构。 对于输入和输出来说,我们使用JSON格式的字符串表达式。 因此,GSQL图形查询语言提供几个函数,从而可以将标准格式的字符串转换为JSON,然后搜索和访问该JSON的内容。
数据转换函数
以下的解析函数将字符串转换为JSONOBJECT或JSONARRAY:
如果输入的字符串无法转换为JSON对象或JSON数组,则这两个函数都会实时报错。 所以若要格式正确,除了正确嵌套和正确匹配花括号{}和方括号[]之外,每个值都必须是以下几种类型之一:字符串(由双引号引用),数字,布尔值(true或false),JSONOBJECT或JSONARRAY。键值对的每个键必须是由双引号引用的字符串。
见下面的例子。
parse_json_object 和 parse_json_array的例子
Copy CREATE QUERY jsonEx (STRING strA, STRING strB) FOR GRAPH minimalNet {
JSONARRAY jsonA;
JSONOBJECT jsonO;
jsonA = parse_json_array( strA );
jsonO = parse_json_object( strB );
PRINT jsonA, jsonO;
}
Copy GSQL > RUN QUERY jsonEx( "[123]" , "{\" abc\ ":123}" )
or curl - X GET 'http://localhost:9000/query/jsonEx?strA=\[123\]&strB=\{"abc":123\}'
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{
"jsonA" : [123],
"jsonO" : { "abc" : 123 }
}]
}
GSQL > RUN QUERY jsonEx( "{123}" , "{\" 123 \ ":\" 123 \ "}" )
Runtime Error: { 123 } cannot be parsed as a json array .
数据访问方法
JSONOBJECT和JSONARRAY是对象类,每个类都使用点表示法来支持内容访问,例如:
jsonVariable.functionName(parameter_list)
以下方法(类函数)可以作用于JSONOBJECT变量:
如果出现下列情况,上述getType(STRING keyStr)函数会生成实时错误:
函数的返回类型与存储值的类型不同。 详见有关数字格式数据的下条注释。
纯正的JSON只存储“数字”而不区分INT和DOUBLE,但对于TigerGraph,如果输入值的每一位都是一个数字,则它将存储为整数类型。 其他情况下则存储为DOUBLE。 getDouble函数可以读取INT并返回其等效的DOUBLE值,但是对DOUBLE值调用getINT则会报错。
以下方法可以作用于JSONARRAY变量:
与JSONOBJECT的方法类似,上面的getType(INT idx)函数会生成实时错误,如果:
函数的返回类型与存储值的类型不同。详见有关数字格式数据的下条注释。
纯正的JSON只存储“数字”而不区分INT和DOUBLE,但对于TigerGraph,如果输入值的每一位都是一个数字,则它将存储为整数类型。 其他情况下则存储为DOUBLE。 getDouble函数可以读取INT并返回其等效的DOUBLE值,但是对DOUBLE值调用getINT则会报错。
以下是使用这些函数和方法的示例:
JSONOBJECT 和JSONARRAY 函数的例子
Copy CREATE QUERY jsonEx2 () FOR GRAPH minimalNet {
JSONOBJECT jsonO, jsonO2;
JSONARRAY jsonA, jsonA2;
STRING str, str2;
str = "{\"int\":1, \"double\":3.0, \"string\":\"xyz\", \"bool\":true, \"obj\":{\"obj\":{\"bool\":false}}, \"arr\":[\"xyz\",123,true] }";
str2 = "[\" xyz\ ", 123, false, 5.0]" ;
jsonO = parse_json_object( str ) ;
jsonA = parse_json_array( str2 ) ;
jsonO2 = jsonO.getJsonObject( "obj" );
jsonA2 = jsonO.getJsonArray( "arr" );
PRINT jsonO;
PRINT jsonO.getBool("bool"), jsonO.getJsonObject("obj"), jsonO.getJsonArray("arr"), jsonO2.getJsonObject("obj"), jsonA2.getString(0), jsonA.getDouble(3), jsonA.getDouble(1);
}
Copy GSQL > RUN QUERY jsonEx2()
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [ {"jsonO": { "arr": [ "xyz", 123, true ],
"bool" : true,
"string" : "xyz" ,
"double" : 3 ,
"obj" : { "obj" : { "bool" : false}},
"int" : 1
}},
{
"jsonO.getBool(bool)" : true,
"jsonA.getDouble(3)" : 5 ,
"jsonA.getDouble(1)" : 123 ,
"jsonO.getJsonObject(obj)" : { "obj" : { "bool" : false}},
"jsonO2.getJsonObject(obj)" : { "bool" : false},
"jsonO.getJsonArray(arr)" : [ "xyz", 123, true ],
"jsonA2.getString(0)" : "xyz"
}
]
}
顶点、边、累加器函数和属性
访问属性
顶点或边的属性在图形数据库纲目中定义。 此外,每个顶点和边都有一个名叫type的内置属性字符串,它表示该边或顶点的用户自定义类型。 用户可以使用点运算符来访问某个边或顶点的属性(包括type)。
例如,以下代码段展示了两个不同的SELECT语句,但它们输出相同的结果。 第一个使用顶点变量v上的点运算符来访问“subject”属性,该属性在图形数据库纲目中定义。 第一个SELECT语句中的FROM子句要求任何目标顶点都是“post”类型(也在图形数据库纲目中定义)。 第二个SELECT语句通过让点运算符访问内置type属性的方式来检查顶点变量v的类型是否为一个“post”顶点。
Copy CREATE QUERY coffeeRelatedPosts() FOR GRAPH socialNet
{
allVertices = {ANY};
results = SELECT v FROM allVertices:s - (:e) -> post:v WHERE v.subject == "coffee" ;
PRINT results;
results = SELECT v FROM allVertices:s - (:e) -> :v WHERE v.type == "post" AND v.subject == "coffee" ;
PRINT results;
}
Copy GSQL > RUN QUERY coffeeRelatedPosts()
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{ "results" : [{
"v_id" : "4" ,
"attributes" : {
"postTime" : "2011-02-07 05:02:51" ,
"subject" : "coffee"
},
"v_type" : "post"
}]},
{ "results" : [{
"v_id" : "4" ,
"attributes" : {
"postTime" : "2011-02-07 05:02:51" ,
"subject" : "coffee"
},
"v_type" : "post"
}]}
]
}
顶点函数
下面列出了可以通过点运算符,并根据别名来访问的内建函数:
Copy vertex_alias.function_name(parameter)[.FILTER(condition)]
目前,这些函数仅适用于顶点别名(在FROM子句中定义)的访问; 顶点变量并不能用于这些函数。
请注意,为了按边类计算外部出度(outdegree),用户必须定义图形数据库纲目,并令顶点使用WITH STATS=“OUTDEGREE_BY_EDGETYPE”的方式跟踪其边类(但目前“OUTDEGREE_BY_EDGETYPE”已经是STATS的默认选项了)。
Copy CREATE QUERY vertexFunctionExample(vertex < person > m1) FOR GRAPH socialNet {
SetAccum < Vertex > @neighborSet;
SetAccum < Vertex > @neighborSet2;
SetAccum <DATETIME> @attr1;
BagAccum <DATETIME> @attr2;
int deg1, deg2, deg3, deg4;
S = {m1};
S2 = SELECT S
FROM S - (posted:e) -> post:t
ACCUM deg1 = S.outdegree(),
deg2 = S.outdegree( "posted" ),
deg3 = S.outdegree(e.type), # same as deg2
STRING str = "posted" ,
deg4 = S.outdegree(str); # same as deg2
PRINT deg1, deg2, deg3, deg4;
S3 = SELECT S
FROM S:s
POST - ACCUM s.@neighborSet += s.neighbors(),
s.@neighborSet2 += s.neighbors( "posted" ),
s.@attr1 += s.neighborAttribute( "posted" , "post" , "postTime" ),
s.@attr2 += s.edgeAttribute( "liked" , "actionTime" );
PRINT S3;
}
vertexFunctionExample 的结果
Copy GSQL > RUN QUERY vertexFunctionExample( "person5" )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{
"deg4" : 2 ,
"deg2" : 2 ,
"deg3" : 2 ,
"deg1" : 5
},
{ "S3" : [{
"v_id" : "person5" ,
"attributes" : {
"@attr2" : [1263330725],
"@attr1" : [
1297054971 ,
1296694941
],
"gender" : "Female" ,
"@neighborSet" : [
"6" ,
"11" ,
"4" ,
"person7" ,
"person4"
],
"id" : "person5" ,
"@neighborSet2" : [
"4" ,
"11"
]
},
"v_type" : "person"
}]}
]
}
.FILTER参数
可选的.FILTER(条件)子句是一个额外的过滤器,用于选择将哪些元素添加到neighbor,neighborAttribute和edgeAttribute函数的输出集中。该条件会判断每一个元素。 如果判断结果为真,则将元素添加到输出集; 如果是假,则不添加。 下面是一个例子:
Copy CREATE QUERY filterEx ( SET< STRING > pIds, INT yr) FOR GRAPH workNet api( "v2" ) {
SetAccum < vertex < company >> @recentEmplr, @allEmplr;
BagAccum < string > @diffCountry, @allCountry;
Start = {person. * };
L0 = SELECT v
FROM Start :v
WHERE v.id IN pIds
ACCUM
# filter using edge attribute
v.@recentEmplr += v.neighbors( "worksFor" ). filter (worksFor.startYear >= yr),
v.@allEmplr += v.neighbors( "worksFor" ). filter (true),
# vertex alias attribute and neighbor type attribute
v.@diffCountry += v.neighborAttribute( "worksFor" , "company" , "id" )
. filter (v.locationId != company.country),
v.@allCountry += v.neighborAttribute( "worksFor" , "company" , "id" )
;
PRINT yr, L0[L0.@recentEmplr, L0.@allEmplr, L0.@diffCountry, L0.@allCountry]; // api v2
}
Copy GSQL > RUN QUERY filterEx(["person1","person2"], 2016 )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{
"L0" : [
{
"v_id" : "person1" ,
"attributes" : {
"L0.@diffCountry" : ["company2"],
"L0.@recentEmplr" : ["company1"],
"L0.@allCountry" : [ "company1", "company2" ],
"L0.@allEmplr" : [ "company2", "company1" ]
},
"v_type" : "person"
},
{
"v_id" : "person2" ,
"attributes" : {
"L0.@diffCountry" : ["company1"],
"L0.@recentEmplr" : [],
"L0.@allCountry" : [ "company1", "company2" ],
"L0.@allEmplr" : [ "company2", "company1" ]
},
"v_type" : "person"
}
],
"yr" : 2016
}]
}
边函数
下面列出的函数是使用点运算符,并可以通过边的别名访问的内置函数。 边函数遵循与顶点函数相同的一般规则(参见上文)。
累加器函数
每种类型的累加器函数都已经在“累加器类型”一章中详述。
Set和Bag的表达式和运算符
SELECT语句对输入的顶点集执行各种选择和过滤操作以生成输出集。 因此,Set和Bag的表达式及其运算符是令GSQL图形查询语言与众不同且功能强大的缘由。 Set和Bag的表达式可以使用SetAccum或BagAccum来编写。
Copy setBagExpr : = ["@@"] name
| name "." ["@"] name
| name "." "@" name ( "." name "(" [argList] ")" ) +
| name "." name "(" [argList] ")" [ ".".FILTER "(" condition ")" ]
| "@@" name ( "." name "(" [argList] ")" ) +
| setBagExpr ( UNION | INTERSECT | MINUS) setBagExpr
| "(" argList ")"
| "(" setBagExpr ")"
Set和Bag的表达式运算符 – 并集,交集,集合相减
这几个运算符都很容易理解,当两个操作数都是集合时,则结果也是一个集合。 当至少一个操作数是一个Bag时,结果就是一个Bag。 如果一个操作数是Bag,而另一个是Set,则运算符将该Set视为一个Bag。Bag中包含了Set中的每个值。
Copy # Demonstrate Set & Bag operators
CREATE QUERY setOperatorsEx() FOR GRAPH minimalNet {
SetAccum <INT> @@setA, @@setB, @@AunionB, @@AintsctB, @@AminusB;
BagAccum <INT> @@bagD, @@bagE, @@DunionE, @@DintsctE, @@DminusE;
BagAccum <INT> @@DminusA, @@DunionA, @@AunionBbag;
BOOL x;
@@setA = ( 1 , 2 , 3 , 4 ); PRINT @@setA;
@@setB = ( 2 , 4 , 6 , 8 ); PRINT @@setB;
@@AunionB = @@setA UNION @@setB ; PRINT @@AunionB; // ( 1 , 2 , 3 , 4 , 6 , 8 )
@@AintsctB = @@setA INTERSECT @@setB; PRINT @@AintsctB; // ( 2 , 4 )
@@AminusB = @@setA MINUS @@setB ; PRINT @@AminusB; // C = ( 1 , 3 )
@@bagD = ( 1 , 2 , 2 , 3 ); PRINT @@bagD;
@@bagE = ( 2 , 3 , 5 , 7 ); PRINT @@bagE;
@@DunionE = @@bagD UNION @@bagE; PRINT @@DunionE; // ( 1 , 2 , 2 , 2 , 3 , 3 , 5 , 7 )
@@DintsctE = @@bagD INTERSECT @@bagE; PRINT @@DintsctE; // ( 2 , 3 )
@@DminusE = @@bagD MINUS @@bagE; PRINT @@DminusE; // ( 1 , 2 )
@@DminusA = @@bagD MINUS @@setA; PRINT @@DminusA; // ( 2 )
@@DunionA = @@bagD UNION @@setA; PRINT @@DunionA; // ( 1 , 1 , 2 , 2 , 2 , 3 , 3 , 4 )
// because bag UNION set is a bag
@@AunionBbag = @@setA UNION @@setB; PRINT @@AunionBbag; // ( 1 , 2 , 3 , 4 , 6 , 8 )
// because set UNION set is a set
}
Copy GSQL > RUN QUERY setOperatorsEx()
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [ {"@@setA": [ 4, 3, 2, 1 ]},
{ "@@setB" : [ 8, 6, 4, 2 ]},
{ "@@AunionB" : [ 4, 3, 2, 1, 8, 6 ]},
{ "@@AintsctB" : [ 4, 2 ]},
{ "@@AminusB" : [ 3, 1 ]},
{ "@@bagD" : [ 1, 2, 2, 3 ]},
{ "@@bagE" : [ 2, 7, 3, 5 ]},
{ "@@DunionE" : [ 1, 2, 2, 2, 3, 3, 7, 5 ]},
{ "@@DintsctE" : [ 2, 3 ]},
{ "@@DminusE" : [ 1, 2 ]},
{ "@@DminusA" : [2]},
{ "@@DunionA" : [ 1, 1, 2, 2, 2, 3, 3, 4 ]},
{ "@@AunionBbag" : [ 6, 8, 1, 2, 3, 4 ]}
]
}
由于这些运算符的运算结果是一个新的set或Bag,因此可以通过嵌套和链接的方式编写更复杂的表达式,例如:
Copy (setBagExpr_A INTERSECT (setBagExpr_B UNION setBagExpr_C) ) MINUS setBagExpr_D
Set和BagExpression 运算符成员
Set和Bag表达式的运算符成员
例如,假设我们定义一个bag: setBagExpr_A is ("a", "b", "c")
Copy "a" IN setBagExpr_A => true
"d" IN setBagExpr_A => false
"a" NOT IN setBagExpr_A => false
"d" NOT IN setBagExpr_A => true
IN和NOT IN运算符的左侧支持所有的基本类,右侧则支持任何set 或bag表达式。 基本类必须与累加器元素的类型相同。IN和NOT IN返回一个布尔值。
以下示例使用NOT IN排除黑名单中的邻居。
Copy CREATE QUERY friendsNotInblacklist (VERTEX < person > seed, SET< VERTEX < person >> blackList) FOR GRAPH socialNet `{
Start = {seed};
Result = SELECT v
FROM Start:s-(friend:e)-person:v
WHERE v NOT IN blackList;
PRINT Result;
}
查询friendsNotInblacklist的结果
Copy GSQL > RUN QUERY friendsNotInblacklist( "person1" , ["person2"])
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{ "Result" : [{
"v_id" : "person8" ,
"attributes" : {
"gender" : "Male" ,
"id" : "person8"
},
"v_type" : "person"
}]}]
}
聚合函数 – 计数(COUNT),求和(SUM),最小值(MIN),最大值(MAX),平均值(AVG)
聚合函数的输入参数为一个 set或bag,输出为一个值或元素。
sum():返回所有元素的总和。 这仅适用于具有数字类型的Set和Bag。
min():返回最小值。 这仅适用于具有数字类型的Set和Bag
max():返回最大值。 这仅适用于具有数字类型的Set和Bag。
avg():返回所有元素的平均值。 这仅适用于具有数字类型的Set和Bag。 如果Set和Bag内的元素类型是整数,则返回的平均值为整数。
Copy CREATE QUERY aggregateFuncEx(BAG <INT> x) FOR GRAPH minimalNet {
BagAccum <INT> @@t;
@@t += - 5 ; @@t += 2 ; @@t += - 1 ;
PRINT max (@@t), min (@@t), avg (@@t), count (@@t), sum (@@t);
PRINT max (x), min (x), avg (x), count (x), sum (x);
}
Copy GSQL > RUN QUERY aggregateFuncEx([1,2,5])
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{
"sum(@@t)" : - 4 ,
"count(@@t)" : 3 ,
"max(@@t)" : 2 ,
"avg(@@t)" : - 1 ,
"min(@@t)" : - 5
},
{
"avg(x)" : 2 ,
"count(x)" : 3 ,
"max(x)" : 5 ,
"min(x)" : 1 ,
"sum(x)" : 8
}
]
}
其他类型函数
SelectVertex()函数
SelectVertex()读取一个包含特定顶点列表的数据文件,并返回相应的顶点集。 此函数只能在顶点集变量的声明语句中用作种子集。 该数据文件必须是一张包含一列或多列的表,且其中一列必须是顶点id。 此外,用户也可以选择另一列用于标明顶点类型。 SelectVertex()有五个参数,如下表所示:filePath,vertexIdColumn,vertexTypeColumn,separator和header。 列分隔符和列标题的规则与GSQL 加载器的规则相同。
一个顶点集变量的声明语句中可以包含多个SelectVertex()函数调用。 但如果该声明中包含多个引用同一文件的SelectVertex(),则它们必须使用相同的分隔符和标头。 如果文件中的任何行包含无效的顶点类型,则系统会报告运行错误;如果文件的任何行包含不存在的顶点id,则系统会提示一条告警,告警显示无效id的数量。
下面的示例使用了SelectVertex(),从数据文件selectVertexInput.csv中获取信息。
Copy c1,c2,c3
person1,person, 3
person5,person, 4
person6,person, 5
Copy CREATE QUERY selectVertexEx(STRING filename ) FOR GRAPH socialNet {
S = {SelectVertex( filename , $ "c1" , $ 1 , "," , true),
SelectVertex( filename , $ 2 , post, "," , true)
};
PRINT S;
}
Copy GSQL > RUN QUERY selectVertexEx( "/file_directory/selectVertexInput.csv" )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{ "S" : [
{
"v_id" : "4" ,
"attributes" : {
"postTime" : "2011-02-07 05:02:51" ,
"subject" : "coffee"
},
"v_type" : "post"
},
{
"v_id" : "person1" ,
"attributes" : {
"gender" : "Male" ,
"id" : "person1"
},
"v_type" : "person"
},
{
"v_id" : "person5" ,
"attributes" : {
"gender" : "Female" ,
"id" : "person5"
},
"v_type" : "person"
},
{
"v_id" : "3" ,
"attributes" : {
"postTime" : "2011-02-05 01:02:44" ,
"subject" : "cats"
},
"v_type" : "post"
},
{
"v_id" : "5" ,
"attributes" : {
"postTime" : "2011-02-06 01:02:02" ,
"subject" : "tigergraph"
},
"v_type" : "post"
},
{
"v_id" : "person6" ,
"attributes" : {
"gender" : "Male" ,
"id" : "person6"
},
"v_type" : "person"
}
]}]
}
to_vertex() 和to_vertex_set()
函数to_vertex()和函数to_vertex_set()将字符串或字符串集分别转换指定顶点类所规定的顶点或顶点集。 当顶点id只能在运行时被获取时,这两个函数十分有用。
运行这些函数需要将外部id实时转换为GSQL内部id,这是一个相对较慢的过程。 因此,
如果用户查询开始之前就知道id的话,请使用VERTEX或SET <VERTEX>参数编写查询,而不要用STRING或SET<STRING>编写查询,并避免使用to_vertex()或to_vertex_set()这两个函数。
调用一次to_vertex_set()比调用多次to_vertex()的速度要快得多,所以尽可能多使用to_vertex_set()而不是to_vertex()。
to_vertex_set()的第一个参数表示顶点id的集合(字符串集)。 两个函数的第二个参数都是顶点类(字符串)。
to_vertex() 与to_vertex_set()的函数签名
Copy VERTEX to_vertex(STRING id, STRING vertex_type)
SET< VERTEX > to_vertex_set( SET< VERTEX > , STRING vertex_type)
SET< VERTEX > to_vertex_set(BAG < VERTEX > , STRING vertex_type)
系统允许向to_vertex_set一次输入一个Bag的顶点集合,但该功能会启动自动消重功能,从而把bag转换为set。
如果某个顶点id或顶点类不存在,则to_vertex()将会出现运行错误,错误如下所示。 但是to_vertex_set()只有当顶点类型不存在时,才会出现运行错误。 如果一个或多个顶点id不存在,则to_vertex_set()将显示警告消息但仍将运行,并转换所有有效的id并跳过不存在id。 在将字符串集转换为顶点集时,若用户面对无效ID只想要错误而不是警告,则用户应该在FOREACH循环内使用to_vertex(),而不是to_vertex_set()。 详见下面的示例。
to_vertex() 和to_vertex_set()的例子
Copy CREATE QUERY to_vertex_set ( SET< STRING > uids, STRING uid , STRING vtype) FOR GRAPH workNet {
SetAccum < VERTEX > @@v2, @@v3;
SetAccum < STRING > @@strSet;
VERTEX v;
v = to_vertex ( uid , vtype);# to_vertex assigned to a vertex variable
PRINT v;# vertex variable -> only vertex id is printed
@@v2 += to_vertex ( uid , vtype);# to_vertex accumulated to a SetAccum < VERTEX >
PRINT @@v2;# SetAccum of vertex -> only vertex ids are printed
S2 = to_vertex_set (uids, vtype); # to_vertex_set assigned to a vertex set variable
PRINT S2;# vertex set variable -> full details printed
@@strSet = uids;# Show SET< STRING > & SetAccumm < STRING > are the same
S3 = to_vertex_set(@@strSet, vtype); # Input to to_vertex_set is SetAccum < STRING >
SDIFF = S2 MINUS S3;# Now S2 = S3, so SDIFF2 is empty
PRINT SDIFF.size();
#FOREACH vid in uids DO # In this case non - existing ids in uids causes run -time error
# @@v3 += to_vertex( vid, vtype );
# END ;
#L3 = @@v3;
# PRINT L3;
}
Copy GSQL > RUN QUERY to_vertex_set(["person1","personx","person2"], "person3" , "person" )
{
"error" : false,
"message" : "Runtime Warning: 1 ids are invalid person vertex ids." ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{ "v" : "person3" },
{ "@@v2" : ["person3"]},
{ "S2" : [
{
"v_id" : "person1" ,
"attributes" : {
"interestList" : [ "management", "financial" ],
"skillSet" : [ 3, 2, 1 ],
"skillList" : [ 1, 2, 3 ],
"locationId" : "us" ,
"interestSet" : ["financial", "management" ],
"id" : "person1"
},
"v_type" : "person"
},
{
"v_id" : "person2" ,
"attributes" : {
"interestList" : ["engineering"],
"skillSet" : [ 6, 5, 3, 2 ],
"skillList" : [ 2, 3, 5, 6],
"locationId" : "chn" ,
"interestSet" : ["engineering"],
"id" : "person2"
},
"v_type" : "person"
}
]},
{ "SDIFF.size()" : 0 }
]
}
GSQL > RUN QUERY to_vertex_set(["person1","personx"], "person1" , "abc" )
Runtime Error: abc is not valid vertex type .
COALESCE()函数
COALESCE函数按顺序计算每个参数值,并返回第一个非空的(NOT NULL)值。该运算与IS NULL和IS NOT NULL操作相同。 COALESCE函数要求其所有的参数都具有相同的数据类型(布尔,整数,浮点,双浮点,字符串或顶点),唯一的一个例外是不同的数字类型可以放在一起使用。 在这种情况下,所有数字类型都将转换为第一个参数的类型。
Copy CREATE QUERY coalesceFuncEx ( INT p1, DOUBLE p2) FOR GRAPH minimalNet {
PRINT COALESCE (p1, p2, 999 . 5 ); # p2 and the last value will be converted into first argument type , which is INT .
}
Copy GSQL > RUN QUERY coalesceFuncEx(_,_)
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{"coalesce(p1,p2,999.5)": 999}]
}
GSQL > RUN QUERY coalesceFuncEx( 1 , 2 )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{"coalesce(p1,p2,999.5)": 1}]
}
GSQL > RUN QUERY coalesceFuncEx(_, 2 . 5 )
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [{"coalesce(p1,p2,999.5)": 2}]
}
COALESCE函数在允许出现多个可选参数,且至少有一个必须选中的情况下十分有用,例如:
Copy CREATE QUERY coalesceFuncEx2 (STRING homePhone, STRING cellPhone, STRING companyPhone) FOR GRAPH minimalNet {
PRINT "contact number: " + COALESCE (homePhone, cellPhone, companyPhone); # test all NULL
PRINT "contact number: " + COALESCE (homePhone, cellPhone, companyPhone, "N/A" );
}
COALESCE函数的参数列表的最后一个参数,应该拥有一个默认值。 这样,如果当所有的值都为NULL的时候,函数就返回最后一个参数的默认值。
Copy GSQL > RUN QUERY coalesceFuncEx2(_,_,_)
{
"error" : false,
"message" : "" ,
"version" : {
"schema" : 0 ,
"api" : "v2"
},
"results" : [
{ "contact number: +coalesce(homePhone,cellPhone,companyPhone)" : "contact number: " },
{ "contact number:+coalesce(homePhone,cellPhone,companyPhone,N/A)" : "contact number:N/A" }
]
}
带有EVALUATE()函数的动态表达式
函数evaluate()将一个字符串转换为一个表达式,并实时运算执行该表达式。 这使用户有能力创建一个通用的查询,而不必为每种特定的计算都创建单独的查询。
Copy evaluate(expressionStr, typeStr)
evaluate()函数有两个参数:expressionStr是字符串类型的表达式,typeStr也是字符串,用于描述表达式的类型。 此函数返回一个类型为typeStr的值,该值的内容为expressionStr的运算结果。 以下规则适用:
evaluate()只能在SELECT语句的内部使用,并且只能在WHERE子句,ACCUM子句,POST-ACCUM子句,HAVING子句或排序子句中使用。它不能用于LIMIT子句或用于SELECT语句之外。
用户必须在安装查询的时候就指定结果的类型:typeStr必须是基础数据类型的字符串形式,例如“int”,“float”,“double”,“bool”,“string”(不区分大小写)。默认值为“bool”。
在expressionStr中,标识符只能是以下类型:顶点或边的别名,附属于顶点的累加器,全局累加器,参数,或涉及上述变量的标量函数。表达式可能不是局部变量,全局变量或FROM子句内的顶点或边。
表达式中的任何累加器必须是标量累加器(例如,MaxAccum),用于基本类的数据。不支持容器累加器(如SetAccum)或具有非基本类的标量累加器(如VERTEX,EDGE,DATETIME)。不支持容器类型的属性。
以下情况会生成运行时错误:
字符串表达式无法编译(由不存在的顶点或边导致的错误除外)。
静默错误
如果出现以下任何一种情况,查询可能会继续运行,但evaluate()函数所在的整个子句或语句将失败,却不会产生运行错误消息。 对于条件子句(WHERE,HAVING)来说,错误的evaluate()子句会被视为条件值false。 所以包含错误evaluate()语句的赋值动作将不会被执行,包含错误evaluate()语句的排序子句也不会被排序。
表达式使用运算符进行非兼容操作。 例如,123 ==“xyz”。
例:在WHERE条件子句和POST-ACCUM子句中的累加器值中使用动态表达式。
Copy CREATE QUERY evaluateEx (STRING whereCond = "TRUE" , STRING postAccumIntExpr = "1" ) FOR GRAPH socialNet {
SetAccum <INT> @@timeSet;
MaxAccum <INT> @latestLikeTime, @latestLikePostTime;
S = {person. * };
S2 = SELECT s
FROM S:s - (liked:e) -> post:t
WHERE evaluate(whereCond)
ACCUM s.@latestLikeTime += datetime_to_epoch( e.actionTime ),
s.@latestLikePostTime += datetime_to_epoch( t.postTime )
POST - ACCUM @@timeSet += evaluate(postAccumIntExpr, "int" )
;
PRINT @@timeSet;
}
Copy GSQL > RUN QUERY evaluateEx(_,_)
{
"error" : false,
"message" : "" ,
"results" : [{"@@timeSet": [1]}]
}
GSQL > RUN QUERY evaluateEx( "s.gender==\" Male\ "" , "s.@latestLikePostTime" )
{
"error" : false,
"message" : "" ,
"results" : [
{
"@@timeSet" : [1263295325,1296752752,1297054971,1296788551]
}
]
}
GSQL > RUN QUERY evaluateEx( "s.gender==\" Female\ "" , "s.@latestLikeTime + 1" )
{
"error" : false,
"message" : "" ,
"results" : [
{
"@@timeSet" : [1263293536,1263352566,1263330726]
}
]
}
GSQL > RUN QUERY evaluateEx( "xx" , _)
Runtime Error: xx is undefined parameter.
GSQL > RUN QUERY evaluateEx("e.xyz", _)' # The attribute doesn't exist, so the entire condition in WHERE clause is false。
{
"error" : false,
"message" : "" ,
"results" : [{"@@timeSet": []}]
}
GSQL > RUN QUERY evaluateEx( "e.actionTime" , _)
Runtime Error: actionTime is not a primitive type attribute.
GSQL > RUN QUERY evaluateEx( "s.id" , _)
Runtime Error: Expression 's.id' value type is not bool.
GSQL > RUN QUERY evaluateEx("s.gender==\"Female\"", "s.xx") # The attribute doesn't exist, so the entire assignment is skipped.
{
"error" : false,
"message" : "" ,
"results" : [{"@@timeSet": []}]
}
函数形式的查询 (子查询)
一个使用CREATE QUERY ... RETURNS语句定义的查询可被另一个查询调用,即查询可以嵌套。
已知问题:
当前查询无法调用自身。 修复正在进行中。
查询调用另一个查询有以下限制:
被调用查询的每个参数必须是以下类型之一:
基本类:INT,UINT,FLOAT,DOUBLE,STRING,BOOL
返回值可以是以下类型之一。 详见“返回声明”部分。
基本类:INT,UINT,FLOAT,DOUBLE,STRING,BOOL
基本类的累加器,但不支持GroupByAccum累加器和包含元组的累加器。
如果一个查询返回的是SetAccum或BagAccum累加器值, 则可在调用时分别使用Set或Bag的参数
定义查询的顺序是很重要的。 一个查询无法调用一个尚未定义的查询。
Copy CREATE QUERY subquery1 (VERTEX < person > m1) FOR GRAPH socialNet RETURNS (BagAccum < VERTEX < post >> )
{
Start = {m1};
L = SELECT t
FROM Start :s - (liked:e) - post:t;
RETURN L;
}
CREATE QUERY mainquery1 () FOR GRAPH socialNet
{
BagAccum < VERTEX < post >> @@testBag;
Start = {person. * };
Start = SELECT s FROM Start :s
ACCUM @@testBag += subquery1(s);
PRINT @@testBag;
}
用户自定义函数
用户可以在以下文件<tigergraph.root.dir>/dev/gdk/gsql/src/QueryUdf/ExprFunctions.hpp中用C++定义自己的函数表达式,但只允许使用bool,int,float,double和string(NOT std :: string)作为返回值的类型和函数参数的类型。 但是,在函数表达式正文内允许任何C++的类型。 一旦某个函数被定义,则下次执行GSQL时,新函数将会自动添加到GSQL中。
如果需要定义一个用户自定义的结构或一个帮助函数,请在<tigergraph.root.dir>/dev/gdk/gsql/src/QueryUdf/ExprUtil.hpp中定义它们。
以下是一个例子:
Copy # include <algorithm> // for std::reverse
inline bool greater_than_three (double x) {
return x > 3 ;
}
inline string reverse (string str){
std:: reverse (str.begin(), str.end());
return str;
}
Copy CREATE QUERY udfExample() FOR GRAPH minimalNet {
DOUBLE x;
BOOL y;
x = 3 . 5 ;
PRINT greater_than_three(x);
y = greater_than_three( 2 . 5 );
PRINT y;
PRINT reverse ( "abc" );
}
Copy GSQL > RUN QUERY udfExample()
{
"error": false,
"message": "",
"version": {
"schema": 0,
"api": "v2"
},
"results": [
{"greater_than_three(x)": true},
{"y": false},
{"reverse(abc)": "cba"}
]
}
如果ExprFunctions.hpp或ExprUtil.hpp中的任何代码导致了编译错误,则即使某个GSQL查询并未调用任何用户自定义函数,系统也将无法安装任何GSQL查询。 因此,请每次在添加代码后,都要对新的用户自定义表达式函数进行测试。 测试该函数的一种可选的方法是:创建一个新的cpp文件test.cpp并对其进行编译
> g ++ test.cpp
> ./a.out
您可能需要删除ExprFunction.hpp和ExprUtil.hpp中的include标头 #include <gle/engine/cpplib/headers.hpp>才能进行编译。
Copy #include "ExprFunctions.hpp"
#include <iostream>
int main () {
std::cout << to_string (123) << std::endl; // to_string and str_to_int are two built-in functions in ExprFunction.hpp
std::cout << str_to_int ("123") << std::endl;
return 0;
}
表达式的示例
下面是一系列表达式示例。请注意,(argList)是Set或Bag表达式,而[ argList ]是列表表达式。
Copy #Show various types of expressions
CREATE QUERY expressionEx() FOR GRAPH workNet {
TYPEDEF tuple<STRING countryName, STRING companyName> companyInfo;
ListAccum<STRING> @companyNames;
SumAccum<INT> @companyCount;
SumAccum<INT> @numberOfRelationships;
ListAccum<companyInfo> @info;
MapAccum< STRING,ListAccum<STRING> > @@companyEmployeeRelationships;
SumAccum<INT> @@totalRelationshipCount;
ListAccum<INT> @@valueList;
SetAccum<INT> @@valueSet;
SumAccum<INT> @@a;
SumAccum<INT> @@b;
#expr := constant
@@a = 10;
#expr := ["@@"] name
@@b = @@a;
#expr := expr mathOperator expr
@@b = @@a + 5;
#expr := "(" expr ")"
@@b = (@@a + 5);
#expr := "-" expr
@@b = -(@@a + 5);
PRINT @@a, @@b;
#expr := "[" argList "]" // a list
@@valueList = [1,2,3,4,5];
@@valueList += [24,80];
#expr := "(" argList ")" // setBagExpr
@@valueSet += (1,2,3,4,5);
#expr := ( COUNT | ISEMPTY | MAX | MIN | AVG | SUM ) "(" setBagExpr ")"
PRINT MAX(@@valueList);
PRINT AVG(@@valueList);
seed = {ANY};
company1 = SELECT t FROM seed:s -(worksFor)-> :t WHERE (s.id == "company1");
company2 = SELECT t FROM seed:s -(worksFor)-> :t WHERE (s.id == "company2");
#expr := setBagExpr
worksForBoth = company1 INTERSECT company2;
PRINT worksForBoth;
#expr := name "." "type"
employees = SELECT s FROM seed:s WHERE (s.type == "person");
employees = SELECT s FROM employees:s -(worksFor)-> :t
ACCUM
#expr := name "." ["@"] name
s.@companyNames += t.id,
#expr := name "." name "(" [argList] ")" [ ".".FILTER "(" condition ")" ]
s.@numberOfRelationships += s.outdegree(),
#expr := name ["<" type ["," type"]* ">"] "(" [argList] ")"
s.@info += companyInfo(t.country, t.id)
POST-ACCUM
#expr := name "." "@" name ("." name "(" [argList] ")")+ ["." name]
s.@companyCount += s.@companyNames.size(),
#expr := name "." "@" name ["\'"]
@@totalRelationshipCount += s.@companyCount,
FOREACH comp IN s.@companyNames DO
#expr := "(" argList "->" argList ")"
@@companyEmployeeRelationships += (s.id -> comp)
END;
PRINT employees;
PRINT @@totalRelationshipCount;
PRINT @@companyEmployeeRelationships;
#expr := "@@" name ("." name "(" [argList] ")")+ ["." name]
PRINT @@companyEmployeeRelationships.size();
}
Copy GSQL > RUN QUERY expressionEx()
{
"error": false,
"message": "",
"version": {
"schema": 0,
"api": "v2"
},
"results": [
{
"@@a": 10,
"@@b": -15
},
{"max(@@valueList)": 80},
{"avg(@@valueList)": 17},
{"worksForBoth": [
{
"v_id": "person2",
"attributes": {
"interestList": ["engineering"],
"@companyCount": 0,
"@numberOfRelationships": 0,
"skillSet": [ 6, 5, 3, 2 ],
"skillList": [ 2, 3, 5, 6 ],
"locationId": "chn",
"interestSet": ["engineering"],
"@info": [],
"id": "person2",
"@companyNames": []
},
"v_type": "person"
},
{
"v_id": "person1",
"attributes": {
"interestList": [ "management", "financial" ],
"@companyCount": 0,
"@numberOfRelationships": 0,
"skillSet": [ 3, 2, 1 ],
"skillList": [ 1, 2, 3 ],
"locationId": "us",
"interestSet": [ "financial", "management" ],
"@info": [],
"id": "person1",
"@companyNames": []
},
"v_type": "person"
}
]},
{"employees": [
{
"v_id": "person4",
"attributes": {
"interestList": ["football"],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 10, 1, 4 ],
"skillList": [ 4, 1, 10 ],
"locationId": "us",
"interestSet": ["football"],
"@info": [{ "companyName": "company2", "countryName": "chn" }],
"id": "person4",
"@companyNames": ["company2"]
},
"v_type": "person"
},
{
"v_id": "person12",
"attributes": {
"interestList": [
"music",
"engineering",
"teaching",
"teaching",
"teaching"
],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 2, 5, 1 ],
"skillList": [ 1, 5, 2, 2, 2 ],
"locationId": "jp",
"interestSet": [ "teaching", "engineering", "music" ],
"@info": [{ "companyName": "company4", "countryName": "us" }],
"id": "person12",
"@companyNames": ["company4"]
},
"v_type": "person"
},
{
"v_id": "person3",
"attributes": {
"interestList": ["teaching"],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 6, 1, 4 ],
"skillList": [ 4, 1, 6 ],
"locationId": "jp",
"interestSet": ["teaching"],
"@info": [{ "companyName": "company1", "countryName": "us" }],
"id": "person3",
"@companyNames": ["company1"]
},
"v_type": "person"
},
{
"v_id": "person9",
"attributes": {
"interestList": [ "financial", "teaching" ],
"@companyCount": 2,
"@numberOfRelationships": 4,
"skillSet": [ 2, 7, 4 ],
"skillList": [ 4, 7, 2 ],
"locationId": "us",
"interestSet": [ "teaching", "financial" ],
"@info": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company2",
"countryName": "chn"
}
],
"id": "person9",
"@companyNames": [ "company3", "company2" ]
},
"v_type": "person"
},
{
"v_id": "person11",
"attributes": {
"interestList": [ "sport", "football" ],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [10],
"skillList": [10],
"locationId": "can",
"interestSet": [ "football", "sport" ],
"@info": [{ "companyName": "company5", "countryName": "can" }],
"id": "person11",
"@companyNames": ["company5"]
},
"v_type": "person"
},
{
"v_id": "person10",
"attributes": {
"interestList": [ "football", "sport" ],
"@companyCount": 2,
"@numberOfRelationships": 4,
"skillSet": [3],
"skillList": [3],
"locationId": "us",
"interestSet": [ "sport", "football" ],
"@info": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"id": "person10",
"@companyNames": [ "company3", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person7",
"attributes": {
"interestList": [ "art", "sport" ],
"@companyCount": 2,
"@numberOfRelationships": 4,
"skillSet": [ 6, 8 ],
"skillList": [ 8, 6 ],
"locationId": "us",
"interestSet": [ "sport", "art" ],
"@info": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company2",
"countryName": "chn"
}
],
"id": "person7",
"@companyNames": [ "company3", "company2" ]
},
"v_type": "person"
},
{
"v_id": "person1",
"attributes": {
"interestList": [ "management", "financial" ],
"@companyCount": 2,
"@numberOfRelationships": 4,
"skillSet": [ 3, 2, 1 ],
"skillList": [ 1, 2, 3 ],
"locationId": "us",
"interestSet": [ "financial", "management" ],
"@info": [
{
"companyName": "company2",
"countryName": "chn"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"id": "person1",
"@companyNames": [ "company2", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person5",
"attributes": {
"interestList": [ "sport", "financial", "engineering" ],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 5, 2, 8 ],
"skillList": [ 8, 2, 5 ],
"locationId": "can",
"interestSet": [ "engineering", "financial", "sport" ],
"@info": [{ "companyName": "company2", "countryName": "chn" }],
"id": "person5",
"@companyNames": ["company2"]
},
"v_type": "person"
},
{
"v_id": "person6",
"attributes": {
"interestList": [ "music", "art" ],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 10, 7 ],
"skillList": [ 7, 10 ],
"locationId": "jp",
"interestSet": [ "art", "music" ],
"@info": [{ "companyName": "company1", "countryName": "us" }],
"id": "person6",
"@companyNames": ["company1"]
},
"v_type": "person"
},
{
"v_id": "person2",
"attributes": {
"interestList": ["engineering"],
"@companyCount": 2,
"@numberOfRelationships": 4,
"skillSet": [ 6, 5, 3, 2 ],
"skillList": [ 2, 3, 5, 6 ],
"locationId": "chn",
"interestSet": ["engineering"],
"@info": [
{
"companyName": "company2",
"countryName": "chn"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"id": "person2",
"@companyNames": [ "company2", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person8",
"attributes": {
"interestList": ["management"],
"@companyCount": 1,
"@numberOfRelationships": 1,
"skillSet": [ 2, 5, 1 ],
"skillList": [ 1, 5, 2 ],
"locationId": "chn",
"interestSet": ["management"],
"@info": [{ "companyName": "company1", "countryName": "us" }],
"id": "person8",
"@companyNames": ["company1"]
},
"v_type": "person"
}
]},
{"@@totalRelationshipCount": 17},
{"@@companyEmployeeRelationships": {
"person4": ["company2"],
"person3": ["company1"],
"person2": [ "company2", "company1" ],
"person1": [ "company2", "company1" ],
"person9": [ "company3", "company2" ],
"person12": ["company4"],
"person8": ["company1"],
"person7": [ "company3", "company2" ],
"person6": ["company1"],
"person10": [ "company3", "company1" ],
"person5": ["company2"],
"person11": ["company5"]
}},
{"@@companyEmployeeRelationships.size()": 12}
]
}
表达式声明的示例
Copy #Show various types of expression statements
CREATE QUERY expressionStmntEx() FOR GRAPH workNet {
TYPEDEF tuple<STRING countryName, STRING companyName> companyInfo;
ListAccum<companyInfo> @employerInfo;
SumAccum<INT> @@a;
ListAccum<STRING> @employers;
SumAccum<INT> @employerCount;
SetAccum<STRING> @@countrySet;
int x;
#exprStmnt := name "=" expr
x = 10;
#gAccumAssignStmt := "@@" name ("+=" | "=") expr
@@a = 10;
PRINT x, @@a;
start = {person.*};
employees = SELECT s FROM start:s -(worksFor)-> :t
ACCUM #exprStmnt := name "." "@" name ("+="| "=") expr
s.@employers += t.id,
#exprStmnt := name ["<" type ["," type"]* ">"] "(" [argList] ")"
s.@employerInfo += companyInfo(t.country, t.id),
#gAccumAccumStmt := "@@" name "+=" expr
@@countrySet += t.country
#exprStmnt := name "." "@" name ["." name "(" [argList] ")"]
POST-ACCUM s.@employerCount += s.@employers.size();
#exprStmnt := "@@" name ["." name "(" [argList] ")"]+
PRINT @@countrySet.size();
PRINT employees;
}
GSQL > RUN QUERY expressionStmntEx()
{
"error": false,
"message": "",
"version": {
"schema": 0,
"api": "v2"
},
"results": [
{
"@@a": 10,
"x": 10
},
{"@@countrySet.size()": 4},
{"employees": [
{
"v_id": "person4",
"attributes": {
"interestList": ["football"],
"skillSet": [ 10, 1, 4 ],
"skillList": [ 4, 1, 10 ],
"locationId": "us",
"@employerInfo": [{
"companyName": "company2",
"countryName": "chn"
}],
"interestSet": ["football"],
"@employerCount": 1,
"id": "person4",
"@employers": ["company2"]
},
"v_type": "person"
},
{
"v_id": "person11",
"attributes": {
"interestList": [ "sport", "football" ],
"skillSet": [10],
"skillList": [10],
"locationId": "can",
"@employerInfo": [{
"companyName": "company5",
"countryName": "can"
}],
"interestSet": [ "football", "sport" ],
"@employerCount": 1,
"id": "person11",
"@employers": ["company5"]
},
"v_type": "person"
},
{
"v_id": "person10",
"attributes": {
"interestList": [ "football", "sport" ],
"skillSet": [3],
"skillList": [3],
"locationId": "us",
"@employerInfo": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"interestSet": [ "sport", "football" ],
"@employerCount": 2,
"id": "person10",
"@employers": [ "company3", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person7",
"attributes": {
"interestList": [ "art", "sport" ],
"skillSet": [ 6, 8 ],
"skillList": [ 8, 6 ],
"locationId": "us",
"@employerInfo": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company2",
"countryName": "chn"
}
],
"interestSet": [ "sport", "art" ],
"@employerCount": 2,
"id": "person7",
"@employers": [ "company3", "company2" ]
},
"v_type": "person"
},
{
"v_id": "person1",
"attributes": {
"interestList": [ "management", "financial" ],
"skillSet": [ 3, 2, 1 ],
"skillList": [ 1, 2, 3 ],
"locationId": "us",
"@employerInfo": [
{
"companyName": "company2",
"countryName": "chn"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"interestSet": [ "financial", "management" ],
"@employerCount": 2,
"id": "person1",
"@employers": [ "company2", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person6",
"attributes": {
"interestList": [ "music", "art" ],
"skillSet": [ 10, 7 ],
"skillList": [ 7, 10 ],
"locationId": "jp",
"@employerInfo": [{ "companyName": "company1", "countryName": "us" }],
"interestSet": [ "art", "music" ],
"@employerCount": 1,
"id": "person6",
"@employers": ["company1"]
},
"v_type": "person"
},
{
"v_id": "person2",
"attributes": {
"interestList": ["engineering"],
"skillSet": [ 6, 5, 3, 2 ],
"skillList": [ 2, 3, 5, 6 ],
"locationId": "chn",
"@employerInfo": [
{
"companyName": "company2",
"countryName": "chn"
},
{
"companyName": "company1",
"countryName": "us"
}
],
"interestSet": ["engineering"],
"@employerCount": 2,
"id": "person2",
"@employers": [ "company2", "company1" ]
},
"v_type": "person"
},
{
"v_id": "person5",
"attributes": {
"interestList": [ "sport", "financial", "engineering" ],
"skillSet": [ 5, 2, 8 ],
"skillList": [ 8, 2, 5 ],
"locationId": "can",
"@employerInfo": [{
"companyName": "company2",
"countryName": "chn"
}],
"interestSet": [ "engineering", "financial", "sport" ],
"@employerCount": 1,
"id": "person5",
"@employers": ["company2"]
},
"v_type": "person"
},
{
"v_id": "person12",
"attributes": {
"interestList": [
"music",
"engineering",
"teaching",
"teaching",
"teaching"
],
"skillSet": [ 2, 5, 1 ],
"skillList": [ 1, 5, 2, 2, 2 ],
"locationId": "jp",
"@employerInfo": [{ "companyName": "company4", "countryName": "us" }],
"interestSet": [ "teaching", "engineering", "music" ],
"@employerCount": 1,
"id": "person12",
"@employers": ["company4"]
},
"v_type": "person"
},
{
"v_id": "person3",
"attributes": {
"interestList": ["teaching"],
"skillSet": [ 6, 1, 4 ],
"skillList": [ 4, 1, 6 ],
"locationId": "jp",
"@employerInfo": [{ "companyName": "company1", "countryName": "us" }],
"interestSet": ["teaching"],
"@employerCount": 1,
"id": "person3",
"@employers": ["company1"]
},
"v_type": "person"
},
{
"v_id": "person9",
"attributes": {
"interestList": [ "financial", "teaching" ],
"skillSet": [ 2, 7, 4 ],
"skillList": [ 4, 7, 2 ],
"locationId": "us",
"@employerInfo": [
{
"companyName": "company3",
"countryName": "jp"
},
{
"companyName": "company2",
"countryName": "chn"
}
],
"interestSet": [ "teaching", "financial" ],
"@employerCount": 2,
"id": "person9",
"@employers": [ "company3", "company2" ]
},
"v_type": "person"
},
{
"v_id": "person8",
"attributes": {
"interestList": ["management"],
"skillSet": [ 2, 5, 1 ],
"skillList": [ 1, 5, 2 ],
"locationId": "chn",
"@employerInfo": [{ "companyName": "company1", "countryName": "us" }],
"interestSet": ["management"],
"@employerCount": 1,
"id": "person8",
"@employers": ["company1"]
},
"v_type": "person"
}
]}
]
}