diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7b1cff6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# EditorConfig is awesome: https://EditorConfig.org +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9eacff7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build/ + +/node_modules/ + +.DS_Store + +/.idea/ +*.iml diff --git a/adoc/browser.adoc b/adoc/browser.adoc deleted file mode 100644 index 2cb52bf..0000000 --- a/adoc/browser.adoc +++ /dev/null @@ -1,5 +0,0 @@ -:experimental: - -== Get Started - -include::../../developer-resources/get-started/guide-neo4j-browser/guide-neo4j-browser.adoc[tags=guide] \ No newline at end of file diff --git a/adoc/restaurant_recommendation.adoc b/adoc/restaurant_recommendation.adoc deleted file mode 100644 index 48e9a33..0000000 --- a/adoc/restaurant_recommendation.adoc +++ /dev/null @@ -1,122 +0,0 @@ -== Restaurant Recommendations -:author: Neo Technology -:twitter: neo4j -:tags: Recommendation, Graph Based Search -:neo4j-version: 3.0 - -=== Introduction - -image::https://guides.neo4j.com/sushi_restaurants_nyc.svg[height=300,float=right] - -We want to demonstrate how easy it is to model a domain as a graph and answer questions in almost natural language. - -Graph Based Search and Discovery is prominent a use-case for graph databases like http://neo4j.com[Neo4j]. - -Here we use a Domain of restaurants which serve cuisines and are located in a City. - -The domain diagram was created with the http://www.apcjones.com/arrows/#[Arrows tool] - -//// - -//// - -=== Setup: Creating Friends, Restaurants in Cities and their Cusines - -//setup -[source,cypher] ----- -CREATE (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]->(emil:Person {name:"Emil"}), - (philip)-[:IS_FRIEND_OF]->(michael:Person {name:"Michael"}), - (philip)-[:IS_FRIEND_OF]->(andreas:Person {name:"Andreas"}) -CREATE (sushi:Cuisine {name:"Sushi"}), (nyc:City {name:"New York"}), - (iSushi:Restaurant {name:"iSushi"})-[:SERVES]->(sushi),(iSushi)-[:LOCATED_IN]->(nyc), - (michael)-[:LIKES]->(iSushi), - (andreas)-[:LIKES]->(iSushi), - (zam:Restaurant {name:"Zushi Zam"})-[:SERVES]->(sushi),(zam)-[:LOCATED_IN]->(nyc), - (andreas)-[:LIKES]->(zam) ----- - -//graph - -=== Philips Friends - -[source,cypher] ----- -MATCH (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]-(person) -RETURn person.name ----- - -//table - -=== Restaurants in NYC and their cusines - -[source,cypher] ----- -MATCH (nyc:City {name:"New York"})<-[:LOCATED_IN]-(restaurant)-[:SERVES]->(cusine) -RETURN nyc, restaurant, cusine ----- - -//table - -//graph_result - -=== Graph Search Recommendation - -image::https://guides.neo4j.com/sushi_restaurants_nyc.png[height=300,float=right] - -We want to answer the following question - -"" -Find Sushi Restaurants in New York that my friends like. -"" - -To satisfy this question, we have to know who's asking: _Philip_ and he's asking for 4 connected facts - -* _People_ that are friends of _Philip_ -* _Restaurants_ located in _New York_ -* _Restaurants_ that server _Sushi_ -* _Restaurants_ that his _Friends_ like - -[source,cypher] ----- -MATCH (philip:Person {name:"Philip"}), - (philip)-[:IS_FRIEND_OF]-(friend), - (restaurant:Restaurant)-[:LOCATED_IN]->(:City {name:"New York"}), - (restaurant)-[:SERVES]->(:Cuisine {name:"Sushi"}), - (friend)-[:LIKES]->(restaurant) -RETURN restaurant.name, collect(friend.name) AS likers, count(*) AS occurence -ORDER BY occurence DESC ----- - -//table \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ccab100 --- /dev/null +++ b/build.gradle @@ -0,0 +1,74 @@ +import org.asciidoctor.gradle.jvm.AsciidoctorTask +import org.kordamp.gradle.livereload.LiveReloadTask + +plugins { + id 'org.asciidoctor.jvm.gems' version '3.1.0' apply false + id 'org.asciidoctor.jvm.convert' version '3.1.0' apply false + id 'org.kordamp.gradle.livereload' version '0.2.1' apply false +} + +subprojects { + + apply plugin: 'org.asciidoctor.jvm.gems' + + dependencies { + asciidoctorGems 'rubygems:rouge:3.18.0' + } + + repositories { + mavenCentral() + jcenter() + ruby { + gems() + } + } + + asciidoctorj { + gemPaths "${rootProject.buildDir}/.asciidoctorGems" + attributes 'allow-uri-read': '', + 'source-highlighter': 'rouge', + 'rouge-style': 'neo.forest', + 'presenter': 'Neo Technology', + 'twitter': 'neo4j', + 'email': 'info@neotechnology.com', + 'currentyear': '2020', + 'experimental': '' + } + + asciidoctorGemsPrepare.with { + outputDir = "${rootProject.buildDir}/.asciidoctorGems" + } + + task convert(type: AsciidoctorTask) { + dependsOn asciidoctorGemsPrepare + + inputs.dir "${rootProject.projectDir}/templates" + + asciidoctorj { + options template_dirs: ["${rootProject.projectDir}/templates"] + attributes 'imagesdir': "http://localhost:35729/browser-guide/images", + 'allow-uri-read': '', + 'guides': "http://localhost:35729/browser-guide", + 'icons': 'font', + 'leveloffset': '+1', + 'env-guide': '', + 'guide': '', + 'sectanchors': '' + } + + resources { + from("${projectDir}/images") { + include '**' + into 'images' + } + } + + baseDir file("${projectDir}/docs") + sourceDir file("${projectDir}/docs") + outputDir file("${projectDir}/build/browser-guide") + } + + task httpServer(type: LiveReloadTask) { + docRoot "${projectDir}/build" + } +} diff --git a/docs/adoc-guides.adoc b/docs/adoc-guides.adoc deleted file mode 100644 index e69de29..0000000 diff --git a/docs/html-guides.adoc b/docs/html-guides.adoc deleted file mode 100644 index c117a5c..0000000 --- a/docs/html-guides.adoc +++ /dev/null @@ -1,140 +0,0 @@ -= Creating remote browser guides in HTML -== Setting up a remote server -The remote server serving these guides must be open to handle requests from all origins. This is done by setting it's `Access-Control-Allow-Origin` header to allow `*`. Read more here: http://enable-cors.org/server.html - -== Configure Neo4j -Enterprise edition of Neo4j can have configurated whitelist of allowed hostnames to fetch guides from. Community edition have a static whitelist. -The whitelist is in _neo4j-server.properties_. Set to `*` to allow from all hosts. - -== Create a guide -Howto create a guide. - -=== Basic HTML structure -A browser guide is a partial HTML document that sould be encapsulated in `
` tags. - -A guide usually have multiple slides/pages by using a carousel: - -[source,html] ----- - - Slide 1 - Slide 2 - ----- - -The Bootstrap CSS classes can be used, see http://getbootstrap.com/css/ for info on what's available. - -A slide is usually split into two columns with title and lead to the left and content to the right. -To get this structure, use this code: - -[source,html] ----- -
-

Title

-

Informative text

-
-
- content... -
----- - -All HTML is allowed so make sure the guides structure is valid and complete so other parts of the browser don't break. -All ` - - -
-

