|
1 | | -Development Sandbox: |
| 1 | +# nx-arangodb |
2 | 2 |
|
3 | | -<a href="https://colab.research.google.com/drive/1gIfJDEumN6UdZou_VlSbG874xGkHwtU2?usp=sharing" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
| 3 | +<a href="https://colab.research.google.com/github/arangodb/nx-arangodb/blob/main/docs/notebook.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
4 | 4 |
|
5 | | -What's currently possible: |
6 | | -- ArangoDB CRUD Interface for `nx.Graph` |
7 | | -- Algorithm dispatching to `nx` & `nxcg` (`betweenness_centrality`, `pagerank`, `louvain_communities`) |
8 | | -- Algorithm dispatching to ArangoDB (`shortest_path`) |
9 | | -- Data Load from ArangoDB to `nx` object |
10 | | -- Data Load from ArangoDB to `nxcg` object |
11 | | -- Data Load from ArangoDB via dictionary-based remote connection |
12 | 5 |
|
13 | | -Next steps: |
14 | | -- Generalize `nxadb`'s support for `nx` & `nxcg` algorithms |
15 | | -- Improve support for `nxadb.DiGraph` |
16 | | -- CRUD Interface Improvements |
| 6 | +<div style="display: flex; align-items: center; gap: 10px;"> |
| 7 | + <img src="https://avatars.githubusercontent.com/u/388785?s=200&v=4" alt="NetworkX" style="height: 60px;"> |
| 8 | + <img src="https://arangodb.com/wp-content/uploads/2016/05/[email protected]" alt="ArangoDB" style="height: 60px;"> |
| 9 | + <img src="https://rapids.ai/images/RAPIDS-logo.png" alt="RAPIDS" style="height: 60px;"> |
| 10 | + <img src="https://insights.virti.com/content/images/2021/09/20181218-Nvidia-Inception.png" alt="NVIDIA" style="height: 60px;"> |
| 11 | +</div> |
17 | 12 |
|
18 | | -Planned: |
19 | | -- Support for `nxadb.MultiGraph` & `nxadb.MultiDiGraph` |
20 | | -- Data Load from `nx` to ArangoDB |
21 | | -- Data Load from `nxcg` to ArangoDB |
| 13 | +<br> |
22 | 14 |
|
23 | | -```py |
| 15 | +[](https://dl.circleci.com/status-badge/redirect/gh/arangodb/nx-arangodb/tree/main) |
| 16 | +[](https://github.com/arangodb/nx-arangodb/actions/workflows/analyzee.yaml) |
| 17 | +[](https://github.com/arangodb/nx-arangodb/actions/workflows/docs.yaml) |
| 18 | +[](https://github.com/arangodb/nx-arangodb/commits/main) |
| 19 | + |
| 20 | +[](https://pypi.org/project/nx-arangodb/) |
| 21 | +[](https://pypi.org/project/nx-arangodb/) |
| 22 | + |
| 23 | +[](https://github.com/psf/black) |
| 24 | +[](https://pepy.tech/project/nx-arangodb) |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +https://github.com/user-attachments/assets/e5f56574-d3ef-452c-ab21-b47b3d5d5900 |
| 30 | + |
| 31 | + |
| 32 | +## What is this? |
| 33 | + |
| 34 | +This is a [backend to NetworkX](https://networkx.org/documentation/stable/reference/backends.html) that offers [ArangoDB](https://github.com/arangodb/arangodb) as a [Persistence Layer to NetworkX Graphs](https://arangodb.com/introducing-the-arangodb-networkx-persistence-layer/). |
| 35 | + |
| 36 | +`nx-arangodb` allows you to: |
| 37 | +1. Persist NetworkX Graphs to ArangoDB. |
| 38 | +2. Reload NetworkX Graphs from ArangoDB. |
| 39 | +2. Perform CRUD on ArangoDB Graphs via NetworkX. |
| 40 | +3. Run algorithms (CPU & GPU) on ArangoDB Graphs via NetworkX. |
| 41 | + |
| 42 | +Benefits of having ArangoDB as a backend to NetworkX include: |
| 43 | +1. No need to re-create the graph every time you start a new session. |
| 44 | +2. Access to GPU-accelerated graph analytics ([nx-cugraph](https://docs.rapids.ai/api/cugraph/nightly/nx_cugraph/nx_cugraph/)). |
| 45 | +2. Access to a database query language ([Arango Query Language](https://arangodb.com/sql-aql-comparison/)). |
| 46 | +3. Access to a visual interface for graph exploration ([ArangoDB Web UI](https://docs.arangodb.com/3.11/components/web-interface/graphs/)). |
| 47 | +4. Access to cross-collaboration on the same graph ([ArangoDB Cloud](https://dashboard.arangodb.cloud/)). |
| 48 | + |
| 49 | +6. Access to efficient distribution of graph data ([ArangoDB SmartGraphs](https://docs.arangodb.com/3.11/graphs/smartgraphs/)). |
| 50 | + |
| 51 | +<p align="center"> |
| 52 | + <img src="./docs/_static/nxadb.png" style="height: 200px;"> |
| 53 | +</p> |
| 54 | + |
| 55 | + |
| 56 | +## Does this replace NetworkX? |
| 57 | + |
| 58 | +No. This is a plugin to NetworkX, which means that you can use NetworkX as you normally would, but with the added benefit of persisting your graphs to a database. |
| 59 | + |
| 60 | +```python |
24 | 61 | import os |
25 | 62 | import networkx as nx |
26 | 63 | import nx_arangodb as nxadb |
27 | 64 |
|
28 | 65 | os.environ["DATABASE_HOST"] = "http://localhost:8529" |
29 | 66 | os.environ["DATABASE_USERNAME"] = "root" |
30 | | -os.environ["DATABASE_PASSWORD"] = "password" |
| 67 | +os.environ["DATABASE_PASSWORD"] = "openSesame" |
31 | 68 | os.environ["DATABASE_NAME"] = "_system" |
32 | 69 |
|
33 | | -G = nxadb.Graph(name="KarateGraph") |
| 70 | +G = nxadb.Graph(name="MyGraph") |
34 | 71 |
|
35 | | -G_nx = nx.karate_club_graph() |
36 | | -assert len(G.nodes) == len(G_nx.nodes) |
37 | | -assert len(G.adj) == len(G_nx.adj) |
38 | | -assert len(G.edges) == len(G_nx.edges) |
| 72 | +G.add_node(1, foo='bar') |
| 73 | +G.add_node(2, bar='foo') |
| 74 | +G.add_edge(1, 2, weight=2) |
| 75 | + |
| 76 | +res = nx.pagerank(G) |
| 77 | + |
| 78 | +for k, v in res.items(): |
| 79 | + G.nodes[k]['pagerank'] = v |
| 80 | +``` |
| 81 | + |
| 82 | +## Does this mean I need to learn ArangoDB? |
| 83 | + |
| 84 | +No. You can use `nx-arangodb` without knowing anything about ArangoDB. The UX of `nx-arangodb` is designed to be as close as possible to the UX of NetworkX. See the ReadTheDocs for a list of features that are currently unsupported/in-development. |
| 85 | + |
| 86 | +```python |
| 87 | +import os |
| 88 | +import networkx as nx |
| 89 | +import nx_arangodb as nxadb |
| 90 | + |
| 91 | +# os.environ ... |
| 92 | + |
| 93 | +# Re-connect to the graph |
| 94 | +G = nxadb.Graph(name="MyGraph") |
| 95 | + |
| 96 | +assert G.number_of_nodes() == 2 |
| 97 | +assert G.number_of_edges() == 1 |
| 98 | +``` |
| 99 | + |
| 100 | + |
| 101 | +## How do I install it? |
| 102 | + |
| 103 | +```bash |
| 104 | +pip install nx-arangodb |
| 105 | +``` |
| 106 | + |
| 107 | +### What if I want to use nx-cuGraph with it? |
| 108 | + |
| 109 | +```bash |
| 110 | +pip install nx-cugraph-cu12 --extra-index-url https://pypi.nvidia.com |
| 111 | +pip install nx-arangodb |
| 112 | +``` |
| 113 | + |
| 114 | +## What are the easiests ways to set up ArangoDB? |
| 115 | + |
| 116 | +**1) Local Instance via Docker** |
| 117 | + |
| 118 | +Appears on `localhost:8529` with the user `root` & password `openSesame`. |
| 119 | + |
| 120 | +More info: [arangodb.com/download-major](https://arangodb.com/download-major/). |
| 121 | + |
| 122 | +```bash |
| 123 | +docker run -e ARANGO_ROOT_PASSWORD=openSesame -p 8529:8529 arangodb/arangodb |
| 124 | +``` |
| 125 | + |
| 126 | +**2) ArangoDB Cloud Trial** |
| 127 | + |
| 128 | +[ArangoGraph](https://dashboard.arangodb.cloud/home) is ArangoDB’s Cloud offering to use ArangoDB as a managed service. |
| 129 | + |
| 130 | +A 14-day trial is available upon sign up. |
| 131 | + |
| 132 | +**3) Temporary Cloud Instance via Python** |
| 133 | + |
| 134 | +A temporary cloud database can be provisioned using the [adb-cloud-connector](https://github.com/arangodb/adb-cloud-connector?tab=readme-ov-file#arangodb-cloud-connector) python package. |
| 135 | + |
| 136 | +```python |
| 137 | +# !pip install adb-cloud-connector |
| 138 | + |
| 139 | +import os |
| 140 | +from adb_cloud_connector import get_temp_credentials |
| 141 | + |
| 142 | +credentials = get_temp_credentials() |
| 143 | + |
| 144 | +os.environ["DATABASE_HOST"] = credentials["url"] |
| 145 | +os.environ["DATABASE_USERNAME"] = credentials["username"] |
| 146 | +os.environ["DATABASE_PASSWORD"] = credentials["password"] |
| 147 | +os.environ["DATABASE_NAME"] = credentials["database"] |
| 148 | + |
| 149 | +# ... |
| 150 | +``` |
| 151 | + |
| 152 | +## How does Algorithm Dispatching work? |
| 153 | + |
| 154 | +`nx-arangodb` will automatically dispatch algorithm calls to either CPU or GPU based on if `nx-cugraph` is installed. We rely on a rust-based library called [phenolrs](https://github.com/arangoml/phenolrs) to retrieve ArangoDB Graphs as fast as possible. |
| 155 | + |
| 156 | +You can also force-run algorithms on CPU even if `nx-cugraph` is installed: |
| 157 | + |
| 158 | +```python |
| 159 | +import os |
| 160 | +import networkx as nx |
| 161 | +import nx_arangodb as nxadb |
| 162 | + |
| 163 | +# os.environ ... |
| 164 | + |
| 165 | +G = nxadb.Graph(name="MyGraph") |
| 166 | + |
| 167 | +nx.config.backends.arangodb.use_gpu = False |
39 | 168 |
|
40 | | -nx.betweenness_centrality(G) |
41 | 169 | nx.pagerank(G) |
42 | | -nx.community.louvain_communities(G) |
43 | | -nx.shortest_path(G, "person/1", "person/34") |
44 | | -nx.all_neighbors(G, "person/1") |
| 170 | +nx.betweenness_centrality(G) |
| 171 | +# ... |
45 | 172 |
|
46 | | -G.nodes(data='club', default='unknown') |
47 | | -G.edges(data='weight', default=1000) |
| 173 | +nx.config.backends.arangodb.use_gpu = True |
| 174 | +``` |
48 | 175 |
|
49 | | -G.nodes["person/1"] |
50 | | -G.adj["person/1"] |
51 | | -G.edges[("person/1", "person/3")] |
| 176 | +<p align="center"> |
| 177 | + <img src="./docs/_static/dispatch.png" style="height: 200px;"> |
| 178 | +</p> |
52 | 179 |
|
53 | | -G.nodes["person/1"]["name"] = "John Doe" |
54 | | -G.nodes["person/1"].update({"age": 40}) |
55 | | -del G.nodes["person/1"]["name"] |
56 | 180 |
|
57 | | -G.adj["person/1"]["person/3"]["weight"] = 2 |
58 | | -G.adj["person/1"]["person/3"].update({"weight": 3}) |
59 | | -del G.adj["person/1"]["person/3"]["weight"] |
| 181 | +## Can I create an ArangoDB Graph from an existing NetworkX Graph? |
60 | 182 |
|
61 | | -G.edges[("person/1", "person/3")]["weight"] = 0.5 |
62 | | -assert G.adj["person/1"]["person/3"]["weight"] == 0.5 |
| 183 | +Yes, this is actually the recommended way to start using `nx-arangodb`: |
63 | 184 |
|
64 | | -G.add_node("person/35", name="Jane Doe") |
65 | | -G.add_nodes_from( |
66 | | - [("person/36", {"name": "Jack Doe"}), ("person/37", {"name": "Jill Doe"})] |
67 | | -) |
68 | | -G.add_edge("person/1", "person/35", weight=1.5, _edge_type="knows") |
69 | | -G.add_edges_from( |
70 | | - [ |
71 | | - ("person/1", "person/36", {"weight": 2}), |
72 | | - ("person/1", "person/37", {"weight": 3}), |
73 | | - ], |
74 | | - _edge_type="knows", |
75 | | -) |
| 185 | +```python |
| 186 | +import os |
| 187 | +import networkx as nx |
| 188 | +import nx_arangodb as nxadb |
| 189 | + |
| 190 | +# os.environ ... |
76 | 191 |
|
77 | | -G.remove_edge("person/1", "person/35") |
78 | | -G.remove_edges_from([("person/1", "person/36"), ("person/1", "person/37")]) |
79 | | -G.remove_node("person/35") |
80 | | -G.remove_nodes_from(["person/36", "person/37"]) |
| 192 | +G_nx = nx.karate_club_graph() |
81 | 193 |
|
82 | | -G.clear() |
| 194 | +G_nxadb = nxadb.Graph( |
| 195 | + incoming_graph_data=G_nx, |
| 196 | + name="MyKarateGraph" |
| 197 | +) |
83 | 198 |
|
84 | | -assert len(G.nodes) == len(G_nx.nodes) |
85 | | -assert len(G.adj) == len(G_nx.adj) |
86 | | -assert len(G.edges) == len(G_nx.edges) |
87 | | -``` |
| 199 | +assert G_nxadb.number_of_nodes() == G_nx.number_of_nodes() |
| 200 | +assert G_nxadb.number_of_edges() == G_nx.number_of_edges() |
| 201 | +``` |
0 commit comments