README.md 11 KB
Newer Older
1
![](http://syncleus.com/Ferma/images/ferma-logo-text.svg)
2

3
[![Build status](http://git.qoto.org/Ferma/Ferma/badges/master/pipeline.svg)](http://git.qoto.org/Ferma/Ferma/-/commits/master)
4
[![Coverage](https://codecov.io/gh/Syncleus/Ferma/branch/master/graph/badge.svg)](https://codecov.io/gh/Syncleus/Ferma)
5
[![Dependencies](https://www.versioneye.com/user/projects/57e37d4279806f0039830884/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/57e37d4279806f0039830884)
6
[![Codacy](https://api.codacy.com/project/badge/Grade/e287e33b94734124ada41efd0ae48652)](https://www.codacy.com/app/freemo/Ferma?utm_source=github.com&utm_medium=referral&utm_content=Syncleus/Ferma&utm_campaign=Badge_Grade)
7
[![Javadocs](http://www.javadoc.io/badge/com.syncleus.ferma/ferma.svg)](http://www.javadoc.io/doc/com.syncleus.ferma/ferma)
8
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.syncleus.ferma/ferma/badge.png?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.syncleus.ferma/ferma/)
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
9
[![Gitter](https://badges.gitter.im/Syncleus/Ferma.svg)](https://gitter.im/Syncleus/Ferma?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
10

11
An ORM / OGM for the Apache TinkerPop™ graph stack.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
12

13
14
**Licensed under the Apache Software License v2**

Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
15
The Ferma project was originally created as an alternative to the TinkerPop2 Frames project. Which at the time lacked
16
features needed by the community, and its performance was cripplingly slow. Today Ferma is a robust framework that
17
takes on a role similar to an Object-relational Model (ORM) library for traditional databases. Ferma is often referred to
18
19
20
as a Object-graph Model (OGM) library, and maps Java objects to elements in a graph such as a Vertex or an Edge. In
short it allows a schema to be defined using java interfaces and classes which provides a level of abstraction for
interacting with the underlying graph.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
21

22
Ferma 3.x **Supports TinkerPop3**. For TinkerPop2 support use Ferma version 2.x.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
23
24
25

Annotated classes in Ferma have their abstract methods implemented using code generation during start-up with Byte
Buddy, avoiding the need for proxy classes. This in turn significantly improves performance when compared with TinkerPop
26
27
28
Frames and other frameworks. Ferma offers many features including several annotation types to reduce the need for
boilerplate code as well as handling Java typing transparently. This ensures whatever the type of the object is when you
persist it to the graph the same Java type will be used when instantiating a class off of the graph.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
29
30

Ferma is designed to easily replace TinkerPop Frames in existing code, as such, the annotations provided by Ferma are a
31
super-set of those originally provided by TinkerPop Frames.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
32

33
34
35
Ferma is built directly on top of TinkerPop and allows access to all of the internals. This ensures all the
TinkerPop features are available to the end-user. The TinkerPop stack provides several tools which can be used to work
with the Ferma engine.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
36
37
38
39

* **Gremlin**, a database agnostic query language for Graph Databases.
* **Gremlin Server**, a server that provides an interface for executing Gremlin on remote machines.
* a data-flow framework for splitting, merging, filtering, and transforming of data
40
* **Graph Computer**, a framework for running algorithms against a Graph Database.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
41
* Support for both **OLTP** and **OLAP** engines.
42
* **TinkerGraph** a Graph Database and the reference implementation for TinkerPop.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
43
44
* Native **Gephi** integration for visualizing graphs.
* Interfaces for most major Graph Compute Engines including **Hadoop M/R**. **Spark**, and **Giraph**.
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
45

46
47
Ferma also supports any of the many databases compatible with TinkerPop including the following.

48
 * [JanusGraph](http://janusgraph.org/)
49
50
51
52
53
 * [Titan](http://thinkaurelius.github.io/titan/)
 * [Neo4j](http://neo4j.com)
 * [OrientDB](http://www.orientechnologies.com/orientdb/)
 * [MongoDB](http://www.mongodb.org)
 * [Oracle NoSQL](http://www.oracle.com/us/products/database/nosql/overview/index.html)
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
54
 * TinkerGraph
55

56
57
The official Ferma source repository is hosted on [QOTO GitLab](https://git.qoto.org/Ferma/Ferma) with an up-to-date mirror maintained at [Github](https://github.com/Syncleus/Ferma).

58
For documentation refer to our [project page](http://syncleus.com/Ferma) as well as the
59
60
[latest Javadocs](http://www.javadoc.io/doc/com.syncleus.ferma/ferma).

61
For support please use [Gitter](https://gitter.im/Syncleus/Ferma?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
62
or the [official Ferma mailing list and Discourse forum](https://discourse.qoto.org/c/PROJ/FERMA).
63

64
Please file bugs and feature requests on the [QOTO GitLab](https://git.qoto.org/ferma/Ferma/issues).
65

66
67
## Dependency

68
To include Ferma in your project of choice include the following Maven dependency into your build.
69

70
71
72
73
```xml
<dependency>
    <groupId>com.syncleus.ferma</groupId>
    <artifactId>ferma</artifactId>
74
    <version>3.3.2</version>
75
76
</dependency>
```
77

78

79
80
## Getting Started

81
Ferma provides three levels of type resolution: untyped, simple, and annotated. In untyped mode Ferma doesn't handle
82
83
84
85
86
typing at all, instead the type must be explicitly indicated whenever querying. In simple mode Ferma provides type
context encoded as graph element properties which ensures the same type comes out that goes in to a graph. In annotated
mode all the features of simple mode are provided as well as enabling the use of annotations on abstract methods to
instruct Ferma to dynamically construct byte-code to implement the abstract methods at start up.

87
### Untyped Mode Example
88
89
90

In untyped mode there is no automatic typing. Whatever class is explicitly indicated is the type that will be
instantiated when performing queries. Lets start with a simple example domain.
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
```java
public class Person extends AbstractVertexFrame {
  public String getName() {
    return getProperty("name");
  }

  public void setName(String name) {
    setProperty("name", name);
  }

  public List<? extends Knows> getKnowsList() {
    return traverse((v) -> v.outE("knows")).toList(Knows.class);
  }

  public Knows addKnows(Person friend) {
107
    return addFramedEdge("knows", friend, Knows.class);
108
109
110
  }
}

111
public class Knows extends AbstractEdgeFrame {
112
113
114
115
116
117
118
119
120
  public void setYears(int years) {
    setProperty("years", years);
  }

  public int getYears() {
    return getProperty("years");
  }
}
```
121

122
And here is how you interact with the framed elements:
123

124
125
```java
public void testUntyped() {
126
  Graph graph = TinkerGraph.open();
127

128
  // implies untyped mode
129
  FramedGraph fg = new DelegatingFramedGraph(graph);
130

131
132
  Person p1 = fg.addFramedVertex(Person.class);
  p1.setName("Jeff");
133

134
135
136
137
  Person p2 = fg.addFramedVertex(Person.class);
  p2.setName("Julia");
  Knows knows = p1.addKnows(p2);
  knows.setYears(15);
138

Evan Thompson's avatar
Evan Thompson committed
139
  Person jeff = fg.traverse((g) -> g.V().has("name", "Jeff")).next(Person.class);
140
141


142
143
144
  Assert.assertEquals("Jeff", jeff.getName());
}
```
145
146
147

### Simple Mode Example

Evan Thompson's avatar
Evan Thompson committed
148
In simple mode you must provide concrete classes, no abstract or interfaces allowed, and the class should always extend
149
150
151
152
153
from a FramedVertex or FramedEdge. Simple mode doesn't provide any annotations either. The purpose of simple mode is to
provide type resolution. Basically the type of object you use when adding to the graph is the same type you get out when
reading from the graph.

Say we extend the Person class with the Programmer class.
154

155
156
157
158
```java
public class Programmer extends Person {
}
```
159

160
Using simple mode will save the type of Java class the element was created with for use later:
161

162
163
```java
public void testSimpleTyping() {
164
  Graph graph = TinkerGraph.open();
165
166

  // implies simple mode
167
  FramedGraph fg = new DelegatingFramedGraph(graph, true, false);
168
169
170
171
172
173
174

  Person p1 = fg.addFramedVertex(Programmer.class);
  p1.setName("Jeff");

  Person p2 = fg.addFramedVertex(Person.class);
  p2.setName("Julia");

Evan Thompson's avatar
Evan Thompson committed
175
176
  Person jeff = fg.traverse((g) -> g.V().has("name", "Jeff")).next(Person.class);
  Person julia = fg.traverse((g) -> g.V().has("name", "Julia")).next(Person.class);
177
178
179
180
181

  Assert.assertEquals(Programmer.class, jeff.getClass());
  Assert.assertEquals(Person.class, julia.getClass());
}
```
182

183
184
185
186
187
188
189
190
191
192
### Annotated Mode Example

In annotated mode you can either provide concrete classes, abstract classes, or even interfaces. Abstract classes and
concrete classes must extend from FramedVertex or FramedEdge, however, interfaces do not have this restriction.
Annotated mode also provides a set of annotations which must be used to define any abstract methods that are to be
implemented by the engine. Annotated mode provides the same type resolution as provided by simple mode with a bit more
power to determine parent-child relationships at runtime.

The same example as above done with annotations would look something like this.

193
194
195
196
```java
public abstract class Person extends AbstractVertexFrame {
  @Property("name")
  public abstract String getName();
197

198
199
  @Property("name")
  public abstract void setName(String name);
200

201
  @Adjacency(label = "knows")
202
  public abstract List<Person> getKnowsPeople();
203

204
  @Incidence(label = "knows")
205
  public abstract List<Knows> getKnows();
206

207
  @Incidence(label = "knows")
208
  public abstract Knows addKnows(Person friend);
209

210
  public List<? extends Person> getFriendsNamedBill() {
211
      return this.traverse(input -> input.out("knows").has("name", "bill")).toList(Person.class);
212
213
  }
}
214

215
216
217
public abstract class Knows extends AbstractEdgeFrame {
  @Property("years")
  public abstract void setYears(int years);
218

219
220
  @Property("years")
  public abstract int getYears();
221

222
223
  @InVertex
  public abstract Person getIn();
224

225
  @OutVertex
226
  public abstract Person getOut();
227
}
228

229
230
231
public abstract class Programmer extends Person {
}
```
232
233

If we pass a collection of Class objects to the FramedGraph constructor then the annotated type resolver will be used.
234
In this mode you want to tell the engine what classes you will be using so it can handle type resolution properly and
235
construct the byte-code for any abstract annotated methods.
236

237
```java
238
239
public void testAnnotatedTyping() {
  Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{
240
241
242
                Person.class,
                Programmer.class,
                Knows.class}));
243
  Graph graph = TinkerGraph.open();
244

245
246
  //implies annotated mode
  FramedGraph fg = new DelegatingFramedGraph(graph, true, types);
247

248
249
  Person jeff = fg.addFramedVertex(Programmer.class);
  jeff.setName("Jeff");
250

251
252
  Person julia = fg.addFramedVertex(Person.class);
  julia.setName("Julia");
253
  julia.addKnows(jeff);
254

255
256
  Person juliaAgain = fg.traverse((g) -> g.V().has("name", "Julia")).next(Person.class);
  Person jeffAgain = juliaAgain.getKnowsPeople().get(0);
257

258
259
  Assert.assertTrue(Programmer.class.isAssignableFrom(jeffAgain.getClass()));
  Assert.assertTrue(Person.class.isAssignableFrom(juliaAgain.getClass()));
260
}
261
```
262
263
264

## Obtaining the Source

Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
265
The official source repository for Ferma is located in the Syncleus Github repository and can be cloned using the
266
267
following command.

268
```bash
269
git clone https://git.qoto.org/Ferma/Ferma.git
270
```
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

## Building

### Documentation

Install dependencies

```bash
pip install mkdocs mkdocs-material pymdown-extensions
```

Build documentation

```bash
mkdocs build
```

Deploy to Github

```bash
mkdocs gh-deploy
```