REMOTE Cypher

-

Neo4j's graph query language

-
-
-

Neo4j's Cypher language is purpose built for working with graph data.

-
    -
  • uses patterns to describe graph data
  • -
  • familiar SQL-like clauses
  • -
  • declarative, describing what to find, not how to find it
  • -
  • declarative, describing what to find, not how to find it 2
  • -
  • declarative, describing what to find, not how to find it 2
  • -
-
-
- -
-

CREATE

-

Create a node

-
-
-

Let's use Cypher to generate a small social graph.

-
-
CREATE (ee:Person { name: "Emil", from: "Sweden", klout: 99 })
-
-
    -
  • CREATE clause to create data
  • -
  • () parenthesis to indicate a node
  • -
  • ee:Person a variable 'ee' and label 'Person' for the new node
  • -
  • {} brackets to add properties to the node
  • -
-
-
- -
-

MATCH

-

Finding nodes

-
-
-

Now find the node representing Emil:

-
-
MATCH (ee:Person) WHERE ee.name = "Emil" RETURN ee;
-
-
    -
  • MATCH clause to specify a pattern of nodes and relationships
  • -
  • (ee:Person) a single node pattern with label 'Person' which will assign matches to the variable 'ee'
  • -
  • WHERE clause to constrain the results
  • -
  • ee.name = "Emil" compares name property to the value "Emil"
  • -
  • RETURN clause used to request particular results
  • -
-
-
- -
-

CREATE more

-

Nodes and relationships

-
-
-

CREATEclauses can create many nodes and relationships at once.

-
-
MATCH (ee:Person) WHERE ee.name = "Emil"
-CREATE (js:Person { name: "Johan", from: "Sweden", learn: "surfing" }),
-(ir:Person { name: "Ian", from: "England", title: "author" }),
-(rvb:Person { name: "Rik", from: "Belgium", pet: "Orval" }),
-(ally:Person { name: "Allison", from: "California", hobby: "surfing" }),
-(ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir),
-(js)-[:KNOWS]->(ir),(js)-[:KNOWS]->(rvb),
-(ir)-[:KNOWS]->(js),(ir)-[:KNOWS]->(ally),
-(rvb)-[:KNOWS]->(ally)
-
-
-
- -
-

Pattern matching

-

Describe what to find in the graph

-
-
-

For instance, a pattern can be used to find Emil's friends:

-
-
MATCH (ee:Person)-[:KNOWS]-(friends)
-WHERE ee.name = "Emil" RETURN ee, friends
-
-
    -
  • MATCHclause to describe the pattern from known Nodes to found Nodes
  • -
  • (ee)starts the pattern with a Person (qualified by WHERE)
  • -
  • -[:KNOWS]-matches "KNOWS" relationships (in either direction)
  • -
  • (friends)will be bound to Emil's friends
  • -
-
-
- -
-

Recommend

-

Using patterns

-
-
-

- Pattern matching can be used to make recommendations. Johan is learning to surf, so he may want to find - a new friend who already does: -

-
-
MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)
-WHERE js.name = "Johan" AND surfer.hobby = "surfing"
-RETURN DISTINCT surfer
-
-
    -
  • ()empty parenthesis to ignore these nodes
  • -
  • DISTINCTbecause more than one path will match the pattern
  • -
  • surferwill contain Allison, a friend of a friend who surfs
  • -
-
-
- -
-

Next steps

-

- Start your application using Cypher to create and query graph data. Use the REST API - to monitor the database. In special cases, consider a plugin. -

-
-
-

Keep getting started

- -
-
-

Jump into code

