Skip to content
This repository was archived by the owner on Oct 18, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
ad6216a
updated versions
FaKod Mar 15, 2011
58efee1
update plugins
FaKod Mar 15, 2011
af30142
changed shell version
FaKod Mar 16, 2011
36cc180
refactoring, comments and changed implicits
FaKod Mar 16, 2011
2968b92
1st step of making it really really complex
FaKod Mar 17, 2011
8dd7963
added some convenience implicits/objects and tests for them
FaKod Mar 20, 2011
09c2458
added spatial query convenience methods
FaKod Mar 21, 2011
b1d6505
added searchWithin convenience methods
FaKod Mar 21, 2011
0911694
using node pattern (http://wiki.neo4j.org/content/Design_Guide)
FaKod Mar 22, 2011
591c6a6
added factory
FaKod Mar 23, 2011
94e8734
some refactorings (not finished)
FaKod Mar 25, 2011
53fb31b
1st refactored version
FaKod Mar 25, 2011
358aa1f
some refactorings
FaKod Mar 25, 2011
753c624
added some text
FaKod Mar 25, 2011
baa9376
typos
FaKod Mar 25, 2011
edcad76
added example to README
FaKod Mar 25, 2011
b983c94
new search convenience method
FaKod Mar 28, 2011
94651cb
added SearchWithDistance
FaKod Mar 29, 2011
d073ea9
implicit for getting IndexManager
FaKod Apr 11, 2011
9be4cb9
index creation convenience trait
FaKod Apr 11, 2011
b153b6a
renamed
FaKod Apr 11, 2011
bb39385
added Neo4j Index Provider Trait test
FaKod Apr 12, 2011
8f9872a
conversion to ease the use of optional configuration
FaKod Apr 12, 2011
992f2ff
add index trait example to README
FaKod Apr 12, 2011
d640dde
forgot the node index
FaKod Apr 13, 2011
de3e424
Refactoring (should be easier to understand now)
FaKod Apr 14, 2011
9245cb8
refactoring
FaKod Jul 20, 2011
ce2fdc1
changed to Scala 2.9.0-1
FaKod Jul 20, 2011
8952fa3
added layer convenience methods
FaKod Jul 20, 2011
7a645e3
renamed
FaKod Jul 20, 2011
dccf394
serialize and deserialize case classes
FaKod Jul 22, 2011
0f777ba
added Node Case Class serialization and test (1st version)
FaKod Jul 25, 2011
f93d403
removed unused import
FaKod Jul 25, 2011
72d1dcd
added access to relations with "<" operator
FaKod Jul 25, 2011
29fa673
added convenience method for node creation and serialization
FaKod Jul 25, 2011
5042267
simpler names
FaKod Jul 25, 2011
635d447
added some geometry creation convenience methods
FaKod Jul 26, 2011
0dc7849
removed import
FaKod Jul 26, 2011
38eeb43
cleaned up some searches
FaKod Jul 27, 2011
14cbd75
reformat
FaKod Jul 27, 2011
2154b62
nodeIndex += (…) adding to index convenience implicit conversion
FaKod Aug 26, 2011
226676c
Spelling correction in README
Aug 28, 2011
07e54c9
added remove from index convenience
FaKod Aug 29, 2011
5f2dea9
Merge pull request #1 from holdensmagicalunicorn/master
FaKod Aug 29, 2011
b1647bb
changed class property from toString to getName
FaKod Aug 30, 2011
6f78778
Merge branch 'master' of https://github.com/FaKod/neo4j-scala
FaKod Aug 30, 2011
348c30a
removed spatial wrapper stuff and
FaKod Sep 14, 2011
449b993
removed spatial stuff from read me
FaKod Sep 14, 2011
569633f
removed self reference to Neo4jWrapper
FaKod Sep 15, 2011
69c8449
old licence
FaKod Sep 15, 2011
0e102a7
added IDEA files
FaKod Sep 15, 2011
47376f1
created Neo4jWrapper Object make DeSerialization "static"
FaKod Sep 16, 2011
9a4a6f0
updated documentation
FaKod Sep 18, 2011
9f311ef
some typos
FaKod Sep 19, 2011
f5b5da6
added some more Case Class convenience
FaKod Sep 19, 2011
9a663a6
fixed a typo in git repo path
FaKod Sep 20, 2011
bfb1b10
more tests
FaKod Sep 21, 2011
99a4c10
using Neo4j 1.5-SNAPSHOT
FaKod Sep 27, 2011
043e397
case class marshaling for Relations
FaKod Oct 6, 2011
8779c1c
convenience in using case classes with Relations
FaKod Oct 6, 2011
87675f4
changed all T <: Product to AnyRef
FaKod Oct 12, 2011
aa218a4
added method toCCPossible to allow "instance of" checks
FaKod Oct 12, 2011
aa1906e
added some missing GraphDatabaseService methods
FaKod Oct 12, 2011
411f78a
significant (un-)marshaling performance improvements (caching of Scal…
FaKod Oct 12, 2011
86006a0
added singleton Db Service Provider
FaKod Oct 16, 2011
5875fa8
added Scala Lib Shutdown Hook
FaKod Oct 16, 2011
8587bcf
removed index config from trait ctor
FaKod Oct 16, 2011
1514b41
initial commit to support transparent batch processing
FaKod Oct 19, 2011
d7d21a8
fixed some bugs
FaKod Oct 20, 2011
6fed45b
fixed dramatic memory leak
FaKod Oct 20, 2011
21b3b35
added index shutdown
FaKod Oct 20, 2011
d22925e
unused import
FaKod Oct 21, 2011
6797714
added Batch processing
FaKod Oct 21, 2011
2bf9f7a
fix singleton Providers
FaKod Oct 25, 2011
f6399a2
added Github as Maven Repo (temporarily)
FaKod Oct 25, 2011
0762acf
added maven repo info
FaKod Oct 28, 2011
12692dc
allow null Case Class properties (-> no Neo4j property is set in that…
FaKod Nov 1, 2011
d6fea42
added The Matrix Example
FaKod Nov 1, 2011
5dad0f7
emulating the normal index add semantic with batch inserter
FaKod Nov 11, 2011
ab2c131
Added Matrix Example GIST
FaKod Nov 13, 2011
db113a0
working against 1.5 now
FaKod Nov 14, 2011
443d9a1
released 0.1.0
FaKod Nov 15, 2011
cd3b739
Update README.md
FaKod Nov 16, 2011
57f4b32
Update README.md
FaKod Nov 16, 2011
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
generated
target
.manager
*~

.idea
*.i??
*~
22 changes: 0 additions & 22 deletions LICENSE

This file was deleted.

172 changes: 142 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,71 +5,183 @@ The Neo4j Scala wrapper library allows you the [Neo4j open source graph database
domain-specific simplified language. It is written in Scala and is intended
to be used in other Scala projects.

This wrapper is mostly based on the work done by [Martin Kleppmann](http://twitter.com/martinkl) in his [Scala implementation of RESTful JSON HTTP resources on top of the Neo4j graph database and Jersey](http://github.com/ept/neo4j-resources) project. I thought it'd be usefull to extract the Neo4j DSL into a seperate project, and Marting agreed to this.
This wrapper is mostly based on the work done by [Martin Kleppmann](http://twitter.com/martinkl) in his [Scala implementation of RESTful JSON HTTP resources on top of the Neo4j graph database and Jersey](http://github.com/ept/neo4j-resources) project.


Building
--------

You need a Java 5 (or newer) environment and Maven 2.0.9 (or newer) installed:
See this [GIST](https://gist.github.com/1331556) for a usual Neo4j Matrix Example

You may find [Neo4j-Spatial-Scala](http://github.com/FaKod/neo4j-spatial-scala) interesting as well.

$ mvn --version
Apache Maven 3.0-alpha-5 (r883378; 2009-11-23 16:53:41+0100)
Java version: 1.6.0_15
Java home: /usr/lib/jvm/java-6-sun-1.6.0.15/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux" version: "2.6.31-12-generic" arch: "i386" Family: "unix"

You should now be able to do a full build of `neo4j-resources`:
Building
--------

$ git clone git://github.com/jawher/neo4j-scala.git
$ git clone git://github.com/FaKod/neo4j-scala.git
$ cd neo4j-scala
$ mvn clean install

To use this library in your projects, add the following to the `dependencies` section of your
`pom.xml`:
Or try to maven fetch it with a Github Maven Repo:

<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-scala</artifactId>
<version>0.9.9-SNAPSHOT</version>
</dependency>

If you don't use Maven, take `target/neo4j-scala-0.9.9-SNAPSHOT.jar` and all of its dependencies, and add them to your classpath.
<repositories>
<repository>
<id>fakod-releases</id>
<url>https://raw.github.com/FaKod/fakod-mvn-repo/master/releases</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-scala</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>

Troubleshooting
---------------

Please consider using [Github issues tracker](http://github.com/jawher/neo4j-scala/issues) to submit bug reports or feature requests.
Please consider using [Github issues tracker](http://github.com/fakod/neo4j-scala/issues) to submit bug reports or feature requests.


Using this library
------------------
==================

Graph Database Service Provider
------------------------------
Neo4j Scala Wrapper needs a Graph Database Service Provider, it has to implement GraphDatabaseServiceProvider trait.
One possibility is to use the EmbeddedGraphDatabaseServiceProvider for embedded Neo4j instances where you simply have to define a Neo4j storage directory.
A class using the wrapper is f.e.:

class MyNeo4jClass extends SomethingClass with Neo4jWrapper with EmbeddedGraphDatabaseServiceProvider {
def neo4jStoreDir = "/tmp/temp-neo-test"
. . .
}

Transaction Wrapping
--------------------
Transactions are wrapped by withTx. After leaving the "scope" success is called (or rollback if an exception is raised):

withTx {
implicit neo =>
val start = createNode
val end = createNode
start --> "foo" --> end
}

Using an Index
---------------------
Neo4j provides indexes for nodes and relationships. The indexes can be configured by mixing in the Neo4jIndexProvider trait. See [Indexing](http://docs.neo4j.org/chunked/stable/indexing.html)

class MyNeo4jClass extends . . . with Neo4jIndexProvider {
// configuration for the index being created.
override def NodeIndexConfig = ("MyTest1stIndex", Map("provider" -> "lucene", "type" -> "fulltext")) ::
("MyTest2ndIndex", Map("provider" -> "lucene", "type" -> "fulltext")) :: Nil
}

Use one of the configured indexes with

val nodeIndex = getNodeIndex("MyTest1stIndex").get

Add and remove entries by:

nodeIndex += (Node_A, "title", "The Matrix")
nodeIndex -= (Node_A)

Relations
---------

Using this wrapper, this is how creating two relationships can look in Scala:

start --> "KNOWS" --> intermediary --> "KNOWS" --> end
left --> "foo" --> middle <-- "bar" <-- right

Returning the Relation Object:

val relation = start --> "KNOWS" --> end <

Properties
----------

And this is how getting and setting properties on a node or relationship looks like :

// setting the property foo
start("foo") = "bar"
start("foo") match {
// cast Object to String and match . . .
start[String]("foo") match {
case Some(x) => println(x)
case None => println("aww")
case None => println("aww")
}

Using Case Classes
------------------
Neo4j provides storing keys (String) and values (Object) into Nodes. To store Case Classes the property names of the case class are used as keys and the values are stored Strings as well. Working types are limited to basic types like String, integer etc.

case class Test(s: String, i: Int, ji: java.lang.Integer, d: Double, l: Long, b: Boolean)
. . .
withTx {
implicit neo =>
// create new Node with Case Class Test
val node1 = createNode(Test("Something", 1, 2, 3.3, 10, true))

// "recreate" Case Class Test from Node
val node2 = Neo4jWrapper.deSerialize[Test](node)

// or using Option[T] (returning Some[T] if possible)
val nodeOption: Option[Test] = node.toCC[Test]

// yield all Nodes that are of type Case Class Test
val tests = for(n <- getTraverser; t <- n.toCC[Test]) yield t

// create new relation with Case Class Test
node1 --> "foo" --> node2 < Test("other", 0, 1, 1.3, 1, false)
}

Traversing
----------

Besides, the neo4j scala binding makes it possible to write stop and returnable evaluators in a functional style :

//StopEvaluator.END_OF_GRAPH, written in a Scala idiomatic way :
start.traverse(Traverser.Order.BREADTH_FIRST, (tp : TraversalPosition) => false, ReturnableEvaluator.ALL_BUT_START_NODE, DynamicRelationshipType.withName("foo"), Direction.OUTGOING)
start.traverse(Traverser.Order.BREADTH_FIRST, (tp : TraversalPosition) => false,
ReturnableEvaluator.ALL_BUT_START_NODE, "foo", Direction.OUTGOING)

//ReturnableEvaluator.ALL_BUT_START_NODE, written in a Scala idiomatic way :
start.traverse(Traverser.Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH, (tp : TraversalPosition) => tp.notStartNode(), DynamicRelationshipType.withName("foo"), Direction.OUTGOING)
start.traverse(Traverser.Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH, (tp : TraversalPosition) => tp.notStartNode(),
"foo", Direction.OUTGOING)

Batch Processing
-----------------
Neo4j has a batch insertion mode intended for initial imports, which must run in a single thread and bypasses transactions and other checks in favor of performance. See [Batch insertion](http://docs.neo4j.org/chunked/milestone/indexing-batchinsert.html).

The Java interfaces are slightly different. I wrote some wrapper classes to support nearly transparent usage of batch node and batch relation insertion. Means same code for batch insertion and for normal non batch mode. Instead of using

class Builder extends Neo4jWrapper with SingletonEmbeddedGraphDatabaseServiceProvider with Neo4jIndexProvider {...}

simply exchange the provider traits with

class Builder extends Neo4jWrapper with Neo4jBatchIndexProvider with BatchGraphDatabaseServiceProvider {...}

getting the indexes is still the same code

val nodeIndex = getNodeIndex("NodeIndex").get
val relationIndex = getRelationIndex("RelationIndex").get

setting cache size:

nodeIndex.setCacheCapacity("NodeIndex", 1000000)
relationIndex.setCacheCapacity("RelationIndex", 1000000)

Nevertheless, indexes are not available till flushing. To flush call:

License
-------
nodeIndex.flush
relationIndex.flush

See `LICENSE` for details.
After insertion, the batch index manager and batch insertion manager have to be shut down

class Builder extends Neo4jWrapper . . .{
. . .
shutdownIndex
shutdown(ds)
. . .
}
89 changes: 89 additions & 0 deletions examples/eu/fakod/examples/TheMatrix.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package eu.fakod.examples

import org.neo4j.scala.{EmbeddedGraphDatabaseServiceProvider, Neo4jWrapper}
import sys.ShutdownHookThread
import org.neo4j.graphdb.Traverser.Order
import collection.JavaConversions._
import org.neo4j.graphdb._

/**
* The Matrix Example
* http://wiki.neo4j.org/content/The_Matrix
*/
case class Matrix(name: String, profession: String)

object TheMatrix extends App with Neo4jWrapper with EmbeddedGraphDatabaseServiceProvider {

ShutdownHookThread {
shutdown(ds)
}

def neo4jStoreDir = "/tmp/temp-neo-TheMatrix"

final val nodes = Map("Neo" -> "Hacker",
"Morpheus" -> "Hacker",
"Trinity" -> "Hacker",
"Cypher" -> "Hacker",
"Agent Smith" -> "Program",
"The Architect" -> "Whatever")

withTx {
implicit neo =>
val nodeMap = for ((name, prof) <- nodes) yield (name, createNode(Matrix(name, prof)))

getReferenceNode --> "ROOT" --> nodeMap("Neo")

nodeMap("Neo") --> "KNOWS" --> nodeMap("Trinity")
nodeMap("Neo") --> "KNOWS" --> nodeMap("Morpheus") --> "KNOWS" --> nodeMap("Trinity")
nodeMap("Morpheus") --> "KNOWS" --> nodeMap("Cypher") --> "KNOWS" --> nodeMap("Agent Smith")
nodeMap("Agent Smith") --> "CODED_BY" --> nodeMap("The Architect")

/**
* Find the friends
*/

println("\n***** Find the friends")

nodeMap("Neo").traverse(Order.BREADTH_FIRST,
StopEvaluator.END_OF_GRAPH,
ReturnableEvaluator.ALL_BUT_START_NODE,
DynamicRelationshipType.withName("KNOWS"),
Direction.OUTGOING).foreach {
n =>
n.toCC[Matrix] match {
case None => println("not a Matrix Case Class")
case Some(Matrix(name, prof)) => println("Name: " + name + " Profession: " + prof)
}
}

/**
* Find the hackers
*/

println("\n***** Find the hackers")

def isReturnableNode(currentPosition: TraversalPosition) =
currentPosition.lastRelationshipTraversed match {
case null => false
case rel => rel.isType(DynamicRelationshipType.withName("CODED_BY"))
}

val traverser = nodeMap("Neo").traverse(Order.BREADTH_FIRST,
StopEvaluator.END_OF_GRAPH,
isReturnableNode _,
DynamicRelationshipType.withName("CODED_BY"),
Direction.OUTGOING,
DynamicRelationshipType.withName("KNOWS"),
Direction.OUTGOING)

traverser.foreach {
n =>
n.toCC[Matrix] match {
case None => println("not a Matrix Case Class")
case Some(Matrix(name, prof)) =>
println("At depth " +traverser.currentPosition.depth + " Name: " + name + " Profession: " + prof)
}
}
}

}
Loading