Accumulators
Accumulators are special types of variables that accumulate information about the graph during its traversal and exploration. Because they are a unique and important feature of the GSQL query language, we devote a separate section for their introduction, but additional detail on their usage will be covered in other sections, the "SELECT Statement" section in particular. This section covers the following subset of the EBNF language definitions:
EBNF
1
accumDeclStmt :=
2
accumType localAccumName ["=" constant]
3
["," localAccumName ["=" constant]]*
4
| [STATIC] accumType globalAccumName ["=" constant]
5
["," globalAccumName ["=" constant]]*
6
localAccumName := "@"accumName;
7
globalAccumName := "@@"accumName;
8
9
10
accumType := "SumAccum" "<" ( INT | FLOAT | DOUBLE | STRING | STRING COMPRESS) ">"
11
| "MaxAccum" "<" ( INT | FLOAT | DOUBLE ) ">"
12
| "MinAccum" "<" ( INT | FLOAT | DOUBLE ) ">"
13
| "AvgAccum"
14
| "OrAccum"
15
| "AndAccum"
16
| "BitwiseOrAccum"
17
| "BitwiseAndAccum"
18
| "ListAccum" "<" type ">"
19
| "SetAccum" "<" elementType ">"
20
| "BagAccum" "<" elementType ">"
21
| "MapAccum" "<" elementType "," (baseType | accumType | tupleType) ">"
22
| "HeapAccum" "<" tupleType ">" "(" simpleSize "," fieleName [ASC | DESC]
23
["," fieldName [ASC | DESC]]* ")"
24
| "GroupByAccum" "<" elementType fieldName ["," elementType fieldName]* ,
25
accumType fieldName ["," accumType fieldName]* ">"
26
| "ArrayAccum" "<" accumName ">"
27
28
elementType := baseType | tupleType | STRING COMPRESS
29
30
gAccumAccumStmt := globalAccumName "+=" expr
31
32
accumClause := ACCUM DMLSubStmtList
33
34
postAccumClause := "POST-ACCUM" DMLSubStmtList
35
Copied!
There are a number of different types of accumulators, each providing specific accumulation functions. Accumulators are declared to have one of two types of association: global or vertex-attached.
More technically, accumulators are mutable mutex variables shared among all the graph computation threads exploring the graph within a given query. To improve performance, the graph processing engine employs multithreaded processing. Modification of accumulators is coordinated at run-time so the accumulation operator works correctly (i.e., mutually exclusively) across all threads. This is particularly relevant in the ACCUM clause. During traversal of the graph, the selected set of edges or vertices is partitioned among a group of threads. These threads have shared mutually exclusive access to the accumulators.

Declaration of Accumulators

Global accumulators can be declared anywhere in the query. Vertex-attached accumulators can be declared anywhere in the query except for in a FOREACH loop or WHILE loop. Accumulators are block-scoped and can only be accessed in the block where they are declared.
The name of a vertex-attached accumulator begins with a single @. The name of a global accumulator begins with @@. Additionally, a global accumulator may be declared to be static.
EBNF for Accumulator Declaration
1
accumDeclStmt :=
2
accumType localAccumName ["=" expr]
3
["," localAccumName ["=" expr]]*
4
| [STATIC] accumType globalAccumName ["=" expr]
5
["," globalAccumName ["=" expr]]*
6
localAccumName := "@"accumName;
7
globalAccumName := "@@"accumName;
Copied!

Vertex-attached Accumulators

Vertex-attached accumulators are mutable state variables that are attached to each vertex in the graph for the duration of the query's lifetime. They act as run-time attributes of a vertex. They are shared, mutual exclusively, among all of the query's processes.
Vertex-attached accumulators can be set to a value with the = operator. Additionally, an accumulate operator += can be used to update the state of the accumulator; the function of += depends on the accumulator type.
In the example below, there are two accumulators attached to each vertex. The initial value of an accumulator of a given type is predefined, however it can be changed at declaration as in the accumulator @weight below. All vertex-attached accumulator names have a single leading at-sign "@".
Vertex-Attached Accumulators
1
SumAccum<int> @neighbors;
2
MaxAccum<float> @weight = 2.8;
Copied!
If there is a graph with 10 vertices, then there is an instance of @neighbors and @weight for each vertex (hence 10 of each, and 20 total accumulator instances). These are accessed via the dot operator on a vertex variable or a vertex alias (e.g., [email protected] ). The accumulator operator += only impacts the accumulator for the specific vertex being referenced. A statement such as [email protected] += 1will only impact v1 's @neighbors and not the @neighbors for other vertices.
Vertex-attached accumulators can only be accessed or updated (via = or +=) in an ACCUM or POST-ACCUM clause within a SELECT block. The only exception to this rule is that vertex-attached accumulators can be referenced in a PRINT statement, as the PRINT has access to all information attached to a vertex set.
Edge-attached accumulators are not supported.

