Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/seancheatham/scala-graph

A collection of Scala graph libraries and adapters for graph databases.
https://github.com/seancheatham/scala-graph

Last synced: 17 days ago
JSON representation

A collection of Scala graph libraries and adapters for graph databases.

Awesome Lists containing this project

README

        

Graph library/interface with adapter(s), written in Scala

[![Build Status](https://travis-ci.org/SeanCheatham/scala-graph.svg?branch=master)](https://travis-ci.org/SeanCheatham/scala-graph)

# Overview
This library serves two purposes:
1. Provide a common abstraction for accessing and manipulating a graph data structure
2. 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.

# Usage
This library is written in Scala. It _might_ interoperate with other JVM languages, but I make no guarantees.

## Include the library in your project.
In the *build.sbt* file located in your project root:
```scala
// 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"
```
## Create a Graph instance
### Create a mutable in-memory graph:
```scala
import com.seancheatham.graph.adapters.memory.MutableGraph
val graph =
new MutableGraph()
```
### Create an immutable in-memory graph:
```scala
import com.seancheatham.graph.adapters.memory.ImmutableGraph
val graph =
ImmutableGraph()()
```
### Create an embedded Neo4jGraph:
```scala
// 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")
```

### Connect to a remote Neo4j Instance
```scala
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)
```

## Create a node
```scala
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.
```
## Get a node by ID
```scala
val alsoNode1: Option[Node] =
graph.getNode("1")
// OR, to be safe (see above)
node1.graph.getNode("1")
```
## Get nodes by label and/or data
```scala
val nodes: TraversableOnce[Node] =
graph.getNodes(Some("label"), Map("name" -> JsString("potato")))
```
## Create an edge between two nodes
```scala
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)))
```
## Fetch inbound or outbound edges for a node
```scala
val incomingEdges: TraversableOnce[Edge] =
graph.getIngressEdges(node1)

val outgoingEdges: TraversableOnce[Edge] =
graph.getEgressEdges(node1)
```
## Update a node/edge
```scala
val updatedNode1 =
graph.updateNode(node1)("name" -> JsString("carrot"), "category" -> JsString("vegetable"))

val updatedEdge1 =
graph.updateEdge(edge1)("weight" -> Json.toJson(2.3))
```

## Expose a Graph as an Akka-backed HTTP Server
The graph-akka-layer module allows you to expose a Graph through a REST API Server, backed by Akka.

### From an existing Graph instance
```scala
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()
```

### Run as an Application via main method
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.