├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ ├── META-INF
│ └── MANIFEST.MF
│ └── org
│ └── elasticgremlin
│ ├── groovy
│ └── plugin
│ │ └── ElasticGraphGremlinPlugin.java
│ ├── process
│ └── optimize
│ │ ├── ElasticGraphStep.java
│ │ ├── ElasticOptimizationStrategy.java
│ │ └── ElasticVertexStep.java
│ ├── queryhandler
│ ├── EdgeHandler.java
│ ├── Predicates.java
│ ├── QueryHandler.java
│ ├── SimpleQueryHandler.java
│ ├── VertexHandler.java
│ ├── elasticsearch
│ │ ├── Geo.java
│ │ ├── edgedoc
│ │ │ ├── DocEdge.java
│ │ │ └── DocEdgeHandler.java
│ │ ├── helpers
│ │ │ ├── ElasticClientFactory.java
│ │ │ ├── ElasticHelper.java
│ │ │ ├── ElasticMutations.java
│ │ │ ├── LazyGetter.java
│ │ │ ├── QueryIterator.java
│ │ │ └── TimingAccessor.java
│ │ ├── stardoc
│ │ │ ├── BasicEdgeMapping.java
│ │ │ ├── EdgeMapping.java
│ │ │ ├── InnerEdge.java
│ │ │ ├── StarHandler.java
│ │ │ └── StarVertex.java
│ │ └── vertexdoc
│ │ │ ├── DocVertex.java
│ │ │ └── DocVertexHandler.java
│ └── virtualvertex
│ │ ├── VirtualVertex.java
│ │ └── VirtualVertexHandler.java
│ └── structure
│ ├── BaseEdge.java
│ ├── BaseElement.java
│ ├── BaseProperty.java
│ ├── BaseVertex.java
│ ├── BaseVertexProperty.java
│ ├── ElasticFeatures.java
│ └── ElasticGraph.java
└── test
└── java
└── org
└── elasticgremlin
├── ElasticGraphGraphProvider.java
├── elastic
├── ConfigurationTests.java
├── PerformanceTests.java
├── SpatialStepTests.java
└── TemporaryTests.java
├── simpleQueryHandler
├── groovy
│ ├── ElasticGraphGroovyEnvironmentIntegrateTest.java
│ ├── ElasticGraphGroovyEnvironmentTest.java
│ └── ElasticGraphGroovyProcessStandardTest.java
└── java
│ ├── ElasticGraphProcessStandardTest.java
│ ├── ElasticGraphStructurePerformanceTest.java
│ └── ElasticGraphStructureStandardTest.java
└── starQueryHandler
├── ModernGraphGraphProvider.java
├── ModernGraphQueryHandler.java
├── groovy
├── ModernGraphGroovyEnvironmentIntegrateTest.java
├── ModernGraphGroovyProcessStandardTest.java
└── ModernGraphProcessStandardTest.java
└── java
├── ModernGraphGroovyEnvironmentTest.java
├── ModernGraphStructurePerformanceTest.java
└── ModernGraphStructureStandardTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
14 | # Custom
15 | .idea/
16 | data/
17 | *.iml
18 | out/
19 | target/
20 | *.tmp
21 | build/
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Notice:** This project has migrated over to [Unipop](https://github.com/rmagen/unipop)
2 |
3 | # elastic-gremlin
4 |
5 | [TinkerPop 3](http://tinkerpop.incubator.apache.org/docs/3.0.0-SNAPSHOT/) implementation on Elasticsearch backend. You should read up on Tinkerpop before you use elastic-gremlin.
6 |
7 | ## Features
8 | - **Scalable**
9 | Using ElasticSearch's scale-out capabilities we can spread out our graph to many nodes, enabling more data while retaining good performance.
10 | - **Indexing**
11 | We utilise ES's great indexing capabilities. Either let elastic-gremlin automatically create them, or configure the mappings for your specific needs.
12 | You can index Text (including analyzers), Numbers, Dates, Geo (just use the Geo predicate in a 'has' clause), etc..
13 | - **Custom Schema**
14 | ES offers many different ways to customize the way your data is stored, enabling you to optimize it for your specific querying needs. We give you the power to use all these features and get the most out of your ES cluster.
15 | You can also utilize this ability to query existing data that you've loaded into ElasticSearch, by mapping the data to vertex-edge relationships of different kinds.
16 | - **Aggregations** (Coming Soon)
17 | Aggregation traversals (e.g. g.V().count()) can benefit greatly from ES's [Aggregation module](https://www.elastic.co/guide/en/elasticsearch/reference/1.x/search-aggregations.html)
18 |
19 |
20 | ## Getting Started!
21 | 1. clone & build elastic-gremlin
22 |
23 | ```git clone https://github.com/rmagen/elastic-gremlin.git```
24 |
25 | ```mvn clean install -Dmaven.test.skip=true```
26 |
27 | 2. Create an ElasticGraph:
28 |
29 | ```java
30 | BaseConfiguration config = new BaseConfiguration();
31 | /* put configuration properties as you like*/
32 | ElasticGraph graph = new ElasticGraph(config);
33 | GraphTraversalSource g = graph.traversal();
34 | g.addV();
35 | ```
36 | 3. Or just use the Gremlin Server or Gremlin Console.
37 |
38 |
39 | ##Confiuration
40 |
41 | ###Basic
42 | Basic usage of elastic-gremlin creates or uses an existing ES index, with each Vertex and Edge contained in its own document.
43 | You can customize some of the behaviour:
44 |
45 | - `elasticsearch.client` (Default: "NODE")
46 | The client type used to connect to elasticsearch.
47 | - `NODE` Sets up a local elasticsearch node and runs against it. elastic-gremlin defaults to NODE, so you can get up and running as quickly as possible.
48 | - `TRANSPORT_CLIENT` Connects to an existing ES node.
49 | - `NODE_CLIENT` An optimized way to connect to an ES cluster.
50 | For more information read [here](http://www.elastic.co/guide/en/elasticsearch/client/java-api/current/client.html)
51 | - `elasticsearch.cluster.name`(Default: "elasticsearch")
52 | The elasticsearch cluster's name.
53 | - `elasticsearch.cluster.address` (Default: "127.0.0.1:9300")
54 | The elasticsearch nodes' address. The format is: "ip1:port1,ip2:port2,...".
55 | - `elasticsearch.refresh` (Default: true)
56 | Whether to refresh the ES index before every search. Useful for testing.
57 | - `elasticsearch.index.name` (Default: "graph")
58 | The name of the elasticsearch index.
59 | - `elasticsearch.bulk` (Default: false)
60 | Cache all mutations in-memory and execute them in bulk when calling `ElasticGraph.commit()`.
61 |
62 | And most importantly you can customize the ES Index's Mappings to best fit your data. You can use ES's own APIs to do it. elastic-gremlin will automatically utilize your indices as best as he can.
63 |
64 |
65 | ###Advanced
66 | In addition to index mappings, ES offers many other ways to optimize your queries.
67 | - Model your documents in [different ways](https://www.elastic.co/guide/en/elasticsearch/guide/current/modeling-your-data.html) (Nested Objects, Parent-Child Relationship, etc)
68 | - and your [indices](https://www.elastic.co/guide/en/elasticsearch/guide/current/time-based.html)
69 | - [routing](https://www.elastic.co/blog/customizing-your-document-routing)
70 | - batch together queries
71 | - upsert documents
72 | - and any other ES feature that could help optimize your use-case...
73 |
74 | Implement `QueryHandler` to use a customized schema that works best for your data.
75 | We still don't have enough documentation on this, but you can take a look at the implementations of `SimpleQueryHandler` and `ModernGraphQueryHandler`
76 |
77 |
78 |
79 | You're welcome to send us any comments or questions (rmagen@gmail.com)
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | elastic-gremlin
5 | elastic-gremlin
6 | 0.1.0
7 |
8 | 3.0.0-incubating
9 | 1.5.2
10 |
11 |
12 |
13 | org.apache.tinkerpop
14 | gremlin-core
15 | ${tinkerpop.version}
16 |
17 |
18 | org.apache.tinkerpop
19 | gremlin-groovy
20 | ${tinkerpop.version}
21 |
22 |
23 | org.apache.tinkerpop
24 | gremlin-test
25 | ${tinkerpop.version}
26 | test
27 |
28 |
29 | org.apache.tinkerpop
30 | gremlin-groovy-test
31 | ${tinkerpop.version}
32 | test
33 |
34 |
35 |
36 | org.elasticsearch
37 | elasticsearch
38 | ${elasticsearch.version}
39 |
40 |
41 | com.spatial4j
42 | spatial4j
43 | 0.4.1
44 |
45 |
46 | com.vividsolutions
47 | jts
48 | 1.12
49 |
50 |
51 | xerces
52 | xercesImpl
53 |
54 |
55 |
56 |
57 | com.github.stephenc.eaio-uuid
58 | uuid
59 | 3.4.0
60 |
61 |
62 | org.json
63 | json
64 | 20090211
65 |
66 |
67 |
68 | ${basedir}/target
69 |
70 |
71 |
72 | org.apache.maven.plugins
73 | maven-compiler-plugin
74 | 3.1
75 |
76 | 1.8
77 | 1.8
78 |
79 |
80 |
81 |
82 |
83 |
84 | maven-enforcer-plugin
85 | 1.3.1
86 |
87 |
88 | enforce-all
89 |
90 | enforce
91 |
92 |
93 |
94 |
95 |
96 | [1.8.0-40,)
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | maven-dependency-plugin
105 |
106 |
107 | install
108 |
109 | copy-dependencies
110 |
111 |
112 | ${project.build.directory}/lib
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path: elasticsearch-1.5.2.jar hamcrest-all-1.3.jar groovy-2.4.1-
3 | indy.jar groovy-groovysh-2.4.1-indy.jar junit-benchmarks-0.7.2.jar iv
4 | y-2.3.0.jar jackson-core-2.5.3.jar hamcrest-core-1.3.jar groovy-conso
5 | le-2.4.1.jar gremlin-groovy-3.0.1-SNAPSHOT.jar groovy-jsr223-2.4.1-in
6 | dy.jar log4j-1.2.17.jar lucene-queries-4.10.4.jar gremlin-groovy-test
7 | -3.0.1-SNAPSHOT.jar slf4j-log4j12-1.7.12.jar jline-2.12.jar jcl-over-
8 | slf4j-1.7.12.jar commons-configuration-1.10.jar commons-io-2.4.jar gr
9 | abbag-1.8.1.jar lucene-queryparser-4.10.4.jar lucene-core-4.10.4.jar
10 | hppc-0.7.1.jar groovy-templates-2.4.1.jar groovy-xml-2.4.1.jar asm-co
11 | mmons-4.1.jar asm-4.1.jar gremlin-shaded-3.0.1-SNAPSHOT.jar h2-1.3.17
12 | 1.jar jackson-databind-2.5.3.jar groovy-2.4.1.jar javatuples-1.2.jar
13 | lucene-sandbox-4.10.4.jar lucene-highlighter-4.10.4.jar gremlin-test-
14 | 3.0.1-SNAPSHOT.jar lucene-suggest-4.10.4.jar commons-lang3-3.3.1.jar
15 | lucene-spatial-4.10.4.jar json-20090211.jar commons-lang-2.6.jar luce
16 | ne-grouping-4.10.4.jar groovy-swing-2.4.1.jar lucene-misc-4.10.4.jar
17 | jcabi-log-0.14.jar jackson-annotations-2.5.0.jar spatial4j-0.4.1.jar
18 | uuid-3.4.0.jar antlr-runtime-3.5.jar snakeyaml-1.15.jar jcabi-manifes
19 | ts-1.1.jar groovy-json-2.4.1-indy.jar jts-1.12.jar slf4j-api-1.7.12.j
20 | ar lucene-memory-4.10.4.jar lucene-analyzers-common-4.10.4.jar gremli
21 | n-core-3.0.1-SNAPSHOT.jar junit-4.12.jar mockito-all-1.9.5.jar lucene
22 | -join-4.10.4.jar
23 | Main-Class:
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/org/elasticgremlin/groovy/plugin/ElasticGraphGremlinPlugin.java:
--------------------------------------------------------------------------------
1 | package org.elasticgremlin.groovy.plugin;
2 |
3 | import org.elasticgremlin.structure.ElasticGraph;
4 | import org.apache.tinkerpop.gremlin.groovy.plugin.*;
5 |
6 | import java.util.*;
7 |
8 | /**
9 | * @author Stephen Mallette (http://stephen.genoprime.com)
10 | */
11 | public class ElasticGraphGremlinPlugin extends AbstractGremlinPlugin {
12 |
13 |
14 | private static final Set IMPORTS = new HashSet() {{
15 | add(IMPORT_SPACE + ElasticGraph.class.getPackage().getName() + DOT_STAR);
16 | }};
17 |
18 | @Override
19 | public String getName() {
20 | return "tinkerpop.elasticgremlin";
21 | }
22 |
23 | @Override
24 | public void pluginTo(final PluginAcceptor pluginAcceptor) throws PluginInitializationException, IllegalEnvironmentException {
25 | pluginAcceptor.addImports(IMPORTS);
26 | }
27 |
28 | @Override
29 | public void afterPluginTo(final PluginAcceptor pluginAcceptor) throws IllegalEnvironmentException, PluginInitializationException {
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/elasticgremlin/process/optimize/ElasticGraphStep.java:
--------------------------------------------------------------------------------
1 | package org.elasticgremlin.process.optimize;
2 |
3 | import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
4 | import org.apache.tinkerpop.gremlin.structure.*;
5 | import org.elasticgremlin.queryhandler.*;
6 |
7 | import java.util.Iterator;
8 |
9 | public class ElasticGraphStep extends GraphStep {
10 |
11 | private final Predicates predicates;
12 | private final QueryHandler queryHandler;
13 |
14 | public ElasticGraphStep(GraphStep originalStep, Predicates predicates, QueryHandler queryHandler) {
15 | super(originalStep.getTraversal(), originalStep.getReturnClass(), originalStep.getIds());
16 | originalStep.getLabels().forEach(label -> this.addLabel(label.toString()));
17 | predicates.labels.forEach(label -> this.addLabel(label.toString()));
18 | this.predicates = predicates;
19 | this.queryHandler = queryHandler;
20 |
21 | this.setIteratorSupplier(() -> (Iterator) (Vertex.class.isAssignableFrom(this.returnClass) ? this.vertices() : this.edges()));
22 | }
23 |
24 | private Iterator extends Vertex> vertices() {
25 | return queryHandler.vertices(predicates);
26 | }
27 |
28 | private Iterator extends Edge> edges() {
29 | return queryHandler.edges(predicates);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/elasticgremlin/process/optimize/ElasticOptimizationStrategy.java:
--------------------------------------------------------------------------------
1 | package org.elasticgremlin.process.optimize;
2 |
3 | import org.apache.tinkerpop.gremlin.process.traversal.*;
4 | import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
5 | import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
6 | import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
7 | import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
8 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
9 | import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
10 | import org.apache.tinkerpop.gremlin.structure.*;
11 | import org.elasticgremlin.queryhandler.Predicates;
12 | import org.elasticgremlin.structure.ElasticGraph;
13 |
14 | public class ElasticOptimizationStrategy extends AbstractTraversalStrategy {
15 | private static final ElasticOptimizationStrategy INSTANCE = new ElasticOptimizationStrategy();
16 | public static ElasticOptimizationStrategy instance() {
17 | return INSTANCE;
18 | }
19 |
20 | @Override
21 | public void apply(Traversal.Admin, ?> traversal) {
22 | if(traversal.getEngine().isComputer()) return;
23 | Graph graph = traversal.getGraph().get();
24 | if(!(graph instanceof ElasticGraph)) return;
25 | ElasticGraph elasticGraph = (ElasticGraph) graph;
26 |
27 | TraversalHelper.getStepsOfClass(GraphStep.class, traversal).forEach(graphStep -> {
28 | if(graphStep.getIds().length == 0) {
29 | Predicates predicates = getPredicates(graphStep, traversal);
30 | final ElasticGraphStep> elasticGraphStep = new ElasticGraphStep<>(graphStep, predicates, elasticGraph.getQueryHandler());
31 | TraversalHelper.replaceStep(graphStep, (Step) elasticGraphStep, traversal);
32 | }
33 | });
34 |
35 | TraversalHelper.getStepsOfClass(VertexStep.class, traversal).forEach(vertexStep -> {
36 | boolean returnVertex = vertexStep.getReturnClass().equals(Vertex.class);
37 | Predicates predicates = returnVertex ? new Predicates() : getPredicates(vertexStep, traversal);
38 |
39 | ElasticVertexStep elasticVertexStep = new ElasticVertexStep(vertexStep, predicates);
40 | TraversalHelper.replaceStep(vertexStep, elasticVertexStep, traversal);
41 | });
42 | }
43 |
44 | private Predicates getPredicates(Step step, Traversal.Admin traversal){
45 | Predicates predicates = new Predicates();
46 | Step, ?> nextStep = step.getNextStep();
47 |
48 | while(true) {
49 | if(nextStep instanceof HasContainerHolder) {
50 | HasContainerHolder hasContainerHolder = (HasContainerHolder) nextStep;
51 | hasContainerHolder.getHasContainers().forEach(predicates.hasContainers::add);
52 | collectLabels(predicates, nextStep);
53 | traversal.removeStep(nextStep);
54 | }
55 | else if(nextStep instanceof RangeGlobalStep) {
56 | /*RangeGlobalStep rangeGlobalStep = (RangeGlobalStep) nextStep;
57 | predicates.limitLow = rangeGlobalStep.getLowRange();
58 | predicates.limitHigh = rangeGlobalStep.getHighRange();
59 | collectLabels(predicates, nextStep);
60 | traversal.removeStep(rangeGlobalStep);*/
61 | }
62 | else return predicates;
63 |
64 | nextStep = nextStep.getNextStep();
65 | }
66 | }
67 |
68 | private void collectLabels(Predicates predicates, Step, ?> step) {
69 | step.getLabels().forEach(predicates.labels::add);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/org/elasticgremlin/process/optimize/ElasticVertexStep.java:
--------------------------------------------------------------------------------
1 | package org.elasticgremlin.process.optimize;
2 |
3 | import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
4 | import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
5 | import org.apache.tinkerpop.gremlin.structure.*;
6 | import org.elasticgremlin.queryhandler.Predicates;
7 | import org.elasticgremlin.structure.BaseVertex;
8 |
9 | import java.util.Iterator;
10 |
11 | public class ElasticVertexStep extends VertexStep {
12 | private final Predicates predicates;
13 |
14 | public ElasticVertexStep(VertexStep originalStep, Predicates predicates) {
15 | super(originalStep.getTraversal(), originalStep.getReturnClass(), originalStep.getDirection(),
16 | originalStep.getEdgeLabels());
17 | originalStep.getLabels().forEach(label -> this.addLabel(label.toString()));
18 | predicates.labels.forEach(this::addLabel);
19 | this.predicates = predicates;
20 | }
21 |
22 | @Override
23 | protected Iterator flatMap(Traverser.Admin traverser) {
24 | Vertex vertex = traverser.get();
25 | if (!(vertex instanceof BaseVertex)) return super.flatMap(traverser);
26 | BaseVertex baseVertex = (BaseVertex) vertex;
27 |
28 | if (Vertex.class.isAssignableFrom(this.getReturnClass()))
29 | return (Iterator) baseVertex.vertices(this.getDirection(), this.getEdgeLabels(), predicates);
30 |
31 | return (Iterator) baseVertex.edges(this.getDirection(), this.getEdgeLabels(), predicates);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/elasticgremlin/queryhandler/EdgeHandler.java:
--------------------------------------------------------------------------------
1 | package org.elasticgremlin.queryhandler;
2 |
3 | import org.apache.tinkerpop.gremlin.structure.*;
4 | import org.elasticgremlin.structure.BaseVertex;
5 |
6 | import java.util.*;
7 |
8 | public interface EdgeHandler {
9 | Iterator edges();
10 | Iterator edges(Object[] edgeIds);
11 | public Iterator edges(Predicates predicates);
12 | public Map