Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Gremlin vis bug with non-string vertex IDs #245

Merged
merged 1 commit into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions src/graph_notebook/network/gremlin/GremlinNetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ def add_results_with_pattern(self, results, pattern_list: list):
previous_pattern = pattern_list[i - 1] if i != 0 else pattern_list[-1]
next_pattern = pattern_list[i + 1] if i < len(pattern_list) - 1 else pattern_list[0]

current_node_id = str(get_id(path[path_index]))
try:
prev_node_id = str(get_id(path[path_index - 1]))
except IndexError:
prev_node_id = None
try:
next_node_id = str(get_id(path[path_index + 1]))
except IndexError:
next_node_id = None

# the current pattern is V, inV, or outV
if path_pattern in V_PATTERNS:
# we cannot reconcile an edge type with a node
Expand All @@ -212,11 +222,12 @@ def add_results_with_pattern(self, results, pattern_list: list):
self.add_vertex(path[path_index])
# if the path index is over 0, we need to handle edges between this node and the previous one
if path_index > 0:
# TODO: First node (PathPattern.V) is rendered blank if T.id is a integer instead of a string.
if path_pattern == PathPattern.V:
# two V patterns next to each other is an undirected, unlabeled edge
if previous_pattern == PathPattern.V:
self.add_blank_edge(get_id(path[path_index - 1]),
get_id(path[path_index]),
self.add_blank_edge(prev_node_id,
current_node_id,
undirected=True)
# IN_V -> V will draw an outgoing edge from the current element to the previous one.
elif previous_pattern == PathPattern.IN_V:
Expand All @@ -229,43 +240,41 @@ def add_results_with_pattern(self, results, pattern_list: list):
# draw an unlabeled, directed edge from previous -> current
# we can only process V and OUT_V as no two adjacent vertices can both be incoming.
if (previous_pattern == PathPattern.V or PathPattern.OUT_V) and path_index > 0:
self.add_blank_edge(get_id(path[path_index - 1]), get_id(path[path_index]), undirected=False)
self.add_blank_edge(prev_node_id, current_node_id, undirected=False)
else:
raise SAME_DIRECTION_ADJACENT_VERTICES
# path_pattern (OUT_V) -> previous_pattern (V, IN_V)
elif path_pattern == PathPattern.OUT_V and previous_pattern not in E_PATTERNS:
# draw an unlabeled, directed edge from current -> previous
# we can only process V and IN_V as no two adjacent vertices can both be outgoing.
if (previous_pattern == PathPattern.V or PathPattern.IN_V) and path_index > 0:
self.add_blank_edge(get_id(path[path_index]), get_id(path[path_index - 1]), undirected=False)
self.add_blank_edge(current_node_id, prev_node_id, undirected=False)
else:
raise SAME_DIRECTION_ADJACENT_VERTICES
elif path_pattern in E_PATTERNS:
# if the type of the given path element is not Edge,
# draw an undirected edge using this element for edge data
edge = path[path_index]
path_previous = get_id(path[path_index - 1])
path_next = get_id(path[path_index + 1])

if path_pattern == PathPattern.E:
# V -> V where the Vertex pattern is identical on either side of the edge
if next_pattern == previous_pattern:
# this is only valid if both are V, two connected vertices cannot have same direction
if next_pattern == PathPattern.V:
self.add_path_edge(edge, path_previous, path_next, UNDIRECTED_EDGE)
self.add_path_edge(edge, prev_node_id, next_node_id, UNDIRECTED_EDGE)
else:
raise SAME_DIRECTION_ADJACENT_VERTICES
# IN_V -> E -> V
elif previous_pattern == PathPattern.IN_V:
self.add_path_edge(edge, path_next, path_previous)
self.add_path_edge(edge, next_node_id, prev_node_id)
# OUT_V -> E -> V
elif previous_pattern == PathPattern.OUT_V:
self.add_path_edge(edge, path_previous, path_next)
self.add_path_edge(edge, prev_node_id, next_node_id)
# If the edge direction is specified, use it as the source of truth
elif path_pattern == PathPattern.IN_E:
self.add_path_edge(edge, from_id=path_next, to_id=path_previous)
self.add_path_edge(edge, from_id=next_node_id, to_id=prev_node_id)
elif path_pattern == PathPattern.OUT_E:
self.add_path_edge(edge, from_id=path_previous, to_id=path_next)
self.add_path_edge(edge, from_id=prev_node_id, to_id=next_node_id)
else:
raise INVALID_PATH_ERROR
path_index += 1
Expand Down
47 changes: 46 additions & 1 deletion test/unit/network/gremlin/test_gremlin_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from gremlin_python.structure.graph import Path, Edge, Vertex
from gremlin_python.process.traversal import T, Direction
from graph_notebook.network.EventfulNetwork import EVENT_ADD_NODE
from graph_notebook.network.gremlin.GremlinNetwork import GremlinNetwork
from graph_notebook.network.gremlin.GremlinNetwork import GremlinNetwork, PathPattern


class TestGremlinNetwork(unittest.TestCase):
Expand Down Expand Up @@ -2401,6 +2401,51 @@ def test_add_results_as_path_containing_nested_tokens(self):
self.assertEqual(inv_data['properties'], in_vertex_expected)
self.assertEqual(edge_data_value, edge_value_expected)

def test_add_path_with_v_oute_inv_pattern_integer_ids(self):
path = Path([], [{T.id: 13, T.label: 'airport', 'country': ['US'], 'code': ['LAX'], 'longest': [12091],
'city': ['Los Angeles'], 'elev': [127], 'icao': ['KLAX'], 'lon': [-118.4079971],
'type': ['airport'], 'region': ['US-CA'], 'runways': [4], 'lat': [33.94250107],
'desc': ['Los Angeles International Airport']}, 6512,
{T.id: 63, T.label: 'airport', 'country': ['NZ'], 'code': ['AKL'], 'longest': [11926],
'city': ['Auckland'], 'elev': [23], 'icao': ['NZAA'], 'lon': [174.792007446],
'type': ['airport'], 'region': ['NZ-AUK'], 'runways': [2], 'lat': [-37.0080986023],
'desc': ['Auckland International Airport']}])
pattern = [PathPattern.V, PathPattern.OUT_E, PathPattern.IN_V]
gn = GremlinNetwork()
gn.add_results_with_pattern([path], pattern)
edge_data = gn.graph.get_edge_data('13', '63')
self.assertIn(6512, edge_data)

def test_add_path_with_blank_edge_pattern_integer_ids(self):
path = Path([], [{T.id: 13, T.label: 'airport', 'country': ['US'], 'code': ['LAX'], 'longest': [12091],
'city': ['Los Angeles'], 'elev': [127], 'icao': ['KLAX'], 'lon': [-118.4079971],
'type': ['airport'], 'region': ['US-CA'], 'runways': [4], 'lat': [33.94250107],
'desc': ['Los Angeles International Airport']},
{T.id: 63, T.label: 'airport', 'country': ['NZ'], 'code': ['AKL'], 'longest': [11926],
'city': ['Auckland'], 'elev': [23], 'icao': ['NZAA'], 'lon': [174.792007446],
'type': ['airport'], 'region': ['NZ-AUK'], 'runways': [2], 'lat': [-37.0080986023],
'desc': ['Auckland International Airport']}])
pattern = [PathPattern.V, PathPattern.IN_V]
gn = GremlinNetwork()
gn.add_results_with_pattern([path], pattern)
edge_data = gn.graph.get_edge_data('13', '63')
self.assertIsNotNone(edge_data)

def test_add_path_with_v_oute_inv_pattern_string_ids(self):
path = Path([], [{T.id: '13', T.label: 'airport', 'country': ['US'], 'code': ['LAX'], 'longest': [12091],
'city': ['Los Angeles'], 'elev': [127], 'icao': ['KLAX'], 'lon': [-118.4079971],
'type': ['airport'], 'region': ['US-CA'], 'runways': [4], 'lat': [33.94250107],
'desc': ['Los Angeles International Airport']}, 6512,
{T.id: '63', T.label: 'airport', 'country': ['NZ'], 'code': ['AKL'], 'longest': [11926],
'city': ['Auckland'], 'elev': [23], 'icao': ['NZAA'], 'lon': [174.792007446],
'type': ['airport'], 'region': ['NZ-AUK'], 'runways': [2], 'lat': [-37.0080986023],
'desc': ['Auckland International Airport']}])
pattern = [PathPattern.V, PathPattern.OUT_E, PathPattern.IN_V]
gn = GremlinNetwork()
gn.add_results_with_pattern([path], pattern)
edge_data = gn.graph.get_edge_data('13', '63')
self.assertIn(6512, edge_data)


if __name__ == '__main__':
unittest.main()