4.2. Graph Data Model: Frames and Namespaces

xGT uses the concept of a frame as a fundamental building block for its data storage. A frame is a structured collection of homogeneous data in which all elements in the frame, called rows, have the same number of elements. A row in a frame has a number of columns, each of which can have one of the fundamental xGT data types (Data Types in xGT).

Frames in xGT have several properties associated with them: a schema, which consists of a description of the frame’s columns, their names and data types, and a name. This means that each vertex or edge in a single frame has the same set of properties.

Frame names in xGT are represented using a two-level naming scheme. The first part of the name represents the namespace in which the frame is stored, while the second part of the name represents the frame’s name proper. Frame names need to be unique only within their own namespace.

xGT uses the term “fully qualified name” to indicate the fully specified name of a frame, including its namespace. Two underscores “__” are used to separate the namespace of a frame from its name in a fully qualified name: namespace1__FrameA, namespace2__FrameA.

The name of a namespace must be globally unique within xGT. Namespaces can be thought of as living under a global namespace directory that xGT keeps for its users.

4.2.1. Types of Frames in xGT

xGT supports three fundamental types of frames to store user data in the system:

  • TableFrame: Tables represent a collection of rows with the only restriction being that they conform to the table’s schema.

  • VertexFrame: Vertex frames represent a collection of rows conforming to a schema, with the additional restriction that the values of the key column must be unique across the entire vertex frame. Each row in a vertex frame corresponds to a vertex in xGT’s graph model.

  • EdgeFrame: Edge frames also represent a collection of rows conforming to a schema, with the restrictions that the values of two columns in each row must map to the values of the keys columns in the source and target vertex frame, respectively. Multiple rows in an edge frame can have the same values for source and target key columns. Each row in an edge frame corresponds to an edge in xGT’s graph model.

Each frame can be thought of as a grouping of homogeneous vertices, edges, or rows. A VertexFrame may store all vertices representing a single entity type, while an EdgeFrame may store all edges representing a single type of relationship or connection. For example, in a social network graph, there might be one vertex frame representing people and several edge frames, each storing connections of a different type: “friend-of”, “knows”, “family”, “works-with”. A TableFrame is most often used to store results of a query.

4.2.2. Creating Frames

The three types of frames can be created by the client API calls create_table_frame(), create_vertex_frame() and create_edge_frame(). Note that each of these API calls requires slightly different parameters to accommodate the requirements listed above.

server = xgt.Connection()

person_frame = server.create_vertex_frame(name = 'career__Employees',
                                          schema = [['person_id', xgt.INT],
                                                    ['name', xgt.TEXT]],
                                          key = 'person_id')

company_frame = server.create_vertex_frame(name = 'career__Companies',
                                           schema = [['company_id', xgt.INT],
                                                     ['name', xgt.TEXT],
                                                     ['profit', xgt.INT]],
                                           key = 'company_id')

friend_frame = server.create_edge_frame(name = 'career__FriendsWith',
                                        source = 'career__Employees',
                                        target = 'career__Employees',
                                        schema = [['source_id', xgt.INT],
                                                  ['target_id', xgt.INT]],
                                        source_key = 'source_id',
                                        target_key = 'target_id')

work_frame = server.create_edge_frame(name = 'career__WorksFor',
                                      source = 'career__Employees',
                                      target = 'career__Companies',
                                      schema = [['source_id', xgt.INT],
                                                ['target_id', xgt.INT],
                                                ['position', xgt.TEXT],
                                                ['years' , xgt.INT]],
                                      source_key = 'source_id',
                                      target_key = 'target_id')

The frame career__Employees contains vertices representing people. The key column person_id uniquely identifies each vertex, while the column name gives additional information, which need not be unique. The frame career__Employees groups vertices that represent companies. Note that because the frame schema of career__Employees has three columns, each vertex within it must have three properties, one of them the unique key.

Frames career__FriendsWith and career__WorksFor define two edge types, each connecting already defined vertex frames. The source and target frames must be created before an edge frame is created. Note that an edge frame may connect vertices from the same vertex frame, as career__FriendsWith does, or may connect vertices from two different frames, as career__WorksFor does.

If a frame has been previously created and already exists on the server, the client can be used to retrieve a proxy object to that frame. This is done with get_table_frame(), get_vertex_frame(), and get_edge_frame(). Additionally, client API calls are provided to list the existing table, vertex and edge frames in a running xGT instance: get_table_frames(), get_vertex_frames() and get_edge_frames(). Those calls can be restricted to list the frames resident in particular namespaces.

4.2.3. Dropping Frames

All frame types can be deleted using the client API call drop_frame(). Note that a frame cannot be dropped if doing so creates an invalid graph. In order to drop a vertex frame, it must not be the source or target of any edge frame. This is the case even if the frames are empty. Frame Drop provides additional information about dropping frames.

4.2.4. Namespaces

All frames in xGT are grouped into namespaces and frames names need to be unique only within a namespace. A user might connect to an xGT server on which namespaces have already been created or the user might create a new namespace to store frames. A namespace can be created with create_namespace():

server.create_namespace('mynamespace')

If the namespace indicted by a frame name does not already exist, it will be created along with the frame. In this example, if the namespace named graph does not already exist, it will be created so that it can store graph__Vertex.

vertex_frame = server.create_vertex_frame(name = 'graph__VertexFrame',
                                          schema = [['id', xgt.INT]],
                                          key = 'id')

Client API calls can be used to obtain the list of namespaces with get_namespaces() and delete a namespace with drop_namespace(). Unless the force_drop parameter is set to true, a namespace will not be dropped if it contains any frames.

4.2.5. Access Control

xGT supports access control on frames. When creating frames or namespaces, security labels can optionally be attached for each of the access types:

  • Create: The create access type allows the insertion of new rows into the frame in question.

  • Read: The read access type allows reading operations on the data rows held by the frame.

  • Update: The update access type allows the updating of existing rows in the frame. Columns of existing rows can be modified if this access type is granted.

  • Delete: The delete access type allows the deletion of existing rows from a frame. Delete access on a frame is also required to delete the frame itself.

In order to perform an action on a frame or namespace, the connected user must have required labels in their label set. For example, to read a frame, the user must have the labels attached to read access for that frame. To load new data into the frame, the user must have the labels attached to read access and create access for that frame. If xGT is being used with access control, the label set of a user will be configured by the administrator as described in Configuring Groups and Labels.

Security labels are attached by passing in a dictionary parameter security_labels that contains four keys for each of the access types:

namepace_labels = { 'create' : ['label1'],
                    'delete' : ['label1']
                  }
server.create_namespace(name = 'graph',
                        security_labels = namespace_labels)
frame_labels = { 'create' : ['label1', 'label2'],
                 'read'   : ['label2'],
                 'update' : ['label1', 'label2', 'label3'],
                 'delete' : ['label1', 'label2', 'label3']
               }
vertex_frame = server.create_vertex_frame(name = 'graph__VertexFrame',
                                          schema = [['id', xgt.INT]],
                                          key = 'id',
                                          security_labels = frame_labels)

The above example creates a namespace with one set of labels and a frame within it with a different set of labels. If a namespace does not exist and is implicitly created along with a frame, it will be assigned the same labels as the frame. By default, no labels are attached for any of the four access types. Any attempts to perform an action for which the user does not have the required label set will result in an XgtSecurityError() being thrown.

More information about access control is found in Access Control.