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:
parent
2c5d756d52
commit
1fac26fa0f
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
```
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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!
|
||||
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
|
@ -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]
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user