You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/05/06 14:26:49 UTC

incubator-tinkerpop git commit: Provides a fix for TINKERPOP3-660 with the GraphMLReader.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master dcead316c -> da90fd5b9


Provides a fix for TINKERPOP3-660 with the GraphMLReader.

GraphMLReader was not able to properly read <edge> elements before <node> elements.  The <edge> would create/cache the vertex, but then when the <node> came along it would only find it in the cache and not set the properties.  Note that this comes with a limitation that the vertex label will not be set if the <edge> comes before the <vertex> as per the TinkerPop contract that vertex labels can not be changed.  That limitation has been documented.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/da90fd5b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/da90fd5b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/da90fd5b

Branch: refs/heads/master
Commit: da90fd5b97caa4ddeb6752faae6f5d5425051c20
Parents: dcead31
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed May 6 08:23:38 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed May 6 08:23:38 2015 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 docs/src/the-graph.asciidoc                     |  2 ++
 .../structure/io/graphml/GraphMLReader.java     | 20 +++++++++++++++-----
 .../tinkerpop/gremlin/structure/IoTest.java     | 18 ++++++++++++++----
 .../io/graphml/tinkerpop-classic-unordered.xml  |  1 +
 5 files changed, 33 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/da90fd5b/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index f4fae8b..4203262 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::http://www.tinkerpop.com/docs/current/images/gremlin-hindu.png[width=225]
 TinkerPop 3.0.0.M9 (NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed bug in `GraphML` reader that was not allowing `<edge>` elements to come before `<node>` elements as allowable by the GraphML specification.
 * Added `VertexFeature.getCardinality`.
 * Added `AdjacentToIncidentStrategy` which rewrites `out().count()` to `outE().count()` (and similar such patterns).
 * `GryoPool` now takes a `Configuration` object which allows setting the size of the pool and the `IoRegistry` instance.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/da90fd5b/docs/src/the-graph.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/the-graph.asciidoc b/docs/src/the-graph.asciidoc
index 88a5127..aeefbea 100644
--- a/docs/src/the-graph.asciidoc
+++ b/docs/src/the-graph.asciidoc
@@ -269,6 +269,8 @@ As GraphML is a specification for the serialization of an entire graph and not t
 
 CAUTION: GraphML is a "lossy" format in that it only supports primitive values for properties and does not have support for `Graph` variables.  It will use `toString` to serialize property values outside of those primitives.
 
+CAUTION: GraphML, as a specification, allows for `<edge>` and `<node>` elements to appear in any order.  The `GraphMLReader` will support that, however, that capability comes with a limitation. TinkerPop does not allow the vertex label to be changed after the vertex has been created.  Therefore, if an `<edge>` element comes before the `<node>` the label on the vertex will be ignored.  It is thus better to order `<node>` elements in the GraphML to appear before all `<edge>` elements if vertex labels are important to the graph.
+
 The following code shows how to write a `Graph` instance to file called `tinkerpop-modern.xml` and then how to read that file back into a different instance:
 
 [source,java]

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/da90fd5b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
index 6a50679..f8d3aee 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
@@ -123,8 +123,8 @@ public class GraphMLReader implements GraphReader {
                             // graphml allows edges and vertices to be mixed in terms of how they are positioned
                             // in the xml therefore it is possible that an edge is created prior to its definition
                             // as a vertex.
-                            edgeOutVertex = findOrCreate(vertexIdOut, graphToWriteTo, supportsVertexIds, cache);
-                            edgeInVertex = findOrCreate(vertexIdIn, graphToWriteTo, supportsVertexIds, cache);
+                            edgeOutVertex = findOrCreate(vertexIdOut, graphToWriteTo, supportsVertexIds, cache, false);
+                            edgeInVertex = findOrCreate(vertexIdIn, graphToWriteTo, supportsVertexIds, cache, false);
 
                             if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                                 graphToWriteTo.tx().commit();
@@ -163,7 +163,7 @@ public class GraphMLReader implements GraphReader {
                         final String currentVertexLabel = Optional.ofNullable(vertexLabel).orElse(Vertex.DEFAULT_LABEL);
                         final Object[] propsAsArray = vertexProps.entrySet().stream().flatMap(e -> Stream.of(e.getKey(), e.getValue())).toArray();
 
-                        findOrCreate(currentVertexId, graphToWriteTo, supportsVertexIds, cache, ElementHelper.upsert(propsAsArray, T.label, currentVertexLabel));
+                        findOrCreate(currentVertexId, graphToWriteTo, supportsVertexIds, cache, true, ElementHelper.upsert(propsAsArray, T.label, currentVertexLabel));
 
                         if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                             graphToWriteTo.tx().commit();
@@ -278,9 +278,19 @@ public class GraphMLReader implements GraphReader {
     }
 
     private static Vertex findOrCreate(final Object id, final Graph graphToWriteTo, final boolean supportsIds,
-                                       final Map<Object,Vertex> cache, final Object... args) {
+                                       final Map<Object,Vertex> cache, final boolean asVertex, final Object... args) {
         if (cache.containsKey(id)) {
-            return cache.get(id);
+            // if the request to findOrCreate come from a vertex then AND the vertex was already created, that means
+            // that the vertex was created by an edge that arrived first in the stream (allowable via GraphML
+            // specification).  as the edge only carries the vertex id and not its properties, the properties
+            // of the vertex need to be attached at this point.
+            if (asVertex) {
+                final Vertex v = cache.get(id);
+                ElementHelper.attachProperties(v, args);
+                return v;
+            } else {
+                return cache.get(id);
+            }
         } else {
             final Object [] argsReady = supportsIds ? ElementHelper.upsert(args, T.id, id) : args;
             final Vertex v = graphToWriteTo.addVertex(argsReady);

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/da90fd5b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/IoTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/IoTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/IoTest.java
index 697b499..cbc3473 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/IoTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/IoTest.java
@@ -121,7 +121,18 @@ public class IoTest extends AbstractGremlinTest {
     @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_INTEGER_VALUES)
     @FeatureRequirement(featureClass = EdgePropertyFeatures.class, feature = EdgePropertyFeatures.FEATURE_FLOAT_VALUES)
     public void shouldReadGraphML() throws IOException {
-        readGraphMLIntoGraph(graph);
+        readGraphMLIntoGraph(graph, "tinkerpop-classic.xml");
+        assertClassicGraph(graph, false, true);
+    }
+
+    @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)
+    @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)
+    public void shouldReadGraphMLUnorderedElements() throws IOException {
+        readGraphMLIntoGraph(graph, "tinkerpop-classic-unordered.xml");
         assertClassicGraph(graph, false, true);
     }
 
@@ -2368,10 +2379,9 @@ public class IoTest extends AbstractGremlinTest {
         validator.validate(xmlFile);
     }
 
-    private static void readGraphMLIntoGraph(final Graph g) throws IOException {
+    private static void readGraphMLIntoGraph(final Graph g, final String file) throws IOException {
         final GraphReader reader = GraphMLReader.build().create();
-        final String y = TestHelper.convertPackageToResourcePath(GraphMLResourceAccess.class);
-        try (final InputStream stream = IoTest.class.getResourceAsStream(TestHelper.convertPackageToResourcePath(GraphMLResourceAccess.class) + "tinkerpop-classic.xml")) {
+        try (final InputStream stream = IoTest.class.getResourceAsStream(TestHelper.convertPackageToResourcePath(GraphMLResourceAccess.class) + file)) {
             reader.readGraph(stream, g);
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/da90fd5b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-unordered.xml
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-unordered.xml b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-unordered.xml
new file mode 100644
index 0000000..04867ba
--- /dev/null
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphml/tinkerpop-classic-unordered.xml
@@ -0,0 +1 @@
+<?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="labelV" for="node" attr.name="labelV" attr.type="string"></key><key id="name" for="node" attr.name="name" attr.type="string"></key><key id="lang" for="node" attr.name="lang" attr.type="string"></key><key id="age" for="node" attr.name="age" attr.type="int"></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"><edge id="12" source="6" target="3"><data key="labelE">created</data><data key="weight">0.2</data></edge><node id="1"><data key="labelV">vertex</data><data key="name">marko</data><data key="age">29</data></node><node id="2"><data key="labelV">vertex</data><data key="name">vadas</data><data key="age">2
 7</data></node><edge id="11" source="4" target="3"><data key="labelE">created</data><data key="weight">0.4</data></edge><node id="3"><data key="labelV">vertex</data><data key="name">lop</data><data key="lang">java</data></node><node id="4"><data key="labelV">vertex</data><data key="name">josh</data><data key="age">32</data></node><edge id="10" source="4" target="5"><data key="labelE">created</data><data key="weight">1.0</data></edge><node id="5"><data key="labelV">vertex</data><data key="name">ripple</data><data key="lang">java</data></node><node id="6"><data key="labelV">vertex</data><data key="name">peter</data><data key="age">35</data></node><edge id="7" source="1" target="2"><data key="labelE">knows</data><data key="weight">0.5</data></edge><edge id="8" source="1" target="4"><data key="labelE">knows</data><data key="weight">1.0</data></edge><edge id="9" source="1" target="3"><data key="labelE">created</data><data key="weight">0.4</data></edge></graph></graphml>
\ No newline at end of file