- -
-
-
- \ No newline at end of file diff --git a/adoc/query-template.adoc b/examples/query-template.adoc similarity index 100% rename from adoc/query-template.adoc rename to examples/query-template.adoc diff --git a/adoc/template-table.adoc b/examples/template-table.adoc similarity index 100% rename from adoc/template-table.adoc rename to examples/template-table.adoc diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..cc4fdc2 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9492014 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..2fe81a7 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9618d8d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/guide-extension/.gitignore b/guide-extension/.gitignore deleted file mode 100644 index 775e11c..0000000 --- a/guide-extension/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -neo4j-home -.idea -.DS_Store -*.ipr -*.iws -*.iml -*.zip -target -*.log -tmp - diff --git a/guide-extension/guides_in_neo_demo.jpg b/guide-extension/guides_in_neo_demo.jpg deleted file mode 100644 index 2e6a0e3..0000000 Binary files a/guide-extension/guides_in_neo_demo.jpg and /dev/null differ diff --git a/guide-extension/pom.xml b/guide-extension/pom.xml deleted file mode 100644 index 6a94145..0000000 --- a/guide-extension/pom.xml +++ /dev/null @@ -1,143 +0,0 @@ - - 4.0.0 - org.neo4j - neo4j-guide-extension - jar - 3.2.3 - Neo4j-Web - Neo4j Web Extension - - UTF-8 - 1.7.6 - 3.2.3 - 1.19 - - - - - java.net - http://download.java.net/maven/2 - - - - - junit - junit - 4.12 - test - - - org.codehaus.jackson - jackson-jaxrs - 1.9.13 - - - org.neo4j - neo4j - ${neo4j.version} - - - org.neo4j - neo4j-io - ${neo4j.version} - test - test-jar - - - org.neo4j - neo4j-kernel - ${neo4j.version} - test - test-jar - - - org.apache.httpcomponents - httpclient - 4.4 - test - - - org.neo4j.test - neo4j-harness - ${neo4j.version} - test - - - org.neo4j - server-api - ${neo4j.version} - - - org.neo4j.app - neo4j-server - ${neo4j.version} - test - test-jar - - - org.neo4j.app - neo4j-server - ${neo4j.version} - provided - - - org.neo4j - neo4j - - - org.mortbay.jetty - jetty - - - com.sun.jersey - jersey-server - - - de.huxhorn.lilith - de.huxhorn.lilith.3rdparty.rrd4j - - - com.sun.jersey.contribs - jersey-multipart - - - org.apache.felix - org.apache.felix.main - - - org.apache.felix - org.apache.felix.fileinstall - - - - - org.mortbay.jetty - jetty - 6.1.25 - test - - - com.sun.jersey - jersey-server - ${jersey.version} - - - com.sun.jersey - jersey-client - ${jersey.version} - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.1 - - 1.7 - 1.7 - - - - - diff --git a/guide-extension/readme.adoc b/guide-extension/readme.adoc deleted file mode 100644 index d8101cd..0000000 --- a/guide-extension/readme.adoc +++ /dev/null @@ -1,60 +0,0 @@ -== Neo4j Server Extension for Serving Browser Guides - -This is an a simple extension for http://neo4j.com/download[Neo4j Server] that can serve html content from a pre-configured directory. - -This can be used for small, self-containted demos or Neo4j Browser Guides. - -=== The Demo: Neo4j-Guides - -As my demo I provide a setup that exposes HTML files for a Neo4j-Guide from a configured directory. - -The `StaticWebResource` provides the web-files of the visualization from the `resources/webapp` directory. - -*Note that you have to disable auth for this demo as I haven't added means for it to retrieve a username/password.* - -You can use the demo by cloning and building (`mvn clean install`) this repository. -And then copy the resulting jar in the server's plugin directory. -And edit `neo4j-server.properties` to register the package name with an endpoint. - -.For Neo4j 2.3 -[source] ----- -cp target/neo4j-guide-extension-2.3.2.jar $NEO4J_HOME/plugins/ -echo 'org.neo4j.server.thirdparty_jaxrs_classes=extension.web=/guides' >> $NEO4J_HOME/conf/neo4j-server.properties -echo 'org.neo4j.server.guide.directory=data/guides' >> $NEO4J_HOME/conf/neo4j-server.properties -$NEO4J_HOME/bin/neo4j restart - -:play http://localhost:7474/guides/test.html ----- - -.For Neo4j 3.x -[source] ----- -cp target/neo4j-guide-extension-2.3.2.jar $NEO4J_HOME/plugins/ -echo 'dbms.unmanaged_extension_classes=extension.web=/guides' >> $NEO4J_HOME/conf/neo4j-server.conf -echo 'org.neo4j.server.guide.directory=data/guides' >> $NEO4J_HOME/conf/neo4j-server.conf -$NEO4J_HOME/bin/neo4j restart - -:play http://localhost:7474/guides/test.html ----- - -.This shows the restaurant-recommendation-graphgist running inside the Neo4j-Browser -image::guides_in_neo_demo.jpg[] - -You can also download https://dl.dropboxusercontent.com/u/14493611/neo4j-guide-extension-2.3.2.jar[the 2.3.2 JAR from here]. - -=== How does it work? - -It is actually quite simple. -This is the core idea of exposing static web resources under the mountpoint. - -[source,java] ----- -@GET -@Path("{file:(?i).+\\.(png|jpg|jpeg|svg|gif|html?|js|css|txt|grass)}") -public Response file(@PathParam("file") String file) throws IOException { - InputStream fileStream = findFileStream(file); - if (fileStream == null) return Response.status(Response.Status.NOT_FOUND).build(); - else return Response.ok(fileStream, mediaType(file)).build(); -} ----- diff --git a/guide-extension/src/main/java/extension/web/StaticWebResource.java b/guide-extension/src/main/java/extension/web/StaticWebResource.java deleted file mode 100644 index 88563be..0000000 --- a/guide-extension/src/main/java/extension/web/StaticWebResource.java +++ /dev/null @@ -1,96 +0,0 @@ -package extension.web; - -import org.neo4j.kernel.configuration.Config; -import org.neo4j.server.web.WebServer; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -@Path("/") -public class StaticWebResource { - - private File directory; - - public StaticWebResource(@Context Config configuration, @Context WebServer server) { - - String path = configuration.getRaw().get("org.neo4j.server.guide.directory"); - if (path == null) path = "guides"; - File file = new File(path); - this.directory = file.exists() ? file : null; - - } - - @Path("/") - @Produces("text/html") - @GET - public Response index() throws IOException { - return file("index.html"); // TODO html-file listing? - } - - static Map resources = new ConcurrentHashMap<>(); - - @GET - @Path("{file:(?i).+\\.(png|jpg|jpeg|svg|gif|html?|js|css|txt|grass)}") - public Response file(@PathParam("file") String file) throws IOException { - InputStream fileStream = findFileStream(file); - if (fileStream == null) return Response.status(Response.Status.NOT_FOUND).build(); - else return Response.ok(fileStream, mediaType(file)).build(); - } - - private InputStream findFileStream(String fileName) throws IOException { - File file = resources.computeIfAbsent(fileName, new Function() { - public File apply(String s) { - return findFile(s); - } - }); - return file == null ? null : new FileInputStream(file); - } - - private File findFile(@PathParam("file") String file) { - File f = new File(directory, file); - return f.exists() ? f : null; - } - - public String mediaType(String file) { - int dot = file.lastIndexOf("."); - if (dot == -1) return MediaType.TEXT_PLAIN; - String ext = file.substring(dot + 1).toLowerCase(); - switch (ext) { - case "png": - return "image/png"; - case "gif": - return "image/gif"; - case "json": - return MediaType.APPLICATION_JSON; - case "js": - return "text/javascript"; - case "css": - return "text/css"; - case "svg": - return MediaType.APPLICATION_SVG_XML; - case "html": - return MediaType.TEXT_HTML; - case "txt": - return MediaType.TEXT_PLAIN; - case "jpg": - case "jpeg": - return "image/jpg"; - default: - return MediaType.TEXT_PLAIN; - } - } -} diff --git a/guide-extension/src/test/java/extension/web/StaticWebResourceTest.java b/guide-extension/src/test/java/extension/web/StaticWebResourceTest.java deleted file mode 100644 index eabd61c..0000000 --- a/guide-extension/src/test/java/extension/web/StaticWebResourceTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package extension.web; - -import org.junit.Rule; -import org.junit.*; -import org.neo4j.harness.junit.Neo4jRule; -//import org.neo4j.test.Mute; -import org.neo4j.test.server.HTTP; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonMap; -import static org.junit.Assert.*; - -public class StaticWebResourceTest { - - private final static String CONTENT = "