Global Accumulators

A global accumulator is a single mutable accumulator that can be accessed or updated within a query. The names of global accumulators start with a double at-sign "@@".
Global Accumulators
1
SumAccum<int> @@totalNeighbors;
2
MaxAccum<float> @@entropy = 1.0;
Copied!
Global accumulators can only be assigned (using the = operator) outside a SELECT block (i.e., not within an ACCUM or POST-ACCUM clause). Global accumulators can be accessed or updated via the accumulate operator += anywhere within a query, including inside a SELECT block.
It is important to note that the accumulation operation for global accumulators in an ACCUM clause executes once for each process. That is, if the FROM clause uses an edge-induced selection (introduced in Section "SELECT Statement"), the ACCUM clause executes one process for each edge in the selected edge set. If the FROM clause uses a vertex-induced selection (introduced in Section "SELECT Statement"), the ACCUM clause executes one process for each vertex in the selected vertex set. Since global accumulators are shared in a mutually exclusive manner among processes, they behave very differently than a non-accumulator variable (see Section "Variable Types" for more details) in an ACCUM clause. Take the following code example. The global accumulator@@globalRelationshipCount is accumulated for every worksFor edge traversed since it is shared among processes. Conversely, relationshipCount appears to have only been incremented once. This is because a non-accumulator variable is not shared among processes. Each process has its own separate unshared copy of relationshipCount and increments the original value by one. (E.g., each process increments relationshipCount from 0 to 1.) There is no accumulation and the final value is one.
Global Variable vs Global Accumulator
1
#Count the total number of employment relationships for all companies
2
CREATE QUERY countEmploymentRelationships() FOR GRAPH workNet {
3
4
INT localRelationshipCount;
5
SumAccum<INT> @@globalRelationshipCount;
6
7
start = {company.*};
8
9
companies = SELECT s FROM start:s -(worksFor)-> :t
10
ACCUM @@globalRelationshipCount += 1,
11
localRelationshipCount = localRelationshipCount + 1;
12
13
PRINT localRelationshipCount;
14
PRINT @@globalRelationshipCount;
15
}
Copied!
countEmploymentRelationship.json Results
1
GSQL > RUN QUERY countEmploymentRelationships()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"localRelationshipCount": 1},
12
{"@@globalRelationshipCount": 17}
13
]
14
}
Copied!

Static Global Accumulators

A static global accumulator retains its value after the execution of a query. To declare a static global accumulator, include the STATIC keyword at the beginning of the declaration statement. For example, if a static global accumulator is incremented by 1 each time a query is executed, then its value is equal to the number of times the query has been run, since the query was installed. Each static global accumulator belongs to the particular query in which it is declared; it cannot be shared among different queries. The value only persists in the context of running the same query multiple times. The value will reset to the default value when the GPE is restarted.
Static Global Accumulators example
1
CREATE QUERY staticAccumEx(INT x) FOR GRAPH minimalNet {
2
STATIC ListAccum<INT> @@testList;
3
@@testList += x;
4
PRINT @@testList;
5
}
Copied!
staticAccumEx.json Result
1
GSQL > RUN QUERY staticAccumEx(3)
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [{"@@testList": [
11
3,
12
-5,
13
3
14
]}]
15
}
16
GSQL > RUN QUERY staticAccumEx(-5)
17
{
18
"error": false,
19
"message": "",
20
"version": {
21
"edition": "developer",
22
"schema": 0,
23
"api": "v2"
24
},
25
"results": [{"@@testList": [
26
3,
27
-5,
28
3,
29
-5
30
]}]
31
}
Copied!
There is no command to deallocate a static global accumulator. If a static global accumulator is a collection accumulator and is no longer needed, it should be cleared to minimize memory usage.

Accumulator Types

