/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tinkerpop.gremlin.process.computer.bulkloading; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.TestHelper; import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; import org.apache.tinkerpop.gremlin.process.IgnoreEngine; import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.apache.tinkerpop.gremlin.structure.util.GraphFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; import org.junit.After; import org.junit.Test; import java.io.File; import java.lang.reflect.Field; import java.util.Iterator; import java.util.function.Function; import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** * @author Daniel Kuppitz (http://gremlin.guru) */ public class BulkLoaderVertexProgramTest extends AbstractGremlinProcessTest { final static String TINKERGRAPH_LOCATION = TestHelper.makeTestDataDirectory(BulkLoaderVertexProgramTest.class) + "tinkertest.kryo"; private BulkLoader getBulkLoader(final BulkLoaderVertexProgram blvp) throws Exception { final Field field = BulkLoaderVertexProgram.class.getDeclaredField("bulkLoader"); field.setAccessible(true); return (BulkLoader) field.get(blvp); } private Configuration getWriteGraphConfiguration() { final Configuration configuration = new BaseConfiguration(); configuration.setProperty(Graph.GRAPH, "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph"); configuration.setProperty("gremlin.tinkergraph.graphLocation", TINKERGRAPH_LOCATION); configuration.setProperty("gremlin.tinkergraph.graphFormat", "gryo"); return configuration; } private Graph getWriteGraph() { return GraphFactory.open(getWriteGraphConfiguration()); } @After public void cleanup() { final File graph = new File(TINKERGRAPH_LOCATION); assertTrue(!graph.exists() || graph.delete()); } @Test public void shouldUseIncrementalBulkLoaderByDefault() throws Exception { final BulkLoader loader = getBulkLoader(BulkLoaderVertexProgram.build().create(graph)); assertTrue(loader instanceof IncrementalBulkLoader); assertTrue(loader.keepOriginalIds()); assertFalse(loader.useUserSuppliedIds()); } @Test @LoadGraphWith(MODERN) public void shouldStoreOriginalIds() throws Exception { final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .userSuppliedIds(false) .writeGraph(getWriteGraphConfiguration()).create(graph); final BulkLoader loader = getBulkLoader(blvp); assertFalse(loader.useUserSuppliedIds()); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); assertGraphEquality(graph, getWriteGraph(), v -> v.value(loader.getVertexIdProperty())); } @Test @LoadGraphWith(MODERN) public void shouldNotStoreOriginalIds() throws Exception { final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .userSuppliedIds(true) .writeGraph(getWriteGraphConfiguration()).create(graph); final BulkLoader loader = getBulkLoader(blvp); assertTrue(loader.useUserSuppliedIds()); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); assertGraphEquality(graph, getWriteGraph()); } @Test @LoadGraphWith(MODERN) public void shouldOverwriteExistingElements() throws Exception { final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .userSuppliedIds(true) .writeGraph(getWriteGraphConfiguration()).create(graph); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); // initial graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); // incremental assertGraphEquality(graph, getWriteGraph()); } @Test @LoadGraphWith(MODERN) @IgnoreEngine(TraversalEngine.Type.COMPUTER) // we can't modify the graph in computer mode public void shouldProperlyHandleMetaProperties() throws Exception { graph.traversal().V().has("name", "marko").properties("name").property("alias", "okram").iterate(); final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .userSuppliedIds(true) .writeGraph(getWriteGraphConfiguration()).create(graph); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); assertGraphEquality(graph, getWriteGraph()); } @Test @LoadGraphWith(MODERN) public void shouldUseOneTimeBulkLoader() throws Exception { for (int iteration = 1; iteration <= 2; iteration++) { final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .bulkLoader(OneTimeBulkLoader.class) .writeGraph(getWriteGraphConfiguration()).create(graph); final BulkLoader loader = getBulkLoader(blvp); assertTrue(loader instanceof OneTimeBulkLoader); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); final Graph result = getWriteGraph(); assertEquals(6 * iteration, IteratorUtils.count(result.vertices())); assertEquals(6 * iteration, IteratorUtils.count(result.edges())); result.close(); } } @Test @LoadGraphWith(MODERN) public void shouldUseOneTimeBulkLoaderWithUserSuppliedIds() throws Exception { final BulkLoaderVertexProgram blvp = BulkLoaderVertexProgram.build() .bulkLoader(OneTimeBulkLoader.class) .userSuppliedIds(true) .writeGraph(getWriteGraphConfiguration()).create(graph); final BulkLoader loader = getBulkLoader(blvp); assertTrue(loader instanceof OneTimeBulkLoader); graphProvider.getGraphComputer(graph).workers(1).program(blvp).submit().get(); final Graph result = getWriteGraph(); assertEquals(6, IteratorUtils.count(result.vertices())); assertEquals(6, IteratorUtils.count(result.edges())); result.close(); } private static void assertGraphEquality(final Graph source, final Graph target) { assertGraphEquality(source, target, Element::id); } private static void assertGraphEquality(final Graph source, final Graph target, final Function<Vertex, Object> idAccessor) { final GraphTraversalSource tg = target.traversal(); assertEquals(IteratorUtils.count(source.vertices()), IteratorUtils.count(target.vertices())); assertEquals(IteratorUtils.count(target.edges()), IteratorUtils.count(target.edges())); source.vertices().forEachRemaining(originalVertex -> { Vertex tmpVertex = null; final Iterator<Vertex> vertexIterator = target.vertices(); while (vertexIterator.hasNext()) { final Vertex v = vertexIterator.next(); if (idAccessor.apply(v).toString().equals(originalVertex.id().toString())) { tmpVertex = v; break; } } assertNotNull(tmpVertex); final Vertex clonedVertex = tmpVertex; assertEquals(IteratorUtils.count(originalVertex.edges(Direction.IN)), IteratorUtils.count(clonedVertex.edges(Direction.IN))); assertEquals(IteratorUtils.count(originalVertex.edges(Direction.OUT)), IteratorUtils.count(clonedVertex.edges(Direction.OUT))); assertEquals(originalVertex.label(), clonedVertex.label()); originalVertex.properties().forEachRemaining(originalProperty -> { VertexProperty clonedProperty = null; final Iterator<VertexProperty<Object>> vertexPropertyIterator = clonedVertex.properties(originalProperty.key()); while (vertexPropertyIterator.hasNext()) { final VertexProperty p = vertexPropertyIterator.next(); if (p.value().equals(originalProperty.value())) { clonedProperty = p; break; } } assertNotNull(clonedProperty); assertEquals(originalProperty.isPresent(), clonedProperty.isPresent()); assertEquals(originalProperty.value(), clonedProperty.value()); }); originalVertex.edges(Direction.OUT).forEachRemaining(originalEdge -> { GraphTraversal t = tg.V(clonedVertex).outE(originalEdge.label()); originalEdge.properties().forEachRemaining(p -> t.has(p.key(), p.value())); assertTrue(t.hasNext()); }); }); } }