Hello World

"; - - @Rule - public Neo4jRule server = new Neo4jRule() - .withConfig("org.neo4j.server.guide.directory","neo4j-home/guides") - .withExtension("/guides", StaticWebResource.class.getPackage().getName()); - - - @Before public void setUp() throws IOException { - // todo create / copy file to the server directory neo4j-home/guides - File guides = new File("neo4j-home","guides"); - guides.mkdirs(); - Writer w = new FileWriter(new File(guides,"test.html")); - w.write(CONTENT); - w.close(); - } - @Test - public void testConfig() throws Exception { - String baseUri = server.httpURI().resolve("/guides/").toString(); - HTTP.Response response = - HTTP.withBaseUri(baseUri).GET("test.html"); - - assertEquals(200, response.status()); - String content = response.rawContent(); - System.err.println(content); - assertEquals(CONTENT, content); - } - - -} diff --git a/html/browser.html b/html/browser.html deleted file mode 100644 index 120cbf5..0000000 --- a/html/browser.html +++ /dev/null @@ -1,432 +0,0 @@ - -
- - - - - - -
-

Get Started

-
-
-
-

Start by typing :play intro into the command-line and pressing Enter. -Please follow the guide to learn about our user interface.

-
-
-
-
- - - - -
-

Feedback & Questions

-
-
-
-

If you have feedback or questions on how to use the Neo4j Browser, there is a small messaging system in the configuration (cog) drawer. -You can provide your name and send us a message.

-
-
-
-
- - - - -
-

Useful Commands and Keyboard Shortcuts

-
-
- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ShortcutPurpose

:help

Help System

:help commands

Useful Commands

:clear

Clear Frames

:style [reset]

Styling Popup & Reset

:help keys

Keyboard Help

Ctrl+Enter or Cmd+Enter

Execute Statement

Ctrl+Up or Cmd+Up

Previous Statement

Shift+Enter

Enter Multiline Mode

/

Move Focus to Editor

ESC

Toggle Editor to Full Screen

-
-
-
- - - - -
-

Built in Guides

-
-
-
-

If you want to learn more first, click on any of the helpful links shown after startup: these are quick guides that introduce the different concepts. -You find more helpful links in the left sidebar in the "Information" tab, with the (i).

-
-
-
    -
  • -

    Intro - a guided tour of Neo4j browser :play intro

    -
  • -
  • -

    Concepts - GraphDB 101 :play concepts

    -
  • -
  • -

    Cypher - query language :play cypher

    -
  • -
  • -

    The Movie Graph - a mini graph model with use-cases :play movie graph

    -
  • -
  • -

    The Northwind Database - the classic demo database with import instructions & use-case queries :play northwind graph

    -
  • -
  • -

    Custom Guides - starting with Neo4j 2.3 you can use :play <url> to play a custom guide, e.g. :play http://guides.neo4j.com/intro/create.html from the fundamentals training.

    -
  • -
-
-
-

Import our sample movie graph by entering :play movie graph.

-
-
-

On the second slide click the large Cypher CREATE ... statement, then hit the Run button.

-
-
-

After a few seconds the data is imported, and you’ll see a subset of the movie data rendered as a graph.

-
-
-
-
- - - - -
-

Styling Neo4j Browser Visualization

-
-
-
-

You can pan the visual view around and drag nodes to rearrange them.

-
-
-

The nodes already have a sensible captions, it auto-selects a property from the property list to be rendered as caption.

-
-
-

If you click on any node or relationship you see the properties of that element below the visualization, larger property sets might be folded in, there is a little triangle on the right to fold them out.

-
-
-

E.g. you click on one of the Movies then you can see it’s properties below the graph. -Same for actors or the ACTED_IN relationships.

-
-
-

If you click on any label or relationship above the graph visualization, you can then chose its styling in the area below the graph.

-
-
-

Colors, sizes and captions are selectable from there.

-
-
-

For instance click on the (Movies) label above the graph and change the color, size and captions of nodes labeled with Movie.

-
-
-
-style node -
-
-
-
-style relationship -
-
-
-
-
- - - - -
-

Running Queries

-
-
-
-

When you continue with the guide, you will see more queries. -You can get them into the editor by clicking on them. -To execute, hit the triangular play button.

-
-
-

Query results are rendered either as visual graph or tabular result. -You can switch between those with the icons on the left side of the result frame.

-
-
-

Remove all accumulated output frames with :clear, the cross removes a single frame and aborts a (long-)running statement.

-
-
-

You can click the query above the graph visualisation to pull it back into the editor.

-
-
-

Use the keyboard shortcuts listed above to work efficiently with the editor area.

-
-
-

