diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index cf6d3760..10ca75f7 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -8,8 +8,6 @@ * xref:cypher/index.adoc[What is Cypher] ** xref:cypher/intro-tutorial.adoc[Get started with Cypher] ** xref:cypher/cypher-sql.adoc[] -** xref:cypher/patterns.adoc[] -** xref:cypher/patterns-in-practice.adoc[] ** xref:cypher/results.adoc[] ** xref:cypher/updating.adoc[] ** xref:cypher/large-statements.adoc[] diff --git a/modules/ROOT/pages/cypher/intro-tutorial.adoc b/modules/ROOT/pages/cypher/intro-tutorial.adoc index d3d96dbd..9a4cf9b3 100644 --- a/modules/ROOT/pages/cypher/intro-tutorial.adoc +++ b/modules/ROOT/pages/cypher/intro-tutorial.adoc @@ -752,7 +752,7 @@ For the first query, the result is "Joe Versus the Volcano", and for the second: == Find patterns In the previous step, you queried the graph for nodes. -Now you are going to retrieve related nodes by finding the xref:cypher/patterns.adoc[patterns] within the graph, that is, how these nodes are related to each other. +Now you are going to retrieve related nodes by finding the link:https://neo4j.com/docs/cypher-manual/current/patterns/[patterns] within the graph, that is, how these nodes are related to each other. === All Tom Hanks movies diff --git a/modules/ROOT/pages/cypher/patterns-in-practice.adoc b/modules/ROOT/pages/cypher/patterns-in-practice.adoc deleted file mode 100644 index 7d3a2ff9..00000000 --- a/modules/ROOT/pages/cypher/patterns-in-practice.adoc +++ /dev/null @@ -1,384 +0,0 @@ -:description: This section describes how patterns are used in practice, explains the basic concepts of Cypher. -:page-includedriver: true -:page-ad-overline-link: https://graphacademy.neo4j.com/courses/cypher-fundamentals -:page-ad-overline: Neo4j GraphAcademy -:page-ad-title: Cypher Fundamentals -:page-ad-description: Learn Cypher in this free, hands-on course -:page-ad-link: https://graphacademy.neo4j.com/courses/cypher-fundamentals -:page-ad-underline-role: button -:page-ad-underline: Learn more - -[[cypher-intro-patterns-in-practice]] -= Patterns in practice - - -[[cypher-intro-patterns-in-practice-creating-data]] -== Creating and returning data - -Let's start by looking into the clauses that allow you to create data. - -To add data, you just use the patterns you already know. -By providing patterns, you can specify what graph structures, labels, and properties you would like to make part of your graph. - -Obviously the simplest clause is called `CREATE`. -It creates the patterns that you specify. - -For the patterns you have looked at so far this could look like the following: - -[source, cypher, role="noplay"] ----- -CREATE (:Movie {title: 'The Matrix', released: 1997}) ----- - -If you run this statement, Cypher returns the number of changes: in this case adding one node, one label, and two properties. - -[queryresult] ----- -Created Nodes: 1 -Added Labels: 1 -Set Properties: 2 -Rows: 0 ----- - -As you started out with an empty database, you now have a database with a single node in it: - -image::cypher-intro-patterns-in-practice01-arr.svg[role="middle",width=350] - -If you also want to return the created data, you can add a `RETURN` clause, which refers to the variable you have assigned to your pattern elements. + -The `RETURN` keyword in Cypher specifies what values or results you might want to return from a Cypher query. + -You can tell Cypher to return nodes, relationships, node and relationship properties, or patterns in your query results. + -`RETURN` is not required when doing write procedures, but is needed for reads. + -The node and relationship variables, which are discussed xref:cypher/patterns.adoc#cypher-intro-patterns-node-syntax[earlier], become important when using `RETURN`. - -[source, cypher, role="noplay"] ----- -CREATE (p:Person {name: 'Keanu Reeves', born: 1964}) -RETURN p ----- - -This is what gets returned: - -[queryresult] ----- -Created Nodes: 1 -Added Labels: 1 -Set Properties: 2 -Rows: 1 - -+----------------------------------------------+ -| p | -+----------------------------------------------+ -| (:Person {name: 'Keanu Reeves', born: 1964}) | -+----------------------------------------------+ ----- - - -If you want to create more than one element, you can separate the elements with commas or use multiple `CREATE` statements. - -You can, of course, also create more complex structures, like an `ACTED_IN` relationship with information about the character, or `DIRECTED` ones for the director. - -[source, cypher, role="noplay"] ----- -CREATE (a:Person {name: 'Tom Hanks', born: 1956})-[r:ACTED_IN {roles: ['Forrest']}]->(m:Movie {title: 'Forrest Gump', released: 1994}) -CREATE (d:Person {name: 'Robert Zemeckis', born: 1951})-[:DIRECTED]->(m) -RETURN a, d, r, m ----- - -This is the part of the updated graph: - -image::cypher-intro-patterns-in-practice02-arr.svg[role="middle",width=600] - -In most cases, you want to add new data to existing structures. -This requires knowing how to find existing patterns in your graph data, which is covered in the next section. - -[[cypher-intro-patterns-in-practice-matching-patterns]] -== Matching patterns - -Matching patterns is a task for the `MATCH` statement. -You pass the same kind of patterns you have used so far to `MATCH` to describe what you are looking for. -It is similar to _query by example_, only that your examples also include the structures. -To bring back nodes, relationships, properties, or patterns, you need to have variables specified in your `MATCH` clause for the data you want to return. - -[NOTE] -==== -A `MATCH` statement searches for the patterns you specify and return _one row per successful pattern match_. -==== - -To find the data you have created so far, you can start looking for all nodes labeled with the `Movie` label. - -[source, cypher, role="noplay"] ----- -MATCH (m:Movie) -RETURN m ----- - -Here's the result: - -image::cypher-intro-patterns-in-practice03-arr.svg[role="middle",width=600] - -This should show both _The Matrix_ and _Forrest Gump_. - -You can also look for a specific person, like _Keanu Reeves_. - -[source, cypher, role="noplay"] ----- -MATCH (p:Person {name: 'Keanu Reeves'}) -RETURN p ----- - -This query returns the matching node: - -image::cypher-intro-patterns-in-practice04-arr.svg[role="middle",width=350] - -Note that you only provide enough information to find the nodes, not all properties are required. -In most cases, you have key-properties like SSN, ISBN, emails, logins, geolocation, or product codes to look for. - -You can also find more interesting connections, like, for instance, the movies' titles that _Tom Hanks_ acted in and roles he played. - -[source, cypher, role="noplay"] ----- -MATCH (p:Person {name: 'Tom Hanks'})-[r:ACTED_IN]->(m:Movie) -RETURN m.title, r.roles ----- - -[queryresult] ----- -Rows: 1 - -+------------------------------+ -| m.title | r.roles | -+------------------------------+ -| 'Forrest Gump' | ['Forrest'] | -+------------------------------+ ----- - -In this case, you only returned the properties of the nodes and relationships that you are interested in. -You can access them everywhere via a dot notation `identifer.property`. - -Of course, this only lists T. Hank's role as _Forrest_ in _Forrest Gump_ because that's all data that you have added. - -Now you know enough to add new nodes to existing ones and can combine `MATCH` and `CREATE` to attach structures to the graph. - -[#cypher-examples] -=== Cypher examples - -Let us look at some examples of using `MATCH` and `RETURN` keywords. -Each subsequent example is more complicated than the previous one. The two last examples start with explanations of what we are trying to achieve. If you click the **Run Query** button below each Cypher code snippet, you can see the results in the format of a graph or table. - -* *Example 1:* Find the labeled `Person` nodes in the graph. -Note that you must use a variable like `p` for the `Person` node if you want to retrieve the node in the `RETURN` clause. - -[source, cypher, role=runnable editable graph] ----- -MATCH (p:Person) -RETURN p -LIMIT 1 ----- - - -* *Example 2:* Find `Person` nodes in the graph that have a name of 'Tom Hanks'. -Remember that you can name your variable anything you want, as long as you reference that same name later. - -[source, cypher, role=runnable editable graph] ----- -MATCH (tom:Person {name: 'Tom Hanks'}) -RETURN tom ----- - - -* *Example 3:* Find which `Movie` Tom Hanks has directed. - -Explanation: at first you should find Tom Hanks' `Person` node and after that the `Movie` nodes he is connected to. -To do that, you have to follow the `DIRECTED` relationship from Tom Hanks' `Person` node to the `Movie` node. -You have also specified a label of `Movie` so that the query only looks at nodes with that label. -Since you only care about returning the movie in this query, you need to give that node a variable (`movie`) but do not need to give variables for the `Person` node or `DIRECTED` relationship. - -[source, cypher, role=runnable editable graph] ----- -MATCH (:Person {name: 'Tom Hanks'})-[:DIRECTED]->(movie:Movie) -RETURN movie ----- - - -* *Example 4:* Find which `Movie` Tom Hanks has directed, but this time, return only the title of the movie. - -Explanation: this query is similar to the previous one. -Example 3 returned the entire `Movie` node with all its properties. -For this example, you still need to find Tom's movies, but now you only care about their titles. -You should access the node's `title` property using the syntax `variable.property` to return the name value. - -[source, cypher, role=runnable editable] ----- -MATCH (:Person {name: 'Tom Hanks'})-[:DIRECTED]->(movie:Movie) -RETURN movie.title ----- - - -[#cypher-aliases] -=== Aliasing return values - -Not all properties are simple like `movie.title` in the example above. -Some properties have poor names due to property length, multi-word descriptions, developer jargon, and other shortcuts. -These naming conventions can be difficult to read, especially if they end up on reports and other user-facing interfaces. - -.Poorly-named properties -[source,cypher,role=runnable] ----- -//poorly-named property -MATCH (tom:Person {name:'Tom Hanks'})-[rel:DIRECTED]-(movie:Movie) -RETURN tom.name, tom.born, movie.title, movie.released ----- - -Just like with SQL, you can rename return results by using the `AS` keyword and aliasing the property with a cleaner name. - -.Cleaner Results with aliasing -[source,cypher,role=runnable editable] ----- -//cleaner printed results with aliasing -MATCH (tom:Person {name:'Tom Hanks'})-[rel:DIRECTED]-(movie:Movie) -RETURN tom.name AS name, tom.born AS `Year Born`, movie.title AS title, movie.released AS `Year Released` ----- - -// .Results Without Aliases: -// image:{neo4j-img-base-uri}cypher_without_aliases.jpg[role="popup-link"] - -// .Results With Aliases: -// image:{neo4j-img-base-uri}cypher_with_aliases.jpg[role="popup-link"] - -[NOTE] -==== -You can specify return aliases that have spaces by using the backtick character before and after the alias (movie.released AS `Year Released`). -If you do not have an alias that contains spaces, then you do not need to use backticks. -==== - -[[cypher-intro-patterns-in-practice-attaching-structures]] -== Attaching structures - -To extend the graph with new information, you first match the existing connection points and then attach the newly created nodes to them with relationships. -Adding _Cloud Atlas_ as a new movie for _Tom Hanks_ could be achieved like this: - -[source, cypher, role="noplay"] ----- -MATCH (p:Person {name: 'Tom Hanks'}) -CREATE (m:Movie {title: 'Cloud Atlas', released: 2012}) -CREATE (p)-[r:ACTED_IN {roles: ['Zachry']}]->(m) -RETURN p, r, m ----- - -Here's what the structure looks like in the database: - -image::cypher-intro-patterns-in-practice05-arr.svg[role="middle",width=600] - -[TIP] -==== -It is important to remember that you can assign variables to both nodes and relationships and use them later on, no matter if they were created or matched. -==== - -It is possible to attach both node and relationship in a single `CREATE` clause. -For readability, it helps to split them up though. - - -[IMPORTANT] -==== -A tricky aspect of the combination of `MATCH` and `CREATE` is that you get _one row per matched pattern_. -This causes subsequent `CREATE` statements to be executed once for each row. -In many cases, this is what you want. -If that's not intended, move the `CREATE` statement before the `MATCH`, or change the cardinality of the query with means discussed later or use the _get or create_ semantics of the next clause: *`MERGE`*. -==== - - -[[cypher-intro-patterns-in-practice-completing-patterns]] -== Completing patterns - -Whenever you get data from external systems or are not sure if certain information already exists in the graph, you want to be able to express a repeatable (idempotent) update operation. -In Cypher *`MERGE`* clause has this function. -It acts like a combination of `MATCH` _or_ `CREATE`, which checks for the existence of data before creating it. -With `MERGE`, you define a pattern to be found or created. -Usually, as with `MATCH`, you only want to include the key property to look for in your core pattern. -`MERGE` allows you to provide additional properties you want to set `ON CREATE`. - -If you do not know whether your graph already contained _Cloud Atlas_, you could merge it again. - -[source, cypher, role="noplay"] ----- -MERGE (m:Movie {title: 'Cloud Atlas'}) -ON CREATE SET m.released = 2012 -RETURN m ----- - -[queryresult] ----- -Created Nodes: 1 -Added Labels: 1 -Set Properties: 2 -Rows: 1 - -+-------------------------------------------------+ -| m | -+-------------------------------------------------+ -| (:Movie {title: 'Cloud Atlas', released: 2012}) | -+-------------------------------------------------+ ----- - -You get a result in both cases: either the data (potentially more than one row) that was already in the graph or a single, newly created `Movie` node. - -[NOTE] -==== -A `MERGE` clause without any previously assigned variables in it either matches the full pattern or creates the full pattern. -It never produces a partial mix of matching and creating within a pattern. -To achieve a partial match/create, make sure to use already defined variables for the parts that shouldn't be affected. -==== - -So foremost `MERGE` makes sure that you can't create duplicate information or structures, but it comes with the cost of needing to check for existing matches first. -Especially on large graphs, it can be costly to scan a large set of labeled nodes for a specific property. -You can alleviate some of that by creating supporting indexes or constraints, which are discussed in the upcoming sections. -But it's still not for free, so whenever you're sure to not create duplicate data use `CREATE` over `MERGE`. - -[TIP] -==== -`MERGE` can also assert that a relationship is only created once. -For that to work you _have to pass in_ both nodes from a previous pattern match. -==== - -[source, cypher, role="noplay"] ----- -MATCH (m:Movie {title: 'Cloud Atlas'}) -MATCH (p:Person {name: 'Tom Hanks'}) -MERGE (p)-[r:ACTED_IN]->(m) -ON CREATE SET r.roles =['Zachry'] -RETURN p, r, m ----- - -image::cypher-intro-patterns-in-practice06-arr.svg[role="middle",width=600] - -If the direction of a relationship is arbitrary, you can leave off the arrowhead. -`MERGE` checks for the relationship in either direction and creates a new directed relationship if there is no matching relationship. - -If you choose to pass in only one node from a preceding clause, `MERGE` offers an interesting functionality. -It only matches within the direct neighborhood of the provided node for the given pattern, and if the pattern is not found creates it. -This can come in very handy for creating, for example, tree structures. - -[source,cypher, indent=0] ----- -CREATE (y:Year {year: 2014}) -MERGE (y)<-[:IN_YEAR]-(m10:Month {month: 10}) -MERGE (y)<-[:IN_YEAR]-(m11:Month {month: 11}) -RETURN y, m10, m11 ----- - -This is the graph structure that gets created: - -image::cypher-intro-patterns-in-practice07-arr.svg[role="middle",width=600] - -Here is no global search for the two `Month` nodes; they are only searched for in the context of the _2014_ `Year` node. - -[.arrange] -== Code challenge - -Now knowing the basics, use the parts below to build a Cypher statement to find the `title` and year of `release` for every `:Movie` that Tom Hanks has `:DIRECTED`. -Click the parts to add them in order and once you are done, click **Run Query** to see whether you have got it right. -You can click any part of the query inside the code block to remove it. - -[source,cypher] -MATCH (p:Person {name: "Tom Hanks"})-[:DIRECTED]->(m:Movie) RETURN m.title, m.released - diff --git a/modules/ROOT/pages/cypher/patterns.adoc b/modules/ROOT/pages/cypher/patterns.adoc deleted file mode 100644 index f283db1c..00000000 --- a/modules/ROOT/pages/cypher/patterns.adoc +++ /dev/null @@ -1,145 +0,0 @@ -:description: This section gives an introduction to the concept of patterns. -:page-ad-overline-link: https://graphacademy.neo4j.com/courses/cypher-fundamentals -:page-ad-overline: Neo4j GraphAcademy -:page-ad-title: Cypher Fundamentals -:page-ad-description: Learn Cypher in this free, hands-on course -:page-ad-link: https://graphacademy.neo4j.com/courses/cypher-fundamentals -:page-ad-underline-role: button -:page-ad-underline: Learn more - -[[cypher-intro-patterns]] -= Patterns - -Neo4j's property graphs are composed of nodes and relationships, either of which may have properties. -Nodes represent entities, for example concepts, events, places, and things. -Relationships connect pairs of nodes. - -However, nodes and relationships can be considered as low-level building blocks. -The real strength of the property graph lies in its ability to encode _patterns_ of connected nodes and relationships. -A single node or relationship typically encodes very little information, -but a pattern of nodes and relationships can encode arbitrarily complex ideas. - -Cypher, Neo4j's query language, is strongly based on patterns. -Specifically, patterns are used to match desired graph structures. -Once a matching structure has been found or created, Neo4j can use it for further processing. - -A simple pattern, which has only a single relationship, connects a pair of nodes (or, occasionally, a node to itself). -For example, _a Person_ `LIVES_IN` _a City_ or _a City is_ `PART_OF` _a Country_. - -Complex patterns, using multiple relationships, can express arbitrarily complex concepts and support a variety of interesting use cases. -For example, we might want to match instances where _a Person_ `LIVES_IN` _a Country_. -The following Cypher code combines two simple patterns into a slightly more complex pattern which performs this match: - -[source, cypher syntax, role="noheader"] ----- -(:Person) -[:LIVES_IN]-> (:City) -[:PART_OF]-> (:Country) ----- - -Diagrams made up of icons and arrows are commonly used to visualize graphs. -Textual annotations provide labels, define properties etc. - - -[[cypher-intro-patterns-node-syntax]] -== Node syntax - -Cypher uses a pair of parentheses to represent a node: `()`. -This is reminiscent of a circle or a rectangle with rounded end caps. -Below are some examples of nodes, providing varying types and amounts of detail: - -[source, cypher syntax, role="noheader"] ----- -() -(matrix) -(:Movie) -(matrix:Movie) -(matrix:Movie {title: 'The Matrix'}) -(matrix:Movie {title: 'The Matrix', released: 1997}) ----- - -The simplest form, `()`, represents an anonymous, uncharacterized node. -If we want to refer to the node elsewhere, we can add a variable, for example: `(matrix)`. -A variable is restricted to a single statement. -It may have different or no meaning in another statement. - -The `:Movie` pattern declares a label of the node. -This allows us to restricts the pattern, keeping it from matching (say) a structure with an `Actor` node in this position. - -The node's properties, for example `title`, are represented as a list of key-value pairs, enclosed within a pair of braces, for example: `{name: 'Keanu Reeves'}`. -Properties can be used to store information and/or restrict patterns. - - -[[cypher-intro-patterns-relationship-syntax]] -== Relationship syntax - -Cypher uses a pair of dashes (`--`) to represent an undirected relationship. -Directed relationships have an arrowhead at one end (`+<--+`, `+-->+`). -Bracketed expressions (`+[...]+`) can be used to add details. -This may include variables, properties, and type information: - -[source, cypher syntax, role="noheader"] ----- ---> --[role]-> --[:ACTED_IN]-> --[role:ACTED_IN]-> --[role:ACTED_IN {roles: ['Neo']}]-> ----- - -The syntax and semantics found within a relationship's bracket pair are very similar to those used between a node's parentheses. -A variable (e.g., `role`) can be defined, to be used elsewhere in the statement. -The relationship's type (e.g., `:ACTED_IN`) is analogous to the node's label. -The properties (e.g., `roles`) are entirely equivalent to node properties. - - -[[cypher-intro-patterns-pattern-syntax]] -== Pattern syntax - -Combining the syntax for nodes and relationships, we can express patterns. -The following could be a simple pattern (or fact) in this domain: - -[source, cypher syntax, role="noheader"] ----- -(keanu:Person:Actor {name: 'Keanu Reeves'})-[role:ACTED_IN {roles: ['Neo']}]->(matrix:Movie {title: 'The Matrix'}) ----- - -Equivalent to node labels, the `:ACTED_IN` pattern declares the relationship type of the relationship. -Variables (e.g., `role`) can be used elsewhere in the statement to refer to the relationship. - -As with node properties, relationship properties are represented as a list of key/value pairs enclosed within a pair of braces, for example: `{roles: ['Neo']}`. -In this case, we used an array property for the `roles`, allowing multiple roles to be specified. -Properties can be used to store information and/or restrict patterns. - - -[[cypher-intro-patterns-pattern-variables]] -== Pattern variables - -To increase modularity and reduce repetition, Cypher allows patterns to be assigned to variables. -This allows the matching paths to be inspected, used in other expressions, etc. - -[source, cypher syntax, role="noheader"] ----- -acted_in = (:Person)-[:ACTED_IN]->(:Movie) ----- - -The `acted_in` variable would contain two nodes and the connecting relationship for each path that was found or created. -There are a number of functions to access details of a path, for example: `nodes(path)`, `relationships(path)`, and `length(path)`. - - -[[cypher-intro-patterns-clauses]] -== Clauses - -Cypher statements typically have multiple _clauses_, each of which performs a specific task, for example: - -* create and match patterns in the graph -* filter, project, sort, or paginate results -* compose partial statements - -By combining Cypher clauses, you can compose complex statements that express what you want to know or create. - -For detailed information on Cypher clauses and their use, refer to link:https://neo4j.com/docs/cypher-manual/current/clauses/[Cypher Manual -> Clauses^]. - -You can also visit the link:https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise/[Cypher Cheat Sheet^] for quick reference on Cypher syntax. - - - - diff --git a/modules/ROOT/pages/cypher/updating.adoc b/modules/ROOT/pages/cypher/updating.adoc index 5e8f63d2..57676da5 100644 --- a/modules/ROOT/pages/cypher/updating.adoc +++ b/modules/ROOT/pages/cypher/updating.adoc @@ -261,7 +261,7 @@ SET n.birthdate = null [[cypher-merge]] == Avoiding duplicate data using _MERGE_ -It was briefly mentioned xref::cypher/patterns-in-practice.adoc#cypher-intro-patterns-in-practice-completing-patterns/[earlier] that there are some ways in Cypher to avoid creating duplicate data. +There are some ways in Cypher to avoid creating duplicate data. One of those ways is using the `MERGE` keyword. `MERGE` does a "select-or-insert" operation that first checks if the data exists in the database. If it exists, then Cypher returns it as is or makes any updates you specify on the existing node or relationship.