The following are the accumulator types we currently support. Each type of accumulator supports one or more data types.
EBNF for Accumulator Types
1
accumType := "SumAccum" "<" ( INT | FLOAT | DOUBLE | STRING | STRING COMPRESS) ">"
2
| "MaxAccum" "<" ( INT | FLOAT | DOUBLE ) ">"
3
| "MinAccum" "<" ( INT | FLOAT | DOUBLE ) ">"
4
| "AvgAccum"
5
| "OrAccum"
6
| "AndAccum"
7
| "BitwiseOrAccum"
8
| "BitwiseAndAccum"
9
| "ListAccum" "<" type ">"
10
| "SetAccum" "<" elementType ">"
11
| "BagAccum" "<" elementType ">"
12
| "MapAccum" "<" elementType "," (baseType | accumType | tupleType) ">"
13
| "HeapAccum" "<" tupleType ">" "(" simpleSize "," fieleName [ASC | DESC]
14
["," fieldName [ASC | DESC]]* ")"
15
| "GroupByAccum" "<" elementType fieldName ["," elementType fieldName]* ,
16
accumType fieldName ["," accumType fieldName]* ">"
17
| "ArrayAccum" "<" accumName ">"
18
19
elementType := baseType | tupleType | STRING COMPRESS
20
21
gAccumAccumStmt := globaAccumName "+=" expr
Copied!
The accumulators fall into two major groups :
  • Scalar Accumulators store a single value:
    • SumAccum
    • MinAccum, MaxAccum
    • AvgAccum
    • AndAccum, OrAccum
    • BitwiseAndAccum, BitwiseOrAccum
  • Collection Accumulators store a set of values:
    • ListAccum
    • SetAccum
    • BagAccum
    • MapAccum
    • ArrayAccum
    • HeapAccum
    • GroupByAccum
The details of each accumulator type are summarized in the table below. The Accumulation Operation column explains how the accumulator accumName is updated when the statement accumName += newVal is executed. Following the table are example queries for each accumulator type.
Table Ac1: Accumulator Types and Their Accumulation Behavior
Accumulator Type (Case Sensitive)
Default Initial Value
Accumulation operation (result of accumName += newVal )
SumAccum<INT>
0
accumName plus newVal
SumAccum<FLOAT or DOUBLE>
0.0
accumName plus newVal
SumAccum<STRING>
empty string
String concatenation of accumName and newVal
MaxAccum<INT>
INT_MIN
The greater of newVal and accumName
MaxAccum<FLOAT or DOUBLE>
FLOAT_MIN or DOUBLE_MIN
The greater of newVal and accumName
MaxAccum<STRING>
empty string
The greater of newVal and accumName , according to UTF-8 lexicographical ordering
MaxAccum<VERTEX>
the vertex with internal id 0
The vertex with the greater internal id , either newVal or accumName
MaxAccum<tupleTyple>
default for each field of the tuple
The greater of newVal and accumName. tupleType is a user-defined sequence of baseTypes. Ordering is hierarchical, using the leftmost field of the tuple first, then the next field, and so on.
MinAccum<INT>
INT_MAX
The lesser of newVal and accumName
MinAccum<FLOAT or DOUBLE>
FLOAT_MAX or DOUBLE_MAX
The lesser of newVal and accumName
MinAccum<STRING>
empty string
The lesser of newVal and accumName , according to UTF-8 lexicographical ordering
MinAccum<VERTEX>
unknown
The vertex with the lesser internal id, either newVal or accumName
MinAccum<tupleType>
default for each field of the tuple
The lesser of newVal and accumName. tupleType is a user-defined sequence of baseTypes. Ordering is hierarchical, using the leftmost field of the tuple first, then the next field, and so on.
AvgAccum
0.0 (double precision)
Double precision average of newVal and all previous values accumulated toaccumName
AndAccum
True
Boolean AND of newVal and accumName
OrAccum
False
Boolean OR of newVal and accumName
BitwiseAndAccum
-1 (INT) = 64-bit sequence of 1s
Bitwise AND of newVal and accumName
BitwiseOrAccum
0 (INT) = 64-bit sequence of 0s
Bitwise OR of newVal and accumName
ListAccum< type >
(ordered collection of elements)
empty list
List with newVal appended to end of accumName. newVal can be a single value or a list. If accumName is [ 2, 4, 6 ], then accumName += 4 produces accumName equal to [ 2, 4, 6, 4 ]
SetAccum< type >
(unordered collection of elements, duplicate items not allowed)
empty set
Set union of newVal and accumName . newVal can be a single value or a set/bag.If accumName is ( 2, 4, 6 ), then accumName += 4 produces accumName equal to ( 2, 4, 6)
BagAccum<type >
(unordered collection of elements, duplicate items allowed)
empty bag
Bag union of newVal and accumName . newVal can be a single value or a set/bag.If accumName is ( 2, 4, 6 ), then accumName += 4 would result in accumName equal to ( 2, 4, 4, 6)
MapAccum< type, type >
(unordered collection of (key,value) pairs)
empty map
Add or update a key:value pair to the accumName map. If accumName is [ ("red",3), ("green",4),("blue",2) ], then accumName += ("black"-> 5) produces accumName equal to [ ("red",3), ("green",4),("blue",2), ("black",5) ]
ArrayAccum< accumType >
empty list
See the ArrayAccum section below for details.
HeapAccum< tuple >(heapSize, sortKey [, sortKey_i]*)
(sorted collection of tuples)
empty heap
Insert newVal into the accumName heap, maintaining the heap in sorted order, according to the sortKey(s) and size limit declared for this HeapAccum
GroupByAccum< type [, type]* , accumType [, accumType]* >
empty group by map
Add or update a key:value pair in accumName . See Section "GroupByAccum" for more details.

