Change Password

Input error
Input error
Input error
Submit

Change Nickname

Current Nickname:
Submit
v4.0

Query

Graph data is dimensionally higher than tables, so that requires a more flexible and extensible organizational form to achieve the retrieval, traversal and aquisition of data. Unlike relational databases, graph traversal is more complex and diverse. For instance, it's necessary to use different logic or judgement rules to walk through the paths, which differs greatly from using only the nested forms in SQL. UQL is designed from the comprehension of data, graph data and graph computing business, it aims at making it clearly defined and easier for users to understand and operate. Therefore, UQL helps graph database operators to design complex graph query tasks more conveniently so that they may focus on business data query design, logic combing, and data operation and maintenance.

UQL integrates the features of functional programming language linguistically, retains the features of Data Manipulation Language (DML), and undergoes a large number of upgrades and optimizations to ensure better execution performance while keeping the flexibility and convenience.

Query Mechanism

The structured UQL sentences will be parsed and optimized once being delivered to Ultipa server, after which to be allocated to the high performace graph computing engine for graph query, and the query result is finally returned to user after the rest processing and assembling is performed.

This chapter will introduce the query, alias and return mechanism of UQL as a whole, with the purpose of giving users a general understanding. If user has doubts while reading, please continue to study the following chapters for detailed introduction to each section.

Please see an UQL example:

find().nodes() as target return target limit 10

where:

  • find().nodes() initiates a query of node;
  • as target defines an alias, the query result of the previous sentence is expressed as alias "target";
  • return target assembles the returned value, which is the value of "target";
  • limit 10 sets the limit of the amount of data to return, here is 10 the maximum.

The green part is the UQL query statement styled as [command].[parameter].[parameter]..., a complex UQL sentence may contain mutiple query statements, and the result of query serves as the input and processing source of subsequent statements. Later in this chapter, the concept and usage of various query commands and their parameters will be introduced in turn.

The orange part return and limit are clause keyword. Clause is used to compute and process the result delivered from the previous statements (functional operation, aggregation, sorting, Cartesian product combination, etc.). Read chapter Data Stream, Clause for a detailed description of clause keyword.

The red part as is the alias keyword that defines alias for the current result so that it can be used in subsequent statements. Alias is link that makes various parts of UQL to work together.

Alias System

There are two types of aliases, custom alias and system alias.

Custom Alias

The target in the previous UQL example is a custom alias. Custom alias is defined by the following rules:

  • Defined by alias keyword as;
  • Please refer to chapter Basic Concepts for the naming conventions of alias, note that custom alias also accepts only 1 character;
  • Can't have the same name with existing custom alias (except in subgraph template), nor can system reserved words be used (see chapter Basic Concepts for details).

When using custom alias, user needs to understand the object that is defined and its life cycle:

  • Object being defined
    • A data column of path, node, edge that is queried, the result after being processed by function or clause (value, array, table). Please see the table below for details.
  • Life cycle
    • In one UQL sentence, alias defined in one chain statement or clause can be used at least in the very next chain statement or clause;
    • In one UQL sentence, alias of the result that is processed by with clause can be used in any chain statement or clause after that with clause.

There are 6 structure types defined by custom alias:

Structure Type Definition Example Data Structure Example
PATH n().e().n() as paths {nodes: [<NODE>, <NODE>, ...], edges: [<EDGE>, <EDGE>, ...]}
NODE n(as nodes).e().n() {id: , uuid: , schema: , values: {...}}
EDGE n().e(as edges).n() {uuid: , schema: , from: , from_uuid: , to: , to_uuid: , values: {...}}
ATTR n(as nodes).e().n()
with nodes.level as nodeAttr1
with sum(nodes.level) as nodeAttr2
Atomic data type without any internal structure, such as string, number and so on
ARRAY n(as nodes).e().n()
with collect(nodes.name) as nodeArray
[<ATTR>, <ATTR>, ...]
TABLE n(as nodes).e().n()
with table(nodes.name, nodes.level) as nodeTable
{headers: [], table_rows: [<ARRAY>, <ARRAY>, ...]}

