Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArangoDB - Graph creation basics

I'm brand new to ArangoDB. I'm familiar with Neo4J, but was drawn to ArangoDB's performance and multi-model design. The documentation seems very deep, but I'm having trouble getting started.

I would like to know a simple way to do some basic graph operations. All I've found so far tells me how to connect entire collections together, but I would like to simply be able to define a node, define another node, and define the edge between them.

Ideally via HTTP, how can I:

  • Add a node to the graph
  • Create an edge between two nodes I've added to my graph
  • Create a collection and add existing nodes to that collection

As an example, I would like to create a simple graph like the tree illustrated here: https://www.arangodb.com/2015/07/data-modeling-with-multi-model-databases/

Aircraft fleet maintenance example tree

I'd like basic instructions on how to create a subset of this graph. I would like to:

  • Create nodes called airline0 and airline1 in a collection called fleets.
  • Create nodes plane0, plane1, plane2 in a collection called planes. - Put an arbitrary attribute in each plane's document- let's say color.
  • Create a node called Jennifer in a collection called pilots.

Next, I would like to connect up the graph. Based on the documentation, it looks like edges themselves are documents, and thus can have attributes. I'd like to create the following edges:

  • (airline0)-[owns]->(plane0)
  • (airline0)-[owns]->(plane1) this edge has since: 2013 as an attribute
  • (airline1)-[owns]->(plane2)
  • (airline1)-[previouslyOwned]->(plane1) between: [1999,2013]
  • (plane0)-[inFleet]->(airline0)
  • (plane1)-[inFleet]->(airline0)
  • (plane1)-[wasInFleet]->(airline1) between: [1999,2013]
  • (plane2)-[inFleet]->(airline1)
  • (jennifer)-[canfly]->(plane0)
  • (plane0)-[hasPilot]->(jennifer)

Please show me how I can create such a graph via HTTP. If not HTTP, I'd like to know how to do this via arangosh.

like image 898
Nate Gardner Avatar asked Jan 07 '23 03:01

Nate Gardner


1 Answers

Let me start with the arangosh, because it is easier to read. I'll give the HTTP commands as an addendum.

ArangoDB Shell

You would need the three document collections "fleets", "planes", and "pilots" as you mentioned above and an at least one edge collection to hold the graph structure. If you want to traverse the graph structure jumping between "owns" and "inFleet" and "canfly", I suggest to use one collection "relations" and give the edges an attribute "type".

An alternative solution is to use three edge collections "owns" and "inFleet" and "canfly". In order to make a more fact-based recommendation, it would be good to know more about your use-case.

arangosh [_system]> db._create("fleets");
[ArangoCollection 139792431, "fleets" (type document, status loaded)]

arangosh [_system]> db._create("planes");
[ArangoCollection 140382255, "planes" (type document, status loaded)]

arangosh [_system]> db._create("pilots");
[ArangoCollection 140972079, "pilots" (type document, status loaded)]

arangosh [_system]> db._createEdgeCollection("relations");
[ArangoCollection 141103151, "relations" (type edge, status loaded)]

Next, create the documents in the collection "fleets". I will use the name of the airline as key. Depending on your use case, there might be a better key. For example, maybe there is a universal abbreviation (like LH for Lufthansa).

arangosh [_system]> db.fleets.save({ _key: "airline0", name: "Airline 0" });
arangosh [_system]> db.fleets.save({ _key: "airline1", name: "Airline 1" });

Repeat the same for planes and pilots:

arangosh [_system]> db.planes.save({ _key: "plane0", name: "Plane Zero", color: "red" })
arangosh [_system]> db.planes.save({ _key: "plane1", name: "Plane One", color: "red" })
arangosh [_system]> db.planes.save({ _key: "plane2", name: "Plane One", color: "green" })
arangosh [_system]> db.pilots.save({ _key: "jennifer", name: "Jenifer" });

You should select the keys according to your use-case. If there are no "natural" keys, then leave out the "_key" attribute. ArangoDB will generate a unique key for you.

Next, add the relations between the nodes creates above. The syntax in ArangoDB 2.8 is similar to creating a document above. In addition, you need to supply the "from" and "to" keys of the vertices, you want to connect.

arangosh [_system]> db.relations.save("fleets/airline0", "planes/plane0", { type: 'owns' });
arangosh [_system]> db.relations.save("fleets/airline0", "planes/plane1", { type: 'owns', since: 2013 });
arangosh [_system]> db.relations.save("fleets/airline1", "planes/plane2", { type: 'owns' });
arangosh [_system]> db.relations.save("fleets/airline1", "planes/plane1", { type: 'previouslyOwned', begin: 1999, end: 2013 });
arangosh [_system]> db.relations.save("pilots/jennifer", "planes/plane0", { type: 'canfly' });

If 'inFleet' / 'wasInFleet' / 'hasPilot' is the reverse of 'owns' / 'previouslyOwned' / 'canfly', than you do not need to create a separate edge for it, because edges are directional.

If there are differences between 'owns' and 'inFleet' you can create the relations similar to the above:

arangosh [_system]> db.relations.save("planes/plane0", "fleets/airline0", { type: 'inFleet' });
...

Now in order to follow the path "jennifer can fly planeX owned by airlineY" use:

arangosh> db._query("FOR v, e IN OUTBOUND 'pilots/jennifer' relations FILTER e.type == 'canfly' FOR w, f IN INBOUND v relations FILTER f.type == 'owns' RETURN { plane: v, airline: w }")
[
  {
    "plane" : {
      "color" : "red",
      "name" : "Plane Zero",
      "_id" : "planes/plane0",
      "_rev" : "153686063",
      "_key" : "plane0"
    },
    "airline" : {
      "name" : "Airline 0",
      "_id" : "fleets/airline0",
      "_rev" : "149884975",
      "_key" : "airline0"
    }
  }
]

Or to reverse the path (without using 'inFleet' and 'hasPilot'):

arangosh> db._query("FOR v, e IN OUTBOUND 'fleets/airline0' relations FILTER e.type == 'owns' FOR w, f IN INBOUND v relations FILTER f.type == 'canfly' RETURN { plane: v, w: w }")
[
  {
    "plane" : {
      "color" : "red",
      "name" : "Plane Zero",
      "_id" : "planes/plane0",
      "_rev" : "153686063",
      "_key" : "plane0"
    },
    "w" : {
      "_id" : "pilots/jennifer",
      "_rev" : "330240047",
      "_key" : "jennifer"
    }
  }
]

HTTP

Let me give you example for the various types of commands executed above.

arangosh [_system]> db._create("fleets");

this translates to

curl -X POST --data-binary @- --dump - http://localhost:8529/_api/collection <<EOF
{ 
  "name" : "fleets" 
}
EOF

Next

arangosh [_system]> db._createEdgeCollection("relations");

translates to

curl -X POST --data-binary @- --dump - http://localhost:8529/_api/collection <<EOF
{ 
  "name" : "relations", "type": 3 
}
EOF

Next

arangosh [_system]> db.fleets.save({ _key: "airline0", name: "Airline 0" });

translates to

curl -X POST --data-binary @- --dump - http://localhost:8529/_api/document?collection=products <<EOF
{ "_key": "airline0", "name": "Airline 0" }
EOF

Next

db.relations.save("pilots/jennifer", "planes/plane0", { type: 'canfly' });

translates to

curl -X POST --data-binary @- --dump - http://localhost:8529/_api/edge/?collection=relations&from=pilots/jennifer&to=planes/plane0 <<EOF
{ 
  "type" : "canfly" 
}
EOF
like image 118
fceller Avatar answered Jan 19 '23 23:01

fceller