SumAccum

The SumAccum type computes and stores the cumulative sum of numeric values or the cumulative concatenation of text values. The output of a SumAccum is a single numeric or string value. SumAccum variables operate on values of type INT, UINT, FLOAT, DOUBLE, or STRING only.
The += operator updates the accumulator's state. For INT, FLOAT, and DOUBLE types, += arg performs a numeric addition, while for the STRING value type += arg concatenates arg to the current value of the SumAccum.
SumAccum Example
1
# SumAccum Example
2
CREATE QUERY sumAccumEx() FOR GRAPH minimalNet {
3
4
SumAccum<INT> @@intAccum;
5
SumAccum<FLOAT> @@floatAccum;
6
SumAccum<DOUBLE> @@doubleAccum;
7
SumAccum<STRING> @@stringAccum;
8
9
@@intAccum = 1;
10
@@intAccum += 1;
11
12
@@floatAccum = @@intAccum;
13
@@floatAccum = @@floatAccum / 3;
14
15
@@doubleAccum = @@floatAccum * 8;
16
@@doubleAccum += -1;
17
18
@@stringAccum = "Hello ";
19
@@stringAccum += "World";
20
21
PRINT @@intAccum;
22
PRINT @@floatAccum;
23
PRINT @@doubleAccum;
24
PRINT @@stringAccum;
25
}
Copied!
sumAccumEx.json Result
1
GSQL > RUN QUERY sumAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"@@intAccum": 2},
12
{"@@floatAccum": 0.66667},
13
{"@@doubleAccum": 4.33333},
14
{"@@stringAccum": "Hello World"}
15
]
16
}
Copied!

MinAccum / MaxAccum

The MinAccum and MaxAccum types calculate and store the cumulative minimum or the cumulative maximum of a series of values. The output of a MinAccum or a MaxAccum is a single value of the type that was passed in. MinAccum and MaxAccum variables operate on values of type INT, UINT, FLOAT, DOUBLE, STRING, TUPLE, and VERTEX (with optional specific vertex type) only.
For MinAccum, += arg checks if the current value held is less than arg and stores the smaller of the two. MaxAccum behaves the same, with the exception that it checks for and stores the greater instead of the lesser of the two.
MinAccum and MaxAccum Example
1
# MinAccum and MaxAccum Example
2
CREATE QUERY minMaxAccumEx() FOR GRAPH minimalNet {
3
4
MinAccum<INT> @@minAccum;
5
MaxAccum<FLOAT> @@maxAccum;
6
7
@@minAccum += 40;
8
@@minAccum += 20;
9
@@minAccum += -10;
10
11
@@maxAccum += -1.1;
12
@@maxAccum += 2.5;
13
@@maxAccum += 2.8;
14
15
PRINT @@minAccum;
16
PRINT @@maxAccum;
17
}
Copied!
minMaxAccumEx.json Result
1
GSQL > RUN QUERY minMaxAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"@@minAccum": -10},
12
{"@@maxAccum": 2.8}
13
]
14
}
Copied!
String minimum and maximum values are based on their UTF-8 codes, which is a multilingual superset of the ASCII codes. Within ASCII, a < z, uppercase is less than lowercase, and digits are less than alphabetic characters.
MinAccum and MaxAccum operating on VERTEX type have a special comparison. They do not compare vertex ids, but TigerGraph internal ids, which might not be in the same order as the external ids. Comparing internal ids is much faster, so MinAccum/MaxAccum<VERTEX> provides an efficient way to compare and select vertices. This is helpful for some graph algorithms that require the vertices to be numbered and sortable. For example, the following query returns one post from each person. The returned vertex is not necessarily the vertex with the alphabetically largest id.
MaxAccum<VERTEX> example
1
# Output one random post vertex from each person
2
CREATE QUERY minMaxAccumVertex() FOR GRAPH socialNet api("v2") {
3
4
MaxAccum<VERTEX> @maxVertex;
5
allUser = {person.*};
6
allUser = SELECT src
7
FROM allUser:src -(posted)-> post:tgt
8
ACCUM src.@maxVertex += tgt
9
ORDER BY src.id;
10
PRINT allUser[allUser.@maxVertex]; // api v2
11
}
Copied!
minMaxAccuxVertex.json Result
1
GSQL > RUN QUERY minMaxAccumVertex()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [{"allUser": [
11
{
12
"v_id": "person1",
13
"attributes": {"[email protected]": "0"},
14
"v_type": "person"
15
},
16
{
17
"v_id": "person2",
18
"attributes": {"[email protected]": "1"},
19
"v_type": "person"
20
},
21
{
22
"v_id": "person3",
23
"attributes": {"[email protected]": "2"},
24
"v_type": "person"
25
},
26
{
27
"v_id": "person4",
28
"attributes": {"[email protected]": "3"},
29
"v_type": "person"
30
},
31
{
32
"v_id": "person5",
33
"attributes": {"[email protected]": "11"},
34
"v_type": "person"
35
},
36
{
37
"v_id": "person6",
38
"attributes": {"[email protected]": "10"},
39
"v_type": "person"
40
},
41
{
42
"v_id": "person7",
43
"attributes": {"[email protected]": "9"},
44
"v_type": "person"
45
},
46
{
47
"v_id": "person8",
48
"attributes": {"[email protected]": "7"},
49
"v_type": "person"
50
}
51
]}]
52
}
Copied!
Tuple data types are treated as hierarchical structures, where the first field used for ordering is the leftmost one. When a tuple is used as an element of a MinAccum or MaxAccum, tuple fields can be directly accessed from the accumulator. For example, if we have the following tuple type and MaxAccum :
1
TYPEDEF TUPLE <FLOAT weight> EDGE_WEIGHT
2
MinAccum<EDGE_WEIGHT> @@AccTest;
Copied!
Then the weight field of the tuple can be accessed directly from the MacAccum through the doc operator(.):
1
@@AccTest.weight // Will return the weight field value for the EDGE_WEIGHT
2
// type tuple stored in the MaxAccum
Copied!

