memgraph/docs/user_technical/open-cypher.md
Teon Banek 514d9d2808 Add section on indexing in user documentation
Summary:
The openCypher chapter of user documentation now includes information on
creating label & property index.

Reviewers: florijan, buda

Reviewed By: florijan

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D537
2017-07-12 11:31:50 +02:00

415 lines
15 KiB
Markdown

## openCypher Query Language
[*openCypher*](http://www.opencypher.org/) is a query language for querying
graph databases. It aims to be intuitive and easy to learn, while
providing a powerful interface for working with graph based data.
*Memgraph* supports most of the commonly used constructs of the language. This
chapter contains the details of features which are implemented. Additionally,
not yet supported features of the language are listed.
* [Reading existing Data](#reading-existing-data)
* [Writing new Data](#writing-new-data)
* [Reading & Writing](#reading-amp-writing)
* [Indexing](#indexing)
* [Other Features](#other-features)
### Reading existing Data
The simplest usage of the language is to find data stored in the
database. For that purpose, the following clauses are offered:
* `MATCH`, which searches for patterns;
* `WHERE`, for filtering the matched data and
* `RETURN`, for defining what will be presented to the user in the result
set.
#### MATCH
This clause is used to obtain data from Memgraph by matching it to a given
pattern. For example, to find each node in the database, you can use the
following query.
MATCH (node) RETURN node
Finding connected nodes can be achieved by using the query:
MATCH (node1) -[connection]- (node2) RETURN node1, connection, node2
In addition to general pattern matching, you can narrow the search down by
specifying node labels and properties. Similarly, edge types and properties
can also be specified. For example, finding each node labeled as `Person` and
with property `age` being 42, is done with the following query.
MATCH (n :Person {age: 42}) RETURN n.
While their friends can be found with the following.
MATCH (n :Person {age: 42}) -[:FriendOf]- (friend) RETURN friend.
More details on how `MATCH` works can be found
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/match/).
Note that *variable length paths* and *named paths* are not yet supported.
The `MATCH` clause can be modified by prepending the `OPTIONAL` keyword.
`OPTIONAL MATCH` clause behaves the same as a regular `MATCH`, but when it
fails to find the pattern, missing parts of the pattern will be filled with
`null` values. Examples can be found
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/optional-match/).
#### WHERE
You have already seen that simple filtering can be achieved by using labels
and properties in `MATCH` patterns. When more complex filtering is desired,
you can use `WHERE` paired with `MATCH` or `OPTIONAL MATCH`. For example,
finding each person older than 20 is done with the this query.
MATCH (n :Person) WHERE n.age > 20 RETURN n
Additional examples can be found
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/where/).
#### RETURN
The `RETURN` clause defines which data should be included in the resulting
set. Basic usage was already shown in the examples for `MATCH` and `WHERE`
clauses. Another feature of `RETURN` is renaming the results using the `AS`
keyword.
Example.
MATCH (n :Person) RETURN n AS people
That query would display all nodes under the header named `people` instead of
`n`.
When you want to get everything that was matched, you can use the `*`
(*asterisk*) symbol.
This query:
MATCH (node1) -[connection]- (node2) RETURN *
is equivalent to:
MATCH (node1) -[connection]- (node2) RETURN node1, connection, node2
`RETURN` can be followed by the `DISTINCT` operator, which will remove
duplicate results. For example, getting unique names of people can be achieved
with:
MATCH (n :Person) RETURN DISTINCT n.name
Besides choosing what will be the result and how it will be named, the
`RETURN` clause can also be used to:
* limit results with `LIMIT` sub-clause;
* skip results with `SKIP` sub-clause;
* order results with `ORDER BY` sub-clause and
* perform aggregations (such as `count`).
More details on `RETURN` can be found
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/return/).
##### SKIP & LIMIT
These sub-clauses take a number of how many results to skip or limit.
For example, to get the first 3 results you can use this query.
MATCH (n :Person) RETURN n LIMIT 3
If you want to get all the results after the first 3, you can use the
following.
MATCH (n :Person) RETURN n SKIP 3
The `SKIP` and `LIMIT` can be combined. So for example, to get the 2nd result,
you can do:
MATCH (n :Person) RETURN n SKIP 1 LIMIT 1
##### ORDER BY
Since the patterns which are matched can come in any order, it is very useful
to be able to enforce some ordering among the results. In such cases, you can
use the `ORDER BY` sub-clause.
For example, the following query will get all `:Person` nodes and order them
by their names.
MATCH (n :Person) RETURN n ORDER BY n.name
By default, ordering will be in the ascending order. To change the order to be
descending, you should append `DESC`.
For example, to order people by their name descending, you can use this query.
MATCH (n :Person) RETURN n ORDER BY n.name DESC
You can also order by multiple variables. The results will be sorted by the
first variable listed. If the values are equal, the results are sorted by the
second variable, and so on.
Example. Ordering by first name descending and last name ascending.
MATCH (n :Person) RETURN n ORDER BY n.name DESC, n.lastName
Note that `ORDER BY` sees only the variable names as carried over by `RETURN`.
This means that the following will result in an error.
MATCH (n :Person) RETURN old AS new ORDER BY old.name
Instead, the `new` variable must be used:
MATCH (n: Person) RETURN old AS new ORDER BY new.name
The `ORDER BY` sub-clause may come in handy with `SKIP` and/or `LIMIT`
sub-clauses. For example, to get the oldest person you can use the following.
MATCH (n :Person) RETURN n ORDER BY n.age DESC LIMIT 1
##### Aggregating
openCypher has functions for aggregating data. Memgraph currently supports
the following aggregating functions.
* `avg`, for calculating the average.
* `collect`, for collecting multiple values into a single list.
* `count`, for counting the resulting values.
* `max`, for calculating the maximum result.
* `min`, for calculating the minimum result.
* `sum`, for getting the sum of numeric results.
Example, calculating the average age.
MATCH (n :Person) RETURN avg(n.age) AS averageAge
Click
[here](https://neo4j.com/docs/developer-manual/current/cypher/functions/aggregating/)
for additional details on how aggregations work.
### Writing new Data
For adding new data, you can use the following clauses.
* `CREATE`, for creating new nodes and edges.
* `SET`, for adding new or updating existing labels and properties.
* `DELETE`, for deleting nodes and edges.
* `REMOVE`, for removing labels and properties.
You can still use the `RETURN` clause to produce results after writing, but it
is not mandatory.
#### CREATE
This clause is used to add new nodes and edges to the database. The creation
is done by providing a pattern, similarly to `MATCH` clause.
For example, to create 2 new nodes connected with a new edge, use this query.
CREATE (node1) -[:edge_type]-> (node2)
Additional information on `CREATE` is
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/create/).
#### SET
The `SET` clause is used to update labels and properties of already existing
data.
Example. Incrementing everyone's age by 1.
MATCH (n :Person) SET n.age = n.age + 1
Click
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/create/)
for a more detailed explanation on what can be done with `SET`.
#### DELETE
This clause is used to delete nodes and edges from the database.
Example. Removing all edges of a single type.
MATCH () -[edge :type]- () DELETE edge
When testing the database, you want to often have a clean start by deleting
every node and edge in the database. It is reasonable that deleting each node
should delete all edges coming into or out of that node.
MATCH (node) DELETE node
But, openCypher prevents accidental deletion of edges. Therefore, the above
query will report an error. Instead, you need to use the `DETACH` keyword,
which will remove edges from a node you are deleting. The following should
work and *delete everything* in the database.
MATCH (node) DETACH DELETE node
More examples are
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/delete/).
#### REMOVE
The `REMOVE` clause is used to remove labels and properties from nodes and
edges.
Example.
MATCH (n :WrongLabel) REMOVE n :WrongLabel, n.property
### Reading & Writing
OpenCypher supports combining multiple reads and writes using the
`WITH` clause. In addition to combining, the `MERGE` clause is provided which
may create patterns if they do not exist.
#### WITH
The write part of the query cannot be simply followed by another read part. In
order to combine them, `WITH` clause must be used. The names this clause
establishes are transferred from one part to another.
For example, creating a node and finding all nodes with the same property.
CREATE (node {property: 42}) WITH node.property AS propValue
MATCH (n {property: propValue}) RETURN n
Note that the `node` is not visible after `WITH`, since only `node.property`
was carried over.
This clause behaves very much like `RETURN`, so you should refer to features
of `RETURN`.
#### MERGE
The `MERGE` clause is used to ensure that a pattern you are looking for exists
in the database. This means that if the pattern is not found, it will be
created. In a way, this clause is like a combination of `MATCH` and `CREATE`.
Example. Ensure that a person has at least one friend.
MATCH (n :Person) MERGE (n) -[:FriendOf]-> (m)
The clause also provides additional features for updating the values depending
on whether the pattern was created or matched. This is achieved with `ON
CREATE` and `ON MATCH` sub clauses.
Example. Set a different properties depending on what `MERGE` did.
MATCH (n :Person) MERGE (n) -[:FriendOf]-> (m)
ON CREATE SET m.prop = "created" ON MATCH SET m.prop = "existed"
For more details, click [this
link](https://neo4j.com/docs/developer-manual/current/cypher/clauses/merge/).
### Indexing
An index stores additional information on certain types of data, so that
retrieving said data becomes more efficient. Downsides of indexing are:
* requiring extra storage for each index and
* slowing down writes to the database.
Carefully choosing which data to index can tremendously improve data retrieval
efficiency, and thus make index downsides negligible.
Memgraph automatically indexes labeled data. This improves queries
which fetch nodes by label:
MATCH (n :Label) ... RETURN n
Indexing can also be applied to data with a specific combination of label and
property. These are not automatically created, instead a user needs to create
them explicitly. Creation is done using a special
`CREATE INDEX ON :Label(property)` language construct.
For example, to index nodes which is labeled as `:Person` and has a property
named `age`:
CREATE INDEX ON :Person(age)
After the index is created, retrieving those nodes will become more efficient.
For example, the following query will retrieve all nodes which have an `age`
property, instead of fetching each `:Person` node and checking whether the
property exists.
MATCH (n :Person {age: 42}) RETURN n
Using index based retrieval also works when filtering labels and properties
with `WHERE`. For example, the same effect as in the previous example can be
done with:
MATCH (n) WHERE n:Person AND n.age = 42 RETURN n
Since the filter inside `WHERE` can contain any kind of an expression, the
expression can be complicated enough so that the index does not get used. We
are continuously improving the recognition of index usage opportunities from a
`WHERE` expression. If there is any suspicion that an index may not be used,
we recommend putting properties and labels inside the `MATCH` pattern.
Currently, once an index is created it cannot be deleted. This feature will be
implemented very soon. The expected syntax for removing an index will be `DROP
INDEX ON :Label(property)`.
### Other Features
The following sections describe some of the other supported features.
#### UNWIND
The `UNWIND` clause is used to unwind a list of values as individual rows.
Example. Produce rows out of a single list.
UNWIND [1,2,3] AS listElement RETURN listElement
More examples are
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/unwind/).
#### Functions
You have already been introduced to one type of functions, [aggregating
functions](#aggregating). This section contains the list of other supported
functions.
Name | Description
--------------|------------
`coalesce` | Returns the first non null argument.
`startNode` | Returns the starting node of an edge.
`endNode` | Returns the destination node of an edge.
`head` | Returns the first element of a list.
`last` | Returns the last element of a list.
`properties` | Returns the properties of a node or an edge.
`size` | Returns the number of elements in a list.
`toBoolean` | Converts the argument to a boolean.
`toFloat` | Converts the argument to a floating point number.
`toInteger` | Converts the argument to an integer.
`type` | Returns the type of an edge as a character string.
`keys` | Returns a list keys of properties from an edge or a node. Each key is represented as a string of characters.
`labels` | Return a list of labels from a node. Each label is represented as a character string.
`range` | Constructs a list of value in given range.
`tail` | Returns all elements after the first of a given list.
`abs` | Returns the absolute value of a number.
`ceil` | Returns the smallest integer greater than or equal to given number.
`floor` | Returns the largest integer smaller than or equal to given number.
`round` | Returns the number, rounded to the nearest integer. Tie-breaking is done using the *commercial rounding*, where -1.5 produces -2 and 1.5 produces 2.
`exp` | Calculates `e^n` where `e` is the base of the natural logarithm, and `n` is the given number.
`log` | Calculates the natural logarithm of a given number.
`log10` | Calculates the logarithm (base 10) of a given number.
`sqrt` | Calculates the square root of a given number.
`acos` | Calculates the arccosine of a given number.
`asin` | Calculates the arcsine of a given number.
`atan` | Calculates the arctangent of a given number.
`atan2` | Calculates the arctangent2 of a given number.
`cos` | Calculates the cosine of a given number.
`sin` | Calculates the sine of a given number.
`tan` | Calculates the tangent of a given number.
`sign` | Applies the signum function to a given number and returns the result. The signum of positive numbers is 1, of negative -1 and for 0 returns 0.
`e` | Returns the base of the natural logarithm.
`pi` | Returns the constant *pi*.
`startsWith` | Check if the first argument starts with the second.
`endsWith` | Check if the first argument ends with the second.
`contains` | Check if the first argument has an element which is equal to the second argument.