PGX 20.2.2
Documentation

Using Collections and Maps

This guide shows examples of creation and usages of collections and maps.

Let's begin by creating a session.

cd $PGX_HOME
./bin/pgx-jshell // starting the shell will create an implicit session
import oracle.pgx.api.*;

...

PgxSession session = Pgx.createSession("my-session");
from pypgx import get_session

session = get_session(session_name="example")

The created session object is your entry point to PGX's features. Let's get started with collection data types.

Collection Data Types

PGX defines two types of collections:

  • Graph-bound collections: Such as vertex and edge collections, these collections belong to the graph.
  • Session-bound collections: Belong to the session.

Graph-bound Collections

To work with vertex and edge collections, you first need to load a graph. For more information on graph loading, please refer to Load a graph with Shell and Load your own graph data tutorials.

Vertex Collections

v0 = graph.getVertex(100) // 'graph' is the loaded graph object. '100' -> '103' are vertex ids that supposedly
v1 = graph.getVertex(101) // exist in the graph.
v2 = graph.getVertex(102)
v3 = graph.getVertex(103)

myVertexSet = graph.createVertexSet("myVertexSet")  // A name is automatically generated if none given.
myVertexSet.add(v0)  // Adds vertex 'v0' to the set.
myVertexSet.addAll([v1, v2, v3]) // Supports variadic parameter as well: myVertexSet.addAll(v1, v2, v3).
import java.util.Arrays;
import oracle.pgx.api.*;

...

PgxVertex v0 = graph.getVertex(100);
PgxVertex v1 = graph.getVertex(101);
PgxVertex v2 = graph.getVertex(102);
PgxVertex v3 = graph.getVertex(103);

VertexSet myVertexSet = graph.createVertexSet("myVertexSet");  // A name is automatically generated if none given.
myVertexSet.add(v0);
myVertexSet.addAll(Arrays.asList(v1, v2, v3));
...

v0 = graph.get_vertex(100)
v1 = graph.get_vertex(101)
v2 = graph.get_vertex(102)
v3 = graph.get_vertex(103)

my_vertex_set = graph.create_vertex_set("myVertexSet") 
my_vertex_set.add(v0)
my_vertex_set.add_all([v1,v2,v3])

Edge Collections

e0 = graph.getEdge(100) // 'graph' is the loaded graph object. '100' -> '103' are edge ids that supposedly
e1 = graph.getEdge(101) // exist in the graph.
e2 = graph.getEdge(102)
e3 = graph.getEdge(103)

myEdgeSequence = graph.createEdgeSequence("myEdgeSequence")
myEdgeSequence.add(e0)
myEdgeSequence.addAll([e1, e2, e3])
import java.util.Arrays;
import oracle.pgx.api.*;

...

PgxEdge e0 = graph.getEdge(100);
PgxEdge e1 = graph.getEdge(101);
PgxEdge e2 = graph.getEdge(102);
PgxEdge e3 = graph.getEdge(103);

EdgeSequence myEdgeSequence = graph.createEdgeSequence("myEdgeSequence");
myEdgeSequence.add(e0);
myEdgeSequence.addAll(Arrays.asList(e1, e2, e3));
e0 = graph.get_edge(100)
e1 = graph.get_edge(101)
e2 = graph.get_edge(102)
e3 = graph.get_edge(103)

my_edge_sequence = graph.create_edge_sequence("my_edge_sequence")
my_edge_sequence.add(e0)
my_edge_sequence.add_all([e1, e2, e3])

Session-bound Collections

PGX lets users create and manipulate collections directly in the session without the need for a graph. Session-bound collections can be further passed as parameters to graph algorithms or used like any other collection object. The following sub-sections describe currently supported types of these collections.

Scalar Collections

Scalar collections hold simple data types like Integer, Long, Float, Double and Boolean. They can be managed by the PgxSession APIs:

Creation

You can use createSet() and createSequence() methods to create scalar collections:

myIntSet = session.createSet(PropertyType.INTEGER, "myIntSet")
myDoubleSequence = session.createSequence(PropertyType.DOUBLE)  // A name will be automatically generated if none is provided.
println myDoubleSequence.getName()  // Display the generated name.
import oracle.pgx.api.*;
import oracle.pgx.common.types.*;

...

ScalarSet myIntSet = session.createSet(PropertyType.INTEGER, "myIntSet");
ScalarSequence myDoubleSequence = session.createSequence(PropertyType.DOUBLE);
System.out.println(myDoubleSequence.getName());
Operations