AvgAccum

The AvgAccum type calculates and stores the cumulative mean of a series of numeric values. Internally, its state information includes the sum value of all inputs and a count of how many input values it has accumulated. The output is the mean value; the sum and the count values are not accessible to the user. The data type of an AvgAccum variable is not declared; all AvgAccum accumulators accept inputs of type INT, UINT, FLOAT, and DOUBLE. The output is always DOUBLE type.
The += arg operation updates the AvgAccum variable's state to be the mean of all the previous arguments along with the current argument; The = arg operation clears all the previously accumulated state and sets the new state to be arg with a count of one.
AvgAccum Example
1
# AvgAccum Example
2
CREATE QUERY avgAccumEx() FOR GRAPH minimalNet {
3
4
AvgAccum @@averageAccum;
5
6
@@averageAccum += 10;
7
@@averageAccum += 5.5; # avg = (10+5.5) / 2.0
8
@@averageAccum += -1; # avg = (10+5.5-1) / 3.0
9
10
PRINT @@averageAccum; # 4.8333...
11
12
@@averageAccum = 99; # reset
13
@@averageAccum += 101; # avg = (99 + 101) / 2
14
15
PRINT @@averageAccum; # 100
16
}
Copied!
avgAccumEx.json Result
1
GSQL > RUN QUERY avgAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"@@averageAccum": 4.83333},
12
{"@@averageAccum": 100}
13
]
14
}
Copied!

AndAccum / OrAccum

The AndAccum and OrAccum types calculate and store the cumulative result of a series of boolean operations. The output of an AndAccum or an OrAccum is a single boolean value (True or False). AndAccum and OrAccum variables operate on boolean values only. The data type does not need to be declared.
For AndAccum, += arg updates the state to be the logical AND between the current boolean state and arg. OrAccum behaves the same, with the exception that it stores the result of a logical OR operation.
AndAccum and OrAccum Example
1
# AndAccum and OrAccum Example
2
CREATE QUERY andOrAccumEx() FOR GRAPH minimalNet {
3
# T = True
4
# F = False
5
6
AndAccum @@andAccumVar; # (default value = T)
7
OrAccum @@orAccumVar; # (default value = F)
8
9
@@andAccumVar += True; # T and T = T
10
@@andAccumVar += False; # T and F = F
11
@@andAccumVar += True; # F and T = F
12
13
PRINT @@andAccumVar;
14
15
@@orAccumVar += False; # F or F == F
16
@@orAccumVar += True; # F or T == T
17
@@orAccumVar += False; # T or F == T
18
19
PRINT @@orAccumVar;
20
}
Copied!
andOrAccumEx.json Result
1
GSQL > RUN QUERY andOrAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"@@andAccumVar": false},
12
{"@@orAccumVar": true}
13
]
14
}
Copied!

BitwiseAndAccum / BitwiseOrAccum