Navigate input history with Ctrl+Up and Ctrl+Down, access all of it via :history. The history will be persisted across browser restarts.

-
-
-

You can switch between tabular, visual mode, query plan and x-ray mode for results with the icons on the left of each panel,

-
-
- - - - - -
-
Note
-
-Don’t worry if you don’t see any output, you might just be in visual mode but returned tabular/scalar data, just switch the mode to tabular -
-
-
-

Query time is reported in the tabular view, don’t rely on that exact timing though it includes the latency and (de-)serialization costs, not just the actual query execution time.

-
-
-

You can download the results as CSV from the tabular output panel (top right download icon), and as JSON (download icon above the panel). -The graph visualization can be exported as PNG and SVG.

-
-
-
-
- - - - -
-

Meta Graph

-
-
-
-

In the left side drawer on the three bubbles section (that resemble the Neo4j logo) you find the currently used node-labels and relationship types. -Clicking on any of those runs a quick query to show you a sample of the graph using those.

-
-
-
-
- - - - -
-

Queries and Favorites

-
-
-
-

If you start with an empty frame, display some nodes and relationships, use the Favorites (Star) drawer on the left, click on the Get Some Data entry, and run the query. -This executes the statement MATCH (n) RETURN n limit 100 which fetches some nodes.

-
-
-

The browser helpfully also fetches and displays relationships between those nodes, even if they were not part of your query result. -You can disable the latter behavior with the "Auto-Complete" switch in the bottom left corner. -Then only relationships returned by the actual query will be shown.

-
-
-

You can save your own queries as favorites by "starring" them. -Use a comment // comment above your query for a title. -Use folders to organize the favorites you can rearrange them by dragging and delete if they are no longer useful.

-
-
- - - - - -
-
Note
-
-Favorites are stored in your local browser storage, so they are only available per Browser and URL. -
-
- - - -
-

For more advanced styling you can bring up the style-viewer with :style, download the graph-style-sheet (GRASS), edit it offline and drag it back onto the drag-area of the viewer.

-
-
- - - - - -
-
Note
-
-You can reset to the default styles with :style reset. -Alternatively by clicking the "fire extinguisher" icon in the popup from :style. -
-
-
-

Within the GRASS file you can change colors, fonts, sizes, outlines and titles per node-label and relationship-type. -It is also possible to combine multiple properties into a caption with caption: '{name}, born in {born}';

-
-
-
-style sheet grass -
-
-
-
-
- - - - -
-

Configuration

-
-
-
-
    -
  • -

    since Neo4j 2.3 there is a config drawer on the left (with the cog), no need for the :config command anymore

    -
  • -
  • -

    you can retrieve the current configuration with :config

    -
  • -
  • -

    the individual settings are configured with:

    -
    -
      -
    • -

      :config maxNeighbours:100 - maxiumum number of neighbours for a node

      -
    • -
    • -

      :config maxRows:100 - maximum number of rows for the tabular result

      -
    • -
    -
    -
  • -
-
-
-
-
- - - - -
-

Executing REST requests

-
-
-
-

You can also execute REST requests with the Neo4j Browser, the command-syntax is
-:COMMAND /a/path {"some":"data"}. -The available commands are :GET, :POST, :PUT and :DELETE.

-
-
-

A simple query would inspect the available endpoints of the database :GET /db/data/, the results are listed as formatted JSON. -Then you can for instance retrieve all labels in the database with :GET /db/data/labels.

-
-
-

To execute a Cypher statement you post to the transaction Cypher endpoint like this:

-
-
-
-
:POST /db/data/transaction/commit {"statements":[
-     {"statement":"MATCH (m:Movie)  WHERE m.title={title} RETURN m.title, m.released, labels(m)",
-      "parameters":{"title":"Cloud Atlas"}}]}
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/html/restaurant_recommendation.html b/html/restaurant_recommendation.html deleted file mode 100644 index 2807d39..0000000 --- a/html/restaurant_recommendation.html +++ /dev/null @@ -1,193 +0,0 @@ - - -
- - - - - -

Restaurant Recommendations

- - - - -
-

Introduction

-
-
-
-
-sushi restaurants nyc -
-
-
-

We want to demonstrate how easy it is to model a domain as a graph and answer questions in almost natural language.

-
-
-

Graph Based Search and Discovery is prominent a use-case for graph databases like Neo4j.

-
-
-

Here we use a Domain of restaurants which serve cuisines and are located in a City.

-
-
-

The domain diagram was created with the Arrows tool

-
-
-
-
- - - - -
-

Setup: Creating Friends, Restaurants in Cities and their Cusines

-
-
-
-
-
CREATE (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]->(emil:Person {name:"Emil"}),
-       (philip)-[:IS_FRIEND_OF]->(michael:Person {name:"Michael"}),
-       (philip)-[:IS_FRIEND_OF]->(andreas:Person {name:"Andreas"})
-CREATE (sushi:Cuisine {name:"Sushi"}), (nyc:City {name:"New York"}),
-       (iSushi:Restaurant {name:"iSushi"})-[:SERVES]->(sushi),(iSushi)-[:LOCATED_IN]->(nyc),
-       (michael)-[:LIKES]->(iSushi),
-       (andreas)-[:LIKES]->(iSushi),
-       (zam:Restaurant {name:"Zushi Zam"})-[:SERVES]->(sushi),(zam)-[:LOCATED_IN]->(nyc),
-       (andreas)-[:LIKES]->(zam)
-
-
-
-
-
- - - - -
-

Philips Friends

-
-
-
-
-
MATCH (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]-(person)
-RETURn person.name
-
-
-
-
-
- - - - -
-

Restaurants in NYC and their cusines

-
-
-
-
-
MATCH (nyc:City {name:"New York"})<-[:LOCATED_IN]-(restaurant)-[:SERVES]->(cusine)
-RETURN nyc, restaurant, cusine
-
-
-
-
-
- - - - -
-

Graph Search Recommendation

-
-
-
-
-sushi restaurants nyc -
-
-
-

We want to answer the following question

-
-
-
-
-

Find Sushi Restaurants in New York that my friends like.

-
-
-
-
-

