├── README.adoc ├── meta ├── Home.adoc ├── HowTo.adoc ├── README.adoc └── Simple.adoc └── other ├── BankFraudDetection.adoc ├── NetworkDataCenterManagement1.adoc ├── SocialNetworkGraph.adoc ├── TVShowGraph.adoc ├── ThePublicationGraph.adoc ├── images ├── BankFraud-1.png ├── datacenter-management-1.PNG ├── network-inventory-cost-accounting-graph-1.PNG ├── social-network-graph-1.png ├── tv-show-graph-1.PNG └── tv-show-graph-2.PNG └── sarah.adoc /README.adoc: -------------------------------------------------------------------------------- 1 | == GraphGists 2 | 3 | This repo contains content for use at http://gist.neo4j.org/. 4 | 5 | 6 | -------------------------------------------------------------------------------- /meta/Home.adoc: -------------------------------------------------------------------------------- 1 | = What is the Neo4j GraphGist Project? = 2 | 3 | :neo4j-version: 2.1.0 4 | :author: Anders Nawroth 5 | :twitter: @nawroth 6 | :tags: domain:example 7 | 8 | image:https://dl.dropboxusercontent.com/u/14493611/neo4j-logo.png[] 9 | 10 | http://neo4j.com[Neo4j] GraphGists are an easy way to create and share documents containing not just prose, structure 11 | and pictures but most importantly **example graph models and use-cases** expressed in Neo4j's query language http://docs.neo4j.org/refcard/2.1/[Cypher]. 12 | 13 | These documents are written in AsciiDoc -- the simple, textual markup language -- and rendered in your browser as rich and interactive web pages that you 14 | can quickly evolve from describing simple howtos or questions to providing an extensive use-case specification. 15 | 16 | To see the expressive power of this approach, here are some winners of our past community competitions: 17 | 18 | == Examples 19 | [none] 20 | * **Identity and Access Management** link:./?4471127413fd724ed0a3[Entitlements and Access Control] by https://twitter.com/kennybastani[@kennybastani] 21 | * **Finance** link:./?github-neo4j-contrib%2Fgists%2F%2Fother%2FBankFraudDetection.adoc[Bank Fraud Detection] by https://twitter.com/kennybastani[@kennybastani] 22 | * **Sports** link:./?8019511[Alpine Skiing seasons] by https://twitter.com/pac_19[@pac_19] 23 | * **Life Science** link:./?7968633[Pharmaceutical Drugs and their Targets] by https://twitter.com/joshkunken[@joshkunken] 24 | * **Resources** link:./?8141937[Piping Water] by https://twitter.com/shaundaley1[@shaundaley1] 25 | * **Retail** link:./?8139605[Single Malt Scotch Whisky] by https://twitter.com/patbaumgartner[@patbaumgartner] 26 | * **Telecommunications** link:./?8526106[Amazon Web Services Global Infrastructure Graph] by https://twitter.com/aidanjcasey[@aidanjcasey] 27 | * **Infrastructure** link:./?8635758[Roads, Nodes and Automobiles] by http://www.jacqui.tk[@tekiegirl] 28 | * **Recommendation** link:./?8173017[Movie Recommendations with k-NN and Cosine Similarity] by http://twitter.com/_nicolemargaret[@_nicolemargaret] 29 | * **Fun** link:./?6506717[Chess Games and Positions] by https://twitter.com/wefreema[@wefreema] 30 | * **One hundred more** examples can be found in the https://github.com/neo4j-contrib/graphgist/wiki[GraphGist Collection] 31 | 32 | == Getting Started 33 | 34 | === Follow these easy steps 35 | 36 | . **Log into** your GitHub account 37 | . **Choose** one of the examples listed above, click the green **page source** button. 38 | . **Fork** the original GraphGist into your own account and **start to edit** the prose, images, setup and use-case Cypher queries. 39 | . **Paste** the Github Gist URL into the top right URL box of any GraphGist page and hit enter; your Gist will be loaded and rendered immediately. 40 | . **Reload** your GraphGist page whenever you made an update to your document. 41 | . **Share** your GraphGist with your colleagues, friends or us. 42 | Hit the submit link in the footer, when you are ready to get your t-shirt reward. 43 | 44 | ++++ 45 | 46 | ++++ 47 | 48 | 49 | === Setup a Graph to show you and your Likes 50 | 51 | //setup 52 | [source,cypher] 53 | ---- 54 | CREATE (you:Person {name:"You"})-[like:LIKE]->(us:Database:NoSql:Graph {name:"Neo4j" }) 55 | RETURN you, like, us 56 | ---- 57 | 58 | And render as a graph. 59 | 60 | //graph 61 | 62 | === Now query the graph to show all the things you like 63 | 64 | [source,cypher] 65 | ---- 66 | MATCH (you:Person {name:"You"})-[like:LIKE]->(liked) 67 | RETURN you.name AS who, type(like) AS how, liked.name AS what 68 | ---- 69 | 70 | And render as a table. 71 | 72 | //table 73 | 74 | NOTE: This document is a GraphGist itself, so you can use the green https://github.com/neo4j-contrib/gists/blob/master/meta/Home.adoc[Page Source] button on top of the page to see the original AsciiDoc document. 75 | 76 | We'd love to get your feedback, so feel free to write us at *docs at neo4j.org* or comment in the section below. 77 | 78 | // * link:./?github-neo4j-contrib%2Fgists%2F%2Fmeta%2FSimple.adoc[A simple GraphGist] 79 | // * link:./?github-neo4j-contrib%2Fgists%2F%2Fmeta%2FHowTo.adoc[How to create a GraphGist] 80 | -------------------------------------------------------------------------------- /meta/HowTo.adoc: -------------------------------------------------------------------------------- 1 | = How to create a GraphGist 2 | 3 | :neo4j-version: 2.0.0 4 | :author: Anders Nawroth 5 | :twitter: @nawroth 6 | 7 | You create a GraphGist by creating a https://gist.github.com/[GitHub Gist] in http://asciidoctor.org/docs/asciidoc-quick-reference/[AsciiDoc] and enter the URL to it in the form on this page. 8 | Alternatively, you can put an AsciiDoc document in https://www.dropbox.com/[Dropbox] and enter the public URL in the form. 9 | 10 | This GraphGist shows the basics of using AsciiDoc syntax and a few additions for GraphGists. 11 | The additions are entered as comments on their own line. 12 | They are: +//console+ for a query console; +//hide+, +//setup+ and +//output+ to configure a query; +//graph+ and +//table+ to visualize queries and show a result table. 13 | 14 | Click on the Page Source button in the menu to see the source for this GraphGist. 15 | Read below to get the full details. 16 | 17 | == Include a query console 18 | 19 | +//console+ 20 | 21 | becomes: 22 | 23 | //console 24 | 25 | == Define a http://docs.neo4j.org/chunked/snapshot/cypher-query-lang.html[Cypher] query 26 | 27 | [source,cypher] 28 | ---- 29 | CREATE (n{name:'cypher'})-[r:LIKES]->({name:'icecream'}) 30 | RETURN n.name, r 31 | ---- 32 | 33 | becomes: 34 | 35 | [source,cypher] 36 | ---- 37 | CREATE (n{name:'cypher'})-[r:LIKES]->({name:'icecream'}) 38 | RETURN n.name, r 39 | ---- 40 | 41 | _Queries are executed in the order they appear on the page during rendering, so make sure they can be performed in that order._ 42 | If you have a _setup query,_ it normally makes most sense to define it as the first query on the page. 43 | If it takes up too much space, hide it (see below for information on this). 44 | Each query has a green or red button to indicate if the query was successful or not. 45 | The console is set up after the executions, with an empty database, for the reader to play around with the queries. 46 | 47 | There's three additional settings you can use for queries. 48 | They all go as comments, on their own lines, before the query. 49 | The settings are: 50 | 51 | [width="50%",cols="1m,5"] 52 | |=== 53 | | hide | Hide the query. The reader can still expand it to see it. 54 | Useful for long queries like setting up initial data. 55 | | setup | Initialize the console with this query. 56 | | output | Show the output from the query. 57 | The output is always there, but this option makes it visible at page load for this query. 58 | |=== 59 | 60 | Let's try all the settings together, which means this query will be used to initialize the console, it will be hidden, and the raw output will be shown: 61 | 62 | //hide 63 | //setup 64 | //output 65 | [source,cypher] 66 | ---- 67 | CREATE (n{name:'neo4j'})-[:LIKES]->({name:'complex data'}) 68 | RETURN n.name 69 | ---- 70 | 71 | which becomes: 72 | 73 | //hide 74 | //setup 75 | //output 76 | [source,cypher] 77 | ---- 78 | CREATE (n{name:'neo4j'})-[:LIKES]->({name:'complex data'}) 79 | RETURN n.name 80 | ---- 81 | 82 | [NOTE] 83 | The test run will always run the queries from top to bottom, so it usually makes sense to have the setup query as the first query. 84 | 85 | == Show a graph visualization 86 | 87 | The visualization is based on the database contents after the preceding query in the page. 88 | 89 | +//graph+ 90 | 91 | becomes: 92 | 93 | //graph 94 | 95 | == Show a result table for a query 96 | 97 | This will show a result table for the preceding query. 98 | 99 | +//table+ 100 | 101 | becomes: 102 | 103 | //table 104 | 105 | == Basic AsciiDoc formatting 106 | 107 | [width="50%",cols="1m,1a"] 108 | |=== 109 | | \_Italic_ | _Italic_ 110 | | \*Bold* | *Bold* 111 | | \`Monospace` | `Monospace` 112 | | `http://www.neo4j.org/` | http://www.neo4j.org/ 113 | | `http://www.neo4j.org/[neo4j.org]` | http://www.neo4j.org/[neo4j.org] 114 | | `link:./?5956246[Link to a GraphGist]` | link:./?5956246[Link to a GraphGist] 115 | |=== 116 | 117 | === Headings: 118 | 119 | = Heading 1 120 | == Heading 2 121 | === Heading 3 122 | 123 | === Images: 124 | 125 | Static images: 126 | 127 | image::http://assets.neo4j.org/img/still/cineasts.gif[] 128 | 129 | becomes 130 | 131 | image::http://assets.neo4j.org/img/still/cineasts.gif[] 132 | 133 | Dynamically generated image (using http://yuml.me/[yUML]): 134 | 135 | image::http://yuml.me/diagram/scruffy/class/[Order]-billing%20%3E[Address%7Cname=hej],%20[Order]-shipping%20%3E[Address],[Order]-has%3E[Item][test] 136 | 137 | becomes 138 | 139 | image::http://yuml.me/diagram/scruffy/class/[Order]-billing%20%3E[Address%7Cname=hej],%20[Order]-shipping%20%3E[Address],[Order]-has%3E[Item][test] 140 | 141 | === Lists: 142 | 143 | ---- 144 | * Item 1 145 | ** Item 1.1 146 | * Item 2 147 | ---- 148 | 149 | * Item 1 150 | ** Item 1.1 151 | * Item 2 152 | 153 | ---- 154 | . First 155 | . Second 156 | ---- 157 | 158 | . First 159 | . Second 160 | 161 | Monospaced block: indent lines with one space. 162 | 163 | Tables are well supported. 164 | See http://asciidoctor.org/docs/asciidoc-quick-reference/[AsciiDoc Quick Reference] for information on that and more. 165 | 166 | 167 | == Mathematical formulas 168 | 169 | When using Math formulas, put them into a source block using LaTex syntax with `\(` as a start delimiter. 170 | 171 | The end delimiter is `\)`. 172 | The delimiters and the content between them should be placed in a AsciiDoc passthrough block without attribute substitution. 173 | The formulas are rendered through http://www.mathjax.org/demos/tex-samples/[MathJAX], supported commands are http://docs.mathjax.org/en/latest/tex.html#supported-latex-commands[here]. 174 | 175 | [subs=none] 176 | ++++ 177 | \(ax^2 + bx + c \ne 0\) 178 | ++++ 179 | 180 | becomes 181 | 182 | ++++ 183 | \(ax^2 + bx + c \ne 0\) 184 | ++++ 185 | 186 | Below are some more examples. 187 | 188 | [subs=none] 189 | ++++ 190 | 1. 191 | \( 192 | \begin{equation} 193 | \left[ 194 | {\bf X} + {\rm a} \ \geq\ 195 | \underline{\hat a} \sum_i^N \lim_{x \rightarrow k} \delta C 196 | \right] 197 | \end{equation} 198 | \) 199 |
200 | 2. \(ax^2 + bx + c \ne 0\) 201 | 202 |
203 | 4. \(x = {-b \pm \sqrt{b^2-4ac} \over 2a}\) 204 |
205 | 206 | 5. \(\sin^{-1} \theta\) 207 |
208 | 209 | 6. \(\int_a^b f(x)~dx\) 210 |
211 | 212 | 7.\(\sum\limits_{i=1}^n X_i\) 213 |
214 | ++++ 215 | 216 | for more examples, see http://gist.neo4j.org/?6725918[Some GraphGist Latex Examples] 217 | 218 | -------------------------------------------------------------------------------- /meta/README.adoc: -------------------------------------------------------------------------------- 1 | == Meta GraphGists 2 | 3 | Gists about GraphGist. 4 | 5 | 6 | -------------------------------------------------------------------------------- /meta/Simple.adoc: -------------------------------------------------------------------------------- 1 | = A simple GraphGist 2 | 3 | :author: Anders Nawroth 4 | :twitter: @nawroth 5 | 6 | You create a GraphGist by creating a https://gist.github.com/[GitHub Gist] in http://asciidoctor.org/docs/asciidoc-quick-reference/[AsciiDoc] and enter the URL to it in the form on this page. 7 | 8 | Click on the Page Source button in the menu to see the source for this GraphGist! 9 | 10 | == Include a query console 11 | 12 | +//console+ 13 | 14 | becomes: 15 | 16 | //console 17 | 18 | == Define a http://docs.neo4j.org/chunked/snapshot/cypher-query-lang.html[Cypher] query 19 | 20 | [source,cypher] 21 | ---- 22 | CREATE (n{name:'cypher'})-[r:LIKES]->({name:'icecream'}) return n.name, r 23 | ---- 24 | 25 | becomes: 26 | 27 | [source,cypher] 28 | ---- 29 | CREATE (n{name:'cypher'})-[r:LIKES]->({name:'icecream'}) return n.name, r 30 | ---- 31 | 32 | _Queries are executed in the order they appear on the page during rendering, so make sure they can be performed in that order._ 33 | Each query has a green or red button to indicate if the query was successful or not. 34 | The console is set up after the executions, with an empty database, for the reader to play around with the queries. 35 | 36 | -------------------------------------------------------------------------------- /other/BankFraudDetection.adoc: -------------------------------------------------------------------------------- 1 | = Bank Fraud Detection 2 | :neo4j-version: 2.0.0-RC1 3 | :author: Kenny Bastani 4 | :twitter: @kennybastani 5 | :tags: domain:finance, use-case:fraud-detection 6 | 7 | This interactive Neo4j graph tutorial covers bank fraud detection scenarios. 8 | 9 | ''' 10 | 11 | *Table of Contents* 12 | 13 | * *Introduction* 14 | ** <> 15 | * *Scenario* 16 | ** <> 17 | ** <> 18 | * *Solution* 19 | ** <> 20 | ** <> 21 | * *Data Model* 22 | ** <> 23 | * *Database Setup* 24 | ** <> 25 | * *Cypher Queries* 26 | ** <> 27 | ** <> 28 | ** <> 29 | 30 | ''' 31 | 32 | == Introduction to Problem 33 | 34 | Banks and Insurance companies lose billions of dollars every year to fraud. Traditional methods of fraud detection play an important role in minimizing these losses. However increasingly sophisticated fraudsters have developed a variety of ways to elude discovery, both by working together, and by leveraging various other means of constructing false identities. 35 | 36 | ''' 37 | 38 | == Explanation of Scenario 39 | 40 | While no fraud prevention measures can ever be perfect, significant opportunity for improvement lies in looking beyond the individual data points, to the connections that link them. Oftentimes these connections go unnoticed until it is too late— something that is unfortunate, as these connections oftentimes hold the best clues. 41 | 42 | === Typical Scenario 43 | 44 | While the exact details behind each first-party fraud collusion vary from operation to operation, the pattern below illustrates how fraud rings commonly operate: 45 | 46 | * A group of two or more people organize into a fraud ring 47 | * The ring shares a subset of legitimate contact information, for example phone numbers and addresses, combining them to create a number of synthetic identities 48 | * Ring members open accounts using these synthetic identities 49 | * New accounts are added to the original ones: unsecured credit lines, credit cards, overdraft protection, personal loans, etc. 50 | * The accounts are used as normally, with regular purchases and timely payments 51 | * Banks increase the revolving credit lines over time, due to the observed responsible credit behavior 52 | * One day the ring “busts out”, coordinating their activity, maxing out all of their credit lines, and disappearing 53 | * Sometimes fraudsters will go a step further and bring all of their balances to zero using fake checks immediately before the prior step, doubling the damage 54 | * Collections processes ensue, but agents are never able to reach the fraudster 55 | * The uncollectible debt is written off 56 | 57 | ''' 58 | 59 | == Explanation of Solution 60 | 61 | Graph databases offer new methods of uncovering fraud rings and other sophisticated scams with a high-level of accuracy, and are capable of stopping advanced fraud scenarios in real-time. 62 | 63 | === How Graph Databases Can Help 64 | 65 | Augmenting one’s existing fraud detection infrastructure to support ring detection can be done by running appropriate entity link analysis queries using a graph database, and running checks during key stages in the customer & account lifecycle, such as: 66 | 67 | * At the time the account is created 68 | * During an investigation 69 | * As soon as a credit balance threshold is hit 70 | * When a check is bounced 71 | 72 | Real-time graph traversals tied to the right kinds of events can help banks identify probable fraud rings: during or even before the Bust-Out occurs. 73 | 74 | ''' 75 | 76 | == Bank Fraud Graph Data Model 77 | 78 | Graph databases have emerged as an ideal tool for overcoming these hurdles. Languages like Cypher provide a simple semantic for detecting rings in the graph, navigating connections in memory, in real time. 79 | 80 | The graph data model below represents how the data actually looks to the graph database, and illustrates how one can find rings by simply walking the graph: 81 | 82 | image::https://raw.github.com/neo4j-contrib/gists/master/other/images/BankFraud-1.png[Bank Fraud] 83 | 84 | ''' 85 | 86 | == Sample Data Set 87 | 88 | //setup 89 | [source,cypher] 90 | ---- 91 | 92 | // Create account holders 93 | CREATE (accountHolder1:AccountHolder { 94 | FirstName: "John", 95 | LastName: "Doe", 96 | UniqueId: "JohnDoe" }) 97 | 98 | CREATE (accountHolder2:AccountHolder { 99 | FirstName: "Jane", 100 | LastName: "Appleseed", 101 | UniqueId: "JaneAppleseed" }) 102 | 103 | CREATE (accountHolder3:AccountHolder { 104 | FirstName: "Matt", 105 | LastName: "Smith", 106 | UniqueId: "MattSmith" }) 107 | 108 | // Create Address 109 | CREATE (address1:Address { 110 | Street: "123 NW 1st Street", 111 | City: "San Francisco", 112 | State: "California", 113 | ZipCode: "94101" }) 114 | 115 | // Connect 3 account holders to 1 address 116 | CREATE (accountHolder1)-[:HAS_ADDRESS]->(address1), 117 | (accountHolder2)-[:HAS_ADDRESS]->(address1), 118 | (accountHolder3)-[:HAS_ADDRESS]->(address1) 119 | 120 | // Create Phone Number 121 | CREATE (phoneNumber1:PhoneNumber { PhoneNumber: "555-555-5555" }) 122 | 123 | // Connect 2 account holders to 1 phone number 124 | CREATE (accountHolder1)-[:HAS_PHONENUMBER]->(phoneNumber1), 125 | (accountHolder2)-[:HAS_PHONENUMBER]->(phoneNumber1) 126 | 127 | // Create SSN 128 | CREATE (ssn1:SSN { SSN: "241-23-1234" }) 129 | 130 | // Connect 2 account holders to 1 SSN 131 | CREATE (accountHolder2)-[:HAS_SSN]->(ssn1), 132 | (accountHolder3)-[:HAS_SSN]->(ssn1) 133 | 134 | // Create SSN and connect 1 account holder 135 | CREATE (ssn2:SSN { SSN: "241-23-4567" })<-[:HAS_SSN]-(accountHolder1) 136 | 137 | // Create Credit Card and connect 1 account holder 138 | CREATE (creditCard1:CreditCard { 139 | AccountNumber: "1234567890123456", 140 | Limit: 5000, Balance: 1442.23, 141 | ExpirationDate: "01-20", 142 | SecurityCode: "123" })<-[:HAS_CREDITCARD]-(accountHolder1) 143 | 144 | // Create Bank Account and connect 1 account holder 145 | CREATE (bankAccount1:BankAccount { 146 | AccountNumber: "2345678901234567", 147 | Balance: 7054.43 })<-[:HAS_BANKACCOUNT]-(accountHolder1) 148 | 149 | // Create Credit Card and connect 1 account holder 150 | CREATE (creditCard2:CreditCard { 151 | AccountNumber: "1234567890123456", 152 | Limit: 4000, Balance: 2345.56, 153 | ExpirationDate: "02-20", 154 | SecurityCode: "456" })<-[:HAS_CREDITCARD]-(accountHolder2) 155 | 156 | // Create Bank Account and connect 1 account holder 157 | CREATE (bankAccount2:BankAccount { 158 | AccountNumber: "3456789012345678", 159 | Balance: 4231.12 })<-[:HAS_BANKACCOUNT]-(accountHolder2) 160 | 161 | // Create Unsecured Loan and connect 1 account holder 162 | CREATE (unsecuredLoan2:UnsecuredLoan { 163 | AccountNumber: "4567890123456789-0", 164 | Balance: 9045.53, 165 | APR: .0541, 166 | LoanAmount: 12000.00 })<-[:HAS_UNSECUREDLOAN]-(accountHolder2) 167 | 168 | // Create Bank Account and connect 1 account holder 169 | CREATE (bankAccount3:BankAccount { 170 | AccountNumber: "4567890123456789", 171 | Balance: 12345.45 })<-[:HAS_BANKACCOUNT]-(accountHolder3) 172 | 173 | // Create Unsecured Loan and connect 1 account holder 174 | CREATE (unsecuredLoan3:UnsecuredLoan { 175 | AccountNumber: "5678901234567890-0", 176 | Balance: 16341.95, APR: .0341, 177 | LoanAmount: 22000.00 })<-[:HAS_UNSECUREDLOAN]-(accountHolder3) 178 | 179 | // Create Phone Number and connect 1 account holder 180 | CREATE (phoneNumber2:PhoneNumber { 181 | PhoneNumber: "555-555-1234" })<-[:HAS_PHONENUMBER]-(accountHolder3) 182 | 183 | RETURN * 184 | ---- 185 | 186 | //graph 187 | 188 | ''' 189 | 190 | == Entity Link Analysis 191 | 192 | Performing entity link analysis on the above data model is demonstrated below. 193 | 194 | ==== Find account holders who share more than one piece of legitimate contact information 195 | 196 | [source,cypher] 197 | ---- 198 | MATCH (accountHolder:AccountHolder)-[]->(contactInformation) 199 | WITH contactInformation, 200 | count(accountHolder) AS RingSize 201 | MATCH (contactInformation)<-[]-(accountHolder) 202 | WITH collect(accountHolder.UniqueId) AS AccountHolders, 203 | contactInformation, RingSize 204 | WHERE RingSize > 1 205 | RETURN AccountHolders AS FraudRing, 206 | labels(contactInformation) AS ContactType, 207 | RingSize 208 | ORDER BY RingSize DESC 209 | ---- 210 | 211 | //output 212 | //table 213 | 214 | ==== Determine the financial risk of a possible fraud ring 215 | 216 | [source,cypher] 217 | ---- 218 | MATCH (accountHolder:AccountHolder)-[]->(contactInformation) 219 | WITH contactInformation, 220 | count(accountHolder) AS RingSize 221 | MATCH (contactInformation)<-[]-(accountHolder), 222 | (accountHolder)-[r:HAS_CREDITCARD|HAS_UNSECUREDLOAN]->(unsecuredAccount) 223 | WITH collect(DISTINCT accountHolder.UniqueId) AS AccountHolders, 224 | contactInformation, RingSize, 225 | SUM(CASE type(r) 226 | WHEN 'HAS_CREDITCARD' THEN unsecuredAccount.Limit 227 | WHEN 'HAS_UNSECUREDLOAN' THEN unsecuredAccount.Balance 228 | ELSE 0 229 | END) as FinancialRisk 230 | WHERE RingSize > 1 231 | RETURN AccountHolders AS FraudRing, 232 | labels(contactInformation) AS ContactType, 233 | RingSize, 234 | round(FinancialRisk) as FinancialRisk 235 | ORDER BY FinancialRisk DESC 236 | ---- 237 | 238 | //output 239 | //table 240 | -------------------------------------------------------------------------------- /other/NetworkDataCenterManagement1.adoc: -------------------------------------------------------------------------------- 1 | = Network Dependency Graph 2 | :neo4j-version: 2.0.0-RC1 3 | :author: Kenny Bastani 4 | :twitter: @kennybastani 5 | :tags: domain:networks, use-case:network-dependencies 6 | 7 | This interactive Neo4j tutorial covers a scenario in Network and Data Center Management for ACME. ACME is a fictional company with a large network infrastructure that includes a CRM application, ERP application, and a Data Warehousing solution. ACME has a series of public facing websites that they need to be up and running in order to conduct their business and support their customers. 8 | 9 | ''' 10 | 11 | *Table of Contents* 12 | 13 | * *Data Model* 14 | ** <> 15 | * *Cypher Script* 16 | ** <> 17 | * *Visualization* 18 | ** <> 19 | * *Find Network Inventory* 20 | ** <> 21 | * *Find Direct Dependencies* 22 | ** <> 23 | ** <> 24 | ** <> 25 | * *Find Crticial System Dependencies* 26 | ** <> 27 | ** <> 28 | ** <> 29 | 30 | ''' 31 | 32 | === ACME's Network Dependency Graph 33 | 34 | image::http://raw.github.com/neo4j-contrib/gists/master/other/images/datacenter-management-1.PNG[Network Dependency Graph] 35 | 36 | === Database Setup 37 | 38 | Below you will find the full Cypher script for creating ACME's Network Dependency Graph in Neo4j. This simple script is the full setup of the data set that we will later perform analysis on. 39 | 40 | //setup 41 | [source,cypher] 42 | ---- 43 | // Create CRM 44 | CREATE (crm1:Application { 45 | ip:'10.10.32.1', 46 | host:'CRM-APPLICATION', 47 | type: 'APPLICATION', 48 | system: 'CRM' 49 | }) 50 | 51 | // Create ERP 52 | CREATE (erp1:Application { 53 | ip:'10.10.33.1', 54 | host:'ERP-APPLICATION', 55 | type: 'APPLICATION', 56 | system: 'ERP' 57 | }) 58 | 59 | // Create Data Warehouse 60 | CREATE (datawarehouse1:Application { 61 | ip:'10.10.34.1', 62 | host:'DATA-WAREHOUSE', 63 | type: 'DATABASE', 64 | system: 'DW' 65 | }) 66 | 67 | // Create Public Website 1 68 | CREATE (Internet1:Internet { 69 | ip:'10.10.35.1', 70 | host:'global.acme.com', 71 | type: "APPLICATION", 72 | system: "INTERNET" 73 | }) 74 | 75 | // Create Public Website 2 76 | CREATE (Internet2:Internet { 77 | ip:'10.10.35.2', 78 | host:'support.acme.com', 79 | type: "APPLICATION", 80 | system: "INTERNET" 81 | }) 82 | 83 | // Create Public Website 3 84 | CREATE (Internet3:Internet { 85 | ip:'10.10.35.3', 86 | host:'shop.acme.com', 87 | type: "APPLICATION", 88 | system: "INTERNET" 89 | }) 90 | 91 | // Create Public Website 4 92 | CREATE (Internet4:Internet { 93 | ip:'10.10.35.4', 94 | host:'training.acme.com', 95 | type: "APPLICATION", 96 | system: "INTERNET" 97 | }) 98 | 99 | // Create Public Website 5 100 | CREATE (Internet5:Internet { 101 | ip:'10.10.35.1', 102 | host:'partners.acme.com', 103 | type: "APPLICATION", 104 | system: "INTERNET" 105 | }) 106 | 107 | // Create Internal Website 1 108 | CREATE (Intranet1:Intranet { 109 | ip:'10.10.35.2', 110 | host:'events.acme.net', 111 | type: "APPLICATION", 112 | system: "INTRANET" 113 | }) 114 | 115 | // Create Internal Website 2 116 | CREATE (Intranet2:Intranet { 117 | ip:'10.10.35.3', 118 | host:'intranet.acme.net', 119 | type: "APPLICATION", 120 | system: "INTRANET" 121 | }) 122 | 123 | // Create Internal Website 3 124 | CREATE (Intranet3:Intranet { 125 | ip:'10.10.35.4', 126 | host:'humanresources.acme.net', 127 | type: "APPLICATION", 128 | system: "INTRANET" 129 | }) 130 | 131 | // Create Webserver VM 1 132 | CREATE (webservervm1:VirtualMachine { 133 | ip:'10.10.35.5', 134 | host:'WEBSERVER-1', 135 | type: "WEB SERVER", 136 | system: "VIRTUAL MACHINE" 137 | }) 138 | 139 | // Create Webserver VM 2 140 | CREATE (webservervm2:VirtualMachine { 141 | ip:'10.10.35.6', 142 | host:'WEBSERVER-2', 143 | type: "WEB SERVER", 144 | system: "VIRTUAL MACHINE" 145 | }) 146 | 147 | // Create Database VM 1 148 | CREATE (customerdatabase1:VirtualMachine { 149 | ip:'10.10.35.7', 150 | host:'CUSTOMER-DB-1', 151 | type: "DATABASE SERVER", 152 | system: "VIRTUAL MACHINE" 153 | }) 154 | 155 | // Create Database VM 2 156 | CREATE (customerdatabase2:VirtualMachine { 157 | ip:'10.10.35.8', 158 | host:'CUSTOMER-DB-2', 159 | type: "DATABASE SERVER", 160 | system: "VIRTUAL MACHINE" 161 | }) 162 | 163 | // Create Database VM 3 164 | CREATE (databasevm3:VirtualMachine { 165 | ip:'10.10.35.9', 166 | host:'ERP-DB', 167 | type: "DATABASE SERVER", 168 | system: "VIRTUAL MACHINE" 169 | }) 170 | 171 | // Create Database VM 4 172 | CREATE (dwdatabase:VirtualMachine { 173 | ip:'10.10.35.10', 174 | host:'DW-DATABASE', 175 | type: "DATABASE SERVER", 176 | system: "VIRTUAL MACHINE" 177 | }) 178 | 179 | // Create Hardware 1 180 | CREATE (hardware1:Hardware { 181 | ip:'10.10.35.11', 182 | host:'HARDWARE-SERVER-1', 183 | type: "HARDWARE SERVER", 184 | system: "PHYSICAL INFRASTRUCTURE" 185 | }) 186 | 187 | // Create Hardware 2 188 | CREATE (hardware2:Hardware { 189 | ip:'10.10.35.12', 190 | host:'HARDWARE-SERVER-2', 191 | type: "HARDWARE SERVER", 192 | system: "PHYSICAL INFRASTRUCTURE" 193 | }) 194 | 195 | // Create Hardware 3 196 | CREATE (hardware3:Hardware { 197 | ip:'10.10.35.13', 198 | host:'HARDWARE-SERVER-3', 199 | type: "HARDWARE SERVER", 200 | system: "PHYSICAL INFRASTRUCTURE" 201 | }) 202 | 203 | // Create SAN 1 204 | CREATE (san1:Hardware { 205 | ip:'10.10.35.14', 206 | host:'SAN', 207 | type: "STORAGE AREA NETWORK", 208 | system: "PHYSICAL INFRASTRUCTURE" 209 | }) 210 | 211 | // Connect CRM to Database VM 1 212 | CREATE (crm1)-[:DEPENDS_ON]->(customerdatabase1) 213 | 214 | // Connect Public Websites 1-3 to Database VM 1 215 | CREATE (Internet1)-[:DEPENDS_ON]->(customerdatabase1), 216 | (Internet2)-[:DEPENDS_ON]->(customerdatabase1), 217 | (Internet3)-[:DEPENDS_ON]->(customerdatabase1) 218 | 219 | // Connect Database VM 1 to Hardware 1 220 | CREATE (customerdatabase1)-[:DEPENDS_ON]->(hardware1) 221 | 222 | // Connect Hardware 1 to SAN 1 223 | CREATE (hardware1)-[:DEPENDS_ON]->(san1) 224 | 225 | // Connect Public Websites 1-3 to Webserver VM 1 226 | CREATE (webservervm1)<-[:DEPENDS_ON]-(Internet1), 227 | (webservervm1)<-[:DEPENDS_ON]-(Internet2), 228 | (webservervm1)<-[:DEPENDS_ON]-(Internet3) 229 | 230 | // Connect Internal Websites 1-3 to Webserver VM 1 231 | CREATE (webservervm1)<-[:DEPENDS_ON]-(Intranet1), 232 | (webservervm1)<-[:DEPENDS_ON]-(Intranet2), 233 | (webservervm1)<-[:DEPENDS_ON]-(Intranet3) 234 | 235 | // Connect Webserver VM 1 to Hardware 2 236 | CREATE (webservervm1)-[:DEPENDS_ON]->(hardware2) 237 | 238 | // Connect Hardware 2 to SAN 1 239 | CREATE (hardware2)-[:DEPENDS_ON]->(san1) 240 | 241 | // Connect Webserver VM 2 to Hardware 2 242 | CREATE (webservervm2)-[:DEPENDS_ON]->(hardware2) 243 | 244 | // Connect Public Websites 4-6 to Webserver VM 2 245 | CREATE (webservervm2)<-[:DEPENDS_ON]-(Internet4), 246 | (webservervm2)<-[:DEPENDS_ON]-(Internet5) 247 | 248 | // Connect Database VM 2 to Hardware 2 249 | CREATE (hardware2)<-[:DEPENDS_ON]-(customerdatabase2) 250 | 251 | // Connect Public Websites 4-5 to Database VM 2 252 | CREATE (Internet4)-[:DEPENDS_ON]->(customerdatabase2), 253 | (Internet5)-[:DEPENDS_ON]->(customerdatabase2) 254 | 255 | // Connect Hardware 3 to SAN 1 256 | CREATE (hardware3)-[:DEPENDS_ON]->(san1) 257 | 258 | // Connect Database VM 3 to Hardware 3 259 | CREATE (hardware3)<-[:DEPENDS_ON]-(databasevm3) 260 | 261 | // Connect ERP 1 to Database VM 3 262 | CREATE (erp1)-[:DEPENDS_ON]->(databasevm3) 263 | 264 | // Connect Database VM 4 to Hardware 3 265 | CREATE (hardware3)<-[:DEPENDS_ON]-(dwdatabase) 266 | 267 | // Connect Data Warehouse 1 to Database VM 4 268 | CREATE (datawarehouse1)-[:DEPENDS_ON]->(dwdatabase) 269 | 270 | RETURN * 271 | 272 | ---- 273 | 274 | ''' 275 | 276 | === Interactive Graph Visualization 277 | //graph 278 | 279 | ''' 280 | 281 | === ACME's Network Inventory 282 | 283 | The query below generates a data table that gives a quick overview of ACME's network infrastructure. 284 | 285 | [source,cypher] 286 | ---- 287 | MATCH (n) 288 | RETURN labels(n)[0] as type, 289 | count(*) as count, 290 | collect(n.host) as names 291 | ---- 292 | 293 | //table 294 | 295 | ''' 296 | 297 | === Find direct dependencies of all public websites 298 | 299 | The query below queries the data model to find all business web applications that are on the public facing internet for ACME. 300 | 301 | [source,cypher] 302 | ---- 303 | MATCH (website)-[:DEPENDS_ON]->(downstream) 304 | WHERE website.system = "INTERNET" 305 | RETURN website.host as Host, 306 | collect(downstream.host) as Dependencies 307 | ORDER BY Host 308 | ---- 309 | 310 | //table 311 | 312 | ''' 313 | 314 | === Find direct dependencies of all internal websites 315 | 316 | The query below queries the data model to find all business websites that are on the private intranet for ACME. 317 | 318 | [source,cypher] 319 | ---- 320 | MATCH (website)-[:DEPENDS_ON]->(downstream) 321 | WHERE website.system = "INTRANET" 322 | RETURN website.host as Host, 323 | collect(downstream.host) as Dependencies 324 | ORDER BY Host 325 | ---- 326 | 327 | //table 328 | 329 | ''' 330 | 331 | === Find the most depended-upon component 332 | 333 | The query below finds the most heavily relied upon component within ACME's network infrastructure. As expected, the most depended upon component is the SAN (Storage Area Network). 334 | 335 | [source,cypher] 336 | ---- 337 | MATCH (n)<-[:DEPENDS_ON*]-(dependent) 338 | RETURN n.host as Host, 339 | count(DISTINCT dependent) AS Dependents 340 | ORDER BY Dependents DESC 341 | LIMIT 1 342 | ---- 343 | 344 | //table 345 | 346 | ''' 347 | 348 | === Find dependency chain for business critical components: CRM 349 | 350 | The query below finds the path of dependent components from left to right for ACME's CRM application. If ACME's CRM (Customer Relationship Management) application goes down it will cause significant impacts to its business. If any one of the components to the right of the CRM hostname fails, the CRM application will fail. 351 | 352 | [source,cypher] 353 | ---- 354 | MATCH (dependency)<-[:DEPENDS_ON*]-(dependent) 355 | WITH dependency, count(DISTINCT dependent) AS Dependents 356 | ORDER BY Dependents DESC 357 | LIMIT 1 358 | WITH dependency 359 | MATCH p=(resource)-[:DEPENDS_ON*]->(dependency) 360 | WHERE resource.system = "CRM" 361 | RETURN "[" + head(nodes(p)).host + "]" + 362 | reduce(s = "", n in tail(nodes(p)) | s + " -> " + "[" + n.host + "]") as Chain 363 | ---- 364 | 365 | //table 366 | 367 | ''' 368 | 369 | === Find dependency chain for business critical components: ERP 370 | 371 | The query below finds the path of dependent components from left to right for ACME's ERP (Enterprise Resource Planning) application. The ERP application represents an array of business resources dedicated to supporting ongoing business activities at ACME, including finance and supply chain management. If ACME's ERP application goes down it will cause significant impacts to its business. If any one of the components to the right of the ERP hostname fails, then the ERP application will fail. This failure will cause revenue impacts since ACME's business relies on this system to conduct business. 372 | 373 | [source,cypher] 374 | ---- 375 | MATCH (dependency)<-[:DEPENDS_ON*]-(dependent) 376 | WITH dependency, count(DISTINCT dependent) AS Dependents 377 | ORDER BY Dependents DESC 378 | LIMIT 1 379 | WITH dependency 380 | MATCH p=(resource)-[:DEPENDS_ON*]->(dependency) 381 | WHERE resource.system = "ERP" 382 | RETURN "[" + head(nodes(p)).host + "]" + 383 | reduce(s = "", n in tail(nodes(p)) | s + " -> " + "[" + n.host + "]") as Chain 384 | ---- 385 | 386 | //table 387 | 388 | ''' 389 | 390 | === Find dependency chain for business critical components: Data Warehouse 391 | 392 | The query below finds the path of dependent components from left to right for ACME's DW (Data Warehouse) application. The DW application represents an array of business intelligence resources dedicated to supporting time-sensitive analytical processes at ACME. If ACME's DW application goes down it will cause significant impacts to the business operations at ACME on the technical side. If any one of the components to the right of the DW hostname fails, then the DW application will fail. This failure will cause public facing websites like the eCommerce application to not reflect the latest available data from ACME's ERP application. 393 | 394 | [source,cypher] 395 | ---- 396 | MATCH (dependency)<-[:DEPENDS_ON*]-(dependent) 397 | WITH dependency, count(DISTINCT dependent) AS Dependents 398 | ORDER BY Dependents DESC 399 | LIMIT 1 400 | WITH dependency 401 | MATCH p=(resource)-[:DEPENDS_ON*]->(dependency) 402 | WHERE resource.system = "DW" 403 | RETURN "[" + head(nodes(p)).host + "]" + 404 | reduce(s = "", n in tail(nodes(p)) | s + " -> " + "[" + n.host + "]") as Chain 405 | ---- 406 | 407 | //table 408 | 409 | === Find the impact of the removal of a network component : Hardware Server 410 | 411 | The query below finds the applications depending on ACME's HARDWARE-SERVER-3. In case a network administrator wants to plan an intervention on the server, he has to know what will be the applications impacted. This way he can warn the applications users. 412 | 413 | [source,cypher] 414 | ---- 415 | MATCH (application:Application)-[:DEPENDS_ON*]->(server) 416 | WHERE server.host = "HARDWARE-SERVER-3" 417 | RETURN application.type as Type, 418 | application.host as Host 419 | ---- 420 | 421 | //table 422 | -------------------------------------------------------------------------------- /other/SocialNetworkGraph.adoc: -------------------------------------------------------------------------------- 1 | = Social Network Graph Example from Diaspora 2 | 3 | Sarah Mei recently wrote a http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/[blog post] describing how she and her colleagues modeled a collection of TV shows and a social network. A few of us at Neo felt strongly that these domains were very graphy in nature. 4 | 5 | We wanted to see if our intuition was right (we love the Diaspora project and extend our help to you) and so with the help of http://docs.neo4j.org/chunked/preview/cypher-query-lang.html[Cypher], created a mini version of each of the domains that Sarah described. 6 | 7 | This is the second of two GraphGists that are part of the http://blog.neo4j.org/2013/11/why-graph-databases-are-best-tool-for-handling-connected-data-like-diaspora.html[response to Sarah's blog post]. If you would like to quickly jump to the first one that details the TV Show Graph data model, you can find it here: http://gist.neo4j.org/?github-neo4j-contrib%2Fgists%2F%2Fother%2FTVShowGraph.adoc[TV Show Graph Diaspora example] 8 | 9 | == Social Network Data Model 10 | 11 | image::http://www.sarahmei.com/blog/wp-content/uploads/2013/11/Screen-Shot-2013-11-09-at-8.11.30-PM.png[] 12 | 13 | == Social Network Setup 14 | 15 | // setup 16 | // hide 17 | [source,cypher] 18 | ---- 19 | CREATE (rachel:User {name: "Rachel Green"}) 20 | CREATE (monica:User {name: "Monica Geller"}) 21 | CREATE (phoebe:User {name: "Phoebe Buffay"}) 22 | CREATE (joey:User {name: "Joey Tribbiani"}) 23 | CREATE (chandler:User {name: "Chandler Bing"}) 24 | CREATE (ross:User {name: "Ross Geller"}) 25 | 26 | CREATE (rachel)-[:FRIEND]->(monica) 27 | CREATE (rachel)-[:FRIEND]->(phoebe) 28 | CREATE (rachel)-[:FRIEND]->(joey) 29 | CREATE (rachel)-[:FRIEND]->(chandler) 30 | CREATE (rachel)-[:FRIEND]->(ross) 31 | 32 | CREATE (monica)-[:FRIEND]->(phoebe) 33 | CREATE (monica)-[:FRIEND]->(joey) 34 | CREATE (monica)-[:FRIEND]->(chandler) 35 | CREATE (monica)-[:FRIEND]->(ross) 36 | 37 | CREATE (phoebe)-[:FRIEND]->(joey) 38 | CREATE (phoebe)-[:FRIEND]->(chandler) 39 | CREATE (phoebe)-[:FRIEND]->(ross) 40 | 41 | CREATE (joey)-[:FRIEND]->(chandler) 42 | CREATE (joey)-[:FRIEND]->(ross) 43 | 44 | CREATE (chandler)-[:FRIEND]->(ross) 45 | 46 | CREATE (monica)-[:POSTED]->(post0:Post { id: "0", text: "You don't like the game, because you suck at it." }) 47 | CREATE (phoebe)-[:POSTED]->(post1:Post { id: "1", text: "Chandler still thinks I'm pregnant and he hasn't asked me how I'm feeling or offered to carry my bags. I feel bad for the woman who ends up with him." }) 48 | CREATE (joey)-[:POSTED]->(post2:Post { id: "2", text: "Just because she went to Yale drama, she thinks she's like the greatest actress since, since, sliced bread!" }) 49 | CREATE (chandler)-[:POSTED]->(post3:Post { id: "3", text: " In my defense, it was dark and he was a very pretty guy." }) 50 | CREATE (rachel)-[:POSTED]->(post4:Post { id: "4", text: "I don't want my baby's first words to be 'How You Doing'" }) 51 | CREATE (ross)-[:POSTED]->(post5:Post { id: "5", text: "Chandler entered a Vanilla Ice look-alike contest and *won*!" }) 52 | 53 | // Comments 54 | CREATE (post0)<-[:COMMENTED{ id: "6", text: "lol" }]-(ross) 55 | CREATE (post1)<-[:COMMENTED{ id: "7", text: "lol" }]-(rachel) 56 | CREATE (post2)<-[:COMMENTED{ id: "8", text: "lol" }]-(chandler) 57 | CREATE (post3)<-[:COMMENTED{ id: "9", text: "lol" }]-(joey) 58 | CREATE (post4)<-[:COMMENTED{ id: "10", text: "lol" }]-(phoebe) 59 | CREATE (post5)<-[:COMMENTED{ id: "11", text: "lol" }]-(monica) 60 | 61 | 62 | // Likes 63 | CREATE (post0)<-[:LIKED{ id: "12", text: "Ross likes this." }]-(ross) 64 | CREATE (post1)<-[:LIKED{ id: "13", text: "Rachel likes this." }]-(rachel) 65 | CREATE (post2)<-[:LIKED{ id: "14", text: "Chandler likes this." }]-(chandler) 66 | CREATE (post3)<-[:LIKED{ id: "15", text: "Joey likes this." }]-(joey) 67 | CREATE (post4)<-[:LIKED{ id: "16", text: "Phoebe likes this." }]-(phoebe) 68 | CREATE (post5)<-[:LIKED{ id: "17", text: "Monica likes this." }]-(monica) 69 | ---- 70 | 71 | image::https://raw.github.com/neo4j-contrib/gists/master/other/images/social-network-graph-1.png[] 72 | 73 | Now let's write some queries! 74 | 75 | We'll start with one to find the posts made by Rachel's friends: 76 | 77 | [source,cypher] 78 | ---- 79 | MATCH (u:User)-[:FRIEND]-(f)-[:POSTED]->(post) 80 | WHERE u.name = "Rachel Green" 81 | RETURN f.name AS friend, post.text as content 82 | ---- 83 | 84 | // table 85 | 86 | Our next query might be a slight variation on this to collect the people who have liked a post: 87 | 88 | [source,cypher] 89 | ---- 90 | MATCH (u:User)-[:FRIEND]-(f)-[:POSTED]->(post)<-[like:LIKED]-(liker) 91 | WHERE u.name = "Rachel Green" 92 | RETURN f.name AS friend, post.text as content, COLLECT(liker.name) as liked_by 93 | ---- 94 | 95 | // table 96 | 97 | A third query could collect all actions on a post, be they likes or comments: 98 | 99 | [source,cypher] 100 | ---- 101 | MATCH (u:User)-[:FRIEND]-(f)-[:POSTED]->(post)<-[a:LIKED|:COMMENTED]->(person) 102 | WHERE u.name = "Rachel Green" 103 | RETURN f.name AS friend, post.text AS content, 104 | COLLECT({ text: a.text, person: person.name, action: TYPE(a)}) AS actions 105 | ---- 106 | 107 | // table 108 | 109 | 110 | //graph 111 | 112 | -------------------------------------------------------------------------------- /other/TVShowGraph.adoc: -------------------------------------------------------------------------------- 1 | = TV Show Graph 2 | 3 | :neo4j-version: 2.0.0-RC1 4 | :author: Kenny Bastani 5 | :twitter: @kennybastani 6 | 7 | Sarah Mei recently wrote a http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/[blog post] describing how she and her colleagues modeled a collection of TV shows and a social network. A few of us at Neo felt strongly that these domains were very graphy in nature. 8 | 9 | We wanted to see if our intuition was right (we love the Diaspora project and extend our help to you) and so with the help of http://docs.neo4j.org/chunked/preview/cypher-query-lang.html[Cypher], created a mini version of each of the domains that Sarah described. 10 | 11 | This is the first of two GraphGists that are part of http://blog.neo4j.org/2013/11/why-graph-databases-are-best-tool-for-handling-connected-data-like-diaspora.html[the response to Sarah's blog post]. If you would like to quickly jump to the second one that details the social networking data model, you can find it here: http://gist.neo4j.org/?github-neo4j-contrib%2Fgists%2F%2Fother%2FSocialNetworkGraph.adoc[Social Network Graph Diaspora example] 12 | 13 | == TV Show Data Model 14 | 15 | image::http://www.sarahmei.com/blog/wp-content/uploads/2013/11/Screen-Shot-2013-11-09-at-7.09.27-PM.png[] 16 | 17 | == The TV Series setup 18 | 19 | // setup 20 | // hide 21 | [source,cypher] 22 | ---- 23 | CREATE (himym:TVShow {name: "How I Met Your Mother"}) 24 | CREATE (himym_s1:Season {name: "HIMYM Season 1"}) 25 | CREATE (himym_s1_e1:Episode {name: "Pilot"}) 26 | 27 | CREATE (ted:Character {name: "Ted Mosby"}) 28 | CREATE (marshall:Character {name: "Marshall Eriksen"}) 29 | CREATE (robin:Character {name: "Robin Scherbatsky"}) 30 | CREATE (barney:Character {name: "Barney Stinson"}) 31 | CREATE (lily:Character {name: "Lily Aldrin"}) 32 | 33 | CREATE (joshRadnor:Actor {name: "Josh Radnor"}) 34 | CREATE (jasonSegel:Actor {name: "Jason Segel"}) 35 | CREATE (cobieSmulders:Actor {name: "Cobie Smulders"}) 36 | CREATE (neilPatrickHarris:Actor {name: "Neil Patrick Harris"}) 37 | CREATE (alysonHannigan:Actor {name: "Alyson Hannigan"}) 38 | 39 | CREATE UNIQUE (joshRadnor)-[:PLAYED_CHARACTER]->(ted) 40 | CREATE UNIQUE (jasonSegel)-[:PLAYED_CHARACTER]->(marshall) 41 | CREATE UNIQUE (cobieSmulders)-[:PLAYED_CHARACTER]->(robin) 42 | CREATE UNIQUE (neilPatrickHarris)-[:PLAYED_CHARACTER]->(barney) 43 | CREATE UNIQUE (alysonHannigan)-[:PLAYED_CHARACTER]->(lily) 44 | 45 | CREATE UNIQUE (himym)-[:HAS_SEASON]->(himym_s1) 46 | 47 | CREATE UNIQUE (himym_s1)-[:HAS_EPISODE]->(himym_s1_e1) 48 | 49 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(ted) 50 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(marshall) 51 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(robin) 52 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(barney) 53 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(lily) 54 | 55 | CREATE (himym_s1_e1_review1 {title: "Meet Me At The Bar In 15 Minutes & Suit Up", content: "It was awesome"}) 56 | CREATE (wakenPayne:User {name: "WakenPayne"}) 57 | 58 | CREATE (himym_s1_e1_review2 {title: "What a great pilot for a show :)", content: "The humour is great."}) 59 | CREATE (atlasredux:User {name: "atlasredux"}) 60 | 61 | CREATE (wakenPayne)-[:WROTE_REVIEW]->(himym_s1_e1_review1)<-[:HAS_REVIEW]-(himym_s1_e1) 62 | CREATE (atlasredux)-[:WROTE_REVIEW]->(himym_s1_e1_review2)<-[:HAS_REVIEW]-(himym_s1_e1) 63 | 64 | ---- 65 | 66 | //graph 67 | 68 | image::https://raw.github.com/neo4j-contrib/gists/master/other/images/tv-show-graph-2.PNG[] 69 | 70 | == All info for a show 71 | 72 | For a particular TV show, show all the seasons and all the episodes and all the reviews and all the cast members from that show i.e. all of the information connected to that TV show. 73 | 74 | [source,cypher] 75 | ---- 76 | MATCH (tvShow:TVShow)-[:HAS_SEASON]->(season)-[:HAS_EPISODE]->(episode) 77 | WHERE tvShow.name = "How I Met Your Mother" 78 | RETURN season, episode 79 | ---- 80 | 81 | //table 82 | 83 | We could also grab the reviews if there are any by slightly tweaking the query: 84 | 85 | [source,cypher] 86 | ---- 87 | MATCH (tvShow:TVShow)-[:HAS_SEASON]->(season)-[:HAS_EPISODE]->(episode) 88 | WHERE tvShow.name = "How I Met Your Mother" 89 | WITH season, episode 90 | OPTIONAL MATCH (episode)-[:HAS_REVIEW]->(review) 91 | RETURN season, episode, review 92 | ---- 93 | 94 | //table 95 | 96 | == Chronological listing of all episodes 97 | 98 | Sarah’s next query was: 99 | 100 | Display a chronological listing of all of the episodes of all the different shows that an actor had ever been in. 101 | 102 | First let’s add another TV show that Josh Radnor appeared in: 103 | 104 | [source,cypher] 105 | ---- 106 | CREATE (er:TVShow {name: "ER"}) 107 | CREATE (er_s9:Season {name: "ER S7"}) 108 | CREATE (er_s9_e17:Episode {name: "Peter's Progress"}) 109 | CREATE (tedMosby:Character {name: "The Advocate "}) 110 | 111 | CREATE UNIQUE (er)-[:HAS_SEASON]->(er_s9) 112 | CREATE UNIQUE (er_s9)-[:HAS_EPISODE]->(er_s9_e17) 113 | 114 | WITH er_s9_e17 115 | 116 | MATCH (actor:Actor), (episode:Episode) 117 | WHERE actor.name = "Josh Radnor" AND episode.name = "Peter's Progress" 118 | WITH actor, episode 119 | 120 | CREATE (keith {name: "Keith"}) 121 | CREATE UNIQUE (actor)-[:PLAYED_CHARACTER]->(keith) 122 | CREATE UNIQUE (episode)-[:FEATURED_CHARACTER]->(keith) 123 | ---- 124 | 125 | And now we’ll create a query to find the shows that he’s appeared in: 126 | 127 | [source,cypher] 128 | ---- 129 | MATCH (actor:Actor)-[:PLAYED_CHARACTER]->(character)<-[:FEATURED_CHARACTER]-(episode) 130 | WHERE actor.name = "Josh Radnor" 131 | RETURN episode.name, character.name 132 | ---- 133 | //table 134 | 135 | We could then easily add in more seasons, episodes and reviews if we wanted to. 136 | -------------------------------------------------------------------------------- /other/ThePublicationGraph.adoc: -------------------------------------------------------------------------------- 1 | = The Publication Graph 2 | 3 | In the world of publications and CMSes, meta-data about different articles, authors, issues and other entities lends itself very obviously to a graph. 4 | This example is modeling just a small subset of a fictive domain in this area. 5 | 6 | == Prepare the schema, make `Person` unique 7 | 8 | [source,cypher] 9 | ---- 10 | CREATE CONSTRAINT ON (p:Person) ASSERT p.handle IS UNIQUE 11 | ---- 12 | 13 | 14 | == Insert some basic data 15 | 16 | [source,cypher] 17 | ---- 18 | CREATE 19 | (JM_DE:Publication{name:'Java Magazin', language:'DE'}), 20 | (JM_DE)<-[:ISSUE_OF]-(JMNov2013{month:11, title:'Java Magazin 11/2013'})-[:IN_YEAR]->(_2013{year:2013}), 21 | (Neo4j20Tutorial:Content{title:'Neo4j 2.0 Tutorial'}), 22 | (SnS:Publisher{name:'S&S Media'})-[:PUBLISHES]->(JM_DE), 23 | (JMNov2013)-[:CONTAINS]->(Neo4j20Tutorial), 24 | (Olli:Reader{name:'Oliver Meyer',handle:'@olli'})-[:RATED{rating:4}]->(Neo4j20Tutorial), 25 | (MH:Author:Reader{name:'Michael Hunger',handle:'@mesirii'})-[:AUTHORED]->(Neo4j20Tutorial), 26 | (Neo4j20Tutorial)-[:RELATED_TO]->(Neo4j20Rel:Content{title:'Neo4j 2.0-M05 released'})-[:TAGGED]->(NoSQL:Tag{name:'NOSQL'}), 27 | (Neo4j20Tutorial)-[:TAGGED]->(NoSQL), 28 | (Neo4j20Tutorial)-[:TAGGED]->(:Tag{name:'tutorial'}), 29 | (Neo4j20Tutorial)-[:TAGGED]->(:Tag{name:'Neo4j'}) 30 | ---- 31 | 32 | //graph 33 | 34 | == Find all articles in 2013 tagged with `NOSQL` 35 | 36 | [source,cypher] 37 | ---- 38 | MATCH 39 | (year)<-[:IN_YEAR]-(issue)-[:ISSUE_OF]->(pub:Publication), 40 | (issue)-[:CONTAINS]->(content:Content)-[:TAGGED]->(nosql:Tag) 41 | WHERE 42 | year.year = 2013 AND 43 | nosql.name='NOSQL' 44 | RETURN 45 | content.title as Title, issue.title as Issue, pub.name as Publication 46 | ---- 47 | 48 | //table 49 | -------------------------------------------------------------------------------- /other/images/BankFraud-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/BankFraud-1.png -------------------------------------------------------------------------------- /other/images/datacenter-management-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/datacenter-management-1.PNG -------------------------------------------------------------------------------- /other/images/network-inventory-cost-accounting-graph-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/network-inventory-cost-accounting-graph-1.PNG -------------------------------------------------------------------------------- /other/images/social-network-graph-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/social-network-graph-1.png -------------------------------------------------------------------------------- /other/images/tv-show-graph-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/tv-show-graph-1.PNG -------------------------------------------------------------------------------- /other/images/tv-show-graph-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo4j-contrib/gists/c390f2bda6a0cdf6bb9e1f9766d001d72510ca8c/other/images/tv-show-graph-2.PNG -------------------------------------------------------------------------------- /other/sarah.adoc: -------------------------------------------------------------------------------- 1 | = The Diaspora data model - OMG it's a graph! 2 | 3 | Sarah Mei recently wrote a http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/[blog post] describing how she and her colleagues modelled a TV show and a social network, and as I read more of the post it felt like both domains were very graphy in nature. 4 | 5 | We wanted to see if our intuition was right (we love the Diaspora project and extend our help to you) and so with the help of http://docs.neo4j.org/chunked/preview/cypher-query-lang.html[Cypher], created a mini version of each of the domains that Sarah described. 6 | 7 | The TV show model is as follows: 8 | 9 | image::http://www.sarahmei.com/blog/wp-content/uploads/2013/11/Screen-Shot-2013-11-09-at-7.09.27-PM.png[] 10 | 11 | == The TV Series setup 12 | 13 | [source,cypher] 14 | ---- 15 | CREATE (himym:TVShow {name: "How I Met Your Mother"}) 16 | CREATE (himym_s1:Season {name: "HIMYM Season 1"}) 17 | CREATE (himym_s1_e1:Episode {name: "Pilot"}) 18 | 19 | CREATE (ted:Character {name: "Ted Mosby"}) 20 | CREATE (marshall:Character {name: "Marshall Eriksen"}) 21 | CREATE (robin:Character {name: "Robin Scherbatsky"}) 22 | CREATE (barney:Character {name: "Barney Stinson"}) 23 | CREATE (lily:Character {name: "Lily Aldrin"}) 24 | 25 | CREATE (joshRadnor:Actor {name: "Josh Radnor"}) 26 | CREATE (jasonSegel:Actor {name: "Jason Segel"}) 27 | CREATE (cobieSmulders:Actor {name: "Cobie Smulders"}) 28 | CREATE (neilPatrickHarris:Actor {name: "Neil Patrick Harris"}) 29 | CREATE (alysonHannigan:Actor {name: "Alyson Hannigan"}) 30 | 31 | CREATE UNIQUE (joshRadnor)-[:PLAYED_CHARACTER]->(ted) 32 | CREATE UNIQUE (jasonSegel)-[:PLAYED_CHARACTER]->(marshall) 33 | CREATE UNIQUE (cobieSmulders)-[:PLAYED_CHARACTER]->(robin) 34 | CREATE UNIQUE (neilPatrickHarris)-[:PLAYED_CHARACTER]->(barney) 35 | CREATE UNIQUE (alysonHannigan)-[:PLAYED_CHARACTER]->(lily) 36 | 37 | CREATE UNIQUE (himym)-[:HAS_SEASON]->(himym_s1) 38 | 39 | CREATE UNIQUE (himym_s1)-[:HAS_EPISODE]->(himym_s1_e1) 40 | 41 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(ted) 42 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(marshall) 43 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(robin) 44 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(barney) 45 | CREATE UNIQUE (himym_s1_e1)-[:FEATURED_CHARACTER]->(lily) 46 | 47 | CREATE (himym_s1_e1_review1 {title: "Meet Me At The Bar In 15 Minutes & Suit Up", content: "It was awesome"}) 48 | CREATE (wakenPayne:User {name: "WakenPayne"}) 49 | 50 | CREATE (himym_s1_e1_review2 {title: "What a great pilot for a show :)", content: "The humour is great."}) 51 | CREATE (atlasredux:User {name: "atlasredux"}) 52 | 53 | CREATE (wakenPayne)-[:WROTE_REVIEW]->(himym_s1_e1_review1)<-[:HAS_REVIEW]-(himym_s1_e1) 54 | CREATE (atlasredux)-[:WROTE_REVIEW]->(himym_s1_e1_review2)<-[:HAS_REVIEW]-(himym_s1_e1) 55 | 56 | ---- 57 | 58 | //graph 59 | 60 | 61 | == All info for a show 62 | 63 | For a particular TV show, show all the seasons and all the episodes and all the reviews and all the cast members from that show i.e. all of the information connected to that TV show. 64 | 65 | [source,cypher] 66 | ---- 67 | MATCH (tvShow:TVShow)-[:HAS_SEASON]->(season)-[:HAS_EPISODE]->(episode) 68 | WHERE tvShow.name = "How I Met Your Mother" 69 | RETURN season, episode 70 | ---- 71 | 72 | //table 73 | 74 | We could also grab the reviews if there are any by slightly tweaking the query: 75 | 76 | [source,cypher] 77 | ---- 78 | MATCH (tvShow:TVShow)-[:HAS_SEASON]->(season)-[:HAS_EPISODE]->(episode) 79 | WHERE tvShow.name = "How I Met Your Mother" 80 | WITH season, episode 81 | MATCH episode-[?:HAS_REVIEW]->(review) 82 | RETURN season, episode, review 83 | ---- 84 | 85 | //table 86 | 87 | == Chronological listing of all episodes 88 | 89 | Sarah’s next query was: 90 | 91 | Display a chronological listing of all of the episodes of all the different shows that an actor had ever been in. 92 | 93 | First let’s add another TV show that Josh Radnor appeared in: 94 | 95 | [source,cypher] 96 | ---- 97 | CREATE (er:TVShow {name: "ER"}) 98 | CREATE (er_s9:Season {name: "ER S7"}) 99 | CREATE (er_s9_e17:Episode {name: "Peter's Progress"}) 100 | CREATE (tedMosby:Character {name: "The Advocate "}) 101 | 102 | CREATE UNIQUE (er)-[:HAS_SEASON]->(er_s9) 103 | CREATE UNIQUE (er_s7)-[:HAS_EPISODE]->(er_s9_e17) 104 | 105 | WITH er_s9_e17 106 | 107 | MATCH (actor:Actor), (episode:Episode) 108 | WHERE actor.name = "Josh Radnor" AND episode.name = "Peter's Progress" 109 | WITH actor, episode 110 | 111 | CREATE (keith {name: "Keith"}) 112 | CREATE UNIQUE (actor)-[:PLAYED_CHARACTER]->(keith) 113 | CREATE UNIQUE (episode)-[:FEATURED_CHARACTER]->(keith) 114 | ---- 115 | 116 | And now we’ll create a query to find the shows that he’s appeared in: 117 | 118 | [source,cypher] 119 | ---- 120 | MATCH (actor:Actor)-[:PLAYED_CHARACTER]->(character)<-[:FEATURED_CHARACTER]-(episode) 121 | WHERE actor.name = "Josh Radnor" 122 | RETURN episode.name, character.name 123 | ---- 124 | //table 125 | 126 | We could then easily add in more seasons, episodes and reviews if we wanted to. 127 | --------------------------------------------------------------------------------