When executing a UQL statement, if there is any data stream with no defined alias, or if there is any alias defined but not ever used, the validity and accuracy of UQL might be spoiled. Please aviod missing defining alias or defining unuseful alias when writing UQL.

System Alias

There are 3 system aliases, prev_n, prev_e and this. They can be used directly without definition:

  • this can be called in all Ultipa filters to represent the current node/edge;
  • prev_n and prev_e are only valid in the basic templates; prev_n refers to the previous node of the current node/edge, prev_e refers to the previous edge of the current node/edge.

In practical applications, this is rarely used unless to eliminate any ambiguity; ambiguity occurs when the names of the node/edge's property and the custom alias are repeated, this has to be used in this case if there is a need to refer to the property of node/edge.

... as balance
find().nodes({this.balance > 5000})

Note: In this example, this.balance in nodes() represents the balance property of the current node; since the custom alias defined in the previous statement is still valid in the current statement, using balance in nodes() directly is in conflict with the name of node's property balance, so that this is used.

Overview of RETURN Clause

Most of the preceding examples use return to call custom alias and process, compute and assemble it into the final result.

Suppose that nodes, edges and paths are the custom aliases of nodes, edges and paths, user can make the following calls in return:

When the structure type of the returned alias is NODE, EDGE or PATH, system properties (_uuid, _id, _from, _to, _from_uuid, _to_uuid) and schema of nodes and/or edges are carried by default, the table below won't repeat these info.