The BitwiseAndAccum and BitwiseOrAccum types calculate and store the cumulative result of a series of bitwise boolean operations and store the resulting bit sequences. BitwiseAndAccum and BitwiseOrAccum operator on INT only. The data type does not need to be declared.
Fundamental for understanding and using bitwise operations is the knowledge that integers are stored in base-2 representation as a 64-bit sequence of 1s and 0s. "Bitwise" means that each bit is treated as a separate boolean value, with 1 representing true and 0 representing false. Hence, an integer is equivalent to a sequence of boolean values. Computing the Bitwise AND of two numbers A and B means to compute the bit sequence C where the j th bit of C, denoted C j , is equal to (A j AND B j ).
For BitwiseAndAccum, += arg updates the accumulator's state to be the Bitwise AND of the current state and arg . BitwiseOrAccum behaves the same, with the exception that it computes a Bitwise OR.
Bitwise Operations and Negative Integers
Most computer systems represent negative integers using "2's complement" format, where the uppermost bit has special significance. Operations that affect the uppermost bit are crossing the boundary between positive and negative numbers, and vice versa.
BitwiseAndAccum and BitwiseOrAccum Example
1
# BitwiseAndAccum and BitwiseOrAccum Example
2
CREATE QUERY bitwiseAccumEx() FOR GRAPH minimalNet {
3
4
BitwiseAndAccum @@bwAndAccumVar; # default value = 64-bits of 1 = -1 (INT)
5
BitwiseOrAccum @@bwOrAccumVar; # default value = 64-bits of 0 = 0 (INT))
6
7
# 11110000 = 240
8
# 00001111 = 15
9
# 10101010 = 170
10
# 01010101 = 85
11
12
# BitwiseAndAccum
13
@@bwAndAccumVar += 170; # 11111111 & 10101010 -> 10101010
14
@@bwAndAccumVar += 85; # 10101010 & 01010101 -> 00000000
15
PRINT @@bwAndAccumVar; # 0
16
17
@@bwAndAccumVar = 15; # reset to 00001111
18
@@bwAndAccumVar += 85; # 00001111 & 01010101 -> 00000101
19
PRINT @@bwAndAccumVar; # 5
20
21
# BitwiseOrAccum
22
@@bwOrAccumVar += 170; # 00000000 | 10101010 -> 10101010
23
@@bwOrAccumVar += 85; # 10101010 | 01010101 -> 11111111 = 255
24
PRINT @@bwOrAccumVar; # 255
25
26
@@bwOrAccumVar = 15; # reset to 00001111
27
@@bwOrAccumVar += 85; # 00001111 | 01010101 -> 01011111 = 95
28
PRINT @@bwOrAccumVar; # 95
29
}
Copied!
bitwiseAccumEx.json Result
1
GSQL > RUN QUERY bitwiseAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"@@bwAndAccumVar": 0},
12
{"@@bwAndAccumVar": 5},
13
{"@@bwOrAccumVar": 255},
14
{"@@bwOrAccumVar": 95}
15
]
16
}
Copied!

ListAccum

The ListAccum type maintains a sequential collection of elements. The output of a ListAccum is a list of values in the order the elements were added. The element type can be any base type, tuple, or STRING COMPRESS. Additionally, a ListAccum can contain a nested collection of type ListAccum. Nesting of ListAccums is limited to a depth of three.
The += arg operation appends arg to the end of the list. In this case, arg may be either a single element or another ListAccum.
ListAccum supports two additional operations:
  • @list1 + @list2 creates a new ListAccum, which contains the elements of @list1 followed by the elements of @list2. The two ListAccums must have identical data types.
Change in "+" definition
The pre-v2.0 definition of the ListAccum "+" operator ( @list + arg: Add arg to each member of @list) is no longer supported.
  • @list1 * @list2 (STRING data only) generates a new list of strings consisting of all permutations of an element of the first list followed by an element of the second list.
ListAccum also supports the following class functions.
Functions that modify the ListAccum (mutator functions) can be used only under the following conditions:
  • Mutator functions of global accumulators may only be used at the query-body level.
  • Mutator functions of vertex-attached accumulators may only be used in a POST-ACCUM clause.
