diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..54db2c4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "asciidoc.antora.enableAntoraSupport": false +} \ No newline at end of file diff --git a/data/northwind-subset-data-only-no-model.zip b/data/northwind-subset-data-only-no-model.zip new file mode 100644 index 0000000..4d111a9 Binary files /dev/null and b/data/northwind-subset-data-only-no-model.zip differ diff --git a/data/northwind-subset-node-and-relationship-mapping.zip b/data/northwind-subset-node-and-relationship-mapping.zip index e6252f3..275a6f5 100644 Binary files a/data/northwind-subset-node-and-relationship-mapping.zip and b/data/northwind-subset-node-and-relationship-mapping.zip differ diff --git a/data/northwind-subset-node-only-mapping.zip b/data/northwind-subset-node-only-mapping.zip index f20541e..2839673 100644 Binary files a/data/northwind-subset-node-only-mapping.zip and b/data/northwind-subset-node-only-mapping.zip differ diff --git a/data/northwind-subset-shipper-mapping.zip b/data/northwind-subset-shipper-mapping.zip index da29363..58030cb 100644 Binary files a/data/northwind-subset-shipper-mapping.zip and b/data/northwind-subset-shipper-mapping.zip differ diff --git a/documentation/browser-preview.workspace.adoc b/documentation/browser-preview.workspace.adoc new file mode 100644 index 0000000..ebc9298 --- /dev/null +++ b/documentation/browser-preview.workspace.adoc @@ -0,0 +1,115 @@ += New Browser Preview +// http://localhost:4000/browser-preview.workspace.json + +== Introduction + +Welcome to the New Browser Preview! +Browser's querying functionality has been modernized and integrated into Neo4j Aura, and these benefits are now available in the new Browser, bundled with the Neo4j on-prem distribution. + +If you use Neo4j Aura you’ll see the same capabilities as this New Browser Preview offered under the **Query** part of the integrated experience. +Query and Browser are similar, but Query provides features you can expect from a cloud offering, like user content backed by cloud storage, so it’s available wherever you log in. +For the standalone Browser, content continues to be backed by LocalStorage and therefore tied to the browser you use to access the application. + +With that context, read on to learn more about the big new updates in this preview: + +- New Cypher editor +- Richer table visualization +- More scalable graph visualization +- New history and quick search +- Improved saved Cypher experience +- Revised parameters + +== New Cypher editor + +One of the biggest improvements is the new editor which is now built from the same source as the Cypher language. +The Cypher language is ever-evolving and the new editor helps you stay up-to-date with the latest language features. +Here are a few ways the new editor helps you do that: + +Syntax highlighting:: Richer syntax highlighting identifies potential errors from things like property values being misinterpreted as Cypher keywords and differentiates more tokens for ease of reading. + +image::cypher-editor-syntax-highlighting.png[] + + +Auto completions:: The underpinnings of the Cypher editor now have an improved understanding of valid constructs, meaning it will, for example, more accurately complete the next valid keyword. + +image::cypher-editor-auto-completions.gif[] + +Inline help:: When using a procedure or making a function call, helpful descriptions and signatures are presented, allowing you to better understand what’s expected as an input or what might be returned. + +image::cypher-editor-inline-help.png[] + +Cypher linting:: One of the most useful new features is Cypher linting, which lets you see useful warnings and errors _before_ running a query. +This helps shorten the feedback loop, so you don’t have to run a query to spot syntactic or semantic errors. +This is especially useful when editing larger queries or using new language constructs where you might not know what to expect. + +image::cypher-editor-linting.png[] + +Cypher reference:: As a complement to the in-editor help, a searchable Cypher reference is now available in the sidebar. +This is useful to check the syntax of a Cypher construct or want a quick reference of which temporal functions exist and how to use them, for example. +The reference also provides links to the Cypher manual for more in-depth explanations and examples. + +image::cypher-reference.gif[] + +== Richer table visualization + +The table visualization now employs reactive result fetching by default. +This means that the number of rows returned by a query is automatically limited, regardless of any `LIMIT` statements you apply. +This is useful for both new and experienced users since an unintentional omission of a `LIMIT` statement can lead to an unexpectedly large amount of results returned, which could previously have overwhelmed Browser. +The table now also employs virtualized rendering meaning that even if you do return a larger number of rows, only those in view are rendered to keep the application more responsive. + +There are functional improvements too. +A new render for paths, relationships, and nodes allows you to more readily discern labels/types and key/value pairs. +By default, the render is compact, but optionally it allows graph objects to be pretty-printed for situations where readability is more important than compactness. + +Simple result filtering is now also available, allowing you to perform simple text matches on returned results. +It's often simpler and quicker than modifying a Cypher statement to contain a WHERE clause. + +image::table-visualization.gif[] + + +== More scalable graph visualization + +The graph visualization has been rebuilt using a new engine while maintaining the familiar layout algorithm from the outgoing graph visualization. +This makes the visualization more responsive and allows for a larger number of nodes and relationships to be visualized. + +Another important functional change is that the visualization now only displays items you explicitly return in Cypher statements - it no longer automatically connects returned nodes with relationships that exist between them. +This can still be achieved on-demand via a context menu in the visualization to “show all relationships”. + +image::scalable-graph-visualization.gif[] + + +== New history and quick search + +The familiar and convenient up/down arrow history feature remains but has been supplemented with a dedicated sidebar to review and manage history, allowing history to be selectively deleted or exported. + +For convenience, the history available in the sidebar is also searchable via a fuzzy search from the main editor, allowing you to quickly find a query in your history. +This can be invoked from the […] more menu on the main editor or via Ctrl+R. + +image::history-quick-search.gif[] + + +== Improved saved Cypher experience + +The “Favorites” experience from Browser is now “Saved Cypher” and provides a refreshed way of creating and managing Cypher. +You can now more readily re-order items among nested folders, and Cypher statements saved from the editors recall the last folders used for convenience. + +image::saved-cypher.gif[] + +== Revised paramaters + +The parameters implementation has rationalized the `:param` and `:params` variants that differed in Browser. +While singular and plural versions of the command are respected, they behave the same way and offer support for setting parameters singularly via the arrow syntax `:param a => 1` or multiply via Cypher maps `:param {a:1, b: 2}`. + +== And finally... + +Hope you enjoy using the new Browser preview. +Please note that the following are not yet supported: + +- `:server [connect | disconnect]` commands and frames. For the time being the connection header at the top of the page is used to connect to instances +- `:sysinfo` command to review details of your dbms cluster +- `:play` commands to play builtin and custom guides +- `:server user [add | list]` commands to support user management - this is possible via the cypher surface, see docs for more details. +- GraSS and the `:style` command to set custom styles. Some basic styling support is provided via the UI to change colors, captions and size as well as ordering the priority of styles when multiple labels apply to a node. + +This new Browser preview will ultimately replace the existing Browser as the default and later, only experience. +If these items or anything else is important to you, please head over to link:https://feedback.neo4j.com/query[] and drop your feedback there. \ No newline at end of file diff --git a/documentation/connect-drivers-dotnet.adoc b/documentation/connect-drivers-dotnet.adoc new file mode 100644 index 0000000..3039be4 --- /dev/null +++ b/documentation/connect-drivers-dotnet.adoc @@ -0,0 +1,20 @@ +== Installation + +The .NET driver is distributed via the NuGet Gallery. + +link:https://www.nuget.org/packages/Neo4j.Driver/[More info on installing the driver ^] + +== Connect to the database + + +[source, csharp, role=nocollapse, copy=true] +---- +using Neo4j.Driver; + +const string uri = "{neo4j-database-uri}"; +const string user = ""; +const string password = ""; + +await using var driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password)); +await driver.VerifyConnectivityAsync(); +---- diff --git a/documentation/connect-drivers-go.adoc b/documentation/connect-drivers-go.adoc new file mode 100644 index 0000000..a4fa4a1 --- /dev/null +++ b/documentation/connect-drivers-go.adoc @@ -0,0 +1,43 @@ +== Installation + +From within a module, use `go get` to install the link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/[Neo4j Go Driver]: + +[source, bash, copy=true] +---- +go get github.com/neo4j/neo4j-go-driver/v5 +---- + +link:https://neo4j.com/docs/go-manual/current/install/#install-driver[More info on installing the driver ^] + + +== Connect to the database + +Connect to a database by creating a `DriverWithContext` object and providing a URL and an authentication token. +Once you have a `DriverWithContext` instance, use the `.VerifyConnectivity()` method to ensure that a working connection can be established. + +[source, go, role=nocollapse, copy=true] +---- +package main + +import ( + "context" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" +) + +func main() { + ctx := context.Background() + // URI examples: "neo4j://localhost", "neo4j+s://xxx.databases.neo4j.io" + dbUri := "{neo4j-database-uri}" + dbUser := "" + dbPassword := "" + driver, err := neo4j.NewDriverWithContext( + dbUri, + neo4j.BasicAuth(dbUser, dbPassword, "")) + defer driver.Close(ctx) + + err = driver.VerifyConnectivity(ctx) + if err != nil { + panic(err) + } +} +---- diff --git a/documentation/connect-drivers-java.adoc b/documentation/connect-drivers-java.adoc new file mode 100644 index 0000000..e6d866a --- /dev/null +++ b/documentation/connect-drivers-java.adoc @@ -0,0 +1,42 @@ +== Install Driver + +Add the Neo4j Java driver to the list of dependencies in the `pom.xml` of your Maven project: + +[source, xml, subs="attributes+", copy=true] +---- + + org.neo4j.driver + neo4j-java-driver + 5.28.4 + +---- + +link:https://neo4j.com/docs/java-manual/current/install/#install-driver[More info on installing the driver ^] + +== Connect to the database + +Connect to a database by creating a `Driver` object and providing a URL and an authentication token. +Once you have a `Driver` instance, use the `.verifyConnectivity()` method to ensure that a working connection can be established. + +[source, java, role=nocollapse, copy=true] +---- +package demo; + +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.GraphDatabase; + +public class App { + + public static void main(String... args) { + + // URI examples: "neo4j://localhost", "neo4j+s://xxx.databases.neo4j.io" + final String dbUri = "{neo4j-database-uri}"; + final String dbUser = ""; + final String dbPassword = ""; + + try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) { + driver.verifyConnectivity(); + } + } +} +---- diff --git a/documentation/connect-drivers-javascript.adoc b/documentation/connect-drivers-javascript.adoc new file mode 100644 index 0000000..bab95e2 --- /dev/null +++ b/documentation/connect-drivers-javascript.adoc @@ -0,0 +1,37 @@ +== Installation + +Install the Neo4j JavaScript driver with `npm`: + +[source, bash, copy=true] +---- +npm i neo4j-driver +---- + +link:https://neo4j.com/docs/javascript-manual/current/install/#install-driver[More info on installing the driver ^] + + +== Connect to the database + +Connect to a database by creating a `Driver` object and providing a URL and an authentication token. +Once you have a `Driver` instance, use the `.getServerInfo()` method to ensure that a working connection can be established by retrieving the server information. + +[source, javascript, copy=true] +---- +var neo4j = require('neo4j-driver'); +(async () => { + // URI examples: 'neo4j://localhost', 'neo4j+s://xxx.databases.neo4j.io' + const URI = '{neo4j-database-uri}' + const USER = '' + const PASSWORD = '' + let driver + + try { + driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD)) + const serverInfo = await driver.getServerInfo() + console.log('Connection established') + console.log(serverInfo) + } catch(err) { + console.log(`Connection error\n${err}\nCause: ${err.cause}`) + } +})(); +---- \ No newline at end of file diff --git a/documentation/connect-drivers-python.adoc b/documentation/connect-drivers-python.adoc new file mode 100644 index 0000000..8df9007 --- /dev/null +++ b/documentation/connect-drivers-python.adoc @@ -0,0 +1,25 @@ +== Install Driver + +[source, bash, copy=true] +---- +pip install neo4j +---- + +link:https://neo4j.com/docs/python-manual/current/install/#install-driver[More info on installing the driver ^] + +== Connect to the Database + +Connect to a database by creating a `Driver` object and providing a URL and an authentication token. +Once you have a `Driver` instance, use the `.verify_connectivity()` method to ensure that a working connection can be established. + +[source, python, copy=true] +---- +from neo4j import GraphDatabase + +# URI examples: "neo4j://localhost", "neo4j+s://xxx.databases.neo4j.io" +URI = "{neo4j-database-uri}" +AUTH = ("", "") + +with GraphDatabase.driver(URI, auth=AUTH) as driver: + driver.verify_connectivity() +---- diff --git a/documentation/data-importer.adoc b/documentation/data-importer.adoc index 22dbc50..3cbc412 100644 --- a/documentation/data-importer.adoc +++ b/documentation/data-importer.adoc @@ -1,18 +1,18 @@ = Learn how to import and map data with Neo4j Data Importer // NOTE: Browser may cache files when loading from zip -// TODO: Update the URL of files to be Github after completing local development testing -:northwind-subset-data-only-zip-file: http://localhost:8000/data/northwind-subset-data-only.zip -:northwind-subset-node-only-mapping-zip-file: http://localhost:8000/data/northwind-subset-node-only-mapping.zip -:northwind-subset-shipper-mapping-zip-file: http://localhost:8000/data/northwind-subset-shipper-mapping.zip -:people_locations_nodes_only_zip_file: http://localhost:8000/data/people_locations_nodes_only.zip -:people_locations_full_zip_file: http://localhost:8000/data/people_locations_full.zip -:northwind-subset-node-and-relationship-mapping-zip-file: http://localhost:8000/data/northwind-subset-node-and-relationship-mapping.zip +:northwind-subset-data-only-no-model-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-data-only-no-model.zip +:northwind-subset-data-only-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-data-only.zip +:northwind-subset-node-only-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-node-only-mapping.zip +:northwind-subset-shipper-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-shipper-mapping.zip +:people_locations_nodes_only_zip_file: https://neo4j-graph-examples.github.io/get-started/data/people_locations_nodes_only.zip +:people_locations_full_zip_file: https://neo4j-graph-examples.github.io/get-started/data/people_locations_full.zip +:northwind-subset-node-and-relationship-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-node-and-relationship-mapping.zip == Introduction Workspace's data importer offers a powerful and simple way to model and load data into Neo4j. -It's great if you're new to graphs or have rapid prototyping needs. +It's great if you're new to graphs or have rapid prototyping needs. If you have more advanced needs, checkout the _What's next?_ section at the end of this guide. This guide will teach you how to: @@ -23,7 +23,8 @@ This guide will teach you how to: [TIP] ==== -If you haven't already, we recommend going through the _Getting started with Neo4j_ guide to learn the basics of Neo4j. We're continuing with the Northwind dataset. +If you haven't already, it's recommended to go through the _Learn the basics_ guide to learn the basics of Neo4j. +This guide is continuing with the same dataset, Northwind. ==== @@ -31,7 +32,7 @@ If you haven't already, we recommend going through the _Getting started with Neo === Add the Northwind files -To get started, {northwind-subset-data-only-zip-file}[download and unzip this file of CSVs^] and then drop the files onto the highlight:import/import-file-panel[files panel]. +To get started, {northwind-subset-data-only-no-model-zip-file}[download and unzip this file of CSVs^] and then drop the files onto the highlight:import/import-file-panel[files panel]. [%collapsible] .Are you having trouble? @@ -43,11 +44,11 @@ button::Add Northwind files[role=NX_IMPORT_LOAD,endpoint={northwind-subset-data- === File structure -Now that you've added the files, you should now be able to see each file's header and the first row of data in the highlight:import/import-file-panel[Files panel]. +Now that you've added the files, you should be able to see each file's header and the first row of data in the highlight:import/import-file-panel[Files panel]. [TIP] ==== -Importer always requires files to have a *header row* as well as at least one *data row* in order to map and import data. +Importer always requires files to have a *header row* as well as at least one *data row* in order to map and import data. ==== The `order-details.csv` file looks like this: @@ -59,7 +60,9 @@ OrderID,ProductID,UnitPrice,Quantity,Discount 10248,72,34.8,5,0 ---- -This file tells us which orders contain specific products and their price. If you inspect the content of the file, you'll notice that `OrderID` is repeated. We'll learn later about how this can be used to create a `CONTAINS` relationship linking `Orders` and `Products`. +This file tells you which orders contain specific products and their price. +If you inspect the content of the file, you'll notice that `OrderID` is repeated. +You'll learn later about how this can be used to create a `CONTAINS` relationship linking `Orders` and `Products`. The `products.csv` and `orders.csv` files refer to the other parts of the Northwind data model. @@ -68,14 +71,14 @@ The `products.csv` and `orders.csv` files refer to the other parts of the Northw === Create the Order node -We're going to create a simple model with two nodes and one relationship. -Add a node using the highlight:import/import-add-node[add node button], and give it the label `Order`. +You are going to create a simple model with two nodes and one relationship. +Add a node using the highlight:import/import-add-node[add node button], and give it the label `Order`. image::simple-model.png[] - + === Map a file -The `Order` node you have just created isn't fully mapped yet; we need it to show a green tick. +The `Order` node you have just created isn't fully mapped yet; it needs to show a green check mark. Select `orders.csv` from the highlight:import/import-node-file-dropdown[file dropdown] in the highlight:import/import-mapping-panel[mapping details panel]. @@ -83,39 +86,47 @@ Select `orders.csv` from the highlight:import/import-node-file-dropdown[file dro Let's now add some properties to the `Order` node from our `orders.csv` file. -* Click the highlight:import/import-select-from-file-button[select from file] button. +* Click the highlight:import/import-select-from-file-button[Map from file] button. * Select the `orderId`, `orderDate` and `requiredDate` columns and click *Confirm*. -* Edit the `orderId` property in the mapping details panel by clicking the pencil icon. -* Change its data type from `integer` to `string`, and then rename it to `id` (it obviously relates to an order). -* Click the tick icon to save your edit. +* Edit the name `orderId` property in the mapping details panel by clicking the pencil icon and then rename it to `id` (it obviously relates to an order). +* Change its data type from `integer` to `string` using the drop-down. -[TIP] + +[NOTE] ==== -Properties with the same name will be created automatically. -Workspace will guess each datatype based on a sample of the values it found. Always double check this when working with unfamiliar data. For example, Northwind's date/time columns are identified as strings. You can change this if you wish. +When selected from file, properties are given the name of the column selected when created. +Workspace guesses each datatype based on a sample of the values it found. +Always double-check this when working with unfamiliar data. +For example, Northwind's date/time columns are identified as strings, but you can edit that if you want to. ==== -// TODO: properties with same name... this needs rewording for clarity. - +// TODO: properties with same name... this needs rewording for clarity == Relationships and IDs === Setting a node ID -Nodes need an ID to define relationships with other nodes. An ID also ensures an import doesn't create a node more than once if it's referenced multiple times in a data file. +Nodes need an ID to define relationships with other nodes. +An ID also ensures an import doesn't create a node more than once if it's referenced multiple times in a data file. -* Return to the _Definition_ tab and note that the `id` property is set as the ID for the node highlight:import/import-node-id[ID]. -* The import tool did this for you automatically based on the property name containing the `id` string. In other cases, you may need to correct it or set it manually. +In the _Definition_ tab, you can see that the `id` property is set as the ID for the node highlight:import/import-node-id[ID]. +The import tool did this for you automatically based on the property name containing the `id` string. +In other cases, you may need to correct it or set it manually. +// TO-DO: Add property highlight has been lost, requested the Importer team re-add it. This TO-DO can be deleted once confirmed working. [TIP] ==== -You can also specify properites and their data types in isolation from mapping by using the highlight:import/import-property-add-button[add property] button. You can then map a column from your data file to the property in the file mapping tab. +You can also specify properites and their data types in isolation from mapping by using the highlight:import/import-property-add-button[add property] button. +You can then map a column from your data file to the property in the file mapping tab. ==== +=== Create the Product node -=== Create the Product node +Now you just need to repeat the process you followed for `Order` and create a `Product` node from the `products.csv` file. +Here you need to map the `produtId` and `productName` columns, rename the `productId` property to be simply `id` and set it to be a `string`. +Ensure `id` is selected as the ID. -Now you just need to repeat the process you followed for `Order`, creating a `Product` node from the `products.csv` file. -Here you need to map the `produtId` and `productName` columns, rename the `productId` property to be simply `id` and set it to be a `string`. Ensure `id` is selected as the ID. +Once you have created both nodes and mapped files accordingly, you should see a green check mark on both nodes. +This indicates that the mapping is complete. [%collapsible] .Are you having trouble? @@ -125,54 +136,89 @@ If you're unsure if you've followed the steps correctly so far, you can go ahead button::Load Northwind node mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-node-only-mapping-zip-file}] ==== +== Constraints and indexes + +To ensure accuracy of your data and support read performance, Data Importer automatically creates a uniqueness constraint and a corresponding index on the property you select as the node ID. +You can add further indexes in addition to the mandatory constraint and index. + +Constraints and indexes have their own tab in the highlight:import/import-mapping-panel[mapping details panel]. +Use the `+`-sign to add an index and then select which property to add the index on. + +Data Importer generates a name for the index and the index type created is Neo4j's default index. +If you make a mistake, select the erroneous index and click the trash-can to delete it. + +If you know that you are going to use a property regularly, it is good practice to add an index to it. +For example, if you are doing administrative work with Northwind, you may be interested in the order dates. +See if you can add an index to the `orderDate` property that will help you with that! + +[%collapsible] +.Hint +==== +From the highlight:import/import-mapping-panel[mapping details panel], tap the `+` and select the `orderDate` property. +==== + +[NOTE] +==== +Only the properties you mapped from the _Definition_ tab are available to create indexes on. +To modify the selection, you need to go back to the _Definition_ tab. +==== + +To learn more about indexes and constraints, see link:https://neo4j.com/docs/cypher-manual/current/indexes/[Cypher Manual -> Indexes] and link:https://neo4j.com/docs/cypher-manual/current/constraints/[Cypher Manual -> Constraints] repsectively. == Create relationships [TIP] ==== -As we've observed in our data file, `Orders` `CONTAIN` `Products`. We use a convention of https://en.wikipedia.org/wiki/Camel_case[CamelCase^] for node Labels and capitalized https://en.wikipedia.org/wiki/Snake_case[SNAKE_CASE^] for Relationships. +As you've seen already, your data concerns `Orders` that `CONTAIN` specific `Products`. +Conventionally, https://en.wikipedia.org/wiki/Camel_case[CamelCase^] is used for node labels and capitalized https://en.wikipedia.org/wiki/Snake_case[SNAKE_CASE^] for relationship types. ==== You have two nodes and now you need to create a relationship to connect them. * Hover by the edge of the `Order` node circle and you'll see a `+` sign. * Click and hold it and you'll see another circle. -* Drag the new circle on to the `Product` node and relase to create the relationship. -* With the relationship arrow selected, we can now name how `Order` relates to `Product`. +* Drag the new circle on to the `Product` node and relase to create the relationship. +* With the relationship arrow selected, you can now specify how `Order` relates to `Product`. * In the highlight:import/import-relationship-type[type] section of the highlight:import/import-mapping-panel[mapping details panel], enter the text `CONTAINS`. [TIP] ==== -Just like newly created nodes, the relationship will only show a green tick once you have completed its mapping. +Just like newly created nodes, the relationship will only show a green check mark once you have completed its mapping. You can also name relationships by double-clicking the arrow in the graph model and typing it directly. -You can rapidly add nodes with a linking relationship by hovering over an existing node; when a green plus icon appears, click-drag from the node and then release onto the canvas. +You can rapidly add nodes with a linking relationship by releasing the circle on an empty space the canvas instead of an existing node. Selected nodes can be deleted by clicking the highlight:import/import-delete-node-or-rel[delete button] or with the backspace key. +You can quickly change the direction of a relationship with _Switch direction_ next to the relationship type. ==== -=== Map a file to a relationship +== Map a file to a relationship -The next stage is critical in helping the importer understand how a file defines a relationship. This is what will give you a connected graph. +The next stage is critical in helping the importer understand how a file defines a relationship. +This is what will give you a connected graph. -* If you look in the highlight:import/import-file-panel[Files panel], you'll see `order-details.csv` has columns that correspond with the `id` of our `Order` and `Product` nodes. +* If you look in the highlight:import/import-file-panel[Files panel], you'll see `order-details.csv` has columns that correspond with the `id` of our `Order` and `Product` nodes. * Ensuring you have the relationship selected, select the `order-details.csv` file from the highlight:import/import-relationship-file-dropdown[File dropdown]. // TODO: Add id selector for relationship dropdown to enable UI higlighting * In the highlight:import/import-relationship-mapping-table[relationship mapping table] you will see the nodes and ID properties at each end of the `CONTAINS` relationship. Setup the *From* and *To* for the `CONTAINS` relationship: -* The `From` end of the node is the `Order` node with the `id` property (remember that this property was mapped to the `orderId` column in the `orders.csv` file). -* Our `order-details.csv` file also contains an `orderId` column, so select this in the highlight:import/import-rel-from-dropdown[from dropdown]. This gives Data Importer the information it requires to link up the From end of the relationship. -* We need to select the correct file column for the `To` end of the relationship (the Product node). As you might guess, this is the `productId` in the highlight:import/import-rel-to-dropdown[to dropdown] +* The `From` end of the node is the `Order` node with the `id` property (remember that this property was mapped to the `orderId` column in the `orders.csv` file). +* Your `order-details.csv` file also contains an `orderId` column, so select this in the highlight:import/import-rel-from-dropdown[from dropdown]. +This gives Data Importer the information it requires to link up the From end of the relationship. +* You need to select the correct file column for the `To` end of the relationship (the Product node). +As you might guess, this is the `productId` in the highlight:import/import-rel-to-dropdown[to dropdown] -There should now be no dashed outlines in the highlight:import/import-model-panel[Graph Model pane] as we have successfully mapped the file. +Everything in the highlight:import/import-model-panel[Data model pane] should now have green check marks as you have successfully mapped the file. === More properties for richer queries -For relationships, you can add properties that might be useful for your queries. +For relationships, you can add properties that may be useful for your queries. -In the `order-details.csv` file you'll notice the columns `unitPrice`, `quantity` and `discount` could be useful to add as properties to the `CONTAINS` relationship. These properties are well suited to being on the relationship since they couldn't easily be encapsulated on the nodes at either end of the relationship. For example `quantity` does not belong on either the `Product` or `Order` nodes since products will be sold in different quantities on different orders. +In the `order-details.csv` file, you'll notice the columns `unitPrice`, `quantity` and `discount` could be useful to add as properties to the `CONTAINS` relationship. +These properties are well suited to being on the relationship since they couldn't easily be encapsulated on the nodes at either end of the relationship. +For example `quantity` does not belong on either the `Product` or `Order` nodes since products will be sold in different quantities on different orders. -Just as we did for nodes, use the highlight:import/import-select-from-file-button[select from file] button to map those columns to new properties on the relationship. +Just as you did for nodes, use the highlight:import/import-select-from-file-button[Map from file] button to map those columns to new properties on the relationship. [TIP] ==== @@ -191,29 +237,31 @@ button::Load model and mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-no === Relationship defined in the same file as one node -In this example, a separate link table `order-details.csv` defines the relationship linking `Orders` and `Products`. +In this example, a separate flat file, `order-details.csv`, defines the relationship linking `Orders` and `Products`. -However, it can be quite common to have files where the relationship is defined by the same file as that used for the node at one (or sometimes both) ends of the relationship. In our example, you can see how the `orders.csv` file also contains a `shipVia` column which could be used to define the relationship to a `Shipper` node created from the `shippers.csv` file. +However, it is quite common to have files where the relationship is defined by the same file as that used for the node at one (or sometimes both) ends of the relationship. +In this example, you can see how the `orders.csv` file also contains a `shipVia` column which could be used to define the relationship to a `Shipper` node created from the `shippers.csv` file. -To see how this mapping looks, we have prepared an example for you to inspect the configuration. +To see how this mapping looks, here's an example for you to inspect the configuration. button::Load Northwind shipper mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-shipper-mapping-zip-file}] -Here you can see we are using the `orders.csv` file to define both the `Order` node and the `SHIPS` relationship, as well as mapping the `Shipper` node to `shippers.csv`. +Here you can see that the `orders.csv` file is used to define both the `Order` node and the `SHIPS` relationship, as well as mapping the `Shipper` node to `shippers.csv`. === Relationship defined in the same file as both nodes -In examples where the nodes at each end of the relationship are both mapped to the same file, the relationship can ususally be inferred by the same file. If you first setup the nodes with their IDs and mapping, when you draw the relationship we will assist you by mapping the `From`` and `To`` parts of the relationship automatically. +In examples where the nodes at each end of the relationship are both mapped to the same file, the relationship can ususally be inferred by the same file. +If you first set up the nodes with their IDs and mapping, when then you draw the relationship, the `From` and `To` parts of the relationship will be mapped automatically. You can try this out by loading the simple example below and connecting the two nodes that are mapped to the same file: button::Load people and locations[role=NX_IMPORT_LOAD,endpoint={people_locations_nodes_only_zip_file}] -The model we are aiming for is as below. +The model you are aiming for is as below. image::import-people and locations.png[] -If you add the relationships and label their types as above, you'll observe that the `From` and `To`` relationships are automatically mapped for you. +If you add the relationships and label their types as above, you'll observe that the `From` and `To` relationships are automatically mapped for you. // TO-DO: Is not so neat in this example switching to a completely different context - would be better to add a Northwind related example of ths - look at doing this as it's a good example to show. @@ -227,11 +275,11 @@ button::Load configuration[role=NX_IMPORT_LOAD,endpoint={people_locations_full_z == Ready to import? -Let's get back to the Nortwind model so we can pick up where we left off, start by reloading what we created earlier. +Let's get back to the Nortwind model, start by reloading the small Northwind model you created. button::Load model and mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-node-and-relationship-mapping-zip-file}] -Any dashed lines in your model means that the mapping is not complete. +Any object in your model without a green check mark means that the mapping is not complete. If the mapping is not complete, you will not be able to run the import. The following items **must be** mapped on a **node**: @@ -256,21 +304,22 @@ Click the highlight:import/import-load-preview-button[Preview button] to see a s image::preview.png[] Even though the preview only scans the first few rows of your files, it is often sufficient to make sure everything connects as expected. +You can click individual elements in the preview to verify that their properties appear as expected. But you should keep in mind that it is only a preview and only a sample of your data. The actual graph may look different once the full import is complete. You want to have your mapping completely done before previewing, but if you have missed something, you are still able to do a preview, but the incomplete elements will not be rendered. -In other words, any dashed element in your model will not show up in the preview. +In other words, any element without a check mark in your model will not show up in the preview. -As mentioned before, if any element in your model is dashed, you will **not** be able to run the import. +As mentioned before, if any element in your model not mapped, you will **not** be able to run the import. == Running an import -Click highlight:import/import-run-import-button[Run import] to import the files specified in your model. -The simple model you have created in this example only maps to 3 of the 11 available files. -The files not specified in your model are **not** imported, but they remain in the highlight:import/import-file-panel[Files panel]. +Click highlight:import/import-run-import-button[Run import] to import the files specified in your model. + +If any uploaded files are not specified in your model, these are **not** imported, but they remain in the highlight:import/import-file-panel[Files panel]. -If any mapping is incomplete, we will tell you that your model has errors and add a red exclamations mark next to the incomplete element in the model. +If any mapping is incomplete, you will be informed that your model has errors and a red exclamation mark is shown next to the incomplete element in the model. When you select an incomplete element, the mapping pane also highlights the missing details. Once you've addressed any errors, go ahead and run the import again. @@ -278,10 +327,11 @@ You should see a popup window showing the successful results. image::import_results.png[] -The summary shows what was included in the import. +The summary shows what was included in the import. You can compare to your CSV files to verify that everything was imported. -Congratulations on modelling, mapping, and loading your data! You can now explore and query it to learn more about the power of graphs and Neo4j. +Congratulations on modelling, mapping, and loading your data! +You can now explore and query it to learn more about the power of graphs and Neo4j. We have a few very useful importer tips to complete this guide. [TIP] @@ -300,7 +350,7 @@ Ensure you are in the import tab. button::Import[role=NX_TAB_NAV,tab=import] -image::save-load.png[] +image::save_load.png[] When you choose to download your model, with or without data, you are essentially saving it. The model doesn't have to be mapped for you to download. @@ -313,39 +363,40 @@ The data is stored as CSV-files and the model as a JSON file, which makes it eas You can run the import multiple times without duplicating your data. For example, if you want to make some changes to your model after you've run the import, just fix your model and when you are happy run the import again. -The changes you made will overwrite what you had before, but no existing elements will be recreated. +The changes you made will overwrite what you had before, but no existing elements will be recreated, unless you change their IDs. === When you outgrow the Data Importer -Workspace's importer may not meet _all_ of your varied load needs, whether they are transformations or differing data formats. -If you need more control, the chances are you can achieve the load using some of the other approaches to loading data into Neo4j. +Workspace's importer may not meet _all_ of your varied load needs, whether they are transformations or differing data formats. +If you need more control, the chances are you can achieve the load using some of the other approaches to loading data into Neo4j. The following are useful resources for different needs: -- https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/[LOAD CSV]] for writing your own bespoke Cypher load scripts from CSVs, leveraging the full capabilities of Cypher. -- https://neo4j.com/docs/operations-manual/current/tutorial/neo4j-admin-import/[Neo4j-admin import]] for loading large amounts of CSV data rapidly into an offline database -- https://neo4j.com/product/connectors/[Neo4j connectors] to connect data from a variety of soruces into Neo4j. -- https://neo4j.com/docs/apoc/current/overview/apoc.load/[APOC Load procedures] for specialist Cypher procedures to make it easier to ingest data from formats including, json, xml and arrow. +- https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/[LOAD CSV] for writing your own bespoke Cypher load scripts from CSVs, leveraging the full capabilities of Cypher. +- https://neo4j.com/docs/operations-manual/current/tutorial/neo4j-admin-import/[Neo4j-admin import] for loading large amounts of CSV data rapidly into an offline database +- https://neo4j.com/product/connectors/[Neo4j connectors] to connect data from a variety of sources into Neo4j. +- https://neo4j.com/docs/apoc/current/overview/apoc.load/[APOC Load procedures] for special Cypher procedures to make it easier to ingest data from formats including json, xml and arrow. == Frequently Asked Questions -*Missing files - why does the importer say I need to provide my files after I've aready provided them?* +*Missing files - why does Data Importer say I need to provide my files after I've aready provided them?* -When you provide the importer with your files, you are actually providing your web browser with a link to those files on your local file system, they aren't uploaded anywhere. The importer streams the content of the files to you database only when you run the import. +When you provide the importer with your files, you are actually providing your web browser with a link to those files on your local file system, they aren't uploaded anywhere. +The importer streams the content of the files to you database only when you run the import. If you reload the page, the importer loses access to the connection to those files due to security restrictions. -These are in place to prevent web applications accessing files you haven't given express permission to use on page load. +These are in place to prevent web applications accessing files you haven't given express permission to use on page load. You simply need to re-provide the files when requested by data importer to be able to run an import. *How can I replace a file?* -The importer doesn't currently allow you to swap out files in the UI. -However, there is a workaround that may prove useful. +The importer doesn't currently allow you to swap out files in the UI. +However, there is a workaround that may prove useful. If you want to provide a different file with the same column structure to data importer, you can rename it to match and then simply add the file to the files panel. This will replace the reference to the latest file and be available for use by your import. -*How do I change the database data importer loads into?* +*How do I change the database Data Importer loads into?* -If you are using a Neo4j instance that supports multiple databases, the importer will use the home database to import data into. +If you are using a Neo4j instance that supports multiple databases, the importer will use the home database to import data into. You may have the facility to change the home database for the user that you connect to your DBMS with, read more on setting the home database for a user https://neo4j.com/docs/cypher-manual/current/access-control/manage-users/[here]. diff --git a/documentation/explore-upx.adoc b/documentation/explore-upx.adoc new file mode 100644 index 0000000..7855bb4 --- /dev/null +++ b/documentation/explore-upx.adoc @@ -0,0 +1,293 @@ += Explore and interact with the data visualization + +== Explore guide - an introduction + +The _Explore_ tool is a no-code interface that allows you to explore and interact with your graph data. + +In order to use Explore, you need to have data in your database and therefore it's recommended that you take this guide _after_ the Data Importer guide. + +However, if you already feel comfortable with importing and modeling data, you can quickly load the Northwind example dataset below without having to take the Import guide. + +[%collapsible] +.Load and import Northwind +==== +Use the button to load Northwind data and model: + +button::Load the Northwind dataset[role=NX_IMPORT_LOAD,endpoint=https://raw.githubusercontent.com/neo4j-graph-examples/northwind/main/import/northwind-data-importer-mode-data.zip] + +Click `Run import` and once it's completed click `Explore results`. + +With that in place, let's actually start exploring! +==== + +If you already have imported the dataset, you can just hit _Next_ and get straight to exploring! + +== The Explore UI + +[role=NX_TAB_NAV,tab=explore] +pagelaunch::[] + +When you first open the Explore tool (provided that you have data in your database), you're presented with a sample graph on the canvas, also called the _scene_, and a legend panel on the right and a sidebar on the left. + +The highlight:explore/tabpanel-categories[legend panel] shows the available node labels and relationships, respectively, in your data. +You can view them all or filter by whether they are present or not in the current scene. + +The sidebar contains the Perspective drawer, which you will have a closer look at later. + +On the bottom is the map and the layout options. + +On the top is the highlight:explore/searchBox[search bar] where you define what you want to see in the scene. + +The next step is about the search bar. + +== Search + +Any graph exploration starts in the search bar. +You can search using any of the node labels/relationship types in the legend panel. + +When you click the empty search bar, you'll see a number of suggestions. +The first one is the sample graph, `Show me a graph`, that will visualize a some of your data. +The other suggestions consist of the node labels and relationship types in your database. +You can see these in the legend panel as well. + +When you clear the search bar, the returned elements from your previous search stay in the scene and any new returned elements are added to existing scene. + +When you want a clean slate, bring up the _context menu_ by right-clicking on an empty part of the scene and select _Clear Scene_. + +Alternatively, you can use a keyboard shortcut: ⌘+⌫ for Mac or Ctrl+⌫ for Windows, to clear your scene. + +With an empty scene, you're ready to get back to more refined searching in the next step. + +== Search for something specific + +Let's try an example in the Northwind dataset. +Say you want to see which suppliers supply products in the different categories to get a better grasp of what is being supplied by whom. +This would have been a costly operation in SQL, but is a quick thing to do in a graph database. + +If you remember the datamodel for Northwind: + +image::small-model.png[] + +This pattern is easy to enter in the search bar. + +Click the search bar and select first `Supplier` and then `Product` followed by `Category` and press enter to execute. +Note that you _can_ specify the relationship type, but in this simple dataset, you don't have to. + +In the visualization it is visible that one group of products is disconnected from the others. +Can you tell which product category they belong to? + +[%collapsible] +.Hint +==== +The _Dairy Products_ form a subgraph of their own. +==== + +You can be even more specific in your search, as you'll see shortly. + +== Specific values + +You can also search for specific property values from the search bar. +You can specify a property on one node label or on many. + +Say you want to refine your search a little and find which _categories_ do _customers in London_ order _discontinued products_ from. +This extra information is stored as properties on the nodes and these can be specified directly in the search bar. + +(If you can't remember the properties in the example dataset, you can find them in the _Perspective drawer_ from the sidebar, just click on the node label you're interested in to expand a list of its properties.) + +Start by selecting the _Customer_ category, then scroll down and find `Customer city:value`, select it and then type _London_. + +image::london2.png[] + +Now you have the the start nodes specified so let's get the next step in your pattern. + +[NOTE] +==== +The Neo4j database is _case sensitive_ and property values are matched in a case-sensitive fashion. +==== + +== Specific values continued + +A customer _purchases_ an order but since you don't need to specify the relationship, select the `-(any)-` relationship and then _Order_ and add that to the pattern. +You are not specifying any properties on the _Order_ node, so proceed to _Product_ by using to add another `-(any)-` relationship to the pattern. + +On the _Product_ node, you want only the _discontinued_ products so add that to the _Product_ node in the same way as you did with the `Customer`-node. +The _discontinued_ property is `boolean` and the only possible values are `true` or `false`, so type _true_ after the colon and confirm with . + +image::discontinued.png[] + +Now there's only one node left to add to the pattern and that's the _Category_. +Since you are not specifying any properties on the _Category_ nodes either, just add it as is. + +You should now have a search pattern that looks like this: + +image::pattern2.png[] + +When you run the search pattern, you can see that one category has more discontinued products ordered by customers in London than the others. +Can you tell which one? + +== Node Inspector + +From the visualization, only the title of each node is visible. +The title is selected from the properties of that node (you'll learn how to change the title property in a later step), but you can use the Inspector to see all the information about a node or a relationship by double-clicking on it. + +For a node, the Inspector will show you: + +* all the node's properties and what datatype they are (this is visible if you hover over them). +* a list of all its neighbors, both on and off the Scene. +* a list of the relationsips used to connect this node to its neighbors. + +For a relationship, the Inspector shows a list of the properties and values on the relationship and a more detailed list of the nodes it connects. + +You can edit the properties from the Inspector and this includes both adding new and deleting existing properties. + +But the Inspector is only one way you can interact with your data. +The next step will show you more. + +== Scene interactions + +There are many ways to interact with the data and the best way to demonstrate this is to start with just a few nodes. + +Try to bring out the different categories in the dataset! + +(Hint: Go to the search bar) + +[%collapsible] +.Can't remember how to do this? +==== +Use the button: + +button::Visualize categories[role=NX_EXPLORE_SEARCH,search=Categories] +==== + +You should now have the eight _Category_ nodes visible. +Pick one node and right-click on it to bring up the context menu (the same menu you brought up to clear your Scene previously). + +The context-menu allows you to do many different things, let's start with _Expand_. +You can either expand to see *all* its neighbors, or restrict the expansion to a certain relationship type. +The _Categories_ only have one relationship type so in this case, the choice is easy. + +Another interesting thing you can do from the context menu is to find the _shortest path_ between to nodes. +Select (`⌘` and click on Mac, `Ctrl` and click on Windows) two nodes, say _Confections_ and _Condiments_ for example. +Bring up the context menu for one of them, it doesn't matter which one, and select _Path_ -> _Shortest Path_. +Can you see which node that connects them? + +If you guessed the _Order_ titled *White Clover Markets*, you are correct. +Now if you expand this _Order_ node to see the _purchased_ relationship, you can determine which customer has purchased something from both categories in the same order. + +In the next step, you'll learn how you can change the look of what you see in your Scene. + +== Styling - default + +The highlight:explore/tabpanel-categories[legend panel] on your right contains a list of the elements in your dataset and how they are represented in the visualization. +But you can style this any way you want, change captions or change the size and colors of the elements, either by default or rule-based. + +Let's try to style the elements in the scene! + +Start by bringing some more nodes and relationships on to your Scene by selecting all the Category-nodes and select _Expand_ from the context menu (right-click while hovering over one of the selected nodes). + +Expand all and you should see all the products in the various categories. +Click on the circle next to the _Product_ in the legend panel to see all styling options. +The styling options for relationships are equivalent and you access them from the _Relationships_ tab on the top of the legend panel. +// (would be cool to highlight _Relationships_ in the legend pandel here). + +Try change the color of the Product nodes or play around with different sizes. +You can also change the text on the node/relationship to any of the property keys for the selected node category or relationship type. +If you don't like text, you can pick an icon to represent nodes of a category instead. + +All of these changes will be applied to _all_ the product nodes in the Scene by default. +But if you want to highlight differences in property values, try the rule-based styling instead. + +Click **Next** to explore! + +== Styling - Rule-based + +Let's say you want to be able to see which products are discontinued directly in your Scene. +Go back to the _Product_ in the legend panel, select **Rule-based** and the _Add rule-based styling_. + +From the list of available properties, you'll find `discontinued` which has a boolean value (`true` or `false`) which is easy to distinguish in the visualization by applying a contrasting color to all Product nodes with the `discontinued` property of `true`. +But you could also change the size or text on affected nodes, the choice is yours. + +Of course, not all property values are boolean, numerical values offer even more options for rule-based styling. +Try styling based on the `unitsInStock` property for example, you can experiment with single values, try gradient coloring or sizing based on a range, or pick unique values. + +image::style.png[] + +In the next step you'll learn how to use filters to refine the results in your Scene. + +== Filtering +//a highlight would be cool here +Apart from using styling to differentiate by property values, you can use filters to filter out affected nodes and/or relationships. + +Let's assume that you want to place an order of 100 items from the seafood category and the only requirements are that it is seafood and that 100 items are available now. + +Start by clearing the Scene and then bring up products in the seafood category. + +[%collapsible] +.Can't remember how to do this? +==== +Start typing _Category_, hit to complete. +Type _categoryName_, to complete and then _Seafood_. +Select _Product_ from the dropdown in the search bar and complete the search by pressing . + +or use the button + +button::Seafood products[role=NX_EXPLORE_SEARCH,search=Category categoryName Seafood Product] +==== + +With those in place click the filter icon (under the search bar) and **Add filter**. +//implement this: highlight:explore/filter-collapse-button[filter icon] +First you need define which node label or relationship type to use the filter on, in this example you are looking for _Products_. + +Just like with the styling, you then need to select a property to filter on. +You want to see how many items are in stock and the property key for that is `unitsInStock`. +A histogram shows available values. +Go ahead and specify that you want a minimum of 100 items. + +Once you apply the filter, all items that don't meet the requirements (in this case, products with less than 100 items in stock) are greyed out and can't be interacted with. +If you want to remove them completely from the Scene, click **Dismiss filtered elements**. +//a highlight here +You can apply multiple filters too and if you want to remove a filter, use the toggle on the filter or delete it altogether. +When you remove a filter, you'll see that greyed-out elements come back but dismissed elements don't. + +Hit **Next** to learn more about the last filtering feature, the **Slicer**. + +== Slicer + +If you want to showcase elements by a range of _numerical_ properties, the **Slicer** is the way to go. +You find it below the **Filter** button. +//Highlight here, if possible +The Slicer lets you select a range of numerical values on a property key and highlight the range dynamically in the Scene via a timeline. +You can scrub manually or use the playback function. + +Let's try it out! + +Say you want get a general idea of the product prices in the different categories without having to manually compary. + +As usual, start by clearing the scene. + +With a clean slate, bring out the products and the categories. + +[%collapsible] +.Need help to do this? +==== +button::Products in categories[role=NX_EXPLORE_SEARCH,search=Category Product] +==== + +Click the Slicer button and specify which property with _numerical_ values you want to use. +For the purpose of this example, select _unitPrice_ and then set your range on the timeline and press play and watch products appear and disappear in the Scene as their unit prices appear within the range on the timeline. + +In this example, it would be interesting to see products added to categories successively without disappearing again. +This can be done by changing the _playback mode_ to _Start of Range to end_ in the Settings. + +image::slicer-settings1.png[] + +If you want to see the products removed instead of added, expand the range to cover the entire timeline and the select the _Within range_ playback mode and press play. + +This is just one example on a small amount of elements. +You can use the Slicer on any numerical values, feel free to play around. +If you're unsure about the datatypes of the properties, you can always have a look in the Perspective drawer on the sidebar. +//highlight here +highlight:explore/perspective[Perspective drawer] + + + diff --git a/documentation/explore.adoc b/documentation/explore.adoc index ec4416f..da244af 100644 --- a/documentation/explore.adoc +++ b/documentation/explore.adoc @@ -15,7 +15,7 @@ Use the button to load Northwind data and model: button::Load the Northwind dataset[role=NX_IMPORT_LOAD,endpoint=https://raw.githubusercontent.com/neo4j-graph-examples/northwind/main/import/northwind-data-importer-mode-data.zip] -Click `Run import` and once it's completed click `Start Exploring`. +Click `Run import` and once it's completed click `Explore results`. With that in place, let's actually start exploring! ==== @@ -54,7 +54,7 @@ When you clear the search bar, the returned elements from your previous search s When you want a clean slate, bring up the _context menu_ by right-clicking on an empty part of the scene and select _Clear Scene_. -Alternatively, you can use a keyboard shortcut: _Mac_: `⌘+⌫` or _Windows_: `Ctrl+⌫` to clear your scene. +Alternatively, you can use a keyboard shortcut: ⌘+⌫ for Mac or Ctrl+⌫ for Windows, to clear your scene. With an empty scene, you're ready to get back to more refined searching in the next step. @@ -94,19 +94,24 @@ This extra information is stored as properties on the nodes and these can be spe (If you can't remember the properties in the example dataset, you can find them in the _Perspective drawer_ from the sidebar, just click on the node label you're interested in to expand a list of its properties.) -Start by selecting the _Customer_ category, then type _city_ and select the suggestion (alternatively press `TAB` to autocomplete) then type _London_ and select the suggestion. +Start by selecting the _Customer_ category, then scroll down and find `Customer city:value`, select it and then type _London_. -image::london1.png[] +image::london2.png[] Now you have the the start nodes specified so let's get the next step in your pattern. +[NOTE] +==== +The Neo4j database is _case sensitive_ and property values are matched in a case-sensitive fashion. +==== + == Specific values continued -A customer _purchases_ an order but since you don't need to specify the relationship, go straight to _Order_ and add that to the pattern. -You are not specifying any properties on the _Order_ node, so proceed to _Product_. +A customer _purchases_ an order but since you don't need to specify the relationship, select the `-(any)-` relationship and then _Order_ and add that to the pattern. +You are not specifying any properties on the _Order_ node, so proceed to _Product_ by using to add another `-(any)-` relationship to the pattern. -On the _Product_ node, you want only the _discontinued_ products so add that to the _Product_ node. -The _discontinued_ property is `boolean` and the only possible values are `true` or `false`, so type _true_ after the colon. +On the _Product_ node, you want only the _discontinued_ products so add that to the _Product_ node in the same way as you did with the `Customer`-node. +The _discontinued_ property is `boolean` and the only possible values are `true` or `false`, so type _true_ after the colon and confirm with . image::discontinued.png[] @@ -115,7 +120,7 @@ Since you are not specifying any properties on the _Category_ nodes either, just You should now have a search pattern that looks like this: -image::pattern.png[] +image::pattern2.png[] When you run the search pattern, you can see that one category has more discontinued products ordered by customers in London than the others. Can you tell which one? @@ -131,7 +136,7 @@ For a node, the Inspector will show you: * a list of all its neighbors, both on and off the Scene. * a list of the relationsips used to connect this node to its neighbors. -For a relationship, the Inspector shows a list of the relationships on the relationship and a more detailed list of the nodes it connects. +For a relationship, the Inspector shows a list of the properties and values on the relationship and a more detailed list of the nodes it connects. You can edit the properties from the Inspector and this includes both adding new and deleting existing properties. diff --git a/documentation/get-started-upx.adoc b/documentation/get-started-upx.adoc new file mode 100644 index 0000000..639de53 --- /dev/null +++ b/documentation/get-started-upx.adoc @@ -0,0 +1,279 @@ += Learn graph fundamentals with Neo4j +:imagesdir: https://neo4j-graph-examples.github.io/get-started/documentation/img/ + +== Learn the basics + +This guide teaches you about the power of graph databases. +It is the recommended starting place for all new users as it touches upon the concepts and tools you need to work with graphs. + +=== What you will learn + +This guide takes around 10 minutes and by the end of it you will able to: + +- Understand the _graph property model_ and what problems it can help you solve. +- Convert an understanding of a relational database model to a graph. +- Import and model data from CSV files and map them to a graph. +- Visually explore that data, without code, in a graph. +- Write your first simple graph queries using _Cypher_. + +=== Get started! + +You are going to use the classic relational dataset known as Northwind and bring the fictional company into a graph-enabled future. + + +== What is a graph? + +=== Concepts + +A graph database stores _nodes_ (`Supplier`, `Product`, etc) and their _relationships_ (e.g. `Supplier SUPPLIES Product`). + +Other types of databases may use tables and documents, but in a graph, data is stored in the same way as you may sketch ideas on a whiteboard. + +image::model.png[] + +In relational databases, you are often required to add explicit joins to your queries. +In doing this, relationships are calculated at runtime, which can be an expensive and slow operation. + +In a graph, where the relationships are stored, many powerful operations are faster and simpler. + +=== Schema-free + +In a relational database, you must define your schema (the structure of the data). +In a graph, your data is managed without restricting it to a predefined schema. +This allows more flexibility in thinking about the data and in evolving it. + +== Nodes, properties, relationships + +The nodes and relationships in your graph can have _types_ and _properties_. + +=== Nodes and properties + +Nodes can be tagged with _labels_, representing their different roles in your dataset (e.g. `Supplier`, `Employee`, `Customer`). +They can also have any number of key-value pairs as _properties_ (e.g. `name:"Camembert Pierrot"`). + +=== Relationships + +_Relationships_ provide directed, typed, or attributed, connections between two node entities (e.g. `Shipper SHIPS Order`). + +Relationships always have a _direction_, a _type_, a start node, and an end node. +They can also have properties, just like nodes. + +Nodes can have any number of relationships without sacrificing performance. + +Although relationships are always directed, they can be navigated efficiently in any direction. +In this example, you can find who shipped an order and you can also reverse that and find what orders were shipped. + + +== Re-imagining a classic (Northwind) + +// await signals.emit(SIGNAL_NAME.WorkspaceNavigate, { scope: APP_SCOPE.import }); +The classic Northwind dataset represents an online shop. + +The button below lets you load the dataset and the datamodel in one click, for your convenience. + +button::Get the Northwind dataset[role=NX_IMPORT_LOAD,endpoint=https://neo4j-graph-examples.github.io/get-started/data/northwind-data-importer-model-data.zip] + +image::product-category-supplier.png[] + +You are now going to transform this relational database into a graph database. + +image::product-graph.png[] + +You can see the CSV files from Northwind's tables represented as a graph model. +The mappings for these files are already prepared for you. + +Notice the relationships connecting the nodes, e.g. a `Customer PURCHASED an Order` and the `Order ORDERS Products`. + + + +== Finish the Northwind import + +For each node and relationship in the model you can see which parts of the CSV file are mapped to which properties. + +Source and target IDs from the original join tables or foreign keys are used to create relationships to connect nodes. + +The model is interactive; you can click around and explore its nodes and relationships. + +=== Preview your data import + +You can see a preview of the data import by clicking the highlight:import/import-load-preview-button[Preview button]. + +This allows you to check node labels, the property names and values, and the relationship types and directions. + +If you're satisfied, click the highlight:import/import-run-import-button[Run import button] to load your data into your graph. + +If something goes wrong, keep in mind that the tool can import the same data multiple times and you can reset your database to blank in the AuraDB Console. + +// A/B Test: TBD we could leave off one simple mapping, e.g. shipper and let the user do it (or prepare the node without mapping the rel and properties (but pick one that lends itself well to auto-mapping) in an area of the model that is non-crucial for later steps but not sure if that would have too many folks fail here + +=== Explore your data + +After you have imported the Northwind dataset, click the _Start Exploring_ button in the report popup or use the _Explore_ tool. + +Next you are going to see the power of graph visualization. + +// TODO button switch to explore + + +== Explore your graph + +With the data in a graph, it is time to get familiar with the _Explore_ tool. + +The `Show me a graph` Search phrase runs automatically to show an example subset of the data. +The visualized graph represents the relationships in the data in an intuitive way. + +[NOTE] +==== +You can also run the _Show me a graph_ example Search phrase yourself by typing the _Show me a graph_ in the top-left search bar. +==== + +=== Searching for data in Explore + +You can use simple search phrases based on your node labels and relationship types to visualize your graph. +If you ran the example Search phrase, you should clear the scene before you continue. +Right-click anywhere on the canvas and select _Clear Scene_ or `Ctrl+Bksp`/`Cmd+Bksp`. + +If you enter `Category` and then press return; it fetches and displays all categories. +You can now explore and expand the graph visualization. + +This is a great way to discover interesting relationships and formulate questions about your data. + +// TODO captions!! + +Another useful feature is to select two nodes (`Ctrl-Click`/`Cmd-Click``) and select _Paths -> Shortest Path_ from the right-click context menu on one of them. + +// TBD educate about paths in search box! + +You can select all `Categories` by clicking on their box in the right side legend and then choose _Expand -> All_ in the context menu to see all the products contained in these categories. + +The context menu also offers many more options like editing, partial expansion, clearing the scene, or dismissing (un-)selected nodes. + +== Advanced exploration + +In the bottom-right of the _Explore_ canvas you can switch between the default force-based layout, a hierarchical layout, and a coordinate layout. + +You can style your data in the right legend using colors, icons, sizes, and captions, and even apply rules for these. + +// TODO: a screenshot here might be good to inspire or show what's possible. + +Click on `Category` in the legend panel and pick a different color, icon, and/or size for your nodes. + +Selected nodes and relationships are highlighted and counted in the legend panel and shown in the card view in the lower left corner. +There you can explore your data structurally. + +Explore also offers options to filter your on-screen nodes with a advanced filter menu, and even rudimentary user programming by storing Cypher phrases to reuse later. + +Learn more in the link:https://neo4j.com/docs/bloom-user-guide/current/bloom-visual-tour/[documentation^] and videos. + +// TODO switch to Query + +== Basic Querying + +Switch to the _Query_ tool, if you haven't already done so. + +On the left sidebar you can see the counts of types of nodes and relationships. +Click on `(Product)` - the database fetches a few elements with the `Product`-label using a minimal query. + +.Load query for product nodes +[source,cypher] +---- +MATCH (n:Product) +RETURN n +LIMIT 25 +---- + +The result nodes are visualized in the _graph view_, and you can double-click nodes to see their neighbors. + +In the right properties side-panel you can inspect more properties. +You can also style nodes (size, color, caption) by clicking on the `(Product)` label on top. + +Results can also be shown in a tabular view by clicking the _table view_ option. +Nodes and relationships are visualized in a JSON structure. +That view is shown by default if you return only scalar values. + +// TBD Alternatively we could have them click on [:SUPPLIES] and then they would already see a graph visualization, it would use graph patterns and pattern variable, but it might be too complex. I would actually prefer this one. +// See screenhots below. + +== Writing your first query + +Like any other database, Neo4j can be queried with a query language. + +Neo4j's graph query language is called _Cypher_ and is well-suited for finding patterns. +Unlike SQL, there is no reliance on writing complex joins. + +In Cypher, you represent the graph patterns with ascii-art. + +Parentheses `(p:Product {name:'Camembert Pierrot'})` form "circles" around nodes and arrows `+-[:SUPPLIES]->+` depicts relationships. + +You draw in text what you would draw on the whiteboard. + +These patterns are used to find, create, and update graph data. + +You've already seen the `MATCH (n:Product) RETURN n LIMIT 25` statement that was run previously. + +Now click on the statement to edit it and change the pattern and result to: + +[source,cypher] +---- +MATCH (n:Product)<-[r:SUPPLIES]-(s:Supplier) +RETURN n,r,s +LIMIT 25 +---- + +then click on the run icon icon:PlayIcon[]. + +Congratulations, you've written and run your first Cypher query! + + +== A more advanced query + +For the last part of this guide you get the opportunity to try some more powerful queries. + +First, this query finds all products ordered by a customer and who supplies them. + +.All products ordered by a customer and who supplies those +[source,cypher] +---- +MATCH path=(c:Customer)-[:PURCHASED]->()-[:ORDERS]->(:Product)<-[:SUPPLIES]-(:Supplier) +WHERE c.companyName = 'Blauer See Delikatessen' +RETURN path; +---- + +image::example.png[] + +You can also see how many products in the `Produce` category each customer ordered. + +.Find total quantity per customer in the "Produce" category +[source,cypher] +---- +MATCH (cust:Customer)-[:PURCHASED]->(:Order)-[o:ORDERS]->(p:Product), + (p)-[:PART_OF]->(c:Category {categoryName:'Produce'}) +RETURN cust.contactName as CustomerName, + sum(o.quantity) AS TotalProductsPurchased +---- + +== Next steps + +Congratulations on completing this tutorial. + +You can do more with the Northwind dataset or you can reset your instance in Neo4j Aura Console and import your own data. + +For your next steps, a suggestion is to look at furthering your Cypher knowledge or building an application using Neo4j's popular language drivers. + + +=== Next steps with Cypher + +To learn more about Cypher, check out the interactive https://graphacademy.neo4j.com/categories/beginners/[GraphAcademy course^] and have a look at the https://neo4j.com/docs/cypher-cheat-sheet/current/[Cypher Cheat Sheet^]. + +=== Creating applications + +As you get more familiar with Cypher, you can use the https://neo4j.com/docs/getting-started/current/languages-guides/[Neo4j drivers^] for C#, Go, Java, JavaScript, and Python to build your applications, or use our https://neo4j.com/product/graphql-library/[GraphQL] or https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/[Spring Data Neo4j] integrations for building APIs. + +=== Go further with GraphAcademy + +GraphAcademy is provided by Neo4j and offers in-depth courses on many aspects of graph databases. +Check out the https://graphacademy.neo4j.com/[GraphAcademy website^]. + +//=== Mastering data importer + +// TODO: expand this diff --git a/documentation/get-started.adoc b/documentation/get-started.adoc index 4f00af1..534f6d3 100644 --- a/documentation/get-started.adoc +++ b/documentation/get-started.adoc @@ -1,7 +1,7 @@ = Learn graph fundamentals with Neo4j :imagesdir: https://neo4j-graph-examples.github.io/get-started/documentation/img/ -== Get started +== Learn the basics This guide teaches you about the power of graph databases. It is the recommended starting place for all new users as it touches upon the concepts and tools you need to work with graphs. @@ -13,10 +13,10 @@ This guide takes around 10 minutes and by the end of it you will able to: - Understand the _graph property model_ and what problems it can help you solve. - Convert an understanding of a relational database model to a graph. - Import and model data from CSV files and map them to a graph. -- Visually explore that data, without code, in a graph. +- Visually explore that data, without code, in a graph. - Write your first simple graph queries using _Cypher_. -=== Get started! +=== Get started! You are going to use the classic relational dataset known as Northwind and bring the fictional company into a graph-enabled future. @@ -25,26 +25,26 @@ You are going to use the classic relational dataset known as Northwind and bring === Concepts -A graph database stores _nodes_ (`Supplier`, `Product`, etc) and their _relationships_ (e.g. `Supplier SUPPLIES Product`). +A graph database stores _nodes_ (`Supplier`, `Product`, etc) and their _relationships_ (e.g. `Supplier SUPPLIES Product`). -Other types of databases may use tables and documents, but in a graph, data is stored in the same way as you may sketch ideas on a whiteboard. +Other types of databases may use tables and documents, but in a graph, data is stored in the same way as you may sketch ideas on a whiteboard. image::model.png[] -In relational databases, you are often required to add explicit joins to your queries. +In relational databases, you are often required to add explicit joins to your queries. In doing this, relationships are calculated at runtime, which can be an expensive and slow operation. In a graph, where the relationships are stored, many powerful operations are faster and simpler. === Schema-free -In a relational database, you must define your schema (the structure of the data). -In a graph, your data is managed without restricting it to a predefined schema. +In a relational database, you must define your schema (the structure of the data). +In a graph, your data is managed without restricting it to a predefined schema. This allows more flexibility in thinking about the data and in evolving it. == Nodes, properties, relationships -The nodes and relationships in your graph can have _types_ and _properties_. +The nodes and relationships in your graph can have _types_ and _properties_. === Nodes and properties @@ -55,10 +55,10 @@ They can also have any number of key-value pairs as _properties_ (e.g. `name:"Ca _Relationships_ provide directed, typed, or attributed, connections between two node entities (e.g. `Shipper SHIPS Order`). -Relationships always have a _direction_, a _type_, a start node, and an end node. +Relationships always have a _direction_, a _type_, a start node, and an end node. They can also have properties, just like nodes. -Nodes can have any number of relationships without sacrificing performance. +Nodes can have any number of relationships without sacrificing performance. Although relationships are always directed, they can be navigated efficiently in any direction. In this example, you can find who shipped an order and you can also reverse that and find what orders were shipped. @@ -67,7 +67,7 @@ In this example, you can find who shipped an order and you can also reverse that == Re-imagining a classic (Northwind) // await signals.emit(SIGNAL_NAME.WorkspaceNavigate, { scope: APP_SCOPE.import }); -The classic Northwind dataset represents an online shop. +The classic Northwind dataset represents an online shop. The button below lets you load the dataset and the datamodel in one click, for your convenience. @@ -79,7 +79,7 @@ You are now going to transform this relational database into a graph database. image::product-graph.png[] -You can see the CSV files from Northwind's tables represented as a graph model. +You can see the CSV files from Northwind's tables represented as a graph model. The mappings for these files are already prepared for you. Notice the relationships connecting the nodes, e.g. a `Customer PURCHASED an Order` and the `Order ORDERS Products`. @@ -92,7 +92,7 @@ For each node and relationship in the model you can see which parts of the CSV f Source and target IDs from the original join tables or foreign keys are used to create relationships to connect nodes. -The model is interactive; you can click around and explore its nodes and relationships. +The model is interactive; you can click around and explore its nodes and relationships. === Preview your data import @@ -108,7 +108,7 @@ If something goes wrong, keep in mind that the tool can import the same data mul === Explore your data -After you have imported the Northwind dataset, click the _Start Exploring_ button in the report popup or switch to the _Explore_ tab. +After you have imported the Northwind dataset, click the _Start Exploring_ button in the report popup or switch to the _Explore_ tab. Next you are going to see the power of graph visualization. @@ -133,10 +133,10 @@ You can use simple search phrases based on your node labels and relationship typ If you ran the example Search Phrase, you should clear the scene before you continue. Right-click anywhere on the canvas and select _Clear Scene_ or `Ctrl+Bksp`/`Cmd+Bksp`. -If you enter `Category` and then press return; it fetches and displays all categories. -You can now explore and expand the graph visualization. +If you enter `Category` and then press return; it fetches and displays all categories. +You can now explore and expand the graph visualization. -This is a great way to discover interesting relationships and formulate questions about your data. +This is a great way to discover interesting relationships and formulate questions about your data. // TODO captions!! @@ -150,7 +150,7 @@ The context menu also offers many more options like editing, partial expansion, == Advanced exploration -In the bottom-right of _Explore_ you can switch between the default force-based layout and a hierarchical layout. +In the bottom-right of _Explore_ you can switch between the default force-based layout, a hierarchical layout, and a coordinate layout. You can style your data in the right legend using colors, icons, sizes, and captions, and even apply rules for these. @@ -158,7 +158,7 @@ You can style your data in the right legend using colors, icons, sizes, and capt Click on `Category` in the legend panel and pick a different color, icon, and/or size for your nodes. -Selected nodes and relationships are highlighted and counted in the legend panel and shown in the card view in the lower left corner. +Selected nodes and relationships are highlighted and counted in the legend panel and shown in the card view in the lower left corner. There you can explore your data structurally. Explore also offers options to filter your on-screen nodes with a advanced filter menu, and even rudimentary user programming by storing Cypher phrases to reuse later. @@ -169,22 +169,22 @@ Learn more in the link:https://neo4j.com/docs/bloom-user-guide/current/bloom-vis == Basic Querying -Switch to the _Query_ tab, if you haven't already done so. +Switch to the _Query_ tab, if you haven't already done so. -On the left sidebar in the first entry (database) you can see the counts of types of nodes and relationships. +On the left sidebar in the first entry (database) you can see the counts of types of nodes and relationships. Click on `(Product)` - the database fetches a few elements with the `Product`-label using a minimal query. .Load query for product nodes [source,cypher] ---- -MATCH (n:Product) -RETURN n +MATCH (n:Product) +RETURN n LIMIT 25 ---- -The result nodes are visualized in the _graph view_, and you can double-click nodes to see their neighbors. +The result nodes are visualized in the _graph view_, and you can double-click nodes to see their neighbors. -In the right properties side-panel you can inspect more properties. +In the right properties side-panel you can inspect more properties. You can also style nodes (size, color, caption) by clicking on the `(Product)` label on top. Results can also be shown in a tabular view by clicking the _table view_ option. @@ -196,14 +196,14 @@ That view is shown by default if you return only scalar values. == Writing your first query -Like any other database, Neo4j can be queried with a query language. +Like any other database, Neo4j can be queried with a query language. -Neo4j's graph query language is called _Cypher_ and is very well-suited for finding patterns. -Unlike SQL, there is no reliance on writing complex joins. +Neo4j's graph query language is called _Cypher_ and is very well-suited for finding patterns. +Unlike SQL, there is no reliance on writing complex joins. -In Cypher, you represent the graph patterns that you've seen in _Import_ and _Explore_ with ascii-art. +In Cypher, you represent the graph patterns that you've seen in _Import_ and _Explore_ with ascii-art. -Parentheses `(p:Product {name:'Camembert Pierrot'})` form "circles" around nodes and arrows `+-[:SUPPLIES]->+` depicts relationships. +Parentheses `(p:Product {name:'Camembert Pierrot'})` form "circles" around nodes and arrows `+-[:SUPPLIES]->+` depicts relationships. You draw in text what you would draw on the whiteboard. @@ -211,12 +211,12 @@ These patterns are used to find, create, and update graph data. You've already seen the `MATCH (n:Product) RETURN n LIMIT 25` statement that was run previously. -Now click on the statement to edit it and change the pattern and result to: +Now click on the statement to edit it and change the pattern and result to: [source,cypher] ---- MATCH (n:Product)<-[r:SUPPLIES]-(s:Supplier) -RETURN n,r,s +RETURN n,r,s LIMIT 25 ---- @@ -225,9 +225,9 @@ then click on the run icon icon:PlayIcon[]. Congratulations, you've written and run your first Cypher query! -== A more advanced query +== A more advanced query -For the last part of this guide you get the opportunity to try some more powerful queries. +For the last part of this guide you get the opportunity to try some more powerful queries. First, this query finds all products ordered by a customer and who supplies them. @@ -248,7 +248,7 @@ You can also see how many products in the `Produce` category each customer order ---- MATCH (cust:Customer)-[:PURCHASED]->(:Order)-[o:ORDERS]->(p:Product), (p)-[:PART_OF]->(c:Category {categoryName:'Produce'}) -RETURN cust.contactName as CustomerName, +RETURN cust.contactName as CustomerName, sum(o.quantity) AS TotalProductsPurchased ---- @@ -260,19 +260,19 @@ You can do more with the Northwind dataset or you can reset your instance in Aur For your next steps, a suggestion is to look at furthering your Cypher knowledge or building an application using Neo4j's popular language drivers. -=== Next steps with Cypher +=== Next steps with Cypher To learn more about Cypher, check out the interactive https://graphacademy.neo4j.com/categories/beginners/[GraphAcademy course^] and have a look at the https://neo4j.com/docs/cypher-cheat-sheet/current/[Cypher Cheat Sheet^]. === Creating applications -As you get more familiar with Cypher, you can use the https://neo4j.com/docs/getting-started/current/languages-guides/[Neo4j drivers^] for C#, Go, Java, JavaScript, and Python to build your applications, or use our GraphQL or Spring Data Neo4j integrations for building APIs. +As you get more familiar with Cypher, you can use the https://neo4j.com/docs/getting-started/current/languages-guides/[Neo4j drivers^] for C#, Go, Java, JavaScript, and Python to build your applications, or use our https://neo4j.com/product/graphql-library/[GraphQL] or https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/[Spring Data Neo4j] integrations for building APIs. === Go further with GraphAcademy -GraphAcademy is provided by Neo4j and offers in-depth courses on many aspects of graph databases. +GraphAcademy is provided by Neo4j and offers in-depth courses on many aspects of graph databases. Check out the https://graphacademy.neo4j.com/[GraphAcademy website^]. //=== Mastering data importer -// TODO: expand this +// TODO: expand this diff --git a/documentation/img/cypher-editor-auto-completions.gif b/documentation/img/cypher-editor-auto-completions.gif new file mode 100644 index 0000000..d312a66 Binary files /dev/null and b/documentation/img/cypher-editor-auto-completions.gif differ diff --git a/documentation/img/cypher-editor-inline-help.png b/documentation/img/cypher-editor-inline-help.png new file mode 100644 index 0000000..feb8521 Binary files /dev/null and b/documentation/img/cypher-editor-inline-help.png differ diff --git a/documentation/img/cypher-editor-linting.png b/documentation/img/cypher-editor-linting.png new file mode 100644 index 0000000..1f1b6fa Binary files /dev/null and b/documentation/img/cypher-editor-linting.png differ diff --git a/documentation/img/cypher-editor-syntax-highlighting.png b/documentation/img/cypher-editor-syntax-highlighting.png new file mode 100644 index 0000000..fea821b Binary files /dev/null and b/documentation/img/cypher-editor-syntax-highlighting.png differ diff --git a/documentation/img/cypher-reference.gif b/documentation/img/cypher-reference.gif new file mode 100644 index 0000000..245f48f Binary files /dev/null and b/documentation/img/cypher-reference.gif differ diff --git a/documentation/img/discontinued.png b/documentation/img/discontinued.png index 17081a6..5178e08 100644 Binary files a/documentation/img/discontinued.png and b/documentation/img/discontinued.png differ diff --git a/documentation/img/history-quick-search.gif b/documentation/img/history-quick-search.gif new file mode 100644 index 0000000..6c84ac4 Binary files /dev/null and b/documentation/img/history-quick-search.gif differ diff --git a/documentation/img/import-add-new-data-source.png b/documentation/img/import-add-new-data-source.png new file mode 100644 index 0000000..5ee4096 Binary files /dev/null and b/documentation/img/import-add-new-data-source.png differ diff --git a/documentation/img/import-graph-models.png b/documentation/img/import-graph-models.png new file mode 100644 index 0000000..7ce0b1b Binary files /dev/null and b/documentation/img/import-graph-models.png differ diff --git a/documentation/img/import-import-jobs.png b/documentation/img/import-import-jobs.png new file mode 100644 index 0000000..e9ee731 Binary files /dev/null and b/documentation/img/import-import-jobs.png differ diff --git a/documentation/img/import-iterate-graph-model.gif b/documentation/img/import-iterate-graph-model.gif new file mode 100644 index 0000000..3c4b412 Binary files /dev/null and b/documentation/img/import-iterate-graph-model.gif differ diff --git a/documentation/img/import-query-db-info-refresh.gif b/documentation/img/import-query-db-info-refresh.gif new file mode 100644 index 0000000..5b4c655 Binary files /dev/null and b/documentation/img/import-query-db-info-refresh.gif differ diff --git a/documentation/img/import-source-config-form.png b/documentation/img/import-source-config-form.png new file mode 100644 index 0000000..3e85b66 Binary files /dev/null and b/documentation/img/import-source-config-form.png differ diff --git a/documentation/img/import-source-table-schema.png b/documentation/img/import-source-table-schema.png new file mode 100644 index 0000000..c1c381e Binary files /dev/null and b/documentation/img/import-source-table-schema.png differ diff --git a/documentation/img/import-tables-mapped.png b/documentation/img/import-tables-mapped.png new file mode 100644 index 0000000..138f180 Binary files /dev/null and b/documentation/img/import-tables-mapped.png differ diff --git a/documentation/img/london2.png b/documentation/img/london2.png new file mode 100644 index 0000000..12d5b4d Binary files /dev/null and b/documentation/img/london2.png differ diff --git a/documentation/img/movie-model.png b/documentation/img/movie-model.png new file mode 100644 index 0000000..9128b15 Binary files /dev/null and b/documentation/img/movie-model.png differ diff --git a/documentation/img/pattern2.png b/documentation/img/pattern2.png new file mode 100644 index 0000000..c24997f Binary files /dev/null and b/documentation/img/pattern2.png differ diff --git a/documentation/img/preview_1.png b/documentation/img/preview.png similarity index 100% rename from documentation/img/preview_1.png rename to documentation/img/preview.png diff --git a/documentation/img/save-load.png b/documentation/img/save-load.png deleted file mode 100644 index 554b2f4..0000000 Binary files a/documentation/img/save-load.png and /dev/null differ diff --git a/documentation/img/save_load.png b/documentation/img/save_load.png new file mode 100644 index 0000000..99c85d8 Binary files /dev/null and b/documentation/img/save_load.png differ diff --git a/documentation/img/saved-cypher.gif b/documentation/img/saved-cypher.gif new file mode 100644 index 0000000..95fc65f Binary files /dev/null and b/documentation/img/saved-cypher.gif differ diff --git a/documentation/img/scalable-graph-visualization.gif b/documentation/img/scalable-graph-visualization.gif new file mode 100644 index 0000000..924eadc Binary files /dev/null and b/documentation/img/scalable-graph-visualization.gif differ diff --git a/documentation/img/table-visualization.gif b/documentation/img/table-visualization.gif new file mode 100644 index 0000000..312c289 Binary files /dev/null and b/documentation/img/table-visualization.gif differ diff --git a/documentation/import-from-rdbms.workspace.adoc b/documentation/import-from-rdbms.workspace.adoc new file mode 100644 index 0000000..0608f8e --- /dev/null +++ b/documentation/import-from-rdbms.workspace.adoc @@ -0,0 +1,149 @@ += Import from Relational Database +[role=NX_TAB_NAV,tab=import] + +== Introduction + +The import service now offers a way to import directly from data sources such as relational databases. +If your data is already in reasonable shape for use in a graph database, it is possible to connect directly to your source and configure an import job. + +This guide will take you through a three-stage process: + +. Configuring a data source +. Reviewing a generated graph model and mapping to the data source +. Running the import job + + +=== Connectivity requirements + +- Your database should be one of the supported types, including Postgres, MySQL, SQL Server, and Oracle. +- It should be accessible via a public IP address. +- You should have username/password authentication setup. Using a read-only user is recommended. + +=== Limitations + +The following are not yet supported: + +- Advanced configuration options such as custom certificates for data sources. +- Imports from data sources in a Virtual Private Cloud (VPC) into a Neo4j managed VPC. + + +Start by setting up a connection to a relational database and complete your first import. + + +== Configuring a data source + +[role=NX_TAB_NAV,tab=import] + +If you haven't already, navigate to the `Data Serices > Import` menu item to access the import service. + +Once in the Import service, the first step is to configure a new data source. +Two categories of data sources are available: + +- Direct connection -- you provide the import service with access to your data source, including connection URL, database name, and credentials. +- Proivision of CSV files -- you provide CSV files from your filesystem as the data source. +A separate guide, _Import from CSV_, is available to take you through this process. + +This guide focuses on connecting directly to a data source. +The "New data source" button on the Data Sources tab, presents you with a number of data source options. +In this guide, you will connect to PostgreSQL. + + +Complete the form with the required information for your data source. +If there are any problems connecting to your data source, you stay on the connection form and have the opportunity to tweak the details before continuing. + +image::import-source-config-form.png[] + +[TIP] +==== +Currently, error reporting is limited, so you should validate that all your details are correct by successfully connecting from your development machine. +Also, note that your database needs to be publicly accessible to connect to it from Neo4j Aura. +==== + +Once the connection is successful, you are prompted to review and confirm the table schema for the database you've selected to connect to. +Here you can see a summary of the tables and columns in your database to help validate that you're connected to the right data source. +If everything looks good, hit `Confirm`. +This adds your data source and saves it for future re-use. + +image::import-source-table-schema.png[] + +[TIP] +==== +While your connection details are retained, your password is not. +You need to re-provide the password for your data source when you use it again or trigger the import job. +==== + +Once you've added a data source, you can either start generating a candidate graph from it, or hit `Later` to come back and do this later. +If you come back later, use the [...] button on a row and the `New graph model from data source` option to start the graph generation flow. +The next step in this guide is generating a graph model. + + +== Generating a graph model + + +Use the `Generate graph model` button once you have added a data source. +Doing this inspects any constraints that exist in your database, looking for primary key constraints to create nodes with IDs and foreign keys to generate relationships between them. +If suitable constraints are found, a corresponding candidate graph is generated, and the tables and columns are mapped to it. +If your dataset doesn't have any such constraints (or only part of the schema does), you have to map your tables to nodes and relationships manually. +If you're not familiar with your data source, it may take some time to understand the different entities and connections present in your tables. + +If no constraints are found *at all* in your source database, everything is mapped to a node for your convenience. +This saves you from doing some manual mapping, but note that a graph with just nodes doesn't make for a connected graph! +From here, delete nodes that should be relationships and recreate relationships between the remaining nodes as appropriate for your data. + + +[TIP] +===== +The generation and mapping doesn't currently support composite primary or foregin keys, so you won't see mappings related to these, nor be able to import them easily via the import UI just yet. +===== + +=== Refining a model + +Even in this example where a well-connected graph model has been generated, the model can benefit from some tidy-up. +For example, tables mapped to nodes use the corresponding table name as the label, but this can be made more suitable for your graph. +The same applies to relationships that by default use a concatenation of related table names. +Relationship direction may also benefit from being reversed for the chosen semantics. +See the example below where the concepts of Person, Order, and Employee and their corresponding relationships are tidied up. + +image::import-iterate-graph-model.gif[] + +In the Data source panel on the left-hand side, blue icons denote that the column from a particular table has been mapped to the graph model. +Reviewing the list of tables to any that have not been mapped can be useful. + +image::import-tables-mapped.png[] + + +If the data is in the right shape, it can be mapped manually to the graph model. +You can learn more about how nodes and relationships are mapped in the _Import from CSV_ guide that covers the same concepts required here. +It explains node IDs and relationship mappings in more detail with CSV files instead of tables. + +When all parts of the graph model (nodes and relationships) are successfully mapped to tables, they are annotated with a green check mark. +If an import is attempted and anything is missing, it is highlighted in red to be fixed before proceeding with the import. + +== Running an import job + +Once you're happy with your graph model and how your tables are mapped to it, you can run the import job. +If you're already connected to an instance, this instance is used. +Otherwise, you are prompted to select an instance. + +When submitting the job, you are prompted for two sets of credentials: + +- The data source password (as used when setting up the data source) +- The destination neo4j instance password. These were provided when you created the instance and optionally made available to download in a `.txt` file of the format `Neo4j--Created-.txt` + +Once the job has been successfully submitted, you are redirected to the import jobs page, which tracks the current status of the import job. + +image::import-import-jobs.png[] + +[TIP] +==== +The high-level status of the import job is refreshed periodically but does not currently show progress. +If you want to see live updates of the nodes and relationships being imported into the graph, you can switch to the Query app, monitor the Database Information sidebar, and refresh it to see counts increment. + +image::import-query-db-info-refresh.gif[] + +==== + +If you want to return to a model, you can find it stored in the Graph models tab. +From here you can open a model and rerun an import or adapt the model as required before rerunning. + +image::import-graph-models.png[] \ No newline at end of file diff --git a/documentation/import-upx.adoc b/documentation/import-upx.adoc new file mode 100644 index 0000000..0a1f4b5 --- /dev/null +++ b/documentation/import-upx.adoc @@ -0,0 +1,434 @@ += Import data from CSV +// NOTE: Browser may cache files when loading from zip + +:northwind-subset-data-only-no-model-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-data-only-no-model.zip +:northwind-subset-data-only-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-data-only.zip +:northwind-subset-node-only-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-node-only-mapping.zip +:northwind-subset-shipper-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-shipper-mapping.zip +:people_locations_nodes_only_zip_file: https://neo4j-graph-examples.github.io/get-started/data/people_locations_nodes_only.zip +:people_locations_full_zip_file: https://neo4j-graph-examples.github.io/get-started/data/people_locations_full.zip +:northwind-subset-node-and-relationship-mapping-zip-file: https://neo4j-graph-examples.github.io/get-started/data/northwind-subset-node-and-relationship-mapping.zip + +== Introduction + +Data importer offers a powerful and simple way to model and load data into Neo4j. +It's great if you're new to graphs or have rapid prototyping needs. +If you have more advanced needs, checkout the _What's next?_ section at the end of this guide. + + +This guide focuses on loading data from CSV, if loading data from a relational database, refer to the guide _Import from Relational Database_. + +This guide will teach you how to: + +* Create a graph model +* Configure its properties and relationships +* Upload and map data files (we have prepared some for you) + +[TIP] +==== +If you haven't already, it's recommended to go through the _Learn the basics_ guide to learn the basics of Neo4j. +This guide is continuing with the same dataset, Northwind. +==== + + +== Working with data files + +=== Add the Northwind files + +To get started, navigate to the `Data Services > Import` menu item and choose the CSV option when adding a data source. Then {northwind-subset-data-only-no-model-zip-file}[download and unzip this file of CSVs^] and drop the files onto the highlight:import/import-file-panel[data source panel]. + +[%collapsible] +.Are you having trouble? +==== +You can also click the following button to add the CSV files automatically. + +button::Add Northwind files[role=NX_IMPORT_LOAD,endpoint={northwind-subset-data-only-zip-file}] +==== + +=== File structure + +Now that you've added the files, you should be able to see each file's header and the first row of data in the highlight:import/import-file-panel[data source panel]. + +[TIP] +==== +Importer always requires files to have a *header row* as well as at least one *data row* in order to map and import data. +==== + +The `order-details.csv` file looks like this: + +---- +OrderID,ProductID,UnitPrice,Quantity,Discount +10248,11,14.00,12,0 +10248,42,9.8,10,0 +10248,72,34.8,5,0 +---- + +This file tells you which orders contain specific products and their price. +If you inspect the content of the file, you'll notice that `OrderID` is repeated. +You'll learn later about how this can be used to create a `CONTAINS` relationship linking `Orders` and `Products`. + +The `products.csv` and `orders.csv` files refer to the other parts of the Northwind data model. + + +== Nodes and properties + +=== Create the Order node + +You are going to create a simple model with two nodes and one relationship. +Add a node using the highlight:import/import-add-node[add node button], and give it the label `Order`. + +image::simple-model.png[] + +=== Map a file + +The `Order` node you have just created isn't fully mapped yet; it needs to show a green check mark. +Select `orders.csv` from the highlight:import/import-node-file-dropdown[file dropdown] in the highlight:import/import-mapping-panel[mapping details panel]. + + +=== Defining and mapping properties + +Let's now add some properties to the `Order` node from our `orders.csv` file. + +* Click the highlight:import/import-select-from-file-button[Map from table] button. +* Select the `orderId`, `orderDate` and `requiredDate` columns and click *Confirm*. +* Edit the name `orderId` property in the mapping details panel by clicking the pencil icon and then rename it to `id` (it obviously relates to an order). +* Change its data type from `integer` to `string` using the drop-down. + + +[NOTE] +==== +When selected from file, properties are given the name of the column selected when created. +Importer guesses each datatype based on a sample of the values it found. +Always double-check this when working with unfamiliar data. +For example, Northwind's date/time columns are identified as strings, but you can edit that if you want to. +==== +// TODO: properties with same name... this needs rewording for clarity + +== Relationships and IDs + +=== Setting a node ID + +Nodes need an ID to define relationships with other nodes. +An ID also ensures an import doesn't create a node more than once if it's referenced multiple times in a data file. + +In the _Definition_ tab, you can see that the `id` property is set as the ID for the node highlight:import/import-node-id[ID]. +The import tool did this for you automatically based on the property name containing the `id` string. +In other cases, you may need to correct it or set it manually. + +// TO-DO: Add property highlight has been lost, requested the Importer team re-add it. This TO-DO can be deleted once confirmed working. +[TIP] +==== +You can also specify properites and their data types in isolation from mapping by using the highlight:import/import-property-add-button[add property] button. +You can then map a column from your data file to the property in the file mapping tab. +==== + +=== Create the Product node + +Now you just need to repeat the process you followed for `Order` and create a `Product` node from the `products.csv` file. +Here you need to map the `productId` and `productName` columns, rename the `productId` property to be simply `id` and set it to be a `string`. +Ensure `id` is selected as the ID. + +Once you have created both nodes and mapped files accordingly, you should see a green check mark on both nodes. +This indicates that the mapping is complete. + +[%collapsible] +.Are you having trouble? +==== +If you're unsure if you've followed the steps correctly so far, you can go ahead and load the correct mapping so everything is in order before continuing. + +button::Load Northwind node mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-node-only-mapping-zip-file}] +==== + +== Constraints and indexes + +To ensure accuracy of your data and support read performance, Data Importer automatically creates a uniqueness constraint and a corresponding index on the property you select as the node ID. +You can add further indexes in addition to the mandatory constraint and index. + +Constraints and indexes have their own tab in the highlight:import/import-mapping-panel[mapping details panel]. +Use the `+`-sign to add an index and then select which property to add the index on. + +Data Importer generates a name for the index and the index type created is Neo4j's default index. +If you make a mistake, select the erroneous index and click the trash-can to delete it. + +If you know that you are going to use a property regularly, it is good practice to add an index to it. +For example, if you are doing administrative work with Northwind, you may be interested in the order dates. +See if you can add an index to the `orderDate` property that will help you with that! + +[%collapsible] +.Hint +==== +From the highlight:import/import-mapping-panel[mapping details panel], tap the `+` and select the `orderDate` property. +==== + +[NOTE] +==== +Only the properties you mapped from the _Definition_ tab are available to create indexes on. +To modify the selection, you need to go back to the _Definition_ tab. +==== + +To learn more about indexes and constraints, see link:https://neo4j.com/docs/cypher-manual/current/indexes/[Cypher Manual -> Indexes] and link:https://neo4j.com/docs/cypher-manual/current/constraints/[Cypher Manual -> Constraints] repsectively. + +== Create relationships + +[TIP] +==== +As you've seen already, your data concerns `Orders` that `CONTAIN` specific `Products`. +Conventionally, https://en.wikipedia.org/wiki/Camel_case[CamelCase^] is used for node labels and capitalized https://en.wikipedia.org/wiki/Snake_case[SNAKE_CASE^] for relationship types. +==== + +You have two nodes and now you need to create a relationship to connect them. + +* Hover by the edge of the `Order` node circle and you'll see a `+` sign. +* Click and hold it and you'll see another circle. +* Drag the new circle on to the `Product` node and relase to create the relationship. +* With the relationship arrow selected, you can now specify how `Order` relates to `Product`. +* In the highlight:import/import-relationship-type[type] section of the highlight:import/import-mapping-panel[mapping details panel], enter the text `CONTAINS`. + +[TIP] +==== +Just like newly created nodes, the relationship will only show a green check mark once you have completed its mapping. +You can also name relationships by double-clicking the arrow in the graph model and typing it directly. +You can rapidly add nodes with a linking relationship by releasing the circle on an empty space the canvas instead of an existing node. +Selected nodes can be deleted by clicking the highlight:import/import-delete-node-or-rel[delete button] or with the backspace key. +You can quickly change the direction of a relationship with _Switch direction_ next to the relationship type. +==== + +== Map a file to a relationship + +The next stage is critical in helping the importer understand how a file defines a relationship. +This is what will give you a connected graph. + +* If you look in the highlight:import/import-file-panel[data source panel], you'll see `order-details.csv` has columns that correspond with the `id` of our `Order` and `Product` nodes. +* Ensuring you have the relationship selected, select the `order-details.csv` file from the highlight:import/import-relationship-file-dropdown[File dropdown]. +// TODO: Add id selector for relationship dropdown to enable UI higlighting +* In the highlight:import/import-relationship-mapping-table[relationship mapping table] you will see the nodes and ID properties at each end of the `CONTAINS` relationship. + +Setup the *From* and *To* for the `CONTAINS` relationship: + +* The `From` end of the node is the `Order` node with the `id` property (remember that this property was mapped to the `orderId` column in the `orders.csv` file). +* Your `order-details.csv` file also contains an `orderId` column, so select this in the highlight:import/import-rel-from-dropdown[from dropdown]. +This gives Data Importer the information it requires to link up the From end of the relationship. +* You need to select the correct file column for the `To` end of the relationship (the Product node). +As you might guess, this is the `productId` in the highlight:import/import-rel-to-dropdown[to dropdown] + +Everything in the highlight:import/import-model-panel[Data model pane] should now have green check marks as you have successfully mapped the file. + +=== More properties for richer queries + +For relationships, you can add properties that may be useful for your queries. + +In the `order-details.csv` file, you'll notice the columns `unitPrice`, `quantity` and `discount` could be useful to add as properties to the `CONTAINS` relationship. +These properties are well suited to being on the relationship since they couldn't easily be encapsulated on the nodes at either end of the relationship. +For example `quantity` does not belong on either the `Product` or `Order` nodes since products will be sold in different quantities on different orders. + +Just as you did for nodes, use the highlight:import/import-select-from-file-button[Map from table] button to map those columns to new properties on the relationship. + +[TIP] +==== +You don't need to include the `orderID` or the `productID` here, as their only purpose is to create the `CONTAINS` relationship in our model and we've already used them to do that. +==== + +[%collapsible] +.Are you having trouble? +==== +If you're unsure if you've followed the steps correctly so far, you can go ahead and load the correct mapping so everything is in order before continuing. + +button::Load model and mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-node-and-relationship-mapping-zip-file}] +==== + +== Dealing with different file structures + +=== Relationship defined in the same file as one node + +In this example, a separate flat file, `order-details.csv`, defines the relationship linking `Orders` and `Products`. + +However, it is quite common to have files where the relationship is defined by the same file as that used for the node at one (or sometimes both) ends of the relationship. +In this example, you can see how the `orders.csv` file also contains a `shipVia` column which could be used to define the relationship to a `Shipper` node created from the `shippers.csv` file. + +To see how this mapping looks, here's an example for you to inspect the configuration. + +button::Load Northwind shipper mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-shipper-mapping-zip-file}] + +Here you can see that the `orders.csv` file is used to define both the `Order` node and the `SHIPS` relationship, as well as mapping the `Shipper` node to `shippers.csv`. + +=== Relationship defined in the same file as both nodes + +In examples where the nodes at each end of the relationship are both mapped to the same file, the relationship can ususally be inferred by the same file. +If you first set up the nodes with their IDs and mapping, when then you draw the relationship, the `From` and `To` parts of the relationship will be mapped automatically. + +You can try this out by loading the simple example below and connecting the two nodes that are mapped to the same file: + +button::Load people and locations[role=NX_IMPORT_LOAD,endpoint={people_locations_nodes_only_zip_file}] + +The model you are aiming for is as below. + +image::import-people and locations.png[] + +If you add the relationships and label their types as above, you'll observe that the `From` and `To` relationships are automatically mapped for you. + +// TO-DO: Is not so neat in this example switching to a completely different context - would be better to add a Northwind related example of ths - look at doing this as it's a good example to show. + +[%collapsible] +.Are you having trouble? +==== +You can also click the button to load the people and locations with their relationship mapping. + +button::Load configuration[role=NX_IMPORT_LOAD,endpoint={people_locations_full_zip_file}] +==== + +== Ready to import? + +Let's get back to the Nortwind model, start by reloading the small Northwind model you created. + +button::Load model and mapping[role=NX_IMPORT_LOAD,endpoint={northwind-subset-node-and-relationship-mapping-zip-file}] + +Any object in your model without a green check mark means that the mapping is not complete. +If the mapping is not complete, you will not be able to run the import. + +The following items **must be** mapped on a **node**: + +* Label +* File +* A minimum of one property +* ID + +The following items **must be** mapped on a **relationship**: + +* Type +* File +* ID file columns (for both _From_ and _To_ nodes) + +== Preview your graph + +When you're satisfied with your model and mapping, you can preview a sample of your data before running the actual import. + +Click the highlight:import/import-load-preview-button[Preview button] to see a sample of your data visualized. + +image::preview.png[] + +Even though the preview only scans the first few rows of your files, it is often sufficient to make sure everything connects as expected. +You can click individual elements in the preview to verify that their properties appear as expected. +But you should keep in mind that it is only a preview and only a sample of your data. +The actual graph may look different once the full import is complete. + +You want to have your mapping completely done before previewing, but if you have missed something, you are still able to do a preview, but the incomplete elements will not be rendered. +In other words, any element without a check mark in your model will not show up in the preview. + +As mentioned before, if any element in your model is not mapped, you will **not** be able to run the import. + +== Running an import + +Click highlight:import/import-run-import-button[Run import] to import the files specified in your model. + +If any uploaded files are not specified in your model, these are **not** imported, but they remain in the highlight:import/import-file-panel[data source panel]. + +If any mapping is incomplete, you will be informed that your model has errors and a red exclamation mark is shown next to the incomplete element in the model. +When you select an incomplete element, the mapping pane also highlights the missing details. + +Once you've addressed any errors, go ahead and run the import again. +You should see a popup window showing the successful results. + +image::import_results.png[] + +The summary shows what was included in the import. +You can compare to your CSV files to verify that everything was imported. + +Congratulations on modelling, mapping, and loading your data! +You can now explore and query it to learn more about the power of graphs and Neo4j. +We have a few very useful importer tips to complete this guide. + +[TIP] +==== +Note that if you run this guide after the _Getting Started_ guide, the count may show _updated_ rather than _created_ since Data Importer will ensure duplicate IDs are not created for elements already loaded. +==== + +== Final tips + +=== Saving and loading models + +As you work with data models, may want to come back to it or share it at some point. +The importer lets you _download_ your model, with or without the data you've mapped to it. + +Ensure you are in the import tab. + +button::Import[role=NX_TAB_NAV,tab=import] + +image::save_load.png[] + +When you choose to download your model, with or without data, you are essentially saving it. +The model doesn't have to be mapped for you to download. + +If you have a downloaded model, you can open it from this same menu, again with or without data. + +The data is stored as CSV-files and the model as a JSON file, which makes it easy to share. + +=== Re-running imports and updating your model + +You can run the import multiple times without duplicating your data. +For example, if you want to make some changes to your model after you've run the import, just fix your model and when you are happy run the import again. +The changes you made will overwrite what you had before, but no existing elements will be recreated, unless you change their IDs. + +=== When you outgrow the Data Importer + +Importer may not meet _all_ of your varied load needs, whether they are transformations or differing data formats. +If you need more control, the chances are you can achieve the load using some of the other approaches to loading data into Neo4j. +The following are useful resources for different needs: + +- https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/[LOAD CSV] for writing your own bespoke Cypher load scripts from CSVs, leveraging the full capabilities of Cypher. +- https://neo4j.com/docs/operations-manual/current/tutorial/neo4j-admin-import/[Neo4j-admin import] for loading large amounts of CSV data rapidly into an offline database +- https://neo4j.com/product/connectors/[Neo4j connectors] to connect data from a variety of sources into Neo4j. +- https://neo4j.com/docs/apoc/current/overview/apoc.load/[APOC Load procedures] for special Cypher procedures to make it easier to ingest data from formats including json, xml and arrow. + +== Frequently Asked Questions + +*Missing files - why does Data Importer say I need to provide my files after I've aready provided them?* + +When you provide the importer with your files, you are actually providing your web browser with a link to those files on your local file system, they aren't uploaded anywhere. +The importer streams the content of the files to you database only when you run the import. +If you reload the page, the importer loses access to the connection to those files due to security restrictions. +These are in place to prevent web applications accessing files you haven't given express permission to use on page load. +You simply need to re-provide the files when requested by data importer to be able to run an import. + +*How can I replace a file?* + +The importer doesn't currently allow you to swap out files in the UI. +However, there is a workaround that may prove useful. +If you want to provide a different file with the same column structure to data importer, you can rename it to match and then simply add the file to the files panel. +This will replace the reference to the latest file and be available for use by your import. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/movies-upx.adoc b/documentation/movies-upx.adoc new file mode 100644 index 0000000..ab60d17 --- /dev/null +++ b/documentation/movies-upx.adoc @@ -0,0 +1,904 @@ += Movies graph +:imagesdir: https://neo4j-graph-examples.github.io/get-started/documentation/img/ + +== Movies graph + +This guide uses pop-cultural connections to teach you how to use Cypher to create and query data. +You will use the Query tool to explore connections between actors, directors, and movies, and also solve the famous Bacon-path. + +Note that this guide assumes that you use an empty database as you will modify it along the way. +You will learn how to delete the data you create towards the end of the guide as well. + +=== What you will learn + +This guide takes around 10 minutes and by the end of it you will be able to: + +- Create nodes and relationships that connect them. +- Find individual nodes by using conditional matches. +- Find patterns in the graph. +- Understand and use the shortest path algorithm. +- Write a basic recommendation query. +- Delete all data. + +Let's get started! + +In the next step you are going to create the data you'll be working with. + +== Create the data + +The Cypher `CREATE` clause is used to create data in your graph. +If you are not familiar with Cypher syntax, you can try the _Query fundamentals_ guide or see the link:https://neo4j.com/docs/cypher-manual/current[Cypher Manual]. + +You are going to create a dataset with `Person` and `Movie` nodes and different types of relationships to connect them. + +image::movie-model.png[] + +[source,cypher] +---- +CREATE CONSTRAINT movie_title IF NOT EXISTS FOR (m:Movie) REQUIRE m.title IS UNIQUE; +CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE; + +MERGE (TheMatrix:Movie {title:'The Matrix'}) ON CREATE SET TheMatrix.released=1999, TheMatrix.tagline='Welcome to the Real World' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix) +MERGE (LillyW)-[:DIRECTED]->(TheMatrix) +MERGE (LanaW)-[:DIRECTED]->(TheMatrix) +MERGE (JoelS)-[:PRODUCED]->(TheMatrix) + +MERGE (Emil:Person {name:'Emil Eifrem'}) ON CREATE SET Emil.born=1978 +MERGE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix); + + +MERGE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded'}) ON CREATE SET TheMatrixReloaded.released=2003, TheMatrixReloaded.tagline='Free your mind' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded) +MERGE (LillyW)-[:DIRECTED]->(TheMatrixReloaded) +MERGE (LanaW)-[:DIRECTED]->(TheMatrixReloaded) +MERGE (JoelS)-[:PRODUCED]->(TheMatrixReloaded); + + +MERGE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions'}) ON CREATE SET TheMatrixRevolutions.released=2003, TheMatrixRevolutions.tagline='Everything that has a beginning has an end' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions) +MERGE (LillyW)-[:DIRECTED]->(TheMatrixRevolutions) +MERGE (LanaW)-[:DIRECTED]->(TheMatrixRevolutions) +MERGE (JoelS)-[:PRODUCED]->(TheMatrixRevolutions); + + +MERGE (TheDevilsAdvocate:Movie {title:"The Devil's Advocate", released:1997, tagline:'Evil has its winning ways'}) + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Charlize:Person {name:'Charlize Theron'}) ON CREATE SET Charlize.born=1975 +MERGE (Al:Person {name:'Al Pacino'}) ON CREATE SET Al.born=1940 +MERGE (Taylor:Person {name:'Taylor Hackford'}) ON CREATE SET Taylor.born=1944 + +MERGE (Keanu)-[:ACTED_IN {roles:['Kevin Lomax']}]->(TheDevilsAdvocate) +MERGE (Charlize)-[:ACTED_IN {roles:['Mary Ann Lomax']}]->(TheDevilsAdvocate) +MERGE (Al)-[:ACTED_IN {roles:['John Milton']}]->(TheDevilsAdvocate) +MERGE (Taylor)-[:DIRECTED]->(TheDevilsAdvocate); + + +MERGE (AFewGoodMen:Movie {title:'A Few Good Men'}) ON CREATE SET AFewGoodMen.released=1992, AFewGoodMen.tagline='In the heart of the nation\'s capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DemiM:Person {name:'Demi Moore'}) ON CREATE SET DemiM.born=1962 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (KieferS:Person {name:'Kiefer Sutherland'}) ON CREATE SET KieferS.born=1966 +MERGE (NoahW:Person {name:'Noah Wyle'}) ON CREATE SET NoahW.born=1971 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 +MERGE (KevinP:Person {name:'Kevin Pollak'}) ON CREATE SET KevinP.born=1957 +MERGE (JTW:Person {name:'J.T. Walsh'}) ON CREATE SET JTW.born=1943 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (ChristopherG:Person {name:'Christopher Guest'}) ON CREATE SET ChristopherG.born=1948 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 +MERGE (AaronS:Person {name:'Aaron Sorkin'}) ON CREATE SET AaronS.born=1961 + +MERGE (TomC)-[:ACTED_IN {roles:['Lt. Daniel Kaffee']}]->(AFewGoodMen) +MERGE (JackN)-[:ACTED_IN {roles:['Col. Nathan R. Jessup']}]->(AFewGoodMen) +MERGE (DemiM)-[:ACTED_IN {roles:['Lt. Cdr. JoAnne Galloway']}]->(AFewGoodMen) +MERGE (KevinB)-[:ACTED_IN {roles:['Capt. Jack Ross']}]->(AFewGoodMen) +MERGE (KieferS)-[:ACTED_IN {roles:['Lt. Jonathan Kendrick']}]->(AFewGoodMen) +MERGE (NoahW)-[:ACTED_IN {roles:['Cpl. Jeffrey Barnes']}]->(AFewGoodMen) +MERGE (CubaG)-[:ACTED_IN {roles:['Cpl. Carl Hammaker']}]->(AFewGoodMen) +MERGE (KevinP)-[:ACTED_IN {roles:['Lt. Sam Weinberg']}]->(AFewGoodMen) +MERGE (JTW)-[:ACTED_IN {roles:['Lt. Col. Matthew Andrew Markinson']}]->(AFewGoodMen) +MERGE (JamesM)-[:ACTED_IN {roles:['Pfc. Louden Downey']}]->(AFewGoodMen) +MERGE (ChristopherG)-[:ACTED_IN {roles:['Dr. Stone']}]->(AFewGoodMen) +MERGE (AaronS)-[:ACTED_IN {roles:['Man in Bar']}]->(AFewGoodMen) +MERGE (RobR)-[:DIRECTED]->(AFewGoodMen) +MERGE (AaronS)-[:WROTE]->(AFewGoodMen); + + +MERGE (TopGun:Movie {title:'Top Gun'}) ON CREATE SET TopGun.released=1986, TopGun.tagline='I feel the need, the need for speed.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (KellyM:Person {name:'Kelly McGillis'}) ON CREATE SET KellyM.born=1957 +MERGE (ValK:Person {name:'Val Kilmer'}) ON CREATE SET ValK.born=1959 +MERGE (AnthonyE:Person {name:'Anthony Edwards'}) ON CREATE SET AnthonyE.born=1962 +MERGE (TomS:Person {name:'Tom Skerritt'}) ON CREATE SET TomS.born=1933 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (TonyS:Person {name:'Tony Scott'}) ON CREATE SET TonyS.born=1944 +MERGE (JimC:Person {name:'Jim Cash'}) ON CREATE SET JimC.born=1941 + +MERGE (TomC)-[:ACTED_IN {roles:['Maverick']}]->(TopGun) +MERGE (KellyM)-[:ACTED_IN {roles:['Charlie']}]->(TopGun) +MERGE (ValK)-[:ACTED_IN {roles:['Iceman']}]->(TopGun) +MERGE (AnthonyE)-[:ACTED_IN {roles:['Goose']}]->(TopGun) +MERGE (TomS)-[:ACTED_IN {roles:['Viper']}]->(TopGun) +MERGE (MegR)-[:ACTED_IN {roles:['Carole']}]->(TopGun) +MERGE (TonyS)-[:DIRECTED]->(TopGun) +MERGE (JimC)-[:WROTE]->(TopGun); + + +MERGE (JerryMaguire:Movie {title:'Jerry Maguire'}) ON CREATE SET JerryMaguire.released=2000, JerryMaguire.tagline='The rest of his life begins now.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 +MERGE (ReneeZ:Person {name:'Renee Zellweger'}) ON CREATE SET ReneeZ.born=1969 +MERGE (KellyP:Person {name:'Kelly Preston'}) ON CREATE SET KellyP.born=1962 +MERGE (JerryO:Person {name:'Jerry O\'Connell'}) ON CREATE SET JerryO.born=1974 +MERGE (JayM:Person {name:'Jay Mohr'}) ON CREATE SET JayM.born=1970 +MERGE (BonnieH:Person {name:'Bonnie Hunt'}) ON CREATE SET BonnieH.born=1961 +MERGE (ReginaK:Person {name:'Regina King'}) ON CREATE SET ReginaK.born=1971 +MERGE (JonathanL:Person {name:'Jonathan Lipnicki'}) ON CREATE SET JonathanL.born=1996 +MERGE (CameronC:Person {name:'Cameron Crowe'}) ON CREATE SET CameronC.born=1957 + +MERGE (TomC)-[:ACTED_IN {roles:['Jerry Maguire']}]->(JerryMaguire) +MERGE (CubaG)-[:ACTED_IN {roles:['Rod Tidwell']}]->(JerryMaguire) +MERGE (ReneeZ)-[:ACTED_IN {roles:['Dorothy Boyd']}]->(JerryMaguire) +MERGE (KellyP)-[:ACTED_IN {roles:['Avery Bishop']}]->(JerryMaguire) +MERGE (JerryO)-[:ACTED_IN {roles:['Frank Cushman']}]->(JerryMaguire) +MERGE (JayM)-[:ACTED_IN {roles:['Bob Sugar']}]->(JerryMaguire) +MERGE (BonnieH)-[:ACTED_IN {roles:['Laurel Boyd']}]->(JerryMaguire) +MERGE (ReginaK)-[:ACTED_IN {roles:['Marcee Tidwell']}]->(JerryMaguire) +MERGE (JonathanL)-[:ACTED_IN {roles:['Ray Boyd']}]->(JerryMaguire) +MERGE (CameronC)-[:DIRECTED]->(JerryMaguire) +MERGE (CameronC)-[:PRODUCED]->(JerryMaguire) +MERGE (CameronC)-[:WROTE]->(JerryMaguire); + +MERGE (StandByMe:Movie {title:'Stand By Me'}) ON CREATE SET StandByMe.released=1986, StandByMe.tagline='For some, it\'s the last real taste of innocence, and the first real taste of life. But for everyone, it\'s the time that memories are made of.' + +MERGE (RiverP:Person {name:'River Phoenix'}) ON CREATE SET RiverP.born=1970 +MERGE (CoreyF:Person {name:'Corey Feldman'}) ON CREATE SET CoreyF.born=1971 +MERGE (JerryO:Person {name:'Jerry O\'Connell'}) ON CREATE SET JerryO.born=1974 +MERGE (WilW:Person {name:'Wil Wheaton'}) ON CREATE SET WilW.born=1972 +MERGE (KieferS:Person {name:'Kiefer Sutherland'}) ON CREATE SET KieferS.born=1966 +MERGE (JohnC:Person {name:'John Cusack'}) ON CREATE SET JohnC.born=1966 +MERGE (MarshallB:Person {name:'Marshall Bell'}) ON CREATE SET MarshallB.born=1942 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 + +MERGE (WilW)-[:ACTED_IN {roles:['Gordie Lachance']}]->(StandByMe) +MERGE (RiverP)-[:ACTED_IN {roles:['Chris Chambers']}]->(StandByMe) +MERGE (JerryO)-[:ACTED_IN {roles:['Vern Tessio']}]->(StandByMe) +MERGE (CoreyF)-[:ACTED_IN {roles:['Teddy Duchamp']}]->(StandByMe) +MERGE (JohnC)-[:ACTED_IN {roles:['Denny Lachance']}]->(StandByMe) +MERGE (KieferS)-[:ACTED_IN {roles:['Ace Merrill']}]->(StandByMe) +MERGE (MarshallB)-[:ACTED_IN {roles:['Mr. Lachance']}]->(StandByMe) +MERGE (RobR)-[:DIRECTED]->(StandByMe); + +MERGE (AsGoodAsItGets:Movie {title:'As Good as It Gets'}) ON CREATE SET AsGoodAsItGets.released=1997, AsGoodAsItGets.tagline='A comedy from the heart that goes for the throat.' + +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (GregK:Person {name:'Greg Kinnear'}) ON CREATE SET GregK.born=1963 +MERGE (JamesB:Person {name:'James L. Brooks'}) ON CREATE SET JamesB.born=1940 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 + +MERGE (JackN)-[:ACTED_IN {roles:['Melvin Udall']}]->(AsGoodAsItGets) +MERGE (HelenH)-[:ACTED_IN {roles:['Carol Connelly']}]->(AsGoodAsItGets) +MERGE (GregK)-[:ACTED_IN {roles:['Simon Bishop']}]->(AsGoodAsItGets) +MERGE (CubaG)-[:ACTED_IN {roles:['Frank Sachs']}]->(AsGoodAsItGets) +MERGE (JamesB)-[:DIRECTED]->(AsGoodAsItGets); + +MERGE (WhatDreamsMayCome:Movie {title:'What Dreams May Come'}) ON CREATE SET WhatDreamsMayCome.released=1998, WhatDreamsMayCome.tagline='After life there is more. The end is just the beginning.' + +MERGE (AnnabellaS:Person {name:'Annabella Sciorra'}) ON CREATE SET AnnabellaS.born=1960 +MERGE (MaxS:Person {name:'Max von Sydow'}) ON CREATE SET MaxS.born=1929 +MERGE (WernerH:Person {name:'Werner Herzog'}) ON CREATE SET WernerH.born=1942 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (VincentW:Person {name:'Vincent Ward'}) ON CREATE SET VincentW.born=1956 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 + +MERGE (Robin)-[:ACTED_IN {roles:['Chris Nielsen']}]->(WhatDreamsMayCome) +MERGE (CubaG)-[:ACTED_IN {roles:['Albert Lewis']}]->(WhatDreamsMayCome) +MERGE (AnnabellaS)-[:ACTED_IN {roles:['Annie Collins-Nielsen']}]->(WhatDreamsMayCome) +MERGE (MaxS)-[:ACTED_IN {roles:['The Tracker']}]->(WhatDreamsMayCome) +MERGE (WernerH)-[:ACTED_IN {roles:['The Face']}]->(WhatDreamsMayCome) +MERGE (VincentW)-[:DIRECTED]->(WhatDreamsMayCome); + +MERGE (SnowFallingonCedars:Movie {title:'Snow Falling on Cedars'}) ON CREATE SET SnowFallingonCedars.released=1999, SnowFallingonCedars.tagline='First loves last. Forever.' + +MERGE (EthanH:Person {name:'Ethan Hawke'}) ON CREATE SET EthanH.born=1970 +MERGE (RickY:Person {name:'Rick Yune'}) ON CREATE SET RickY.born=1971 +MERGE (JamesC:Person {name:'James Cromwell'}) ON CREATE SET JamesC.born=1940 +MERGE (ScottH:Person {name:'Scott Hicks'}) ON CREATE SET ScottH.born=1953 +MERGE (MaxS:Person {name:'Max von Sydow'}) ON CREATE SET MaxS.born=1929 + +MERGE (EthanH)-[:ACTED_IN {roles:['Ishmael Chambers']}]->(SnowFallingonCedars) +MERGE (RickY)-[:ACTED_IN {roles:['Kazuo Miyamoto']}]->(SnowFallingonCedars) +MERGE (MaxS)-[:ACTED_IN {roles:['Nels Gudmundsson']}]->(SnowFallingonCedars) +MERGE (JamesC)-[:ACTED_IN {roles:['Judge Fielding']}]->(SnowFallingonCedars) +MERGE (ScottH)-[:DIRECTED]->(SnowFallingonCedars); + +MERGE (YouveGotMail:Movie {title:'You\'ve Got Mail'}) ON CREATE SET YouveGotMail.released=1998, YouveGotMail.tagline='At odds in life... in love on-line.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (GregK:Person {name:'Greg Kinnear'}) ON CREATE SET GregK.born=1963 +MERGE (ParkerP:Person {name:'Parker Posey'}) ON CREATE SET ParkerP.born=1968 +MERGE (DaveC:Person {name:'Dave Chappelle'}) ON CREATE SET DaveC.born=1973 +MERGE (SteveZ:Person {name:'Steve Zahn'}) ON CREATE SET SteveZ.born=1967 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail) +MERGE (MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail) +MERGE (GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail) +MERGE (ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail) +MERGE (DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail) +MERGE (SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail) +MERGE (NoraE)-[:DIRECTED]->(YouveGotMail); + +MERGE (SleeplessInSeattle:Movie {title:'Sleepless in Seattle'}) ON CREATE SET SleeplessInSeattle.released=1993, SleeplessInSeattle.tagline='What if someone you never met, someone you never saw, someone you never knew was the only someone for you?' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (RitaW:Person {name:'Rita Wilson'}) ON CREATE SET RitaW.born=1956 +MERGE (BillPull:Person {name:'Bill Pullman'}) ON CREATE SET BillPull.born=1953 +MERGE (VictorG:Person {name:'Victor Garber'}) ON CREATE SET VictorG.born=1949 +MERGE (RosieO:Person {name:'Rosie O\'Donnell'}) ON CREATE SET RosieO.born=1962 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (TomH)-[:ACTED_IN {roles:['Sam Baldwin']}]->(SleeplessInSeattle) +MERGE (MegR)-[:ACTED_IN {roles:['Annie Reed']}]->(SleeplessInSeattle) +MERGE (RitaW)-[:ACTED_IN {roles:['Suzy']}]->(SleeplessInSeattle) +MERGE (BillPull)-[:ACTED_IN {roles:['Walter']}]->(SleeplessInSeattle) +MERGE (VictorG)-[:ACTED_IN {roles:['Greg']}]->(SleeplessInSeattle) +MERGE (RosieO)-[:ACTED_IN {roles:['Becky']}]->(SleeplessInSeattle) +MERGE (NoraE)-[:DIRECTED]->(SleeplessInSeattle); + +MERGE (JoeVersustheVolcano:Movie {title:'Joe Versus the Volcano'}) ON CREATE SET JoeVersustheVolcano.released=1990, JoeVersustheVolcano.tagline='A story of love, lava and burning desire.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (JohnS:Person {name:'John Patrick Stanley'}) ON CREATE SET JohnS.born=1950 +MERGE (Nathan:Person {name:'Nathan Lane'}) ON CREATE SET Nathan.born=1956 + +MERGE (TomH)-[:ACTED_IN {roles:['Joe Banks']}]->(JoeVersustheVolcano) +MERGE (MegR)-[:ACTED_IN {roles:['DeDe', 'Angelica Graynamore', 'Patricia Graynamore']}]->(JoeVersustheVolcano) +MERGE (Nathan)-[:ACTED_IN {roles:['Baw']}]->(JoeVersustheVolcano) +MERGE (JohnS)-[:DIRECTED]->(JoeVersustheVolcano); + +MERGE (WhenHarryMetSally:Movie {title:'When Harry Met Sally'}) ON CREATE SET WhenHarryMetSally.released=1998, WhenHarryMetSally.tagline='Can two friends sleep together and still love each other in the morning?' + +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (BillyC:Person {name:'Billy Crystal'}) ON CREATE SET BillyC.born=1948 +MERGE (CarrieF:Person {name:'Carrie Fisher'}) ON CREATE SET CarrieF.born=1956 +MERGE (BrunoK:Person {name:'Bruno Kirby'}) ON CREATE SET BrunoK.born=1949 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (BillyC)-[:ACTED_IN {roles:['Harry Burns']}]->(WhenHarryMetSally) +MERGE (MegR)-[:ACTED_IN {roles:['Sally Albright']}]->(WhenHarryMetSally) +MERGE (CarrieF)-[:ACTED_IN {roles:['Marie']}]->(WhenHarryMetSally) +MERGE (BrunoK)-[:ACTED_IN {roles:['Jess']}]->(WhenHarryMetSally) +MERGE (RobR)-[:DIRECTED]->(WhenHarryMetSally) +MERGE (RobR)-[:PRODUCED]->(WhenHarryMetSally) +MERGE (NoraE)-[:PRODUCED]->(WhenHarryMetSally) +MERGE (NoraE)-[:WROTE]->(WhenHarryMetSally); + +MERGE (ThatThingYouDo:Movie {title:'That Thing You Do'}) ON CREATE SET ThatThingYouDo.released=1996, ThatThingYouDo.tagline='In every life there comes a time when that thing you dream becomes that thing you do' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (LivT:Person {name:'Liv Tyler'}) ON CREATE SET LivT.born=1977 +MERGE (Charlize:Person {name:'Charlize Theron'}) ON CREATE SET Charlize.born=1975 + +MERGE (TomH)-[:ACTED_IN {roles:['Mr. White']}]->(ThatThingYouDo) +MERGE (LivT)-[:ACTED_IN {roles:['Faye Dolan']}]->(ThatThingYouDo) +MERGE (Charlize)-[:ACTED_IN {roles:['Tina']}]->(ThatThingYouDo) +MERGE (TomH)-[:DIRECTED]->(ThatThingYouDo); + +MERGE (TheReplacements:Movie {title:'The Replacements'}) ON CREATE SET TheReplacements.released=2000, TheReplacements.tagline='Pain heals, Chicks dig scars... Glory lasts forever' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Brooke:Person {name:'Brooke Langton'}) ON CREATE SET Brooke.born=1970 +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 +MERGE (Orlando:Person {name:'Orlando Jones'}) ON CREATE SET Orlando.born=1968 +MERGE (Howard:Person {name:'Howard Deutch'}) ON CREATE SET Howard.born=1950 + +MERGE (Keanu)-[:ACTED_IN {roles:['Shane Falco']}]->(TheReplacements) +MERGE (Brooke)-[:ACTED_IN {roles:['Annabelle Farrell']}]->(TheReplacements) +MERGE (Gene)-[:ACTED_IN {roles:['Jimmy McGinty']}]->(TheReplacements) +MERGE (Orlando)-[:ACTED_IN {roles:['Clifford Franklin']}]->(TheReplacements) +MERGE (Howard)-[:DIRECTED]->(TheReplacements); + +MERGE (RescueDawn:Movie {title:'RescueDawn'}) ON CREATE SET RescueDawn.released=2006, RescueDawn.tagline='Based on the extraordinary true story of one man\'s fight for freedom' + +MERGE (ChristianB:Person {name:'Christian Bale'}) ON CREATE SET ChristianB.born=1974 +MERGE (ZachG:Person {name:'Zach Grenier'}) ON CREATE SET ZachG.born=1954 +MERGE (MarshallB:Person {name:'Marshall Bell'}) ON CREATE SET MarshallB.born=1942 +MERGE (SteveZ:Person {name:'Steve Zahn'}) ON CREATE SET SteveZ.born=1967 +MERGE (WernerH:Person {name:'Werner Herzog'}) ON CREATE SET WernerH.born=1942 + +MERGE (MarshallB)-[:ACTED_IN {roles:['Admiral']}]->(RescueDawn) +MERGE (ChristianB)-[:ACTED_IN {roles:['Dieter Dengler']}]->(RescueDawn) +MERGE (ZachG)-[:ACTED_IN {roles:['Squad Leader']}]->(RescueDawn) +MERGE (SteveZ)-[:ACTED_IN {roles:['Duane']}]->(RescueDawn) +MERGE (WernerH)-[:DIRECTED]->(RescueDawn); + +MERGE (TheBirdcage:Movie {title:'The Birdcage'}) ON CREATE SET TheBirdcage.released=1996, TheBirdcage.tagline='Come as you are' + +MERGE (MikeN:Person {name:'Mike Nichols'}) ON CREATE SET MikeN.born=1931 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (Nathan:Person {name:'Nathan Lane'}) ON CREATE SET Nathan.born=1956 +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 + +MERGE (Robin)-[:ACTED_IN {roles:['Armand Goldman']}]->(TheBirdcage) +MERGE (Nathan)-[:ACTED_IN {roles:['Albert Goldman']}]->(TheBirdcage) +MERGE (Gene)-[:ACTED_IN {roles:['Sen. Kevin Keeley']}]->(TheBirdcage) +MERGE (MikeN)-[:DIRECTED]->(TheBirdcage); + +MERGE (Unforgiven:Movie {title:'Unforgiven'}) ON CREATE SET Unforgiven.released=1992, Unforgiven.tagline='It\'s a hell of a thing, killing a man' + +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 +MERGE (RichardH:Person {name:'Richard Harris'}) ON CREATE SET RichardH.born=1930 +MERGE (ClintE:Person {name:'Clint Eastwood'}) ON CREATE SET ClintE.born=1930 + +MERGE (RichardH)-[:ACTED_IN {roles:['English Bob']}]->(Unforgiven) +MERGE (ClintE)-[:ACTED_IN {roles:['Bill Munny']}]->(Unforgiven) +MERGE (Gene)-[:ACTED_IN {roles:['Little Bill Daggett']}]->(Unforgiven) +MERGE (ClintE)-[:DIRECTED]->(Unforgiven); + +MERGE (JohnnyMnemonic:Movie {title:'Johnny Mnemonic'}) ON CREATE SET JohnnyMnemonic.released=1995, JohnnyMnemonic.tagline='The hottest data on earth. In the coolest head in town' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Takeshi:Person {name:'Takeshi Kitano'}) ON CREATE SET Takeshi.born=1947 +MERGE (Dina:Person {name:'Dina Meyer'}) ON CREATE SET Dina.born=1968 +MERGE (IceT:Person {name:'Ice-T'}) ON CREATE SET IceT.born=1958 +MERGE (RobertL:Person {name:'Robert Longo'}) ON CREATE SET RobertL.born=1953 + +MERGE (Keanu)-[:ACTED_IN {roles:['Johnny Mnemonic']}]->(JohnnyMnemonic) +MERGE (Takeshi)-[:ACTED_IN {roles:['Takahashi']}]->(JohnnyMnemonic) +MERGE (Dina)-[:ACTED_IN {roles:['Jane']}]->(JohnnyMnemonic) +MERGE (IceT)-[:ACTED_IN {roles:['J-Bone']}]->(JohnnyMnemonic) +MERGE (RobertL)-[:DIRECTED]->(JohnnyMnemonic); + +MERGE (CloudAtlas:Movie {title:'Cloud Atlas'}) ON CREATE SET CloudAtlas.released=2012, CloudAtlas.tagline='Everything is connected' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (HalleB:Person {name:'Halle Berry'}) ON CREATE SET HalleB.born=1966 +MERGE (JimB:Person {name:'Jim Broadbent'}) ON CREATE SET JimB.born=1949 +MERGE (TomT:Person {name:'Tom Tykwer'}) ON CREATE SET TomT.born=1965 +MERGE (DavidMitchell:Person {name:'David Mitchell'}) ON CREATE SET DavidMitchell.born=1969 +MERGE (StefanArndt:Person {name:'Stefan Arndt'}) ON CREATE SET StefanArndt.born=1961 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 + +MERGE (TomH)-[:ACTED_IN {roles:['Zachry', 'Dr. Henry Goose', 'Isaac Sachs', 'Dermot Hoggins']}]->(CloudAtlas) +MERGE (Hugo)-[:ACTED_IN {roles:['Bill Smoke', 'Haskell Moore', 'Tadeusz Kesselring', 'Nurse Noakes', 'Boardman Mephi', 'Old Georgie']}]->(CloudAtlas) +MERGE (HalleB)-[:ACTED_IN {roles:['Luisa Rey', 'Jocasta Ayrs', 'Ovid', 'Meronym']}]->(CloudAtlas) +MERGE (JimB)-[:ACTED_IN {roles:['Vyvyan Ayrs', 'Captain Molyneux', 'Timothy Cavendish']}]->(CloudAtlas) +MERGE (TomT)-[:DIRECTED]->(CloudAtlas) +MERGE (LillyW)-[:DIRECTED]->(CloudAtlas) +MERGE (LanaW)-[:DIRECTED]->(CloudAtlas) +MERGE (DavidMitchell)-[:WROTE]->(CloudAtlas) +MERGE (StefanArndt)-[:PRODUCED]->(CloudAtlas); + +MERGE (TheDaVinciCode:Movie {title:'The Da Vinci Code'}) ON CREATE SET TheDaVinciCode.released=2006, TheDaVinciCode.tagline='Break The Codes' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (IanM:Person {name:'Ian McKellen'}) ON CREATE SET IanM.born=1939 +MERGE (AudreyT:Person {name:'Audrey Tautou'}) ON CREATE SET AudreyT.born=1976 +MERGE (PaulB:Person {name:'Paul Bettany'}) ON CREATE SET PaulB.born=1971 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (TomH)-[:ACTED_IN {roles:['Dr. Robert Langdon']}]->(TheDaVinciCode) +MERGE (IanM)-[:ACTED_IN {roles:['Sir Leight Teabing']}]->(TheDaVinciCode) +MERGE (AudreyT)-[:ACTED_IN {roles:['Sophie Neveu']}]->(TheDaVinciCode) +MERGE (PaulB)-[:ACTED_IN {roles:['Silas']}]->(TheDaVinciCode) +MERGE (RonH)-[:DIRECTED]->(TheDaVinciCode); + +MERGE (VforVendetta:Movie {title:'V for Vendetta'}) ON CREATE SET VforVendetta.released=2006, VforVendetta.tagline='Freedom! Forever!' + +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (NatalieP:Person {name:'Natalie Portman'}) ON CREATE SET NatalieP.born=1981 +MERGE (StephenR:Person {name:'Stephen Rea'}) ON CREATE SET StephenR.born=1946 +MERGE (JohnH:Person {name:'John Hurt'}) ON CREATE SET JohnH.born=1940 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Hugo)-[:ACTED_IN {roles:['V']}]->(VforVendetta) +MERGE (NatalieP)-[:ACTED_IN {roles:['Evey Hammond']}]->(VforVendetta) +MERGE (StephenR)-[:ACTED_IN {roles:['Eric Finch']}]->(VforVendetta) +MERGE (JohnH)-[:ACTED_IN {roles:['High Chancellor Adam Sutler']}]->(VforVendetta) +MERGE (BenM)-[:ACTED_IN {roles:['Dascomb']}]->(VforVendetta) +MERGE (JamesM)-[:DIRECTED]->(VforVendetta) +MERGE (LillyW)-[:PRODUCED]->(VforVendetta) +MERGE (LanaW)-[:PRODUCED]->(VforVendetta) +MERGE (JoelS)-[:PRODUCED]->(VforVendetta) +MERGE (LillyW)-[:WROTE]->(VforVendetta) +MERGE (LanaW)-[:WROTE]->(VforVendetta); + +MERGE (SpeedRacer:Movie {title:'Speed Racer'}) ON CREATE SET SpeedRacer.released=2008, SpeedRacer.tagline='Speed has no limits' + +MERGE (EmileH:Person {name:'Emile Hirsch'}) ON CREATE SET EmileH.born=1985 +MERGE (JohnG:Person {name:'John Goodman'}) ON CREATE SET JohnG.born=1960 +MERGE (SusanS:Person {name:'Susan Sarandon'}) ON CREATE SET SusanS.born=1946 +MERGE (MatthewF:Person {name:'Matthew Fox'}) ON CREATE SET MatthewF.born=1966 +MERGE (ChristinaR:Person {name:'Christina Ricci'}) ON CREATE SET ChristinaR.born=1980 +MERGE (Rain:Person {name:'Rain'}) ON CREATE SET Rain.born=1982 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (EmileH)-[:ACTED_IN {roles:['Speed Racer']}]->(SpeedRacer) +MERGE (JohnG)-[:ACTED_IN {roles:['Pops']}]->(SpeedRacer) +MERGE (SusanS)-[:ACTED_IN {roles:['Mom']}]->(SpeedRacer) +MERGE (MatthewF)-[:ACTED_IN {roles:['Racer X']}]->(SpeedRacer) +MERGE (ChristinaR)-[:ACTED_IN {roles:['Trixie']}]->(SpeedRacer) +MERGE (Rain)-[:ACTED_IN {roles:['Taejo Togokahn']}]->(SpeedRacer) +MERGE (BenM)-[:ACTED_IN {roles:['Cass Jones']}]->(SpeedRacer) +MERGE (LillyW)-[:DIRECTED]->(SpeedRacer) +MERGE (LanaW)-[:DIRECTED]->(SpeedRacer) +MERGE (LillyW)-[:WROTE]->(SpeedRacer) +MERGE (LanaW)-[:WROTE]->(SpeedRacer) +MERGE (JoelS)-[:PRODUCED]->(SpeedRacer); + +MERGE (NinjaAssassin:Movie {title:'Ninja Assassin'}) ON CREATE SET NinjaAssassin.released=2009, NinjaAssassin.tagline='Prepare to enter a secret world of assassins' + +MERGE (NaomieH:Person {name:'Naomie Harris'}) +MERGE (Rain:Person {name:'Rain'}) ON CREATE SET Rain.born=1982 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (RickY:Person {name:'Rick Yune'}) ON CREATE SET RickY.born=1971 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Rain)-[:ACTED_IN {roles:['Raizo']}]->(NinjaAssassin) +MERGE (NaomieH)-[:ACTED_IN {roles:['Mika Coretti']}]->(NinjaAssassin) +MERGE (RickY)-[:ACTED_IN {roles:['Takeshi']}]->(NinjaAssassin) +MERGE (BenM)-[:ACTED_IN {roles:['Ryan Maslow']}]->(NinjaAssassin) +MERGE (JamesM)-[:DIRECTED]->(NinjaAssassin) +MERGE (LillyW)-[:PRODUCED]->(NinjaAssassin) +MERGE (LanaW)-[:PRODUCED]->(NinjaAssassin) +MERGE (JoelS)-[:PRODUCED]->(NinjaAssassin); + +MERGE (TheGreenMile:Movie {title:'The Green Mile'}) ON CREATE SET TheGreenMile.released=1999, TheGreenMile.tagline='Walk a mile you\'ll never forget.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (JamesC:Person {name:'James Cromwell'}) ON CREATE SET JamesC.born=1940 +MERGE (BonnieH:Person {name:'Bonnie Hunt'}) ON CREATE SET BonnieH.born=1961 +MERGE (MichaelD:Person {name:'Michael Clarke Duncan'}) ON CREATE SET MichaelD.born=1957 +MERGE (DavidM:Person {name:'David Morse'}) ON CREATE SET DavidM.born=1953 +MERGE (SamR:Person {name:'Sam Rockwell'}) ON CREATE SET SamR.born=1968 +MERGE (GaryS:Person {name:'Gary Sinise'}) ON CREATE SET GaryS.born=1955 +MERGE (PatriciaC:Person {name:'Patricia Clarkson'}) ON CREATE SET PatriciaC.born=1959 +MERGE (FrankD:Person {name:'Frank Darabont'}) ON CREATE SET FrankD.born=1959 + +MERGE (TomH)-[:ACTED_IN {roles:['Paul Edgecomb']}]->(TheGreenMile) +MERGE (MichaelD)-[:ACTED_IN {roles:['John Coffey']}]->(TheGreenMile) +MERGE (DavidM)-[:ACTED_IN {roles:['Brutus "Brutal" Howell']}]->(TheGreenMile) +MERGE (BonnieH)-[:ACTED_IN {roles:['Jan Edgecomb']}]->(TheGreenMile) +MERGE (JamesC)-[:ACTED_IN {roles:['Warden Hal Moores']}]->(TheGreenMile) +MERGE (SamR)-[:ACTED_IN {roles:['"Wild Bill" Wharton']}]->(TheGreenMile) +MERGE (GaryS)-[:ACTED_IN {roles:['Burt Hammersmith']}]->(TheGreenMile) +MERGE (PatriciaC)-[:ACTED_IN {roles:['Melinda Moores']}]->(TheGreenMile) +MERGE (FrankD)-[:DIRECTED]->(TheGreenMile); + +MERGE (FrostNixon:Movie {title:'Frost/Nixon'}) ON CREATE SET FrostNixon.released=2008, FrostNixon.tagline='400 million people were waiting for the truth.' + +MERGE (FrankL:Person {name:'Frank Langella'}) ON CREATE SET FrankL.born=1938 +MERGE (MichaelS:Person {name:'Michael Sheen'}) ON CREATE SET MichaelS.born=1969 +MERGE (OliverP:Person {name:'Oliver Platt'}) ON CREATE SET OliverP.born=1960 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (SamR:Person {name:'Sam Rockwell'}) ON CREATE SET SamR.born=1968 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (FrankL)-[:ACTED_IN {roles:['Richard Nixon']}]->(FrostNixon) +MERGE (MichaelS)-[:ACTED_IN {roles:['David Frost']}]->(FrostNixon) +MERGE (KevinB)-[:ACTED_IN {roles:['Jack Brennan']}]->(FrostNixon) +MERGE (OliverP)-[:ACTED_IN {roles:['Bob Zelnick']}]->(FrostNixon) +MERGE (SamR)-[:ACTED_IN {roles:['James Reston, Jr.']}]->(FrostNixon) +MERGE (RonH)-[:DIRECTED]->(FrostNixon); + +MERGE (Hoffa:Movie {title:'Hoffa'}) ON CREATE SET Hoffa.released=1992, Hoffa.tagline='He didn\'t want law. He wanted justice.' + +MERGE (DannyD:Person {name:'Danny DeVito'}) ON CREATE SET DannyD.born=1944 +MERGE (JohnR:Person {name:'John C. Reilly'}) ON CREATE SET JohnR.born=1965 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (JTW:Person {name:'J.T. Walsh'}) ON CREATE SET JTW.born=1943 + +MERGE (JackN)-[:ACTED_IN {roles:['Hoffa']}]->(Hoffa) +MERGE (DannyD)-[:ACTED_IN {roles:['Robert "Bobby" Ciaro']}]->(Hoffa) +MERGE (JTW)-[:ACTED_IN {roles:['Frank Fitzsimmons']}]->(Hoffa) +MERGE (JohnR)-[:ACTED_IN {roles:['Peter "Pete" Connelly']}]->(Hoffa) +MERGE (DannyD)-[:DIRECTED]->(Hoffa); + +MERGE (Apollo13:Movie {title:'Apollo 13'}) ON CREATE SET Apollo13.released=1995, Apollo13.tagline='Houston, we have a problem.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (EdH:Person {name:'Ed Harris'}) ON CREATE SET EdH.born=1950 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (GaryS:Person {name:'Gary Sinise'}) ON CREATE SET GaryS.born=1955 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (TomH)-[:ACTED_IN {roles:['Jim Lovell']}]->(Apollo13) +MERGE (KevinB)-[:ACTED_IN {roles:['Jack Swigert']}]->(Apollo13) +MERGE (EdH)-[:ACTED_IN {roles:['Gene Kranz']}]->(Apollo13) +MERGE (BillPax)-[:ACTED_IN {roles:['Fred Haise']}]->(Apollo13) +MERGE (GaryS)-[:ACTED_IN {roles:['Ken Mattingly']}]->(Apollo13) +MERGE (RonH)-[:DIRECTED]->(Apollo13); + +MERGE (Twister:Movie {title:'Twister'}) ON CREATE SET Twister.released=1996, Twister.tagline='Don\'t Breathe. Don\'t Look Back.' + +MERGE (PhilipH:Person {name:'Philip Seymour Hoffman'}) ON CREATE SET PhilipH.born=1967 +MERGE (JanB:Person {name:'Jan de Bont'}) ON CREATE SET JanB.born=1943 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (ZachG:Person {name:'Zach Grenier'}) ON CREATE SET ZachG.born=1954 + +MERGE (BillPax)-[:ACTED_IN {roles:['Bill Harding']}]->(Twister) +MERGE (HelenH)-[:ACTED_IN {roles:['Dr. Jo Harding']}]->(Twister) +MERGE (ZachG)-[:ACTED_IN {roles:['Eddie']}]->(Twister) +MERGE (PhilipH)-[:ACTED_IN {roles:['Dustin "Dusty" Davis']}]->(Twister) +MERGE (JanB)-[:DIRECTED]->(Twister); + +MERGE (CastAway:Movie {title:'Cast Away'}) ON CREATE SET CastAway.released=2000, CastAway.tagline='At the edge of the world, his journey begins.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (RobertZ:Person {name:'Robert Zemeckis'}) ON CREATE SET RobertZ.born=1951 + +MERGE (TomH)-[:ACTED_IN {roles:['Chuck Noland']}]->(CastAway) +MERGE (HelenH)-[:ACTED_IN {roles:['Kelly Frears']}]->(CastAway) +MERGE (RobertZ)-[:DIRECTED]->(CastAway); + +MERGE (OneFlewOvertheCuckoosNest:Movie {title:'One Flew Over the Cuckoo\'s Nest'}) ON CREATE SET OneFlewOvertheCuckoosNest.released=1975, OneFlewOvertheCuckoosNest.tagline='If he\'s crazy, what does that make you?' + +MERGE (MilosF:Person {name:'Milos Forman'}) ON CREATE SET MilosF.born=1932 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DannyD:Person {name:'Danny DeVito'}) ON CREATE SET DannyD.born=1944 + +MERGE (JackN)-[:ACTED_IN {roles:['Randle McMurphy']}]->(OneFlewOvertheCuckoosNest) +MERGE (DannyD)-[:ACTED_IN {roles:['Martini']}]->(OneFlewOvertheCuckoosNest) +MERGE (MilosF)-[:DIRECTED]->(OneFlewOvertheCuckoosNest); + +MERGE (SomethingsGottaGive:Movie {title:'Something\'s Gotta Give'}) ON CREATE SET SomethingsGottaGive.released=2003 + +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DianeK:Person {name:'Diane Keaton'}) ON CREATE SET DianeK.born=1946 +MERGE (NancyM:Person {name:'Nancy Meyers'}) ON CREATE SET NancyM.born=1949 +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 + +MERGE (JackN)-[:ACTED_IN {roles:['Harry Sanborn']}]->(SomethingsGottaGive) +MERGE (DianeK)-[:ACTED_IN {roles:['Erica Barry']}]->(SomethingsGottaGive) +MERGE (Keanu)-[:ACTED_IN {roles:['Julian Mercer']}]->(SomethingsGottaGive) +MERGE (NancyM)-[:DIRECTED]->(SomethingsGottaGive) +MERGE (NancyM)-[:PRODUCED]->(SomethingsGottaGive) +MERGE (NancyM)-[:WROTE]->(SomethingsGottaGive); + +MERGE (BicentennialMan:Movie {title:'Bicentennial Man'}) ON CREATE SET BicentennialMan.released=1999, BicentennialMan.tagline='One robot\'s 200 year journey to become an ordinary man.' + +MERGE (ChrisC:Person {name:'Chris Columbus'}) ON CREATE SET ChrisC.born=1958 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (OliverP:Person {name:'Oliver Platt'}) ON CREATE SET OliverP.born=1960 + +MERGE (Robin)-[:ACTED_IN {roles:['Andrew Marin']}]->(BicentennialMan) +MERGE (OliverP)-[:ACTED_IN {roles:['Rupert Burns']}]->(BicentennialMan) +MERGE (ChrisC)-[:DIRECTED]->(BicentennialMan); + +MERGE (CharlieWilsonsWar:Movie {title:'Charlie Wilson\'s War'}) ON CREATE SET CharlieWilsonsWar.released=2007, CharlieWilsonsWar.tagline='A stiff drink. A little mascara. A lot of nerve. Who said they couldn\'t bring down the Soviet empire.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (PhilipH:Person {name:'Philip Seymour Hoffman'}) ON CREATE SET PhilipH.born=1967 +MERGE (JuliaR:Person {name:'Julia Roberts'}) ON CREATE SET JuliaR.born=1967 +MERGE (MikeN:Person {name:'Mike Nichols'}) ON CREATE SET MikeN.born=1931 + +MERGE (TomH)-[:ACTED_IN {roles:['Rep. Charlie Wilson']}]->(CharlieWilsonsWar) +MERGE (JuliaR)-[:ACTED_IN {roles:['Joanne Herring']}]->(CharlieWilsonsWar) +MERGE (PhilipH)-[:ACTED_IN {roles:['Gust Avrakotos']}]->(CharlieWilsonsWar) +MERGE (MikeN)-[:DIRECTED]->(CharlieWilsonsWar); + +MERGE (ThePolarExpress:Movie {title:'The Polar Express'}) ON CREATE SET ThePolarExpress.released=2004, ThePolarExpress.tagline='This Holiday Season... Believe' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (RobertZ:Person {name:'Robert Zemeckis'}) ON CREATE SET RobertZ.born=1951 + +MERGE (TomH)-[:ACTED_IN {roles:['Hero Boy', 'Father', 'Conductor', 'Hobo', 'Scrooge', 'Santa Claus']}]->(ThePolarExpress) +MERGE (RobertZ)-[:DIRECTED]->(ThePolarExpress); + +MERGE (ALeagueofTheirOwn:Movie {title:'A League of Their Own'}) ON CREATE SET ALeagueofTheirOwn.released=1992, ALeagueofTheirOwn.tagline='Once in a lifetime you get a chance to do something different.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (Madonna:Person {name:'Madonna'}) ON CREATE SET Madonna.born=1954 +MERGE (GeenaD:Person {name:'Geena Davis'}) ON CREATE SET GeenaD.born=1956 +MERGE (LoriP:Person {name:'Lori Petty'}) ON CREATE SET LoriP.born=1963 +MERGE (PennyM:Person {name:'Penny Marshall'}) ON CREATE SET PennyM.born=1943 +MERGE (RosieO:Person {name:'Rosie O\'Donnell'}) ON CREATE SET RosieO.born=1962 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 + +MERGE (TomH)-[:ACTED_IN {roles:['Jimmy Dugan']}]->(ALeagueofTheirOwn) +MERGE (GeenaD)-[:ACTED_IN {roles:['Dottie Hinson']}]->(ALeagueofTheirOwn) +MERGE (LoriP)-[:ACTED_IN {roles:['Kit Keller']}]->(ALeagueofTheirOwn) +MERGE (RosieO)-[:ACTED_IN {roles:['Doris Murphy']}]->(ALeagueofTheirOwn) +MERGE (Madonna)-[:ACTED_IN {roles:['"All the Way" Mae Mordabito']}]->(ALeagueofTheirOwn) +MERGE (BillPax)-[:ACTED_IN {roles:['Bob Hinson']}]->(ALeagueofTheirOwn) +MERGE (PennyM)-[:DIRECTED]->(ALeagueofTheirOwn); + + +MATCH (CloudAtlas:Movie {title:'Cloud Atlas'}) +MATCH (TheReplacements:Movie {title:'The Replacements'}) +MATCH (Unforgiven:Movie {title:'Unforgiven'}) +MATCH (TheBirdcage:Movie {title:'The Birdcage'}) +MATCH (TheDaVinciCode:Movie {title:'The Da Vinci Code'}) +MATCH (JerryMaguire:Movie {title:'Jerry Maguire'}) + +MERGE (PaulBlythe:Person {name:'Paul Blythe'}) +MERGE (AngelaScope:Person {name:'Angela Scope'}) +MERGE (JessicaThompson:Person {name:'Jessica Thompson'}) +MERGE (JamesThompson:Person {name:'James Thompson'}) + +MERGE (JamesThompson)-[:FOLLOWS]->(JessicaThompson) +MERGE (AngelaScope)-[:FOLLOWS]->(JessicaThompson) +MERGE (PaulBlythe)-[:FOLLOWS]->(AngelaScope) + +MERGE (JessicaThompson)-[:REVIEWED {summary:'An amazing journey', rating:95}]->(CloudAtlas) +MERGE (JessicaThompson)-[:REVIEWED {summary:'Silly, but fun', rating:65}]->(TheReplacements) +MERGE (JamesThompson)-[:REVIEWED {summary:'The coolest football movie ever', rating:100}]->(TheReplacements) +MERGE (AngelaScope)-[:REVIEWED {summary:'Pretty funny at times', rating:62}]->(TheReplacements) +MERGE (JessicaThompson)-[:REVIEWED {summary:'Dark, but compelling', rating:85}]->(Unforgiven) +MERGE (JessicaThompson)-[:REVIEWED {summary:"Slapstick redeemed only by the Robin Williams and Gene Hackman's stellar performances", rating:45}]->(TheBirdcage) +MERGE (JessicaThompson)-[:REVIEWED {summary:'A solid romp', rating:68}]->(TheDaVinciCode) +MERGE (JamesThompson)-[:REVIEWED {summary:'Fun, but a little far fetched', rating:65}]->(TheDaVinciCode) +MERGE (JessicaThompson)-[:REVIEWED {summary:'You had me at Jerry', rating:92}]->(JerryMaguire); +---- + +To see a subset of the imported data run the following statement + +[source,cypher] +---- +MATCH (person:Person {name: 'Tom Hanks'}) +MATCH path = (person)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +RETURN path; +---- + +In the next step, you will look for nodes and their properties. + +== Find nodes + +To start, can you find the actor _Tom Hanks_ which is a `Person` in the graph? + +Run the following query: + +[source,cypher] +---- +MATCH (p:Person {name: "Tom Hanks"}) +RETURN p +---- + +Next, can you find a `Movie` called _Cloud Atlas_? + +[%collapsible] +.Reveal the solution +==== +[source,cypher] +---- +MATCH (m:Movie {title:"Cloud Atlas"}) +RETURN m +---- +==== + +Similarly, you can find all the people (nodes with the `Person` label) in the graph, but limit the returned number to ten: + +[source,cypher] +---- +MATCH (p:Person) +RETURN p.name LIMIT 10 +---- + +[TIP] +==== +Try to remove the property key `.name` from the RETURN clause and see the difference. + +[source,cypher] +---- +MATCH (p:Person) +RETURN p LIMIT 10 +---- +==== + +If you want to find movies released in a specific timespan, you can add conditions by using `WHERE`: + +[source,cypher] +---- +MATCH (m:Movie) WHERE m.released >= 1990 AND m.released < 2000 +RETURN m.title, m.released +---- + +In the next step you will look for patterns in the graph. + +== Find patterns + +A pattern in the graph is a specific arrangement of nodes and relationships that can be matched in the graph. +To find which movies Tom Hanks have acted in, specify the pattern as follows: + +[source,cypher] +---- +MATCH (p:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m:Movie) +RETURN m.title +---- + +Can you specify a pattern to find who directed _Cloud Atlas_? +Hint: The relationship between a person who is a director and the movie they directed is `:DIRECTED`. + +[%collapsible] +.Reveal the solution +==== +[source,cypher] +---- +MATCH (m:Movie {title: "Cloud Atlas"})<-[:DIRECTED]-(director:Person) +RETURN director.name +---- +==== + +If you extend the length of the pattern, you can find co-actors: + +[source,cypher] +---- +MATCH (:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) +RETURN coActors.name +---- + +If you want to see this all as a graph, the easiest way is to return the `path` of your patterns. + +[source,cypher] +---- +MATCH path= (:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) +RETURN path +---- + +You can return _all_ relationship properties if you are not sure exactly what you are looking for: + +[source,cypher] +---- +MATCH (p:Person)-[relationship]-(:Movie {title: "Cloud Atlas"}) +RETURN p.name, type(relationship), relationship +---- + +This query returns a list of Person-nodes that are connected to the Movie-node _Cloud Atlas_, the relationship type, and _all_ the properties on the relationship. + +In the next step, you are going to prove whether the Hollywood version of six degrees of separation is true in your dataset. + +== Six degrees of Kevin Bacon + +You may have heard about the concept that any two people on Earth are six or fewer connections apart. +In Hollywood, this is said to be true for Kevin Bacon and any other actor. + +The following query lets you see all movies _and_ people up to six hops away from Kevin Bacon: + +[source,cypher] +---- +MATCH (:Person {name:"Kevin Bacon"})-[*1..6]-(n) +RETURN DISTINCT n +---- + +But is it true that every actor is really connected to Kevin Bacon? + +Cypher has a built-in algorithm for this, "Shortest Path" and it looks like this: + +[source,cypher] +---- +MATCH path=shortestPath( + (:Person {name:"Kevin Bacon"})-[*]-(:Person {name:"Meg Ryan"}) +) +RETURN path +---- + +You can try to change _Meg Ryan_ out for any other actor in the dataset and see if you can find one farther away than six hops. + +In the next step, you are going to recommend new colleagues for Tom Hanks. + +== Recommendations + +A basic recommendation approach is to find connections past an immediate neighborhood of nodes which are themselves well-connected. +For Tom Hanks, this means to find actors who he has yet to work with, but who has worked with his previous co-actors. +Then you need to find someone who can introduce Tom Hanks to his potential new co-actor. + +To find a list of potential co-actors, run the following query: + +[source,cypher] +---- +MATCH (p:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), + (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors) +WHERE NOT exists { (p)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) } AND p <> cocoActors +RETURN cocoActors.name AS recommended, count(*) AS score ORDER BY score DESC +---- + +The `WHERE` part of the query ensures that you don't get actors who already worked with Tom Hanks and nor Tom Hanks himself. +The results are ordered by the number of co-occurrences they have in common. + +Now, if you think it would be a good idea for Tom Hanks and Keanu Reeves to do a movie together, who would be able to introduce them, and in which movies have they acted jointly? + +[source,cypher] +---- +MATCH (p1:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), + (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(p2:Person {name:"Keanu Reeves"}) +RETURN DISTINCT coActors.name AS matchmaker +---- + +In the last step, you are going to clean up your database by deleting the data you have created. + +== Clean up + +This dataset is fun to experiment with, but once you are done, you can **delete everything** with the following: + +[source,cypher] +---- +MATCH (n:Person|Movie) +DETACH DELETE n +---- + +[WARNING] +==== +This does in fact permanently delete the nodes and relationships in this database, so use with caution. +==== + +You can verify that there is nothing left by a simple query: + +[source,cypher] +---- +MATCH () +RETURN count (*) +---- + +Well done! + +If you want to learn more about Cypher, see the following: + +* https://graphacademy.neo4j.com/categories/cypher/[Free Online Cypher Courses^] +* https://neo4j.com/docs/getting-started/cypher-intro/[Cypher Getting Started^] +* https://neo4j.com/docs/cypher-manual/current/introduction/[Cypher Documentation^] +* https://neo4j.com/docs/cypher-cheat-sheet/[Cypher Cheat-Sheet^]. + + + diff --git a/documentation/movies.workspace.adoc b/documentation/movies.workspace.adoc new file mode 100644 index 0000000..766c113 --- /dev/null +++ b/documentation/movies.workspace.adoc @@ -0,0 +1,942 @@ += Movies graph +:imagesdir: https://neo4j-graph-examples.github.io/get-started/documentation/img/ + +== Movies graph + +This guide uses pop-cultural connections to teach you how to use Cypher to create and query data. +You will explore connections between actors, directors, and movies, and also solve the famous Bacon-path. + +Note that this guide assumes that you use an empty database as you will modify it along the way. +You will learn how to delete the data you create towards the end of the guide as well. + +=== What you will learn + +This guide takes around 10 minutes and by the end of it you will be able to: + +- Create nodes and relationships that connect them. +- Find individual nodes by using conditional matches. +- Find patterns in the graph. +- Understand and use the shortest path algorithm. +- Write a basic recommendation query. +- Delete all data. + +Let's get started! + +In the next step you are going to create the data you'll be working with. + +== Create the data + +The Cypher `CREATE` clause is used to create data in your graph. +If you are not familiar with Cypher syntax, you can try the _Query fundamentals_ guide or see the link:https://neo4j.com/docs/cypher-manual/current[Cypher Manual]. + +You are going to create a dataset with `Person` and `Movie` nodes and different types of relationships to connect them. + +image::movie-model.png[] + +[source,cypher] +---- +CREATE CONSTRAINT movie_title IF NOT EXISTS FOR (m:Movie) REQUIRE m.title IS UNIQUE; +CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE; + +MERGE (TheMatrix:Movie {title:'The Matrix'}) ON CREATE SET TheMatrix.released=1999, TheMatrix.tagline='Welcome to the Real World' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix) +MERGE (LillyW)-[:DIRECTED]->(TheMatrix) +MERGE (LanaW)-[:DIRECTED]->(TheMatrix) +MERGE (JoelS)-[:PRODUCED]->(TheMatrix) + +MERGE (Emil:Person {name:'Emil Eifrem'}) ON CREATE SET Emil.born=1978 +MERGE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix); + + +MERGE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded'}) ON CREATE SET TheMatrixReloaded.released=2003, TheMatrixReloaded.tagline='Free your mind' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded) +MERGE (LillyW)-[:DIRECTED]->(TheMatrixReloaded) +MERGE (LanaW)-[:DIRECTED]->(TheMatrixReloaded) +MERGE (JoelS)-[:PRODUCED]->(TheMatrixReloaded); + + +MERGE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions'}) ON CREATE SET TheMatrixRevolutions.released=2003, TheMatrixRevolutions.tagline='Everything that has a beginning has an end' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967 +MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions) +MERGE (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions) +MERGE (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions) +MERGE (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions) +MERGE (LillyW)-[:DIRECTED]->(TheMatrixRevolutions) +MERGE (LanaW)-[:DIRECTED]->(TheMatrixRevolutions) +MERGE (JoelS)-[:PRODUCED]->(TheMatrixRevolutions); + + +MERGE (TheDevilsAdvocate:Movie {title:"The Devil's Advocate", released:1997, tagline:'Evil has its winning ways'}) + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Charlize:Person {name:'Charlize Theron'}) ON CREATE SET Charlize.born=1975 +MERGE (Al:Person {name:'Al Pacino'}) ON CREATE SET Al.born=1940 +MERGE (Taylor:Person {name:'Taylor Hackford'}) ON CREATE SET Taylor.born=1944 + +MERGE (Keanu)-[:ACTED_IN {roles:['Kevin Lomax']}]->(TheDevilsAdvocate) +MERGE (Charlize)-[:ACTED_IN {roles:['Mary Ann Lomax']}]->(TheDevilsAdvocate) +MERGE (Al)-[:ACTED_IN {roles:['John Milton']}]->(TheDevilsAdvocate) +MERGE (Taylor)-[:DIRECTED]->(TheDevilsAdvocate); + + +MERGE (AFewGoodMen:Movie {title:'A Few Good Men'}) ON CREATE SET AFewGoodMen.released=1992, AFewGoodMen.tagline='In the heart of the nation\'s capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DemiM:Person {name:'Demi Moore'}) ON CREATE SET DemiM.born=1962 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (KieferS:Person {name:'Kiefer Sutherland'}) ON CREATE SET KieferS.born=1966 +MERGE (NoahW:Person {name:'Noah Wyle'}) ON CREATE SET NoahW.born=1971 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 +MERGE (KevinP:Person {name:'Kevin Pollak'}) ON CREATE SET KevinP.born=1957 +MERGE (JTW:Person {name:'J.T. Walsh'}) ON CREATE SET JTW.born=1943 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (ChristopherG:Person {name:'Christopher Guest'}) ON CREATE SET ChristopherG.born=1948 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 +MERGE (AaronS:Person {name:'Aaron Sorkin'}) ON CREATE SET AaronS.born=1961 + +MERGE (TomC)-[:ACTED_IN {roles:['Lt. Daniel Kaffee']}]->(AFewGoodMen) +MERGE (JackN)-[:ACTED_IN {roles:['Col. Nathan R. Jessup']}]->(AFewGoodMen) +MERGE (DemiM)-[:ACTED_IN {roles:['Lt. Cdr. JoAnne Galloway']}]->(AFewGoodMen) +MERGE (KevinB)-[:ACTED_IN {roles:['Capt. Jack Ross']}]->(AFewGoodMen) +MERGE (KieferS)-[:ACTED_IN {roles:['Lt. Jonathan Kendrick']}]->(AFewGoodMen) +MERGE (NoahW)-[:ACTED_IN {roles:['Cpl. Jeffrey Barnes']}]->(AFewGoodMen) +MERGE (CubaG)-[:ACTED_IN {roles:['Cpl. Carl Hammaker']}]->(AFewGoodMen) +MERGE (KevinP)-[:ACTED_IN {roles:['Lt. Sam Weinberg']}]->(AFewGoodMen) +MERGE (JTW)-[:ACTED_IN {roles:['Lt. Col. Matthew Andrew Markinson']}]->(AFewGoodMen) +MERGE (JamesM)-[:ACTED_IN {roles:['Pfc. Louden Downey']}]->(AFewGoodMen) +MERGE (ChristopherG)-[:ACTED_IN {roles:['Dr. Stone']}]->(AFewGoodMen) +MERGE (AaronS)-[:ACTED_IN {roles:['Man in Bar']}]->(AFewGoodMen) +MERGE (RobR)-[:DIRECTED]->(AFewGoodMen) +MERGE (AaronS)-[:WROTE]->(AFewGoodMen); + + +MERGE (TopGun:Movie {title:'Top Gun'}) ON CREATE SET TopGun.released=1986, TopGun.tagline='I feel the need, the need for speed.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (KellyM:Person {name:'Kelly McGillis'}) ON CREATE SET KellyM.born=1957 +MERGE (ValK:Person {name:'Val Kilmer'}) ON CREATE SET ValK.born=1959 +MERGE (AnthonyE:Person {name:'Anthony Edwards'}) ON CREATE SET AnthonyE.born=1962 +MERGE (TomS:Person {name:'Tom Skerritt'}) ON CREATE SET TomS.born=1933 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (TonyS:Person {name:'Tony Scott'}) ON CREATE SET TonyS.born=1944 +MERGE (JimC:Person {name:'Jim Cash'}) ON CREATE SET JimC.born=1941 + +MERGE (TomC)-[:ACTED_IN {roles:['Maverick']}]->(TopGun) +MERGE (KellyM)-[:ACTED_IN {roles:['Charlie']}]->(TopGun) +MERGE (ValK)-[:ACTED_IN {roles:['Iceman']}]->(TopGun) +MERGE (AnthonyE)-[:ACTED_IN {roles:['Goose']}]->(TopGun) +MERGE (TomS)-[:ACTED_IN {roles:['Viper']}]->(TopGun) +MERGE (MegR)-[:ACTED_IN {roles:['Carole']}]->(TopGun) +MERGE (TonyS)-[:DIRECTED]->(TopGun) +MERGE (JimC)-[:WROTE]->(TopGun); + + +MERGE (JerryMaguire:Movie {title:'Jerry Maguire'}) ON CREATE SET JerryMaguire.released=2000, JerryMaguire.tagline='The rest of his life begins now.' + +MERGE (TomC:Person {name:'Tom Cruise'}) ON CREATE SET TomC.born=1962 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 +MERGE (ReneeZ:Person {name:'Renee Zellweger'}) ON CREATE SET ReneeZ.born=1969 +MERGE (KellyP:Person {name:'Kelly Preston'}) ON CREATE SET KellyP.born=1962 +MERGE (JerryO:Person {name:'Jerry O\'Connell'}) ON CREATE SET JerryO.born=1974 +MERGE (JayM:Person {name:'Jay Mohr'}) ON CREATE SET JayM.born=1970 +MERGE (BonnieH:Person {name:'Bonnie Hunt'}) ON CREATE SET BonnieH.born=1961 +MERGE (ReginaK:Person {name:'Regina King'}) ON CREATE SET ReginaK.born=1971 +MERGE (JonathanL:Person {name:'Jonathan Lipnicki'}) ON CREATE SET JonathanL.born=1996 +MERGE (CameronC:Person {name:'Cameron Crowe'}) ON CREATE SET CameronC.born=1957 + +MERGE (TomC)-[:ACTED_IN {roles:['Jerry Maguire']}]->(JerryMaguire) +MERGE (CubaG)-[:ACTED_IN {roles:['Rod Tidwell']}]->(JerryMaguire) +MERGE (ReneeZ)-[:ACTED_IN {roles:['Dorothy Boyd']}]->(JerryMaguire) +MERGE (KellyP)-[:ACTED_IN {roles:['Avery Bishop']}]->(JerryMaguire) +MERGE (JerryO)-[:ACTED_IN {roles:['Frank Cushman']}]->(JerryMaguire) +MERGE (JayM)-[:ACTED_IN {roles:['Bob Sugar']}]->(JerryMaguire) +MERGE (BonnieH)-[:ACTED_IN {roles:['Laurel Boyd']}]->(JerryMaguire) +MERGE (ReginaK)-[:ACTED_IN {roles:['Marcee Tidwell']}]->(JerryMaguire) +MERGE (JonathanL)-[:ACTED_IN {roles:['Ray Boyd']}]->(JerryMaguire) +MERGE (CameronC)-[:DIRECTED]->(JerryMaguire) +MERGE (CameronC)-[:PRODUCED]->(JerryMaguire) +MERGE (CameronC)-[:WROTE]->(JerryMaguire); + +MERGE (StandByMe:Movie {title:'Stand By Me'}) ON CREATE SET StandByMe.released=1986, StandByMe.tagline='For some, it\'s the last real taste of innocence, and the first real taste of life. But for everyone, it\'s the time that memories are made of.' + +MERGE (RiverP:Person {name:'River Phoenix'}) ON CREATE SET RiverP.born=1970 +MERGE (CoreyF:Person {name:'Corey Feldman'}) ON CREATE SET CoreyF.born=1971 +MERGE (JerryO:Person {name:'Jerry O\'Connell'}) ON CREATE SET JerryO.born=1974 +MERGE (WilW:Person {name:'Wil Wheaton'}) ON CREATE SET WilW.born=1972 +MERGE (KieferS:Person {name:'Kiefer Sutherland'}) ON CREATE SET KieferS.born=1966 +MERGE (JohnC:Person {name:'John Cusack'}) ON CREATE SET JohnC.born=1966 +MERGE (MarshallB:Person {name:'Marshall Bell'}) ON CREATE SET MarshallB.born=1942 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 + +MERGE (WilW)-[:ACTED_IN {roles:['Gordie Lachance']}]->(StandByMe) +MERGE (RiverP)-[:ACTED_IN {roles:['Chris Chambers']}]->(StandByMe) +MERGE (JerryO)-[:ACTED_IN {roles:['Vern Tessio']}]->(StandByMe) +MERGE (CoreyF)-[:ACTED_IN {roles:['Teddy Duchamp']}]->(StandByMe) +MERGE (JohnC)-[:ACTED_IN {roles:['Denny Lachance']}]->(StandByMe) +MERGE (KieferS)-[:ACTED_IN {roles:['Ace Merrill']}]->(StandByMe) +MERGE (MarshallB)-[:ACTED_IN {roles:['Mr. Lachance']}]->(StandByMe) +MERGE (RobR)-[:DIRECTED]->(StandByMe); + +MERGE (AsGoodAsItGets:Movie {title:'As Good as It Gets'}) ON CREATE SET AsGoodAsItGets.released=1997, AsGoodAsItGets.tagline='A comedy from the heart that goes for the throat.' + +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (GregK:Person {name:'Greg Kinnear'}) ON CREATE SET GregK.born=1963 +MERGE (JamesB:Person {name:'James L. Brooks'}) ON CREATE SET JamesB.born=1940 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 + +MERGE (JackN)-[:ACTED_IN {roles:['Melvin Udall']}]->(AsGoodAsItGets) +MERGE (HelenH)-[:ACTED_IN {roles:['Carol Connelly']}]->(AsGoodAsItGets) +MERGE (GregK)-[:ACTED_IN {roles:['Simon Bishop']}]->(AsGoodAsItGets) +MERGE (CubaG)-[:ACTED_IN {roles:['Frank Sachs']}]->(AsGoodAsItGets) +MERGE (JamesB)-[:DIRECTED]->(AsGoodAsItGets); + +MERGE (WhatDreamsMayCome:Movie {title:'What Dreams May Come'}) ON CREATE SET WhatDreamsMayCome.released=1998, WhatDreamsMayCome.tagline='After life there is more. The end is just the beginning.' + +MERGE (AnnabellaS:Person {name:'Annabella Sciorra'}) ON CREATE SET AnnabellaS.born=1960 +MERGE (MaxS:Person {name:'Max von Sydow'}) ON CREATE SET MaxS.born=1929 +MERGE (WernerH:Person {name:'Werner Herzog'}) ON CREATE SET WernerH.born=1942 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (VincentW:Person {name:'Vincent Ward'}) ON CREATE SET VincentW.born=1956 +MERGE (CubaG:Person {name:'Cuba Gooding Jr.'}) ON CREATE SET CubaG.born=1968 + +MERGE (Robin)-[:ACTED_IN {roles:['Chris Nielsen']}]->(WhatDreamsMayCome) +MERGE (CubaG)-[:ACTED_IN {roles:['Albert Lewis']}]->(WhatDreamsMayCome) +MERGE (AnnabellaS)-[:ACTED_IN {roles:['Annie Collins-Nielsen']}]->(WhatDreamsMayCome) +MERGE (MaxS)-[:ACTED_IN {roles:['The Tracker']}]->(WhatDreamsMayCome) +MERGE (WernerH)-[:ACTED_IN {roles:['The Face']}]->(WhatDreamsMayCome) +MERGE (VincentW)-[:DIRECTED]->(WhatDreamsMayCome); + +MERGE (SnowFallingonCedars:Movie {title:'Snow Falling on Cedars'}) ON CREATE SET SnowFallingonCedars.released=1999, SnowFallingonCedars.tagline='First loves last. Forever.' + +MERGE (EthanH:Person {name:'Ethan Hawke'}) ON CREATE SET EthanH.born=1970 +MERGE (RickY:Person {name:'Rick Yune'}) ON CREATE SET RickY.born=1971 +MERGE (JamesC:Person {name:'James Cromwell'}) ON CREATE SET JamesC.born=1940 +MERGE (ScottH:Person {name:'Scott Hicks'}) ON CREATE SET ScottH.born=1953 +MERGE (MaxS:Person {name:'Max von Sydow'}) ON CREATE SET MaxS.born=1929 + +MERGE (EthanH)-[:ACTED_IN {roles:['Ishmael Chambers']}]->(SnowFallingonCedars) +MERGE (RickY)-[:ACTED_IN {roles:['Kazuo Miyamoto']}]->(SnowFallingonCedars) +MERGE (MaxS)-[:ACTED_IN {roles:['Nels Gudmundsson']}]->(SnowFallingonCedars) +MERGE (JamesC)-[:ACTED_IN {roles:['Judge Fielding']}]->(SnowFallingonCedars) +MERGE (ScottH)-[:DIRECTED]->(SnowFallingonCedars); + +MERGE (YouveGotMail:Movie {title:'You\'ve Got Mail'}) ON CREATE SET YouveGotMail.released=1998, YouveGotMail.tagline='At odds in life... in love on-line.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (GregK:Person {name:'Greg Kinnear'}) ON CREATE SET GregK.born=1963 +MERGE (ParkerP:Person {name:'Parker Posey'}) ON CREATE SET ParkerP.born=1968 +MERGE (DaveC:Person {name:'Dave Chappelle'}) ON CREATE SET DaveC.born=1973 +MERGE (SteveZ:Person {name:'Steve Zahn'}) ON CREATE SET SteveZ.born=1967 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail) +MERGE (MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail) +MERGE (GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail) +MERGE (ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail) +MERGE (DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail) +MERGE (SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail) +MERGE (NoraE)-[:DIRECTED]->(YouveGotMail); + +MERGE (SleeplessInSeattle:Movie {title:'Sleepless in Seattle'}) ON CREATE SET SleeplessInSeattle.released=1993, SleeplessInSeattle.tagline='What if someone you never met, someone you never saw, someone you never knew was the only someone for you?' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (RitaW:Person {name:'Rita Wilson'}) ON CREATE SET RitaW.born=1956 +MERGE (BillPull:Person {name:'Bill Pullman'}) ON CREATE SET BillPull.born=1953 +MERGE (VictorG:Person {name:'Victor Garber'}) ON CREATE SET VictorG.born=1949 +MERGE (RosieO:Person {name:'Rosie O\'Donnell'}) ON CREATE SET RosieO.born=1962 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (TomH)-[:ACTED_IN {roles:['Sam Baldwin']}]->(SleeplessInSeattle) +MERGE (MegR)-[:ACTED_IN {roles:['Annie Reed']}]->(SleeplessInSeattle) +MERGE (RitaW)-[:ACTED_IN {roles:['Suzy']}]->(SleeplessInSeattle) +MERGE (BillPull)-[:ACTED_IN {roles:['Walter']}]->(SleeplessInSeattle) +MERGE (VictorG)-[:ACTED_IN {roles:['Greg']}]->(SleeplessInSeattle) +MERGE (RosieO)-[:ACTED_IN {roles:['Becky']}]->(SleeplessInSeattle) +MERGE (NoraE)-[:DIRECTED]->(SleeplessInSeattle); + +MERGE (JoeVersustheVolcano:Movie {title:'Joe Versus the Volcano'}) ON CREATE SET JoeVersustheVolcano.released=1990, JoeVersustheVolcano.tagline='A story of love, lava and burning desire.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (JohnS:Person {name:'John Patrick Stanley'}) ON CREATE SET JohnS.born=1950 +MERGE (Nathan:Person {name:'Nathan Lane'}) ON CREATE SET Nathan.born=1956 + +MERGE (TomH)-[:ACTED_IN {roles:['Joe Banks']}]->(JoeVersustheVolcano) +MERGE (MegR)-[:ACTED_IN {roles:['DeDe', 'Angelica Graynamore', 'Patricia Graynamore']}]->(JoeVersustheVolcano) +MERGE (Nathan)-[:ACTED_IN {roles:['Baw']}]->(JoeVersustheVolcano) +MERGE (JohnS)-[:DIRECTED]->(JoeVersustheVolcano); + +MERGE (WhenHarryMetSally:Movie {title:'When Harry Met Sally'}) ON CREATE SET WhenHarryMetSally.released=1998, WhenHarryMetSally.tagline='Can two friends sleep together and still love each other in the morning?' + +MERGE (MegR:Person {name:'Meg Ryan'}) ON CREATE SET MegR.born=1961 +MERGE (BillyC:Person {name:'Billy Crystal'}) ON CREATE SET BillyC.born=1948 +MERGE (CarrieF:Person {name:'Carrie Fisher'}) ON CREATE SET CarrieF.born=1956 +MERGE (BrunoK:Person {name:'Bruno Kirby'}) ON CREATE SET BrunoK.born=1949 +MERGE (RobR:Person {name:'Rob Reiner'}) ON CREATE SET RobR.born=1947 +MERGE (NoraE:Person {name:'Nora Ephron'}) ON CREATE SET NoraE.born=1941 + +MERGE (BillyC)-[:ACTED_IN {roles:['Harry Burns']}]->(WhenHarryMetSally) +MERGE (MegR)-[:ACTED_IN {roles:['Sally Albright']}]->(WhenHarryMetSally) +MERGE (CarrieF)-[:ACTED_IN {roles:['Marie']}]->(WhenHarryMetSally) +MERGE (BrunoK)-[:ACTED_IN {roles:['Jess']}]->(WhenHarryMetSally) +MERGE (RobR)-[:DIRECTED]->(WhenHarryMetSally) +MERGE (RobR)-[:PRODUCED]->(WhenHarryMetSally) +MERGE (NoraE)-[:PRODUCED]->(WhenHarryMetSally) +MERGE (NoraE)-[:WROTE]->(WhenHarryMetSally); + +MERGE (ThatThingYouDo:Movie {title:'That Thing You Do'}) ON CREATE SET ThatThingYouDo.released=1996, ThatThingYouDo.tagline='In every life there comes a time when that thing you dream becomes that thing you do' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (LivT:Person {name:'Liv Tyler'}) ON CREATE SET LivT.born=1977 +MERGE (Charlize:Person {name:'Charlize Theron'}) ON CREATE SET Charlize.born=1975 + +MERGE (TomH)-[:ACTED_IN {roles:['Mr. White']}]->(ThatThingYouDo) +MERGE (LivT)-[:ACTED_IN {roles:['Faye Dolan']}]->(ThatThingYouDo) +MERGE (Charlize)-[:ACTED_IN {roles:['Tina']}]->(ThatThingYouDo) +MERGE (TomH)-[:DIRECTED]->(ThatThingYouDo); + +MERGE (TheReplacements:Movie {title:'The Replacements'}) ON CREATE SET TheReplacements.released=2000, TheReplacements.tagline='Pain heals, Chicks dig scars... Glory lasts forever' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Brooke:Person {name:'Brooke Langton'}) ON CREATE SET Brooke.born=1970 +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 +MERGE (Orlando:Person {name:'Orlando Jones'}) ON CREATE SET Orlando.born=1968 +MERGE (Howard:Person {name:'Howard Deutch'}) ON CREATE SET Howard.born=1950 + +MERGE (Keanu)-[:ACTED_IN {roles:['Shane Falco']}]->(TheReplacements) +MERGE (Brooke)-[:ACTED_IN {roles:['Annabelle Farrell']}]->(TheReplacements) +MERGE (Gene)-[:ACTED_IN {roles:['Jimmy McGinty']}]->(TheReplacements) +MERGE (Orlando)-[:ACTED_IN {roles:['Clifford Franklin']}]->(TheReplacements) +MERGE (Howard)-[:DIRECTED]->(TheReplacements); + +MERGE (RescueDawn:Movie {title:'RescueDawn'}) ON CREATE SET RescueDawn.released=2006, RescueDawn.tagline='Based on the extraordinary true story of one man\'s fight for freedom' + +MERGE (ChristianB:Person {name:'Christian Bale'}) ON CREATE SET ChristianB.born=1974 +MERGE (ZachG:Person {name:'Zach Grenier'}) ON CREATE SET ZachG.born=1954 +MERGE (MarshallB:Person {name:'Marshall Bell'}) ON CREATE SET MarshallB.born=1942 +MERGE (SteveZ:Person {name:'Steve Zahn'}) ON CREATE SET SteveZ.born=1967 +MERGE (WernerH:Person {name:'Werner Herzog'}) ON CREATE SET WernerH.born=1942 + +MERGE (MarshallB)-[:ACTED_IN {roles:['Admiral']}]->(RescueDawn) +MERGE (ChristianB)-[:ACTED_IN {roles:['Dieter Dengler']}]->(RescueDawn) +MERGE (ZachG)-[:ACTED_IN {roles:['Squad Leader']}]->(RescueDawn) +MERGE (SteveZ)-[:ACTED_IN {roles:['Duane']}]->(RescueDawn) +MERGE (WernerH)-[:DIRECTED]->(RescueDawn); + +MERGE (TheBirdcage:Movie {title:'The Birdcage'}) ON CREATE SET TheBirdcage.released=1996, TheBirdcage.tagline='Come as you are' + +MERGE (MikeN:Person {name:'Mike Nichols'}) ON CREATE SET MikeN.born=1931 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (Nathan:Person {name:'Nathan Lane'}) ON CREATE SET Nathan.born=1956 +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 + +MERGE (Robin)-[:ACTED_IN {roles:['Armand Goldman']}]->(TheBirdcage) +MERGE (Nathan)-[:ACTED_IN {roles:['Albert Goldman']}]->(TheBirdcage) +MERGE (Gene)-[:ACTED_IN {roles:['Sen. Kevin Keeley']}]->(TheBirdcage) +MERGE (MikeN)-[:DIRECTED]->(TheBirdcage); + +MERGE (Unforgiven:Movie {title:'Unforgiven'}) ON CREATE SET Unforgiven.released=1992, Unforgiven.tagline='It\'s a hell of a thing, killing a man' + +MERGE (Gene:Person {name:'Gene Hackman'}) ON CREATE SET Gene.born=1930 +MERGE (RichardH:Person {name:'Richard Harris'}) ON CREATE SET RichardH.born=1930 +MERGE (ClintE:Person {name:'Clint Eastwood'}) ON CREATE SET ClintE.born=1930 + +MERGE (RichardH)-[:ACTED_IN {roles:['English Bob']}]->(Unforgiven) +MERGE (ClintE)-[:ACTED_IN {roles:['Bill Munny']}]->(Unforgiven) +MERGE (Gene)-[:ACTED_IN {roles:['Little Bill Daggett']}]->(Unforgiven) +MERGE (ClintE)-[:DIRECTED]->(Unforgiven); + +MERGE (JohnnyMnemonic:Movie {title:'Johnny Mnemonic'}) ON CREATE SET JohnnyMnemonic.released=1995, JohnnyMnemonic.tagline='The hottest data on earth. In the coolest head in town' + +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 +MERGE (Takeshi:Person {name:'Takeshi Kitano'}) ON CREATE SET Takeshi.born=1947 +MERGE (Dina:Person {name:'Dina Meyer'}) ON CREATE SET Dina.born=1968 +MERGE (IceT:Person {name:'Ice-T'}) ON CREATE SET IceT.born=1958 +MERGE (RobertL:Person {name:'Robert Longo'}) ON CREATE SET RobertL.born=1953 + +MERGE (Keanu)-[:ACTED_IN {roles:['Johnny Mnemonic']}]->(JohnnyMnemonic) +MERGE (Takeshi)-[:ACTED_IN {roles:['Takahashi']}]->(JohnnyMnemonic) +MERGE (Dina)-[:ACTED_IN {roles:['Jane']}]->(JohnnyMnemonic) +MERGE (IceT)-[:ACTED_IN {roles:['J-Bone']}]->(JohnnyMnemonic) +MERGE (RobertL)-[:DIRECTED]->(JohnnyMnemonic); + +MERGE (CloudAtlas:Movie {title:'Cloud Atlas'}) ON CREATE SET CloudAtlas.released=2012, CloudAtlas.tagline='Everything is connected' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (HalleB:Person {name:'Halle Berry'}) ON CREATE SET HalleB.born=1966 +MERGE (JimB:Person {name:'Jim Broadbent'}) ON CREATE SET JimB.born=1949 +MERGE (TomT:Person {name:'Tom Tykwer'}) ON CREATE SET TomT.born=1965 +MERGE (DavidMitchell:Person {name:'David Mitchell'}) ON CREATE SET DavidMitchell.born=1969 +MERGE (StefanArndt:Person {name:'Stefan Arndt'}) ON CREATE SET StefanArndt.born=1961 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 + +MERGE (TomH)-[:ACTED_IN {roles:['Zachry', 'Dr. Henry Goose', 'Isaac Sachs', 'Dermot Hoggins']}]->(CloudAtlas) +MERGE (Hugo)-[:ACTED_IN {roles:['Bill Smoke', 'Haskell Moore', 'Tadeusz Kesselring', 'Nurse Noakes', 'Boardman Mephi', 'Old Georgie']}]->(CloudAtlas) +MERGE (HalleB)-[:ACTED_IN {roles:['Luisa Rey', 'Jocasta Ayrs', 'Ovid', 'Meronym']}]->(CloudAtlas) +MERGE (JimB)-[:ACTED_IN {roles:['Vyvyan Ayrs', 'Captain Molyneux', 'Timothy Cavendish']}]->(CloudAtlas) +MERGE (TomT)-[:DIRECTED]->(CloudAtlas) +MERGE (LillyW)-[:DIRECTED]->(CloudAtlas) +MERGE (LanaW)-[:DIRECTED]->(CloudAtlas) +MERGE (DavidMitchell)-[:WROTE]->(CloudAtlas) +MERGE (StefanArndt)-[:PRODUCED]->(CloudAtlas); + +MERGE (TheDaVinciCode:Movie {title:'The Da Vinci Code'}) ON CREATE SET TheDaVinciCode.released=2006, TheDaVinciCode.tagline='Break The Codes' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (IanM:Person {name:'Ian McKellen'}) ON CREATE SET IanM.born=1939 +MERGE (AudreyT:Person {name:'Audrey Tautou'}) ON CREATE SET AudreyT.born=1976 +MERGE (PaulB:Person {name:'Paul Bettany'}) ON CREATE SET PaulB.born=1971 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (TomH)-[:ACTED_IN {roles:['Dr. Robert Langdon']}]->(TheDaVinciCode) +MERGE (IanM)-[:ACTED_IN {roles:['Sir Leight Teabing']}]->(TheDaVinciCode) +MERGE (AudreyT)-[:ACTED_IN {roles:['Sophie Neveu']}]->(TheDaVinciCode) +MERGE (PaulB)-[:ACTED_IN {roles:['Silas']}]->(TheDaVinciCode) +MERGE (RonH)-[:DIRECTED]->(TheDaVinciCode); + +MERGE (VforVendetta:Movie {title:'V for Vendetta'}) ON CREATE SET VforVendetta.released=2006, VforVendetta.tagline='Freedom! Forever!' + +MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960 +MERGE (NatalieP:Person {name:'Natalie Portman'}) ON CREATE SET NatalieP.born=1981 +MERGE (StephenR:Person {name:'Stephen Rea'}) ON CREATE SET StephenR.born=1946 +MERGE (JohnH:Person {name:'John Hurt'}) ON CREATE SET JohnH.born=1940 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Hugo)-[:ACTED_IN {roles:['V']}]->(VforVendetta) +MERGE (NatalieP)-[:ACTED_IN {roles:['Evey Hammond']}]->(VforVendetta) +MERGE (StephenR)-[:ACTED_IN {roles:['Eric Finch']}]->(VforVendetta) +MERGE (JohnH)-[:ACTED_IN {roles:['High Chancellor Adam Sutler']}]->(VforVendetta) +MERGE (BenM)-[:ACTED_IN {roles:['Dascomb']}]->(VforVendetta) +MERGE (JamesM)-[:DIRECTED]->(VforVendetta) +MERGE (LillyW)-[:PRODUCED]->(VforVendetta) +MERGE (LanaW)-[:PRODUCED]->(VforVendetta) +MERGE (JoelS)-[:PRODUCED]->(VforVendetta) +MERGE (LillyW)-[:WROTE]->(VforVendetta) +MERGE (LanaW)-[:WROTE]->(VforVendetta); + +MERGE (SpeedRacer:Movie {title:'Speed Racer'}) ON CREATE SET SpeedRacer.released=2008, SpeedRacer.tagline='Speed has no limits' + +MERGE (EmileH:Person {name:'Emile Hirsch'}) ON CREATE SET EmileH.born=1985 +MERGE (JohnG:Person {name:'John Goodman'}) ON CREATE SET JohnG.born=1960 +MERGE (SusanS:Person {name:'Susan Sarandon'}) ON CREATE SET SusanS.born=1946 +MERGE (MatthewF:Person {name:'Matthew Fox'}) ON CREATE SET MatthewF.born=1966 +MERGE (ChristinaR:Person {name:'Christina Ricci'}) ON CREATE SET ChristinaR.born=1980 +MERGE (Rain:Person {name:'Rain'}) ON CREATE SET Rain.born=1982 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (EmileH)-[:ACTED_IN {roles:['Speed Racer']}]->(SpeedRacer) +MERGE (JohnG)-[:ACTED_IN {roles:['Pops']}]->(SpeedRacer) +MERGE (SusanS)-[:ACTED_IN {roles:['Mom']}]->(SpeedRacer) +MERGE (MatthewF)-[:ACTED_IN {roles:['Racer X']}]->(SpeedRacer) +MERGE (ChristinaR)-[:ACTED_IN {roles:['Trixie']}]->(SpeedRacer) +MERGE (Rain)-[:ACTED_IN {roles:['Taejo Togokahn']}]->(SpeedRacer) +MERGE (BenM)-[:ACTED_IN {roles:['Cass Jones']}]->(SpeedRacer) +MERGE (LillyW)-[:DIRECTED]->(SpeedRacer) +MERGE (LanaW)-[:DIRECTED]->(SpeedRacer) +MERGE (LillyW)-[:WROTE]->(SpeedRacer) +MERGE (LanaW)-[:WROTE]->(SpeedRacer) +MERGE (JoelS)-[:PRODUCED]->(SpeedRacer); + +MERGE (NinjaAssassin:Movie {title:'Ninja Assassin'}) ON CREATE SET NinjaAssassin.released=2009, NinjaAssassin.tagline='Prepare to enter a secret world of assassins' + +MERGE (NaomieH:Person {name:'Naomie Harris'}) +MERGE (Rain:Person {name:'Rain'}) ON CREATE SET Rain.born=1982 +MERGE (BenM:Person {name:'Ben Miles'}) ON CREATE SET BenM.born=1967 +MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967 +MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965 +MERGE (RickY:Person {name:'Rick Yune'}) ON CREATE SET RickY.born=1971 +MERGE (JamesM:Person {name:'James Marshall'}) ON CREATE SET JamesM.born=1967 +MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952 + +MERGE (Rain)-[:ACTED_IN {roles:['Raizo']}]->(NinjaAssassin) +MERGE (NaomieH)-[:ACTED_IN {roles:['Mika Coretti']}]->(NinjaAssassin) +MERGE (RickY)-[:ACTED_IN {roles:['Takeshi']}]->(NinjaAssassin) +MERGE (BenM)-[:ACTED_IN {roles:['Ryan Maslow']}]->(NinjaAssassin) +MERGE (JamesM)-[:DIRECTED]->(NinjaAssassin) +MERGE (LillyW)-[:PRODUCED]->(NinjaAssassin) +MERGE (LanaW)-[:PRODUCED]->(NinjaAssassin) +MERGE (JoelS)-[:PRODUCED]->(NinjaAssassin); + +MERGE (TheGreenMile:Movie {title:'The Green Mile'}) ON CREATE SET TheGreenMile.released=1999, TheGreenMile.tagline='Walk a mile you\'ll never forget.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (JamesC:Person {name:'James Cromwell'}) ON CREATE SET JamesC.born=1940 +MERGE (BonnieH:Person {name:'Bonnie Hunt'}) ON CREATE SET BonnieH.born=1961 +MERGE (MichaelD:Person {name:'Michael Clarke Duncan'}) ON CREATE SET MichaelD.born=1957 +MERGE (DavidM:Person {name:'David Morse'}) ON CREATE SET DavidM.born=1953 +MERGE (SamR:Person {name:'Sam Rockwell'}) ON CREATE SET SamR.born=1968 +MERGE (GaryS:Person {name:'Gary Sinise'}) ON CREATE SET GaryS.born=1955 +MERGE (PatriciaC:Person {name:'Patricia Clarkson'}) ON CREATE SET PatriciaC.born=1959 +MERGE (FrankD:Person {name:'Frank Darabont'}) ON CREATE SET FrankD.born=1959 + +MERGE (TomH)-[:ACTED_IN {roles:['Paul Edgecomb']}]->(TheGreenMile) +MERGE (MichaelD)-[:ACTED_IN {roles:['John Coffey']}]->(TheGreenMile) +MERGE (DavidM)-[:ACTED_IN {roles:['Brutus "Brutal" Howell']}]->(TheGreenMile) +MERGE (BonnieH)-[:ACTED_IN {roles:['Jan Edgecomb']}]->(TheGreenMile) +MERGE (JamesC)-[:ACTED_IN {roles:['Warden Hal Moores']}]->(TheGreenMile) +MERGE (SamR)-[:ACTED_IN {roles:['"Wild Bill" Wharton']}]->(TheGreenMile) +MERGE (GaryS)-[:ACTED_IN {roles:['Burt Hammersmith']}]->(TheGreenMile) +MERGE (PatriciaC)-[:ACTED_IN {roles:['Melinda Moores']}]->(TheGreenMile) +MERGE (FrankD)-[:DIRECTED]->(TheGreenMile); + +MERGE (FrostNixon:Movie {title:'Frost/Nixon'}) ON CREATE SET FrostNixon.released=2008, FrostNixon.tagline='400 million people were waiting for the truth.' + +MERGE (FrankL:Person {name:'Frank Langella'}) ON CREATE SET FrankL.born=1938 +MERGE (MichaelS:Person {name:'Michael Sheen'}) ON CREATE SET MichaelS.born=1969 +MERGE (OliverP:Person {name:'Oliver Platt'}) ON CREATE SET OliverP.born=1960 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (SamR:Person {name:'Sam Rockwell'}) ON CREATE SET SamR.born=1968 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (FrankL)-[:ACTED_IN {roles:['Richard Nixon']}]->(FrostNixon) +MERGE (MichaelS)-[:ACTED_IN {roles:['David Frost']}]->(FrostNixon) +MERGE (KevinB)-[:ACTED_IN {roles:['Jack Brennan']}]->(FrostNixon) +MERGE (OliverP)-[:ACTED_IN {roles:['Bob Zelnick']}]->(FrostNixon) +MERGE (SamR)-[:ACTED_IN {roles:['James Reston, Jr.']}]->(FrostNixon) +MERGE (RonH)-[:DIRECTED]->(FrostNixon); + +MERGE (Hoffa:Movie {title:'Hoffa'}) ON CREATE SET Hoffa.released=1992, Hoffa.tagline='He didn\'t want law. He wanted justice.' + +MERGE (DannyD:Person {name:'Danny DeVito'}) ON CREATE SET DannyD.born=1944 +MERGE (JohnR:Person {name:'John C. Reilly'}) ON CREATE SET JohnR.born=1965 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (JTW:Person {name:'J.T. Walsh'}) ON CREATE SET JTW.born=1943 + +MERGE (JackN)-[:ACTED_IN {roles:['Hoffa']}]->(Hoffa) +MERGE (DannyD)-[:ACTED_IN {roles:['Robert "Bobby" Ciaro']}]->(Hoffa) +MERGE (JTW)-[:ACTED_IN {roles:['Frank Fitzsimmons']}]->(Hoffa) +MERGE (JohnR)-[:ACTED_IN {roles:['Peter "Pete" Connelly']}]->(Hoffa) +MERGE (DannyD)-[:DIRECTED]->(Hoffa); + +MERGE (Apollo13:Movie {title:'Apollo 13'}) ON CREATE SET Apollo13.released=1995, Apollo13.tagline='Houston, we have a problem.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (EdH:Person {name:'Ed Harris'}) ON CREATE SET EdH.born=1950 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 +MERGE (KevinB:Person {name:'Kevin Bacon'}) ON CREATE SET KevinB.born=1958 +MERGE (GaryS:Person {name:'Gary Sinise'}) ON CREATE SET GaryS.born=1955 +MERGE (RonH:Person {name:'Ron Howard'}) ON CREATE SET RonH.born=1954 + +MERGE (TomH)-[:ACTED_IN {roles:['Jim Lovell']}]->(Apollo13) +MERGE (KevinB)-[:ACTED_IN {roles:['Jack Swigert']}]->(Apollo13) +MERGE (EdH)-[:ACTED_IN {roles:['Gene Kranz']}]->(Apollo13) +MERGE (BillPax)-[:ACTED_IN {roles:['Fred Haise']}]->(Apollo13) +MERGE (GaryS)-[:ACTED_IN {roles:['Ken Mattingly']}]->(Apollo13) +MERGE (RonH)-[:DIRECTED]->(Apollo13); + +MERGE (Twister:Movie {title:'Twister'}) ON CREATE SET Twister.released=1996, Twister.tagline='Don\'t Breathe. Don\'t Look Back.' + +MERGE (PhilipH:Person {name:'Philip Seymour Hoffman'}) ON CREATE SET PhilipH.born=1967 +MERGE (JanB:Person {name:'Jan de Bont'}) ON CREATE SET JanB.born=1943 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (ZachG:Person {name:'Zach Grenier'}) ON CREATE SET ZachG.born=1954 + +MERGE (BillPax)-[:ACTED_IN {roles:['Bill Harding']}]->(Twister) +MERGE (HelenH)-[:ACTED_IN {roles:['Dr. Jo Harding']}]->(Twister) +MERGE (ZachG)-[:ACTED_IN {roles:['Eddie']}]->(Twister) +MERGE (PhilipH)-[:ACTED_IN {roles:['Dustin "Dusty" Davis']}]->(Twister) +MERGE (JanB)-[:DIRECTED]->(Twister); + +MERGE (CastAway:Movie {title:'Cast Away'}) ON CREATE SET CastAway.released=2000, CastAway.tagline='At the edge of the world, his journey begins.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (HelenH:Person {name:'Helen Hunt'}) ON CREATE SET HelenH.born=1963 +MERGE (RobertZ:Person {name:'Robert Zemeckis'}) ON CREATE SET RobertZ.born=1951 + +MERGE (TomH)-[:ACTED_IN {roles:['Chuck Noland']}]->(CastAway) +MERGE (HelenH)-[:ACTED_IN {roles:['Kelly Frears']}]->(CastAway) +MERGE (RobertZ)-[:DIRECTED]->(CastAway); + +MERGE (OneFlewOvertheCuckoosNest:Movie {title:'One Flew Over the Cuckoo\'s Nest'}) ON CREATE SET OneFlewOvertheCuckoosNest.released=1975, OneFlewOvertheCuckoosNest.tagline='If he\'s crazy, what does that make you?' + +MERGE (MilosF:Person {name:'Milos Forman'}) ON CREATE SET MilosF.born=1932 +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DannyD:Person {name:'Danny DeVito'}) ON CREATE SET DannyD.born=1944 + +MERGE (JackN)-[:ACTED_IN {roles:['Randle McMurphy']}]->(OneFlewOvertheCuckoosNest) +MERGE (DannyD)-[:ACTED_IN {roles:['Martini']}]->(OneFlewOvertheCuckoosNest) +MERGE (MilosF)-[:DIRECTED]->(OneFlewOvertheCuckoosNest); + +MERGE (SomethingsGottaGive:Movie {title:'Something\'s Gotta Give'}) ON CREATE SET SomethingsGottaGive.released=2003 + +MERGE (JackN:Person {name:'Jack Nicholson'}) ON CREATE SET JackN.born=1937 +MERGE (DianeK:Person {name:'Diane Keaton'}) ON CREATE SET DianeK.born=1946 +MERGE (NancyM:Person {name:'Nancy Meyers'}) ON CREATE SET NancyM.born=1949 +MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964 + +MERGE (JackN)-[:ACTED_IN {roles:['Harry Sanborn']}]->(SomethingsGottaGive) +MERGE (DianeK)-[:ACTED_IN {roles:['Erica Barry']}]->(SomethingsGottaGive) +MERGE (Keanu)-[:ACTED_IN {roles:['Julian Mercer']}]->(SomethingsGottaGive) +MERGE (NancyM)-[:DIRECTED]->(SomethingsGottaGive) +MERGE (NancyM)-[:PRODUCED]->(SomethingsGottaGive) +MERGE (NancyM)-[:WROTE]->(SomethingsGottaGive); + +MERGE (BicentennialMan:Movie {title:'Bicentennial Man'}) ON CREATE SET BicentennialMan.released=1999, BicentennialMan.tagline='One robot\'s 200 year journey to become an ordinary man.' + +MERGE (ChrisC:Person {name:'Chris Columbus'}) ON CREATE SET ChrisC.born=1958 +MERGE (Robin:Person {name:'Robin Williams'}) ON CREATE SET Robin.born=1951 +MERGE (OliverP:Person {name:'Oliver Platt'}) ON CREATE SET OliverP.born=1960 + +MERGE (Robin)-[:ACTED_IN {roles:['Andrew Marin']}]->(BicentennialMan) +MERGE (OliverP)-[:ACTED_IN {roles:['Rupert Burns']}]->(BicentennialMan) +MERGE (ChrisC)-[:DIRECTED]->(BicentennialMan); + +MERGE (CharlieWilsonsWar:Movie {title:'Charlie Wilson\'s War'}) ON CREATE SET CharlieWilsonsWar.released=2007, CharlieWilsonsWar.tagline='A stiff drink. A little mascara. A lot of nerve. Who said they couldn\'t bring down the Soviet empire.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (PhilipH:Person {name:'Philip Seymour Hoffman'}) ON CREATE SET PhilipH.born=1967 +MERGE (JuliaR:Person {name:'Julia Roberts'}) ON CREATE SET JuliaR.born=1967 +MERGE (MikeN:Person {name:'Mike Nichols'}) ON CREATE SET MikeN.born=1931 + +MERGE (TomH)-[:ACTED_IN {roles:['Rep. Charlie Wilson']}]->(CharlieWilsonsWar) +MERGE (JuliaR)-[:ACTED_IN {roles:['Joanne Herring']}]->(CharlieWilsonsWar) +MERGE (PhilipH)-[:ACTED_IN {roles:['Gust Avrakotos']}]->(CharlieWilsonsWar) +MERGE (MikeN)-[:DIRECTED]->(CharlieWilsonsWar); + +MERGE (ThePolarExpress:Movie {title:'The Polar Express'}) ON CREATE SET ThePolarExpress.released=2004, ThePolarExpress.tagline='This Holiday Season... Believe' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (RobertZ:Person {name:'Robert Zemeckis'}) ON CREATE SET RobertZ.born=1951 + +MERGE (TomH)-[:ACTED_IN {roles:['Hero Boy', 'Father', 'Conductor', 'Hobo', 'Scrooge', 'Santa Claus']}]->(ThePolarExpress) +MERGE (RobertZ)-[:DIRECTED]->(ThePolarExpress); + +MERGE (ALeagueofTheirOwn:Movie {title:'A League of Their Own'}) ON CREATE SET ALeagueofTheirOwn.released=1992, ALeagueofTheirOwn.tagline='Once in a lifetime you get a chance to do something different.' + +MERGE (TomH:Person {name:'Tom Hanks'}) ON CREATE SET TomH.born=1956 +MERGE (Madonna:Person {name:'Madonna'}) ON CREATE SET Madonna.born=1954 +MERGE (GeenaD:Person {name:'Geena Davis'}) ON CREATE SET GeenaD.born=1956 +MERGE (LoriP:Person {name:'Lori Petty'}) ON CREATE SET LoriP.born=1963 +MERGE (PennyM:Person {name:'Penny Marshall'}) ON CREATE SET PennyM.born=1943 +MERGE (RosieO:Person {name:'Rosie O\'Donnell'}) ON CREATE SET RosieO.born=1962 +MERGE (BillPax:Person {name:'Bill Paxton'}) ON CREATE SET BillPax.born=1955 + +MERGE (TomH)-[:ACTED_IN {roles:['Jimmy Dugan']}]->(ALeagueofTheirOwn) +MERGE (GeenaD)-[:ACTED_IN {roles:['Dottie Hinson']}]->(ALeagueofTheirOwn) +MERGE (LoriP)-[:ACTED_IN {roles:['Kit Keller']}]->(ALeagueofTheirOwn) +MERGE (RosieO)-[:ACTED_IN {roles:['Doris Murphy']}]->(ALeagueofTheirOwn) +MERGE (Madonna)-[:ACTED_IN {roles:['"All the Way" Mae Mordabito']}]->(ALeagueofTheirOwn) +MERGE (BillPax)-[:ACTED_IN {roles:['Bob Hinson']}]->(ALeagueofTheirOwn) +MERGE (PennyM)-[:DIRECTED]->(ALeagueofTheirOwn); + + +MATCH (CloudAtlas:Movie {title:'Cloud Atlas'}) +MATCH (TheReplacements:Movie {title:'The Replacements'}) +MATCH (Unforgiven:Movie {title:'Unforgiven'}) +MATCH (TheBirdcage:Movie {title:'The Birdcage'}) +MATCH (TheDaVinciCode:Movie {title:'The Da Vinci Code'}) +MATCH (JerryMaguire:Movie {title:'Jerry Maguire'}) + +MERGE (PaulBlythe:Person {name:'Paul Blythe'}) +MERGE (AngelaScope:Person {name:'Angela Scope'}) +MERGE (JessicaThompson:Person {name:'Jessica Thompson'}) +MERGE (JamesThompson:Person {name:'James Thompson'}) + +MERGE (JamesThompson)-[:FOLLOWS]->(JessicaThompson) +MERGE (AngelaScope)-[:FOLLOWS]->(JessicaThompson) +MERGE (PaulBlythe)-[:FOLLOWS]->(AngelaScope) + +MERGE (JessicaThompson)-[:REVIEWED {summary:'An amazing journey', rating:95}]->(CloudAtlas) +MERGE (JessicaThompson)-[:REVIEWED {summary:'Silly, but fun', rating:65}]->(TheReplacements) +MERGE (JamesThompson)-[:REVIEWED {summary:'The coolest football movie ever', rating:100}]->(TheReplacements) +MERGE (AngelaScope)-[:REVIEWED {summary:'Pretty funny at times', rating:62}]->(TheReplacements) +MERGE (JessicaThompson)-[:REVIEWED {summary:'Dark, but compelling', rating:85}]->(Unforgiven) +MERGE (JessicaThompson)-[:REVIEWED {summary:"Slapstick redeemed only by the Robin Williams and Gene Hackman's stellar performances", rating:45}]->(TheBirdcage) +MERGE (JessicaThompson)-[:REVIEWED {summary:'A solid romp', rating:68}]->(TheDaVinciCode) +MERGE (JamesThompson)-[:REVIEWED {summary:'Fun, but a little far fetched', rating:65}]->(TheDaVinciCode) +MERGE (JessicaThompson)-[:REVIEWED {summary:'You had me at Jerry', rating:92}]->(JerryMaguire); +---- + +To see a subset of the data you just created, run the following statement + +[source,cypher] +---- +MATCH (person:Person {name: 'Tom Hanks'}) +MATCH path = (person)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +RETURN path; +---- + +In the next step you will learn about indexes and constraints. + +== Indexes and constraints + +To aid query performance, you can add indexes to your data. +The dataset you create in this guide is very small, but it is good practice to use indexes as they can greatly improve query performance when the datasets are larger. + +Run the follwing to see the existing indexes in the database: + +[source, cypher] +---- +SHOW INDEXES +---- + +As you can see, there are already some indexes present and this is a result of the two first lines in the `MERGE` clause in the previous step: + +[source,cypher] +---- +CREATE CONSTRAINT movie_title IF NOT EXISTS FOR (m:Movie) REQUIRE m.title IS UNIQUE; +CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE; +---- + +See link:https://neo4j.com/docs/cypher-manual/current/constraints/[Cypher Manual -> Constraints^] for more information on constraints. + +You can add indexes on any of your properties and if you know beforehand which ones you will use the most, it makes sense to add an index on these. +In the Movies dataset, you may be interested in both the year people were born and the year movies were released. +Run the following to add indexes on these properties: + +[source,cypher] +---- +CREATE INDEX person_born IF NOT EXISTS FOR (p:Person) ON (p.born); +CREATE INDEX movie_released IF NOT EXISTS FOR (m:Movie) ON (m.released) +---- + +See link:https://neo4j.com/docs/cypher-manual/current/indexes/[Cypher Manual -> Indexes^] to learn more about indexes. + +In the next step, you will look for nodes and their properties. + +== Find nodes + +To start, can you find the actor _Tom Hanks_ which is a `Person` in our graph? + +Run the following query: + +[source,cypher] +---- +MATCH (p:Person {name: "Tom Hanks"}) +RETURN p +---- + +Next, can you find a `Movie` called _Cloud Atlas_? + +[%collapsible] +.Reveal the solution +==== +[source,cypher] +---- +MATCH (m:Movie {title:"Cloud Atlas"}) +RETURN m +---- +==== + +Similarly, you can find all the people (nodes with the `Person` label) in the graph, but limit the returned number to ten: + +[source,cypher] +---- +MATCH (p:Person) +RETURN p.name LIMIT 10 +---- + +[TIP] +==== +Try to remove the property key `.name` from the RETURN clause and see the difference. + +[source,cypher] +---- +MATCH (p:Person) +RETURN p LIMIT 10 +---- +==== + +If you want to find movies released in a specific timespan, you can add conditions by using `WHERE`: + +[source,cypher] +---- +MATCH (m:Movie) WHERE m.released >= 1990 AND m.released < 2000 +RETURN m.title, m.released +---- + +In the next step you will look for patterns in the graph. + +== Find patterns + +A pattern in the graph is a specific arrangement of nodes and relationships that can be matched in the graph. +To find which movies Tom Hanks have acted in, specify the pattern as follows: + +NOTE: You might need to switch back to the "Graph" view. + +[source,cypher] +---- +MATCH (p:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m:Movie) +RETURN m.title +---- + +Can you specify a pattern to find who directed _Cloud Atlas_? +Hint: The relationship between a person who is a director and the movie they directed is `:DIRECTED`. + +[%collapsible] +.Reveal the solution +==== +[source,cypher] +---- +MATCH (m:Movie {title: "Cloud Atlas"})<-[:DIRECTED]-(director:Person) +RETURN director.name +---- +==== + +If you extend the length of the pattern, you can find co-actors: + +[source,cypher] +---- +MATCH (:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) +RETURN coActors.name +---- + +If you want to see this all as a graph, the easiest way is to return the `path` of your patterns. + +[source,cypher] +---- +MATCH path= (:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) +RETURN path +---- + +You can return _all_ properties if you are not sure exactly what you are looking for: + +[source,cypher] +---- +MATCH (p:Person)-[relationship]-(:Movie {title: "Cloud Atlas"}) +RETURN p.name, type(relationship), relationship +---- + +This query returns a list of Person-nodes that are connected to the Movie-node _Cloud Atlas_, the relationship type, and _all_ the properties on the relationship. + +In the next step, you are going to prove whether the Hollywood version of six degrees of separation is true in your dataset. + +== Six degrees of Kevin Bacon + +You may have heard about the concept that any two people on Earth are six or fewer connections apart. +In Hollywood, this is said to be true for Kevin Bacon and any other actor. + +The following query lets you see all movies _and_ people up to six hops away from Kevin Bacon: + +[source,cypher] +---- +MATCH (:Person {name:"Kevin Bacon"})-[*1..6]-(n) +RETURN DISTINCT n +---- + +But is it true that every actor is really connected to Kevin Bacon? + +Cypher has a built-in algorithm for this, "Shortest Path" and it looks like this: + +[source,cypher] +---- +MATCH path=shortestPath( + (:Person {name:"Kevin Bacon"})-[*]-(:Person {name:"Meg Ryan"}) +) +RETURN path, length(path) / 2 as distance +---- + +You can try to change _Meg Ryan_ out for any other actor in the dataset and see if you can find one farther away than six hops. + +In the next step, you are going to recommend new colleagues for Tom Hanks. + +== Recommendations + +A basic recommendation approach is to find connections past an immediate neighborhood of nodes which are themselves well-connected. +For Tom Hanks, this means to find actors who he has yet to work with, but who has worked with his previous co-actors. +Then you need to find someone who can introduce Tom Hanks to his potential new co-actor. + +To find a list of potential co-actors, run the following query: + +[source,cypher] +---- +MATCH (p:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), + (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors) +WHERE NOT exists { (p)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) } AND p <> cocoActors +RETURN cocoActors.name AS recommended, count(*) AS score ORDER BY score DESC +---- + +The `WHERE` part of the query ensures that you don't get actors who already worked with Tom Hanks and nor Tom Hanks himself. +The results are ordered by the number of co-occurrences they have in common. + +Now, if you think it would be a good idea for Tom Hanks and Keanu Reeves to do a movie together, who would be able to introduce them, and in which movies have they acted jointly? + +[source,cypher] +---- +MATCH (p1:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), + (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(p2:Person {name:"Keanu Reeves"}) +RETURN DISTINCT coActors.name AS matchmaker +---- + +In the last step, you are going to clean up your database by deleting the data you have created. + +== Clean up + +This dataset is fun to experiment with, but once you are done, you can **delete everything** with the following: + +[source,cypher] +---- +MATCH (n:Person|Movie) +DETACH DELETE n +---- + +[WARNING] +==== +This does in fact permanently delete the nodes and relationships in this database, so use with caution. +==== + +You can verify that there is nothing left by a simple query: + +[source,cypher] +---- +MATCH () +RETURN count (*) +---- + +Well done! + +If you want to learn more about Cypher, see the following: + +* https://graphacademy.neo4j.com/categories/cypher/[Free Online Cypher Courses^] +* https://neo4j.com/docs/getting-started/cypher-intro/[Cypher Getting Started^] +* https://neo4j.com/docs/cypher-manual/current/introduction/[Cypher Documentation^] +* https://neo4j.com/docs/cypher-cheat-sheet/[Cypher Cheat-Sheet^]. + + + diff --git a/documentation/query-upx.adoc b/documentation/query-upx.adoc new file mode 100644 index 0000000..520dbd6 --- /dev/null +++ b/documentation/query-upx.adoc @@ -0,0 +1,236 @@ += Learn basic Cypher in the Query tab of Neo4j Workspace + +== Query Guide + +This guide is the next step after you've completed _Get started_, _Data Importer_, and _Explore_. +You can follow this guide independently as well. + +It gives you an introduction to Cypher fundamentals and presents some more complex queries. +You will learn your way around the Query tool's UI so you can make the most of all it has to offer. + +Just like the previous guides, the Query guide uses the Northwind dataset. +If you have completed the Data Importer guide, you already have the data needed and can just skip past the next step. +If you are doing this guide independently, you need to import the dataset to run your queries on. +Just follow the instructions in the next step and you will be set up in a minute. + +== Load the Northwind dataset + +Again, if you already have completed the Data Importer guide, you can skip this step. +If not, then first navigate to _Import_: + +button::Go to Import[role=NX_TAB_NAV,tab=import] + +Use the button to load and map the data: + +button::Load the Northwind dataset[role=NX_IMPORT_LOAD,endpoint=https://raw.githubusercontent.com/neo4j-graph-examples/northwind/main/import/northwind-data-importer-mode-data.zip] + +Once that's all done, click highlight:import/import-run-import-button[Run import]. + +If you want to learn more about importing data, try the Importer guide. + +With the data imported, navigate back to the _Query_ tool and get started with learning Cypher: + +button::Go back to Query[role=NX_TAB_NAV,tab=query] + +== Get to know the database + +A good place to start is to take stock of what you have in your database. +You access _Database Information_ from the top of the sidebar. + +image::database-icon.png[] +//would be cool to replace this image with a highlight instead + +There you'll see how many nodes you have and all their labels, the number of relationships and their types, and also a list of all the property keys present in the database. + +A node can have multiple labels and the list shows _all_ labels in the database. + +Relationships on the other hand, can have only one type, but multiple relationships can exist between the same nodes. + +The list of property keys include both node properties and relationship properties. + +You can click any of the labels, types, or property keys to run a query that returns a sample of nodes and/or relationships that has that label, type, or property. + +For example, try click on the `Product` node label and you'll see this query populated and executed for you: + +[source,cypher] +---- +MATCH (n:Product) RETURN n LIMIT 25; +---- + +== Excecuting queries with graph results + +Central to the Query tool's UI is the Cypher editor on top where you write and run your queries and the list of result frames. + +When you _run_ any query, a result frame shows the query and its results, pushing previous ones down. + +Try it out by typing in and executing the following Cypher query: + +[source,cypher] +---- +MATCH path=(:Product)-[:PART_OF]->(c:Category) +WHERE c.categoryName = 'Produce' +RETURN path; +---- + +You can edit the query within the frame and run it again without creating a new result frame. + +The frame has two important views: _Graph_ and _Table_. (_Plan_ is for showing query plans and _RAW_ for the raw results). + +//highlight:query/result-view-graph[Result view] +//doesn't work + +// image::result-options.png[] +//would be cool to replace this with a highlight also + +The default view is graph if your query returns graph elements like nodes, relationships or paths. + +NOTE: Relationships are only shown if you return a path, or name and return the relationships as well as the nodes. + +Here you can see `Product` nodes with `PART_OF` relationships to the `Category` with name _Produce_. + +On the right side of the graph view you can see the properties panel with information about the entities in your graph. +You can click on any of them to change their styling, i.e. color, size, and caption, clicking on one element shows its attributes. + +== Showing tabular results + +If your query only returns scalar values (like strings or numbers), the result defaults to the table view and the graph view is not available. + +Change your query to: + +[source,cypher] +---- +MATCH (p:Product)-[:PART_OF]->(c:Category) +WHERE c.categoryName = 'Produce' +RETURN p.productName,c.categoryName; +---- + +The query uses _variables_, `c` and `p`, for the category and the product as you will want to refer to them later. + +[NOTE] +==== +If you prefix your query with `EXPLAIN` or `PROFILE` you can see a plan option for a visual query plan, which helps later with optimizations. +The RAW option shows the submitted query, the Neo4j server version and address, the result, and a summary. +==== + +== Use basic Cypher to answer questions + +// You should be familiar with the data model of the Northwind dataset if you have completed the _Data Import_ guide, otherwise you can still see it in the _Import_ tab since you downloaded it in a previous step. +For writing correct queries it is always good to know what your data looks like. +Besides the sidebar with the overview, a quick way to show the current graph schema is to `CALL` this procedure. + +[source, cypher] +---- +CALL db.schema.visualization() +---- + +Let's take a look at the different companies supplying Northwind with products and see which supplier provides products from which categories: + +[source, cypher] +---- +MATCH (s:Supplier)-->(:Product)-->(c:Category) +RETURN s.companyName as company, collect(distinct c.categoryName) as categories +---- + +This query finds _suppliers_ that _supply_ a _product_ which is _part of_ a _category_ and returns the company names and the categories they supply products from, in a table. +In cases where the same supplier supplies products from more than one category, the distinct category names are collected into a list, as you can see in the _categories_ column. + +Even though you specified the _Product_ node in the `MATCH` part of the query, no information about the actual product is returned since this is not included in the `RETURN` part. + +Maybe you are interested only in suppliers of a certain category, say _Condiments_: + +[source, cypher] +---- +MATCH (s:Supplier)-->(:Product)-->(c:Category) +WHERE c.categoryName = 'Condiments' +RETURN DISTINCT s.companyName as condimentsSuppliers +---- + +Since you are not interested in the `Product` nodes, nor the exact types of the relationships between the nodes here, you don't have to specify them. + +This is fairly basic, so let's move on to something a little more complex. + +== Write more advanced Cypher for problem-solving + +Assume that you want to see which product categories are typically co-ordered with other product categories and how frequently. + +This might help you understand which products to promote alongside others. + +[source, cypher] +---- +// which categories are the products of an order in +MATCH (o:Order)-[:ORDERS]->(:Product)-[:PART_OF]->(c:Category) +// retain same ordering of categories +WITH o, c ORDER BY c.categoryName +// aggregate categories by order into a list of names +WITH o, collect(DISTINCT c.categoryName) as categories +// only orders with more than one category +WHERE size(categories) > 1 +// count how frequently the pairings occur +RETURN categories, count(*) as freq +// order by frequency +ORDER BY freq DESC +LIMIT 50 +---- + +You can extend this and find customers who display similar purchasing patterns, i.e. which customers order similar products most frequently. + +The base question is the same, you just expand across the product to other customers. + +You find the "peer-groups" of our customers, which then can be used for product recommendations (people who bought X also bought) or segmentation into clusters of your customer base. + +[source, cypher] +---- +// pattern from customer purchasing products to another customer purchasing the same products +MATCH (c:Customer)-[:PURCHASED]->(:Order)-[:ORDERS]->(p:Product)<-[:ORDERS]-(:Order)<-[:PURCHASED]-(c2:Customer) +// don't want the same customer pair twice +WHERE c < c2 +// sort by the top-occuring products +WITH c, c2, p, count(*) as productOccurrence +ORDER BY productOccurrence DESC +// return customer pairs ranked by similarity and the top 5 products +RETURN c.companyName, c2.companyName, sum(productOccurrence) as similarity, collect(distinct p.productName)[0..5] as topProducts +ORDER BY similarity DESC LIMIT 10 +---- + +Now you could create relationships for all customers that score more than 50 in your similarity score and see how they cluster. + +[source,cypher] +---- +MATCH (c:Customer)-[:PURCHASED]->(:Order)-[:ORDERS]->(p:Product)<-[:ORDERS]-(:Order)<-[:PURCHASED]-(c2:Customer) +WHERE c < c2 +// find similar customers +WITH c, c2, count(*) as similarity +// with at least 50 shared product purchases +WHERE similarity > 50 +// create a relationship between the two without specifying direction +MERGE (c)-[sim:SIMILAR_TO]-(c2) +// set relationship weight from similairity +ON CREATE SET sim.weight = similarity +---- + +The new relationship shows up in your sidebar (after refresh at the bottom) and graph model and you can use it to show clusters of our customers. + +If you style the relationship `SIMILAR_TO` with the `weight` as caption you can see the strength of the similarity. + +[source,cypher] +---- +MATCH path=()-[:SIMILAR_TO]->() RETURN path +---- + +This should give you a good starting point to see the power of graph queries. + +You can learn more about Cypher here: + +* https://graphacademy.neo4j.com/categories/cypher/[Cypher Online Courses^] +* https://neo4j.com/docs/cypher-manual/current/introduction/[Cypher Manual^] +* https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise/[Cypher Cheat-Sheet^]. + + + + + + + + + + diff --git a/documentation/query.adoc b/documentation/query.adoc index 12ff90b..de5c7f3 100644 --- a/documentation/query.adoc +++ b/documentation/query.adoc @@ -67,7 +67,7 @@ Try it out by typing in and executing the following Cypher query: [source,cypher] ---- -MATCH path=(:Product)-[:PART_OF]->(c:Category) +MATCH path=(:Product)-[:PART_OF]->(c:Category) WHERE c.categoryName = 'Produce' RETURN path; ---- @@ -99,7 +99,7 @@ Change your query to: [source,cypher] ---- -MATCH (p:Product)-[:PART_OF]->(c:Category) +MATCH (p:Product)-[:PART_OF]->(c:Category) WHERE c.categoryName = 'Produce' RETURN p.productName,c.categoryName; ---- @@ -162,10 +162,10 @@ MATCH (o:Order)-[:ORDERS]->(:Product)-[:PART_OF]->(c:Category) // retain same ordering of categories WITH o, c ORDER BY c.categoryName // aggregate categories by order into a list of names -WITH o, collect(DISTINCT c.categoryName) as categories +WITH o, collect(DISTINCT c.categoryName) as categories // only orders with more than one category WHERE size(categories) > 1 -// count how frequently the pairings occurr +// count how frequently the pairings occur RETURN categories, count(*) as freq // order by frequency ORDER BY freq DESC @@ -185,7 +185,7 @@ MATCH (c:Customer)-[:PURCHASED]->(:Order)-[:ORDERS]->(p:Product)<-[:ORDERS]-(:Or // don't want the same customer pair twice WHERE c < c2 // sort by the top-occuring products -WITH c, c2, p, count(*) as productOccurrence +WITH c, c2, p, count(*) as productOccurrence ORDER BY productOccurrence DESC // return customer pairs ranked by similarity and the top 5 products RETURN c.companyName, c2.companyName, sum(productOccurrence) as similarity, collect(distinct p.productName)[0..5] as topProducts @@ -221,8 +221,8 @@ This should give you a good starting point to see the power of graph queries. You can learn more about Cypher here: -* https://graphacademy.neo4j.com/categories/cypher/[Cypher Online Courses^] -* https://neo4j.com/docs/cypher-manual/current/introduction/[Cypher Manual^] +* https://graphacademy.neo4j.com/categories/cypher/[Cypher Online Courses^] +* https://neo4j.com/docs/cypher-manual/current/introduction/[Cypher Manual^] * https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise/[Cypher Cheat-Sheet^]. diff --git a/documentation/workspace-params.adoc b/documentation/workspace-params.adoc index 9eac483..dfd3fc7 100644 --- a/documentation/workspace-params.adoc +++ b/documentation/workspace-params.adoc @@ -11,7 +11,14 @@ You can read more about parameters https://neo4j.com/docs/cypher-manual/current/ === Setting and Managing Parameters -Parameters are set and managed in Query using the `:param` command. +Parameters can be created and managed either via the parameters sidebar or by invoking the `:param` command in a Cypher editor. + +The Parameters sidebar provides dedicated UI inputs for most of the neo4j https://neo4j.com/docs/cypher-manual/current/values-and-types/property-structural-constructed/#property-types[property types]. +There are a few exceptions such as the https://neo4j.com/docs/cypher-manual/current/values-and-types/spatial/#spatial-values-point-type[Point] type and the setting of https://neo4j.com/docs/cypher-manual/current/values-and-types/property-structural-constructed/#constructed-types[constructed types]. +To support the setting of these types via the UI, there is also a special option of `evaluated` in the type dropdown. +This allows you to express any parameter type as you would using the right-hand part of the command syntax inlinecode:++:param pointParam => Point({x:1, y:1})++[], in this example `Point({x:1, y:1})` as the value to be evaluated. + +For types that are not supported by the UI, or indeed if you prefer working with commands, the `:param` command provides the ability to set and manage parameters. The following arguments are supported: * inlinecode:++:param list++[] or inlinecode:++:param++[] - Lists all parameters