Call Format Structure Type Meaning
nodes NODE Nodes that don't carry any custom properties
nodes.<property> ATTR A property of the nodes (or empty if the property doesn't exist; the same below)
nodes.@ ATTR Schemas of the nodes
nodes{<property>, ...} NODE Nodes that carry several custom properties
nodes{*} NODE Nodes that carry all custom properties
edges EDGE Edges that don't carry any custom properties
edges.<property> ATTR A property of the edges
edges.@ ATTR Schemas of the edges
edges{<property>, ...} EDGE Edges that carry several custom properties
edges{*} EDGE Edges that carry all custom properties
paths PATH Paths that don't carry any custom properties of its nodes and edges
paths{<property>, ...}{<property>, ...} PATH Paths that carry several custom properties of its nodes and edges
paths{*}{<property>, ...} PATH Paths that carry all custom properties of its nodes and several custom properties of its edges
paths{<property>, ...}{*} PATH Paths that carry several custom properties of its nodes and all custom properties of its edges
paths{*} PATH Paths that carry all custom properties of its nodes and edges

User may gradually comprehend the concepts above as continue reading.

Read chapter Data Stream, Clause for the detailed description of return.

Node Query

Node query through UQL in a graph is very similar to table query in traditional database, by giving some filtering rules, user can acquire and assemble node data or aggregate the results.

Syntax:

  • Command: find()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported (by default it's nodes), structure type is NODE
Name Type Specification Description Alias Supported Alias Structure Type
nodes filter Ultipa filter; mandatory Filtering rules of node this NODE

The default custom alias nodes is automatcially defined by system when there is no manually defined alias at the end of the node query statement; in this case user can't use nodes to define custom alias for other data in subsequent UQL statement, error of duplicated name will be triggered otherwise. If there is manually defined alias at the end of the node query statement, it shall prevail.

Example: Find nodes whose ID equals C001, return all node properties

find().nodes({_id == "C001"}) 
return nodes{*}

Example: Find cards C001, C002 and C003, return their balance

find().nodes({_id in ["C001", "C002", "C003"]}) 
return nodes.balance

Example: Find 10 @card at level 1 and above, return cards with their number and balance

find().nodes({@card.level > 1})
return nodes{_id, balance} limit 10

Example: Find the 5th to 10th @card at level 1 and above, return cards with their number and balance (define alias manually)

find().nodes({@card.level > 1}) as cards 
return cards{_id, balance} skip 4 limit 6

Example: Find the top 10 @card with the most balance

find().nodes({@card}) as cards
return cards limit 10 
order by cards.balance desc

Example: Calculate the total balance of @card at each level, return level and the sum of balance at each level

find().nodes({@card}) as groups
group by groups.level as level
return level, sum(groups.balance)

Edge Query

Similar to node query, user can do edge query in a graph freely. By giving some filtering rules, user can acquire and assemble node data or aggregate the results.

Syntax:

  • Command: find()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported (by default it's edges), structure type is EDGE
Name Type Specification Description Alias Supported Alias Structure Type
edges filter Ultipa filter; mandatory Filtering rules of edge this EDGE

Similar to node query, the default custom alias edges is automatcially defined by system when there is no manually defined alias at the end of the edge query statement; in this case user can't use edges to define custom alias for other data in subsequent UQL statement, error of duplicated name will be triggered otherwise. If there is manually defined alias at the end of the edge query statement, it shall prevail.

Example: Find @transaction edge with number T001, return all edge properties

find().edges({no == "TRX001"}) return edges{*}

Example: Find 10 @transactions from card C001, return transaction number

find()
  .edges({@transaction && _from == "C001"})
return edges.no limit 10

Example: Find 10 @transaction from card C001, return edges with transaction number and amount

find()
  .edges({@transaction && _from == "C001"})
return edges{no, amount} as item limit 10

A-to-B Query

A-to-B query or shorted as A-B query is to find paths between a pair of nodes by the specified depth, the depth can be from 1 to N; or the depth can be set to the shortest.

Syntax:

  • Command: ab()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported, structure type is PATH
Name Type Specification Description Alias Supported Alias Structure Type
src filter Ultipa filter; mandatory The filtering rules of the start node; error will occur if multiple nodes are found Custom alias,
this
NODE
dest filter Ultipa filter; mandatory The filtering rules of the end node; error will occur if multiple nodes are found Custom alias,
this
NODE
depth range Mandatory To set the depth of the path
depth(N): N edges
depth(:N): 1~N edges
depth(M:N): M~N edges
depth(N).shortest(<>): the shortest (or the least weighted) paths within N edges
/ /
shortest / or @<schema>.<property> Numeric edge property; LTE is required When no edge property is specified, return the shortest path; when edge property is sepcified, return the least weighted paths using the specified property as the weight factor (edges without the property don't form the path). When shortest() is used, value inside depth() should be a constant, that is, depth(N).shortest(<>), means the shortest (or the least weighted) paths within N edges / /
node_filter filter Ultipa filter The filtering rules that nodes other than src and dest need to satisfy this NODE
edge_filter filter Ultipa filter The filtering rules that all edges need to satisfy this EDGE
path_ascend @<schema>.<property> Numeric edge property; LTE is required To return paths where the specified property ascends (edges without the property don't form the path) / /
path_descend @<schema>.<property> Numeric edge property; LTE is required To return paths where the specified property descends (edges without the property don't form the path) / /
direction string left, right To specify the direction of the edge / /
no_circle / / To dismiss the paths with circles; see chapter Basic Concept for the definition of circle under Terminologies / /
limit int -1 or >=0 Number of results to return, -1 means to return all results / /

Examples: Find 5 paths from U001 to U002 within 3 edges, return all properties of node and edge

ab()
  .src({_id == "U001"}).dest({_id == "U002"}).limit(5)
  .depth(:3) as paths
return paths{*}{*}

Examples: Find 5 paths from U001 to U002 within 3 steps, return paths with account name

ab()
  .src({_id == "U001"}).dest({_id == "U002"})
  .depth(:3) as paths
return paths{@account}{} limit 5

Examples: Find transaction paths from U001 to U002 within 3 steps, return paths with account name, card number and transaction number

ab()
  .src({_id == "U001"}).dest({_id == "U002"})
  .depth(:3)
  .edge_filter({@transaction}) as paths
return paths{@account.name, @card._id}{no}

Examples: Find the shortest transaction paths from C001 to C002 within 5 steps

ab()
  .src({_id == "U001"}).dest({_id == "U002"})
  .depth(5).shortest() as paths
return paths

Examples: Find 10 transaction paths from C001 to C002 in the past 24 hours with 3~5 steps

ab()
  .src({_id == "C001"}).dest({_id == "C002"})
  .depth(3:5)
  .edge_filter({@transaction.time > now() - 86400000}) as paths
return paths limit 10

Examples: Find 10 transaction paths from C001 to C002 with transaction amount over 1,000 with 3~5 steps

ab()
  .src({_id == "C001"}).dest({_id == "C002"})
  .depth(3:5)
  .edge_filter({@transaction.amount > 1000}) as paths
return paths limit 10

Examples: Find transaction paths from C001 to C002 within 5 steps and return paths sorted by the time of transaction in ascending order

ab()
  .src({_id == "C001"}).dest({_id == "C002"})
  .depth(:5)
  .path_ascend(@transaction.time) as paths
return paths

Autonet

Autonet function can quickly form a network of multiple specified nodes according to the information of nodes and edges in the graph. Autonet is a more efficient path query function which allows to pass IDs of multiple start/end nodes of paths based on A-B query; that means Autonet is a batch processing of A-B query. Therefore, the parameter limit is limiting the maximum returns of each A-B query results other than the total results of autonet.

Syntax:

  • Command: autonet()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported, structure type is PATH
Name Type Specification Description Alias Supported Alias Structure Type
src filter Ultipa filter; mandatory The filtering rules of the start node Custom alias,
this
NODE
dest filter Ultipa filter The filtering rules of the end node Custom alias,
this
NODE
depth range Mandatory To set the depth of the path
depth(N): N edges
depth(:N): 1~N edges
depth(M:N): M~N edges
depth(N).shortest(<>): the shortest path within N edges
/ /
shortest / / To return the shortest paths / /
node_filter filter Ultipa filter The filtering rules that nodes other than src and dest need to satisfy this NODE
edge_filter filter Ultipa filter The filtering rules that all edges need to satisfy this EDGE
direction string left, right To specify the direction of the edge / /
no_circle / / To dismiss the paths with circles; see chapter Basic Concept for the definition of circle under Terminologies / /
limit int -1 or >=0 Number of results of each A-B query to return, -1 means to return all results / /

Among them, the setting of parameter dest determines the working mode of Autonet:

  • N nodes pairng with each other (if omits dest):
    • N(N-1)/2 pairs of nodes and N(N-1)/2 times of A-B path query
    • When the parameter limit is carried and the value is not -1, maximum limit * N(N-1)/2 paths will be found
  • N nodes pairng with M nodes (if sets dest)
    • N * M pairs of nodes and N * M times of A-B path query
    • When the parameter limit is carried and the value is not -1, maximum limit * N * M paths will be found

Example: Autonet accounts U001, U002, U003, U004 and U005, return 1 path the maximum for each node pair within 5 steps

(Each dotted line indicates the path query between a node pair)
autonet()
  .src({_id in ["U001","U002","U003","U004","U005"]})
  .depth(:5)
  .limit(1) as path
return path

Example: Autonet accounts U001 and U002 to accounts U003, U004 and U005, return 1 path the maximum for each node pair within 5 steps

(Each dotted line indicates the path query between a node pair)
autonet()
  .src({_id in ["U001","U002"]}).dest({_id in ["U003","U004","U005"]})
  .depth(:5)
  .limit(1) as path
return path

K-Hop Query

K-Hop query is to find the neighbor nodes that a node can reach in K hops/steps the shortest, and return the list of the neighbors.

In the field of graph, the concept of K-Hop query is easily misunderstood. Ultipa defines K-Hop query as follows:

  • K represents the number of steps from the start node, with a minimum value of 1;
  • K-Hop neighbors are the nodes that can be reached from the start node at step K through the shortest path (set the weight of edges to 1);
  • K-Hop neighbors won't appear in the neighbors of other steps, for instance, the nodes of 2-hop neighbor don't appear in the set of neighbor nodes of the 3-hop or other hops;
  • The number of K-Hop neighbors refers to the number of all neighbors at step K (after deduplication).
  • In finite graph, when the value of K is big enough, the number of K-Hop neighbors must be 0. Let's say a graph with diameter of 5, the 6-Hop neighbors of all nodes must all be 0.

K-Hop query is executed in a BFS (Breadth First Search) fashion to guarantee the paths to reach the neighbors are the shortest. K-Hop is a graph neighbor query function with an optimized and greatly improved performance, it's suggested to use K-Hop instead of other path query methods when querying neighbor nodes.

Syntax:

  • Command: khop()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported, structure type is NODE
Name Type Specification Description Alias Supported Alias Structure Type
src filter Ultipa filter; mandatory The filtering rules of the start node; error will occur if multiple nodes are found Custom alias,
this
NODE
depth range mandatory To set the depth of the path:
depth(N): N edges
depth(:N): 1~N edges
depth(M:N): M~N edges
/ /
node_filter filter Ultipa filter The filtering rules that neighbor nodes other than the src need to satisfy this NODE
edge_filter filter Ultipa filter The filtering rules that all edges need to satisfy this EDGE
direction string left, right To specify the direction of the edges / /
limit int -1 or >=0 Number of results to return, -1 means to return all results / /

Examples: Count the cards held by U001

khop()
  .src({_id == "U001"}).depth(1)
  .edge_filter({@own}) as nodes
return count(nodes)

Examples: Return the No. of all cards that have indirect 2-3 step transactions but no direct transactions with C001

khop()
  .src({_id == "C001"}).depth(2:3)
  .edge_filter({@transaction}) as nodes
return nodes._id

Examples: Return the No. of all cards that have indirect 2-3 step outgoing transactions but no direct transactions with C001

khop()
  .src({_id == "C001"}).depth(2:3)
  .edge_filter({@transaction}).direction(right) as nodes
return nodes._id

Automatic Spread

Automatic Spread is a query method that explores the neighborhood of the start node through iteratively searching for 1-Hop neighbors layer by layer. Spreading is executed on each and every node in one layer, after all nodes in one layer is done, move to the nodes in the next layer. Specifying the direction of the edge would affect the order of paths that returned. limit clause defines the maximum number of 1-Hop paths to return.

Automatic Spread is a BFS (Breadth First Search) query method that is commonly used in graph query/analysis industry for observing layers of relationship around an entity, and to retrieve and acquire data quickly.

Syntax:

  • Command: spread()
  • Parameter: (see the table below)
  • Parameter Alias: (see the table below)
  • Statement Alias: Custom alias supported, structure type is PATH
Name Type Specification Description Alias Supported Alias Structure Type
src filter Ultipa filter; mandatory The filtering rules of the start node; error will occur if multiple nodes are found Custom alias,
this
NODE
depth int >0; mandatory The maximum depth to spread / /
node_filter filter Ultipa filter The filtering rules that neighbor nodes other than src need to satisfy this NODE
edge_filter filter Ultipa filter The filtering rules that all edges need to satisfy this EDGE
direction string left, right To specify the direction of the edge / /
limit int -1 or >=0 Number of results to return, -1 means to return all results / /

Example: Spread from bank card C001 for 3 levels, filter edges in the right direction (outbound) with node schema @card and edge schema @transaction, return 100 transactions

spread()
  .src({_id == "C001"}).depth(3)
  .node_filter({@card}).edge_filter({@transaction})
  .direction(right) as path
return path limit 100
Please complete the following information to download this book
*
公司名称不能为空
*
公司邮箱必须填写
*
你的名字必须填写
*
你的电话必须填写
*
你的电话必须填写