344 lines
10 KiB
Markdown
344 lines
10 KiB
Markdown
---
|
||
title: Syntax_examples
|
||
updated: 2022-07-18 09:37:40Z
|
||
created: 2021-05-04 14:58:11Z
|
||
---
|
||
|
||
## show database schema info
|
||
CALL db.schema.visualization()
|
||
CALL db.schema.relTypeProperties()
|
||
CALL db.schema.nodeTypeProperties()
|
||
CALL db.propertyKeys()
|
||
|
||
## syntax
|
||
MATCH (variable:Label {propertyKey: propertyValue, propertyKey2: propertyValue2})
|
||
RETURN variable
|
||
|
||
## relationships
|
||
() // a node
|
||
()--() // 2 nodes have some type of relationship
|
||
()-[]-() // 2 nodes have some type of relationship
|
||
()-->() // the first node has a relationship to the second node
|
||
()<--() // the second node has a relationship to the first node
|
||
|
||
MATCH (node1)-[:REL_TYPE]->(node2)
|
||
RETURN node1, node2
|
||
|
||
MATCH (node1)-[:REL_TYPEA | REL_TYPEB]->(node2)
|
||
RETURN node1, node2
|
||
|
||
|
||
|
||
## show node with name "Tom Hanks"
|
||
MATCH (tom {name: "Tom"}) RETURN tom
|
||
|
||
## return all nodes in database
|
||
MATCH (a:Person) WHERE a.name = "Tom" RETURN a
|
||
MATCH (a:Person) RETURN a.name
|
||
|
||
## with where clause
|
||
match (a:Movie)
|
||
where a.released >= 1990 and a.released < 1999
|
||
return a.title;
|
||
|
||
## a list of all properties that match a string
|
||
MATCH (n) WITH keys(n) AS p UNWIND p AS x WITH DISTINCT x WHERE x =~ ".*" RETURN collect(x) AS SET;
|
||
|
||
## delete all nodes and relations
|
||
MATCH (n)
|
||
DETACH DELETE n
|
||
|
||
## create
|
||
```cypher
|
||
create (:Person {name = 'jan', age = 32})
|
||
```
|
||
|
||
match(n:Person {age: 32}) return n
|
||
|
||
match(n:Person {age: 32})
|
||
create (n)-[:RELATIE]->(:Person {name:"klaas"})
|
||
|
||
MATCH (n:Person)
|
||
DETACH DELETE n
|
||
|
||
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(other:Person)
|
||
where toLower(p.name) =~ 'gene.*' and other.born IN [1950,1930]
|
||
and exists((other)-[:DIRECTED]->(m))
|
||
return m.title, other.name, other.born as YearBorn
|
||
|
||
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
|
||
where p.name = 'Tom Hanks'
|
||
with m, datetime().year - m.released as Ago, m.released - p.born as Age
|
||
where 20 <= Ago <= 33
|
||
return m.title, Ago
|
||
|
||
MATCH (m:Movie)
|
||
WITH m, size((:Person)-[:DIRECTED]->(m)) AS directors
|
||
WHERE directors >= 2
|
||
OPTIONAL MATCH (p:Person)-[:REVIEWED]->(m)
|
||
RETURN m.title, p.name
|
||
|
||
|
||
match (a:Person), (m:Movie), (b:Person)
|
||
where a.name = 'Liam Neeson'
|
||
and b.name = 'Benjamin Melniker'
|
||
and m.title = 'Batman Begins'
|
||
create (a)-[:ACTED_IN {roles: ['Rachel','Rachel Dawes']}]->(m)<-[:PRODUCED]-(b)
|
||
return a,m,b
|
||
|
||
MATCH (a:Person),(m:Movie)
|
||
WHERE a.name = 'Christian Bale' AND
|
||
m.title = 'Batman Begins' AND
|
||
NOT exists((a)-[:ACTED_IN]->(m))
|
||
CREATE (a)-[rel:ACTED_IN]->(m)
|
||
SET rel.roles = ['Bruce Wayne','Batman']
|
||
RETURN a, rel, m
|
||
|
||
MATCH (p:Person)-[rel:ACTED_IN]->(m:Movie)
|
||
where m.title = 'Forrest Gump'
|
||
set rel.roles = case p.name
|
||
when 'Tom Hanks' then ['Forrest Gum']
|
||
when 'Robin Wright' then ['Jenny Curran']
|
||
when 'Gary Sinise' then ['Lieutenant Dan Taylor']
|
||
end
|
||
return p,rel,m
|
||
|
||
MATCH (p:Person)-[rel:HELPED]->(p2:Person)
|
||
where p.name = 'Tom Hanks' and p2.name = 'Gary Sinise'
|
||
set rel += {research:'war history'}
|
||
return p,rel,p2
|
||
|
||
merge (m:Movie {name:'Forrest Gump'})
|
||
on match set m.year = 1994
|
||
on match set m.tagline = 'Life is like a box of chocolates…you never know what you’re gonna get.'
|
||
return m
|
||
|
||
merge (p:Movie {name:'Forrest Gump'})
|
||
on match set p:OlderMovie
|
||
return p
|
||
|
||
match (p:Person {name:'Robert Zemeckis'}), (m:Movie {title:'Forrest Gump'})
|
||
merge (p)-[r:DIRECTED]->(m)
|
||
return p,r,m
|
||
|
||
|
||
## constrain uniqueness
|
||
CREATE CONSTRAINT UniqueMovieTitleConstraint
|
||
ON (m:Movie)
|
||
ASSERT m.title IS UNIQUE
|
||
|
||
## constrain uniqueness over two properties
|
||
## only enterprise edition
|
||
CREATE CONSTRAINT UniqueNameBornConstraint
|
||
ON (p:Person)
|
||
ASSERT (p.name, p.born) IS NODE KEY
|
||
|
||
## needs enterprise edition of neo4j
|
||
create constraint PersonBornExistsConstraint on (p:Person)
|
||
assert exists(p.born)
|
||
|
||
|
||
## existence constraint (possible for node
|
||
CREATE CONSTRAINT ExistsMovieTagline
|
||
ON (m:Movie)
|
||
ASSERT exists(m.tagline)
|
||
|
||
DROP CONSTRAINT MovieTitleConstraint
|
||
|
||
## existence constraint for relationship
|
||
## only enterprise edition of neo4j
|
||
CREATE CONSTRAINT ExistsREVIEWEDRating
|
||
ON ()-[rel:REVIEWED]-()
|
||
ASSERT exists(rel.rating)
|
||
|
||
## drop constraint
|
||
DROP CONSTRAINT ExistsREVIEWEDRating
|
||
|
||
CALL db.constraints() better SHOW CONSTRAINTS
|
||
|
||
## Indexes
|
||
## Single property index
|
||
CREATE INDEX MovieReleased FOR (m:Movie) ON (m.released)
|
||
|
||
## composite index
|
||
CREATE INDEX MovieReleasedVideoFormat
|
||
FOR (m:Movie)
|
||
ON (m.released, m.videoFormat)
|
||
|
||
## full-text schema index
|
||
CALL db.index.fulltext.createNodeIndex(
|
||
'MovieTitlePersonName',['Movie', 'Person'], ['title', 'name'])
|
||
### To use a full-text schema index, you must call the query procedure that uses the index.
|
||
CALL db.index.fulltext.queryNodes(
|
||
'MovieTitlePersonName', 'Jerry')
|
||
YIELD node, score
|
||
RETURN node.title, score
|
||
|
||
### Searching on a particular property
|
||
CALL db.index.fulltext.queryNodes(
|
||
'MovieTitlePersonName', 'name: Jerry') YIELD node
|
||
RETURN node
|
||
|
||
## drop index
|
||
DROP INDEX MovieReleasedVideoFormat
|
||
|
||
## dropping full-text schema index
|
||
CALL db.index.fulltext.drop('MovieTitlePersonName')
|
||
|
||
## search a full-text schema index
|
||
CALL db.index.fulltext.queryNodes('MovieTaglineFTIndex', 'real OR world')
|
||
YIELD node
|
||
RETURN node.title, node.tagline
|
||
|
||
## set parameters
|
||
:param year => 2000
|
||
:params {actorName: 'Tom Cruise', movieName: 'Top Gun'}
|
||
## for statement
|
||
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
|
||
WHERE p.name = $actorName AND m.title = $movieName
|
||
RETURN p, m
|
||
## clear
|
||
:params {}
|
||
## view
|
||
:params
|
||
|
||
## Analyzing queries
|
||
- EXPLAIN provides estimates of the graph engine processing that will occur, but does not execute the Cypher statement.
|
||
|
||
- PROFILE provides real profiling information for what has occurred in the graph engine during the query and executes the Cypher statement. (run-time performance metrics)
|
||
|
||
## Monitoring queries
|
||
:queries
|
||
|
||
|
||
## exercise
|
||
:params {year:2006, ratingValue:65}
|
||
|
||
match (p:Person)-[r:REVIEWED]->(m:Movie)<-[:ACTED_IN]-(a:Person)
|
||
where m.released = $year and r.rating = $ratingValue
|
||
return p.name, m.title, m.released, r.rating, collect(a.name)
|
||
|
||
|
||
:auto USING PERIODIC COMMIT LOAD CSV
|
||
commit every 1000 rows
|
||
Eager operators don't act on this command, ie:
|
||
collect()
|
||
count()
|
||
ORDER BY
|
||
DISTINCT
|
||
|
||
LOAD CSV WITH HEADERS FROM
|
||
'https://data.neo4j.com/v4.0-intro-neo4j/directors.csv' AS row
|
||
MATCH (movie:Movie {id:toInteger(row.movieId)})
|
||
MATCH (person:Person {id: toInteger(row.personId)})
|
||
MERGE (person)-[:DIRECTED]->(movie)
|
||
ON CREATE SET person:Director
|
||
|
||
LOAD CSV WITH HEADERS
|
||
FROM 'http://data.neo4j.com/v4.0-intro-neo4j/actors.csv'
|
||
AS line
|
||
MERGE (actor:Person {name: line.name})
|
||
ON CREATE SET actor.born = toInteger(trim(line.birthYear)), actor.actorId = line.id
|
||
ON MATCH SET actor.actorId = line.id
|
||
|
||
|
||
|
||
## before load
|
||
CREATE CONSTRAINT UniqueMovieIdConstraint ON (m:Movie) ASSERT m.id IS UNIQUE;
|
||
## after load
|
||
CREATE INDEX MovieTitleIndex ON (m:Movie) FOR (m.title);
|
||
|
||
|
||
|
||
// Delete all constraints and indexes
|
||
CALL apoc.schema.assert({},{},true);
|
||
// Delete all nodes and relationships
|
||
CALL apoc.periodic.iterate(
|
||
'MATCH (n) RETURN n',
|
||
'DETACH DELETE n',
|
||
{ batchSize:500 }
|
||
)
|
||
|
||
|
||
## test apoc
|
||
CALL dbms.procedures()
|
||
YIELD name WHERE name STARTS WITH "apoc"
|
||
RETURN name
|
||
|
||
|
||
## Graph modelling
|
||
How does Neo4j support graph data modeling?
|
||
- allows you to create property graphs.
|
||
- traversing the graph: traversal means anchoring a query based upon a property value, then traversing the graph to satisfy the query
|
||
|
||
|
||
Nodes and relationships are the key components of a graph.
|
||
Nodes must have labels to categorize entities.
|
||
A label is used to categorize a set of nodes.
|
||
Relationships must have direction and type.
|
||
A relationship is only traversed once during a query.
|
||
Nodes and relationships can have properties.
|
||
Properties are used to provide specific values to a node or relationship.
|
||
|
||
## Your model must address Nodes:
|
||
- Uniqueness of nodes: always have a property (or set of properties) that uniquely identify a node.
|
||
- Complex data: balance between number of properties that represent complex data vs. multiple nodes and relationships.
|
||
|
||
super nodes = (a node with lots of fan-in or fan-out)
|
||
- Reduce property duplication (no repeating property values)
|
||
- Reduce gather-and-inspect (traversal)
|
||
|
||
## Best practices for modeling relationships
|
||
- Using specific relationship types.
|
||
- Reducing symmetric relationships.
|
||
- No semantically identical relationships (PARENT_OF and CHILD_OF)
|
||
- Not all mutual relationships are semantically symmetric(FOLLOWS)
|
||
- Using types vs. properties.
|
||
|
||
## Property best practices
|
||
In the case of property value complexity, it depends on how the property is used. Anchors and traversal paths that use property values need to be parsed at query time.
|
||
|
||
- Property lookups have a cost.
|
||
- Parsing a complex property adds more cost.
|
||
- Anchors and properties used for traversal will be as simple as possible.
|
||
- Identifiers, outputs, and decoration are OK as complex values.
|
||
|
||
## Hierarchy of accessibility
|
||
1. Anchor node label, indexed anchor node properties (cheap)
|
||
2. Relationship types (cheap)
|
||
3. Non-indexed anchor node properties
|
||
4. Downstream node labels
|
||
5. Relationship properties, downstream node properties
|
||
|
||
Downstream labels and properties are most expensive.
|
||
|
||
## Common graph structures used in modeling:
|
||
1. Intermediate nodes
|
||
- (solve hyperedge; n-ary relationships)
|
||
- sharing context (share contextual information)
|
||
- sharing data (deduplicate information)
|
||
- organizing data (avoid density of nodes)
|
||
2. Linked lists (useful whenever the sequence of objects matters)
|
||
- Interleaved linked list
|
||
- Head and tail of linked list (root point to head and tail)
|
||
- No double linked-lists (redundant symmetrical relationships)
|
||
3. Timeline trees
|
||
- use time as either an anchor or a navigational aid
|
||
- topmost node in the timeline is an “all time” node
|
||
- timeline trees consume a lot of space
|
||
4. Multiple structures in a single graph
|
||
|
||
|
||
CREATE (:Airport {code: "ABQ"})<-[:CONNECTED_TO {airline: "WN", flightNumber: 500, date: "2019-1-3", depature: 1445, arrival: 1710}]-(:Airport {code: "LAS"})-[:CONNECTED_TO {airline: "WN", flightNumber: 82, date: "2019-1-3", depature: 1715, arrival: 1820}]->(:Airport {code: "LAX"})
|
||
|
||
|
||
LOAD CSV WITH HEADERS FROM 'file:///flights_2019_1k.csv' AS row
|
||
MERGE (origin:Airport {code: row.Origin})
|
||
MERGE (destination:Airport {code: row.Dest})
|
||
MERGE (origin)-[connection:CONNECTED_TO {
|
||
airline: row.UniqueCarrier,
|
||
flightNumber: row.FlightNum,
|
||
date: toInteger(row.Year) + '-' + toInteger(row.Month) + '-' + toInteger(row.DayofMonth)}]->(destination)
|
||
ON CREATE SET connection.departure = toInteger(row.CRSDepTime), connection.arrival = toInteger(row.CRSArrTime)
|
||
|