To satisfy this question, we have to know who’s asking: Philip and he’s asking for 4 connected facts

-
-
-
    -
  • -People that are friends of Philip -
  • -
  • -Restaurants located in New York -
  • -
  • -Restaurants that server Sushi -
  • -
  • -Restaurants that his Friends like -
  • -
-
-
-
-
MATCH (philip:Person {name:"Philip"}),
-      (philip)-[:IS_FRIEND_OF]-(friend),
-      (restaurant:Restaurant)-[:LOCATED_IN]->(:City {name:"New York"}),
-      (restaurant)-[:SERVES]->(:Cuisine {name:"Sushi"}),
-      (friend)-[:LIKES]->(restaurant)
-RETURN restaurant.name, collect(friend.name) AS likers, count(*) AS occurence
-ORDER BY occurence DESC
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/html/restaurant_recommendation.txt.html b/html/restaurant_recommendation.txt.html deleted file mode 100644 index c3b600c..0000000 --- a/html/restaurant_recommendation.txt.html +++ /dev/null @@ -1,163 +0,0 @@ - -
- - - - - - -
-

Restaurant Recommendations

-
-
- - - -
-
-sushi restaurants nyc -
-
-
-

We want to demonstrate how easy it is to model a domain as a graph and answer questions in almost natural language.

-
-
-

Graph Based Search and Discovery is prominent a use-case for graph databases like Neo4j.

-
-
-

Here we use a Domain of restaurants which serve cuisines and are located in a City.

-
-
-

The domain diagram was created with the Arrows tool

-
- - - -
-
-
CREATE (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]->(emil:Person {name:"Emil"}),
-       (philip)-[:IS_FRIEND_OF]->(michael:Person {name:"Michael"}),
-       (philip)-[:IS_FRIEND_OF]->(andreas:Person {name:"Andreas"})
-create (sushi:Cuisine {name:"Sushi"}), (nyc:City {name:"New York"}),
-       (iSushi:Restaurant {name:"iSushi"})-[:SERVES]->(sushi),(iSushi)-[:LOCATED_IN]->(nyc),
-       (michael)-[:LIKES]->(iSushi),
-       (andreas)-[:LIKES]->(iSushi),
-       (zam:Restaurant {name:"Zushi Zam"})-[:SERVES]->(sushi),(zam)-[:LOCATED_IN]->(nyc),
-       (andreas)-[:LIKES]->(zam)
-
-
- - - -
-
-
MATCH (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]-(person)
-RETURn person.name
-
-
- - - -
-
-
MATCH (nyc:City {name:"New York"})<-[:LOCATED_IN]-(restaurant)-[:SERVES]->(cusine)
-RETURN nyc, restaurant, cusine
-
-
- - - -
-
-sushi restaurants nyc -
-
-
-

We want to answer the following question

-
-
-
-
-

Find Sushi Restaurants in New York that my friends like.

-
-
-
-
-

To satisfy this question, we have to know who’s asking: Philip and he’s asking for 4 connected facts

-
-
-
    -
  • -

    People that are friends of Philip

    -
  • -
  • -

    Restaurants located in New York

    -
  • -
  • -

    Restaurants that server Sushi

    -
  • -
  • -

    Restaurants that his Friends like

    -
  • -
