第 18 章 REST API
The Neo4j REST API is designed with discoverability in mind, so that you can start with a GETon the 第 18.1 节 “Service root”and from there discover URIs to perform other requests. The examples below uses URIs in the examples; they are subject to change in the future, so for future-proofness discover URIs where possible, instead of relying on the current layout. The default representation is json, both for responses and for data sent with POST/PUTrequests.
Below follows a listing of ways to interact with the REST API. For language bindings to the REST API, see 第 5 章 Neo4j远程客户端库.
To interact with the JSON interface you must explicitly set the request header Accept:application/jsonfor those requests that responds with data. You should also set the header Content-Type:application/jsonif your request sends data, for example when you’re creating a relationship. The examples include the relevant request and response headers.
The server supports streaming results, with better performance and lower memory overhead. See 第 18.2 节 “Streaming”for more information.
18.1. Service root
18.1.1. Get service root
The service root is your starting point to discover the REST API. It contains the basic starting points for the database, and some version and extension information. The reference_nodeentry will only be present if there is a reference node set and that node actually exists in the database.
图 18.1. Final Graph
Example request
- GEThttp://localhost:7474/db/data/
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "extensions": { }, "node": "http://localhost:7474/db/data/node", "reference_node": "http://localhost:7474/db/data/node/193", "node_index": "http://localhost:7474/db/data/index/node", "relationship_index": "http://localhost:7474/db/data/index/relationship", "extensions_info": "http://localhost:7474/db/data/ext", "relationship_types": "http://localhost:7474/db/data/relationship/types", "batch": "http://localhost:7474/db/data/batch", "cypher": "http://localhost:7474/db/data/cypher", "neo4j_version": "1.8.M07-98-ge9ef235" } |
18.2. Streaming
The whole REST API can be transmitted as JSON streams, resulting in better performance and lower memory overhead on the server side. To use it, adjust the request headers for every call, see the example below for details.
小心 | |
This feature is new, and you should make yourself comfortable with the streamed response style versus the non-streamed API where results are delivered in a single large response. Expect future releases to have streaming enabled by default since it is a far more efficient mechanism for both client and server. |
图 18.2. Final Graph
Example request
- GEThttp://localhost:7474/db/data/
- Accept:application/json
- X-Stream:true
Example response
- 200:OK
- Content-Type:application/json; stream=true
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "extensions": { }, "node": "http://localhost:7474/db/data/node", "reference_node": "http://localhost:7474/db/data/node/195", "node_index": "http://localhost:7474/db/data/index/node", "relationship_index": "http://localhost:7474/db/data/index/relationship", "extensions_info": "http://localhost:7474/db/data/ext", "relationship_types": "http://localhost:7474/db/data/relationship/types", "batch": "http://localhost:7474/db/data/batch", "cypher": "http://localhost:7474/db/data/cypher", "neo4j_version": "1.8.M07-98-ge9ef235" } |
18.3. Cypher queries
18.3.1. Send queries with parameters
The Neo4j REST API allows querying with Cypher, see 第 15 章 Cypher查询语言. The results are returned as a list of string headers (columns), and a datapart, consisting of a list of all rows, every row consisting of a list of REST representations of the field value — Node, Relationship, Pathor any simple value like String.
提示 | |
In order to speed up queries in repeated scenarios, try not to use literals but replace them with parameters wherever possible in order to let the server cache query plans, see 第 18.3.1 节 “Send queries with parameters”for details. |
18.3.1. Send queries with parameters
Cypher supports queries with parameters which are submitted as a JSON map.
1 2 3 4 | STARTx = node:node_auto_index(name={startName}) MATCHpath = (x-[r]-friend) WHEREfriend.name = {name} RETURNTYPE(r) |
图 18.3. Final Graph
Example request
- POSThttp://localhost:7474/db/data/cypher
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "query": "start x = node:node_auto_index(name={startName}) match path = (x-[r]-friend) where friend.name = {name} return TYPE(r)", "params": { "startName": "I", "name": "you" } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "TYPE(r)"], "data": [ [ "know"] ] } |
18.3.2. Send a Query
A simple query returning all nodes connected to node 1, returning the node and the name property, if it exists, otherwise null:
1 2 3 | STARTx = node(10) MATCHx -[r]-> n RETURNtype(r), n.name?, n.age? |
图 18.4. Final Graph
Example request
- POSThttp://localhost:7474/db/data/cypher
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(10) match x -[r]-> n return type(r), n.name?, n.age?", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "type(r)", "n.name?", "n.age?"], "data": [ [ "know", "him", 25 ], [ "know", "you", null] ] } |
18.3.3. Return paths
Paths can be returned together with other return types by just specifying returns.
1 2 3 | STARTx = node(17) MATCHpath = (x--friend) RETURNpath, friend.name |
图 18.5. Final Graph
Example request
- POSThttp://localhost:7474/db/data/cypher
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(17) match path = (x--friend) return path, friend.name", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 | { "columns": [ "path", "friend.name"], "data": [ [ { "start": "http://localhost:7474/db/data/node/17", "nodes": [ "http://localhost:7474/db/data/node/17", "http://localhost:7474/db/data/node/16"], "length": 1, "relationships": [ "http://localhost:7474/db/data/relationship/9"], "end": "http://localhost:7474/db/data/node/16" }, "you"] ] } |
18.3.4. Nested results
When sending queries that return nested results like list and maps, these will get serialized into nested JSON representations according to their types.
1 2 | STARTn = node(26,25) RETURNcollect(n.name) |
图 18.6. Final Graph
Example request
- POSThttp://localhost:7474/db/data/cypher
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start n = node(26,25) return collect(n.name)", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "collect(n.name)"], "data": [ [ [ "I", "you"] ] ] } |
18.3.5. Server errors
Errors on the server will be reported as a JSON-formatted stacktrace and message.
1 2 | STARTx = node(15) RETURNx.dummy |
图 18.7. Final Graph
Example request
- POSThttp://localhost:7474/db/data/cypher
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(15) return x.dummy", "params": { } } |
Example response
- 400:Bad Request
- Content-Type:application/json
1 2 3 4 5 | { "message": "The property 'dummy' does not exist on Node[15]", "exception": "BadInputException", "stacktrace": [ "org.neo4j.server.rest.repr.RepresentationExceptionHandlingIterable.exceptionOnHasNext(RepresentationExceptionHandlingIterable.java:51)", "org.neo4j.helpers.collection.ExceptionHandlingIterable$1.hasNext(ExceptionHandlingIterable.java:61)", "org.neo4j.helpers.collection.IteratorWrapper.hasNext(IteratorWrapper.java:42)", "org.neo4j.server.rest.repr.ListRepresentation.serialize(ListRepresentation.java:58)", "org.neo4j.server.rest.repr.Serializer.serialize(Serializer.java:75)", "org.neo4j.server.rest.repr.MappingSerializer.putList(MappingSerializer.java:61)", "org.neo4j.server.rest.repr.CypherResultRepresentation.serialize(CypherResultRepresentation.java:50)", "org.neo4j.server.rest.repr.MappingRepresentation.serialize(MappingRepresentation.java:42)", "org.neo4j.server.rest.repr.OutputFormat.format(OutputFormat.java:170)", "org.neo4j.server.rest.repr.OutputFormat.formatRepresentation(OutputFormat.java:120)", "org.neo4j.server.rest.repr.OutputFormat.response(OutputFormat.java:107)", "org.neo4j.server.rest.repr.OutputFormat.ok(OutputFormat.java:55)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:80)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.4. Nodes
18.4.1. Create Node
图 18.8. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node
- Accept:application/json
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/node/26
18.4.2. Create Node with properties
图 18.9. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "foo": "bar" } |
Example response
- 201:Created
- Content-Length:1108
- Content-Type:application/json
- Location:http://localhost:7474/db/data/node/27
18.4.3. Get node
Note that the response contains URI/templates for the available operations for getting properties and relationships.
图 18.10. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/199
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.4.4. Get non-existent node
图 18.11. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/20300000
- Accept:application/json
Example response
- 404:Not Found
- Content-Type:application/json
1 2 3 4 5 | { "message": "Cannot find node with id [20300000] in database.", "exception": "NodeNotFoundException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.node(DatabaseActions.java:123)", "org.neo4j.server.rest.web.DatabaseActions.getNode(DatabaseActions.java:234)", "org.neo4j.server.rest.web.RestfulGraphDatabase.getNode(RestfulGraphDatabase.java:225)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.4.5. Delete node
图 18.12. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/node/35
- Accept:application/json
Example response
- 204:No Content
1 |
18.4.6. Nodes with relationships can not be deleted
The relationships on a node has to be deleted before the node can be deleted.
图 18.13. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/node/36
- Accept:application/json
Example response
- 409:Conflict
- Content-Type:application/json
1 2 3 4 5 | { "message": "The node with id 36 cannot be deleted. Check that the node is orphaned before deletion.", "exception": "OperationFailureException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.deleteNode(DatabaseActions.java:255)", "org.neo4j.server.rest.web.RestfulGraphDatabase.deleteNode(RestfulGraphDatabase.java:239)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.5. Relationships
Relationships are a first class citizen in the Neo4j REST API. They can be accessed either stand-alone or through the nodes they are attached to.
The general pattern to get relationships from a node is:
1 | GET http://localhost:7474/db/data/node/123/relationships/{dir}/{-list|&|types} |
Where diris one of all, in, outand typesis an ampersand-separated list of types. See the examples below for more information.
18.5.1. Get Relationship by ID
图 18.14. Final Graph
Example request
- GEThttp://localhost:7474/db/data/relationship/20
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 | { "extensions": { }, "start": "http://localhost:7474/db/data/node/44", "property": "http://localhost:7474/db/data/relationship/20/properties/{key}", "self": "http://localhost:7474/db/data/relationship/20", "properties": "http://localhost:7474/db/data/relationship/20/properties", "type": "know", "end": "http://localhost:7474/db/data/node/43", "data": { } } |
18.5.2. Create relationship
Upon successful creation of a relationship, the new relationship is returned.
图 18.15. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/66/relationships
- Accept:application/json
- Content-Type:application/json
1 2 3 4 | { "to": "http://localhost:7474/db/data/node/65", "type": "LOVES" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/relationship/35
1 2 3 4 5 6 7 8 9 10 11 12 | { "extensions": { }, "start": "http://localhost:7474/db/data/node/66", "property": "http://localhost:7474/db/data/relationship/35/properties/{key}", "self": "http://localhost:7474/db/data/relationship/35", "properties": "http://localhost:7474/db/data/relationship/35/properties", "type": "LOVES", "end": "http://localhost:7474/db/data/node/65", "data": { } } |
18.5.3. Create a relationship with properties
Upon successful creation of a relationship, the new relationship is returned.
图 18.16. Starting Graph
图 18.17. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/68/relationships
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "to": "http://localhost:7474/db/data/node/67", "type": "LOVES", "data": { "foo": "bar" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/relationship/37
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "extensions": { }, "start": "http://localhost:7474/db/data/node/68", "property": "http://localhost:7474/db/data/relationship/37/properties/{key}", "self": "http://localhost:7474/db/data/relationship/37", "properties": "http://localhost:7474/db/data/relationship/37/properties", "type": "LOVES", "end": "http://localhost:7474/db/data/node/67", "data": { "foo": "bar" } } |
18.5.4. Delete relationship
图 18.18. Starting Graph
图 18.19. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/26
- Accept:application/json
Example response
- 204:No Content
1 |
18.5.5. Get all properties on a relationship
图 18.20. Final Graph
Example request
- GEThttp://localhost:7474/db/data/relationship/30/properties
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "since": "1day", "cost": "high" } |
18.5.6. Set all properties on a relationship
图 18.21. Starting Graph
图 18.22. Final Graph
Example request
- PUThttp://localhost:7474/db/data/relationship/29/properties
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "happy": false } |
Example response
- 204:No Content
1 |
18.5.7. Get single property on a relationship
图 18.23. Final Graph
Example request
- GEThttp://localhost:7474/db/data/relationship/27/properties/cost
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 | "high" |
18.5.8. Set single property on a relationship
图 18.24. Starting Graph
图 18.25. Final Graph
Example request
- PUThttp://localhost:7474/db/data/relationship/28/properties/cost
- Accept:application/json
- Content-Type:application/json
1 | "deadly" |
Example response
- 204:No Content
1 |
18.5.9. Get all relationships
图 18.26. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/25/relationships/all
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.5.10. Get incoming relationships
图 18.27. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/35/relationships/in
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 | [ { "start": "http://localhost:7474/db/data/node/37", "data": { }, "self": "http://localhost:7474/db/data/relationship/16", "property": "http://localhost:7474/db/data/relationship/16/properties/{key}", "properties": "http://localhost:7474/db/data/relationship/16/properties", "type": "LIKES", "extensions": { }, "end": "http://localhost:7474/db/data/node/35" } ] |
18.5.11. Get outgoing relationships
图 18.28. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/40/relationships/out
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [ { "start": "http://localhost:7474/db/data/node/40", "data": { }, "self": "http://localhost:7474/db/data/relationship/18", "property": "http://localhost:7474/db/data/relationship/18/properties/{key}", "properties": "http://localhost:7474/db/data/relationship/18/properties", "type": "LIKES", "extensions": { }, "end": "http://localhost:7474/db/data/node/41" }, { "start": "http://localhost:7474/db/data/node/40", "data": { }, "self": "http://localhost:7474/db/data/relationship/20", "property": "http://localhost:7474/db/data/relationship/20/properties/{key}", "properties": "http://localhost:7474/db/data/relationship/20/properties", "type": "HATES", "extensions": { }, "end": "http://localhost:7474/db/data/node/43" } ] |
18.5.12. Get typed relationships
Note that the "&" needs to be encoded like "%26" for example when using cURLfrom the terminal.
图 18.29. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/45/relationships/all/LIKES&HATES
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.5.13. Get relationships on a node without relationships
图 18.30. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/64/relationships/all
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 | [ ] |
18.6. Relationship types
18.6.1. Get relationship types
18.6.1. Get relationship types
图 18.31. Final Graph
Example request
- GEThttp://localhost:7474/db/data/relationship/types
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 | [ "knows", "likes", "KNOWS", "foo", "bar", "know", "has"] |
18.7. Node properties
18.7.1. Set property on node
Setting different properties will retain the existing ones for this node. Note that a single value are submitted not as a map but just as a value (which is valid JSON) like in the example below.
图 18.32. Final Graph
Example request
- PUThttp://localhost:7474/db/data/node/7/properties/foo
- Accept:application/json
- Content-Type:application/json
1 | "bar" |
Example response
- 204:No Content
1 |
18.7.2. Update node properties
This will replace all existing properties on the node with the new set of attributes.
图 18.33. Final Graph
Example request
- PUThttp://localhost:7474/db/data/node/1/properties
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "age": "18" } |
Example response
- 204:No Content
1 |
18.7.3. Get properties for node
图 18.34. Final Graph
Example request
- GEThttp://localhost:7474/db/data/node/4/properties
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 | { "foo": "bar" } |
18.7.4. Property values can not be null
This example shows the response you get when trying to set a property to null.
图 18.35. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "foo": null } |
Example response
- 400:Bad Request
- Content-Type:application/json
1 2 3 4 5 | { "message": "Could not set property \"foo\", unsupported type: null", "exception": "PropertyValueException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.set(DatabaseActions.java:155)", "org.neo4j.server.rest.web.DatabaseActions.createNode(DatabaseActions.java:213)", "org.neo4j.server.rest.web.RestfulGraphDatabase.createNode(RestfulGraphDatabase.java:195)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.7.5. Property values can not be nested
Nesting properties is not supported. You could for example store the nested JSON as a string instead.
图 18.36. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "foo": { "bar": "baz" } } |
Example response
- 400:Bad Request
- Content-Type:application/json
1 2 3 4 5 | { "message": "Could not set property \"foo\", unsupported type: {bar=baz}", "exception": "PropertyValueException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.set(DatabaseActions.java:155)", "org.neo4j.server.rest.web.DatabaseActions.createNode(DatabaseActions.java:213)", "org.neo4j.server.rest.web.RestfulGraphDatabase.createNode(RestfulGraphDatabase.java:195)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.7.6. Delete all properties from node
图 18.37. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/node/5/properties
- Accept:application/json
Example response
- 204:No Content
18.7.7. Delete a named property from a node
To delete a single property from a node, see the example below.
图 18.38. Starting Graph
图 18.39. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/node/6/properties/name
- Accept:application/json
Example response
- 204:No Content
1 |
18.8. Relationship properties
18.8.1. Update relationship properties
图 18.40. Final Graph
Example request
- PUThttp://localhost:7474/db/data/relationship/131/properties
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "jim": "tobias" } |
Example response
- 204:No Content
18.8.2. Remove properties from a relationship
图 18.41. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/19
- Accept:application/json
Example response
- 204:No Content
1 |
18.8.3. Remove property from a relationship
See the example request below.
图 18.42. Starting Graph
图 18.43. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/21/properties/cost
- Accept:application/json
Example response
- 204:No Content
18.8.4. Remove non-existent property from a relationship
Attempting to remove a property that doesn’t exist results in an error.
图 18.44. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/22/properties/non-existent
- Accept:application/json
Example response
- 404:Not Found
- Content-Type:application/json
1 2 3 4 5 | { "message": "Relationship[22] does not have a property \"non-existent\"", "exception": "NoSuchPropertyException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.removeRelationshipProperty(DatabaseActions.java:729)", "org.neo4j.server.rest.web.RestfulGraphDatabase.deleteRelationshipProperty(RestfulGraphDatabase.java:595)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.8.5. Remove properties from a non-existing relationship
Attempting to remove all properties from a relationship which doesn’t exist results in an error.
图 18.45. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/1234/properties
- Accept:application/json
Example response
- 404:Not Found
- Content-Type:application/json
1 2 3 4 | { "exception": "RelationshipNotFoundException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.relationship(DatabaseActions.java:137)", "org.neo4j.server.rest.web.DatabaseActions.removeAllRelationshipProperties(DatabaseActions.java:707)", "org.neo4j.server.rest.web.RestfulGraphDatabase.deleteAllRelationshipProperties(RestfulGraphDatabase.java:579)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.8.6. Remove property from a non-existing relationship
Attempting to remove a property from a relationship which doesn’t exist results in an error.
图 18.46. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/relationship/1234/properties/cost
- Accept:application/json
Example response
- 404:Not Found
- Content-Type:application/json
1 2 3 4 | { "exception": "RelationshipNotFoundException", "stacktrace": [ "org.neo4j.server.rest.web.DatabaseActions.relationship(DatabaseActions.java:137)", "org.neo4j.server.rest.web.DatabaseActions.removeRelationshipProperty(DatabaseActions.java:723)", "org.neo4j.server.rest.web.RestfulGraphDatabase.deleteRelationshipProperty(RestfulGraphDatabase.java:595)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.9. Indexes
An index can contain either nodes or relationships.
注意 | |
To create an index with default configuration, simply start using it by adding nodes/relationships to it. It will then be automatically created for you. |
What default configuration means depends on how you have configured your database. If you haven’t changed any indexing configuration, it means the indexes will be using a Lucene-based backend.
All the examples below show you how to do operations on node indexes, but all of them are just as applicable to relationship indexes. Simple change the "node" part of the URL to "relationship".
If you want to customize the index settings, see 第 18.9.2 节 “Create node index with configuration”.
18.9.1. Create node index
注意 | |
Instead of creating the index this way, you can simply start to use it, and it will be created automatically with default configuration. |
图 18.47. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "name": "favorites" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/favorites/
1 2 3 | { "template": "http://localhost:7474/db/data/index/node/favorites/{key}/{value}" } |
18.9.2. Create node index with configuration
This request is only necessary if you want to customize the index settings. If you are happy with the defaults, you can just start indexing nodes/relationships, as non-existent indexes will automatically be created as you do. See 第 14.10 节 “Configuration and fulltext indexes”for more information on index configuration.
图 18.48. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "name": "fulltext", "config": { "type": "fulltext", "provider": "lucene" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/fulltext/
1 2 3 4 5 | { "template": "http://localhost:7474/db/data/index/node/fulltext/{key}/{value}", "type": "fulltext", "provider": "lucene" } |
18.9.3. Delete node index
图 18.49. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/index/node/kvnode
- Accept:application/json
Example response
- 204:No Content
1 |
18.9.4. List node indexes
图 18.50. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/node/
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 | { "node_auto_index": { "template": "http://localhost:7474/db/data/index/node/node_auto_index/{key}/{value}", "provider": "lucene", "type": "exact" }, "favorites": { "template": "http://localhost:7474/db/data/index/node/favorites/{key}/{value}", "provider": "lucene", "type": "exact" } } |
18.9.5. Add node to index
Associates a node with the given key/value pair in the given index.
注意 | ||
Spaces in the URI have to be encoded as %20. | ||
小心 | ||
This does notoverwrite previous entries. If you index the same key/value/item combination twice, two index entries are created. To do update-type operations, you need to delete the old entry before adding a new one. |
图 18.51. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/favorites
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "value": "some value", "uri": "http://localhost:7474/db/data/node/99", "key": "some-key" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/favorites/some-key/some%20value/99
18.9.6. Remove all entries with a given node from an index
图 18.52. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/index/node/kvnode/109
- Accept:application/json
Example response
- 204:No Content
1 |
18.9.7. Remove all entries with a given node and key from an index
图 18.53. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/index/node/kvnode/kvkey2/110
- Accept:application/json
Example response
- 204:No Content
1 |
18.9.8. Remove all entries with a given node, key and value from an index
图 18.54. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/index/node/kvnode/kvkey1/value1/111
- Accept:application/json
Example response
- 204:No Content
1 |
18.9.9. Find node by exact match
注意 | |
Spaces in the URI have to be encoded as %20. |
图 18.55. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/node/favorites/key/the%2520value
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.9.10. Find node by query
The query language used here depends on what type of index you are querying. The default index type is Lucene, in which case you should use the Lucene query language here. Below an example of a fuzzy search over multiple keys.
See: http://lucene.apache.org/java/3_5_0/queryparsersyntax.html
Getting the results with a predefined ordering requires adding the parameter
order=ordering
where ordering is one of index, relevance or score. In this case an additional field will be added to each result, named score, that holds the float value that is the score reported by the query result.
图 18.56. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/node/bobTheIndex?query=Name:Build~0.1%20AND%20Gender:Male
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.10. Unique Indexes
18.10.1. Create a unique node in an index
图 18.57. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/people?unique
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 | { "key": "name", "value": "Tobias", "properties": { "name": "Tobias", "sequence": 1 } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/people/name/Tobias/112
18.10.2. Create a unique node in an index (the case where it exists)
图 18.58. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/people?unique
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 | { "key": "name", "value": "Peter", "properties": { "name": "Peter", "sequence": 2 } } |
Example response
- 200:OK
- Content-Type:application/json
18.10.3. Add a node to an index unless a node already exists for the given mapping
图 18.59. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/node/people?unique
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "key": "name", "value": "Mattias", "uri": "http://localhost:7474/db/data/node/114" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/people/name/Mattias/114
18.10.4. Create a unique relationship in an index
图 18.60. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/relationship/knowledge/?unique
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "key": "name", "value": "Tobias", "start": "http://localhost:7474/db/data/node/61", "end": "http://localhost:7474/db/data/node/62", "type": "knowledge" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/relationship/knowledge/name/Tobias/32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "extensions": { }, "start": "http://localhost:7474/db/data/node/61", "property": "http://localhost:7474/db/data/relationship/32/properties/{key}", "self": "http://localhost:7474/db/data/relationship/32", "properties": "http://localhost:7474/db/data/relationship/32/properties", "type": "knowledge", "end": "http://localhost:7474/db/data/node/62", "data": { "name": "Tobias" }, "indexed": "http://localhost:7474/db/data/index/relationship/knowledge/name/Tobias/32" } |
18.10.5. Add a relationship to an index unless a relationship already exists for the given mapping
图 18.61. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/relationship/knowledge/?unique
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "key": "name", "value": "Mattias", "uri": "http://localhost:7474/db/data/relationship/33" } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/relationship/knowledge/name/Mattias/33
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "extensions": { }, "start": "http://localhost:7474/db/data/node/63", "property": "http://localhost:7474/db/data/relationship/33/properties/{key}", "self": "http://localhost:7474/db/data/relationship/33", "properties": "http://localhost:7474/db/data/relationship/33/properties", "type": "knowledge", "end": "http://localhost:7474/db/data/node/64", "data": { }, "indexed": "http://localhost:7474/db/data/index/relationship/knowledge/name/Mattias/33" } |
18.11. Automatic Indexes
18.11.1. Find node by exact match from an automatic index
18.11.2. Find node by query from an automatic index
To enable automatic indexes in neo4j, set up the database for that, see 第 14.12.1 节 “Configuration”. With this feature enabled, you can then index and query nodes in these indexes.
18.11.1. Find node by exact match from an automatic index
Automatic index nodes can be found via exact lookups with normal Index REST syntax.
图 18.62. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/auto/node/name/I
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.11.2. Find node by query from an automatic index
See Find node by query for the actual query syntax.
图 18.63. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/auto/node/?query=name:I
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.12. Configurable Automatic Indexing
18.12.1. Create an auto index for nodes with specific configuration
18.12.2. Create an auto index for relationships with specific configuration
18.12.3. Get current status for autoindexing on nodes
18.12.4. Enable node autoindexing
18.12.5. Lookup list of properties being autoindexed
18.12.6. Add a property for autoindexing on nodes
18.12.7. Remove a property for autoindexing on nodes
Out of the box auto-indexing supports exact matches since they are created with the default configuration (see 第 14.12 节 “Automatic Indexing”) the first time you access them. However it is possible to intervene in the lifecycle of the server before any auto indexes are created to change their configuration.
警告 | |
This approach cannotbe used on databases that already have auto-indexes established. To change the auto-index configuration existing indexes would have to be deleted first, so be careful! | |
小心 | |
This technique works, but it is not particularly pleasant. Future versions of Neo4j may remove this loophole in favour of a better structured feature for managing auto-indexing configurations. |
Auto-indexing must be enabled through configuration before we can create or configure them. Firstly ensure that you’ve added some config like this into your server’s neo4j.propertiesfile:
1 2 3 4 | node_auto_indexing=true relationship_auto_indexing=true node_keys_indexable=name,phone relationship_keys_indexable=since |
The node_auto_indexingand relationship_auto_indexingsettings turn auto-indexing on for nodes and relationships respectively. The node_keys_indexablekey allows you to specify a comma-separated list of node property keys to be indexed. The relationship_keys_indexabledoes the same for relationship property keys.
Next start the server as usual by invoking the start script as described in 第 17.1 节 “服务器安装”.
Next we have to pre-empt the creation of an auto-index, by telling the server to create an apparently manual index which has the same name as the node (or relationship) auto-index. For example, in this case we’ll create a node auto index whose name is node_auto_index, like so:
18.12.1. Create an auto index for nodes with specific configuration
Example request
- POSThttp://localhost:7474/db/data/index/node/
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "name": "node_auto_index", "config": { "type": "fulltext", "provider": "lucene" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/node/node_auto_index/
1 2 3 4 5 | { "template": "http://localhost:7474/db/data/index/node/node_auto_index/{key}/{value}", "type": "fulltext", "provider": "lucene" } |
If you require configured auto-indexes for relationships, the approach is similar:
18.12.2. Create an auto index for relationships with specific configuration
Example request
- POSThttp://localhost:7474/db/data/index/relationship/
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "name": "relationship_auto_index", "config": { "type": "fulltext", "provider": "lucene" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/index/relationship/relationship_auto_index/
1 2 3 4 5 | { "template": "http://localhost:7474/db/data/index/relationship/relationship_auto_index/{key}/{value}", "type": "fulltext", "provider": "lucene" } |
In case you’re curious how this works, on the server side it triggers the creation of an index which happens to have the same name as the auto index that the database would create for itself. Now when we interact with the database, the index thinks the index is already created so the state machine skips over that step and just gets on with normal day-to-day auto-indexing.
小心 | |
You have to do this early in your server lifecycle, before any normal auto indexes are created. |
There are a few REST calls providing a REST interface to the AutoIndexercomponent. The following REST calls work both, for nodeand relationshipby simply changing the respective part of the URL.
18.12.3. Get current status for autoindexing on nodes
图 18.64. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/auto/node/status
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 | false |
18.12.4. Enable node autoindexing
图 18.65. Final Graph
Example request
- PUThttp://localhost:7474/db/data/index/auto/node/status
- Accept:application/json
- Content-Type:application/json
1 | true |
Example response
- 204:No Content
1 |
18.12.5. Lookup list of properties being autoindexed
图 18.66. Final Graph
Example request
- GEThttp://localhost:7474/db/data/index/auto/node/properties
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
1 | [ "some-property"] |
18.12.6. Add a property for autoindexing on nodes
图 18.67. Final Graph
Example request
- POSThttp://localhost:7474/db/data/index/auto/node/properties
- Accept:application/json
- Content-Type:application/json
1 | myProperty1 |
Example response
- 204:No Content
- 18.12.7. Remove a property for autoindexing on nodes
图 18.68. Final Graph
Example request
- DELETEhttp://localhost:7474/db/data/index/auto/node/properties/myProperty1
- Accept:application/json
Example response
- 204:No Content
18.13. Traversals
警告 | |
The Traversal REST Endpoint executes arbitrary Groovy code under the hood as part of the evaluators definitions. In hosted and open environments, this can constitute a security risk. In these case, consider using declarative approaches like 第 15 章 Cypher查询语言or write your own server side plugin executing the interesting traversals with the Java API ( see 第 10.1 节 “服务器插件”) or secure your server, see 第 24.1 节 “安全访问Neo4j服务器”. |
Traversals are performed from a start node. The traversal is controlled by the URI and the body sent with the request.
returnType
The kind of objects in the response is determined by traverse/{returnType}in the URL. returnTypecan have one of these values:
- node
- relationship
- path: contains full representations of start and end node, the rest are URIs.
- fullpath: contains full representations of all nodes and relationships.
To decide how the graph should be traversed you can use these parameters in the request body:
order
Decides in which order to visit nodes. Possible values:
- breadth_first: see Breadth-first search.
- depth_first: see Depth-first search
relationships
Decides which relationship types and directions should be followed. The direction can be one of:
- all
- in
- out
uniqueness
Decides how uniqueness should be calculated. For details on different uniqueness values see the Java API on Uniqueness. Possible values:
- node_global
- none
- relationship_global
- node_path
- relationship_path
prune_evaluator
Decides whether the traverser should continue down that path or if it should be pruned so that the traverser won’t continue down that path. You can write your own prune evaluator as (see 第 18.13.1 节 “Traversal using a return filter”or use the built-innoneprune evaluator.
return_filter
Decides whether the current position should be included in the result. You can provide your own code for this (see 第 18.13.1 节 “Traversal using a return filter”), or use one of the built-in filters:
- all
- all_but_start_node
max_depth
Is a short-hand way of specifying a prune evaluator which prunes after a certain depth. If not specified a max depth of 1 is used and if a prune_evaluatoris specified instead of a max_depth, no max depth limit is set.
The positionobject in the body of the return_filterand prune_evaluatoris a Pathobject representing the path from the start node to the current traversal position.
Out of the box, the REST API supports JavaScript code in filters and evaluators. The script body will be executed in a Java context which has access to the full Neo4j Java API. See the examples for the exact syntax of the request.
18.13.1. Traversal using a return filter
In this example, the noneprune evaluator is used and a return filter is supplied in order to return all names containing "t". The result is to be returned as nodes and the max depth is set to 3.
图 18.69. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/13/traverse/node
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | { "order": "breadth_first", "return_filter": { "body": "position.endNode().getProperty('name').toLowerCase().contains('t')", "language": "javascript" }, "prune_evaluator": { "body": "position.length() > 10", "language": "javascript" }, "uniqueness": "node_global", "relationships": [ { "direction": "all", "type": "knows" }, { "direction": "all", "type": "loves" } ], "max_depth": 3 } |
Example response
- 200:OK
- Content-Type:application/json
18.13.2. Return relationships from a traversal
图 18.70. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/6/traverse/relationship
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 | { "order": "breadth_first", "uniqueness": "none", "return_filter": { "language": "builtin", "name": "all" } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [ { "start": "http://localhost:7474/db/data/node/6", "data": { }, "self": "http://localhost:7474/db/data/relationship/1", "property": "http://localhost:7474/db/data/relationship/1/properties/{key}", "properties": "http://localhost:7474/db/data/relationship/1/properties", "type": "know", "extensions": { }, "end": "http://localhost:7474/db/data/node/5" }, { "start": "http://localhost:7474/db/data/node/6", "data": { }, "self": "http://localhost:7474/db/data/relationship/2", "property": "http://localhost:7474/db/data/relationship/2/properties/{key}", "properties": "http://localhost:7474/db/data/relationship/2/properties", "type": "own", "extensions": { }, "end": "http://localhost:7474/db/data/node/4" } ] |
18.13.3. Return paths from a traversal
图 18.71. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/9/traverse/path
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 | { "order": "breadth_first", "uniqueness": "none", "return_filter": { "language": "builtin", "name": "all" } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [ { "start": "http://localhost:7474/db/data/node/9", "nodes": [ "http://localhost:7474/db/data/node/9"], "length": 0, "relationships": [ ], "end": "http://localhost:7474/db/data/node/9" }, { "start": "http://localhost:7474/db/data/node/9", "nodes": [ "http://localhost:7474/db/data/node/9", "http://localhost:7474/db/data/node/8"], "length": 1, "relationships": [ "http://localhost:7474/db/data/relationship/3"], "end": "http://localhost:7474/db/data/node/8" }, { "start": "http://localhost:7474/db/data/node/9", "nodes": [ "http://localhost:7474/db/data/node/9", "http://localhost:7474/db/data/node/7"], "length": 1, "relationships": [ "http://localhost:7474/db/data/relationship/4"], "end": "http://localhost:7474/db/data/node/7" } ] |
18.13.4. Traversal returning nodes below a certain depth
Here, all nodes at a traversal depth below 3 are returned.
图 18.72. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/20/traverse/node
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 | { "return_filter": { "body": "position.length()<3;", "language": "javascript" }, "prune_evaluator": { "name": "none", "language": "builtin" } } |
Example response
- 200:OK
- Content-Type:application/json
18.13.5. Creating a paged traverser
Paged traversers are created by POST-ing a traversal description to the link identified by the paged_traverserkey in a node representation. When creating a paged traverser, the same options apply as for a regular traverser, meaning that node, path, or fullpath, can be targeted.
Example request
- POSThttp://localhost:7474/db/data/node/67/paged/traverse/node
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "prune_evaluator": { "language": "builtin", "name": "none" }, "return_filter": { "language": "javascript", "body": "position.endNode().getProperty('name').contains('1');" }, "order": "depth_first", "relationships": { "type": "NEXT", "direction": "out" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/node/67/paged/traverse/node/1ff2c67ce33a4b85bcea5ab3f4b60ee8
18.13.6. Paging through the results of a paged traverser
Paged traversers hold state on the server, and allow clients to page through the results of a traversal. To progress to the next page of traversal results, the client issues a HTTP GET request on the paged traversal URI which causes the traversal to fill the next page (or partially fill it if insufficient results are available).
Note that if a traverser expires through inactivity it will cause a 404 response on the next GETrequest. Traversers' leases are renewed on every successful access for the same amount of time as originally specified.
When the paged traverser reaches the end of its results, the client can expect a 404 response as the traverser is disposed by the server.
Example request
- GEThttp://localhost:7474/db/data/node/100/paged/traverse/node/ea5c026574e44cc6a3222927b103bea2
- Accept:application/json
Example response
- 200:OK
- Content-Type:application/json
18.13.7. Paged traverser page size
The default page size is 50 items, but depending on the application larger or smaller pages sizes might be appropriate. This can be set by adding a pageSizequery parameter.
Example request
- POSThttp://localhost:7474/db/data/node/577/paged/traverse/node?pageSize=1
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "prune_evaluator": { "language": "builtin", "name": "none" }, "return_filter": { "language": "javascript", "body": "position.endNode().getProperty('name').contains('1');" }, "order": "depth_first", "relationships": { "type": "NEXT", "direction": "out" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/node/577/paged/traverse/node/2c4fa996b58443108a945ca9ce5a83d4
18.13.8. Paged traverser timeout
The default timeout for a paged traverser is 60 seconds, but depending on the application larger or smaller timeouts might be appropriate. This can be set by adding a leaseTimequery parameter with the number of seconds the paged traverser should last.
Example request
- POSThttp://localhost:7474/db/data/node/610/paged/traverse/node?leaseTime=10
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "prune_evaluator": { "language": "builtin", "name": "none" }, "return_filter": { "language": "javascript", "body": "position.endNode().getProperty('name').contains('1');" }, "order": "depth_first", "relationships": { "type": "NEXT", "direction": "out" } } |
Example response
- 201:Created
- Content-Type:application/json
- Location:http://localhost:7474/db/data/node/610/paged/traverse/node/868b071c0dd74df78e45d40b39aaf03c
18.14. Built-in Graph Algorithms
Neo4j 附带许多内置图算法。他们是从起始节点执行的。遍历控制的 URI 和随请求发送的机构.
algorithm
The algorithm to choose. If not set, default is shortestPath. algorithmcan have one of these values:
- shortestPath
- allSimplePaths
- allPaths
- dijkstra(optional with cost_propertyand default_costparameters)
max_depth
作为一个整数算法的最大深度喜欢 ShortestPath,在适用的情况。默认值为 1.
18.14.1. 查找所有的最短路径
The shortestPathalgorithm can find multiple paths between the same nodes, like in this example.
图 18.73. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/125/paths
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 | { "to": "http://localhost:7474/db/data/node/120", "max_depth": 3, "relationships": { "type": "to", "direction": "out" }, "algorithm": "shortestPath" } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 | [ { "start": "http://localhost:7474/db/data/node/125", "nodes": [ "http://localhost:7474/db/data/node/125", "http://localhost:7474/db/data/node/124", "http://localhost:7474/db/data/node/120"], "length": 2, "relationships": [ "http://localhost:7474/db/data/relationship/73", "http://localhost:7474/db/data/relationship/82"], "end": "http://localhost:7474/db/data/node/120" }, { "start": "http://localhost:7474/db/data/node/125", "nodes": [ "http://localhost:7474/db/data/node/125", "http://localhost:7474/db/data/node/121", "http://localhost:7474/db/data/node/120"], "length": 2, "relationships": [ "http://localhost:7474/db/data/relationship/74", "http://localhost:7474/db/data/relationship/80"], "end": "http://localhost:7474/db/data/node/120" } ] |
18.14.2. 查找节点之间的最短路径之一
如果未不指定任何路径算法,将选择最大深度为 1 的 ShortestPath 算法。在此示例中,max_depth 设置为 3,找到 3 链接的节点之间的最短路径.
图 18.74. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/132/path
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 | { "to": "http://localhost:7474/db/data/node/127", "max_depth": 3, "relationships": { "type": "to", "direction": "out" }, "algorithm": "shortestPath" } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 | { "start": "http://localhost:7474/db/data/node/132", "nodes": [ "http://localhost:7474/db/data/node/132", "http://localhost:7474/db/data/node/128", "http://localhost:7474/db/data/node/127"], "length": 2, "relationships": [ "http://localhost:7474/db/data/relationship/84", "http://localhost:7474/db/data/relationship/90"], "end": "http://localhost:7474/db/data/node/127" } |
18.14.3. 在关系上执行类似权重 Dijkstra 算法
图 18.75. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/147/path
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 | { "to": "http://localhost:7474/db/data/node/150", "cost_property": "cost", "relationships": { "type": "to", "direction": "out" }, "algorithm": "dijkstra" } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 | { "weight": 2.0, "start": "http://localhost:7474/db/data/node/147", "nodes": [ "http://localhost:7474/db/data/node/147", "http://localhost:7474/db/data/node/148", "http://localhost:7474/db/data/node/150"], "length": 2, "relationships": [ "http://localhost:7474/db/data/relationship/106", "http://localhost:7474/db/data/relationship/107"], "end": "http://localhost:7474/db/data/node/150" } |
18.14.4. 在关系上执行权重 Dijkstra 算法
图 18.76. Final Graph
Example request
- POSThttp://localhost:7474/db/data/node/138/path
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 | { "to": "http://localhost:7474/db/data/node/141", "cost_property": "cost", "relationships": { "type": "to", "direction": "out" }, "algorithm": "dijkstra" } |
Example response
- 200:OK
- Content-Type:application/json
18.15. Batch operations
18.15.1. 在批处理中执行多个操作
这允许您执行多个 API 调用通过单个 HTTP 调用,极大地提高性能的大型插入和更新操作。批处理服务期望职务说明的数组作为输入,描述要通过正常的服务器 API 执行的操作的每个工作说明。此服务是事务性的。如果任何操作执行失败 (非 2xx 返回 HTTP 状态代码),将回滚事务并将撤消所有更改.
Each job description should contain a toattribute, with a value relative to the data API root (so http://localhost:7474/db/data/nodebecomes just /node), and a methodattribute containing HTTP verb to use.
(可选) 您可以提供身体特性和 id 属性,以帮助您跟踪的响应,虽然反应,保证能够在收到的职务说明的相同顺序返回。下图概述了职务说明的不同部分:
图 18.77. Final Graph
Eample request
- POSThttp://localhost:7474/db/data/batch
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [ { "method": "PUT", "to": "/node/27/properties", "body": { "age": 1 }, "id": 0 }, { "method": "GET", "to": "/node/27", "id": 1 }, { "method": "POST", "to": "/node", "body": { "age": 1 }, "id": 2 }, { "method": "POST", "to": "/node", "body": { "age": 1 }, "id": 3 } ] |
Example response
- 200:OK
- Content-Type:application/json
18.15.2. 较早前在同一个批处理作业中创建的项目,请参阅
批处理操作 API 允许您从创建的资源,在以后的工作说明,在同一批次调用中返回的 URI 引用。使用 {[作业 ID]} 的特殊语法来从创建资源的 Uri 注入 JSON 字符串中后续作业说明.
图 18.78. Final Graph
Example request
- POSThttp://localhost:7474/db/data/batch
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | [ { "method": "POST", "to": "/node", "id": 0, "body": { "name": "bob" } }, { "method": "POST", "to": "/node", "id": 1, "body": { "age": 12 } }, { "method": "POST", "to": "{0}/relationships", "id": 3, "body": { "to": "{1}", "data": { "since": "2010" }, "type": "KNOWS" } }, { "method": "POST", "to": "/index/relationship/my_rels", "id": 4, "body": { "key": "since", "value": "2010", "uri": "{3}" } } ] |
Example response
- 200:OK
- Content-Type:application/json
[ {
"id": 0,
"location": "http://localhost:7474/db/data/node/30",
"body": {
"extensions": {
},
"paged_traverse": "http://localhost:7474/db/data/node/30/paged/traverse/{returnType}{?pageSize,leaseTime}",
"outgoing_relationships": "http://localhost:7474/db/data/node/30/relationships/out",
"traverse": "http://localhost:7474/db/data/node/30/traverse/{returnType}",
"all_typed_relationships": "http://localhost:7474/db/data/node/30/relationships/all/{-list|&|types}",
"all_relationships": "http://localhost:7474/db/data/node/30/relationships/all",
"property": "http://localhost:7474/db/data/node/30/properties/{key}",
"self": "http://localhost:7474/db/data/node/30",
"outgoing_typed_relationships": "http://localhost:7474/db/data/node/30/relationships/out/{-list|&|types}",
"properties": "http://localhost:7474/db/data/node/30/properties",
"incoming_relationships": "http://localhost:7474/db/data/node/30/relationships/in",
"incoming_typed_relationships": "http://localhost:7474/db/data/node/30/relationships/in/{-list|&|types}",
"create_relationship": "http://localhost:7474/db/data/node/30/relationships",
"data": {
"name": "bob"
}
},
"from": "/node"
}, {
"id": 1,
"location": "http://localhost:7474/db/data/node/31",
"body": {
"extensions": {
},
"paged_traverse": "http://localhost:7474/db/data/node/31/paged/traverse/{returnType}{?pageSize,leaseTime}",
"outgoing_relationships": "http://localhost:7474/db/data/node/31/relationships/out",
"traverse": "http://localhost:7474/db/data/node/31/traverse/{returnType}",
"all_typed_relationships": "http://localhost:7474/db/data/node/31/relationships/all/{-list|&|types}",
"all_relationships": "http://localhost:7474/db/data/node/31/relationships/all",
"property": "http://localhost:7474/db/data/node/31/properties/{key}",
"self": "http://localhost:7474/db/data/node/31",
"outgoing_typed_relationships": "http://localhost:7474/db/data/node/31/relationships/out/{-list|&|types}",
"properties": "http://localhost:7474/db/data/node/31/properties",
"incoming_relationships": "http://localhost:7474/db/data/node/31/relationships/in",
"incoming_typed_relationships": "http://localhost:7474/db/data/node/31/relationships/in/{-list|&|types}",
"create_relationship": "http://localhost:7474/db/data/node/31/relationships",
"data": {
"age": 12
}
},
"from": "/node"
}, {
"id": 3,
"location": "http://localhost:7474/db/data/relationship/10",
"body": {
"extensions": {
},
"start": "http://localhost:7474/db/data/node/30",
"property": "http://localhost:7474/db/data/relationship/10/properties/{key}",
"self": "http://localhost:7474/db/data/relationship/10",
"properties": "http://localhost:7474/db/data/relationship/10/properties",
"type": "KNOWS",
"end": "http://localhost:7474/db/data/node/31",
"data": {
"since": "2010"
}
},
"from": "http://localhost:7474/db/data/node/30/relationships"
}, {
"id": 4,
"location": "http://localhost:7474/db/data/index/relationship/my_rels/since/2010/10",
"body": {
"extensions": {
},
"start": "http://localhost:7474/db/data/node/30",
"property": "http://localhost:7474/db/data/relationship/10/properties/{key}",
"self": "http://localhost:7474/db/data/relationship/10",
"properties": "http://localhost:7474/db/data/relationship/10/properties",
"type": "KNOWS",
"end": "http://localhost:7474/db/data/node/31",
"data": {
"since": "2010"
},
"indexed": "http://localhost:7474/db/data/index/relationship/my_rels/since/2010/10"
},
"from": "/index/relationship/my_rels"
} ]
18.15.3. 批处理流中执行多个操作
图 18.79. Final Graph
Example request
- POSThttp://localhost:7474/db/data/batch
- Accept:application/json
- Content-Type:application/json
- X-Stream:true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [ { "method": "PUT", "to": "/node/145/properties", "body": { "age": 1 }, "id": 0 }, { "method": "GET", "to": "/node/145", "id": 1 }, { "method": "POST", "to": "/node", "body": { "age": 1 }, "id": 2 }, { "method": "POST", "to": "/node", "body": { "age": 1 }, "id": 3 } ] |
Example response
- 200:OK
- Content-Type:application/json
18.16. WADL Support
Neo4j 休息 API 是一个真正 rest 风格的界面,依靠超媒体控件 (链接) 广告对用户的允许操作。超媒体是一种动态界面样式声明构造 (语义标记) 用于告知他们下一步的法律选择的客户端,只是在时间.
小心 | ||
RESTful APIs cannot be modelled by static interface description languages like WSDL or WADL. |
不过为某些使用情况下,开发人员可能希望公开 WADL 说明 Neo4j 休息 api,尤其是当使用工具,预计这种。在这些情况下可能将添加到您的服务器的 neo4j.properties 文件启用 WADL 代:
1 | unsupported_wadl_generation_enabled=true | |
小心 | ||
WADL is not an officially supported part of the Neo4j server API because WADL is insufficiently expressive to capture the set of potential interactions a client can drive with Neo4j server. Expect the WADL description to be incomplete, and in some cases contradictory to the real API. In any cases where the WADL description disagrees with the REST API, the REST API should be considered authoritative. WADL generation may be withdrawn at any point in the Neo4j release cycle. |
18.17. Cypher插件
警告 | |
This functionality is now provided by the core REST API. The plugin will continue to work for some time, but is as of Neo4j 1.6 deprecated. See 第 18.3 节 “Cypher queries”for documentation on the built-in Cypher support. |
The Neo4j Cypher Plugin enables querying with the 第 15 章 Cypher查询语言. The results are returned as a list of string headers (columns), and a datapart, consisting of a list of all rows, every row consisting of a list of REST representations of the field value - Node, Relationshipor any simple value like String.
18.17.1. Send a Query
A simple query returning all nodes connected to node 1, returning the node and the name property, if it exists, otherwise null:
1 2 3 | STARTx = node(3) MATCHx -[r]-> n RETURNtype(r), n.name?, n.age? |
图 18.80. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/CypherPlugin/graphdb/execute_query
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(3) match x -[r]-> n return type(r), n.name?, n.age?", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "type(r)", "n.name?", "n.age?"], "data": [ [ "know", "him", 25 ], [ "know", "you", null] ] } |
18.17.2. Return paths
Paths can be returned together with other return types by just specifying returns.
1 2 3 | STARTx = node(7) MATCHpath = (x--friend) RETURNpath, friend.name |
图 18.81. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/CypherPlugin/graphdb/execute_query
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(7) match path = (x--friend) return path, friend.name", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 6 7 8 9 10 | { "columns": [ "path", "friend.name"], "data": [ [ { "start": "http://localhost:7474/db/data/node/7", "nodes": [ "http://localhost:7474/db/data/node/7", "http://localhost:7474/db/data/node/6"], "length": 1, "relationships": [ "http://localhost:7474/db/data/relationship/3"], "end": "http://localhost:7474/db/data/node/6" }, "you"] ] } |
18.17.3. Send queries with parameters
Cypher supports queries with parameters which are submitted as a JSON map.
1 2 3 4 | STARTx = node:node_auto_index(name={startName}) MATCHpath = (x-[r]-friend) WHEREfriend.name = {name} RETURNTYPE(r) |
图 18.82. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/CypherPlugin/graphdb/execute_query
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 7 | { "query": "start x = node:node_auto_index(name={startName}) match path = (x-[r]-friend) where friend.name = {name} return TYPE(r)", "params": { "startName": "I", "name": "you" } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "TYPE(r)"], "data": [ [ "know"] ] } |
18.17.4. Server errors
Errors on the server will be reported as a JSON-formatted stacktrace and message.
1 2 | STARTx = node(5) RETURNx.dummy |
图 18.83. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/CypherPlugin/graphdb/execute_query
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "query": "start x = node(5) return x.dummy", "params": { } } |
Example response
- 400:Bad Request
- Content-Type:application/json
1 2 3 4 5 | { "message": "The property 'dummy' does not exist on Node[5]", "exception": "BadInputException", "stacktrace": [ "org.neo4j.server.rest.repr.RepresentationExceptionHandlingIterable.exceptionOnHasNext(RepresentationExceptionHandlingIterable.java:51)", "org.neo4j.helpers.collection.ExceptionHandlingIterable$1.hasNext(ExceptionHandlingIterable.java:61)", "org.neo4j.helpers.collection.IteratorWrapper.hasNext(IteratorWrapper.java:42)", "org.neo4j.server.rest.repr.ListRepresentation.serialize(ListRepresentation.java:58)", "org.neo4j.server.rest.repr.Serializer.serialize(Serializer.java:75)", "org.neo4j.server.rest.repr.MappingSerializer.putList(MappingSerializer.java:61)", "org.neo4j.server.rest.repr.CypherResultRepresentation.serialize(CypherResultRepresentation.java:50)", "org.neo4j.server.rest.repr.MappingRepresentation.serialize(MappingRepresentation.java:42)", "org.neo4j.server.rest.repr.OutputFormat.format(OutputFormat.java:170)", "org.neo4j.server.rest.repr.OutputFormat.formatRepresentation(OutputFormat.java:120)", "org.neo4j.server.rest.repr.OutputFormat.response(OutputFormat.java:107)", "org.neo4j.server.rest.repr.OutputFormat.ok(OutputFormat.java:55)", "org.neo4j.server.rest.web.ExtensionService.invokeGraphDatabaseExtension(ExtensionService.java:122)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |
18.18. Gremlin Plugin
Gremlin是 Groovy 基于图形遍历语言。它提供了很好的表现方式的显式地编写脚本通过 Neo4j 图形遍历.
The Neo4j Gremlin Plugin provides an endpoint to send Gremlin scripts to the Neo4j Server. The scripts are executed on the server database and the results are returned as Neo4j Node and Relationship representations. This keeps the types throughout the REST API consistent. The results are quite verbose when returning Neo4j Node, Relationshipor Graphrepresentations. On the other hand, just return properties like in the 第 18.18.4 节 “Send a Gremlin Script - JSON encoded with table results”example for responses tailored to specific needs.
警告 | ||
The Gremlin plugin lets you execute arbitrary Groovy code under the hood. In hosted and open environments, this can constitute a security risk. In these case, consider using declarative approaches like 第 15 章 Cypher查询语言or write your own server side plugin executing the interesting Gremlin or Java routines, see 第 10.1 节 “服务器插件”or secure your server, see 第 24.1 节 “安全访问Neo4j服务器”. | ||
提示 | ||
When returning results from pipes like g.v(0).in(), make sure to iterate through the results in order not to return the pipe object but its content, like g.v(0).in().iterate(). For more caveats, see Gremlin Troubleshooting |
18.18.1. Send a Gremlin Script - URL encoded
Scripts can be sent as URL-encoded In this example, the graph has been autoindexed by Neo4j, so we can look up the name property on nodes.
Raw script source
1 | g.idx('node_auto_index')[[name:'I']].out |
图 18.84. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/x-www-form-urlencoded
1 | script=g.idx%28%27node_auto_index%27%29%5B%5Bname%3A%27I%27%5D%5D.out |
Example response
- 200:OK
- Content-Type:application/json
18.18.2. Load a sample graph
Import a graph form a GraphMLfile can be achieved through the Gremlin GraphMLReader. The following script imports a small GraphML file from an URL into Neo4j, resulting in the depicted graph. The underlying database is auto-indexed, see 第 14.12 节 “Automatic Indexing”so the script can return the imported node by index lookup.
Raw script source
1 2 3 | g.clear() g.loadGraphML('https://raw.github.com/neo4j/gremlin-plugin/master/src/data/graphml1.xml') g.idx('node_auto_index')[[name:'you']] |
图 18.85. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.clear();g.loadGraphML('https://raw.github.com/neo4j/gremlin-plugin/master/src/data/graphml1.xml');g.idx('node_auto_index')[[name:'you']];", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.3. Sort a result using raw Groovy operations
The following script returns a sorted list of all nodes connected via outgoing relationships to node 1, sorted by their name-property.
Raw script source
1 | g.idx('node_auto_index')[[name:'I']].out.sort{it.name} |
图 18.86. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.idx('node_auto_index')[[name:'I']].out.sort{it.name}", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.4. Send a Gremlin Script - JSON encoded with table results
To send a Script JSON encoded, set the payload Content-Type Header. In this example, find all the things that my friends like, and return a table listing my friends by their name, and the names of the things they like in a table with two columns, ignoring the third named step variable I. Remember that everything in Gremlin is an iterator - in order to populate the result table t, iterate through the pipes with iterate().
Raw script source
1 2 3 | t= newTable() g.v(23).as('I').out('know').as('friend').out('like').as('likes').table(t,['friend','likes']){it.name}{it.name}.iterate() t |
图 18.87. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "t= new Table();g.v(23).as('I').out('know').as('friend').out('like').as('likes').table(t,['friend','likes']){it.name}{it.name}.iterate();t;", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "columns": [ "friend", "likes"], "data": [ [ "Joe", "cats"], [ "Joe", "dogs"] ] } |
18.18.5. Returning nested pipes
Raw script source
1 | g.v(27).as('I').out('know').as('friend').out('like').as('likes').table(newTable()){it.name}{it.name}.cap |
图 18.88. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.v(27).as('I').out('know').as('friend').out('like').as('likes').table(new Table()){it.name}{it.name}.cap;", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | [ [ { "data": [ [ "I", "Joe", "cats"], [ "I", "Joe", "dogs"] ], "columns": [ "I", "friend", "likes"] } ] ] |
18.18.6. Set script variables
To set variables in the bindings for the Gremlin Script Engine on the server, you can include a paramsparameter with a String representing a JSON map of variables to set to initial values. These can then be accessed as normal variables within the script.
Raw script source
1 | meaning_of_life |
图 18.89. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 | { "script": "meaning_of_life", "params": { "meaning_of_life": 42.0 } } |
Example response
- 200:OK
- Content-Type:application/json
1 | 42.0 |
18.18.7. Send a Gremlin Script with variables in a JSON Map
Send a Gremlin Script, as JSON payload and additional parameters
Raw script source
1 | g.v(me).out |
图 18.90. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 6 | { "script": "g.v(me).out", "params": { "me": "6" } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.8. Return paths from a Gremlin script
The following script returns paths. Paths in Gremlin consist of the pipes that make up the path from the starting pipes. The server is returning JSON representations of their content as a nested list.
Raw script source
1 | g.v(20).out.name.paths |
图 18.91. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.v(20).out.name.paths", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.9. Send an arbitrary Groovy script - Lucene sorting
This example demonstrates that you via the Groovy runtime embedded with the server have full access to all of the servers Java APIs. The below example creates Nodes in the database both via the Blueprints and the Neo4j API indexes the nodes via the native Neo4j Indexing API constructs a custom Lucene sorting and searching returns a Neo4j IndexHits result iterator.
Raw script source
'******** Additional imports *********'
importorg.neo4j.graphdb.index.*
importorg.neo4j.graphdb.*
importorg.neo4j.index.lucene.*
importorg.apache.lucene.search.*
'**** Blueprints API methods on the injected Neo4jGraph at variable g ****'
meVertex = g.addVertex([name:'me'])
meNode = meVertex.getRawVertex()
'*** get the Neo4j raw instance ***'
neo4j = g.getRawGraph()
'******** Neo4j API methods: *********'
tx = neo4j.beginTx()
youNode = neo4j.createNode()
youNode.setProperty('name','you')
youNode.createRelationshipTo(meNode,DynamicRelationshipType.withName('knows'))
'*** index using Neo4j APIs ***'
idxManager = neo4j.index()
personIndex = idxManager.forNodes('persons')
personIndex.add(meNode,'name',meNode.getProperty('name'))
personIndex.add(youNode,'name',youNode.getProperty('name'))
tx.success()
tx.finish()
'*** Prepare a custom Lucene query context with Neo4j API ***'
query = newQueryContext( 'name:*').sort( newSort(newSortField( 'name',SortField.STRING, true ) ) )
results = personIndex.query( query )
图 18.92. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "'******** Additional imports *********';import org.neo4j.graphdb.index.*;import org.neo4j.graphdb.*;import org.neo4j.index.lucene.*;import org.apache.lucene.search.*;;'**** Blueprints API methods on the injected Neo4jGraph at variable g ****';meVertex = g.addVertex([name:'me']);meNode = meVertex.getRawVertex();;'*** get the Neo4j raw instance ***';neo4j = g.getRawGraph();;;'******** Neo4j API methods: *********';tx = neo4j.beginTx(); youNode = neo4j.createNode(); youNode.setProperty('name','you'); youNode.createRelationshipTo(meNode,DynamicRelationshipType.withName('knows'));;'*** index using Neo4j APIs ***'; idxManager = neo4j.index(); personIndex = idxManager.forNodes('persons'); personIndex.add(meNode,'name',meNode.getProperty('name')); personIndex.add(youNode,'name',youNode.getProperty('name'));tx.success();tx.finish();;;'*** Prepare a custom Lucene query context with Neo4j API ***';query = new QueryContext( 'name:*' ).sort( new Sort(new SortField( 'name',SortField.STRING, true ) ) );results = personIndex.query( query );", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.10. Emit a sample graph
Exporting a graph can be done by simple emitting the appropriate String.
Raw script source
1 2 3 4 | writer = newGraphMLWriter(g) out = newjava.io.ByteArrayOutputStream() writer.outputGraph(out) result = out.toString() |
图 18.93. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "writer = new GraphMLWriter(g);out = new java.io.ByteArrayOutputStream();writer.outputGraph(out);result = out.toString();", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 | "<?xml version=\"1.0\" ?><graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"><key id=\"name\" for=\"node\" attr.name=\"name\" attr.type=\"string\"></key><graph id=\"G\" edgedefault=\"directed\"><node id=\"12\"><data key=\"name\">you</data></node><node id=\"13\"><data key=\"name\">him</data></node><node id=\"14\"><data key=\"name\">I</data></node><edge id=\"6\" source=\"14\" target=\"12\" label=\"know\"></edge><edge id=\"7\" source=\"14\" target=\"13\" label=\"know\"></edge></graph></graphml>" |
18.18.11. HyperEdges - find user roles in groups
Imagine a user being part of different groups. A group can have different roles, and a user can be part of different groups. He also can have different roles in different groups apart from the membership. The association of a User, a Group and a Role can be referred to as a HyperEdge. However, it can be easily modeled in a property graph as a node that captures this n-ary relationship, as depicted below in the U1G2R1node.
To find out in what roles a user is for a particular groups (here Group2), the following script can traverse this HyperEdge node and provide answers.
Raw script source
1 | g.v(37).out('hasRoleInGroup').as('hyperedge').out('hasGroup').filter{it.name=='Group2'}.back('hyperedge').out('hasRole').name |
图 18.94. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.v(37).out('hasRoleInGroup').as('hyperedge').out('hasGroup').filter{it.name=='Group2'}.back('hyperedge').out('hasRole').name", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 | [ "Role1"] |
18.18.12. Group count
This example is showing a group count in Gremlin, for instance the counting of the different relationship types connected to some the start node. The result is collected into a variable that then is returned.
Raw script source
1 2 3 | m = [:] g.v(41).bothE().label.groupCount(m).iterate() m |
图 18.95. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "m = [:];g.v(41).bothE().label.groupCount(m).iterate();m", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 | { "knows": 2, "likes": 1 } |
18.18.13. Collect multiple traversal results
Multiple traversals can be combined into a single result, using splitting and merging pipes in a lazy fashion.
Raw script source
1 | g.idx('node_auto_index')[[name:'Peter']].copySplit(_().out('knows'), _().in('likes')).fairMerge.name |
图 18.96. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.idx('node_auto_index')[[name:'Peter']].copySplit(_().out('knows'), _().in('likes')).fairMerge.name", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 | [ "Ian", "Marie"] |
18.18.14. Collaborative filtering
This example demonstrates basic collaborative filtering - ordering a traversal after occurence counts and substracting objects that are not interesting in the final result.
Here, we are finding Friends-of-Friends that are not Joes friends already. The same can be applied to graphs of users that LIKEthings and others.
Raw script source
1 2 3 4 | x=[] fof=[:] g.v(63).out('knows').aggregate(x).out('knows').except(x).groupCount(fof).iterate() fof.sort{a,b -> b.value <=> a.value} |
图 18.97. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "x=[];fof=[:];g.v(63).out('knows').aggregate(x).out('knows').except(x).groupCount(fof).iterate();fof.sort{a,b -> b.value <=> a.value}", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 2 3 4 5 | { "v[61]": 2, "v[60]": 1, "v[62]": 1 } |
18.18.15. Chunking and offsetting in Gremlin
Raw script source
1 | g.v(51).out('knows').filter{it.name == 'Sara'}[0..100] |
图 18.98. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.v(51).out('knows').filter{it.name == 'Sara'}[0..100]", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
18.18.16. Modify the graph while traversing
This example is showing a group count in Gremlin, for instance the counting of the different relationship types connected to some the start node. The result is collected into a variable that then is returned.
图 18.99. Starting Graph
Raw script source
1 | g.v(44).bothE.each{g.removeEdge(it)} |
图 18.100. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "g.v(44).bothE.each{g.removeEdge(it)}", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 | [ ] |
18.18.17. Flow algorithms with Gremlin
This is a basic stub example for implementing flow algorithms in for instance Flow Networkswith a pipes-based approach and scripting, here between sourceand sinkusing the capacityproperty on relationships as the base for the flow function and modifying the graph during calculation.
图 18.101. Starting Graph
Raw script source
1 2 3 4 5 6 7 | source=g.v(72) sink=g.v(73) maxFlow = 0 source.outE.inV.loop(2){!it.object.equals(sink)}.paths.each{flow = it.capacity.min() maxFlow += flow it.findAll{it.capacity}.each{it.capacity -= flow}} maxFlow |
图 18.102. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 4 5 | { "script": "source=g.v(72);sink=g.v(73);maxFlow = 0;source.outE.inV.loop(2){!it.object.equals(sink)}.paths.each{flow = it.capacity.min(); maxFlow += flow;it.findAll{it.capacity}.each{it.capacity -= flow}};maxFlow", "params": { } } |
Example response
- 200:OK
- Content-Type:application/json
1 | 4 |
18.18.18. Script execution errors
Script errors will result in an HTTP error response code.
图 18.103. Final Graph
Example request
- POSThttp://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
- Accept:application/json
- Content-Type:application/json
1 2 3 | { "script": "g.addVertex([name:{}])" } |
Example response
- 400:Bad Request
- Content-Type:application/json
1 2 3 4 5 | { "message": "javax.script.ScriptException: java.lang.IllegalArgumentException: Unknown property type on: Script25$_run_closure1@6160722b, class Script25$_run_closure1", "exception": "BadInputException", "stacktrace": [ "org.neo4j.server.plugin.gremlin.GremlinPlugin.executeScript(GremlinPlugin.java:88)", "java.lang.reflect.Method.invoke(Method.java:597)", "org.neo4j.server.plugins.PluginMethod.invoke(PluginMethod.java:57)", "org.neo4j.server.plugins.PluginManager.invoke(PluginManager.java:168)", "org.neo4j.server.rest.web.ExtensionService.invokeGraphDatabaseExtension(ExtensionService.java:300)", "org.neo4j.server.rest.web.ExtensionService.invokeGraphDatabaseExtension(ExtensionService.java:122)", "java.lang.reflect.Method.invoke(Method.java:597)"] } |