├── .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 vertices() { 25 | return queryHandler.vertices(predicates); 26 | } 27 | 28 | private Iterator 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> edges(Iterator vertices, Direction direction, String[] edgeLabels, Predicates predicates); 13 | public Edge addEdge(Object edgeId, String label,Vertex outV, Vertex inV, Object[] properties); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/Predicates.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler; 2 | 3 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Predicates { 8 | public ArrayList hasContainers = new ArrayList<>(); 9 | public long limitLow = 0; 10 | public long limitHigh = Long.MAX_VALUE; 11 | public ArrayList labels = new ArrayList<>(); 12 | 13 | @Override 14 | public boolean equals(Object o) { 15 | if (this == o) return true; 16 | if (o == null || getClass() != o.getClass()) return false; 17 | 18 | Predicates that = (Predicates) o; 19 | 20 | if (limitLow != that.limitLow) return false; 21 | if (limitHigh != that.limitHigh) return false; 22 | if (hasContainers != null ? !hasContainers.equals(that.hasContainers) : that.hasContainers != null) 23 | return false; 24 | return !(labels != null ? !labels.equals(that.labels) : that.labels != null); 25 | 26 | } 27 | 28 | @Override 29 | public int hashCode() { 30 | int result = hasContainers != null ? hasContainers.hashCode() : 0; 31 | result = 31 * result + (int) (limitLow ^ (limitLow >>> 32)); 32 | result = 31 * result + (int) (limitHigh ^ (limitHigh >>> 32)); 33 | result = 31 * result + (labels != null ? labels.hashCode() : 0); 34 | return result; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/QueryHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler; 2 | 3 | 4 | import org.apache.commons.configuration.Configuration; 5 | import org.elasticgremlin.structure.ElasticGraph; 6 | 7 | import java.io.IOException; 8 | 9 | public interface QueryHandler extends VertexHandler, EdgeHandler { 10 | 11 | void init(ElasticGraph graph, Configuration configuration) throws IOException; 12 | void commit(); 13 | void printStats(); 14 | void close(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/SimpleQueryHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.structure.*; 5 | import org.elasticgremlin.queryhandler.elasticsearch.edgedoc.DocEdgeHandler; 6 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 7 | import org.elasticgremlin.queryhandler.elasticsearch.vertexdoc.DocVertexHandler; 8 | import org.elasticgremlin.structure.*; 9 | import org.elasticsearch.client.Client; 10 | 11 | import java.io.IOException; 12 | import java.util.*; 13 | 14 | public class SimpleQueryHandler implements QueryHandler { 15 | 16 | private DocEdgeHandler docEdgeHandler; 17 | private DocVertexHandler elasticDocVertexHandler; 18 | private Client client; 19 | private ElasticMutations elasticMutations; 20 | private TimingAccessor timing; 21 | 22 | @Override 23 | public void init(ElasticGraph graph, Configuration configuration) throws IOException { 24 | String indexName = configuration.getString("elasticsearch.index.name", "graph"); 25 | boolean refresh = configuration.getBoolean("elasticsearch.refresh", false); 26 | int scrollSize = configuration.getInt("elasticsearch.scrollSize", 500); 27 | boolean bulk = configuration.getBoolean("elasticsearch.bulk", false); 28 | 29 | client = ElasticClientFactory.create(configuration); 30 | ElasticHelper.createIndex(indexName, client); 31 | 32 | timing = new TimingAccessor(); 33 | elasticMutations = new ElasticMutations(bulk, client, timing); 34 | docEdgeHandler = new DocEdgeHandler(graph, client, elasticMutations, indexName, scrollSize, refresh, timing); 35 | elasticDocVertexHandler = new DocVertexHandler(graph, client, elasticMutations, indexName, scrollSize, refresh, timing); 36 | } 37 | 38 | @Override 39 | public void commit() { elasticMutations.commit(); } 40 | @Override 41 | public void close() { 42 | client.close(); 43 | } 44 | 45 | @Override 46 | public Iterator edges() { 47 | return docEdgeHandler.edges(); 48 | } 49 | 50 | @Override 51 | public Iterator edges(Object[] edgeIds) { 52 | return docEdgeHandler.edges(edgeIds); 53 | } 54 | 55 | @Override 56 | public Iterator edges(Predicates predicates) { 57 | return docEdgeHandler.edges(predicates); 58 | } 59 | 60 | @Override 61 | public Map> edges(Iterator vertices, Direction direction, String[] edgeLabels, Predicates predicates) { 62 | return docEdgeHandler.edges(vertices, direction, edgeLabels, predicates); 63 | } 64 | 65 | @Override 66 | public Edge addEdge(Object edgeId, String label, Vertex outV, Vertex inV, Object[] properties) { 67 | return docEdgeHandler.addEdge(edgeId, label, outV, inV, properties); 68 | } 69 | 70 | @Override 71 | public Iterator vertices() { 72 | return elasticDocVertexHandler.vertices(); 73 | } 74 | 75 | @Override 76 | public Iterator vertices(Object[] vertexIds) { 77 | return elasticDocVertexHandler.vertices(vertexIds); 78 | } 79 | 80 | @Override 81 | public Iterator vertices(Predicates predicates) { 82 | return elasticDocVertexHandler.vertices(predicates); 83 | } 84 | 85 | @Override 86 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction) { 87 | return elasticDocVertexHandler.vertex(vertexId, vertexLabel, edge, direction); 88 | } 89 | 90 | @Override 91 | public BaseVertex addVertex(Object id, String label, Object[] properties) { 92 | return elasticDocVertexHandler.addVertex(id, label, properties); 93 | } 94 | 95 | @Override 96 | public void printStats() { 97 | timing.print(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/VertexHandler.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.Iterator; 7 | 8 | public interface VertexHandler { 9 | Iterator vertices(); 10 | Iterator vertices(Object[] vertexIds); 11 | public Iterator vertices(Predicates predicates); 12 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction); 13 | public BaseVertex addVertex(Object id, String label, Object[] properties); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/Geo.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch; 2 | 3 | import com.spatial4j.core.shape.*; 4 | import org.apache.tinkerpop.gremlin.process.traversal.P; 5 | import org.elasticsearch.common.Preconditions; 6 | import org.elasticsearch.common.geo.ShapeRelation; 7 | import org.elasticsearch.common.geo.builders.ShapeBuilder; 8 | import org.elasticsearch.common.xcontent.XContentParser; 9 | import org.elasticsearch.common.xcontent.json.JsonXContent; 10 | import org.json.JSONObject; 11 | 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | import java.util.function.*; 15 | 16 | public enum Geo implements BiPredicate { 17 | 18 | /** 19 | * Whether the intersection between two geographic regions is non-empty 20 | */ 21 | 22 | INTERSECTS(ShapeRelation.INTERSECTS, (geometry1, geometry2) -> { 23 | SpatialRelation relation = geometry1.relate(geometry2); 24 | return relation == SpatialRelation.INTERSECTS || relation == SpatialRelation.CONTAINS || relation == SpatialRelation.WITHIN; 25 | } 26 | ), 27 | 28 | /** 29 | * Whether the intersection between two geographic regions is empty 30 | */ 31 | DISJOINT(ShapeRelation.DISJOINT, (geometry1, geometry2) -> geometry1.relate(geometry2) == SpatialRelation.DISJOINT), 32 | 33 | /** 34 | * Whether one geographic region is completely contains within another 35 | */ 36 | WITHIN(ShapeRelation.WITHIN, (geometry1, geometry2) -> geometry1.relate(geometry2) == SpatialRelation.WITHIN); 37 | 38 | private ShapeRelation relation; 39 | private BiFunction testFunc; 40 | 41 | Geo(ShapeRelation relation, BiFunction testFunc) { 42 | 43 | this.relation = relation; 44 | this.testFunc = testFunc; 45 | } 46 | 47 | ; 48 | 49 | public ShapeRelation getRelation() { 50 | return relation; 51 | } 52 | 53 | @Override 54 | public boolean test(Object o, Object o2) { 55 | Shape s1 = null; 56 | Shape s2 = null; 57 | try { 58 | s1 = convertObjectToShapeIfPossible(o); 59 | s2 = convertObjectToShapeIfPossible(o2); 60 | } catch (IOException e) { 61 | e.printStackTrace(); 62 | } 63 | 64 | if (s1 == null) return false; 65 | return testFunc.apply(s1,s2); 66 | } 67 | 68 | private Shape convertObjectToShapeIfPossible(Object o) throws IOException { 69 | 70 | if(o instanceof Shape) return (Shape) o; 71 | String geoShapeStringValue = null; 72 | if(o instanceof HashMap) { 73 | HashMap map = (HashMap) o; 74 | Preconditions.checkArgument(map.containsKey("coordinates") && map.containsKey("type")); 75 | geoShapeStringValue = (new JSONObject(map)).toString(); 76 | } 77 | else if (o instanceof String){ 78 | geoShapeStringValue = (String) o; 79 | } 80 | Preconditions.checkNotNull(geoShapeStringValue); 81 | XContentParser parser = JsonXContent.jsonXContent.createParser(geoShapeStringValue); 82 | parser.nextToken(); 83 | 84 | return ShapeBuilder.parse(parser).build(); 85 | 86 | 87 | } 88 | 89 | 90 | public static P intersercts(final V value) { return new P(Geo.INTERSECTS, value); }; 91 | public static P disjoint(final V value) { return new P(Geo.DISJOINT, value); }; 92 | public static P within(final V value) { return new P(Geo.WITHIN, value); }; 93 | } 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/edgedoc/DocEdge.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.edgedoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.ElasticMutations; 5 | import org.elasticgremlin.structure.*; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.ExecutionException; 9 | 10 | public class DocEdge extends BaseEdge { 11 | 12 | public static String OutId = "outId"; 13 | public static String OutLabel = "outLabel"; 14 | public static String InId = "inId"; 15 | public static String InLabel = "inLabel"; 16 | private final ElasticMutations elasticMutations; 17 | private final String indexName; 18 | 19 | 20 | public DocEdge(final Object id, final String label, Object[] keyValues, Vertex outV, Vertex inV, final ElasticGraph graph, ElasticMutations elasticMutations, String indexName) { 21 | super(id, label, keyValues, outV, inV, graph); 22 | this.elasticMutations = elasticMutations; 23 | this.indexName = indexName; 24 | } 25 | 26 | @Override 27 | protected void innerRemoveProperty(Property property) { 28 | try { 29 | elasticMutations.updateElement(this, indexName, null, false); 30 | } catch (ExecutionException | InterruptedException e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | @Override 36 | protected boolean shouldAddProperty(String key) { 37 | return super.shouldAddProperty(key) && !key.equals(OutId) && !key.equals(OutLabel) && !key.equals(InId) && !key.equals(InLabel); 38 | } 39 | 40 | @Override 41 | protected void innerRemove() { 42 | elasticMutations.deleteElement(this, indexName, null); 43 | } 44 | 45 | @Override 46 | public Map allFields() { 47 | Map map = super.allFields(); 48 | map.put(DocEdge.InId, inVertex.id()); 49 | map.put(DocEdge.OutId, outVertex.id()); 50 | map.put(DocEdge.InLabel, inVertex.label()); 51 | map.put(DocEdge.OutLabel, outVertex.label()); 52 | return map; 53 | } 54 | 55 | @Override 56 | protected void innerAddProperty(BaseProperty vertexProperty) { 57 | try { 58 | elasticMutations.updateElement(this, indexName, null, false); 59 | } catch (ExecutionException | InterruptedException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/edgedoc/DocEdgeHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.edgedoc; 2 | 3 | import org.apache.tinkerpop.gremlin.process.traversal.P; 4 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 5 | import org.apache.tinkerpop.gremlin.structure.*; 6 | import org.elasticgremlin.queryhandler.*; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 8 | import org.elasticgremlin.structure.*; 9 | import org.elasticsearch.action.get.*; 10 | import org.elasticsearch.client.Client; 11 | import org.elasticsearch.index.engine.DocumentAlreadyExistsException; 12 | import org.elasticsearch.index.query.*; 13 | import org.elasticsearch.search.SearchHit; 14 | 15 | import java.util.*; 16 | 17 | public class DocEdgeHandler implements EdgeHandler { 18 | private ElasticGraph graph; 19 | private final Client client; 20 | private final ElasticMutations elasticMutations; 21 | private final String indexName; 22 | private final int scrollSize; 23 | private final boolean refresh; 24 | private TimingAccessor timing; 25 | 26 | public DocEdgeHandler(ElasticGraph graph, Client client, ElasticMutations elasticMutations, String indexName, 27 | int scrollSize, boolean refresh, TimingAccessor timing) { 28 | this.graph = graph; 29 | this.client = client; 30 | this.elasticMutations = elasticMutations; 31 | this.indexName = indexName; 32 | this.scrollSize = scrollSize; 33 | this.refresh = refresh; 34 | this.timing = timing; 35 | } 36 | 37 | @Override 38 | public Iterator edges() { 39 | return new QueryIterator<>(FilterBuilders.existsFilter(DocEdge.InId), 0, scrollSize, Integer.MAX_VALUE, 40 | client, this::createEdge, refresh, timing, indexName); 41 | } 42 | 43 | @Override 44 | public Iterator edges(Object[] ids) { 45 | MultiGetRequest request = new MultiGetRequest().refresh(refresh); 46 | for (Object id : ids) request.add(indexName, null, id.toString()); 47 | MultiGetResponse responses = client.multiGet(request).actionGet(); 48 | 49 | ArrayList elements = new ArrayList<>(ids.length); 50 | for (MultiGetItemResponse getResponse : responses) { 51 | GetResponse response = getResponse.getResponse(); 52 | if (!response.isExists()) throw Graph.Exceptions.elementNotFound(Edge.class, response.getId()); 53 | elements.add(createEdge(response)); 54 | } 55 | return elements.iterator(); 56 | } 57 | 58 | @Override 59 | public Iterator edges(Predicates predicates) { 60 | BoolFilterBuilder boolFilter = ElasticHelper.createFilterBuilder(predicates.hasContainers); 61 | boolFilter.must(FilterBuilders.existsFilter(DocEdge.InId)); 62 | return new QueryIterator<>(boolFilter, 0, scrollSize, predicates.limitHigh - predicates.limitLow, 63 | client, this::createEdge, refresh, timing, indexName); 64 | } 65 | 66 | @Override 67 | public Map> edges(Iterator vertices, Direction direction, String[] edgeLabels, Predicates predicates) { 68 | Map idToVertex = new HashMap<>(); 69 | vertices.forEachRemaining(singleVertex -> idToVertex.put(singleVertex.id(), singleVertex)); 70 | 71 | if (edgeLabels != null && edgeLabels.length > 0) 72 | predicates.hasContainers.add(new HasContainer(T.label.getAccessor(), P.within(edgeLabels))); 73 | 74 | Object[] vertexIds = idToVertex.keySet().toArray(); 75 | BoolFilterBuilder boolFilter = ElasticHelper.createFilterBuilder(predicates.hasContainers); 76 | if (direction == Direction.IN) 77 | boolFilter.must(FilterBuilders.termsFilter(DocEdge.InId, vertexIds)); 78 | else if (direction == Direction.OUT) 79 | boolFilter.must(FilterBuilders.termsFilter(DocEdge.OutId, vertexIds)); 80 | else if (direction == Direction.BOTH) 81 | boolFilter.must(FilterBuilders.orFilter( 82 | FilterBuilders.termsFilter(DocEdge.InId, vertexIds), 83 | FilterBuilders.termsFilter(DocEdge.OutId, vertexIds))); 84 | 85 | QueryIterator edgeQueryIterator = new QueryIterator<>(boolFilter, 0, scrollSize, predicates.limitHigh - predicates.limitLow, client, this::createEdge , refresh, timing, indexName); 86 | 87 | Map> results = new HashMap<>(); 88 | edgeQueryIterator.forEachRemaining(edge -> edge.vertices(direction).forEachRemaining(vertex -> { 89 | Set resultEdges = results.get(vertex.id()); 90 | if (resultEdges == null) { 91 | resultEdges = new HashSet<>(); 92 | results.put(vertex.id(), resultEdges); 93 | } 94 | resultEdges.add(edge); 95 | })); 96 | 97 | return results; 98 | } 99 | 100 | @Override 101 | public Edge addEdge(Object edgeId, String label, Vertex outV, Vertex inV, Object[] properties) { 102 | DocEdge elasticEdge = new DocEdge(edgeId, label, properties, outV, inV,graph, elasticMutations, indexName); 103 | try { 104 | elasticMutations.addElement(elasticEdge, indexName, null, true); 105 | } 106 | catch (DocumentAlreadyExistsException ex) { 107 | throw Graph.Exceptions.edgeWithIdAlreadyExists(elasticEdge.id()); 108 | } 109 | return elasticEdge; 110 | } 111 | 112 | private Iterator createEdge(Iterator hits) { 113 | ArrayList edges = new ArrayList<>(); 114 | hits.forEachRemaining(hit -> { 115 | Map fields = hit.getSource(); 116 | BaseVertex outVertex = graph.getQueryHandler().vertex(fields.get(DocEdge.OutId), fields.get(DocEdge.OutLabel).toString(), null, Direction.OUT); 117 | BaseVertex inVertex = graph.getQueryHandler().vertex(fields.get(DocEdge.InId), fields.get(DocEdge.InLabel).toString(), null, Direction.IN); 118 | BaseEdge edge = new DocEdge(hit.getId(), hit.getType(), null, outVertex, inVertex, graph, elasticMutations, indexName); 119 | fields.entrySet().forEach((field) -> edge.addPropertyLocal(field.getKey(), field.getValue())); 120 | edges.add(edge); 121 | }); 122 | return edges.iterator(); 123 | } 124 | 125 | private Edge createEdge(GetResponse hit) { 126 | Map fields = hit.getSource(); 127 | BaseVertex outVertex = graph.getQueryHandler().vertex(fields.get(DocEdge.OutId), fields.get(DocEdge.OutLabel).toString(), null, Direction.OUT); 128 | BaseVertex inVertex = graph.getQueryHandler().vertex(fields.get(DocEdge.InId), fields.get(DocEdge.InLabel).toString(), null, Direction.IN); 129 | BaseEdge edge = new DocEdge(hit.getId(), hit.getType(), null, outVertex, inVertex, graph, elasticMutations, indexName); 130 | fields.entrySet().forEach((field) -> edge.addPropertyLocal(field.getKey(), field.getValue())); 131 | return edge; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/ElasticClientFactory.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.elasticsearch.client.Client; 5 | import org.elasticsearch.client.transport.TransportClient; 6 | import org.elasticsearch.common.settings.*; 7 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 8 | import org.elasticsearch.node.*; 9 | 10 | public class ElasticClientFactory { 11 | 12 | public static class ClientType { 13 | public static String TRANSPORT_CLIENT = "TRANSPORT_CLIENT"; 14 | public static String NODE_CLIENT = "NODE_CLIENT"; 15 | public static String NODE = "NODE"; 16 | } 17 | 18 | public static Client create(Configuration configuration) { 19 | String clientType = configuration.getString("elasticsearch.client", ClientType.NODE); 20 | String clusterName = configuration.getString("elasticsearch.cluster.name", "elasticsearch"); 21 | 22 | if (clientType.equals(ClientType.TRANSPORT_CLIENT)) { 23 | String concatenatedAddresses = configuration.getString("elasticsearch.cluster.address", "127.0.0.1:9300"); 24 | String[] addresses = concatenatedAddresses.split(","); 25 | InetSocketTransportAddress[] inetSocketTransportAddresses = new InetSocketTransportAddress[addresses.length]; 26 | for(int i = 0; i < addresses.length; i++) { 27 | String address = addresses[i]; 28 | String[] split = address.split(":"); 29 | if(split.length != 2) throw new IllegalArgumentException("Address invalid:" + address + ". Should contain ip and port, e.g. 127.0.0.1:9300"); 30 | inetSocketTransportAddresses[i] = new InetSocketTransportAddress(split[0], Integer.parseInt(split[1])); 31 | } 32 | return createTransportClient(clusterName, inetSocketTransportAddresses); 33 | } 34 | else{ 35 | String port = configuration.getString("elasticsearch.cluster.port", "9300"); 36 | return createNode(clusterName, clientType.equals(ClientType.NODE_CLIENT), Integer.parseInt(port)).client(); 37 | } 38 | } 39 | 40 | public static TransportClient createTransportClient(String clusterName, InetSocketTransportAddress... addresses) { 41 | Settings settings = ImmutableSettings.settingsBuilder() 42 | .put("cluster.name", clusterName) 43 | .put("client.transport.sniff", true).build(); 44 | TransportClient transportClient = new TransportClient(settings).addTransportAddresses(addresses); 45 | return transportClient; 46 | } 47 | 48 | public static Node createNode(String clusterName, boolean client, int port) { 49 | Settings settings = NodeBuilder.nodeBuilder().settings() 50 | .put("script.groovy.sandbox.enabled", true) 51 | .put("script.disable_dynamic", false) 52 | .put("transport.tcp.port", port).build(); 53 | Node node = NodeBuilder.nodeBuilder().client(client).data(!client).clusterName(clusterName).settings(settings).build(); 54 | node.start(); 55 | return node; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/ElasticHelper.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.apache.tinkerpop.gremlin.process.traversal.*; 4 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 5 | import org.elasticgremlin.queryhandler.elasticsearch.Geo; 6 | import org.elasticsearch.action.admin.cluster.health.*; 7 | import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; 8 | import org.elasticsearch.action.admin.indices.exists.indices.*; 9 | import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse; 10 | import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; 11 | import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse; 12 | import org.elasticsearch.client.Client; 13 | import org.elasticsearch.common.geo.builders.ShapeBuilder; 14 | import org.elasticsearch.common.settings.*; 15 | import org.elasticsearch.common.unit.TimeValue; 16 | import org.elasticsearch.common.xcontent.XContentParser; 17 | import org.elasticsearch.common.xcontent.json.JsonXContent; 18 | import org.elasticsearch.index.query.*; 19 | 20 | import java.io.IOException; 21 | import java.util.*; 22 | import java.util.function.BiPredicate; 23 | 24 | public class ElasticHelper { 25 | 26 | public static void createIndex(String indexName, Client client) throws IOException { 27 | IndicesExistsRequest request = new IndicesExistsRequest(indexName); 28 | IndicesExistsResponse response = client.admin().indices().exists(request).actionGet(); 29 | if (!response.isExists()) { 30 | Settings settings = ImmutableSettings.settingsBuilder().put("index.analysis.analyzer.default.type", "keyword").build(); 31 | CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName).setSettings(settings); 32 | client.admin().indices().create(createIndexRequestBuilder.request()).actionGet(); 33 | } 34 | 35 | final ClusterHealthRequest clusterHealthRequest = new ClusterHealthRequest(indexName).timeout(TimeValue.timeValueSeconds(10)).waitForYellowStatus(); 36 | final ClusterHealthResponse clusterHealth = client.admin().cluster().health(clusterHealthRequest).actionGet(); 37 | if (clusterHealth.isTimedOut()) { 38 | throw new IOException(clusterHealth.getStatus() + 39 | " status returned from cluster '" + client.admin().cluster().toString() + 40 | "', index '" + indexName + "'"); 41 | 42 | } 43 | } 44 | 45 | public static DeleteByQueryResponse clearIndex(Client client, String indexName){ 46 | DeleteByQueryResponse indexDeleteByQueryResponses = client.prepareDeleteByQuery(indexName).setQuery(QueryBuilders.matchAllQuery()).execute().actionGet(); 47 | 48 | GetMappingsResponse getMappingsResponse = client.admin().indices().prepareGetMappings(indexName).execute().actionGet(); 49 | ArrayList mappings = new ArrayList(); 50 | getMappingsResponse.getMappings().forEach(map -> { 51 | map.value.forEach(map2 -> mappings.add(map2.value.type())); 52 | }); 53 | 54 | if(mappings.size() > 0) { 55 | DeleteMappingResponse deleteMappingResponse = client.admin().indices().prepareDeleteMapping(indexName).setType(mappings.toArray(new String[mappings.size()])).execute().actionGet(); 56 | } 57 | 58 | return indexDeleteByQueryResponses; 59 | } 60 | 61 | public static BoolFilterBuilder createFilterBuilder(List hasContainers) { 62 | BoolFilterBuilder boolFilter = FilterBuilders.boolFilter(); 63 | if(hasContainers != null) hasContainers.forEach(has -> addFilter(boolFilter, has)); 64 | return boolFilter; 65 | } 66 | 67 | private static void addFilter(BoolFilterBuilder boolFilterBuilder, HasContainer has){ 68 | String key = has.getKey(); 69 | Object value = has.getValue(); 70 | BiPredicate predicate = has.getBiPredicate(); 71 | 72 | if(key.equals("~id")) { 73 | IdsFilterBuilder idsFilterBuilder = FilterBuilders.idsFilter(); 74 | if(value.getClass().isArray()) { 75 | for(Object id : (Object[])value) 76 | idsFilterBuilder.addIds(id.toString()); 77 | } 78 | else idsFilterBuilder.addIds(value.toString()); 79 | boolFilterBuilder.must(idsFilterBuilder); 80 | } 81 | else if(key.equals("~label")) { 82 | if(value instanceof List){ 83 | List labels = (List) value; 84 | if(labels.size() == 1) 85 | boolFilterBuilder.must(FilterBuilders.typeFilter(labels.get(0).toString())); 86 | else { 87 | FilterBuilder[] filters = new FilterBuilder[labels.size()]; 88 | for(int i = 0; i < labels.size(); i++) 89 | filters[i] = FilterBuilders.typeFilter(labels.get(i).toString()); 90 | boolFilterBuilder.must(FilterBuilders.orFilter(filters)); 91 | } 92 | } 93 | else boolFilterBuilder.must(FilterBuilders.typeFilter(value.toString())); 94 | } 95 | else if (predicate instanceof Compare) { 96 | String predicateString = predicate.toString(); 97 | switch (predicateString) { 98 | case ("eq"): 99 | boolFilterBuilder.must(FilterBuilders.termFilter(key, value)); 100 | break; 101 | case ("neq"): 102 | boolFilterBuilder.mustNot(FilterBuilders.termFilter(key, value)); 103 | break; 104 | case ("gt"): 105 | boolFilterBuilder.must(FilterBuilders.rangeFilter(key).gt(value)); 106 | break; 107 | case ("gte"): 108 | boolFilterBuilder.must(FilterBuilders.rangeFilter(key).gte(value)); 109 | break; 110 | case ("lt"): 111 | boolFilterBuilder.must(FilterBuilders.rangeFilter(key).lt(value)); 112 | break; 113 | case ("lte"): 114 | boolFilterBuilder.must(FilterBuilders.rangeFilter(key).lte(value)); 115 | break; 116 | case("inside"): 117 | List items =(List) value; 118 | Object firstItem = items.get(0); 119 | Object secondItem = items.get(1); 120 | boolFilterBuilder.must(FilterBuilders.rangeFilter(key).from(firstItem).to(secondItem)); 121 | break; 122 | default: 123 | throw new IllegalArgumentException("predicate not supported in has step: " + predicate.toString()); 124 | } 125 | } else if (predicate instanceof Contains) { 126 | if (predicate == Contains.without) boolFilterBuilder.must(FilterBuilders.missingFilter(key)); 127 | else if (predicate == Contains.within){ 128 | if(value == null) boolFilterBuilder.must(FilterBuilders.existsFilter(key)); 129 | else boolFilterBuilder.must(FilterBuilders.termsFilter (key, value)); 130 | } 131 | } else if (predicate instanceof Geo) boolFilterBuilder.must(new GeoShapeFilterBuilder(key, GetShapeBuilder(value), ((Geo) predicate).getRelation())); 132 | else throw new IllegalArgumentException("predicate not supported by elastic-gremlin: " + predicate.toString()); 133 | } 134 | 135 | private static ShapeBuilder GetShapeBuilder(Object object) { 136 | try { 137 | String geoJson = (String) object; 138 | XContentParser parser = JsonXContent.jsonXContent.createParser(geoJson); 139 | parser.nextToken(); 140 | 141 | return ShapeBuilder.parse(parser); 142 | } catch (Exception e) { 143 | return null; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/ElasticMutations.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.Element; 4 | import org.elasticgremlin.structure.BaseElement; 5 | import org.elasticsearch.action.bulk.BulkRequestBuilder; 6 | import org.elasticsearch.action.delete.DeleteRequestBuilder; 7 | import org.elasticsearch.action.index.IndexRequestBuilder; 8 | import org.elasticsearch.action.update.UpdateRequest; 9 | import org.elasticsearch.client.Client; 10 | 11 | import java.util.*; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | public class ElasticMutations { 15 | 16 | private final TimingAccessor timing; 17 | private Client client; 18 | private BulkRequestBuilder bulkRequest; 19 | private int revision = 0; 20 | 21 | public ElasticMutations(Boolean bulk, Client client, TimingAccessor timing) { 22 | if(bulk) bulkRequest = client.prepareBulk(); 23 | this.timing = timing; 24 | this.client = client; 25 | } 26 | 27 | public void addElement(Element element, String index, String routing, boolean create) { 28 | IndexRequestBuilder indexRequest = client.prepareIndex(index, element.label(), element.id().toString()) 29 | .setSource(propertiesMap(element)).setRouting(routing).setCreate(create); 30 | if(bulkRequest != null) bulkRequest.add(indexRequest); 31 | else indexRequest.execute().actionGet(); 32 | revision++; 33 | } 34 | 35 | private Map propertiesMap(Element element) { 36 | if(element instanceof BaseElement) 37 | return ((BaseElement)element).allFields(); 38 | 39 | Map map = new HashMap<>(); 40 | element.properties().forEachRemaining(property -> map.put(property.key(), property.value())); 41 | return map; 42 | } 43 | 44 | public void updateElement(Element element, String index, String routing, boolean upsert) throws ExecutionException, InterruptedException { 45 | UpdateRequest updateRequest = new UpdateRequest(index, element.label(), element.id().toString()) 46 | .doc(propertiesMap(element)).routing(routing); 47 | if(upsert) 48 | updateRequest.detectNoop(true).docAsUpsert(true); 49 | if(bulkRequest != null) bulkRequest.add(updateRequest); 50 | else client.update(updateRequest).actionGet(); 51 | revision++; 52 | } 53 | 54 | 55 | public void deleteElement(Element element, String index, String routing) { 56 | DeleteRequestBuilder deleteRequestBuilder = client.prepareDelete(index, element.label(), element.id().toString()).setRouting(routing); 57 | if(bulkRequest != null) bulkRequest.add(deleteRequestBuilder); 58 | else deleteRequestBuilder.execute().actionGet(); 59 | revision++; 60 | } 61 | 62 | public void commit() { 63 | if (bulkRequest == null) return; 64 | timing.start("bulk"); 65 | bulkRequest.execute().actionGet(); 66 | timing.stop("bulk"); 67 | } 68 | 69 | public int getRevision() { 70 | return revision; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/LazyGetter.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.elasticgremlin.structure.BaseVertex; 4 | import org.elasticsearch.action.get.*; 5 | import org.elasticsearch.client.Client; 6 | 7 | import java.util.*; 8 | 9 | public class LazyGetter { 10 | 11 | private static final int MAX_LAZY_GET = 1000; 12 | private Client client; 13 | private TimingAccessor timing; 14 | private boolean executed = false; 15 | private MultiGetRequest multiGetRequest = new MultiGetRequest(); 16 | private HashMap> idToVertices = new HashMap(); 17 | private List vertices = new ArrayList<>(); 18 | 19 | public LazyGetter(Client client, TimingAccessor timing) { 20 | this.client = client; 21 | this.timing = timing; 22 | } 23 | 24 | public Boolean canRegister() { 25 | return !executed && multiGetRequest.getItems().size() < MAX_LAZY_GET; 26 | } 27 | 28 | public void register(BaseVertex v, String indexName) { 29 | multiGetRequest.add(indexName, null, v.id().toString()); //TODO: add routing..? 30 | 31 | List vertices = idToVertices.get(v.id().toString()); 32 | if (vertices == null) { 33 | vertices = new ArrayList(); 34 | idToVertices.put(v.id().toString(), vertices); 35 | } 36 | vertices.add(v); 37 | 38 | this.vertices.add(v); 39 | v.setSiblings(this.vertices); 40 | } 41 | 42 | public void execute() { 43 | if (executed) return; 44 | 45 | timing.start("lazyMultiGet"); 46 | MultiGetResponse multiGetItemResponses = client.multiGet(multiGetRequest).actionGet(); 47 | timing.stop("lazyMultiGet"); 48 | 49 | multiGetItemResponses.forEach(response -> { 50 | if (response.isFailed() || !response.getResponse().isExists()) { 51 | System.out.println(response.getFailure().getMessage()); 52 | return; 53 | } 54 | List vertices = idToVertices.get(response.getId()); 55 | if (vertices == null) return; 56 | vertices.forEach(vertex -> vertex.applyLazyFields(response)); 57 | }); 58 | 59 | executed = true; 60 | multiGetRequest = null; 61 | idToVertices = null; 62 | client = null; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/QueryIterator.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.elasticsearch.action.search.SearchResponse; 5 | import org.elasticsearch.client.Client; 6 | import org.elasticsearch.common.unit.TimeValue; 7 | import org.elasticsearch.index.query.*; 8 | import org.elasticsearch.search.SearchHit; 9 | 10 | import java.util.*; 11 | import java.util.function.Function; 12 | 13 | public class QueryIterator implements Iterator { 14 | 15 | private SearchResponse scrollResponse; 16 | private long allowedRemaining; 17 | private final Function, Iterator> convertFunc; 18 | private TimingAccessor timing; 19 | private Client client; 20 | private Iterator hits; 21 | 22 | public QueryIterator(FilterBuilder filter, int startFrom, int scrollSize, long maxSize, Client client, 23 | Function, Iterator> convertFunc, 24 | Boolean refresh, TimingAccessor timing, String... indices) { 25 | this.client = client; 26 | this.allowedRemaining = maxSize; 27 | this.convertFunc = convertFunc; 28 | this.timing = timing; 29 | 30 | if (refresh) client.admin().indices().prepareRefresh(indices).execute().actionGet(); 31 | this.timing.start("scroll"); 32 | scrollResponse = client.prepareSearch(indices) 33 | .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), filter)) 34 | .setFrom(startFrom) 35 | .setScroll(new TimeValue(60000)) 36 | .setSize(maxSize < scrollSize ? (int) maxSize : scrollSize) 37 | .execute().actionGet(); 38 | this.timing.stop("scroll"); 39 | 40 | hits = convertFunc.apply(scrollResponse.getHits().iterator()); 41 | } 42 | 43 | @Override 44 | public boolean hasNext() { 45 | if(allowedRemaining <= 0) return false; 46 | if(hits.hasNext()) return true; 47 | 48 | timing.start("scroll"); 49 | scrollResponse = client.prepareSearchScroll(scrollResponse.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet(); 50 | timing.stop("scroll"); 51 | 52 | hits = convertFunc.apply(scrollResponse.getHits().iterator()); 53 | 54 | return hits.hasNext(); 55 | } 56 | 57 | @Override 58 | public E next() { 59 | allowedRemaining--; 60 | return hits.next(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/helpers/TimingAccessor.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.helpers; 2 | 3 | import org.apache.commons.lang3.time.StopWatch; 4 | 5 | import java.text.DecimalFormat; 6 | import java.util.HashMap; 7 | 8 | public class TimingAccessor { 9 | 10 | private HashMap timers = new HashMap<>(); 11 | static DecimalFormat twoDForm = new DecimalFormat("#.##"); 12 | 13 | public Timer timer(String name) { 14 | if (timers.containsKey(name)) return timers.get(name); 15 | Timer timer = new Timer(name); 16 | timers.put(name, timer); 17 | return timer; 18 | } 19 | 20 | public void start(String name) { 21 | timer(name).start(); 22 | } 23 | 24 | 25 | public void stop(String name) { 26 | timer(name).stop(); 27 | } 28 | 29 | public void print() { 30 | timers.values().forEach((timer) -> timer.PrintStats()); 31 | } 32 | 33 | public class Timer { 34 | 35 | private String name; 36 | StopWatch sw = new StopWatch(); 37 | float numOfRuns = 0; 38 | float longestRun = 0; 39 | private long lastRun = 0; 40 | 41 | public Timer(String name) { 42 | this.name = name; 43 | sw.reset(); 44 | } 45 | 46 | public void start() { 47 | if(!sw.isStarted()) { 48 | sw.start(); 49 | return; 50 | } 51 | if(!sw.isSuspended()) stop(); 52 | sw.resume(); 53 | } 54 | 55 | public void stop() { 56 | sw.suspend(); 57 | long time = sw.getTime() - lastRun; 58 | if (time > longestRun) longestRun = time; 59 | lastRun = time; 60 | numOfRuns++; 61 | } 62 | 63 | public void PrintStats() { 64 | if (numOfRuns > 0) { 65 | float time = sw.getTime() / 1000f; 66 | 67 | System.out.println(name + ": " + twoDForm.format(time) + " total secs, " + twoDForm.format(time / numOfRuns) + " secs per run, " + numOfRuns + " runs, " + twoDForm.format(longestRun / 1000f) + " sec for longest run"); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/stardoc/BasicEdgeMapping.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.stardoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.Direction; 4 | 5 | import java.lang.Object;import java.lang.Override;import java.lang.String;import java.util.Map; 6 | 7 | public class BasicEdgeMapping implements EdgeMapping { 8 | private final String edgeLabel; 9 | private final String externalVertexLabel; 10 | private final Direction direction; 11 | private final String externalVertexField; 12 | 13 | public BasicEdgeMapping(String edgeLabel, String externalVertexLabel, Direction direction, String externalVertexField) { 14 | this.edgeLabel = edgeLabel; 15 | this.externalVertexLabel = externalVertexLabel; 16 | this.direction = direction; 17 | this.externalVertexField = externalVertexField; 18 | } 19 | 20 | @Override 21 | public String getExternalVertexField() { 22 | return externalVertexField; 23 | } 24 | 25 | @Override 26 | public Direction getDirection() { 27 | return direction; 28 | } 29 | 30 | @Override 31 | public Object[] getProperties(Map entries) { 32 | return new Object[0]; 33 | } 34 | 35 | @Override 36 | public String getLabel() { 37 | return edgeLabel; 38 | } 39 | 40 | @Override 41 | public String getExternalVertexLabel() { 42 | return externalVertexLabel; 43 | } 44 | 45 | @Override 46 | public Object getExternalVertexId(Map entries) { 47 | return entries.get(externalVertexField); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/stardoc/EdgeMapping.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.stardoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.Direction; 4 | import java.util.Map; 5 | 6 | public interface EdgeMapping { 7 | 8 | public String getExternalVertexField(); 9 | 10 | public Direction getDirection(); 11 | 12 | public Object[] getProperties(Map entries); 13 | 14 | public String getLabel() ; 15 | 16 | public String getExternalVertexLabel() ; 17 | 18 | public Object getExternalVertexId(Map entries); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/stardoc/InnerEdge.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.stardoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.apache.tinkerpop.gremlin.structure.util.StringFactory; 5 | import org.elasticgremlin.structure.*; 6 | import sun.reflect.generics.reflectiveObjects.NotImplementedException; 7 | 8 | public class InnerEdge extends BaseEdge { 9 | 10 | private final EdgeMapping mapping; 11 | 12 | public InnerEdge(Object edgeId, EdgeMapping mapping, Vertex outVertex, Vertex inVertex, Object[] keyValues, ElasticGraph graph) { 13 | super(edgeId, mapping.getLabel(), keyValues, outVertex, inVertex, graph); 14 | this.mapping = mapping; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return StringFactory.edgeString(this); 20 | } 21 | 22 | @Override 23 | protected void innerRemoveProperty(Property property) { 24 | throw new NotImplementedException(); 25 | } 26 | 27 | @Override 28 | protected void innerRemove() { 29 | throw new NotImplementedException(); 30 | } 31 | 32 | @Override 33 | protected void innerAddProperty(BaseProperty vertexProperty) { 34 | throw new NotImplementedException(); 35 | } 36 | 37 | public EdgeMapping getMapping() { 38 | return mapping; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/stardoc/StarHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.stardoc; 2 | 3 | import org.apache.tinkerpop.gremlin.process.traversal.P; 4 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 5 | import org.apache.tinkerpop.gremlin.structure.*; 6 | import org.elasticgremlin.queryhandler.*; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 8 | import org.elasticgremlin.structure.*; 9 | import org.elasticsearch.client.Client; 10 | import org.elasticsearch.index.engine.DocumentAlreadyExistsException; 11 | import org.elasticsearch.index.query.*; 12 | import org.elasticsearch.search.SearchHit; 13 | 14 | import java.util.*; 15 | 16 | public class StarHandler implements VertexHandler, EdgeHandler { 17 | 18 | private ElasticGraph graph; 19 | private Client client; 20 | private ElasticMutations elasticMutations; 21 | private final int scrollSize; 22 | private final boolean refresh; 23 | private TimingAccessor timing; 24 | private EdgeMapping[] edgeMappings; 25 | private Map lazyGetters; 26 | private LazyGetter defaultLazyGetter; 27 | 28 | protected String[] indices; 29 | 30 | public StarHandler(ElasticGraph graph, Client client, ElasticMutations elasticMutations, String indexName, 31 | int scrollSize, boolean refresh, TimingAccessor timing, EdgeMapping... edgeMappings) { 32 | this(graph, client, elasticMutations, new String[] {indexName}, scrollSize, refresh, timing, edgeMappings); 33 | } 34 | 35 | public StarHandler(ElasticGraph graph, Client client, ElasticMutations elasticMutations, String[] indices, 36 | int scrollSize, boolean refresh, TimingAccessor timing, EdgeMapping... edgeMappings) { 37 | this.graph = graph; 38 | this.client = client; 39 | this.elasticMutations = elasticMutations; 40 | this.indices = indices; 41 | this.scrollSize = scrollSize; 42 | this.refresh = refresh; 43 | this.timing = timing; 44 | this.edgeMappings = edgeMappings; 45 | this.lazyGetters = new HashMap<>(); 46 | } 47 | 48 | @Override 49 | public Iterator vertices() { 50 | Predicates predicates = new Predicates(); 51 | return vertices(predicates); 52 | } 53 | 54 | @Override 55 | public Iterator vertices(Object[] vertexIds) { 56 | List vertices = new ArrayList<>(); 57 | for (Object id : vertexIds) { 58 | StarVertex vertex = new StarVertex(id, null, null, graph, getLazyGetter(), elasticMutations, getDefaultIndex(), edgeMappings); 59 | vertex.setSiblings(vertices); 60 | vertices.add(vertex); 61 | } 62 | return vertices.iterator(); 63 | } 64 | 65 | @Override 66 | public Iterator vertices(Predicates predicates) { 67 | BoolFilterBuilder boolFilter = ElasticHelper.createFilterBuilder(predicates.hasContainers); 68 | return new QueryIterator<>(boolFilter, 0, scrollSize, predicates.limitHigh - predicates.limitLow, 69 | client, this::createVertex, refresh, timing, indices); 70 | } 71 | 72 | 73 | 74 | @Override 75 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction) { 76 | return new StarVertex(vertexId, vertexLabel, null, graph, getLazyGetter(direction), elasticMutations, getDefaultIndex(), edgeMappings); 77 | } 78 | 79 | @Override 80 | public BaseVertex addVertex(Object id, String label, Object[] properties) { 81 | String index = getIndex(properties); 82 | BaseVertex v = new StarVertex(id, label, properties, graph, null, elasticMutations, index, edgeMappings); 83 | 84 | try { 85 | elasticMutations.addElement(v, index, null, true); 86 | } catch (DocumentAlreadyExistsException ex) { 87 | throw Graph.Exceptions.vertexWithIdAlreadyExists(id); 88 | } 89 | return v; 90 | } 91 | 92 | @Override 93 | public Iterator edges() { 94 | return edges(new Predicates()); 95 | } 96 | 97 | @Override 98 | public Iterator edges(Object[] edgeIds) { 99 | Predicates predicates = new Predicates(); 100 | predicates.hasContainers.add(new HasContainer(T.id.getAccessor(), P.within(edgeIds))); 101 | return edges(predicates); 102 | } 103 | 104 | @Override 105 | public Iterator edges(Predicates predicates) { 106 | Iterator vertices = vertices(); 107 | List edges = new ArrayList<>(); 108 | vertices.forEachRemaining(vertex -> { 109 | ((BaseVertex)vertex).edges(Direction.IN, new String[0], predicates).forEachRemaining(edges::add); 110 | ((BaseVertex)vertex).edges(Direction.OUT, new String[0], predicates).forEachRemaining(edges::add); 111 | ((BaseVertex)vertex).edges(Direction.BOTH, new String[0], predicates).forEachRemaining(edges::add); 112 | }); 113 | 114 | return edges.iterator(); 115 | } 116 | 117 | @Override 118 | public Map> edges(Iterator vertices, Direction direction, String[] edgeLabels, Predicates predicates) { 119 | List vertexIds = new ArrayList<>(); 120 | vertices.forEachRemaining(singleVertex -> vertexIds.add(singleVertex.id())); 121 | 122 | BoolFilterBuilder boolFilter = ElasticHelper.createFilterBuilder(predicates.hasContainers); 123 | OrFilterBuilder mappingFilter = FilterBuilders.orFilter(); 124 | boolean empty = true; 125 | for (EdgeMapping mapping : edgeMappings) { 126 | if (edgeLabels != null && edgeLabels.length > 0 && !contains(edgeLabels, mapping.getLabel())) continue; 127 | mappingFilter.add(FilterBuilders.termsFilter(mapping.getExternalVertexField(), vertexIds.toArray())); 128 | empty = false; 129 | } 130 | if (!empty) { 131 | boolFilter.must(mappingFilter); 132 | } 133 | 134 | QueryIterator vertexSearchQuery = new QueryIterator<>(boolFilter, 0, scrollSize, 135 | predicates.limitHigh - predicates.limitLow, client, this::createVertex, refresh, timing, indices); 136 | 137 | 138 | Map> results = new HashMap<>(); 139 | vertexSearchQuery.forEachRemaining(otherVertex -> 140 | otherVertex.edges(direction, edgeLabels).forEachRemaining(edge -> { 141 | Vertex vertex = BaseVertex.vertexToVertex(otherVertex, edge, direction); 142 | Set resultEdges = results.get(vertex.id()); 143 | if (resultEdges == null) { 144 | resultEdges = new HashSet<>(); 145 | results.put(vertex.id(), resultEdges); 146 | } 147 | resultEdges.add(edge); 148 | })); 149 | 150 | return results; 151 | } 152 | 153 | public static boolean contains(String[] edgeLabels, String label) { 154 | for (String edgeLabel : edgeLabels) 155 | if (edgeLabel.equals(label)) return true; 156 | return false; 157 | } 158 | 159 | @Override 160 | public Edge addEdge(Object edgeId, String label, Vertex outV, Vertex inV, Object[] properties) { 161 | boolean out = shouldContainEdge(outV, Direction.OUT, label, properties); 162 | boolean in = shouldContainEdge(inV, Direction.IN, label, properties); 163 | StarVertex containerVertex; 164 | Vertex otherVertex; 165 | if (out) { 166 | containerVertex = (StarVertex) outV; 167 | otherVertex = inV; 168 | } 169 | else if (in) { 170 | containerVertex = (StarVertex) inV; 171 | otherVertex = outV; 172 | } 173 | else { 174 | // 175 | // () 176 | throw new UnsupportedOperationException("Neither the in nor the out vertices can contain the edge. Either their mapping is incompatible or they are not of type StarVertex"); 177 | } 178 | 179 | List keyValues = new ArrayList<>(); 180 | containerVertex.properties().forEachRemaining(property -> { 181 | keyValues.add(property.key()); 182 | keyValues.add(property.value()); 183 | }); 184 | 185 | EdgeMapping mapping = getEdgeMapping(label, out ? Direction.OUT : Direction.IN); 186 | containerVertex.addInnerEdge(mapping, edgeId, label, otherVertex, keyValues.toArray()); 187 | 188 | Predicates predicates = new Predicates(); 189 | predicates.hasContainers.add(new HasContainer(T.id.getAccessor(), P.within(edgeId))); 190 | return containerVertex.edges(mapping.getDirection(), new String[]{label}, predicates).next(); 191 | } 192 | 193 | private EdgeMapping getEdgeMapping(String label, Direction direction) { 194 | for (EdgeMapping mapping : edgeMappings) { 195 | if (mapping.getLabel().equals(label) && mapping.getDirection().equals(direction)) { 196 | return mapping; 197 | } 198 | } 199 | return null; 200 | } 201 | 202 | private boolean shouldContainEdge(Vertex vertex, Direction direction, String edgeLabel, Object[] edgeProperties) { 203 | if (!StarVertex.class.isAssignableFrom(vertex.getClass())) { 204 | return false; 205 | } 206 | StarVertex starVertex = (StarVertex) vertex; 207 | EdgeMapping[] mappings = starVertex.getEdgeMappings(); 208 | for (int i = 0; i < mappings.length; i++) { 209 | EdgeMapping mapping = mappings[i]; 210 | // TODO: Check option of implementing EdgeMapping.equals method 211 | if (i >= edgeMappings.length || !equals(mapping, edgeMappings[i])) { 212 | return false; 213 | } 214 | if (mapping.getDirection().equals(direction) && mapping.getLabel().equals(edgeLabel)) { 215 | return true; 216 | } 217 | } 218 | return false; 219 | } 220 | 221 | protected String getDefaultIndex() { 222 | return this.indices[0]; 223 | } 224 | 225 | protected String getIndex(Object[] properties) { 226 | return getDefaultIndex(); 227 | } 228 | 229 | private LazyGetter getLazyGetter() { 230 | if (defaultLazyGetter == null || !defaultLazyGetter.canRegister()) { 231 | defaultLazyGetter = new LazyGetter(client, timing); 232 | } 233 | return defaultLazyGetter; 234 | } 235 | 236 | private LazyGetter getLazyGetter(Direction direction) { 237 | LazyGetter lazyGetter = lazyGetters.get(direction); 238 | if (lazyGetter == null || !lazyGetter.canRegister()) { 239 | lazyGetter = new LazyGetter(client, timing); 240 | lazyGetters.put(direction, 241 | lazyGetter); 242 | } 243 | return lazyGetter; 244 | } 245 | 246 | private Iterator createVertex(Iterator hits) { 247 | ArrayList vertices = new ArrayList<>(); 248 | hits.forEachRemaining(hit -> { 249 | StarVertex vertex = new StarVertex(hit.id(), hit.getType(), null, graph, null, elasticMutations, hit.getIndex(), edgeMappings); 250 | vertex.setFields(hit.getSource()); 251 | vertex.setSiblings(vertices); 252 | vertices.add(vertex); 253 | }); 254 | return vertices.iterator(); 255 | } 256 | 257 | private boolean equals(EdgeMapping mapping, EdgeMapping otherMapping) { 258 | return mapping.getDirection().equals(otherMapping.getDirection()) && 259 | mapping.getLabel().equals(otherMapping.getLabel()) && 260 | mapping.getExternalVertexField().equals(otherMapping.getExternalVertexField()) && 261 | mapping.getExternalVertexLabel().equals(otherMapping.getExternalVertexLabel()); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/stardoc/StarVertex.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.stardoc; 2 | 3 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 4 | import org.apache.tinkerpop.gremlin.structure.*; 5 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 6 | import org.elasticgremlin.queryhandler.Predicates; 7 | import org.elasticgremlin.structure.*; 8 | import org.elasticsearch.action.get.GetResponse; 9 | import org.elasticsearch.action.get.MultiGetItemResponse; 10 | 11 | import java.util.*; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | public class StarVertex extends BaseVertex { 15 | private final ElasticMutations elasticMutations; 16 | private final String indexName; 17 | private final EdgeMapping[] edgeMappings; 18 | private LazyGetter lazyGetter; 19 | private Set innerEdges; 20 | 21 | public StarVertex(final Object id, final String label, Object[] keyValues, ElasticGraph graph, LazyGetter lazyGetter, ElasticMutations elasticMutations, String indexName, EdgeMapping[] edgeMappings) { 22 | super(id, label, graph, keyValues, elasticMutations); 23 | this.elasticMutations = elasticMutations; 24 | this.indexName = indexName; 25 | this.edgeMappings = edgeMappings; 26 | innerEdges = new HashSet<>(); 27 | if(lazyGetter != null) { 28 | this.lazyGetter = lazyGetter; 29 | lazyGetter.register(this, this.indexName); 30 | } 31 | } 32 | 33 | @Override 34 | public String label() { 35 | if(this.label == null && lazyGetter != null) lazyGetter.execute(); 36 | return super.label(); 37 | } 38 | 39 | @Override 40 | protected void innerAddProperty(BaseVertexProperty vertexProperty) { 41 | try { 42 | elasticMutations.updateElement(this, indexName, null, false); 43 | } catch (ExecutionException | InterruptedException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | @Override 49 | public VertexProperty property(final String key) { 50 | if(lazyGetter != null) lazyGetter.execute(); 51 | return super.property(key); 52 | } 53 | 54 | @Override 55 | protected void innerRemoveProperty(Property property) { 56 | try { 57 | elasticMutations.updateElement(this, indexName, null, false); 58 | } catch (ExecutionException | InterruptedException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | @Override 64 | protected void innerRemove() { 65 | elasticMutations.deleteElement(this, indexName, null); 66 | } 67 | 68 | @Override 69 | public Iterator> properties(final String... propertyKeys) { 70 | if(lazyGetter != null) lazyGetter.execute(); 71 | return super.properties(propertyKeys); 72 | } 73 | 74 | @Override 75 | public void applyLazyFields(MultiGetItemResponse response) { 76 | GetResponse getResponse = response.getResponse(); 77 | if(getResponse.isSourceEmpty()) return; 78 | setFields(getResponse.getSource()); 79 | } 80 | 81 | @Override 82 | public Iterator edges(Direction direction, String[] edgeLabels, Predicates predicates) { 83 | ArrayList edges = new ArrayList<>(); 84 | innerEdges.forEach(edge -> { 85 | EdgeMapping mapping = edge.getMapping(); 86 | if(mapping.getDirection().equals(direction) && 87 | (edgeLabels.length == 0 || StarHandler.contains(edgeLabels, mapping.getLabel()))) { 88 | 89 | // Test predicates on inner edge 90 | boolean passed = true; 91 | for (HasContainer hasContainer : predicates.hasContainers) { 92 | if (!hasContainer.test(edge)) { 93 | passed = false; 94 | } 95 | } 96 | if (passed) { 97 | edges.add(edge); 98 | } 99 | } 100 | }); 101 | 102 | if(edges.size() > 0) return edges.iterator(); 103 | 104 | ArrayList externalEdgeLabels = new ArrayList<>(); 105 | for (String label : edgeLabels) { 106 | boolean internal = false; 107 | for (EdgeMapping mapping : edgeMappings) { 108 | if (label.equals(mapping.getLabel())) { 109 | // This label is internal 110 | internal = true; 111 | } 112 | } 113 | if (!internal) { 114 | externalEdgeLabels.add(label); 115 | } 116 | } 117 | if (!externalEdgeLabels.isEmpty()) 118 | return super.edges(direction, externalEdgeLabels.toArray(new String[externalEdgeLabels.size()]), predicates); 119 | 120 | else return new ArrayList(0).iterator(); 121 | } 122 | 123 | public void setFields(Map entries){ 124 | entries.entrySet().forEach(field -> { 125 | if(field.getValue() != null) addPropertyLocal(field.getKey(), field.getValue()); 126 | }); 127 | 128 | } 129 | 130 | public InnerEdge addInnerEdge(EdgeMapping mapping, Object edgeId, String label, Vertex externalVertex, 131 | Object[] properties) { 132 | boolean mappingExists = false; 133 | for (EdgeMapping edgeMapping : edgeMappings) { 134 | if (mapping.equals(edgeMapping)) { 135 | mappingExists = true; 136 | } 137 | } 138 | if (!mappingExists) { 139 | return null; 140 | } 141 | 142 | property(mapping.getExternalVertexField(), externalVertex.id()); 143 | Vertex inVertex = mapping.getDirection().equals(Direction.IN) ? this : externalVertex; 144 | Vertex outVertex = mapping.getDirection().equals(Direction.OUT) ? this : externalVertex; 145 | InnerEdge edge = new InnerEdge(edgeId, mapping, outVertex, inVertex, properties, graph); 146 | this.innerEdges.add(edge); 147 | return edge; 148 | } 149 | 150 | public EdgeMapping[] getEdgeMappings() { 151 | return edgeMappings; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/vertexdoc/DocVertex.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.vertexdoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 5 | import org.elasticgremlin.structure.*; 6 | 7 | import java.util.*; 8 | import java.util.concurrent.ExecutionException; 9 | 10 | public class DocVertex extends BaseVertex { 11 | private final ElasticMutations elasticMutations; 12 | private final String indexName; 13 | private LazyGetter lazyGetter; 14 | 15 | public DocVertex(final Object id, final String label, Object[] keyValues, ElasticGraph graph, LazyGetter lazyGetter, ElasticMutations elasticMutations, String indexName) { 16 | super(id, label, graph, keyValues, elasticMutations); 17 | this.elasticMutations = elasticMutations; 18 | this.indexName = indexName; 19 | if (lazyGetter != null) { 20 | this.lazyGetter = lazyGetter; 21 | lazyGetter.register(this, this.indexName); 22 | } 23 | } 24 | 25 | @Override 26 | public String label() { 27 | if (this.label == null && lazyGetter != null) lazyGetter.execute(); 28 | return super.label(); 29 | } 30 | 31 | @Override 32 | protected void innerAddProperty(BaseVertexProperty vertexProperty) { 33 | try { 34 | elasticMutations.updateElement(this, indexName, null, false); 35 | } 36 | catch (ExecutionException | InterruptedException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | @Override 42 | public VertexProperty property(final String key) { 43 | if (lazyGetter != null) lazyGetter.execute(); 44 | return super.property(key); 45 | } 46 | 47 | @Override 48 | protected void innerRemoveProperty(Property property) { 49 | try { 50 | elasticMutations.updateElement(this, indexName, null, false); 51 | } 52 | catch (ExecutionException | InterruptedException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | @Override 58 | protected void innerRemove() { 59 | elasticMutations.deleteElement(this, indexName, null); 60 | } 61 | 62 | @Override 63 | public Iterator> properties(final String... propertyKeys) { 64 | if (lazyGetter != null) lazyGetter.execute(); 65 | return super.properties(propertyKeys); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/elasticsearch/vertexdoc/DocVertexHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.elasticsearch.vertexdoc; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.elasticgremlin.queryhandler.*; 5 | import org.elasticgremlin.queryhandler.elasticsearch.edgedoc.DocEdge; 6 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 7 | import org.elasticgremlin.structure.*; 8 | import org.elasticsearch.client.Client; 9 | import org.elasticsearch.index.engine.DocumentAlreadyExistsException; 10 | import org.elasticsearch.index.query.*; 11 | import org.elasticsearch.search.SearchHit; 12 | 13 | import java.util.*; 14 | 15 | public class DocVertexHandler implements VertexHandler { 16 | 17 | private ElasticGraph graph; 18 | private Client client; 19 | private ElasticMutations elasticMutations; 20 | private String indexName; 21 | private final int scrollSize; 22 | private final boolean refresh; 23 | private TimingAccessor timing; 24 | private Map lazyGetters; 25 | private LazyGetter defaultLazyGetter; 26 | 27 | public DocVertexHandler(ElasticGraph graph, Client client, ElasticMutations elasticMutations, String indexName, 28 | int scrollSize, boolean refresh, TimingAccessor timing) { 29 | this.graph = graph; 30 | this.client = client; 31 | this.elasticMutations = elasticMutations; 32 | this.indexName = indexName; 33 | this.scrollSize = scrollSize; 34 | this.refresh = refresh; 35 | this.timing = timing; 36 | this.lazyGetters = new HashMap<>(); 37 | } 38 | 39 | @Override 40 | public Iterator vertices() { 41 | return new QueryIterator<>(FilterBuilders.missingFilter(DocEdge.InId), 0, scrollSize, 42 | Integer.MAX_VALUE, client, this::createVertex, refresh, timing, indexName); 43 | } 44 | 45 | @Override 46 | public Iterator vertices(Object[] vertexIds) { 47 | List vertices = new ArrayList<>(); 48 | for(Object id : vertexIds){ 49 | DocVertex vertex = new DocVertex(id.toString(), null, null, graph, getLazyGetter(), elasticMutations, indexName); 50 | vertex.setSiblings(vertices); 51 | vertices.add(vertex); 52 | } 53 | return vertices.iterator(); 54 | } 55 | 56 | @Override 57 | public Iterator vertices(Predicates predicates) { 58 | BoolFilterBuilder boolFilter = ElasticHelper.createFilterBuilder(predicates.hasContainers); 59 | boolFilter.must(FilterBuilders.missingFilter(DocEdge.InId)); 60 | return new QueryIterator<>(boolFilter, 0, scrollSize, predicates.limitHigh - predicates.limitLow, 61 | client, this::createVertex, refresh, timing, indexName); 62 | } 63 | 64 | @Override 65 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction) { 66 | return new DocVertex(vertexId,vertexLabel, null ,graph,getLazyGetter(direction), elasticMutations, indexName); 67 | } 68 | 69 | @Override 70 | public BaseVertex addVertex(Object id, String label, Object[] properties) { 71 | BaseVertex v = new DocVertex(id, label, properties, graph, null, elasticMutations, indexName); 72 | 73 | try { 74 | elasticMutations.addElement(v, indexName, null, true); 75 | } catch (DocumentAlreadyExistsException ex) { 76 | throw Graph.Exceptions.vertexWithIdAlreadyExists(id); 77 | } 78 | return v; 79 | } 80 | 81 | private LazyGetter getLazyGetter() { 82 | if (defaultLazyGetter == null || !defaultLazyGetter.canRegister()) { 83 | defaultLazyGetter = new LazyGetter(client, timing); 84 | } 85 | return defaultLazyGetter; 86 | } 87 | 88 | private LazyGetter getLazyGetter(Direction direction) { 89 | LazyGetter lazyGetter = lazyGetters.get(direction); 90 | if (lazyGetter == null || !lazyGetter.canRegister()) { 91 | lazyGetter = new LazyGetter(client, timing); 92 | lazyGetters.put(direction, 93 | lazyGetter); 94 | } 95 | return lazyGetter; 96 | } 97 | 98 | private Iterator createVertex(Iterator hits) { 99 | ArrayList vertices = new ArrayList<>(); 100 | hits.forEachRemaining(hit -> { 101 | BaseVertex vertex = new DocVertex(hit.id(), hit.getType(), null, graph, null, elasticMutations, indexName); 102 | vertex.setSiblings(vertices); 103 | hit.getSource().entrySet().forEach((field) -> vertex.addPropertyLocal(field.getKey(), field.getValue())); 104 | vertices.add(vertex); 105 | }); 106 | return vertices.iterator(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/virtualvertex/VirtualVertex.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.virtualvertex; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.Property; 4 | import org.elasticgremlin.structure.*; 5 | 6 | public class VirtualVertex extends BaseVertex { 7 | protected VirtualVertex(Object id, String label, ElasticGraph graph, Object[] keyValues) { 8 | super(id, label, graph, keyValues, null); 9 | } 10 | 11 | @Override 12 | protected void innerAddProperty(BaseVertexProperty vertexProperty) { 13 | 14 | } 15 | 16 | @Override 17 | protected void innerRemoveProperty(Property property) { 18 | 19 | } 20 | 21 | @Override 22 | protected void innerRemove() { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/queryhandler/virtualvertex/VirtualVertexHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.queryhandler.virtualvertex; 2 | 3 | import com.fasterxml.jackson.databind.util.ArrayIterator; 4 | import org.apache.tinkerpop.gremlin.structure.*; 5 | import org.elasticgremlin.queryhandler.*; 6 | import org.elasticgremlin.structure.*; 7 | 8 | import java.util.*; 9 | 10 | public class VirtualVertexHandler implements VertexHandler { 11 | 12 | private static final long VERTEX_BULK = 1000; 13 | 14 | private ElasticGraph graph; 15 | private String label; 16 | private List vertices; 17 | 18 | public VirtualVertexHandler(ElasticGraph graph, String label) { 19 | this.graph = graph; 20 | this.label = label; 21 | this.vertices = new ArrayList<>(); 22 | } 23 | 24 | @Override 25 | public Iterator vertices() { 26 | throw new UnsupportedOperationException(); 27 | } 28 | 29 | @Override 30 | public Iterator vertices(Object[] vertexIds) { 31 | ArrayList vertices = new ArrayList<>(); 32 | for(Object id : vertexIds) { 33 | BaseVertex vertex = new VirtualVertex(id, label, graph, null); 34 | vertices.add(vertex); 35 | vertex.setSiblings(vertices); 36 | } 37 | return new ArrayIterator<>((Vertex[]) vertices.toArray()).iterator(); 38 | } 39 | 40 | @Override 41 | public Iterator vertices(Predicates predicates) { 42 | throw new UnsupportedOperationException(); 43 | } 44 | 45 | @Override 46 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction) { 47 | checkBulk(); 48 | BaseVertex vertex = new VirtualVertex(vertexId, vertexLabel, graph, null); 49 | vertex.setSiblings(vertices); 50 | vertices.add(vertex); 51 | return vertex; 52 | } 53 | 54 | private void checkBulk() { 55 | if (vertices.size() >= VERTEX_BULK) { 56 | vertices = new ArrayList<>(); 57 | } 58 | } 59 | 60 | @Override 61 | public BaseVertex addVertex(Object id, String label, Object[] properties) { 62 | throw new UnsupportedOperationException(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/BaseEdge.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.apache.tinkerpop.gremlin.structure.util.*; 5 | 6 | import java.util.*; 7 | 8 | public abstract class BaseEdge extends BaseElement implements Edge { 9 | 10 | protected Vertex inVertex; 11 | protected Vertex outVertex; 12 | 13 | public BaseEdge(final Object id, final String label, Object[] keyValues, Vertex outVertex, Vertex inVertex, final ElasticGraph graph) { 14 | super(id, label, graph, keyValues); 15 | this.outVertex = outVertex; 16 | this.inVertex = inVertex; 17 | ElementHelper.validateLabel(label); 18 | } 19 | 20 | @Override 21 | public Property createProperty(String key, Object value) { 22 | return new BaseProperty<>(this, key, value); 23 | } 24 | 25 | @Override 26 | public Property property(String key, V value) { 27 | checkRemoved(); 28 | ElementHelper.validateProperty(key, value); 29 | BaseProperty vertexProperty = (BaseProperty) addPropertyLocal(key, value); 30 | innerAddProperty(vertexProperty); 31 | return vertexProperty; 32 | } 33 | 34 | @Override 35 | public Iterator vertices(Direction direction) { 36 | checkRemoved(); 37 | ArrayList vertices = new ArrayList<>(); 38 | if(direction.equals(Direction.OUT) || direction.equals(Direction.BOTH)) 39 | vertices.add(outVertex); 40 | if(direction.equals(Direction.IN) || direction.equals(Direction.BOTH)) 41 | vertices.add(inVertex); 42 | return vertices.iterator(); 43 | } 44 | 45 | protected abstract void innerAddProperty(BaseProperty vertexProperty); 46 | 47 | @Override 48 | public Iterator properties(String... propertyKeys) { 49 | checkRemoved(); 50 | return innerPropertyIterator(propertyKeys); 51 | } 52 | 53 | @Override 54 | protected void checkRemoved() { 55 | if (this.removed) 56 | throw Element.Exceptions.elementAlreadyRemoved(Edge.class, this.id); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return StringFactory.edgeString(this); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/BaseElement.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; 5 | 6 | import java.util.*; 7 | 8 | public abstract class BaseElement implements Element{ 9 | protected HashMap properties = new HashMap<>(); 10 | protected final Object id; 11 | protected String label; 12 | protected final ElasticGraph graph; 13 | protected boolean removed = false; 14 | 15 | public BaseElement(final Object id, final String label, ElasticGraph graph, Object[] keyValues) { 16 | this.graph = graph; 17 | this.id = id != null ? id.toString() : new com.eaio.uuid.UUID().toString(); 18 | this.label = label; 19 | if(keyValues != null) ElementHelper.legalPropertyKeyValueArray(keyValues); 20 | 21 | if (keyValues != null) { 22 | if(keyValues.length % 2 == 1) throw Element.Exceptions.providedKeyValuesMustBeAMultipleOfTwo(); 23 | for (int i = 0; i < keyValues.length; i = i + 2) { 24 | String key = keyValues[i].toString(); 25 | Object value = keyValues[i + 1]; 26 | 27 | addPropertyLocal(key, value); 28 | } 29 | } 30 | 31 | } 32 | 33 | public Property addPropertyLocal(String key, Object value) { 34 | checkRemoved(); 35 | if (shouldAddProperty(key)) { 36 | ElementHelper.validateProperty(key, value); 37 | Property property = createProperty(key, value); 38 | properties.put(key, property); 39 | return property; 40 | } 41 | return null; 42 | } 43 | 44 | @Override 45 | public Object id() { 46 | return this.id; 47 | } 48 | 49 | @Override 50 | public String label() { 51 | return this.label; 52 | } 53 | 54 | @Override 55 | public Graph graph() { 56 | return this.graph; 57 | } 58 | 59 | @Override 60 | public Set keys() { 61 | return this.properties.keySet(); 62 | } 63 | 64 | @Override 65 | public Property property(final String key) { 66 | checkRemoved(); 67 | return this.properties.containsKey(key) ? this.properties.get(key) : Property.empty(); 68 | } 69 | 70 | @Override 71 | public int hashCode() { 72 | return ElementHelper.hashCode(this); 73 | } 74 | 75 | @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") 76 | @Override 77 | public boolean equals(final Object object) { 78 | return ElementHelper.areEqual(this, object); 79 | } 80 | 81 | protected Iterator innerPropertyIterator(String[] propertyKeys) { 82 | HashMap properties = (HashMap) this.properties.clone(); 83 | 84 | if (propertyKeys.length > 0) 85 | return properties.entrySet().stream().filter(entry -> ElementHelper.keyExists(entry.getKey(), propertyKeys)).map(x -> x.getValue()).iterator(); 86 | 87 | return properties.values().iterator(); 88 | } 89 | 90 | 91 | public void removeProperty(Property property) { 92 | properties.remove(property.key()); 93 | this.innerRemoveProperty(property); 94 | } 95 | 96 | protected abstract void innerRemoveProperty(Property property); 97 | 98 | protected abstract Property createProperty(String key, Object value); 99 | 100 | protected boolean shouldAddProperty(String key) { 101 | return !key.equals("label") && !key.equals("id"); 102 | } 103 | 104 | protected abstract void checkRemoved(); 105 | 106 | protected abstract void innerRemove(); 107 | 108 | @Override 109 | public void remove() { 110 | checkRemoved(); 111 | innerRemove(); 112 | this.removed = true; 113 | } 114 | 115 | public Map allFields() { 116 | Map map = new HashMap<>(); 117 | properties.forEach((key, value) -> map.put(key, value.value())); 118 | return map; 119 | } 120 | 121 | public void setLabel(String label) { 122 | this.label = label; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/BaseProperty.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | 4 | import org.apache.tinkerpop.gremlin.structure.*; 5 | import org.apache.tinkerpop.gremlin.structure.util.*; 6 | 7 | public class BaseProperty implements Property { 8 | protected final BaseElement element; 9 | protected final String key; 10 | protected V value; 11 | protected final ElasticGraph graph; 12 | 13 | public BaseProperty(BaseElement element, String key, V value) { 14 | this.element = element; 15 | this.key = key; 16 | this.value = value; 17 | this.graph = this.element.graph; 18 | } 19 | 20 | @Override 21 | public Element element() { 22 | return this.element; 23 | } 24 | 25 | @Override 26 | public String key() { 27 | return this.key; 28 | } 29 | 30 | @Override 31 | public V value() { 32 | return this.value; 33 | } 34 | 35 | @Override 36 | public boolean isPresent() { 37 | return null != this.value; 38 | } 39 | 40 | public String toString() { 41 | return StringFactory.propertyString(this); 42 | } 43 | 44 | public boolean equals(final Object object) { 45 | return ElementHelper.areEqual(this, object); 46 | } 47 | 48 | public int hashCode() { 49 | return ElementHelper.hashCode(this); 50 | } 51 | 52 | @Override 53 | public void remove() { 54 | element.removeProperty(this); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/BaseVertex.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.apache.tinkerpop.gremlin.structure.util.*; 5 | import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; 6 | import org.elasticgremlin.queryhandler.Predicates; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.ElasticMutations; 8 | import org.elasticsearch.action.get.MultiGetItemResponse; 9 | 10 | import java.util.*; 11 | 12 | public abstract class BaseVertex extends BaseElement implements Vertex { 13 | 14 | private final ElasticMutations elasticMutations; 15 | private HashMap> queriedEdges = new HashMap<>(); 16 | protected List siblings; 17 | 18 | protected BaseVertex(Object id, String label, ElasticGraph graph, Object[] keyValues, ElasticMutations elasticMutations) { 19 | super(id, label, graph, keyValues); 20 | this.elasticMutations = elasticMutations; 21 | } 22 | 23 | @Override 24 | public Property createProperty(String key, Object value) { 25 | return new BaseVertexProperty(this, key, value); 26 | } 27 | 28 | @Override 29 | public VertexProperty property(VertexProperty.Cardinality cardinality, String key, V value, Object... propertyKeys) { 30 | checkRemoved(); 31 | if(propertyKeys != null && propertyKeys.length > 0) throw VertexProperty.Exceptions.metaPropertiesNotSupported(); 32 | return this.property(key, value); 33 | } 34 | 35 | @Override 36 | public Iterator edges(Direction direction, String... edgeLabels) { 37 | return edges(direction, edgeLabels, new Predicates()); 38 | } 39 | 40 | @Override 41 | public Iterator vertices(Direction direction, String... edgeLabels) { 42 | return vertices(direction, edgeLabels, new Predicates()); 43 | } 44 | 45 | public Iterator vertices(Direction direction, String[] edgeLabels, Predicates predicates) { 46 | checkRemoved(); 47 | Iterator edgeIterator = edges(direction, edgeLabels, predicates); 48 | ArrayList vertices = new ArrayList<>(); 49 | if (edgeIterator != null) { 50 | edgeIterator.forEachRemaining(edge -> 51 | vertices.add(vertexToVertex(this, edge, direction))); 52 | } 53 | return vertices.iterator(); 54 | } 55 | 56 | public void setSiblings(List siblings) { 57 | this.siblings = siblings; 58 | } 59 | 60 | public void applyLazyFields(MultiGetItemResponse response) { 61 | setLabel(response.getType()); 62 | response.getResponse().getSource().entrySet().forEach((field) -> 63 | addPropertyLocal(field.getKey(), field.getValue())); 64 | } 65 | 66 | public static Vertex vertexToVertex(Vertex originalVertex, Edge edge, Direction direction) { 67 | switch (direction) { 68 | case OUT: 69 | return edge.inVertex(); 70 | case IN: 71 | return edge.outVertex(); 72 | case BOTH: 73 | Vertex outV = edge.outVertex(); 74 | Vertex inV = edge.inVertex(); 75 | if(outV.id().equals(inV.id())) 76 | return originalVertex; //points to self 77 | if(originalVertex.id().equals(inV.id())) 78 | return outV; 79 | if(originalVertex.id().equals(outV.id())) 80 | return inV; 81 | default: 82 | throw new IllegalArgumentException(direction.toString()); 83 | } 84 | } 85 | 86 | 87 | @Override 88 | public VertexProperty property(String key, V value) { 89 | checkRemoved(); 90 | ElementHelper.validateProperty(key, value); 91 | BaseVertexProperty vertexProperty = (BaseVertexProperty) addPropertyLocal(key, value); 92 | innerAddProperty(vertexProperty); 93 | return vertexProperty; 94 | } 95 | 96 | protected abstract void innerAddProperty(BaseVertexProperty vertexProperty); 97 | 98 | @Override 99 | public VertexProperty property(final String key) { 100 | checkRemoved(); 101 | if (this.properties.containsKey(key)) { 102 | return (VertexProperty) this.properties.get(key); 103 | } 104 | else return VertexProperty.empty(); 105 | } 106 | 107 | @Override 108 | public Edge addEdge(final String label, final Vertex vertex, final Object... keyValues) { 109 | if (null == vertex) throw Graph.Exceptions.argumentCanNotBeNull("vertex"); 110 | ElementHelper.legalPropertyKeyValueArray(keyValues); 111 | checkRemoved(); 112 | Object idValue = ElementHelper.getIdValue(keyValues).orElse(null); 113 | 114 | return graph.getQueryHandler().addEdge(idValue, label, this, vertex, keyValues); 115 | } 116 | 117 | @Override 118 | public void remove() { 119 | super.remove(); 120 | Iterator edges = edges(Direction.BOTH); 121 | edges.forEachRemaining(edge-> { 122 | edge.remove(); 123 | }); 124 | } 125 | 126 | @Override 127 | public String toString() { 128 | return StringFactory.vertexString(this); 129 | } 130 | 131 | @Override 132 | public Iterator> properties(final String... propertyKeys) { 133 | checkRemoved(); 134 | return innerPropertyIterator(propertyKeys); 135 | } 136 | 137 | @Override 138 | protected void checkRemoved() { 139 | if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.id); 140 | } 141 | 142 | public Iterator edges(Direction direction, String[] edgeLabels, Predicates predicates) { 143 | EdgeQueryInfo queryInfo = new EdgeQueryInfo(direction, edgeLabels, predicates, elasticMutations.getRevision()); 144 | Set edges = queriedEdges.get(queryInfo); 145 | if (edges != null) return edges.iterator(); 146 | 147 | List vertices = siblings == null ? IteratorUtils.asList(this) : siblings; 148 | 149 | Map> vertexToEdge = graph.getQueryHandler().edges(vertices.iterator(), direction, edgeLabels, predicates); 150 | vertices.forEach( vertex -> vertex.addQueriedEdges(queryInfo, vertexToEdge.get(vertex.id()))); 151 | 152 | Set thisEdges = vertexToEdge.get(this.id()); 153 | return thisEdges != null ? thisEdges.iterator() : Collections.emptyIterator(); 154 | } 155 | 156 | private void addQueriedEdges(EdgeQueryInfo queryInfo, Set edges) { 157 | queriedEdges.put(queryInfo, edges); 158 | } 159 | 160 | private static class EdgeQueryInfo { 161 | private Direction direction; 162 | private String[] edgeLabels; 163 | private Predicates predicates; 164 | private int revision; 165 | 166 | public EdgeQueryInfo(Direction direction, String[] edgeLabels, Predicates predicates, int revision) { 167 | this.direction = direction; 168 | this.edgeLabels = edgeLabels; 169 | this.predicates = predicates; 170 | this.revision = revision; 171 | } 172 | 173 | public Direction getDirection() { 174 | return direction; 175 | } 176 | 177 | public String[] getEdgeLabels() { 178 | return edgeLabels; 179 | } 180 | 181 | public Predicates getPredicates() { 182 | return predicates; 183 | } 184 | 185 | // region equals and hashCode 186 | 187 | @Override 188 | public boolean equals(Object o) { 189 | if (this == o) return true; 190 | if (o == null || getClass() != o.getClass()) return false; 191 | 192 | EdgeQueryInfo that = (EdgeQueryInfo) o; 193 | 194 | if (revision != that.revision) return false; 195 | if (direction != that.direction) return false; 196 | if (!Arrays.equals(edgeLabels, that.edgeLabels)) return false; 197 | return predicates.equals(that.predicates); 198 | 199 | } 200 | 201 | @Override 202 | public int hashCode() { 203 | int result = direction.hashCode(); 204 | result = 31 * result + Arrays.hashCode(edgeLabels); 205 | result = 31 * result + predicates.hashCode(); 206 | result = 31 * result + revision; 207 | return result; 208 | } 209 | 210 | 211 | // endregion 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/BaseVertexProperty.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.*; 4 | import org.apache.tinkerpop.gremlin.structure.util.*; 5 | 6 | import java.util.Iterator; 7 | 8 | public class BaseVertexProperty implements VertexProperty { 9 | 10 | private final BaseVertex vertex; 11 | private final String key; 12 | private final V value; 13 | 14 | public BaseVertexProperty(final BaseVertex vertex, final String key, final V value) { 15 | this.vertex = vertex; 16 | this.key = key; 17 | this.value = value; 18 | } 19 | 20 | @Override 21 | public String key() { 22 | return this.key; 23 | } 24 | 25 | @Override 26 | public V value() { 27 | return this.value; 28 | } 29 | 30 | @Override 31 | public boolean isPresent() { 32 | return true; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return StringFactory.propertyString(this); 38 | } 39 | 40 | @Override 41 | public Object id() { 42 | return (long) (this.key.hashCode() + this.value.hashCode() + this.vertex.id().hashCode()); 43 | } 44 | 45 | @Override 46 | public boolean equals(final Object object) { 47 | return ElementHelper.areEqual(this, object); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return ElementHelper.hashCode((Element) this); 53 | } 54 | 55 | @Override 56 | public Property property(final String key, final U value) { 57 | throw VertexProperty.Exceptions.multiPropertiesNotSupported(); 58 | } 59 | 60 | @Override 61 | public Vertex element() { 62 | return this.vertex; 63 | } 64 | 65 | @Override 66 | public Iterator> properties(String... propertyKeys) { 67 | throw VertexProperty.Exceptions.multiPropertiesNotSupported(); 68 | } 69 | 70 | @Override 71 | public void remove() { 72 | vertex.removeProperty(this); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/ElasticFeatures.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.tinkerpop.gremlin.structure.Graph; 4 | import org.apache.tinkerpop.gremlin.structure.util.StringFactory; 5 | 6 | public class ElasticFeatures implements Graph.Features { 7 | 8 | ElasticVertexFeatures elasticVertexFeatures = new ElasticVertexFeatures(); 9 | ElasticEdgeFeatures elasticEdgeFeatures = new ElasticEdgeFeatures(); 10 | ElasticGraphFeatures elasticGraphFeatures = new ElasticGraphFeatures(); 11 | 12 | @Override 13 | public String toString() { 14 | return StringFactory.featureString(this); 15 | } 16 | 17 | @Override 18 | public VertexFeatures vertex() { 19 | return elasticVertexFeatures; 20 | } 21 | 22 | @Override 23 | public EdgeFeatures edge() { 24 | return elasticEdgeFeatures; 25 | } 26 | 27 | @Override 28 | public GraphFeatures graph() { 29 | return elasticGraphFeatures; 30 | } 31 | 32 | private class ElasticGraphFeatures implements GraphFeatures { 33 | ElasticVariableFeatures elasticVariableFeatures = new ElasticVariableFeatures(); 34 | 35 | @Override 36 | public VariableFeatures variables() { 37 | return elasticVariableFeatures; 38 | } 39 | 40 | @Override 41 | public boolean supportsComputer() { 42 | return false; 43 | } 44 | 45 | @Override 46 | public boolean supportsTransactions() { 47 | return false; 48 | } 49 | 50 | @Override 51 | public boolean supportsThreadedTransactions() { 52 | return false; 53 | } 54 | } 55 | 56 | private class ElasticVariableFeatures implements VariableFeatures { 57 | @Override 58 | public boolean supportsVariables() { 59 | return false; 60 | } 61 | 62 | @Override 63 | public boolean supportsBooleanValues() { 64 | return false; 65 | } 66 | 67 | @Override 68 | public boolean supportsByteValues() { 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean supportsDoubleValues() { 74 | return false; 75 | } 76 | 77 | @Override 78 | public boolean supportsFloatValues() { 79 | return false; 80 | } 81 | 82 | @Override 83 | public boolean supportsIntegerValues() { 84 | return false; 85 | } 86 | 87 | @Override 88 | public boolean supportsLongValues() { 89 | return false; 90 | } 91 | 92 | @Override 93 | public boolean supportsMapValues() { 94 | return false; 95 | } 96 | 97 | @Override 98 | public boolean supportsMixedListValues() { 99 | return false; 100 | } 101 | 102 | @Override 103 | public boolean supportsBooleanArrayValues() { 104 | return false; 105 | } 106 | 107 | @Override 108 | public boolean supportsByteArrayValues() { 109 | return false; 110 | } 111 | 112 | @Override 113 | public boolean supportsDoubleArrayValues() { 114 | return false; 115 | } 116 | 117 | @Override 118 | public boolean supportsFloatArrayValues() { 119 | return false; 120 | } 121 | 122 | @Override 123 | public boolean supportsIntegerArrayValues() { 124 | return false; 125 | } 126 | 127 | @Override 128 | public boolean supportsStringArrayValues() { 129 | return false; 130 | } 131 | 132 | @Override 133 | public boolean supportsLongArrayValues() { 134 | return false; 135 | } 136 | 137 | @Override 138 | public boolean supportsSerializableValues() { 139 | return false; 140 | } 141 | 142 | @Override 143 | public boolean supportsStringValues() { 144 | return false; 145 | } 146 | 147 | @Override 148 | public boolean supportsUniformListValues() { 149 | return false; 150 | } 151 | } 152 | 153 | private class ElasticEdgeFeatures implements EdgeFeatures { 154 | @Override 155 | public boolean supportsNumericIds() { 156 | return false; 157 | } 158 | 159 | @Override 160 | public boolean supportsAnyIds() { 161 | return false; 162 | } 163 | 164 | @Override 165 | public boolean supportsUuidIds() { 166 | return false; 167 | } 168 | 169 | @Override 170 | public boolean supportsCustomIds() { 171 | return false; 172 | } 173 | 174 | @Override 175 | public boolean willAllowId(Object id) { 176 | return true; 177 | } 178 | } 179 | 180 | private class ElasticVertexFeatures implements VertexFeatures { 181 | ElasticVertexPropertyFeatures elasticVertexPropertyFeatures = new ElasticVertexPropertyFeatures(); 182 | 183 | @Override 184 | public boolean supportsMultiProperties() { 185 | return false; 186 | } 187 | 188 | @Override 189 | public boolean supportsNumericIds() { 190 | return false; 191 | } 192 | 193 | @Override 194 | public boolean supportsUuidIds() { 195 | return false; 196 | } 197 | 198 | @Override 199 | public boolean supportsCustomIds() { 200 | return false; 201 | } 202 | 203 | @Override 204 | public boolean supportsAnyIds() { 205 | return false; 206 | } 207 | 208 | @Override 209 | public boolean supportsMetaProperties() { 210 | return false; 211 | } 212 | 213 | @Override 214 | public VertexPropertyFeatures properties() { 215 | return elasticVertexPropertyFeatures; 216 | } 217 | 218 | @Override 219 | public boolean willAllowId(Object id) { 220 | return true; 221 | } 222 | } 223 | 224 | private class ElasticVertexPropertyFeatures implements VertexPropertyFeatures { 225 | @Override 226 | public boolean supportsUserSuppliedIds() { 227 | return false; 228 | } 229 | 230 | @Override 231 | public boolean supportsNumericIds() { 232 | return false; 233 | } 234 | 235 | @Override 236 | public boolean supportsStringIds() { 237 | return false; 238 | } 239 | 240 | @Override 241 | public boolean supportsUuidIds() { 242 | return false; 243 | } 244 | 245 | @Override 246 | public boolean supportsCustomIds() { 247 | return false; 248 | } 249 | 250 | @Override 251 | public boolean supportsAnyIds() { 252 | return false; 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/org/elasticgremlin/structure/ElasticGraph.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.structure; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; 5 | import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; 6 | import org.apache.tinkerpop.gremlin.structure.*; 7 | import org.apache.tinkerpop.gremlin.structure.util.*; 8 | import org.elasticgremlin.process.optimize.ElasticOptimizationStrategy; 9 | import org.elasticgremlin.queryhandler.*; 10 | import org.elasticgremlin.queryhandler.SimpleQueryHandler; 11 | 12 | import java.util.*; 13 | 14 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.FeatureSupportTest$VertexPropertyFunctionalityTest", method = "shouldSupportNumericIdsIfNumericIdsAreGeneratedFromTheGraph", 15 | reason = "need to handle ids in VertexProperties") 16 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.GraphTest", method = "shouldHaveExceptionConsistencyWhenFindVertexByIdThatIsNonExistentViaIterator", 17 | reason = "We don't throw an exception when the vertexdoc doesn't exist, because we support \"lazy vertices\"") 18 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoTest$GraphSONTest", method = "shouldReadLegacyGraphSON", 19 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 20 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoTest$GraphMLTest", method = "shouldReadGraphML", 21 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 22 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoTest$GraphMLTest", method = "shouldReadGraphMLAnAllSupportedDataTypes", 23 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 24 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoTest$GraphMLTest", method = "shouldReadGraphMLUnorderedElements", 25 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 26 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldReadWriteClassic", specific="graphml", 27 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 28 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldReadWriteClassicToFileWithHelpers", specific="graphml", 29 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 30 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldMigrateClassicGraph", specific="graphml", 31 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 32 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldReadWriteClassic", specific="gryo", 33 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 34 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldReadWriteClassicToFileWithHelpers", specific="gryo", 35 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 36 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.io.IoGraphTest", method = "shouldMigrateClassicGraph", specific="gryo", 37 | reason = "https://github.com/rmagen/elastic-gremlin/issues/52") 38 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.structure.GraphConstructionTest", method = "shouldConstructAnEmptyGraph", 39 | reason = "need to investigate...") 40 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.CountTest", method = "g_V_repeatXoutX_timesX3X_count", 41 | reason = "Takes too long.") 42 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.CountTest", method = "g_V_repeatXoutX_timesX8X_count", 43 | reason = "OutOfMemory exception") 44 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest$Traversals", method = "g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup", 45 | reason = "need to investigate...") 46 | @Graph.OptOut(test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest$Traversals", method = "g_V_withSideEffectXsgX_outEXknowsX_subgraphXsgX_name_capXsgX", 47 | reason = "need to investigate...") 48 | @Graph.OptIn(Graph.OptIn.SUITE_STRUCTURE_STANDARD) 49 | @Graph.OptIn(Graph.OptIn.SUITE_PROCESS_STANDARD) 50 | public class ElasticGraph implements Graph { 51 | static { 52 | TraversalStrategies.GlobalCache.registerStrategies(ElasticGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(ElasticOptimizationStrategy.instance())); 53 | } 54 | 55 | //for testSuite 56 | public static ElasticGraph open(final Configuration configuration) throws InstantiationException { 57 | return new ElasticGraph(configuration); 58 | } 59 | 60 | private ElasticFeatures features = new ElasticFeatures(); 61 | private final Configuration configuration; 62 | private QueryHandler queryHandler; 63 | 64 | public ElasticGraph(Configuration configuration) throws InstantiationException { 65 | try { 66 | configuration.setProperty(Graph.GRAPH, ElasticGraph.class.getName()); 67 | this.configuration = configuration; 68 | String queryHandlerName = configuration.getString("queryHandler"); 69 | if(queryHandlerName != null) this.queryHandler = (QueryHandler)Class.forName(queryHandlerName).newInstance(); 70 | else this.queryHandler = new SimpleQueryHandler(); 71 | this.getQueryHandler().init(this, configuration); 72 | } catch(Exception ex) { 73 | InstantiationException instantiationException = new InstantiationException(); 74 | instantiationException.addSuppressed(ex); 75 | throw instantiationException; 76 | } 77 | } 78 | 79 | public QueryHandler getQueryHandler() { 80 | return queryHandler; 81 | } 82 | 83 | public void commit() { queryHandler.commit(); } 84 | 85 | @Override 86 | public Configuration configuration() { 87 | return this.configuration; 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return StringFactory.graphString(this, queryHandler.toString()); 93 | } 94 | 95 | @Override 96 | public void close() { 97 | queryHandler.close(); 98 | } 99 | 100 | @Override 101 | public Features features() { 102 | return features; 103 | } 104 | 105 | @Override 106 | public Transaction tx() { 107 | throw Exceptions.transactionsNotSupported(); 108 | } 109 | 110 | @Override 111 | public Variables variables() { 112 | throw Exceptions.variablesNotSupported(); 113 | } 114 | 115 | 116 | @Override 117 | public C compute(Class graphComputerClass) throws IllegalArgumentException { 118 | throw Exceptions.graphComputerNotSupported(); 119 | } 120 | 121 | @Override 122 | public GraphComputer compute() throws IllegalArgumentException { 123 | throw Exceptions.graphComputerNotSupported(); 124 | } 125 | 126 | @Override 127 | public Iterator vertices(Object... vertexIds) { 128 | if (vertexIds == null || vertexIds.length == 0) return (Iterator) queryHandler.vertices(); 129 | if(vertexIds.length > 1 && !vertexIds[0].getClass().equals(vertexIds[1].getClass())) throw Graph.Exceptions.idArgsMustBeEitherIdOrElement(); 130 | if(vertexIds[0] instanceof Vertex) { 131 | ArrayList list = new ArrayList(); 132 | for(int i = 0; i < vertexIds.length; i++) list.add((Vertex) vertexIds[i]); 133 | return list.iterator(); 134 | } 135 | return (Iterator) queryHandler.vertices(vertexIds); 136 | } 137 | 138 | @Override 139 | public Iterator edges(Object... edgeIds) { 140 | if (edgeIds == null || edgeIds.length == 0) return queryHandler.edges(); 141 | if(edgeIds.length > 1 && !edgeIds[0].getClass().equals(edgeIds[1].getClass())) throw Graph.Exceptions.idArgsMustBeEitherIdOrElement(); 142 | if(edgeIds[0] instanceof Edge) { 143 | ArrayList list = new ArrayList(); 144 | for(int i = 0; i < edgeIds.length; i++) list.add((Edge) edgeIds[i]); 145 | return list.iterator(); 146 | } 147 | return queryHandler.edges(edgeIds); 148 | } 149 | 150 | @Override 151 | public Vertex addVertex(final Object... keyValues) { 152 | ElementHelper.legalPropertyKeyValueArray(keyValues); 153 | Object idValue = ElementHelper.getIdValue(keyValues).orElse(null); 154 | final String label = ElementHelper.getLabelValue(keyValues).orElse(Vertex.DEFAULT_LABEL); 155 | return queryHandler.addVertex(idValue, label, keyValues); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/ElasticGraphGraphProvider.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.commons.io.FileUtils; 5 | import org.apache.tinkerpop.gremlin.*; 6 | import org.apache.tinkerpop.gremlin.structure.*; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 8 | import org.elasticgremlin.structure.*; 9 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 10 | import org.elasticsearch.client.Client; 11 | import org.elasticsearch.common.unit.TimeValue; 12 | import org.elasticsearch.node.Node; 13 | 14 | import java.io.*; 15 | import java.net.ServerSocket; 16 | import java.util.*; 17 | import java.util.concurrent.ExecutionException; 18 | 19 | /** 20 | * @author Stephen Mallette (http://stephen.genoprime.com) 21 | */ 22 | public class ElasticGraphGraphProvider extends AbstractGraphProvider { 23 | 24 | private static String CLUSTER_NAME = "test"; 25 | 26 | private static final Set IMPLEMENTATION = new HashSet() {{ 27 | add(BaseEdge.class); 28 | add(BaseElement.class); 29 | add(ElasticGraph.class); 30 | add(BaseProperty.class); 31 | add(BaseVertex.class); 32 | add(BaseVertexProperty.class); 33 | }}; 34 | 35 | private final int port; 36 | private final Node node; 37 | private final Client client; 38 | 39 | public ElasticGraphGraphProvider() throws IOException, ExecutionException, InterruptedException { 40 | System.setProperty("build.dir", System.getProperty("user.dir") + "\\build"); 41 | 42 | String path = new java.io.File( "." ).getCanonicalPath() + "\\data"; 43 | File file = new File(path); 44 | FileUtils.deleteQuietly(file); 45 | 46 | this.port = findFreePort(); 47 | 48 | node = ElasticClientFactory.createNode(CLUSTER_NAME, false, port); 49 | client = node.client(); 50 | 51 | final ClusterHealthResponse clusterHealth = client.admin().cluster().prepareHealth().setTimeout(TimeValue.timeValueSeconds(10)).setWaitForGreenStatus().execute().get(); 52 | if (clusterHealth.isTimedOut()) System.out.print(clusterHealth.getStatus()); 53 | } 54 | 55 | private static int findFreePort() { 56 | ServerSocket socket = null; 57 | try { 58 | socket = new ServerSocket(0); 59 | socket.setReuseAddress(true); 60 | int port = socket.getLocalPort(); 61 | try { 62 | socket.close(); 63 | } catch (IOException e) { 64 | // Ignore IOException on close() 65 | } 66 | return port; 67 | } catch (IOException e) { 68 | } finally { 69 | if (socket != null) { 70 | try { 71 | socket.close(); 72 | } catch (IOException e) { 73 | } 74 | } 75 | } 76 | throw new IllegalStateException("Could not find a free TCP/IP port to start embedded Jetty HTTP Server on"); 77 | } 78 | 79 | @Override 80 | public Map getBaseConfiguration(String graphName, Class test, String testMethodName, LoadGraphWith.GraphData loadGraphWith) { 81 | return new HashMap() {{ 82 | put(Graph.GRAPH, ElasticGraph.class.getName()); 83 | put("elasticsearch.cluster.name", CLUSTER_NAME); 84 | put("elasticsearch.index.name",graphName.toLowerCase()); 85 | put("elasticsearch.refresh", true); 86 | put("elasticsearch.client", ElasticClientFactory.ClientType.TRANSPORT_CLIENT.toString()); 87 | put("elasticsearch.cluster.address", "127.0.0.1:" + port); 88 | }}; 89 | } 90 | 91 | @Override 92 | public void clear(final Graph g, final Configuration configuration) throws Exception { 93 | if (g != null) { 94 | String indexName = configuration.getString("elasticsearch.index.name"); 95 | ElasticHelper.clearIndex(client, indexName); 96 | g.close(); 97 | } 98 | if(g instanceof ElasticGraph) 99 | ((ElasticGraph)g).getQueryHandler().printStats(); 100 | } 101 | 102 | @Override 103 | public Set getImplementations() { 104 | return IMPLEMENTATION; 105 | } 106 | 107 | @Override 108 | public Object convertId(Object id, Class c) { 109 | return id.toString(); 110 | } 111 | 112 | public Client getClient() { 113 | return client; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/elastic/ConfigurationTests.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.elastic; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.LoadGraphWith; 5 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; 6 | import org.apache.tinkerpop.gremlin.structure.*; 7 | import org.elasticgremlin.ElasticGraphGraphProvider; 8 | import org.junit.*; 9 | 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertFalse; 16 | 17 | public class ConfigurationTests { 18 | 19 | private Graph graph; 20 | 21 | @Before 22 | public void startUp() throws InstantiationException, IOException, ExecutionException, InterruptedException { 23 | ElasticGraphGraphProvider elasticGraphProvider = new ElasticGraphGraphProvider(); 24 | HashMap config = new HashMap<>(); 25 | config.put("elasticsearch.upsert", true); 26 | final Configuration configuration = elasticGraphProvider.newGraphConfiguration("testGraph", this.getClass(), "spatialTests", 27 | config, LoadGraphWith.GraphData.MODERN); 28 | this.graph = elasticGraphProvider.openTestGraph(configuration); 29 | } 30 | 31 | @Test 32 | public void upsertConfiguration() throws InstantiationException { 33 | graph.addVertex(T.id, "1", "field", "a", "field2", "c"); 34 | graph.addVertex(T.id, "1", "field", "b"); 35 | 36 | GraphTraversal traversal = graph.traversal().V("1"); 37 | Vertex vertex = traversal.next(); 38 | assertEquals("b", vertex.property("field").value()); 39 | assertEquals("c", vertex.property("field2").value()); 40 | assertFalse(traversal.hasNext()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/elastic/PerformanceTests.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.elastic; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.LoadGraphWith; 5 | import org.apache.tinkerpop.gremlin.structure.*; 6 | import org.elasticgremlin.ElasticGraphGraphProvider; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.TimingAccessor; 8 | import org.junit.*; 9 | 10 | import java.io.IOException; 11 | import java.util.Iterator; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | public class PerformanceTests { 15 | 16 | TimingAccessor sw = new TimingAccessor(); 17 | private Graph graph; 18 | 19 | @Before 20 | public void startUp() throws InstantiationException, IOException, ExecutionException, InterruptedException { 21 | ElasticGraphGraphProvider elasticGraphProvider = new ElasticGraphGraphProvider(); 22 | final Configuration configuration = elasticGraphProvider.newGraphConfiguration("testGraph", this.getClass(), "performanceTests", LoadGraphWith.GraphData.MODERN); 23 | this.graph = elasticGraphProvider.openTestGraph(configuration); 24 | } 25 | 26 | @Test 27 | public void profile() { 28 | startWatch("add vertices"); 29 | int count = 10000; 30 | for(int i = 0; i < count; i++) 31 | graph.addVertex(); 32 | stopWatch("add vertices"); 33 | 34 | startWatch("vertex iterator"); 35 | Iterator vertexIterator = graph.vertices(); 36 | stopWatch("vertex iterator"); 37 | 38 | startWatch("add edges"); 39 | vertexIterator.forEachRemaining(v -> v.addEdge("bla", v)); 40 | stopWatch("add edges"); 41 | 42 | startWatch("edge iterator"); 43 | Iterator edgeIterator = graph.edges(); 44 | stopWatch("edge iterator"); 45 | 46 | sw.print(); 47 | System.out.println("-----"); 48 | } 49 | 50 | 51 | private void stopWatch(String s) { 52 | sw.timer(s).stop(); 53 | } 54 | 55 | private void startWatch(String s) { 56 | sw.timer(s).start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/elastic/SpatialStepTests.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.elastic; 2 | 3 | import com.spatial4j.core.context.SpatialContext; 4 | import com.spatial4j.core.shape.Point; 5 | import com.spatial4j.core.shape.impl.PointImpl; 6 | import org.apache.commons.configuration.Configuration; 7 | import org.apache.tinkerpop.gremlin.LoadGraphWith; 8 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 9 | import org.apache.tinkerpop.gremlin.structure.*; 10 | import org.elasticgremlin.ElasticGraphGraphProvider; 11 | import org.elasticgremlin.queryhandler.elasticsearch.Geo; 12 | import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; 13 | import org.elasticsearch.client.Client; 14 | import org.elasticsearch.common.xcontent.XContentBuilder; 15 | import org.junit.*; 16 | 17 | import java.io.IOException; 18 | import java.util.*; 19 | import java.util.concurrent.ExecutionException; 20 | 21 | import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 22 | import static org.junit.Assert.assertEquals; 23 | 24 | /** 25 | * Created by Eliran on 6/3/2015. 26 | */ 27 | public class SpatialStepTests { 28 | 29 | String CLUSTER_NAME = "testscluster"; 30 | String INDEX_NAME = "geo_index"; 31 | String DOCUMENT_TYPE = "geo_item"; 32 | Graph graph; 33 | 34 | @Before 35 | public void startUp() throws InstantiationException, IOException, ExecutionException, InterruptedException { 36 | ElasticGraphGraphProvider elasticGraphProvider = new ElasticGraphGraphProvider(); 37 | final Configuration configuration = elasticGraphProvider.newGraphConfiguration("testGraph", this.getClass(), "spatialTests", LoadGraphWith.GraphData.MODERN); 38 | this.graph = elasticGraphProvider.openTestGraph(configuration); 39 | 40 | createGeoShapeMapping(elasticGraphProvider.getClient(),DOCUMENT_TYPE); 41 | } 42 | 43 | 44 | @Test 45 | public void geoPointPolygonsIntersectionTest() throws IOException { 46 | //create polygons 47 | List firstPolygonPoints = new ArrayList(); 48 | firstPolygonPoints.add(new PointImpl(10,10, SpatialContext.GEO)); 49 | firstPolygonPoints.add(new PointImpl(8,10, SpatialContext.GEO)); 50 | firstPolygonPoints.add(new PointImpl(8,8, SpatialContext.GEO)); 51 | firstPolygonPoints.add(new PointImpl(10,8, SpatialContext.GEO)); 52 | firstPolygonPoints.add(new PointImpl(10,10, SpatialContext.GEO)); 53 | Map firstPolygon = buildGeoJsonPolygon(firstPolygonPoints); 54 | List secondPolygonPoints = new ArrayList(); 55 | secondPolygonPoints.add(new PointImpl(14, 10, SpatialContext.GEO)); 56 | secondPolygonPoints.add(new PointImpl(12, 10, SpatialContext.GEO)); 57 | secondPolygonPoints.add(new PointImpl(12, 8, SpatialContext.GEO)); 58 | secondPolygonPoints.add(new PointImpl(14, 8, SpatialContext.GEO)); 59 | secondPolygonPoints.add(new PointImpl(14, 10, SpatialContext.GEO)); 60 | Map secondPolygon = buildGeoJsonPolygon(secondPolygonPoints); 61 | 62 | //add the vertices to graph 63 | graph.addVertex(T.label,DOCUMENT_TYPE,T.id,"1","location",firstPolygon); 64 | graph.addVertex(T.label,DOCUMENT_TYPE,T.id,"2","location",secondPolygon); 65 | 66 | GraphTraversalSource g = graph.traversal(); 67 | 68 | String geoJsonPoint = "{ \"type\": \"Point\",\"coordinates\": [9, 9]}"; 69 | long intersectionCounter = g.V().has("location", Geo.intersercts(geoJsonPoint)).count().next(); 70 | assertEquals(1l, intersectionCounter); 71 | Element location = g.V().has("location", Geo.intersercts(geoJsonPoint)).next(); 72 | assertEquals("1",location.id().toString()); 73 | } 74 | 75 | @Test 76 | public void polygonToPolygonsIntersectionTest() throws IOException { 77 | //create polygons 78 | List firstPolygonPoints = new ArrayList(); 79 | firstPolygonPoints.add(new PointImpl(10,10, SpatialContext.GEO)); 80 | firstPolygonPoints.add(new PointImpl(8,10, SpatialContext.GEO)); 81 | firstPolygonPoints.add(new PointImpl(8,8, SpatialContext.GEO)); 82 | firstPolygonPoints.add(new PointImpl(10,8, SpatialContext.GEO)); 83 | firstPolygonPoints.add(new PointImpl(10,10, SpatialContext.GEO)); 84 | Map firstPolygon = buildGeoJsonPolygon(firstPolygonPoints); 85 | List secondPolygonPoints = new ArrayList(); 86 | secondPolygonPoints.add(new PointImpl(14, 10, SpatialContext.GEO)); 87 | secondPolygonPoints.add(new PointImpl(12, 10, SpatialContext.GEO)); 88 | secondPolygonPoints.add(new PointImpl(12, 8, SpatialContext.GEO)); 89 | secondPolygonPoints.add(new PointImpl(14, 8, SpatialContext.GEO)); 90 | secondPolygonPoints.add(new PointImpl(14, 10, SpatialContext.GEO)); 91 | Map secondPolygon = buildGeoJsonPolygon(secondPolygonPoints); 92 | 93 | //add the vertices to graph 94 | graph.addVertex(T.label,DOCUMENT_TYPE,T.id,"1","location",firstPolygon); 95 | graph.addVertex(T.label,DOCUMENT_TYPE,T.id,"2","location",secondPolygon); 96 | 97 | GraphTraversalSource g = graph.traversal(); 98 | 99 | String geoJsonPoint = "{ \"type\": \"Polygon\",\"coordinates\": [[[9, 10],[11, 10],[11, 8],[9, 8],[9, 10]]]}"; 100 | long intersectionCounter = g.V().has("location", Geo.intersercts(geoJsonPoint)).count().next(); 101 | assertEquals(1l, intersectionCounter); 102 | Element location = g.V().has("location", Geo.intersercts(geoJsonPoint)).next(); 103 | assertEquals("1",location.id().toString()); 104 | 105 | } 106 | 107 | private Map buildGeoJsonPolygon(List points) throws IOException { 108 | Map json = new HashMap(); 109 | json.put("type","Polygon"); 110 | List newPoints = new ArrayList(); 111 | for (Point point : points){ 112 | newPoints.add(new double[]{point.getX(),point.getY()}); 113 | } 114 | Object[] pointsArray = newPoints.toArray(); 115 | Object[] envelopeArray = new Object[] {pointsArray}; 116 | json.put("coordinates",envelopeArray); 117 | return json; 118 | } 119 | private void createGeoShapeMapping(Client client, String documentType) throws IOException { 120 | 121 | final XContentBuilder mappingBuilder = 122 | 123 | jsonBuilder() 124 | .startObject() 125 | .startObject(documentType) 126 | .startObject("properties") 127 | .startObject("location") 128 | .field("type", "geo_shape") 129 | .field("tree_levels", "8") 130 | .endObject() 131 | .endObject() 132 | .endObject() 133 | .endObject(); 134 | 135 | PutMappingResponse putMappingResponse = client.admin().indices() 136 | .preparePutMapping("geo_index") 137 | .setType(documentType) 138 | .setSource(mappingBuilder) 139 | .execute().actionGet(); 140 | 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/elastic/TemporaryTests.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.elastic; 2 | 3 | import org.apache.tinkerpop.gremlin.*; 4 | import org.apache.tinkerpop.gremlin.process.traversal.P; 5 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; 6 | import org.elasticgremlin.ElasticGraphGraphProvider; 7 | import org.junit.*; 8 | 9 | import java.io.IOException; 10 | import java.util.concurrent.ExecutionException; 11 | 12 | import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; 13 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has; 14 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE; 15 | 16 | public class TemporaryTests extends AbstractGremlinTest { 17 | 18 | public TemporaryTests() throws InterruptedException, ExecutionException, IOException { 19 | GraphManager.setGraphProvider(new ElasticGraphGraphProvider()); 20 | } 21 | 22 | @Test 23 | @LoadGraphWith(MODERN) 24 | public void g_V_Drop() throws Exception { 25 | GraphTraversal traversal = g.V().and(has("age", P.gt(27)), outE().count().is(P.gte(2l))).values("name"); 26 | check(traversal); 27 | } 28 | 29 | @Test 30 | @LoadGraphWith(MODERN) 31 | public void get_g_VX1X_out_hasIdX2X() { 32 | GraphTraversal traversal = g.V("1").out().hasId("2"); 33 | check(traversal); 34 | } 35 | 36 | private void check(GraphTraversal traversal) { 37 | System.out.println("pre-strategy:" + traversal); 38 | traversal.hasNext(); 39 | System.out.println("post-strategy:" + traversal); 40 | 41 | //traversal.profile().cap(TraversalMetrics.METRICS_KEY); 42 | 43 | while(traversal.hasNext()) 44 | System.out.println(traversal.next()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/groovy/ElasticGraphGroovyEnvironmentIntegrateTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.elasticgremlin.ElasticGraphGraphProvider; 5 | import org.elasticgremlin.structure.ElasticGraph; 6 | import org.apache.tinkerpop.gremlin.groovy.GroovyEnvironmentIntegrateSuite; 7 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyEnvironmentIntegrateSuite.class) 11 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ElasticGraphGroovyEnvironmentIntegrateTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/groovy/ElasticGraphGroovyEnvironmentTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.elasticgremlin.ElasticGraphGraphProvider; 5 | import org.elasticgremlin.structure.ElasticGraph; 6 | import org.apache.tinkerpop.gremlin.groovy.GroovyEnvironmentSuite; 7 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyEnvironmentSuite.class) 11 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ElasticGraphGroovyEnvironmentTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/groovy/ElasticGraphGroovyProcessStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.elasticgremlin.ElasticGraphGraphProvider; 5 | import org.elasticgremlin.structure.ElasticGraph; 6 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 7 | import org.apache.tinkerpop.gremlin.process.GroovyProcessStandardSuite; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyProcessStandardSuite.class) 11 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ElasticGraphGroovyProcessStandardTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/java/ElasticGraphProcessStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.elasticgremlin.ElasticGraphGraphProvider; 5 | import org.elasticgremlin.structure.ElasticGraph; 6 | import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(ProcessStandardSuite.class) 10 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ElasticGraphProcessStandardTest { 12 | } -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/java/ElasticGraphStructurePerformanceTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.structure.StructurePerformanceSuite; 5 | import org.elasticgremlin.ElasticGraphGraphProvider; 6 | import org.elasticgremlin.structure.ElasticGraph; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(StructurePerformanceSuite.class) 10 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ElasticGraphStructurePerformanceTest { 12 | 13 | } -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/simpleQueryHandler/java/ElasticGraphStructureStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.simpleQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite; 5 | import org.elasticgremlin.ElasticGraphGraphProvider; 6 | import org.elasticgremlin.structure.ElasticGraph; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(StructureStandardSuite.class) 10 | @GraphProviderClass(provider = ElasticGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ElasticGraphStructureStandardTest { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/ModernGraphGraphProvider.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.LoadGraphWith; 5 | import org.elasticgremlin.ElasticGraphGraphProvider; 6 | 7 | import java.io.IOException; 8 | import java.util.Map; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | public class ModernGraphGraphProvider extends ElasticGraphGraphProvider { 12 | 13 | 14 | public ModernGraphGraphProvider() throws IOException, ExecutionException, InterruptedException { 15 | } 16 | 17 | @Override 18 | public Configuration newGraphConfiguration(String graphName, Class test, String testMethodName, Map configurationOverrides, LoadGraphWith.GraphData loadGraphWith) { 19 | Configuration configuration = super.newGraphConfiguration(graphName, test, testMethodName, configurationOverrides, loadGraphWith); 20 | configuration.setProperty("queryHandler", ModernGraphQueryHandler.class.getName()); 21 | return configuration; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/ModernGraphQueryHandler.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler; 2 | 3 | import org.apache.commons.configuration.Configuration; 4 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; 5 | import org.apache.tinkerpop.gremlin.structure.*; 6 | import org.elasticgremlin.queryhandler.*; 7 | import org.elasticgremlin.queryhandler.elasticsearch.helpers.*; 8 | import org.elasticgremlin.queryhandler.elasticsearch.stardoc.*; 9 | import org.elasticgremlin.queryhandler.elasticsearch.vertexdoc.DocVertexHandler; 10 | import org.elasticgremlin.structure.*; 11 | import org.elasticsearch.client.Client; 12 | 13 | import java.io.IOException; 14 | import java.util.*; 15 | 16 | public class ModernGraphQueryHandler implements QueryHandler { 17 | 18 | private static final String PERSON = "person"; 19 | private static final String SOFTWARE = "software"; 20 | 21 | private StarHandler starHandler; 22 | private DocVertexHandler docVertexHandler; 23 | private Client client; 24 | private Map vertexHandlers; 25 | private ElasticMutations elasticMutations; 26 | private TimingAccessor timing; 27 | 28 | @Override 29 | public void init(ElasticGraph graph, Configuration configuration) throws IOException { 30 | String indexName = configuration.getString("elasticsearch.index.name", "graph"); 31 | boolean refresh = configuration.getBoolean("elasticsearch.refresh", false); 32 | int scrollSize = configuration.getInt("elasticsearch.scrollSize", 100); 33 | 34 | this.client = ElasticClientFactory.create(configuration); 35 | ElasticHelper.createIndex(indexName, client); 36 | 37 | timing = new TimingAccessor(); 38 | elasticMutations = new ElasticMutations(false, client, timing); 39 | this.docVertexHandler = new DocVertexHandler(graph, client, elasticMutations, indexName, scrollSize, refresh, timing); 40 | this.starHandler = new StarHandler(graph, client, elasticMutations, indexName, scrollSize, refresh, timing, 41 | new BasicEdgeMapping("knows", "person", Direction.OUT, "knows-fk"), new BasicEdgeMapping("created", "software", Direction.OUT, "created-fk")); 42 | 43 | this.vertexHandlers = new HashMap<>(); 44 | this.vertexHandlers.put(PERSON, starHandler); 45 | this.vertexHandlers.put(SOFTWARE, docVertexHandler); 46 | } 47 | 48 | @Override 49 | public void commit() { elasticMutations.commit(); } 50 | 51 | @Override 52 | public Iterator edges() { 53 | return starHandler.edges(); 54 | } 55 | 56 | @Override 57 | public Iterator edges(Object[] edgeIds) { 58 | return starHandler.edges(edgeIds); 59 | } 60 | 61 | @Override 62 | public Iterator edges(Predicates predicates) { 63 | return starHandler.edges(predicates); 64 | } 65 | 66 | @Override 67 | public Map> edges(Iterator vertices, Direction direction, String[] edgeLabels, Predicates predicates) { 68 | return starHandler.edges(vertices, direction, edgeLabels, predicates); 69 | } 70 | 71 | @Override 72 | public Edge addEdge(Object edgeId, String label, Vertex outV, Vertex inV, Object[] properties) { 73 | return starHandler.addEdge(edgeId, label, outV, inV, properties); 74 | } 75 | 76 | @Override 77 | public Iterator vertices() { 78 | final Iterator starVertices = (Iterator) starHandler.vertices(); 79 | final Iterator docVertices = docVertexHandler.vertices(); 80 | 81 | return new ConcatIterator<>(starVertices, docVertices); 82 | } 83 | 84 | @Override 85 | public Iterator vertices(Object[] vertexIds) { 86 | final Iterator starVertices = (Iterator) starHandler.vertices(vertexIds); 87 | final Iterator docVertices = (Iterator) docVertexHandler.vertices(vertexIds); 88 | 89 | return new ConcatIterator<>(starVertices, docVertices); 90 | } 91 | 92 | @Override 93 | public Iterator vertices(Predicates predicates) { 94 | String label = extractLabel(predicates.hasContainers); 95 | if (label == null) { 96 | Iterator vertices = vertices(); 97 | return testPredicatesLocal(predicates, vertices); 98 | } 99 | 100 | return vertexHandlers.get(label).vertices(predicates); 101 | } 102 | 103 | 104 | @Override 105 | public BaseVertex vertex(Object vertexId, String vertexLabel, Edge edge, Direction direction) { 106 | if (vertexLabel == null) { 107 | BaseVertex starVertex = starHandler.vertex(vertexId, vertexLabel, edge, direction); 108 | BaseVertex docVertex = docVertexHandler.vertex(vertexId, vertexLabel, edge, direction); 109 | return starVertex == null ? docVertex : starVertex ; 110 | } 111 | 112 | return vertexHandlers.get(vertexLabel).vertex(vertexId, vertexLabel, edge, direction); 113 | } 114 | 115 | @Override 116 | public BaseVertex addVertex(Object id, String label, Object[] properties) { 117 | return vertexHandlers.get(label).addVertex(id, label, properties); 118 | } 119 | 120 | @Override 121 | public void printStats() { 122 | timing.print(); 123 | } 124 | 125 | @Override 126 | public void close() { 127 | client.close(); 128 | } 129 | 130 | private Iterator testPredicatesLocal(Predicates predicates, Iterator vertices) { 131 | List passedVertices = new ArrayList<>(); 132 | vertices.forEachRemaining(vertex -> { 133 | boolean passed = true; 134 | for (HasContainer has : predicates.hasContainers) { 135 | passed = passed && has.test(vertex); 136 | } 137 | if (passed) { 138 | passedVertices.add(vertex); 139 | } 140 | }); 141 | return passedVertices.iterator(); 142 | } 143 | 144 | private String extractLabel(ArrayList hasContainers) { 145 | for (HasContainer hasContainer : hasContainers) { 146 | if (hasContainer.getKey().equals(T.label.getAccessor())) { 147 | return hasContainer.getValue().toString(); 148 | } 149 | } 150 | return null; 151 | } 152 | 153 | private static class ConcatIterator implements Iterator { 154 | private final Iterator firstIterator; 155 | private final Iterator secondIterator; 156 | 157 | public ConcatIterator(Iterator firstIterator, Iterator secondIterator) { 158 | this.firstIterator = firstIterator; 159 | this.secondIterator = secondIterator; 160 | } 161 | 162 | @Override 163 | public boolean hasNext() { 164 | return firstIterator.hasNext() || secondIterator.hasNext(); 165 | } 166 | 167 | @Override 168 | public E next() { 169 | return firstIterator.hasNext() ? firstIterator.next() : secondIterator.next(); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/groovy/ModernGraphGroovyEnvironmentIntegrateTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.groovy.GroovyEnvironmentIntegrateSuite; 5 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 6 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 7 | import org.elasticgremlin.structure.ElasticGraph; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyEnvironmentIntegrateSuite.class) 11 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ModernGraphGroovyEnvironmentIntegrateTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/groovy/ModernGraphGroovyProcessStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 5 | import org.apache.tinkerpop.gremlin.process.GroovyProcessStandardSuite; 6 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 7 | import org.elasticgremlin.structure.ElasticGraph; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyProcessStandardSuite.class) 11 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ModernGraphGroovyProcessStandardTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/groovy/ModernGraphProcessStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.groovy; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite; 5 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 6 | import org.elasticgremlin.structure.ElasticGraph; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(ProcessStandardSuite.class) 10 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ModernGraphProcessStandardTest { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/java/ModernGraphGroovyEnvironmentTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.groovy.GroovyEnvironmentSuite; 5 | import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader; 6 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 7 | import org.elasticgremlin.structure.ElasticGraph; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(GroovyEnvironmentSuite.class) 11 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 12 | public class ModernGraphGroovyEnvironmentTest { 13 | static { 14 | SugarLoader.load(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/java/ModernGraphStructurePerformanceTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.structure.StructurePerformanceSuite; 5 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 6 | import org.elasticgremlin.structure.ElasticGraph; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(StructurePerformanceSuite.class) 10 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ModernGraphStructurePerformanceTest { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/elasticgremlin/starQueryHandler/java/ModernGraphStructureStandardTest.java: -------------------------------------------------------------------------------- 1 | package org.elasticgremlin.starQueryHandler.java; 2 | 3 | import org.apache.tinkerpop.gremlin.GraphProviderClass; 4 | import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite; 5 | import org.elasticgremlin.starQueryHandler.ModernGraphGraphProvider; 6 | import org.elasticgremlin.structure.ElasticGraph; 7 | import org.junit.runner.RunWith; 8 | 9 | @RunWith(StructureStandardSuite.class) 10 | @GraphProviderClass(provider = ModernGraphGraphProvider.class, graph = ElasticGraph.class) 11 | public class ModernGraphStructureStandardTest { 12 | 13 | } 14 | --------------------------------------------------------------------------------