TINKERPOP-2006 Minor refactoring following merge of #905 Added a new test for duplicate edge/vertex property keys and reverted the normalized classic graph data set
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/31deab21 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/31deab21 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/31deab21 Branch: refs/heads/master Commit: 31deab2133c8ec02ff9e2f62cf2ec47ce841b289 Parents: f705623 Author: Stephen Mallette <[email protected]> Authored: Tue Aug 28 13:42:25 2018 -0400 Committer: Stephen Mallette <[email protected]> Committed: Tue Aug 28 13:42:25 2018 -0400 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + .../structure/io/graphml/GraphMLWriter.java | 13 +- .../tinkerpop/gremlin/structure/io/IoTest.java | 121 +++++++++++++++++-- .../io/graphml/tinkerpop-classic-normalized.xml | 4 - 4 files changed, 120 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/31deab21/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index cbb4b21..9e9d4f3 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -30,6 +30,7 @@ This release also includes changes from <<release-3-3-3, 3.3.3>>. * Added the `io()` start step and `read()` and `write()` termination steps to the Gremlin language. * Added `GraphFeatures.supportsIoRead()` and `GraphFeatures.supportsIoWrite()`. * Deprecated `Graph.io()` and related infrastructure. +* `GraphMLReader` better handles edge and vertex properties with the same name. * Bumped to Netty 4.1.25. * Bumped to Spark 2.3.1. * Deprecated two `submit()`-related methods on the Java driver `Client` class. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/31deab21/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java index 53c5c12..cc66d37 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -65,7 +66,7 @@ public final class GraphMLWriter implements GraphWriter { private final Optional<String> xmlSchemaLocation; private final String edgeLabelKey; private final String vertexLabelKey; - private Collection<String> intersection; + private Collection<String> intersection = Collections.emptySet(); private GraphMLWriter(final boolean normalize, final Map<String, String> vertexKeyTypes, final Map<String, String> edgeKeyTypes, final String xmlSchemaLocation, @@ -76,7 +77,6 @@ public final class GraphMLWriter implements GraphWriter { this.xmlSchemaLocation = Optional.ofNullable(xmlSchemaLocation); this.edgeLabelKey = edgeLabelKey; this.vertexLabelKey = vertexLabelKey; - this.intersection = null; } /** @@ -224,13 +224,10 @@ public final class GraphMLWriter implements GraphWriter { final Collection<String> edgeKeySet = getEdgeKeysAndNormalizeIfRequired(identifiedEdgeKeyTypes); // in case vertex and edge may have the same attribute name, the key id in graphml have to be different intersection = CollectionUtils.intersection(vertexKeySet, edgeKeySet); - // speeding-up later checks - if (intersection.isEmpty()) { - intersection = null; - } + for (String key : vertexKeySet) { writer.writeStartElement(GraphMLTokens.KEY); - if (intersection != null && intersection.contains(key)) { + if (intersection.contains(key)) { writer.writeAttribute(GraphMLTokens.ID, key.concat(GraphMLTokens.VERTEX_SUFFIX)); } else { writer.writeAttribute(GraphMLTokens.ID, key); @@ -242,7 +239,7 @@ public final class GraphMLWriter implements GraphWriter { } for (String key : edgeKeySet) { writer.writeStartElement(GraphMLTokens.KEY); - if (intersection != null && intersection.contains(key)) { + if (intersection.contains(key)) { writer.writeAttribute(GraphMLTokens.ID, key.concat(GraphMLTokens.EDGE_SUFFIX)); } else { writer.writeAttribute(GraphMLTokens.ID, key); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/31deab21/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java index 729ede7..174de76 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java @@ -98,7 +98,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; - /** * @author Joshua Shinavier (http://fortytwo.net) * @author Stephen Mallette (http://stephen.genoprime.com) @@ -108,7 +107,88 @@ import static org.junit.Assume.assumeThat; public class IoTest { private static final Logger logger = LoggerFactory.getLogger(IoTest.class); + private static final String CLASSIC_GRAPH_WITH_COLOR = "<?xml version=\"1.0\" ?>\n" + + "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd\">\n" + + " <key id=\"age\" for=\"node\" attr.name=\"age\" attr.type=\"int\"></key>\n" + + " <key id=\"colorV\" for=\"node\" attr.name=\"color\" attr.type=\"string\"></key>\n" + + " <key id=\"labelV\" for=\"node\" attr.name=\"labelV\" attr.type=\"string\"></key>\n" + + " <key id=\"lang\" for=\"node\" attr.name=\"lang\" attr.type=\"string\"></key>\n" + + " <key id=\"name\" for=\"node\" attr.name=\"name\" attr.type=\"string\"></key>\n" + + " <key id=\"colorE\" for=\"edge\" attr.name=\"color\" attr.type=\"string\"></key>\n" + + " <key id=\"labelE\" for=\"edge\" attr.name=\"labelE\" attr.type=\"string\"></key>\n" + + " <key id=\"weight\" for=\"edge\" attr.name=\"weight\" attr.type=\"float\"></key>\n" + + " <graph id=\"G\" edgedefault=\"directed\">\n" + + " <node id=\"1\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">29</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">marko</data>\n" + + " </node>\n" + + " <node id=\"2\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">27</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">vadas</data>\n" + + " </node>\n" + + " <node id=\"3\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"lang\">java</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">lop</data>\n" + + " </node>\n" + + " <node id=\"4\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">32</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">josh</data>\n" + + " </node>\n" + + " <node id=\"5\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"lang\">java</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">ripple</data>\n" + + " </node>\n" + + " <node id=\"6\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">35</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">peter</data>\n" + + " </node>\n" + + " <edge id=\"10\" source=\"4\" target=\"5\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">1.0</data>\n" + + " </edge>\n" + + " <edge id=\"11\" source=\"4\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.4</data>\n" + + " </edge>\n" + + " <edge id=\"12\" source=\"6\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.2</data>\n" + + " </edge>\n" + + " <edge id=\"7\" source=\"1\" target=\"2\">\n" + + " <data key=\"labelE\">knows</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.5</data>\n" + + " </edge>\n" + + " <edge id=\"8\" source=\"1\" target=\"4\">\n" + + " <data key=\"labelE\">knows</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">1.0</data>\n" + + " </edge>\n" + + " <edge id=\"9\" source=\"1\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.4</data>\n" + + " </edge>\n" + + " </graph>\n" + + "</graphml>"; + public static class GraphMLTest extends AbstractGremlinTest { + @Test @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES) @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES) @@ -206,6 +286,39 @@ public class IoTest { assertEquals(2, IteratorUtils.count(graph.vertices())); } + @Test + @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES) + @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_REMOVE_EDGES) + @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES) + @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_REMOVE_VERTICES) + @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_STRING_VALUES) + @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_INTEGER_VALUES) + @FeatureRequirement(featureClass = EdgePropertyFeatures.class, feature = EdgePropertyFeatures.FEATURE_FLOAT_VALUES) + @FeatureRequirement(featureClass = EdgePropertyFeatures.class, feature = EdgePropertyFeatures.FEATURE_STRING_VALUES) + public void shouldReadGraphMLWithCommonVertexAndEdgePropertyNames() throws IOException { + final GraphReader reader = GraphMLReader.build().create(); + try (final InputStream stream = new ByteArrayInputStream(CLASSIC_GRAPH_WITH_COLOR.getBytes("UTF-8"))) { + reader.readGraph(stream, graph); + } + + // there is also a "color" property on this dataset that is on both edges and vertices + graph.vertices().forEachRemaining(v -> assertEquals("#6495ed", v.value("color"))); + graph.edges().forEachRemaining(e -> assertEquals("#ee0000", e.value("color"))); + + final GraphWriter writer = GraphMLWriter.build().create(); + try (final OutputStream out = new ByteArrayOutputStream()) { + writer.writeGraph(out, graph); + + graph.vertices().forEachRemaining(Element::remove); + try (final InputStream stream = new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray())) { + reader.readGraph(stream, graph); + } + + // there is also a "color" property on this dataset that is on both edges and vertices + graph.vertices().forEachRemaining(v -> assertEquals("#6495ed", v.value("color"))); + graph.edges().forEachRemaining(e -> assertEquals("#ee0000", e.value("color"))); + } + } @Test(expected = NumberFormatException.class) @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES) @@ -239,12 +352,6 @@ public class IoTest { public void shouldWriteNormalizedGraphML() throws Exception { try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { final GraphMLWriter w = GraphMLWriter.build().normalize(true).create(); - final Vertex v = graph.vertices().next(); - // adding 'color' property to vertex - v.property(VertexProperty.Cardinality.single, "color", "#6495ed"); - final Edge e = graph.edges().next(); - // adding 'color' property to edge - e.property("color", "#ee0000"); w.writeGraph(bos, graph); final String expected = streamToString(IoTest.class.getResourceAsStream(TestHelper.convertPackageToResourcePath(GraphMLResourceAccess.class) + "tinkerpop-classic-normalized.xml")); assertEquals(expected.replace("\n", "").replace("\r", ""), bos.toString().replace("\n", "").replace("\r", "")); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/31deab21/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-normalized.xml ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-normalized.xml b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-normalized.xml index 45d63c1..19896d9 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-normalized.xml +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-normalized.xml @@ -1,18 +1,15 @@ <?xml version="1.0" ?> <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd"> <key id="age" for="node" attr.name="age" attr.type="int"></key> - <key id="colorV" for="node" attr.name="color" attr.type="string"></key> <key id="labelV" for="node" attr.name="labelV" attr.type="string"></key> <key id="lang" for="node" attr.name="lang" attr.type="string"></key> <key id="name" for="node" attr.name="name" attr.type="string"></key> - <key id="colorE" for="edge" attr.name="color" attr.type="string"></key> <key id="labelE" for="edge" attr.name="labelE" attr.type="string"></key> <key id="weight" for="edge" attr.name="weight" attr.type="float"></key> <graph id="G" edgedefault="directed"> <node id="1"> <data key="labelV">vertex</data> <data key="age">29</data> - <data key="colorV">#6495ed</data> <data key="name">marko</data> </node> <node id="2"> @@ -54,7 +51,6 @@ </edge> <edge id="7" source="1" target="2"> <data key="labelE">knows</data> - <data key="colorE">#ee0000</data> <data key="weight">0.5</data> </edge> <edge id="8" source="1" target="4">
