Make drivers more visible, fix inconsistency in user docs, add new code-block standard in user docs

Reviewers: buda

Reviewed By: buda

Differential Revision: https://phabricator.memgraph.io/D1432
This commit is contained in:
Ivan Paljak 2018-06-18 17:11:14 +02:00
parent 2c5d756d52
commit 1fac26fa0f
8 changed files with 304 additions and 152 deletions

View File

@ -17,7 +17,9 @@ complexity of the algorithm.
A sample query that finds a shortest path between two nodes can look like this:
MATCH (a {id: 723})-[le *wShortest 10 (e, n | e.weight) total_weight]-(b {id: 882}) RETURN *
```opencypher
MATCH (a {id: 723})-[edge_list *wShortest 10 (e, n | e.weight) total_weight]-(b {id: 882}) RETURN *
```
This query has an upper bound length restriction set to `10`. This means that no
path that traverses more than `10` edges will be considered as a valid result.
@ -42,10 +44,13 @@ Lets take a look at the following graph and queries.
3 3 3
```
MATCH (a {id: 0})-[le *wShortest 3 (e, n | e.weight) total_weight]-(b {id: 5}) RETURN *
MATCH (a {id: 0})-[le *wShortest (e, n | e.weight) total_weight]-(b {id: 5}) RETURN *
```opencypher
MATCH (a {id: 0})-[edge_list *wShortest 3 (e, n | e.weight) total_weight]-(b {id: 5}) RETURN *
```
```opencypher
MATCH (a {id: 0})-[edge_list *wShortest (e, n | e.weight) total_weight]-(b {id: 5}) RETURN *
```
The first query will try to find the weighted shortest path between nodes `0`
and `5` with the restriction on the path length set to `3`, and the second query
@ -65,4 +70,3 @@ graph.
Because of this, one should always try to narrow down the upper bound limit to
be as precise as possible in order to have a more performant query.

View File

@ -1,16 +1,5 @@
## Bolt Drivers
Clients connect to Memgraph using the
[Bolt protocol](https://boltprotocol.org/). Bolt was designed for efficient
communication with graph databases. Memgraph supports
[Version 1](https://boltprotocol.org/v1/) of the protocol. Official Bolt
protocol drivers are provided for multiple programming languages:
* [Java](https://github.com/neo4j/neo4j-java-driver)
* [Python](https://github.com/neo4j/neo4j-python-driver)
* [Javascript](https://github.com/neo4j/neo4j-javascript-driver)
* [C#](https://github.com/neo4j/neo4j-dotnet-driver)
### Python Driver Example
Neo4j officially supports Python for interacting with an openCypher and Bolt
@ -19,7 +8,7 @@ compliant database. For details consult the
[GitHub project](https://github.com/neo4j/neo4j-python-driver). Following is
a basic usage example:
```
```python
from neo4j.v1 import GraphDatabase, basic_auth
# Initialize and configure the driver.
@ -66,7 +55,7 @@ The example below is equivalent to Python example. Major difference is that
has to be disabled by calling `withoutEncryption` method against the `Config`
builder.
```
```java
import org.neo4j.driver.v1.*;
import org.neo4j.driver.v1.types.*;
import static org.neo4j.driver.v1.Values.parameters;
@ -117,7 +106,7 @@ is needed to handle the overhead. The proxy has to be configured to point out
to Memgraph's Bolt port and web browser driver has to send requests to the
proxy port.
```
```javascript
var neo4j = require('neo4j-driver').v1;
var driver = neo4j.driver("bolt://localhost:7687",
neo4j.auth.basic("neo4j", "1234"),
@ -160,7 +149,7 @@ The C# driver is hosted
performs the same work as all of the previous examples. Encryption is disabled
by setting `EncryptionLevel.NONE` on the `Config`.
```
```csh
using System;
using System.Linq;
using Neo4j.Driver.V1;

View File

@ -34,7 +34,7 @@ talk and rating nodes.
We have prepared a database snapshot for this example, so you can easily import
it when starting Memgraph using the `--durability-directory` option.
```
```bash
/usr/lib/memgraph/memgraph --durability-directory /usr/share/memgraph/examples/TEDTalk \
--durability-enabled=false --snapshot-on-exit=false
```
@ -43,13 +43,13 @@ When using Memgraph installed from DEB or RPM package, you may need to stop
the currently running Memgraph server before you can import the example. Use
the following command:
```
```bash
systemctl stop memgraph
```
When using Docker, you can import the example with the following command:
```
```bash
docker run -p 7687:7687 \
-v mg_lib:/var/lib/memgraph -v mg_log:/var/log/memgraph -v mg_etc:/etc/memgraph \
memgraph --durability-directory /usr/share/memgraph/examples/TEDTalk \
@ -62,30 +62,33 @@ NOTE: If you modify the dataset, the changes will stay only during this run of
Memgraph.
1) Find all talks given by specific speaker:
```
```opencypher
MATCH (n:Speaker {name: "Hans Rosling"})-[:Gave]->(m:Talk)
RETURN m.title;
```
2) Find the top 20 speakers with most talks given:
```
```opencypher
MATCH (n:Speaker)-[:Gave]->(m)
RETURN n.name, COUNT(m) as TalksGiven
ORDER BY TalksGiven DESC LIMIT 20;
```
3) Find talks related by tag to specific talk and count them:
```
MATCH (n:Talk {name: "Michael Green: Why we should build wooden skyscrapers"})-[:HasTag]->(t:Tag)<-[:HasTag]-(m:Talk)
```opencypher
MATCH (n:Talk {name: "Michael Green: Why we should build wooden skyscrapers"})
-[:HasTag]->(t:Tag)<-[:HasTag]-(m:Talk)
WITH * ORDER BY m.name
RETURN t.name, COLLECT(m.name), COUNT(m) AS TalksCount
ORDER BY TalksCount DESC;
```
4) Find 20 most frequently used tags:
```
```opencypher
MATCH (t:Tag)<-[:HasTag]-(n:Talk)
RETURN t.name as Tag, COUNT(n) AS TalksCount
ORDER BY TalksCount DESC, Tag LIMIT 20;
@ -95,13 +98,15 @@ ORDER BY TalksCount DESC, Tag LIMIT 20;
possible values are: Obnoxious, Jaw-dropping, OK, Persuasive, Beautiful,
Confusing, Longwinded, Unconvincing, Fascinating, Ingenious, Courageous, Funny,
Informative and Inspiring.
```
```opencypher
MATCH (r:Rating{name:"Funny"})<-[e:HasRating]-(m:Talk)
RETURN m.name, e.user_count ORDER BY e.user_count DESC LIMIT 20;
```
6) Find inspiring talks and their speakers from the field of technology:
```
```opencypher
MATCH (n:Talk)-[:HasTag]->(m:Tag {name: "technology"})
MATCH (n)-[r:HasRating]->(p:Rating {name: "Inspiring"})
MATCH (n)<-[:Gave]-(s:Speaker)
@ -114,7 +119,7 @@ recommendation. If you've just watched a talk from a certain
speaker (e.g. Hans Rosling) you might be interested in finding more talks from
the same speaker on a similar topic:
```
```opencypher
MATCH (n:Speaker {name: "Hans Rosling"})-[:Gave]->(m:Talk)
MATCH (t:Talk {title: "New insights on poverty"})-[:HasTag]->(tag:Tag)<-[:HasTag]-(m)
WITH * ORDER BY tag.name
@ -126,7 +131,8 @@ The following few queries are focused on extracting information about
TED events.
8) Find how many talks were given per event:
```
```opencypher
MATCH (n:Event)<-[:InEvent]-(t:Talk)
RETURN n.name as Event, COUNT(t) AS TalksCount
ORDER BY TalksCount DESC, Event
@ -134,7 +140,8 @@ LIMIT 20;
```
9) Find the most popular tags in the specific event:
```
```opencypher
MATCH (n:Event {name:"TED2006"})<-[:InEvent]-(t:Talk)-[:HasTag]->(tag:Tag)
RETURN tag.name as Tag, COUNT(t) AS TalksCount
ORDER BY TalksCount DESC, Tag
@ -142,7 +149,8 @@ LIMIT 20;
```
10) Discover which speakers participated in more than 2 events:
```
```opencypher
MATCH (n:Speaker)-[:Gave]->(t:Talk)-[:InEvent]->(e:Event)
WITH n, COUNT(e) AS EventsCount WHERE EventsCount > 2
RETURN n.name as Speaker, EventsCount
@ -151,7 +159,8 @@ ORDER BY EventsCount DESC, Speaker;
11) For each speaker search for other speakers that participated in same
events:
```
```opencypher
MATCH (n:Speaker)-[:Gave]->()-[:InEvent]->(e:Event)<-[:InEvent]-()<-[:Gave]-(m:Speaker)
WHERE n.name != m.name
WITH DISTINCT n, m ORDER BY m.name
@ -208,14 +217,14 @@ sketch below shows how this game is being modeled in our database.
We have prepared a database snapshot for this example, so you can easily import
it when starting Memgraph using the `--durability-directory` option.
```
```bash
/usr/lib/memgraph/memgraph --durability-directory /usr/share/memgraph/examples/football \
--durability-enabled=false --snapshot-on-exit=false
```
When using Docker, you can import the example with the following command:
```
```bash
docker run -p 7687:7687 \
-v mg_lib:/var/lib/memgraph -v mg_log:/var/log/memgraph -v mg_etc:/etc/memgraph \
memgraph --durability-directory /usr/share/memgraph/examples/football \
@ -229,7 +238,7 @@ Memgraph.
1) You might wonder, what leagues are supported?
```
```opencypher
MATCH (n:Game)
RETURN DISTINCT n.league AS League
ORDER BY League;
@ -238,7 +247,7 @@ ORDER BY League;
2) We have stored a certain number of seasons for each league. What is the
oldest/newest season we have included?
```
```opencypher
MATCH (n:Game)
RETURN DISTINCT n.league AS League, MIN(n.season) AS Oldest, MAX(n.season) AS Newest
ORDER BY League;
@ -247,7 +256,7 @@ ORDER BY League;
3) You have already seen one game between Chelsea and Arsenal, let's list all of
them in chronological order.
```
```opencypher
MATCH (n:Team {name: "Chelsea"})-[e:Played]->(w:Game)<-[f:Played]-(m:Team {name: "Arsenal"})
RETURN w.date AS Date, e.side AS Chelsea, f.side AS Arsenal,
w.FT_home_score AS home_score, w.FT_away_score AS away_score
@ -256,7 +265,7 @@ ORDER BY Date;
4) How about filtering games in which Chelsea won?
```
```opencypher
MATCH (n:Team {name: "Chelsea"})-[e:Played {outcome: "won"}]->
(w:Game)<-[f:Played]-(m:Team {name: "Arsenal"})
RETURN w.date AS Date, e.side AS Chelsea, f.side AS Arsenal,
@ -267,7 +276,7 @@ ORDER BY Date;
5) Home field advantage is a thing in football. Let's list the number of home
defeats for each Premier League team in the 2016/2017 season.
```
```opencypher
MATCH (n:Team)-[:Played {side: "home", outcome: "lost"}]->
(w:Game {league: "ENG-Premier League", season: 2016})
RETURN n.name AS Team, count(w) AS home_defeats
@ -279,7 +288,7 @@ each victory, a team is awarded 3 points and for each draw it is awarded
1 point. Let's find out how many points did reigning champions (Chelsea) have
at the end of 2016/2017 season.
```
```opencypher
MATCH (n:Team {name: "Chelsea"})-[:Played {outcome: "drew"}]->(w:Game {season: 2016})
WITH n, COUNT(w) AS draw_points
MATCH (n)-[:Played {outcome: "won"}]->(w:Game {season: 2016})
@ -288,7 +297,7 @@ RETURN draw_points + 3 * COUNT(w) AS total_points;
7) In fact, why not retrieve the whole table?
```
```opencypher
MATCH (n)-[:Played {outcome: "drew"}]->(w:Game {league: "ENG-Premier League", season: 2016})
WITH n, COUNT(w) AS draw_points
MATCH (n)-[:Played {outcome: "won"}]->(w:Game {league: "ENG-Premier League", season: 2016})
@ -300,7 +309,7 @@ ORDER BY total_points DESC;
One basic metric is the average number of goals per game. Let's see the results
at the end of the 2016/2017 season. WARNING: This might shock you.
```
```opencypher
MATCH (w:Game {season: 2016})
RETURN w.league, AVG(w.FT_home_score) + AVG(w.FT_away_score) AS avg_goals_per_game
ORDER BY avg_goals_per_game DESC;
@ -311,7 +320,7 @@ was winning at half time but were overthrown by the other side by the end
of the match. Let's count such occurrences during all supported seasons across
all supported leagues.
```
```opencypher
MATCH (g:Game) WHERE
(g.HT_result = "H" AND g.FT_result = "A") OR
(g.HT_result = "A" AND g.FT_result = "H")
@ -323,7 +332,7 @@ ORDER BY Comebacks DESC;
all triplets of teams where, during the course of one season, team A won against
team B, team B won against team C and team C won against team A.
```
```opencypher
MATCH (a)-[:Played {outcome: "won"}]->(p:Game {league: "ENG-Premier League", season: 2016})<--
(b)-[:Played {outcome: "won"}]->(q:Game {league: "ENG-Premier League", season: 2016})<--
(c)-[:Played {outcome: "won"}]->(r:Game {league: "ENG-Premier League", season: 2016})<--(a)
@ -407,7 +416,7 @@ breadth-first search (BFS) algorithm.
```opencypher
MATCH p = (:City {name: "Zagreb"})
-[:Road * bfs]->
(:City {name: "Paris"})
(:City {name: "Paris"})
RETURN nodes(p);
```
@ -505,6 +514,6 @@ A nice looking set of small graph examples can be found
execute the queries against Memgraph. To clear the database between trying out
examples, execute the query:
```
```opencypher
MATCH (n) DETACH DELETE n;
```

View File

@ -15,7 +15,7 @@ The import tool is run from the console, using the `mg_import_csv` command.
If you installed Memgraph using Docker, you will need to run the importer
using the following command:
```
```bash
docker run -v mg_lib:/var/lib/memgraph -v mg_etc:/etc/memgraph -v mg_import:/import-data \
--entrypoint=mg_import_csv memgraph
```
@ -38,13 +38,13 @@ durability directory.
For information on other options, run:
```
```bash
mg_import_csv --help
```
When using Docker, this translates to:
```
```bash
docker run --entrypoint=mg_import_csv memgraph --help
```
@ -93,21 +93,21 @@ will load the new dataset.
Use the following command:
```
```bash
mg_import_csv --nodes=comment_nodes.csv --nodes=forum_nodes.csv --relationships=relationships.csv
```
If using Docker, things are a bit more complicated. First you need to move the
CSV files where the Docker image can see them:
```
```bash
mkdir -p /var/lib/docker/volumes/mg_import/_data
cp comment_nodes.csv forum_nodes.csv relationships.csv /var/lib/docker/volumes/mg_import/_data
```
Then, run the importer with the following:
```
```bash
docker run -v mg_lib:/var/lib/memgraph -v mg_etc:/etc/memgraph -v mg_import:/import-data \
--entrypoint=mg_import_csv memgraph \
--nodes=/import-data/comment_nodes.csv --nodes=/import-data/forum_nodes.csv \
@ -115,4 +115,3 @@ docker run -v mg_lib:/var/lib/memgraph -v mg_etc:/etc/memgraph -v mg_import:/imp
```
Next time you run Memgraph, the dataset will be loaded.

View File

@ -31,22 +31,30 @@ 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
```opencypher
MATCH (node) RETURN node
```
Finding connected nodes can be achieved by using the query:
MATCH (node1)-[connection]-(node2) RETURN node1, connection, node2
```opencypher
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
```opencypher
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
```opencypher
MATCH (n :Person {age: 42})-[:FriendOf]-(friend) RETURN friend
```
There are cases when a user needs to find data which is connected by
traversing a path of connections, but the user doesn't know how many
@ -56,18 +64,24 @@ with *variable path lengths*. Matching such a path is achieved by using the
traversing from `node1` to `node2` by following any number of connections in a
single direction can be achieved with:
MATCH (node1)-[r*]->(node2) RETURN node1, r, node2
```opencypher
MATCH (node1)-[r*]->(node2) RETURN node1, r, node2
```
If paths are very long, finding them could take a long time. To prevent that,
a user can provide the minimum and maximum length of the path. For example,
paths of length between 2 and 4 can be obtained with a query like:
MATCH (node1)-[r*2..4]->(node2) RETURN node1, r, node2
```opencypher
MATCH (node1)-[r*2..4]->(node2) RETURN node1, r, node2
```
It is possible to name patterns in the query and return the resulting paths.
This is especially useful when matching variable length paths:
MATCH path = ()-[r*2..4]->() RETURN path
```opencypher
MATCH path = ()-[r*2..4]->() RETURN path
```
More details on how `MATCH` works can be found
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/match/).
@ -85,7 +99,9 @@ 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
```opencypher
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/).
@ -99,7 +115,9 @@ keyword.
Example.
MATCH (n :Person) RETURN n AS people
```opencypher
MATCH (n :Person) RETURN n AS people
```
That query would display all nodes under the header named `people` instead of
`n`.
@ -109,17 +127,23 @@ When you want to get everything that was matched, you can use the `*`
This query:
MATCH (node1)-[connection]-(node2) RETURN *
```opencypher
MATCH (node1)-[connection]-(node2) RETURN *
```
is equivalent to:
MATCH (node1)-[connection]-(node2) RETURN node1, connection, node2
```opencypher
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
```opencypher
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:
@ -137,17 +161,23 @@ More details on `RETURN` can be found
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
```opencypher
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
```opencypher
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
```opencypher
MATCH (n :Person) RETURN n SKIP 1 LIMIT 1
```
##### ORDER BY
@ -158,14 +188,18 @@ 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
```opencypher
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
```opencypher
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
@ -173,21 +207,29 @@ 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
```opencypher
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
```opencypher
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
```opencypher
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
```opencypher
MATCH (n :Person) RETURN n ORDER BY n.age DESC LIMIT 1
```
##### Aggregating
@ -203,15 +245,21 @@ the following aggregating functions.
Example, calculating the average age:
MATCH (n :Person) RETURN avg(n.age) AS averageAge
```opencypher
MATCH (n :Person) RETURN avg(n.age) AS averageAge
```
Collecting items into a list:
MATCH (n :Person) RETURN collect(n.name) AS list_of_names
```opencypher
MATCH (n :Person) RETURN collect(n.name) AS list_of_names
```
Collecting items into a map:
MATCH (n :Person) RETURN collect(n.name, n.age) AS map_name_to_age
```opencypher
MATCH (n :Person) RETURN collect(n.name, n.age) AS map_name_to_age
```
Click
[here](https://neo4j.com/docs/developer-manual/current/cypher/functions/aggregating/)
@ -229,16 +277,20 @@ rows from all given queries.
Restrictions when using `UNION` or `UNION ALL`:
* The number and the names of columns returned by queries must be the same
for all of them.
* There can be only one union type between single queries, ie. a query can't
* There can be only one union type between single queries, i.e. a query can't
contain both `UNION` and `UNION ALL`.
Example, get distinct names that are shared between persons and movies:
MATCH(n: Person) RETURN n.name as name UNION MATCH(n: Movie) RETURN n.name as name
```opencypher
MATCH(n: Person) RETURN n.name as name UNION MATCH(n: Movie) RETURN n.name as name
```
Example, get all names that are shared between persons and movies (including duplicates):
MATCH(n: Person) RETURN n.name as name UNION ALL MATCH(n: Movie) RETURN n.name as name
```opencypher
MATCH(n: Person) RETURN n.name as name UNION ALL MATCH(n: Movie) RETURN n.name as name
```
### Writing New Data
@ -262,13 +314,17 @@ 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)
```opencypher
CREATE (node1)-[:edge_type]->(node2)
```
Labels and properties can be set during creation using the same syntax as in
[MATCH](#match) patterns. For example, creating a node with a label and a
property:
CREATE (node :Label {property: "my property value"}
```opencypher
CREATE (node :Label {property: "my property value"}
```
Additional information on `CREATE` is
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/create/).
@ -280,7 +336,9 @@ data.
Example. Incrementing everyone's age by 1.
MATCH (n :Person) SET n.age = n.age + 1
```opencypher
MATCH (n :Person) SET n.age = n.age + 1
```
Click
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/create/)
@ -292,20 +350,26 @@ 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
```opencypher
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
```opencypher
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
```opencypher
MATCH (node) DETACH DELETE node
```
More examples are
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/delete/).
@ -317,7 +381,9 @@ edges.
Example.
MATCH (n :WrongLabel) REMOVE n :WrongLabel, n.property
```opencypher
MATCH (n :WrongLabel) REMOVE n :WrongLabel, n.property
```
### Reading & Writing
@ -333,8 +399,10 @@ 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
```opencypher
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.
@ -351,7 +419,9 @@ 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)
```opencypher
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
@ -359,8 +429,10 @@ 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"
```opencypher
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/).
@ -379,7 +451,9 @@ 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
```opencypher
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
@ -389,20 +463,26 @@ them explicitly. Creation is done using a special
For example, to index nodes which is labeled as `:Person` and has a property
named `age`:
CREATE INDEX ON :Person(age)
```opencypher
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
```opencypher
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
```opencypher
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
@ -423,16 +503,22 @@ The following sections describe some of the other supported features.
OpenCypher supports only simple filtering when matching variable length paths.
For example:
MATCH (n)-[r:Type * {x: 42}]-(m)
```opencypher
MATCH (n)-[edge_list:Type * {x: 42}]-(m)
```
This will produce only those paths whose edges have the required `Type` and `x`
property value.
property value. Edges that compose the produced paths are stored in a symbol
named `edge_list`. Naturally, the user could have specified any other symbol
name.
Memgraph extends openCypher with a syntax for arbitrary filter expressions
during path matching. The next example filters edges which have property `x`
between `0` and `10`.
MATCH (n)-[r * (edge, node | 0 < edge.x < 10)]-(m)
```opencypher
MATCH (n)-[edge_list * (edge, node | 0 < edge.x < 10)]-(m)
```
Here we introduce a lambda function with parentheses, where the first two
arguments, `edge` and `node`, correspond to each edge and node during path
@ -443,7 +529,9 @@ value. If `True`, matching continues, otherwise the path is discarded.
The previous example can be written using the `all` function:
MATCH (n)-[r *]-(m) WHERE all(edge IN r WHERE 0 < edge.x < 10)
```opencypher
MATCH (n)-[edge_list *]-(m) WHERE all(edge IN r WHERE 0 < edge.x < 10)
```
However, filtering using a lambda function is more efficient because paths
may be discarded earlier in the traversal. Furthermore, it provides more
@ -460,7 +548,9 @@ a custom implementation, based on the edge expansion syntax.
Finding the shortest path between nodes can be done using breadth-first
expansion:
MATCH (a {id: 723})-[r:Type *bfs..10]-(b {id: 882}) RETURN *
```opencypher
MATCH (a {id: 723})-[edge_list:Type *bfs..10]-(b {id: 882}) RETURN *
```
The above query will find all paths of length up to 10 between nodes `a` and `b`.
The edge type and maximum path length are used in the same way like in variable
@ -468,17 +558,23 @@ length expansion.
To find only the shortest path, simply append `LIMIT 1` to the `RETURN` clause.
MATCH (a {id: 723})-[r:Type *bfs..10]-(b {id: 882}) RETURN * LIMIT 1
```opencypher
MATCH (a {id: 723})-[edge_list:Type *bfs..10]-(b {id: 882}) RETURN * LIMIT 1
```
Breadth-first expansion allows an arbitrary expression filter that determines
if an expansion is allowed. Following is an example in which expansion is
allowed only over edges whose `x` property is greater than `12` and nodes `y`
whose property is less than `3`:
MATCH (a {id: 723})-[*bfs..10 (e, n | e.x > 12 and n.y < 3)]-() RETURN *
```opencypher
MATCH (a {id: 723})-[*bfs..10 (e, n | e.x > 12 and n.y < 3)]-() RETURN *
```
The filter is defined as a lambda function over `e` and `n`, which denote the edge
and node being expanded over in the breadth first search.
and node being expanded over in the breadth first search. Note that if the user
omits the edge list symbol (`edge_list` in previous examples) it will not be included
in the result.
There are a few benefits of the breadth-first expansion approach, as opposed to
a specialized `shortestPath` function. For one, it is possible to inject
@ -499,7 +595,12 @@ Memgraph provides a custom implementation, based on the edge expansion syntax.
Finding the weighted shortest path between nodes is done using the weighted
shortest path expansion:
MATCH (a {id: 723})-[le *wShortest 10 (e, n | e.weight) total_weight]-(b {id: 882}) RETURN *
```opencypher
MATCH (a {id: 723})-[
edge_list *wShortest 10 (e, n | e.weight) total_weight
]-(b {id: 882})
RETURN *
```
The above query will find the shortest path of length up to 10 nodes between
nodes `a` and `b`. The length restriction parameter is optional.
@ -510,15 +611,24 @@ the sum of all weights on the path between two nodes. Following is an example in
which the weight between nodes is defined as the product of edge weights
(instead of sum), assuming all weights are greater than '1':
MATCH (a {id: 723})-[le *wShortest 10 (e, n | log(e.weight)) total_weight]-(b {id: 882}) RETURN exp(total_weight)
```opencypher
MATCH (a {id: 723})-[
edge_list *wShortest 10 (e, n | log(e.weight)) total_weight
]-(b {id: 882})
RETURN exp(total_weight)
```
Weighted Shortest Path expansions also allows an arbitrary expression filter
that determines if an expansion is allowed. Following is an example in which
expansion is allowed only over edges whose `x` property is greater than `12`
and nodes `y` whose property is less than `3`:
MATCH (a {id: 723})-[le *wShortest 10 (e, n | e.weight) total_weight (e, n | e.x > 12 and n.y < 3)]-(b {id: 882}) RETURN exp(total_weight)
```opencypher
MATCH (a {id: 723})-[
edge_list *wShortest 10 (e, n | e.weight) total_weight (e, n | e.x > 12 and n.y < 3)
]-(b {id: 882})
RETURN exp(total_weight)
```
Both weight and filter expression are defined as lambda functions over `e` and
`n`, which denote the edge and the node being expanded over in the weighted
@ -530,7 +640,9 @@ 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
```opencypher
UNWIND [1,2,3] AS listElement RETURN listElement
```
More examples are
[here](https://neo4j.com/docs/developer-manual/current/cypher/clauses/unwind/).
@ -613,24 +725,32 @@ The syntax uses the `$` symbol to designate a parameter name. We don't allow
old Cypher parameter syntax using curly braces. For example, you can parameterize
filtering a node property:
MATCH (node1 {property: $propertyValue}) RETURN node1
```opencypher
MATCH (node1 {property: $propertyValue}) RETURN node1
```
You can use parameters instead of any literal in the query, but not instead of
property maps even though that is allowed in standard openCypher. Following
example is illegal in Memgraph:
MATCH (node1 $propertyValue) RETURN node1
```opencypher
MATCH (node1 $propertyValue) RETURN node1
```
To use parameters with Python driver use following syntax:
session.run('CREATE (alice:Person {name: $name, age: $ageValue}',
name='Alice', ageValue=22)).consume()
```python
session.run('CREATE (alice:Person {name: $name, age: $ageValue}',
name='Alice', ageValue=22)).consume()
```
To use parameters which names are integers you will need to wrap parameters in
a dictionary and convert them to strings before running a query:
session.run('CREATE (alice:Person {name: $0, age: $1}',
{'0': "Alice", '1': 22})).consume()
```python
session.run('CREATE (alice:Person {name: $0, age: $1}',
{'0': "Alice", '1': 22})).consume()
```
To use parameters with some other driver please consult appropriate
documentation.
@ -644,15 +764,19 @@ expression provided after the `THEN` keyword is returned. If no expression is
matched value following `ELSE` is returned is provided, or `null` if `ELSE` is not
used:
MATCH (n)
RETURN CASE n.currency WHEN "DOLLAR" THEN "$" WHEN "EURO" THEN "€" ELSE "UNKNOWN" END
```opencypher
MATCH (n)
RETURN CASE n.currency WHEN "DOLLAR" THEN "$" WHEN "EURO" THEN "€" ELSE "UNKNOWN" END
```
In generic form, you don't need to provide an expression whose value is compared to
predicates, but you can list multiple predicates and the first one that evaluates
to true is matched:
MATCH (n)
RETURN CASE WHEN n.height < 30 THEN "short" WHEN n.height > 300 THEN "tall" END
```opencypher
MATCH (n)
RETURN CASE WHEN n.height < 30 THEN "short" WHEN n.height > 300 THEN "tall" END
```
### Differences

