felixcheung closed pull request #3244: [ZEPPELIN-3882] Neo4jInterpreter - Support Point and Date Types URL: https://github.com/apache/zeppelin/pull/3244
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/docs/interpreter/neo4j.md b/docs/interpreter/neo4j.md index 1b14127d52..eec9e077b1 100644 --- a/docs/interpreter/neo4j.md +++ b/docs/interpreter/neo4j.md @@ -26,6 +26,9 @@ limitations under the License. ## Overview [Neo4j](https://neo4j.com/product/) is a native graph database, designed to store and process graphs from bottom to top. +### Supported Version + +The Neo4j Interpreter supports all Neo4j versions since v3 via the official [Neo4j Java Driver](https://github.com/neo4j/neo4j-java-driver)  diff --git a/neo4j/pom.xml b/neo4j/pom.xml index b8a89ad27c..cc39fdcf10 100644 --- a/neo4j/pom.xml +++ b/neo4j/pom.xml @@ -33,9 +33,9 @@ <name>Zeppelin: Neo4j interpreter</name> <properties> - <neo4j.driver.version>1.4.3</neo4j.driver.version> - <test.neo4j.kernel.version>3.2.3</test.neo4j.kernel.version> - <neo4j.version>3.2.3</neo4j.version> + <neo4j.driver.version>1.7.1</neo4j.driver.version> + <test.neo4j.kernel.version>3.4.10</test.neo4j.kernel.version> + <neo4j.version>3.4.10</neo4j.version> <jackson.version>2.8.9</jackson.version> <interpreter.name>neo4j</interpreter.name> </properties> diff --git a/neo4j/src/main/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreter.java b/neo4j/src/main/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreter.java index bcb9d7b96a..d7f848548e 100644 --- a/neo4j/src/main/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreter.java +++ b/neo4j/src/main/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreter.java @@ -201,6 +201,20 @@ private void addValueToLine(String key, List<String> columns, List<String> line, value = val.asList(); } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.MAP())) { value = val.asMap(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.POINT())) { + value = val.asPoint(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.DATE())) { + value = val.asLocalDate(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.TIME())) { + value = val.asOffsetTime(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.LOCAL_TIME())) { + value = val.asLocalTime(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.LOCAL_DATE_TIME())) { + value = val.asLocalDateTime(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.DATE_TIME())) { + value = val.asZonedDateTime(); + } else if (val.hasType(InternalTypeSystem.TYPE_SYSTEM.DURATION())) { + value = val.asIsoDuration(); } } if (value instanceof Collection) { diff --git a/neo4j/src/test/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreterTest.java b/neo4j/src/test/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreterTest.java index 24bd5130e6..7940d5f857 100644 --- a/neo4j/src/test/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreterTest.java +++ b/neo4j/src/test/java/org/apache/zeppelin/graph/neo4j/Neo4jCypherInterpreterTest.java @@ -55,10 +55,15 @@ private static final String REL_KNOWS = "KNOWS"; private static final String CYPHER_FOREACH = - "FOREACH (x in range(1,1000) | CREATE (:%s{name: \"name\" + x, age: %s}))"; - private static final String CHPHER_UNWIND = "UNWIND range(1,1000) as x " - + "MATCH (n), (m) WHERE id(n) = x AND id(m) = toInt(rand() * 1000) " + "FOREACH (x in range(1,100) | CREATE (:%s{name: \"name\" + x, age: %s, " + + "address: point({ longitude: 56.7, latitude: 12.78, height: 8 }), " + + "birth: date('1984-04-04')}))"; + private static final String CHPHER_UNWIND = "UNWIND range(1,100) as x " + + "MATCH (n), (m) WHERE id(n) = x AND id(m) = toInt(rand() * 100) " + "CREATE (n)-[:%s]->(m)"; + + private static final String TABLE_RESULT_PREFIX = "%table "; + private static final String NETWORK_RESULT_PREFIX = "%network "; @BeforeClass public static void setUpNeo4jServer() throws Exception { @@ -73,7 +78,7 @@ public static void setUpNeo4jServer() throws Exception { public static void tearDownNeo4jServer() throws Exception { server.close(); } - + @Before public void setUpZeppelin() { Properties p = new Properties(); @@ -83,7 +88,7 @@ public void setUpZeppelin() { interpreter = new Neo4jCypherInterpreter(p); context = InterpreterContext.builder() .setInterpreterOut(new InterpreterOutput(null)) - .build();; + .build(); } @After @@ -98,14 +103,15 @@ public void testTableWithArray() { "return 'a' as colA, 'b' as colB, [1, 2, 3] as colC", context); assertEquals(Code.SUCCESS, result.code()); final String tableResult = "colA\tcolB\tcolC\n\"a\"\t\"b\"\t[1,2,3]\n"; - assertEquals(tableResult, result.toString().replace("%table ", StringUtils.EMPTY)); - + assertEquals(tableResult, result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + result = interpreter.interpret( "return 'a' as colA, 'b' as colB, [{key: \"value\"}, {key: 1}] as colC", context); assertEquals(Code.SUCCESS, result.code()); final String tableResultWithMap = "colA\tcolB\tcolC\n\"a\"\t\"b\"\t[{\"key\":\"value\"},{\"key\":1}]\n"; - assertEquals(tableResultWithMap, result.toString().replace("%table ", StringUtils.EMPTY)); + assertEquals(tableResultWithMap, result.toString().replace(TABLE_RESULT_PREFIX, + StringUtils.EMPTY)); } @Test @@ -121,10 +127,14 @@ public void testRenderTable() { interpreter.open(); InterpreterResult result = interpreter.interpret("MATCH (n:Person) " + "WHERE n.name IN ['name1', 'name2', 'name3'] " - + "RETURN n.name AS name, n.age AS age", context); + + "RETURN n.name AS name, n.age AS age, " + + "n.address AS address, n.birth AS birth", context); assertEquals(Code.SUCCESS, result.code()); - final String tableResult = "name\tage\n\"name1\"\t1\n\"name2\"\t2\n\"name3\"\t3\n"; - assertEquals(tableResult, result.toString().replace("%table ", StringUtils.EMPTY)); + final String tableResult = "name\tage\taddress\tbirth\n" + + "\"name1\"\t1\tPoint{srid=4979, x=56.7, y=12.78, z=8.0}\t1984-04-04\n" + + "\"name2\"\t2\tPoint{srid=4979, x=56.7, y=12.78, z=8.0}\t1984-04-04\n" + + "\"name3\"\t3\tPoint{srid=4979, x=56.7, y=12.78, z=8.0}\t1984-04-04\n"; + assertEquals(tableResult, result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); } @Test @@ -136,7 +146,7 @@ public void testRenderMap() { final String objectListKey = "object.listKey"; InterpreterResult result = interpreter.interpret(jsonQuery, context); assertEquals(Code.SUCCESS, result.code()); - String[] rows = result.toString().replace("%table ", StringUtils.EMPTY) + String[] rows = result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY) .split(Neo4jCypherInterpreter.NEW_LINE); assertEquals(rows.length, 2); List<String> header = Arrays.asList(rows[0].split(Neo4jCypherInterpreter.TAB)); @@ -153,7 +163,7 @@ public void testRenderMap() { + "AS array UNWIND array AS object RETURN object"; result = interpreter.interpret(query, context); assertEquals(Code.SUCCESS, result.code()); - rows = result.toString().replace("%table ", StringUtils.EMPTY) + rows = result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY) .split(Neo4jCypherInterpreter.NEW_LINE); assertEquals(rows.length, 3); header = Arrays.asList(rows[0].split(Neo4jCypherInterpreter.TAB)); @@ -175,7 +185,7 @@ public void testRenderMap() { + "AS array UNWIND array AS object RETURN object"; result = interpreter.interpret(jsonListWithNullQuery, context); assertEquals(Code.SUCCESS, result.code()); - rows = result.toString().replace("%table ", StringUtils.EMPTY) + rows = result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY) .split(Neo4jCypherInterpreter.NEW_LINE); assertEquals(rows.length, 3); header = Arrays.asList(rows[0].split(Neo4jCypherInterpreter.TAB, -1)); @@ -191,13 +201,13 @@ public void testRenderMap() { assertEquals(row.get(header.indexOf(objectKey)), "value2"); assertEquals(row.get(header.indexOf(objectListKey)), "[{\"inner\":\"Map1\"},{\"inner\":\"Map2\"}]"); - + final String jsonListWithoutListKeyQuery = "WITH [{key: \"value\"}," + "{key: \"value2\", listKey: [{inner: \"Map1\"}, {inner: \"Map2\"}]}] " + "AS array UNWIND array AS object RETURN object"; result = interpreter.interpret(jsonListWithoutListKeyQuery, context); assertEquals(Code.SUCCESS, result.code()); - rows = result.toString().replace("%table ", StringUtils.EMPTY) + rows = result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY) .split(Neo4jCypherInterpreter.NEW_LINE); assertEquals(rows.length, 3); header = Arrays.asList(rows[0].split(Neo4jCypherInterpreter.TAB, -1)); @@ -219,7 +229,7 @@ public void testRenderNetwork() { interpreter.open(); InterpreterResult result = interpreter.interpret( "MATCH (n)-[r:KNOWS]-(m) RETURN n, r, m LIMIT 1", context); - GraphResult.Graph graph = gson.fromJson(result.toString().replace("%network ", + GraphResult.Graph graph = gson.fromJson(result.toString().replace(NETWORK_RESULT_PREFIX, StringUtils.EMPTY), GraphResult.Graph.class); assertEquals(2, graph.getNodes().size()); assertEquals(true, graph.getNodes().iterator().next().getLabel().equals(LABEL_PERSON)); @@ -248,4 +258,65 @@ public void testFallingQuery() { context); assertEquals(Code.ERROR, result.code()); } + + @Test + public void testDates() { + InterpreterResult result = interpreter.interpret( + "RETURN datetime('2015-06-24T12:50:35.556+0100') AS theDateTime", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theDateTime\n2015-06-24T12:50:35.556+01:00\n", result.toString() + .replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + + result = interpreter.interpret("RETURN localdatetime('2015185T19:32:24') AS theLocalDateTime", + context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theLocalDateTime\n2015-07-04T19:32:24\n", result.toString() + .replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + + result = interpreter.interpret("RETURN date('+2015-W13-4') AS theDate", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theDate\n2015-03-26\n", result.toString() + .replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + + result = interpreter.interpret("RETURN time('125035.556+0100') AS theTime", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theTime\n12:50:35.556+01:00\n", result.toString().replace(TABLE_RESULT_PREFIX, + StringUtils.EMPTY)); + + result = interpreter.interpret("RETURN localtime('12:50:35.556') AS theLocalTime", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theLocalTime\n12:50:35.556\n", result.toString() + .replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + } + + @Test + public void testDuration() { + InterpreterResult result = interpreter.interpret( + "RETURN duration('P14DT16H12M') AS theDuration", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("theDuration\nP0M14DT58320S\n", result.toString() + .replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + } + + @Test + public void testPoint() { + InterpreterResult result = interpreter.interpret("RETURN point({ x:3, y:0 }) AS cartesian_2d," + + "point({ x:0, y:4, z:1 }) AS cartesian_3d," + + "point({ latitude: 12, longitude: 56 }) AS geo_2d," + + "point({ latitude: 12, longitude: 56, height: 1000 }) AS geo_3d", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("cartesian_2d\tcartesian_3d\tgeo_2d\tgeo_3d\n" + + "Point{srid=7203, x=3.0, y=0.0}\tPoint{srid=9157, x=0.0, y=4.0, z=1.0}\t" + + "Point{srid=4326, x=56.0, y=12.0}\tPoint{srid=4979, x=56.0, y=12.0, z=1000.0}\n", + result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + + result = interpreter.interpret( + "WITH point({ latitude: 12, longitude: 56, height: 1000 }) AS geo_3d " + + "RETURN geo_3d.latitude AS latitude, geo_3d.longitude AS longitude, " + + "geo_3d.height AS height", context); + assertEquals(Code.SUCCESS, result.code()); + assertEquals("latitude\tlongitude\theight\n" + + "12.0\t56.0\t1000.0\n", + result.toString().replace(TABLE_RESULT_PREFIX, StringUtils.EMPTY)); + } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services