Implements: blueprint networkx-graph-driver
Change-Id: I80bf90eafa633705eca707c65254d8a916d26248
This commit is contained in:
parent
7ba498cf58
commit
e58a9db421
@ -4,7 +4,7 @@
|
||||
|
||||
pbr>=1.6
|
||||
Babel>=1.3
|
||||
|
||||
networkx>=1.10
|
||||
oslo.log>=1.12.0 # Apache-2.0
|
||||
pecan>=0.8.0
|
||||
PasteDeploy>=1.5.0
|
||||
|
@ -3,9 +3,9 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking<0.11,>=0.10.0
|
||||
|
||||
coverage>=3.6
|
||||
discover
|
||||
networkx>=1.10
|
||||
python-subunit>=0.0.18
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||
oslo.log>=1.12.0 # Apache-2.0
|
||||
|
28
vitrage/graph/__init__.py
Normal file
28
vitrage/graph/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Graph abstraction
|
||||
"""
|
||||
|
||||
import networkx_graph
|
||||
|
||||
|
||||
def graph_factory(name):
|
||||
"""For now only return NXGraph
|
||||
|
||||
:rtype: Graph
|
||||
"""
|
||||
return networkx_graph.NXGraph(name)
|
276
vitrage/graph/driver.py
Normal file
276
vitrage/graph/driver.py
Normal file
@ -0,0 +1,276 @@
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Defines interface for Graph access and manipulation
|
||||
|
||||
Functions in this module are imported into the vitrage.graph namespace.
|
||||
Call these functions from vitrage.graph namespace and not the
|
||||
vitrage.graph.driver namespace.
|
||||
|
||||
"""
|
||||
import abc
|
||||
import six
|
||||
|
||||
|
||||
class Vertex(object):
|
||||
"""Class Vertex
|
||||
|
||||
A vertex is defined as follows:
|
||||
* vertex_id is a unique identifier
|
||||
* properties is a dictionary
|
||||
|
||||
"""
|
||||
def __init__(self, vertex_id, properties=None):
|
||||
"""Create a Vertex instance
|
||||
|
||||
:type vertex_id: str
|
||||
:type properties: dict
|
||||
:rtype: Vertex
|
||||
"""
|
||||
if not vertex_id:
|
||||
raise AttributeError('Attribute vertex_id is missing')
|
||||
self.vertex_id = vertex_id
|
||||
self.properties = properties
|
||||
|
||||
|
||||
class Edge(object):
|
||||
"""Class Edge represents a directional edge between two vertices
|
||||
|
||||
An edge is defined as follows:
|
||||
* source_id is the first vertex id
|
||||
* target_id is the second vertex id
|
||||
* properties is a dictionary
|
||||
|
||||
+---------------+ edge +---------------+
|
||||
| source vertex |-----------> | target vertex |
|
||||
+---------------+ +---------------+
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, source_id, target_id, label, properties=None):
|
||||
"""Create an Edge instance
|
||||
|
||||
:param source_id: source vertex id
|
||||
:type source_id: str
|
||||
|
||||
:param target_id: target vertex id
|
||||
:type target_id: str
|
||||
|
||||
:param label:
|
||||
:type label: str
|
||||
|
||||
:type properties: dict
|
||||
:rtype: Edge
|
||||
"""
|
||||
if not source_id:
|
||||
raise AttributeError('Attribute source_id is missing')
|
||||
if not target_id:
|
||||
raise AttributeError('Attribute target_id is missing')
|
||||
if not label:
|
||||
raise AttributeError('Attribute label is missing')
|
||||
self.source_id = source_id
|
||||
self.target_id = target_id
|
||||
self.label = label
|
||||
self.properties = properties
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Graph(object):
|
||||
def __init__(self, name, graph_type):
|
||||
"""Create a Graph instance
|
||||
|
||||
:type name: str
|
||||
:type graph_type: str
|
||||
:rtype: Graph
|
||||
"""
|
||||
self.name = name
|
||||
self.graph_type = graph_type
|
||||
|
||||
@abc.abstractmethod
|
||||
def copy(self):
|
||||
"""Create a copy of the graph
|
||||
|
||||
:return: A copy of the graph
|
||||
:rtype: Graph
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_vertex(self, v):
|
||||
"""Add a vertex to the graph
|
||||
|
||||
A copy of Vertex v will be added to the graph.
|
||||
|
||||
Example:
|
||||
--------
|
||||
graph = Graph()
|
||||
v = Vertex(vertex_id=1, properties={prop_key:prop_value})
|
||||
graph.add_vertex(v)
|
||||
|
||||
:param v: the vertex to add
|
||||
:type v: Vertex
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_edge(self, e):
|
||||
"""Add an edge to the graph
|
||||
|
||||
A copy of Edge e will be added to the graph.
|
||||
|
||||
Example:
|
||||
--------
|
||||
graph = Graph()
|
||||
|
||||
v1_prop = {'prop_key':'some value for my first vertex'}
|
||||
v2_prop = {'prop_key':'another value for my second vertex'}
|
||||
v1 = Vertex(vertex_id=1, properties=v1_prop)
|
||||
v2 = Vertex(vertex_id=1, properties=v2_prop)
|
||||
graph.add_vertex(v1)
|
||||
graph.add_vertex(v2)
|
||||
|
||||
e_prop = {'edge_prop':'and here is my edge property value'}
|
||||
e = Edge(source_id=v1.vertex_id, target_id=v2.vertex_id,
|
||||
label='BELONGS', properties=e_prop)
|
||||
graph.add_edge(e)
|
||||
|
||||
:param e: the edge to add
|
||||
:type e: Edge
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_vertex(self, v_id):
|
||||
"""Fetch a vertex from the graph
|
||||
|
||||
:param v_id: vertex id
|
||||
:type v_id: str
|
||||
|
||||
:return: the vertex or None if it does not exist
|
||||
:rtype: Vertex
|
||||
"""
|
||||
pass
|
||||
|
||||
# TODO(ihefetz) uncomment:
|
||||
# @abc.abstractmethod
|
||||
# def get_vertices(self, properties_filter):
|
||||
# pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_edge(self, source_id, target_id, label):
|
||||
"""Fetch an edge from the graph,
|
||||
|
||||
Fetch an edge from the graph, according to its two vertices and label
|
||||
|
||||
:param source_id: vertex id of the source vertex
|
||||
:type source_id: str
|
||||
|
||||
:param target_id: vertex id of the target vertex
|
||||
:type target_id: str
|
||||
|
||||
:param label: the label property of the edge
|
||||
:type label: str
|
||||
|
||||
:return: The edge between the two vertices or None
|
||||
:rtype: Edge
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_edges(self, source_id, target_id, labels=None, directed=True):
|
||||
"""Fetch multiple edges from the graph,
|
||||
|
||||
Fetch an edge from the graph, according to its two vertices and label
|
||||
|
||||
:param source_id: vertex id of the source vertex
|
||||
:type source_id: str
|
||||
|
||||
:param target_id: vertex id of the target vertex
|
||||
:type target_id: str
|
||||
|
||||
:param labels: the label property of the edge
|
||||
:type labels: str or list of str
|
||||
|
||||
:param directed: consider edge direction
|
||||
:type directed: bool
|
||||
|
||||
:return: The edge between the two vertices or None
|
||||
:rtype: Edge
|
||||
"""
|
||||
pass
|
||||
|
||||
# TODO(ihefetz) uncomment:
|
||||
# @abc.abstractmethod
|
||||
# def get_neighboring_edges(self, v_id, properties_filter):
|
||||
# pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_vertex(self, v, hard_update=False):
|
||||
"""Update the vertex properties
|
||||
|
||||
Update an existing vertex and create it if non existing.
|
||||
Hard update: can be used to remove existing fields.
|
||||
|
||||
:param v: the vertex with the new data
|
||||
:type v: Vertex
|
||||
:param hard_update: if True, original properties will be removed.
|
||||
:type hard_update: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_edge(self, e, hard_update=False):
|
||||
"""Update the edge properties
|
||||
|
||||
Update an existing edge and create it if non existing.
|
||||
Hard update: can be used to remove existing fields.
|
||||
|
||||
:param e: the edge with the new data
|
||||
:type e: Edge
|
||||
:param hard_update: if True, original properties will be removed.
|
||||
:type hard_update: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_vertex(self, v):
|
||||
"""Remove Vertex v and its edges from the graph
|
||||
|
||||
:type v: Vertex
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_edge(self, e):
|
||||
"""Remove an edge from the graph
|
||||
|
||||
:type e: Edge
|
||||
"""
|
||||
pass
|
||||
|
||||
# @abc.abstractmethod
|
||||
# def neighbors(self, v, vertex_attr=None, edge_attr=None):
|
||||
# # TODO(ihefetz) also direction? also return the edges?
|
||||
# """TODO(ihefetz)
|
||||
#
|
||||
# :param v: TODO(ihefetz)
|
||||
# :param vertex_attr: TODO(ihefetz)
|
||||
# :param edge_attr: TODO(ihefetz)
|
||||
# :return: TODO(ihefetz)
|
||||
# :rtype: list of Vertex
|
||||
# """
|
||||
# pass
|
135
vitrage/graph/networkx_graph.py
Normal file
135
vitrage/graph/networkx_graph.py
Normal file
@ -0,0 +1,135 @@
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
import networkx as nx
|
||||
|
||||
from driver import Edge
|
||||
from driver import Graph
|
||||
from driver import Vertex
|
||||
|
||||
|
||||
class NXGraph(Graph):
|
||||
|
||||
GRAPH_TYPE = "networkx"
|
||||
|
||||
def __init__(self, name):
|
||||
self.g = nx.MultiDiGraph()
|
||||
super(NXGraph, self).__init__(name=name, graph_type=NXGraph.GRAPH_TYPE)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.g)
|
||||
|
||||
def copy(self):
|
||||
self_copy = NXGraph(self.name)
|
||||
self_copy.g = self.g.copy()
|
||||
return self_copy
|
||||
|
||||
def add_vertex(self, v):
|
||||
"""Add a vertex to the graph
|
||||
|
||||
:type v: Vertex
|
||||
"""
|
||||
properties_copy = copy.copy(v.properties)
|
||||
self.g.add_node(n=v.vertex_id, attr_dict=properties_copy)
|
||||
|
||||
def add_edge(self, e):
|
||||
"""Add an edge to the graph
|
||||
|
||||
:type e: Edge
|
||||
"""
|
||||
properties_copy = copy.copy(e.properties)
|
||||
self.g.add_edge(u=e.source_id, v=e.target_id,
|
||||
key=e.label, attr_dict=properties_copy)
|
||||
|
||||
def get_vertex(self, v_id):
|
||||
"""Fetch a vertex from the graph
|
||||
|
||||
:rtype: Vertex
|
||||
"""
|
||||
properties = self.g.node.get(v_id, None)
|
||||
properties_copy = copy.copy(properties) if properties else None
|
||||
vertex = Vertex(vertex_id=v_id, properties=properties_copy)
|
||||
return vertex
|
||||
|
||||
def _get_edge_properties(self, source_id, target_id, label):
|
||||
try:
|
||||
properties = self.g.adj[source_id][target_id][label]
|
||||
return properties
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_edge(self, source_id, target_id, label):
|
||||
"""Fetch an edge from the graph,
|
||||
|
||||
:rtype: Edge
|
||||
"""
|
||||
properties = self._get_edge_properties(source_id, target_id, label)
|
||||
if properties:
|
||||
properties_copy = copy.copy(properties)
|
||||
item = Edge(source_id=source_id, target_id=target_id,
|
||||
label=label, properties=properties_copy)
|
||||
return item
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_edges(self, source_id, target_id, labels=None, directed=True):
|
||||
"""Fetch multiple edges from the graph
|
||||
|
||||
:rtype: list of Edge
|
||||
"""
|
||||
# TODO(ihefetz) implement this function
|
||||
pass
|
||||
|
||||
def update_vertex(self, v, hard_update=False):
|
||||
"""Update the vertex properties
|
||||
|
||||
:type v: Vertex
|
||||
"""
|
||||
if hard_update:
|
||||
properties = self.g.node.get(v.vertex_id, None)
|
||||
if properties:
|
||||
properties.clear()
|
||||
self.add_vertex(v)
|
||||
|
||||
def update_edge(self, e, hard_update=False):
|
||||
"""Update the edge properties
|
||||
|
||||
:type e: Edge
|
||||
"""
|
||||
if hard_update:
|
||||
properties = self._get_edge_properties(e.source_id,
|
||||
e.target_id,
|
||||
e.label)
|
||||
if properties:
|
||||
properties.clear()
|
||||
self.add_edge(e)
|
||||
|
||||
def remove_vertex(self, v):
|
||||
"""Remove Vertex v and its edges from the graph
|
||||
|
||||
:type v: Vertex
|
||||
"""
|
||||
self.g.remove_node(n=v.vertex_id)
|
||||
|
||||
def remove_edge(self, e):
|
||||
"""Remove an edge from the graph
|
||||
|
||||
:type e: Edge
|
||||
"""
|
||||
self.g.remove_edge(u=e.source_id, v=e.target_id)
|
Loading…
x
Reference in New Issue
Block a user