View File

@ -28,13 +28,13 @@ compatible with all later versions.
After installing and running Docker, download the Memgraph Docker image and
import it with the following command.
```
```bash
docker load -i /path/to/memgraph-<version>-docker.tar.gz
```
Memgraph is then started with another docker command.
```
```bash
docker run -p 7687:7687 \
-v mg_lib:/var/lib/memgraph -v mg_log:/var/log/memgraph -v mg_etc:/etc/memgraph \
memgraph
@ -42,7 +42,7 @@ docker run -p 7687:7687 \
On success, expect to see output similar to the following.
```
```bash
Starting 8 workers
Server is fully armed and operational
Listening on 0.0.0.0 at 7687
@ -61,26 +61,26 @@ configuration, Memgraph needs to be restarted.
After downloading Memgraph as a Debian package, install it by running the
following.
```
```bash
dpkg -i /path/to/memgraph_<version>.deb
```
If the installation was successful, Memgraph should already be running. To
make sure that is true, start it explicitly with the command:
```
```bash
systemctl start memgraph
```
To verify that Memgraph is running, run the following command.
```
```bash
journalctl --unit memgraph
```
It is expected to see something like the following output.
```
```bash
Nov 23 13:40:13 hostname memgraph[14654]: Starting 8 workers
Nov 23 13:40:13 hostname memgraph[14654]: Server is fully armed and operational
Nov 23 13:40:13 hostname memgraph[14654]: Listening on 0.0.0.0 at 7687
@ -90,7 +90,7 @@ Memgraph is now ready to process queries, you may now proceed to
[querying](#querying). To shutdown Memgraph server, issue the following
command.
```
```bash
systemctl stop memgraph
```
@ -102,26 +102,26 @@ changing the configuration, Memgraph needs to be restarted.
If you downloaded the RPM package of Memgraph, you can install it by running
the following command.
```
```bash
rpm -U /path/to/memgraph-<version>.rpm
```
After the successful installation, Memgraph can be started as a service. To do
so, type the following command.
```
```bash
systemctl start memgraph
```
To verify that Memgraph is running, run the following command.
```
```bash
journalctl --unit memgraph
```
It is expected to see something like the following output.
```
```bash
Nov 23 13:40:13 hostname memgraph[14654]: Starting 8 workers
Nov 23 13:40:13 hostname memgraph[14654]: Server is fully armed and operational
Nov 23 13:40:13 hostname memgraph[14654]: Listening on 0.0.0.0 at 7687
@ -131,7 +131,7 @@ Memgraph is now ready to process queries, you may now proceed to
[querying](#querying). To shutdown Memgraph server, issue the following
command.
```
```bash
systemctl stop memgraph
```
@ -152,13 +152,13 @@ described [on the official website](https://neo4j-client.net).
After installing `neo4j-client`, connect to the running Memgraph instance by
issuing the following shell command.
```
```bash
neo4j-client --insecure -u "" -p "" localhost 7687
```
After the client has started it should present a command prompt similar to:
```
```bash
neo4j-client 2.1.3
Enter `:help` for usage hints.
Connected to 'neo4j://@localhost:7687' (insecure)
@ -168,7 +168,7 @@ neo4j>
At this point it is possible to execute openCypher queries on Memgraph. Each
query needs to end with the `;` (*semicolon*) character. For example:
```
```opencypher
CREATE (u:User {name: "Alice"})-[:Likes]->(m:Software {name: "Memgraph"});
```
@ -178,17 +178,35 @@ create a relationship that "Alice" *likes* "Memgraph".
To find created nodes and relationships, execute the following query:
```
```opencypher
MATCH (u:User)-[r]->(x) RETURN u, r, x;
```
#### Supported languages
If users wish to query Memgraph programmatically, they can do so using the
[Bolt protocol](https://boltprotocol.org). Bolt was designed for efficient
communication with graph databases and Memgraph supports
[Version 1](https://boltprotocol.org/v1) of the protocol. Bolt protocol drivers
for some popular programming languages are listed below:
* [Java](https://github.com/neo4j/neo4j-java-driver)
* [Python](https://github.com/neo4j/neo4j-python-driver)
* [JavaScript](https://github.com/neo4j/neo4j-javascript-driver)
* [C#](https://github.com/neo4j/neo4j-dotnet-driver)
* [Ruby](https://github.com/neo4jrb/neo4j)
* [Haskell](https://github.com/zmactep/hasbolt)
* [PHP](https://github.com/graphaware/neo4j-bolt-php)
We have included some basic usage examples for some of the supported languages
in the **Drivers** section.
### Where to Next
To learn more about the openCypher language, visit **openCypher Query
Language** chapter in this document. For real-world examples of how to use
Memgraph visit **Examples** chapter. If you wish to use a programming language
to execute queries on Memgraph, go to the **Drivers** chapter. Details on what
can be stored in Memgraph are in **Data Storage** chapter.
Memgraph visit **Examples** chapter. Details on what can be stored in Memgraph
are in **Data Storage** chapter.
We *welcome and encourage* your feedback!

View File

@ -68,13 +68,17 @@ types. Following is a table of supported data types.
Note that even though it's possible to store `List` and `Map` property values, it is not possible to modify them. It is however possible to replace them completely. So, the following queries are legal:
CREATE (:Node {property: [1, 2, 3]})
CREATE (:Node {property: {key: "value"}})
```opencypher
CREATE (:Node {property: [1, 2, 3]})
CREATE (:Node {property: {key: "value"}})
```
However, these queries are not:
MATCH (n:Node) SET n.property[0] = 0
MATCH (n:Node) SET n.property.key = "other value"
```opencypher
MATCH (n:Node) SET n.property[0] = 0
MATCH (n:Node) SET n.property.key = "other value"
```
### Cold data on disk
@ -89,7 +93,7 @@ For example, a user of a library database might identify author biographies
and book summaries as cold properties. In that case, the user should run
*Memgraph* as follows:
```
```bash
/usr/lib/memgraph/memgraph --properties-on-disk biography,summary
```

View File

@ -43,14 +43,19 @@ manipulating values which are collected into a list.
For example, getting numbers between 0 and 10 and squaring them:
RETURN [x IN range(0, 10) | x^2] AS squares
```opencypher
RETURN [x IN range(0, 10) | x^2] AS squares
```
Another example, to collect `:Person` nodes with `age` less than 42, without
list comprehensions can be achieved with:
MATCH (n :Person) WHERE n.age < 42 RETURN collect(n)
```opencypher
MATCH (n :Person) WHERE n.age < 42 RETURN collect(n)
```
Using list comprehensions, the same can be done with the query:
MATCH (n :Person) RETURN [n IN collect(n) WHERE n.age < 42]
```opencypher
MATCH (n :Person) RETURN [n IN collect(n) WHERE n.age < 42]
```