Skip to content
A collection of Scala graph libraries and adapters for graph databases.
Scala Shell
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
akka/src Bug fixes on tests and test dependencies Nov 26, 2016
akkaAdapter/src
bigtable/src
core/src Implement DocumentGraph and DocumentGraphSpec Jan 31, 2017
documentStorage/src
hbase Added helper alias functions to MutableGraph and ImmutableGraph to ad… Dec 20, 2016
memory/src
neo4j/src Travis now depends on the Neo4j docker Nov 26, 2016
project Implement DocumentGraph and DocumentGraphSpec Jan 31, 2017
.gitignore Updated Typesafe config version Nov 6, 2016
.travis.yml Remove hbase from travis startup Jan 31, 2017
LICENSE Update license Nov 25, 2016
README.md
build.sbt Remove hbase from travis startup Jan 31, 2017
continuousIntegration.json.enc
version.sbt

README.md

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

Build Status

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:

// 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:

import com.seancheatham.graph.adapters.memory.MutableGraph
val graph =
    new MutableGraph()

Create an immutable in-memory graph:

import com.seancheatham.graph.adapters.memory.ImmutableGraph
val graph =
    ImmutableGraph()()

Create an embedded Neo4jGraph:

// 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

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

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

val alsoNode1: Option[Node] = 
    graph.getNode("1")
    // OR, to be safe (see above)
    node1.graph.getNode("1")

Get nodes by label and/or data

val nodes: TraversableOnce[Node] = 
    graph.getNodes(Some("label"), Map("name" -> JsString("potato")))

Create an edge between two nodes

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

val incomingEdges: TraversableOnce[Edge] =
    graph.getIngressEdges(node1)
    
val outgoingEdges: TraversableOnce[Edge] =
    graph.getEgressEdges(node1)

Update a node/edge

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

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.

You can’t perform that action at this time.