Graph library/interface with adapter(s), written in Scala
This library serves two purposes:
- Provide a common abstraction for accessing and manipulating a graph data structure
- Provide adapters for various databases (particularly graph databases)
I am a one-man show, so at best, what you see here is work I need in side projects. I've open-sourced this library because other people may find some of it useful.
My current focus is on providing an abstraction for the Neo4j graph database. As such, I have provided a common interface for accessing either an embedded database, or a remote/production instance.
This library is written in Scala. It might interoperate with other JVM languages, but I make no guarantees.
In the build.sbt file located in your project root:
// The core definitions library:
libraryDependencies += "com.seancheatham" %% "graph-core" % "0.0.2"
// To run a basic, in-memory graph:
libraryDependencies += "com.seancheatham" %% "graph-memory-adapter" % "0.0.2"
// To connect to a Neo4j graph:
libraryDependencies += "com.seancheatham" %% "graph-neo4j-adapter" % "0.0.2"
// To expose a graph as an HTTP server:
libraryDependencies += "com.seancheatham" %% "graph-akka-layer" % "0.0.2"
// To connect to an expopsed HTTP graph server:
libraryDependencies += "com.seancheatham" %% "graph-akka-adapter" % "0.0.2"
// To connect to an HBase graph:
libraryDependencies += "com.seancheatham" %% "graph-hbase-adapter" % "0.0.2"
// To connect to a BigTable graph:
libraryDependencies += "com.seancheatham" %% "graph-big-table-adapter" % "0.0.2"
// To connect to a Document Storage graph:
libraryDependencies += "com.seancheatham" %% "graph-document-storage-adapter" % "0.0.2"
import com.seancheatham.graph.adapters.memory.MutableGraph
val graph =
new MutableGraph()
import com.seancheatham.graph.adapters.memory.ImmutableGraph
val graph =
ImmutableGraph()()
// Create a temporary Neo4j graph
import com.seancheatham.graph.adapters.neo4j._
val graph =
Neo4jGraph.embedded()
// Create a graph which persists to disk
import com.seancheatham.graph.adapters.neo4j._
val graph =
Neo4jGraph.embedded("/path/to/save/to")
import com.seancheatham.graph.adapters.neo4j._
val address =
"bolt://192.168.?.?"
// If auth is required
import org.neo4j.driver.v1.AuthTokens
val auth =
AuthTokens.basic("username", "password")
val graph =
Neo4jGraph(address, auth)
// If auth is not required
val graph =
Neo4jGraph(address)
import play.api.libs.json._
val node1: Node =
graph.addNode("label", Map("name" -> JsString("potato")))
// NOTE: The graph created previously may not be the same graph as `node1.graph`
// Depending on the implementation of the Graph, a brand new graph may be created
// after each change to it. To be safe, once you modify `graph`, throw it out.
// Generally, mutable graphs will re-use the same Graph for each change.
val alsoNode1: Option[Node] =
graph.getNode("1")
// OR, to be safe (see above)
node1.graph.getNode("1")
val nodes: TraversableOnce[Node] =
graph.getNodes(Some("label"), Map("name" -> JsString("potato")))
val edge1: Edge =
graph.addEdge(node1, node2, "edge_label", Map("weight" -> Json.toJson(1.5)))
// Or you can use some syntactic sugar:
import com.seancheatham.graph.Edge.NodeEdgeSyntax
val edge1: Edge =
graph.addEdge(node1 -"LABEL"-> node2, Map("weight" -> Json.toJson(1.5)))
val incomingEdges: TraversableOnce[Edge] =
graph.getIngressEdges(node1)
val outgoingEdges: TraversableOnce[Edge] =
graph.getEgressEdges(node1)
val updatedNode1 =
graph.updateNode(node1)("name" -> JsString("carrot"), "category" -> JsString("vegetable"))
val updatedEdge1 =
graph.updateEdge(edge1)("weight" -> Json.toJson(2.3))
The graph-akka-layer module allows you to expose a Graph through a REST API Server, backed by Akka.
import com.seancheatham.graph.akka.http.HttpServer
val graph: Graph =
???
val server =
HttpServer(graph) // OR HttpServer(graph, "localhost", 8080)
// Visit http://localhost:8080 for API paths and details
...
// Don't forget to shut it down
server.shutdown()
Running the Application with no arguments will start a new mutable graph instance, bound to localhost:8080.
You can run the server using command line arguments (run -help for info), but the preferred way is using Typesafe configurations. In your application.conf file:
graph {
http {
host = "localhost"
port = 8080
}
type = "mutable" // OR: immutable, neo4j-embedded, neo4j-remote
// If graph.type == "neo4j-embedded"
neo4j {
embedded {
dir = "/tmp/neo4jembedded"
}
}
// If graph.type == "neo4j-remote"
neo4j {
remote {
address = "bolt://127.0.0.2"
user = "neo4j"
password = "neo4j"
}
}
}
Once configured, just run the graph-akka-layer's "main()" method.