Function (T is the element type)
Return type
Accessor / Mutator
Description
.size()
INT
Accessor
Returns the number of elements in the list.
.contains( T val )
BOOL
Accessor
Returns true/false if the list does/doesn't contain the value .
.get( INT idx )
T
Accessor
Returns the value at the given index position in the list. The index begins at 0. If the index is out of bound (including any negative value), the default value of the element type is returned.
.clear()
VOID
Mutator
Clears the list so it becomes empty with size 0.
.update (INT index, T value )
VOID
Mutator
Assigns value to the list element at position index.
ListAccum Example
1
# ListAccum Example
2
CREATE QUERY listAccumEx() FOR GRAPH minimalNet {
3
4
ListAccum<INT> @@intListAccum;
5
ListAccum<STRING> @@stringListAccum;
6
ListAccum<STRING> @@stringMultiplyListAccum;
7
ListAccum<STRING> @@stringAdditionAccum;
8
ListAccum<STRING> @@letterListAccum;
9
ListAccum<ListAccum<STRING>> @@nestedListAccum;
10
11
@@intListAccum = [1,3,5];
12
@@intListAccum += [7,9];
13
@@intListAccum += 11;
14
@@intListAccum += 13;
15
@@intListAccum += 15;
16
17
PRINT @@intListAccum;
18
PRINT @@intListAccum.get(0), @@intListAccum.get(1);
19
PRINT @@intListAccum.get(8); # Out of bound: default value of int: 0
20
21
#Other built-in functions
22
PRINT @@intListAccum.size();
23
PRINT @@intListAccum.contains(2);
24
PRINT @@intListAccum.contains(3);
25
26
@@stringListAccum += "Hello";
27
@@stringListAccum += "World";
28
29
PRINT @@stringListAccum; // ["Hello","World"]
30
31
@@letterListAccum += "a";
32
@@letterListAccum += "b";
33
34
# ListA + ListB produces a new list equivalent to ListB appended to ListA.
35
# Ex: [a,b,c] + [d,e,f] => [a,b,c,d,e,f]
36
@@stringAdditionAccum = @@stringListAccum + @@letterListAccum;
37
38
PRINT @@stringAdditionAccum;
39
40
#Multiplication produces a list of all list-to-list element combinations (STRING TYPE ONLY)
41
# Ex: [a,b] * [c,d] = [ac, ad, bc, bd]
42
@@stringMultiplyListAccum = @@stringListAccum * @@letterListAccum;
43
44
PRINT @@stringMultiplyListAccum;
45
46
#Two dimensional list (3 dimensions is possible as well)
47
@@nestedListAccum += [["foo", "bar"], ["Big", "Bang", "Theory"], ["String", "Theory"]];
48
49
PRINT @@nestedListAccum;
50
PRINT @@nestedListAccum.get(0);
51
PRINT @@nestedListAccum.get(0).get(1);
52
}
Copied!
listAccumEx.json Result
1
GSQL > RUN QUERY listAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [ {"@@intListAccum": [ 1, 3, 5, 7, 9, 11, 13, 15 ]},
11
{
12
"@@intListAccum.get(0)": 1,
13
"@@intListAccum.get(1)": 3
14
},
15
{"@@intListAccum.get(8)": 0},
16
{"@@intListAccum.size()": 8},
17
{"@@intListAccum.contains(2)": false},
18
{"@@intListAccum.contains(3)": true},
19
{"@@stringListAccum": [ "Hello", "World" ]},
20
{"@@stringAdditionAccum": [ "Hello", "World", "a", "b"]},
21
{"@@stringMultiplyListAccum": [ "Helloa", "Worlda", "Hellob", "Worldb" ]},
22
{"@@nestedListAccum": [
23
[ "foo", "bar" ],
24
[ "Big", "Bang", "Theory" ],
25
[ "String", "Theory" ]
26
]},
27
{"@@nestedListAccum.get(0)": [ "foo", "bar" ]},
28
{"@@nestedListAccum.get(0).get(1)": "bar"}
29
]
30
}
Copied!
Example for update function on a global ListAccum
1
CREATE QUERY listAccumUpdateEx() FOR GRAPH workNet {
2
3
# Global ListAccum
4
ListAccum<INT> @@intListAccum;
5
ListAccum<STRING> @@stringListAccum;
6
ListAccum<BOOL> @@passFail;
7
8
@@intListAccum += [0,2,4,6,8];
9
@@stringListAccum += ["apple","banana","carrot","daikon"];
10
11
# Global update at Query-Body Level
12
@@passFail += @@intListAccum.update(1,-99);
13
@@passFail += @@intListAccum.update(@@intListAccum.size()-1,40); // last element
14
@@passFail += @@stringListAccum.update(0,"zero"); // first element
15
@@passFail += @@stringListAccum.update(4,"four"); // FAIL: out-of-range
16
17
PRINT @@intListAccum, @@stringListAccum, @@passFail;
18
}
Copied!
Results in listAcccumUpdateEx.json
1
GSQL > RUN QUERY listAccumUpdateEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [{
11
"@@passFail": [ true, true, true, false ],
12
"@@intListAccum": [ 0, -99, 4, 6, 40 ],
13
"@@stringListAccum": [ "zero", "banana", "carrot", "daikon" ]
14
}]
15
}
Copied!
Example for update function on a vertex-attached ListAccum
1
CREATE QUERY listAccumUpdateEx2(SET<VERTEX<person>> seed) FOR GRAPH workNet api("v2") {
2
3
# Each person has an LIST<INT> of skills and a LIST<STRING COMPRESS> of interests.
4
# This function copies their lists into ListAccums, and then udpates the last
5
# int with -99 and updates the last string with "fizz".
6
ListAccum<INT> @intList;
7
ListAccum<STRING COMPRESS> @stringList;
8
ListAccum<STRING> @@intFails, @@strFails;
9
10
S0 (person) = seed;
11
S1 = SELECT s
12
FROM S0:s
13
ACCUM
14
s.@intList = s.skillList,
15
s.@stringList = s.interestList
16
POST-ACCUM
17
INT len = s.@intList.size(),
18
IF NOT s.@intList.update(len-1,-99) THEN
19
@@intFails += s.id END,
20
INT len2 = s.@stringList.size(),
21
IF NOT s.@stringList.update(len2-1,"fizz") THEN
22
@@strFails += s.id END
23
;
24
PRINT S1[S1.skillList, S1.interestList, S1.@intList, S1.@stringList]; // api v2
25
PRINT @@intFails, @@strFails;
26
}
Copied!
Results for listAccumUpdateEx2
1
GSQL > RUN QUERY listAccumUpdateEx2(["person1","person5"])
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [
11
{"S1": [
12
{
13
"v_id": "person1",
14
"attributes": {
15
"[email protected]": [ "management","fizz" ],
16
"S1.interestList": [ "management", "financial"],
17
"S1.skillList": [ 1, 2, 3 ],
18
"[email protected]": [ 1, 2, -99 ]
19
},
20
"v_type": "person"
21
},
22
{
23
"v_id": "person5",
24
"attributes": {
25
"[email protected]": [ "sport", "financial", "fizz" ],
26
"S1.interestList": [ "sport", "financial", "engineering" ],
27
"S1.skillList": [ 8, 2, 5 ],
28
"[email protected]": [ 8, 2, -99 ]
29
},
30
"v_type": "person"
31
}
32
]},
33
{
34
"@@strFails": [],
35
"@@intFails": []
36
}
37
]
38
}
Copied!

