Data Types
This section describes the data types that are native to and are supported by the GSQL Query Language. Most of the data objects used in queries come from one of three sources:
-
The query’s input parameters
-
The vertices, edges, and their attributes which are encountered when traversing the graph
-
The variables defined within the query to assist in the computational work of the query
This section covers the following subset of the EBNF language definitions:
lowercase := [a-z]
uppercase := [A-Z]
letter := lowercase | uppercase
digit := [0-9]
integer := ["-"]digit+
real := ["-"]("."digit+) | ["-"](digit+"."digit*)
numeric := integer | real
stringLiteral := '"' [~["] | '\\' ('"' | '\\')]* '"'
name := (letter | "_") [letter | digit | "_"]* // Can be a single "_" or start with "_"
graphName := name
queryName := name
paramName := name
vertexType := name
edgeType := name
accumName := name
vertexSetName := name
attrName := name
varName := name
tupleType := name
fieldName :=name
funcName := name
type := baseType | tupleType | accumType | STRING COMPRESS
baseType := INT
| UINT
| FLOAT
| DOUBLE
| STRING
| BOOL
| VERTEX ["<" vertexType ">"]
| EDGE
| JSONOBJECT
| JSONARRAY
| DATETIME
filePath := paramName | stringLiteral
typedef := TYPEDEF TUPLE "<" tupleFields ">" tupleType
tupleFields := (baseType fieldName) | (fieldName baseType)
["," (baseType fieldName) | (fieldName baseType)]*
parameterType := baseType
| [ SET | BAG ] "<" baseType ">"
| FILE
Identifiers
An identifier is the name for an instance of a language element. In the GSQL query language, identifiers are used to name elements such as a query, a variable, or a user-defined function.
In the EBNF syntax, an identifier is referred as name.
It can be a sequence of letters, digits, or underscores ("_").
Other punctuation characters are not supported. The initial character can only be a letter or an underscore.
name := (letter | "_") [letter | digit | "_"]*
Overview
Different types of data can be used in different contexts.
The EBNF syntax defines several classes of data types.
The most basic is called base type (baseType).
The other independent types are FILE and STRING COMPRESS.
The remaining types are either compound data types built from the independent data types, or supersets of other types. The table below gives an overview of their definitions and their uses.
| EBNF term | Description | Use Case |
|---|---|---|
|
|
|
|
|
|
|
Sequence of base types |
|
|
Family of specialized data objects which support accumulation operations |
|
|
|
|
|
|
|
(⚠Deprecated data type. Please use |
|
|
|
|
|
|
|
|
Base types
The query language supports the following base types, which can be declared and assigned anywhere within their scope. Any of these base types may be used when defining a global variable, a local variable, a query return value, a parameter, part of a tuple, or an element of a container accumulator. Accumulators are described in detail in a later section.
baseType := INT
| UINT
| FLOAT
| DOUBLE
| STRING
| BOOL
| VERTEX ["<" vertexType ">"]
| EDGE
| JSONOBJECT
| JSONARRAY
| DATETIME
The default value of each base type is shown in the table below. The default value is the initial value of a base type variable (see Section "Variable Types" for more details), or the default return value for some functions.
The first seven types (INT, UINT, FLOAT, DOUBLE, BOOL, STRING, and DATETIME) are the same ones mentioned in the "Attribute Data Types" section of _GSQL Language Reference, Part 1.
| Type | Default value | Literal |
|---|---|---|
|
|
A signed integer: |
|
|
An unsigned integer: |
|
|
A decimal: |
|
|
A decimal with greater precision than |
|
|
|
|
|
Characters enclosed by double quotes: |
|
|
No literal. Can be converted from a correctly formatted string with |
|
|
No literal. |
|
No edge: |
No literal. |
|
An empty object: |
No literal. Can be converted from a correctly formatted string with |
|
An empty array: |
No literal. Can be converted from a correctly formatted string with |
|
The GSQL Loader can read FLOAT and DOUBLE values with exponential notation (e.g., 1.25 E-7). |
Vertex
VERTEX is considered a base type in the GSQL query language.
Both query parameters and variables in a query body can be of type VERTEX.
Vertex types
A graph schema defines specific vertex types.
Each vertex type has its own set of attributes.
The parameter or variable type can be restricted by giving the vertex type in angle brackets <> after the keyword VERTEX.
A vertex variable declared without a specifier is called a generic vertex variable.
VERTEX anyVertex; VERTEX<person> owner;
All vertices have a built-in attribute type. The built-in attribute is of type string. You can access it with the dot (.) operator.
For example, if you declare a vertex variable VERTEX<person> personVertex, then personVertex.type returns "person".
Edge
EDGE is considered a base type in the GSQL query language.
Both query parameters and variables in a query body can be of type EDGE.
Edge types
A graph schema defines specific edge types.
Each edge type has its own set of attributes.
The parameter or variable type can be restricted by giving the edge type in angle brackets <> after the keyword EDGE.
An edge variable declared without a specifier is called a generic edge variable.
EDGE anyEdge; EDGE<friendship> friendEdge;
All edges have a built-in attribute type. The built-in attribute is of type string. You can access it with the dot (.) operator.
For example, if you define an edge variable EDGE<friendship> friendEdge, then friendEdge.type returns "Friendship".
Vertex and Edge Attribute Types
The following table maps vertex or edge attribute types in the Data Definition Language (DDL) to GSQL query language types. If an attribute of a vertex or edge is referenced in a GSQL query, they will be automatically converted to their corresponding data type in the GSQL query language.
| DDL | GSQL Query |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONOBJECT
A JSONOBJECT instance’s external representation (as input and output) is a string, starting and ending with curly braces ({}) which enclose an unordered list of key-value pairs.
JSONOBJECT is immutable.
No operator is allowed to alter its value.
Assign a JSONOBJECT value to a base type variable
There is no JSONOBJECT literal in the GSQL query language.
Therefore, to assign value to a JSONOBJECT base type variable in GSQL, you need to use the parse_json_object() function to convert a string representation of s JSON object to a JSONOBJECT value.
For example, the following line declares a variable han with a JSONOBJECT value:
JSONOBJECT han = parse_json_object("{\"f_name\": \"Han\", \"l_name\": \"Solo\"}");
JSONARRAY
A JSONARRAY is represented as a string, starting and ending with square brackets ([])which enclose an ordered list of values.
JSONARRAY is immutable.
No operator is allowed to alter its value.
Assign a JSONARRAY value to a base type variable
There is no JSONARRAY literal in the GSQL query language.
Therefore, to assign value to a JSONARRAY base type variable in GSQL, you need to use the parse_json_array() function to convert a string representation of s JSON object to a JSONARRAY value.
For example, the following line declares a variable fruits with a JSONARRAY value:
JSONARRAY fruits = parse_json_array("[\"apple\", \"banana\", \"citrus\"]");
Container types
Container types include the following data types:
-
SET -
BAG -
LIST -
MAP
| Type | Literal | Example | Default value |
|---|---|---|---|
|
Elements enclosed by parentheses, separated by commas. |
|
Empty set. |
|
Elements enclosed by parentheses, separated by commas. |
|
Empty bag. |
|
Elements enclosed by square brackets, separated by commas. |
|
Empty list. |
|
No literal. |
N/A |
Empty map. |
To see how container type variables are declared in a GSQL query, see Local container variables.
Tuple
A tuple is a user-defined data structure consisting of a fixed sequence of base type variables.
Tuple types can be created and named using a TYPEDEF statement.
Tuples must be defined first, before any other statements in a query.
typedef := TYPEDEF TUPLE "<" tupleFields ">" tupleType
tupleFields := (baseType fieldName) | (fieldName baseType)
["," (baseType fieldName) | (fieldName baseType)]*
A tuple can also be defined in a graph schema and then can be used as a vertex or edge attribute type. A tuple type that has been defined in the graph schema does not need to be re-defined in a query.
The vertex type person contains two complex attributes:
-
secretInfoof typeSECRET_INFO, which a user-defined tuple -
portfolioof typeMAP<STRING, DOUBLE>
Investment_Net SchemaTYPEDEF TUPLE <age UINT (4), mothers_name STRING(20) > SECRET_INFO
CREATE VERTEX Person(PRIMARY_ID person_id STRING, portfolio MAP<STRING, DOUBLE>, secret_info SECRET_INFO)
CREATE VERTEX Stock_Order(PRIMARY_ID order_id STRING, ticker STRING, order_size UINT, price FLOAT)
CREATE UNDIRECTED EDGE make_order(FROM Person, TO Stock_Order, order_time DATETIME)
CREATE GRAPH Investment_Net (*)
The query below reads both the SECRET_INFO tuple and the portfolio MAP.
The tuple type does not need to be redefined in the query.
To read and save the map, we define a MapAccum with the same types for key and value as the portfolio attribute.
In addition, the query creates a new tuple type, ORDER_RECORD.
CREATE QUERY tuple_ex(VERTEX<Person> p) FOR GRAPH Investment_Net{
TYPEDEF TUPLE <STRING ticker, FLOAT price, DATETIME order_time> Order_Record; (1)
SetAccum<Secret_Info> @@info; (2)
ListAccum<Order_Record> @@order_records;
MapAccum<STRING, DOUBLE> @@portf;
INIT = {p};
// Get person p's secret_info and portfolio
X = SELECT v FROM INIT:v
ACCUM @@portf += v.portfolio, @@info += v.secret_info;
// Search person p's orders to record ticker, price, and order time.
// Note that the tuple gathers info from both edges and vertices.
orders = SELECT t
FROM INIT:s -(Make_Order:e)-Stock_Order:t
ACCUM @@order_records += Order_Record(t.ticker, t.price, e.order_time);
PRINT @@portf, @@info;
PRINT @@order_records;
}
| 1 | This statement defines a new tuple Order_Record at the top of the query. |
| 2 | Secret_Info has already been defined in Investment_Net Schema. |
GSQL > RUN QUERY tuple_ex("person1")
{
"error": false,
"message": "",
"version": {
"schema": 0,
"edition": "enterprise",
"api": "v2"
},
"results": [
{
"@@info": [{
"mothers_name": "JAMES",
"age": 25
}],
"@@portf": {
"AAPL": 3142.24,
"MS": 5000,
"G": 6112.23
}
},
{"@@order_records": [
{
"ticker": "B",
"price": 202.32001,
"order_time": "2017-03-03 18:42:30"
},
{
"ticker": "AAPL",
"price": 34.42,
"order_time": "2017-03-03 18:42:28"
},
{
"ticker": "A",
"price": 50.55,
"order_time": "2017-03-03 18:42:29"
}
]}
]
}
STRING COMPRESS
|
|
STRING COMPRESS is an integer type encoded by the system to represent string values. STRING COMPRESS uses less memory than STRING.
The STRING COMPRESS type is designed to act like STRING: data are loaded and printed just as string data, and most functions and operators which take STRING input can also take STRING COMPRESS input. The difference is in how the data are stored internally.
A STRING COMPRESS value can be obtained from a STRING_SET COMPRESS or STRING_LIST COMPRESS attribute or from converting a STRING value.
Using STRING COMPRESS instead of STRING can sometimes reduce storage space used, but results in slower access times.
The storage space is only be smaller if:
-
The original strings are long.
-
There are only a small number of different strings.
Performance is always be slower compared to STRING; the slowdown is greater if the STRING COMPRESS attributes are accessed more often.
STRING COMPRESS type is beneficial for sets of string values when the same values are used multiple times.
In practice, STRING COMPRESS are most useful for container accumulators like ListAccum<STRING COMPRESS> or SetAccum<STRING COMPRESS>.
An accumulator containing STRING COMPRESS stores the dictionary when it is assigned an attribute value or from another accumulator containing STRING COMPRESS.
An accumulator containing STRING COMPRESS can store multiple dictionaries.
A STRING value can be converted to a STRING COMPRESS value only if the value is in the dictionaries.
If the STRING value is not in the dictionaries, the original string value is saved.
A STRING COMPRESS value can be automatically converted to a STRING value.
When a STRING COMPRESS value is output (e.g. by a PRINT statement), it is shown as a STRING.
Below is an example query that uses the STRING COMPRESS type.
CREATE QUERY string_compress_ex(VERTEX<Person> m1) FOR GRAPH Work_Net {
ListAccum<STRING COMPRESS> @@str_compress_list, @@str_compress_list2;
SetAccum<STRING COMPRESS> @@str_compress_set, @@str_compress_set2;
ListAccum<STRING> @@str_list, @@str_list2;
SetAccum<STRING> @@str_set, @@str_set2;
S = {m1};
S = SELECT s
FROM S:s
ACCUM @@str_set += s.interest_set,
@@str_list += s.interest_list,
// Uses the dictionary from person.interest_set
@@str_compress_set += s.interest_set,
// Use the dictionary from person.interest_list
@@str_compress_list += s.interest_list;
// @@str_compress_list2 gets the dictionary from @@str_compress_list, which is from person.interest_list
@@str_compress_list2 += @@str_compress_list;
// "xyz" is not in the dictionary, so store the actual string value
@@str_compress_list2 += "xyz";
@@str_compress_set2 += @@str_compress_set;
@@str_compress_set2 += @@str_set;
// String compress integer values are decoded to strings
@@str_list2 += @@str_compress_list;
@@str_set2 += @@str_compress_set;
PRINT @@str_set, @@str_list, @@str_compress_set, @@str_compress_list;
PRINT @@str_set2, @@str_list2, @@str_compress_set2, @@str_compress_list2;
}
GSQL > RUN QUERY string_compress_ex("person12")
{
"error": false,
"message": "",
"version": {
"edition": "developer",
"schema": 0,
"api": "v2"
},
"results": [
{
"@@str_compress_list": [
"music",
"engineering",
"teaching",
"teaching",
"teaching"
],
"@@strSet": [ "teaching", "engineering", "music" ],
"@@strCompressSet": [ "music", "engineering", "teaching" ],
"@@str_list": [
"music",
"engineering",
"teaching",
"teaching",
"teaching"
]
},
{
"@@strSet2": [ "music", "engineering", "teaching" ],
"@@strCompressList2": [
"music",
"engineering",
"teaching",
"teaching",
"teaching",
"xyz"
],
"@@strList2": [
"music",
"engineering",
"teaching",
"teaching",
"teaching"
],
"@@strCompressSet2": [ "teaching", "engineering", "music" ]
}
]
}
FILE Object
A FILE object is a sequential data storage object, associated with a text file on the local machine.
|
When referring to a |
When a FILE object is declared, associated with a particular text file, any existing content in the text file will be erased.
During the execution of the query, content written to the FILE will be appended to the FILE.
When the query where the FILE was declared finishes running, the FILE contents are saved to the text file.
A FILE object can be passed as a parameter to another query. When a query receives a FILE object as a parameter, it can append data to that FILE, as can every other query which receives this FILE object as a parameter.
Query parameter types
Input parameters to a query can be base type (except EDGE , JSONARRAY, or JSONOBJECT).
A parameter can also be a SET or BAG which uses base type (except EDGE , JSONARRAY, or JSONOBJECT) as the element type. A FILE object can also be a parameter.
Within the query, SET and BAG are converted to SetAccum and BagAccum, respectively.
|
A query parameter is immutable. It cannot be assigned a new value within the query. The |
parameterType := INT
| UINT
| FLOAT
| DOUBLE
| STRING
| BOOL
| VERTEX ["<" vertexType ">"]
| DATETIME
| [ SET | BAG ] "<" baseType ">"
| FILE
(SET<VERTEX<person> p1, BAG<INT> ids, FILE f1)