Once a scalar collection is created, you can run many operations on it. Feel free to push the following examples further and explore more about scalar collections.

myIntSet.add(10)
myIntSet.addAll([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
myIntSet.addAll([0,1,2]) // Element uniqueness. This operation has no effect on the set.
println myIntSet

myIntSet.contains(1)  // Checks the presence of an element. This code returns `true`.
myIntSet.remove(10)
myIntSet.removeAll([4, 5, 6, 7, 8, 9]) // Leaves only elements `0, 1, 2, 3`.
println  myIntSet
import java.util.Arrays;
import oracle.pgx.api.*;

...

myIntSet.add(10);
myIntSet.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
myIntSet.addAll(Arrays.asList(0, 1, 2))

myIntSet.contains(1);  // Returns `true`.
myIntSet.remove(10);
myIntSet.removeAll(Arrays.asList(4, 5, 6, 7, 8, 9));
Traversal

Scalar collections can be traversed either using an Iterator or using the new Stream API. You can add for example elements of a sequence to a set, traverse a sequence and filter out elements you don't want, and then add the rest to another scalar collection. Let's see how to do it:

myIntSet.forEach({x -> print x + "\n"})
myIntSet.stream().filter({x -> x % 2 == 0}).forEach({x -> myDoubleSequence.add(x)})
println myDoubleSequence
import java.util.Iterator;
import java.util.stream.Stream;
import oracle.pgx.api.*;

...

myIntSet.forEach(x -> System.out.println(x))
myIntSet.stream().filter(x -> x % 2 == 0).forEach(myDoubleSequence::add)

Map Data Types

PGX defines two types of maps:

  • Graph-bound maps: These maps support any key or value type and are created using a graph object.
  • Session-bound maps: Keys or values in these maps are of any type except from graph-related types (i.e., vertices or edges). These maps belong to the session.

Graph-bound Maps

Some data types like VERTEX or EDGE depend on the graph. Consequently, mappings involving these data types also depend on the graph. PGX provides PgxGraph and PgxMap APIs to manage such maps:

!!! bg-info Note that if you destroy the graph you will lose the map. Consider using session-bound maps instead (see next section) if your map doesn't involve any graph-related key or value type.

Vertices as Keys

v0 = graph.getVertex(100)
v1 = graph.getVertex(101)
v2 = graph.getVertex(102)
v3 = graph.getVertex(103)

vertexToLongMap = graph.createMap(PropertyType.VERTEX, PropertyType.LONG, "vertexToLongMap")
vertexToLongMap.put(v0, v0.getDegreeAsync().get())
vertexToLongMap.put(v1, v1.getDegreeAsync().get())
vertexToLongMap.put(v2, v2.getDegreeAsync().get())
vertexToLongMap.put(v3, v3.getDegreeAsync().get())
import java.util.Arrays;
import oracle.pgx.api.*;

...

PgxVertex v0 = graph.getVertex(100);
PgxVertex v1 = graph.getVertex(101);
PgxVertex v2 = graph.getVertex(102);
PgxVertex v3 = graph.getVertex(103);

PgxMap<PgxVertex, Long> vertexToLongMap = graph.createMap(PropertyType.VERTEX, PropertyType.LONG, "vertexToLongMap");
vertexToLongMap.put(v0, v0.getDegree());
vertexToLongMap.put(v1, v1.getDegree());
vertexToLongMap.put(v2, v2.getDegree());
vertexToLongMap.put(v3, v3.getDegree());
v0 = graph.get_vertex(100)
v1 = graph.get_vertex(101)
v2 = graph.get_vertex(102)
v3 = graph.get_vertex(103)

vertex_to_long_map = graph.create_map("vertex", "long", "vertex_to_long_map")
vertex_to_long_map.put(v0, v0.degree)
vertex_to_long_map.put(v1, v1.degree)
vertex_to_long_map.put(v2, v2.degree)
vertex_to_long_map.put(v3, v3.degree)

Edges as Keys

e0 = graph.getEdge(100)
e1 = graph.getEdge(101)
e2 = graph.getEdge(102)
e3 = graph.getEdge(103)

edgeToVertexMap = graph.createMap(PropertyType.EDGE, PropertyType.VERTEX, "edgeToVertexMap")
edgeToVertexMap.put(e0, e0.getSource())
edgeToVertexMap.put(e1, e1.getSource())
edgeToVertexMap.put(e2, e2.getSource())
edgeToVertexMap.put(e3, e3.getSource())
import java.util.Arrays;
import oracle.pgx.api.*;

...

PgxEdge e0 = graph.getEdge(100);
PgxEdge e1 = graph.getEdge(101);
PgxEdge e2 = graph.getEdge(102);
PgxEdge e3 = graph.getEdge(103);

PgxMap<PgxEdge, PgxVertex> edgeToVertexMap = graph.createMap(PropertyType.EDGE, PropertyType.VERTEX, "edgeToVertexMap");
edgeToVertexMap.put(e0, e0.getSource());
edgeToVertexMap.put(e1, e1.getSource());
edgeToVertexMap.put(e2, e2.getSource());
edgeToVertexMap.put(e3, e3.getSource());

:::Python

e0 = graph.get_edge(100) e1 = graph.get_edge(101) e2 = graph.get_edge(102) e3 = graph.get_edge(103)

edge_to_long_map = graph.create_map("edge", "long", "edge_to_long_map") edge_to_long_map.put(e0, e0.source) edge_to_long_map.put(e1, e1.source) edge_to_long_map.put(e2, e2.source) edge_to_long_map.put(e3, e3.source) !END_CODE_TABS

Session-bound Maps

Maps can be directly created in the session. In that case, you cannot use any graph-related data type as the map key or value type. Session-bound maps can be further passed as parameters to graph algorithms or used like any other map object. They are managed by PgxSession and PgxMaps APIs.

Creation

You can use createMap() method and its overloads to create session-bound maps.

intToDouble = session.createMap(PropertyType.INTEGER, PropertyType.DOUBLE, "intToDouble")
intToTime = session.createMap(PropertyType.INTEGER, PropertyType.TIME)  // A name will be automatically generated.
println intToTime.getName()
println intToTime.getSessionId()
println intToTime.getGraph()  // `null`: Not bound to a graph.
println intToTime.getKeyType()
println intToTime.getValueType()
import java.time.LocalTime;
import oracle.pgx.api.*;
import oracle.pgx.common.types.*;

...

PgxMap<Integer, Double> intToDouble = session.createMap(PropertyType.INTEGER, PropertyType.DOUBLE, "intToDouble");
PgxMap<Integer, LocalTime> intToTime = session.createSequence(PropertyType.INTEGER, PropertyType.TIME);
System.out.println(intToTime.getName());
System.out.println(intToTime.getSessionId());
System.out.println(intToTime.getGraph());  // `null`: Not bound to a graph.
System.out.println(intToTime.getKeyType());
System.out.println(intToTime.getValueType());
Operations

The most important operations of session-bound maps include setting, removing and checking existence of entries:

intToDouble.put(0, 0.314)
intToDouble.put(1, 3.14)
intToDouble.put(2, 31.4)
intToDouble.put(3, 314)

println intToDouble.size()  // 4
println intToDouble.get(1)
println intToDouble.get(3)
println intToDouble.get(10)  // null

println intToDouble.containsKey(0)  // `true`
intToDouble.remove(0)
println intToDouble.containsKey(0)  // `false`
println intToDouble.containsKey(10)  // `false`
intToDouble.remove(10)
println intToDouble.containsKey(10)  // `false`

println intToDouble.put(1, 999)  //  previous mapped value (`3.14`) is replaced by `999`
intToDouble.destroy()
import java.util.Arrays;
import oracle.pgx.api.*;

...

intToDouble.put(0, 0.314);
intToDouble.put(1, 3.14);
intToDouble.put(2, 31.4);
intToDouble.put(3, 314);

System.out.println(inToDouble.size());  // 4
System.out.println(intToDouble.get(1));
System.out.println(intToDouble.get(3));
System.out.println(intToDouble.get(10));  // null

System.out.println(intToDouble.containsKey(0));  // `true`
intToDouble.remove(0);
System.out.println(intToDouble.containsKey(0));  // `false`
System.out.println(intToDouble.containsKey(10));  // `false`
intToDouble.remove(10);
System.out.println(intToDouble.containsKey(10));  // `false`

System.out.println(intToDouble.put(1, 999));  //  previous mapped value (`3.14`) is replaced by `999`
intToDouble.destroy();
Traversal

You can use entries() method to get an iterable of map entries and keys() method to get an iterable of map keys.

intToDouble.entries().forEach {it -> println (it)}
intToDouble.keys().forEach {it -> println (it)}
import java.util.Iterable;
import java.util.stream.Stream;
import oracle.pgx.api.*;

...

Iterable<Map.Entry> entries = intToDouble.entries();
entries.forEach(System.out::println);
Iterable<Map.Entry> keys = intToDouble.keys();
keys.forEach(System.out::println);