SetAccum

The SetAccum type maintains a collection of unique elements. The output of a SetAccum is a list of elements in arbitrary order. A SetAccum instance can contain values of one type. The element type can be any base type, tuple, or STRING COMPRESS.
For SetAccum, the += arg operation adds a non-duplicate element or set of elements to the set. If an element is already represented in the set, then the SetAccum state does not change.
SetAccum also can be used with the three canonical set operators: UNION, INTERSECT, and MINUS (see Section "Set/Bag Expression and Operators" for more details).
SetAccum also supports the following class functions.
Functions that modify the SetAccum (mutator functions) can be used only under the following conditions:
  • Mutator functions of global accumulators may only be used at the query-body level.
  • Mutator functions of vertex-attached accumulators may only be used in a POST-ACCUM clause.
Function (T is the element type)
Return type
Accessor / Mutator
Description
size()
INT
Accessor
Returns the number of elements in the set.
contains( T value )
BOOL
Accessor
Returns true/false if the set does/doesn't contain the value.
remove( T value )
VOID
Mutator
Removes value from the set.
clear()
VOID
Mutator
Clears the set so it becomes empty with size 0.
SetAccum Example
1
# SetAccum Example
2
CREATE QUERY setAccumEx() FOR GRAPH minimalNet {
3
4
SetAccum<INT> @@intSetAccum;
5
SetAccum<STRING> @@stringSetAccum;
6
7
@@intSetAccum += 5;
8
@@intSetAccum.clear();
9
10
@@intSetAccum += 4;
11
@@intSetAccum += 11;
12
@@intSetAccum += 1;
13
@@intSetAccum += 11; # Sets do not store duplicates
14
15
@@intSetAccum += (1,2,3,4); # Can create simple sets this way
16
PRINT @@intSetAccum;
17
@@intSetAccum.remove(2);
18
PRINT @@intSetAccum AS RemovedVal2; # Demostrate remove.
19
20
PRINT @@intSetAccum.contains(3);
21
22
@@stringSetAccum += "Hello";
23
@@stringSetAccum += "Hello";
24
@@stringSetAccum += "There";
25
@@stringSetAccum += "World";
26
PRINT @@stringSetAccum;
27
28
PRINT @@stringSetAccum.contains("Hello");
29
PRINT @@stringSetAccum.size();
30
}
Copied!
setAccumEx.json Result
1
GSQL > RUN QUERY setAccumEx()
2
{
3
"error": false,
4
"message": "",
5
"version": {
6
"edition": "developer",
7
"schema": 0,
8
"api": "v2"
9
},
10
"results": [ {"@@intSetAccum": [ 3, 2, 1, 11, 4 ]},
11
{"@@intSetAccum.contains(3)": true},
12