-
-
-
-
MATCH (philip:Person {name:"Philip"}),
-      (philip)-[:IS_FRIEND_OF]-(friend),
-      (restaurant:Restaurant)-[:LOCATED_IN]->(:City {name:"New York"}),
-      (restaurant)-[:SERVES]->(:Cuisine {name:"Sushi"}),
-      (friend)-[:LIKES]->(restaurant)
-RETURN restaurant.name, collect(friend.name) as likers, count(*) as occurence
-ORDER BY occurence DESC
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/http-server.py b/http-server.py deleted file mode 100755 index 8acc156..0000000 --- a/http-server.py +++ /dev/null @@ -1,23 +0,0 @@ -#! /usr/bin/env python -import os -try: - from http.server import HTTPServer, SimpleHTTPRequestHandler -except ImportError: - from BaseHTTPServer import HTTPServer - from SimpleHTTPServer import SimpleHTTPRequestHandler - -class CORSRequestHandler(SimpleHTTPRequestHandler): - - def end_headers (self): - self.send_header('Access-Control-Allow-Origin', '*') - self.send_header('Access-Control-Allow-Methods', 'GET') - self.send_header('Access-Control-Allow-Headers', '*') - self.send_header('Access-Control-Allow-Headers', 'Pragma,Cache-Control,If-Modified-Since,Content-Type,X-Requested-With,X-stream,X-Ajax-Browser-Auth') - SimpleHTTPRequestHandler.end_headers(self) - - def do_OPTIONS(self): - self.send_response(200) - self.end_headers() - -if __name__ == '__main__': - HTTPServer(('0.0.0.0', 8001), CORSRequestHandler).serve_forever() diff --git a/http.rb b/http.rb deleted file mode 100644 index 1be0213..0000000 --- a/http.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'rubygems' -require 'sinatra' - -before do - response['Access-Control-Allow-Headers'] = '*, pragma, cache-control, x-stream, accept, If-Modified-Since, X-Ajax-Browser-Auth' - response['Access-Control-Allow-Methods'] = 'GET, OPTIONS' - response['Access-Control-Allow-Origin'] = request.env['HTTP_ORIGIN'] -end - -options '*' do - 200 -end - -get '/:file' do |file| - send_file File.join("html", file) -end \ No newline at end of file diff --git a/http.sh b/http.sh deleted file mode 100644 index 89ea357..0000000 --- a/http.sh +++ /dev/null @@ -1,3 +0,0 @@ -PORT=${1-8001} -gem install --no-ri --no-rdoc sinatra -ruby http.rb -p $PORT \ No newline at end of file diff --git a/readme.adoc b/readme.adoc index c9c89de..1f363be 100644 --- a/readme.adoc +++ b/readme.adoc @@ -1,38 +1,40 @@ == Converting Asciidoc Files to Neo4j Browser Guides -This program uses AsciiDoctor erb templates to generate an outline html and a slide for each level two header. +This program uses AsciiDoctor ERB templates to generate an outline HTML and a slide for each level two header. === Create HTML ----- -./run.sh path/to/a_guide.adoc [guide.html] +The following command will convert the AsciiDoc files in _guide/docs_ to HTML: --> html/a_guide.html ----- + $ ./gradlew convert + +The HTML files are available in the _build/browser-guide_ directory at the root of this repository. === Start Local Server -It is patched to allow CORS headers for the browser to serve the HTML directory. +In a new terminal, run the following command to start a local HTTP server: +[source,console] ---- -python http-server.py & +$ ./gradlew httpServer ---- -=== Configuration +=== View in Neo4j Browser -* before Neo4j 3.0 add `dbms.browser.remote_content_hostname_whitelist=*` to `conf/neo4j-server.properties` -* from Neo4j 3.0 add `browser.remote_content_hostname_whitelist=*` to `conf/neo4j.conf` +To view this guide in the Neo4j Browser, type the following command in the action bar: -and restart. -You can also add the specific `localhost:8001` address. - -For `neo4j-community` you have to use `sudo` and run the http script on port 80. -For example, use `BaseHTTPServer.HTTPServer(("0.0.0.0", 80),CORSRequestHandler).serve_forever()` in `http.py` +---- +:play http://localhost:35729/browser-guide/index.html +---- -To view the guides in the Neo4j Browser, run: +[TIP] +==== +You can use the `--continuous` flag to automatically convert the AsciiDoc files to HTML when the content is updated: +[source,console] ---- -:play http://localhost:8001/html/a_guide.html +$ ./gradlew convert --continuous ---- +==== -You can find more details on how to create guides and their format in link:docs/remote-guides.md[] and an example in link:docs/remote.html[] +You can find more details on how to create guides and their format at https://neo4j.com/developer/guide-create-neo4j-browser-guide/ diff --git a/restaurant-recommendation/docs/01.adoc b/restaurant-recommendation/docs/01.adoc new file mode 100644 index 0000000..8e25071 --- /dev/null +++ b/restaurant-recommendation/docs/01.adoc @@ -0,0 +1,49 @@ += Restaurant Recommendations + +== Restaurant Recommendations + +Welcome to the Neo4j Applied Graph Data Science for Web Applications Training Course! + +In this guide we're going to get familiar with the Yelp dataset. +Let's get started! + +== Graph Model + +This is the graph model that we'll be working with: + +image::sushi_restaurants_nyc.svg[height=300] + +== Setup: Creating Friends, Restaurants in Cities and their Cuisines + +[source,cypher] +---- +CREATE (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]->(emil:Person {name:"Emil"}), + (philip)-[:IS_FRIEND_OF]->(michael:Person {name:"Michael"}), + (philip)-[:IS_FRIEND_OF]->(andreas:Person {name:"Andreas"}) +CREATE (sushi:Cuisine {name:"Sushi"}), (nyc:City {name:"New York"}), + (iSushi:Restaurant {name:"iSushi"})-[:SERVES]->(sushi),(iSushi)-[:LOCATED_IN]->(nyc), + (michael)-[:LIKES]->(iSushi), + (andreas)-[:LIKES]->(iSushi), + (zam:Restaurant {name:"Zushi Zam"})-[:SERVES]->(sushi),(zam)-[:LOCATED_IN]->(nyc), + (andreas)-[:LIKES]->(zam) +---- + +== Philips Friends + +[source,cypher] +---- +MATCH (philip:Person {name:"Philip"})-[:IS_FRIEND_OF]-(person) +RETURn person.name +---- + +== Restaurants in NYC and their cusines + +[source,cypher] +---- +MATCH (nyc:City {name:"New York"})<-[:LOCATED_IN]-(restaurant)-[:SERVES]->(cusine) +RETURN nyc, restaurant, cusine +---- + +ifdef::env-guide[] +pass:a[Continue to Exercise 2: Graph Search Recommendation] +endif::[] diff --git a/restaurant-recommendation/docs/02.adoc b/restaurant-recommendation/docs/02.adoc new file mode 100644 index 0000000..86f008e --- /dev/null +++ b/restaurant-recommendation/docs/02.adoc @@ -0,0 +1,30 @@ += Restaurant Recommendations + +== Graph Search Recommendation + +image::sushi_restaurants_nyc.png[height=300] + +We want to answer the following question + +"" Find Sushi Restaurants in New York that my friends like. +"" + +== Find Relations + +To satisfy this question, we have to know who's asking: _Philip_ and he's asking for 4 connected facts + +* _People_ that are friends of _Philip_ +* _Restaurants_ located in _New York_ +* _Restaurants_ that server _Sushi_ +* _Restaurants_ that his _Friends_ like + +[source,cypher] +---- +MATCH (philip:Person {name:"Philip"}), + (philip)-[:IS_FRIEND_OF]-(friend), + (restaurant:Restaurant)-[:LOCATED_IN]->(:City {name:"New York"}), + (restaurant)-[:SERVES]->(:Cuisine {name:"Sushi"}), + (friend)-[:LIKES]->(restaurant) +RETURN restaurant.name, collect(friend.name) AS likers, count(*) AS occurence +ORDER BY occurence DESC +---- diff --git a/restaurant-recommendation/docs/index.adoc b/restaurant-recommendation/docs/index.adoc new file mode 100644 index 0000000..dffc6b2 --- /dev/null +++ b/restaurant-recommendation/docs/index.adoc @@ -0,0 +1,27 @@ += Restaurant Recommendations +:imagesdir: ../images + +== Restaurant Recommendations + +We want to demonstrate how easy it is to model a domain as a graph and answer questions in almost natural language. +Graph Based Search and Discovery is prominent a use-case for graph databases like http://neo4j.com[Neo4j]. +Here we use a Domain of restaurants which serve cuisines and are located in a City. + +The domain diagram was created with the http://www.apcjones.com/arrows/#[Arrows tool]. + +Here are the exercises you perform for this course: + +. pass:a[Setup] +. pass:a[Graph Search Recommendation] + +== Further Resources + +* http://neo4j.com/graphgists[Graph Gist Examples] +* http://neo4j.com/docs/stable/cypher-refcard/[Cypher Reference Card] +* http://neo4j.com/docs/developer-manual/current/#cypher-query-lang[Neo4j Developer Manual] +* http://neo4j.com/developer/resources#_neo4j_cypher_resources[Cypher Resource Collection] +* http://graphdatabases.com[e-book: Graph Databases (free)] + +ifdef::env-guide[] +pass:a[Continue to Exercise 1: Setup] +endif::[] diff --git a/img/sushi_restaurants_nyc.png b/restaurant-recommendation/images/sushi_restaurants_nyc.png similarity index 100% rename from img/sushi_restaurants_nyc.png rename to restaurant-recommendation/images/sushi_restaurants_nyc.png diff --git a/img/sushi_restaurants_nyc.svg b/restaurant-recommendation/images/sushi_restaurants_nyc.svg similarity index 100% rename from img/sushi_restaurants_nyc.svg rename to restaurant-recommendation/images/sushi_restaurants_nyc.svg diff --git a/run.sh b/run.sh deleted file mode 100755 index 3fb3b2f..0000000 --- a/run.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -asciidoctor -v || gem install asciidoctor - -echo "Usage ./run.sh OR ./run.sh path/to/a_guide.adoc [guide.html] [+1 (header-offset)] [http://guide-host:port]" -# mkdir -p html -DIR=${0%%/run.sh} - -function render { - ADOC=${1-../exercise/lab_01.adoc} - shift - HTML=${ADOC%.*}.html - HTML=html/${HTML##*/} - HTML=${1-$HTML} - shift - OFFSET=${1-+1} - shift - BASE_URL=${1-http://guides.neo4j.com/intro} - shift - echo rendering $ADOC to $HTML -echo asciidoctor $ADOC -T $DIR/templates -a allow-uri-read -a experimental -a guides=$BASE_URL -a current=$BASE_URL -a img=$BASE_URL/img -a leveloffset=${OFFSET} -a env-guide= -a guide= -o ${HTML} "$@" - asciidoctor $ADOC -T $DIR/templates -a allow-uri-read -a guides=$BASE_URL -a icons=font -a current=$BASE_URL -a img=$BASE_URL/img -a leveloffset=${OFFSET} -a env-guide= -a guide= -o ${HTML} "$@" -} - -if [ $# == 0 ]; then - render ../exercise/lab_01.adoc - render ../exercise/lab_02.adoc - render ../exercise/lab_03.adoc - render ../04_create_data_interactive.adoc html/create.html - render ../05_cypher_deep_dive_starter.adoc html/starter.html - render ../05_cypher_deep_dive_expert.adoc html/expert.html - render ../05_cypher_deep_dive_advanced.adoc html/advanced.html -else - render "$@" -fi - -# s3cmd put -P --recursive html/* s3://guides.neo4j.com/intro/ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..7662e8e --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'neo4j-guide' + +include 'restaurant-recommendation' +project(':restaurant-recommendation').projectDir = file('restaurant-recommendation') + diff --git a/templates/block_admonition.html.erb b/templates/block_admonition.html.erb old mode 100644 new mode 100755 index 4eb9fd9..215b430 --- a/templates/block_admonition.html.erb +++ b/templates/block_admonition.html.erb @@ -3,11 +3,11 @@ <% if @document.attr? :icons, 'font' %> -<% +<% elsif @document.attr? :icons %> -<%= @caption %><% +<%= attr 'textlabel' %><% else %> -
<%= @caption %>
<% +
<%= attr 'textlabel' %>
<% end %> <% diff --git a/templates/block_audio.html.erb b/templates/block_audio.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_colist.html.erb b/templates/block_colist.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_dlist.html.erb b/templates/block_dlist.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_example.html.erb b/templates/block_example.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_floating_title.html.erb b/templates/block_floating_title.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_image.html.erb b/templates/block_image.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_listing.html.erb b/templates/block_listing.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_literal.html.erb b/templates/block_literal.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_math.html.erb b/templates/block_math.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_olist.html.erb b/templates/block_olist.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_open.html.erb b/templates/block_open.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_page_break.html.erb b/templates/block_page_break.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_paragraph.html.erb b/templates/block_paragraph.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_pass.html.erb b/templates/block_pass.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_preamble.html.erb b/templates/block_preamble.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_quote.html.erb b/templates/block_quote.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_ruler.html.erb b/templates/block_ruler.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_sidebar.html.erb b/templates/block_sidebar.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_table.html.erb b/templates/block_table.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_toc.html.erb b/templates/block_toc.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_ulist.html.erb b/templates/block_ulist.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_verse.html.erb b/templates/block_verse.html.erb old mode 100644 new mode 100755 diff --git a/templates/block_video.html.erb b/templates/block_video.html.erb old mode 100644 new mode 100755 diff --git a/templates/document.html.erb b/templates/document.html.erb old mode 100644 new mode 100755 diff --git a/templates/embedded.html.erb b/templates/embedded.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_anchor.html.erb b/templates/inline_anchor.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_break.html.erb b/templates/inline_break.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_button.html.erb b/templates/inline_button.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_callout.html.erb b/templates/inline_callout.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_footnote.html.erb b/templates/inline_footnote.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_image.html.erb b/templates/inline_image.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_indexterm.html.erb b/templates/inline_indexterm.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_kbd.html.erb b/templates/inline_kbd.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_menu.html.erb b/templates/inline_menu.html.erb old mode 100644 new mode 100755 diff --git a/templates/inline_quoted.html.erb b/templates/inline_quoted.html.erb old mode 100644 new mode 100755 diff --git a/templates/section.html.erb b/templates/section.html.erb old mode 100644 new mode 100755 index 0503325..224ddab --- a/templates/section.html.erb +++ b/templates/section.html.erb @@ -1,5 +1,4 @@ <% slevel = @level.zero? && @special ? 1 : @level %> -<% puts("#{slevel} #{title}")%> <% if slevel == 2 %>
@@ -13,4 +12,4 @@ <% else %>

<%=title %>

<%= content %> -<% end %> \ No newline at end of file +<% end %>