├── .gitignore ├── .gitmodules ├── README.md ├── configuration ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── neo4j │ └── graphdatabases │ ├── AccessControlConfig.java │ ├── AccessControlWithRelationshipPropertiesConfig.java │ ├── LogisticsConfig.java │ ├── SimpleSocialNetworkConfig.java │ └── SocialNetworkConfig.java ├── data-generation ├── pom.xml └── src │ └── test │ └── java │ └── org │ └── neo4j │ └── graphdatabases │ └── dataset_builders │ ├── AccessControl.java │ ├── AccessControlWithRelationshipProperties.java │ ├── Logistics.java │ ├── SimpleSocialNetwork.java │ ├── SocialNetwork.java │ ├── helpers │ └── SevenDays.java │ ├── properties │ ├── DurationOnProjectProperty.java │ ├── ProjectDuration.java │ ├── ProjectDurationGenerator.java │ └── ProjectDurationProperty.java │ └── traversers │ ├── FindAllColleagues.java │ ├── FindColleagues.java │ └── IsCompanyProject.java ├── performance-testing ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── neo4j │ │ └── graphdatabases │ │ └── performance_tests │ │ └── testing │ │ ├── DefaultExecutionEngineWrapper.java │ │ ├── DoNothingWithTestResults.java │ │ ├── MultipleTestRuns.java │ │ ├── ParamsGenerator.java │ │ ├── PrintTestResults.java │ │ ├── QueryType.java │ │ ├── ResultFormatter.java │ │ ├── ResultsContainSameElementsUnordered.java │ │ ├── SingleTest.java │ │ ├── SingleTestRunResultHandler.java │ │ ├── SingleTestRunResultHandlerFactory.java │ │ ├── SysOutWriter.java │ │ ├── TakeXTestResults.java │ │ └── TestResultsHandler.java │ └── test │ └── java │ └── org │ └── neo4j │ └── graphdatabases │ └── performance_tests │ ├── AccessControl.java │ ├── AccessControlWithRelationshipProperties.java │ ├── Logistics.java │ ├── SimpleSocialNetwork.java │ ├── SocialNetwork.java │ └── testing │ └── ResultsContainSameElementsUnorderedTest.java ├── pom.xml └── queries ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── neo4j │ │ └── graphdatabases │ │ └── queries │ │ ├── AccessControlQueries.java │ │ ├── AccessControlWithRelationshipPropertiesQueries.java │ │ ├── EmailQueries.java │ │ ├── LogisticsQueries.java │ │ ├── ShakespeareQueries.java │ │ ├── ShakespeareQueriesUsingAutoIndexes.java │ │ ├── SimpleSocialNetworkQueries.java │ │ ├── SocialNetworkQueries.java │ │ ├── helpers │ │ ├── DbUtils.java │ │ ├── ExecutionEngineWrapper.java │ │ ├── ExecutionResultIterator.java │ │ ├── ExecutionResultsIterator.java │ │ ├── IndexNodeByOtherNodeIndexer.java │ │ ├── QueryUnionExecutionEngine.java │ │ └── QueryUnionExecutionResult.java │ │ ├── server │ │ └── SimpleSocialNetworkExtension.java │ │ ├── testing │ │ ├── IndexParam.java │ │ ├── IndexParams.java │ │ └── TestOutputWriter.java │ │ └── traversals │ │ ├── FriendOfAFriendDepth4.java │ │ ├── IndexResources.java │ │ ├── ParcelRouteCalculator.java │ │ └── SimpleParcelRouteCalculator.java └── resources │ └── META_INF │ └── services │ ├── javax.script.ScriptEngineFactory │ └── org.neo4j.server.plugins.ServerPlugin └── test └── java └── org └── neo4j └── graphdatabases └── queries ├── AccessControlQueriesTest.java ├── AccessControlWithRelationshipPropertiesQueriesTest.java ├── EmailQueriesTest.java ├── LogisticsQueriesTest.java ├── ShakespeareQueriesTest.java ├── SimpleSocialNetworkQueriesTest.java ├── SocialNetworkQueriesTest.java ├── helpers ├── Db.java ├── IndexNodeByOtherNodeIndexerTest.java ├── PrintingExecutionEngineWrapper.java └── QueryUnionExecutionEngineTest.java └── server └── SimpleSocialNetworkExtensionTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | datasets/ 2 | examples/ 3 | datasets-old/ 4 | .DS_Store 5 | build 6 | target 7 | .settings 8 | .project 9 | .idea 10 | .classpath 11 | *.iml 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "neode"] 2 | path = neode 3 | url = https://github.com/jexp/neode.git -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Graph Databases Use Cases 2 | ========================= 3 | 4 | Example use case implementations from the O'Reilly book [Graph Databases](http://graphdatabases.com/) by [@iansrobinson](http://twitter.com/iansrobinson), [@jimwebber](http://twitter.com/jimwebber) and [@emileifrem](http://twitter.com/emileifrem). 5 | 6 | Setup 7 | ----- 8 | 9 | This repository contains a submodule, _neode_, which is used to build the performance datasets. After cloning the repository, you will need to initialize the submodule: 10 | 11 | git submodule init 12 | 13 | and then: 14 | 15 | git submodule update 16 | 17 | To run the use case queries: 18 | 19 | mvn clean install 20 | 21 | Overview 22 | -------- 23 | 24 | Queries are developed in a test-driven fashion against small, well-known representative graphs (as described pp.83-87 of the book). The queries can then be run against a much larger, randomly-generated graph (typically, 1-2 million nodes and several million relationships), to test their relative performance. (Note: these performance tests do not test production-like scenarios; rather, they act as a sanity check, ensuring that queries that run fast against a very small graph are still reasonably performant when run against a larger graph.) 25 | 26 | The project contains 3 modules (in addition to the _neode_ submodule): 27 | 28 | * _queries_ 29 | 30 | Contains the use case queries and the unit tests used to develop the queries. 31 | * _dataset_builders_ 32 | 33 | Builds larger, randomly-generated sample datasets. 34 | * _performance_tests_ 35 | 36 | Runs the queries against the large sample datasets. 37 | 38 | Running the Performance Tests 39 | ----------------------------- 40 | 41 | First, build the project as described in Setup. 42 | 43 | Before you run the performance tests you will need to generate sample datasets. To create a sample dataset run: 44 | 45 | mvn test -pl data-generation -DargLine="-Xms2g -Xmx2g" -Dtest=AccessControl|Logistics|SocialNetwork 46 | 47 | For example, to generate a sample dataset for the Logistics queries, run: 48 | 49 | mvn test -pl data-generation -DargLine="-Xms2g -Xmx2g" -Dtest=Logistics 50 | 51 | *WARNING:* Building the sample datasets takes a long time (several tens of minutes in some cases). 52 | 53 | To execute the performance tests against a sample dataset, run: 54 | 55 | mvn test -pl performance-testing -DargLine="-Xms2g -Xmx2g" -Dtest=AccessControl|Logistics|SocialNetwork 56 | -------------------------------------------------------------------------------- /configuration/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.neo4j.graphdatabases 8 | configuration 9 | 2.0-SNAPSHOT 10 | jar 11 | 12 | 13 | 1.7 14 | 1.7 15 | UTF-8 16 | 17 | 18 | 19 | 20 | joda-time 21 | joda-time 22 | 2.1 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /configuration/src/main/java/org/neo4j/graphdatabases/AccessControlConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases; 2 | 3 | public class AccessControlConfig 4 | { 5 | public static final String STORE_DIR = "../datasets/access-control-no-attributes/"; 6 | public static final String TITLE = "Access Control (fine-grained permission relationships)"; 7 | public static final int NUMBER_OF_ADMINS = 1000; 8 | public static final int NUMBER_OF_GROUPS = 2000; 9 | public static final int NUMBER_OF_COMPANIES = 30000; 10 | } 11 | -------------------------------------------------------------------------------- /configuration/src/main/java/org/neo4j/graphdatabases/AccessControlWithRelationshipPropertiesConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases; 2 | 3 | public class AccessControlWithRelationshipPropertiesConfig 4 | { 5 | public static final String STORE_DIR = "../datasets/access-control/"; 6 | public static final String TITLE = "Access Control"; 7 | public static final int NUMBER_OF_ADMINS = 1000; 8 | public static final int NUMBER_OF_GROUPS = 2000; 9 | public static final int NUMBER_OF_COMPANIES = 30000; 10 | } 11 | -------------------------------------------------------------------------------- /configuration/src/main/java/org/neo4j/graphdatabases/LogisticsConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases; 2 | 3 | import org.joda.time.DateTime; 4 | import org.joda.time.DateTimeZone; 5 | 6 | public class LogisticsConfig 7 | { 8 | public static final String TITLE = "Logistics"; 9 | public static final String STORE_DIR = "../datasets/logistics/"; 10 | public static final DateTime START_DATE = new DateTime( 2012, 10, 15, 0, 0, 0, 0, DateTimeZone.UTC ); 11 | public static final int NUMBER_OF_PARCEL_CENTRES = 20; 12 | public static final int MIN_NUMBER_OF_DELIVERY_BASES_PER_PARCEL_CENTRE = 30; 13 | public static final int MAX_NUMBER_OF_DELIVERY_BASES_PER_PARCEL_CENTRE = 50; 14 | public static final int MIN_NUMBER_OF_DELIVERY_AREAS_PER_DELIVERY_BASE = 20; 15 | public static final int MAX_NUMBER_OF_DELIVERY_AREAS_PER_DELIVERY_BASE = 40; 16 | public static final int MIN_NUMBER_OF_DELIVERY_SEGMENTS_PER_DELIVERY_AREA = 50; 17 | public static final int MAX_NUMBER_OF_DELIVERY_SEGMENTS_PER_DELIVERY_AREA = 100; 18 | } 19 | -------------------------------------------------------------------------------- /configuration/src/main/java/org/neo4j/graphdatabases/SimpleSocialNetworkConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases; 2 | 3 | public class SimpleSocialNetworkConfig 4 | { 5 | public static final String STORE_DIR = "../datasets/simple-social-network/"; 6 | public static final String TITLE = "Simple Social Network"; 7 | public static final int NUMBER_USERS = 20900; 8 | public static final int MIN_NUMBER_OF_FRIENDS = 50; 9 | public static final int MAX_NUMBER_OF_FRIENDS = 100; 10 | } 11 | -------------------------------------------------------------------------------- /configuration/src/main/java/org/neo4j/graphdatabases/SocialNetworkConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases; 2 | 3 | public class SocialNetworkConfig 4 | { 5 | public static final String STORE_DIR = "../datasets/social-network"; 6 | public static final String TITLE = "Social Network"; 7 | public static final int NUMBER_USERS = 1000000; 8 | public static final int NUMBER_COMPANIES = 10000; 9 | public static final int NUMBER_TOPICS = 100; 10 | } 11 | -------------------------------------------------------------------------------- /data-generation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.neo4j.graphdatabases 8 | data-generation 9 | 2.0-SNAPSHOT 10 | jar 11 | 12 | 13 | 1.7 14 | 1.7 15 | UTF-8 16 | 2.0.1 17 | 18 | 19 | 20 | 21 | org.neo4j 22 | neo4j-kernel 23 | ${neo4j.version} 24 | 25 | 26 | org.neo4j 27 | neo4j-enterprise 28 | ${neo4j.version} 29 | 30 | 31 | org.neo4j.graphdatabases 32 | configuration 33 | 2.0-SNAPSHOT 34 | 35 | 36 | org.neo4j.graphdatabases 37 | queries 38 | 2.0-SNAPSHOT 39 | 40 | 41 | neode 42 | neode 43 | 2.0 44 | 45 | 46 | joda-time 47 | joda-time 48 | 2.1 49 | 50 | 51 | junit 52 | junit 53 | 4.11 54 | test 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/AccessControl.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Test; 6 | 7 | import org.neo4j.graphdatabases.AccessControlConfig; 8 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 9 | import org.neo4j.graphdatabases.queries.traversals.IndexResources; 10 | import org.neo4j.graphdb.Direction; 11 | import org.neo4j.graphdb.GraphDatabaseService; 12 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 13 | import org.neo4j.kernel.impl.util.FileUtils; 14 | import org.neo4j.neode.Dataset; 15 | import org.neo4j.neode.DatasetManager; 16 | import org.neo4j.neode.NodeCollection; 17 | import org.neo4j.neode.NodeSpecification; 18 | import org.neo4j.neode.Range; 19 | import org.neo4j.neode.RelationshipSpecification; 20 | import org.neo4j.neode.RelationshipUniqueness; 21 | import org.neo4j.neode.logging.SysOutLog; 22 | import org.neo4j.neode.statistics.AsciiDocFormatter; 23 | import org.neo4j.neode.statistics.GraphStatistics; 24 | 25 | import static org.neo4j.neode.Range.minMax; 26 | import static org.neo4j.neode.TargetNodesStrategy.create; 27 | import static org.neo4j.neode.TargetNodesStrategy.getExisting; 28 | import static org.neo4j.neode.TargetNodesStrategy.getOrCreate; 29 | import static org.neo4j.neode.properties.Property.indexableProperty; 30 | import static org.neo4j.neode.properties.Property.property; 31 | 32 | public class AccessControl 33 | { 34 | public static final Range GROUPS_PER_ADMIN = minMax( 1, 3 ); 35 | public static final Range ALLOWED_COMPANIES_PER_GROUP = minMax( 10, 50 ); 36 | public static final Range DENIED_COMPANIES_PER_GROUP = minMax( 2, 10 ); 37 | public static final Range EMPLOYEES_PER_COMPANY = minMax( 5, 100 ); 38 | public static final Range ACCOUNTS_PER_EMPLOYEE = minMax( 1, 5 ); 39 | 40 | @Test 41 | public void buildAccessControl() throws Exception 42 | { 43 | File dir = new File( AccessControlConfig.STORE_DIR ); 44 | FileUtils.deleteRecursively( dir ); 45 | 46 | GraphDatabaseService db = new GraphDatabaseFactory() 47 | .newEmbeddedDatabaseBuilder( AccessControlConfig.STORE_DIR ) 48 | .setConfig( DbUtils.dbConfig() ) 49 | .newGraphDatabase(); 50 | DatasetManager dsm = new DatasetManager( db, SysOutLog.INSTANCE ); 51 | 52 | NodeSpecification adminSpec = dsm.nodeSpecification( "Administrator", indexableProperty( db, "Administrator", "name" ) ); 53 | NodeSpecification groupSpec = dsm.nodeSpecification( "Group", property( "name" ) ); 54 | NodeSpecification companySpec = dsm.nodeSpecification( "Company", indexableProperty( db, "Company", "name" ) ); 55 | NodeSpecification customerSpec = dsm.nodeSpecification( "Employee", indexableProperty( db, "Employee", "name", "Resource")); 56 | NodeSpecification accountSpec = dsm.nodeSpecification( "Account", indexableProperty( db, "Account", "name", "Resource")); 57 | 58 | RelationshipSpecification member_of = dsm.relationshipSpecification( "MEMBER_OF" ); 59 | RelationshipSpecification allowed_inherit = dsm.relationshipSpecification( "ALLOWED_INHERIT" ); 60 | RelationshipSpecification allowed_do_not_inherit = dsm.relationshipSpecification( "ALLOWED_DO_NOT_INHERIT" ); 61 | RelationshipSpecification denied = dsm.relationshipSpecification( "DENIED" ); 62 | RelationshipSpecification child_of = dsm.relationshipSpecification( "CHILD_OF" ); 63 | RelationshipSpecification works_for = dsm.relationshipSpecification( "WORKS_FOR" ); 64 | RelationshipSpecification has_account = dsm.relationshipSpecification( "HAS_ACCOUNT" ); 65 | 66 | Dataset dataset = dsm.newDataset( "Access Control (without using inherit attributes)" ); 67 | 68 | NodeCollection administrators = adminSpec.create( AccessControlConfig.NUMBER_OF_ADMINS ).update( dataset ); 69 | NodeCollection groups = administrators.createRelationshipsTo( 70 | getOrCreate( groupSpec, AccessControlConfig.NUMBER_OF_GROUPS ) 71 | .numberOfTargetNodes( GROUPS_PER_ADMIN ) 72 | .relationship( member_of ) 73 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 74 | .update( dataset ); 75 | 76 | NodeCollection companies1allowedInherit = groups.createRelationshipsTo( 77 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.17 ) ) 78 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 79 | .relationship( allowed_inherit ) 80 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 81 | .update( dataset ); 82 | 83 | NodeCollection companies1allowedDoNotInherit = groups.createRelationshipsTo( 84 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.08 ) ) 85 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 86 | .relationship( allowed_do_not_inherit ) 87 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 88 | .update( dataset ); 89 | 90 | NodeCollection companies1denied = groups.createRelationshipsTo( 91 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.1 ) ) 92 | .numberOfTargetNodes( DENIED_COMPANIES_PER_GROUP ) 93 | .relationship( denied ) 94 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 95 | .update( dataset ); 96 | 97 | NodeCollection companies2allowedInherit = groups.createRelationshipsTo( 98 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.33 ) ) 99 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 100 | .relationship( allowed_inherit ) 101 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 102 | .update( dataset ); 103 | 104 | NodeCollection companies2allowedDoNotInherit = groups.createRelationshipsTo( 105 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.17 ) ) 106 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 107 | .relationship( allowed_do_not_inherit ) 108 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 109 | .update( dataset ); 110 | 111 | NodeCollection companies2denied = groups.createRelationshipsTo( 112 | getOrCreate( companySpec, percentageOf( AccessControlConfig.NUMBER_OF_COMPANIES, 0.15 ) ) 113 | .numberOfTargetNodes( DENIED_COMPANIES_PER_GROUP ) 114 | .relationship( denied ) 115 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 116 | .update( dataset ); 117 | 118 | NodeCollection companies1 = companies1allowedInherit.combine( companies1allowedDoNotInherit ).combine( 119 | companies1denied ); 120 | NodeCollection companies2 = companies2allowedInherit.combine( companies2allowedDoNotInherit ).combine( 121 | companies2denied ); 122 | 123 | companies2.createRelationshipsTo( 124 | getExisting( companies1 ) 125 | .numberOfTargetNodes( 1 ) 126 | .relationship( child_of ) 127 | .exactlyOneRelationship() ) 128 | .updateNoReturn( dataset ); 129 | 130 | 131 | NodeCollection companies = companies1.combine( companies2 ); 132 | NodeCollection employees = companies.createRelationshipsTo( 133 | create( customerSpec ) 134 | .numberOfTargetNodes( EMPLOYEES_PER_COMPANY ) 135 | .relationship( works_for, Direction.INCOMING ) 136 | .exactlyOneRelationship() ) 137 | .update( dataset, 1000 ); 138 | 139 | employees.createRelationshipsTo( 140 | create( accountSpec ) 141 | .numberOfTargetNodes( ACCOUNTS_PER_EMPLOYEE ) 142 | .relationship( has_account, Direction.OUTGOING ) 143 | .exactlyOneRelationship() ) 144 | .updateNoReturn( dataset ); 145 | 146 | dataset.end(); 147 | 148 | new IndexResources( db ).execute(); 149 | 150 | GraphStatistics.create( db, AccessControlConfig.TITLE ) 151 | .describeTo( new AsciiDocFormatter( SysOutLog.INSTANCE ) ); 152 | 153 | db.shutdown(); 154 | } 155 | 156 | private int percentageOf( int i, double percentage ) 157 | { 158 | return (int) (i * percentage); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/AccessControlWithRelationshipProperties.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders; 2 | 3 | import java.io.File; 4 | import java.util.Random; 5 | 6 | import org.junit.Test; 7 | 8 | import org.neo4j.graphdatabases.AccessControlWithRelationshipPropertiesConfig; 9 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 10 | import org.neo4j.graphdatabases.queries.traversals.IndexResources; 11 | import org.neo4j.graphdb.Direction; 12 | import org.neo4j.graphdb.GraphDatabaseService; 13 | import org.neo4j.graphdb.PropertyContainer; 14 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 15 | import org.neo4j.kernel.impl.util.FileUtils; 16 | import org.neo4j.neode.Dataset; 17 | import org.neo4j.neode.DatasetManager; 18 | import org.neo4j.neode.NodeCollection; 19 | import org.neo4j.neode.NodeSpecification; 20 | import org.neo4j.neode.Range; 21 | import org.neo4j.neode.RelationshipSpecification; 22 | import org.neo4j.neode.RelationshipUniqueness; 23 | import org.neo4j.neode.logging.SysOutLog; 24 | import org.neo4j.neode.properties.Property; 25 | import org.neo4j.neode.statistics.AsciiDocFormatter; 26 | import org.neo4j.neode.statistics.GraphStatistics; 27 | 28 | import static org.neo4j.neode.Range.minMax; 29 | import static org.neo4j.neode.TargetNodesStrategy.create; 30 | import static org.neo4j.neode.TargetNodesStrategy.getExisting; 31 | import static org.neo4j.neode.TargetNodesStrategy.getOrCreate; 32 | import static org.neo4j.neode.properties.Property.indexableProperty; 33 | import static org.neo4j.neode.properties.Property.property; 34 | 35 | public class AccessControlWithRelationshipProperties 36 | { 37 | public static final Range GROUPS_PER_ADMIN = minMax( 1, 3 ); 38 | public static final Range ALLOWED_COMPANIES_PER_GROUP = minMax( 10, 50 ); 39 | public static final Range DENIED_COMPANIES_PER_GROUP = minMax( 2, 10 ); 40 | public static final Range EMPLOYEES_PER_COMPANY = minMax( 5, 100 ); 41 | public static final Range ACCOUNTS_PER_EMPLOYEE = minMax( 1, 5 ); 42 | 43 | @Test 44 | public void buildAccessControl() throws Exception 45 | { 46 | File dir = new File( AccessControlWithRelationshipPropertiesConfig.STORE_DIR ); 47 | FileUtils.deleteRecursively( dir ); 48 | 49 | GraphDatabaseService db = new GraphDatabaseFactory() 50 | .newEmbeddedDatabaseBuilder( AccessControlWithRelationshipPropertiesConfig.STORE_DIR ) 51 | .setConfig( DbUtils.dbConfig() ) 52 | .newGraphDatabase(); 53 | DatasetManager dsm = new DatasetManager( db, SysOutLog.INSTANCE ); 54 | 55 | NodeSpecification adminSpec = dsm.nodeSpecification( "Administrator", indexableProperty( db, "Administrator", "name" ) ); 56 | NodeSpecification groupSpec = dsm.nodeSpecification( "Group", property( "name" ) ); 57 | NodeSpecification companySpec = dsm.nodeSpecification( "Company", indexableProperty( db, "Company", "name" ) ); 58 | NodeSpecification customerSpec = dsm.nodeSpecification( "Employee", indexableProperty( db, "Employee", "name", "Resource")); 59 | NodeSpecification accountSpec = dsm.nodeSpecification( "Account", indexableProperty( db, "Account", "name", "Resource")); 60 | 61 | Property inheritProperty = new Property() 62 | { 63 | private final Random random = new Random(); 64 | 65 | @Override 66 | public void setProperty( PropertyContainer propertyContainer, GraphDatabaseService graphDatabaseService, 67 | String label, int iteration ) 68 | { 69 | int i = random.nextInt( 3 ); 70 | boolean value = i < 2; 71 | propertyContainer.setProperty( "inherit", value ); 72 | } 73 | }; 74 | 75 | RelationshipSpecification member_of = dsm.relationshipSpecification( "MEMBER_OF" ); 76 | RelationshipSpecification allowed = dsm.relationshipSpecification( "ALLOWED", inheritProperty ); 77 | RelationshipSpecification denied = dsm.relationshipSpecification( "DENIED" ); 78 | RelationshipSpecification child_of = dsm.relationshipSpecification( "CHILD_OF" ); 79 | RelationshipSpecification works_for = dsm.relationshipSpecification( "WORKS_FOR" ); 80 | RelationshipSpecification has_account = dsm.relationshipSpecification( "HAS_ACCOUNT" ); 81 | 82 | Dataset dataset = dsm.newDataset( AccessControlWithRelationshipPropertiesConfig.TITLE ); 83 | 84 | NodeCollection administrators = adminSpec.create( AccessControlWithRelationshipPropertiesConfig 85 | .NUMBER_OF_ADMINS ).update( dataset ); 86 | NodeCollection groups = administrators.createRelationshipsTo( 87 | getOrCreate( groupSpec, AccessControlWithRelationshipPropertiesConfig.NUMBER_OF_GROUPS ) 88 | .numberOfTargetNodes( GROUPS_PER_ADMIN ) 89 | .relationship( member_of ) 90 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 91 | .update( dataset ); 92 | 93 | NodeCollection companies1allowed = groups.createRelationshipsTo( 94 | getOrCreate( companySpec, percentageOf( AccessControlWithRelationshipPropertiesConfig 95 | .NUMBER_OF_COMPANIES, 0.25 ) ) 96 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 97 | .relationship( allowed ) 98 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 99 | .update( dataset ); 100 | 101 | NodeCollection companies1denied = groups.createRelationshipsTo( 102 | getOrCreate( companySpec, percentageOf( AccessControlWithRelationshipPropertiesConfig 103 | .NUMBER_OF_COMPANIES, 0.1 ) ) 104 | .numberOfTargetNodes( DENIED_COMPANIES_PER_GROUP ) 105 | .relationship( denied ) 106 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 107 | .update( dataset ); 108 | 109 | NodeCollection companies2allowed = groups.createRelationshipsTo( 110 | getOrCreate( companySpec, percentageOf( AccessControlWithRelationshipPropertiesConfig 111 | .NUMBER_OF_COMPANIES, 0.50 ) ) 112 | .numberOfTargetNodes( ALLOWED_COMPANIES_PER_GROUP ) 113 | .relationship( allowed ) 114 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 115 | .update( dataset ); 116 | 117 | NodeCollection companies2denied = groups.createRelationshipsTo( 118 | getOrCreate( companySpec, percentageOf( AccessControlWithRelationshipPropertiesConfig 119 | .NUMBER_OF_COMPANIES, 0.15 ) ) 120 | .numberOfTargetNodes( DENIED_COMPANIES_PER_GROUP ) 121 | .relationship( denied ) 122 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 123 | .update( dataset ); 124 | 125 | NodeCollection companies1 = companies1allowed.combine( companies1denied ); 126 | NodeCollection companies2 = companies2allowed.combine( companies2denied ); 127 | 128 | companies2.createRelationshipsTo( 129 | getExisting( companies1 ) 130 | .numberOfTargetNodes( 1 ) 131 | .relationship( child_of ) 132 | .exactlyOneRelationship() ) 133 | .updateNoReturn( dataset ); 134 | 135 | 136 | NodeCollection companies = companies1.combine( companies2 ); 137 | NodeCollection employees = companies.createRelationshipsTo( 138 | create( customerSpec ) 139 | .numberOfTargetNodes( EMPLOYEES_PER_COMPANY ) 140 | .relationship( works_for, Direction.INCOMING ) 141 | .exactlyOneRelationship() ) 142 | .update( dataset, 1000 ); 143 | 144 | employees.createRelationshipsTo( 145 | create( accountSpec ) 146 | .numberOfTargetNodes( ACCOUNTS_PER_EMPLOYEE ) 147 | .relationship( has_account, Direction.OUTGOING ) 148 | .exactlyOneRelationship() ) 149 | .updateNoReturn( dataset ); 150 | 151 | dataset.end(); 152 | 153 | new IndexResources( db ).execute(); 154 | 155 | GraphStatistics.create( db, AccessControlWithRelationshipPropertiesConfig.TITLE ) 156 | .describeTo( new AsciiDocFormatter( SysOutLog.INSTANCE ) ); 157 | 158 | db.shutdown(); 159 | 160 | } 161 | 162 | private int percentageOf( int i, double percentage ) 163 | { 164 | return (int) (i * percentage); 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/Logistics.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders; 2 | 3 | import java.io.File; 4 | import java.util.Iterator; 5 | import java.util.NoSuchElementException; 6 | import java.util.Random; 7 | 8 | import org.joda.time.Interval; 9 | import org.junit.Test; 10 | 11 | import org.neo4j.graphdatabases.LogisticsConfig; 12 | import org.neo4j.graphdatabases.dataset_builders.helpers.SevenDays; 13 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 14 | import org.neo4j.graphdb.GraphDatabaseService; 15 | import org.neo4j.graphdb.PropertyContainer; 16 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 17 | import org.neo4j.kernel.impl.util.FileUtils; 18 | import org.neo4j.neode.Dataset; 19 | import org.neo4j.neode.DatasetManager; 20 | import org.neo4j.neode.NodeCollection; 21 | import org.neo4j.neode.NodeSpecification; 22 | import org.neo4j.neode.logging.SysOutLog; 23 | import org.neo4j.neode.properties.Property; 24 | import org.neo4j.neode.statistics.AsciiDocFormatter; 25 | import org.neo4j.neode.statistics.GraphStatistics; 26 | 27 | import static org.neo4j.neode.Range.exactly; 28 | import static org.neo4j.neode.Range.minMax; 29 | import static org.neo4j.neode.TargetNodesStrategy.create; 30 | import static org.neo4j.neode.TargetNodesStrategy.getOrCreate; 31 | import static org.neo4j.neode.properties.Property.indexableProperty; 32 | 33 | public class Logistics 34 | { 35 | @Test 36 | public void buildLogistics() throws Exception 37 | { 38 | File dir = new File( LogisticsConfig.STORE_DIR ); 39 | FileUtils.deleteRecursively( dir ); 40 | 41 | GraphDatabaseService db = new GraphDatabaseFactory() 42 | .newEmbeddedDatabaseBuilder( LogisticsConfig.STORE_DIR ) 43 | .setConfig( DbUtils.dbConfig() ) 44 | .newGraphDatabase(); 45 | DatasetManager dsm = new DatasetManager( db, SysOutLog.INSTANCE ); 46 | 47 | NodeSpecification parcelCentreSpec = dsm.nodeSpecification( "ParcelCentre", 48 | indexableProperty( db, "ParcelCentre", "name", "Location" ) ); 49 | NodeSpecification deliveryBaseSpec = dsm.nodeSpecification( "DeliveryBase", 50 | indexableProperty( db, "DeliveryBase","name", "Location" ) ); 51 | NodeSpecification deliveryAreaSpec = dsm.nodeSpecification( "DeliveryArea", 52 | indexableProperty( db, "DeliveryArea", "name", "Location" ) ); 53 | NodeSpecification deliverySegmentSpec = dsm.nodeSpecification( "DeliverySegment", 54 | indexableProperty( db, "DeliverySegment", "name", "Location" ) ); 55 | 56 | Property costProperty = new CostProperty(); 57 | 58 | Dataset dataset = dsm.newDataset( LogisticsConfig.TITLE ); 59 | 60 | NodeCollection parcelCentres = parcelCentreSpec.create( LogisticsConfig.NUMBER_OF_PARCEL_CENTRES ).update( 61 | dataset ); 62 | 63 | NodeCollection deliveryBases = parcelCentres.createRelationshipsTo( 64 | getOrCreate( deliveryBaseSpec, 400 ) 65 | .numberOfTargetNodes( minMax( 66 | LogisticsConfig.MIN_NUMBER_OF_DELIVERY_BASES_PER_PARCEL_CENTRE, 67 | LogisticsConfig.MAX_NUMBER_OF_DELIVERY_BASES_PER_PARCEL_CENTRE ) ) 68 | .relationship( dsm.relationshipSpecification( "CONNECTED_TO", 69 | new IntervalProperty( 2 ), 70 | costProperty ) ) 71 | .relationshipConstraints( exactly( 2 ) ) ) 72 | .update( dataset ); 73 | 74 | NodeCollection deliveryAreas = deliveryBases.createRelationshipsTo( 75 | create( deliveryAreaSpec ) 76 | .numberOfTargetNodes( minMax( 77 | LogisticsConfig.MIN_NUMBER_OF_DELIVERY_AREAS_PER_DELIVERY_BASE, 78 | LogisticsConfig.MAX_NUMBER_OF_DELIVERY_AREAS_PER_DELIVERY_BASE ) ) 79 | .relationship( dsm.relationshipSpecification( "DELIVERY_ROUTE", 80 | new IntervalProperty( 3 ), 81 | costProperty ) ) 82 | .relationshipConstraints( exactly( 3 ) ) ) 83 | .update( dataset ); 84 | deliveryAreas.createRelationshipsTo( 85 | create( deliverySegmentSpec ) 86 | .numberOfTargetNodes( minMax( 87 | LogisticsConfig.MIN_NUMBER_OF_DELIVERY_SEGMENTS_PER_DELIVERY_AREA, 88 | LogisticsConfig.MAX_NUMBER_OF_DELIVERY_SEGMENTS_PER_DELIVERY_AREA ) ) 89 | .relationship( dsm.relationshipSpecification( "DELIVERY_ROUTE", 90 | new IntervalProperty( 3 ), 91 | costProperty ) ) 92 | .relationshipConstraints( exactly( 3 ) ) ) 93 | .updateNoReturn( dataset, 1000 ); 94 | 95 | dataset.end(); 96 | 97 | GraphStatistics.create( db, LogisticsConfig.TITLE ) 98 | .describeTo( new AsciiDocFormatter( SysOutLog.INSTANCE ) ); 99 | 100 | db.shutdown(); 101 | 102 | } 103 | 104 | private static class IntervalProperty extends Property 105 | { 106 | private final int numberOfIntervals; 107 | private final SevenDays sevenDays = new SevenDays( LogisticsConfig.START_DATE ); 108 | 109 | private Iterator intervals; 110 | private int counter; 111 | 112 | private IntervalProperty( int numberOfIntervals ) 113 | { 114 | this.numberOfIntervals = numberOfIntervals; 115 | this.counter = numberOfIntervals; 116 | } 117 | 118 | @Override 119 | public void setProperty( PropertyContainer propertyContainer, GraphDatabaseService graphDatabaseService, 120 | String label, int iteration ) 121 | { 122 | if ( counter++ >= numberOfIntervals ) 123 | { 124 | intervals = sevenDays.calculateIntervals( numberOfIntervals ).iterator(); 125 | counter = 1; 126 | } 127 | 128 | try 129 | { 130 | Interval nextInterval = intervals.next(); 131 | propertyContainer.setProperty( "start_date", nextInterval.getStartMillis() ); 132 | propertyContainer.setProperty( "end_date", nextInterval.getEndMillis() ); 133 | } 134 | catch ( NoSuchElementException e ) 135 | { 136 | throw new IllegalStateException( String.format( "counter: %s, numberOfIntervals: %s, iteration: %s", 137 | counter, numberOfIntervals, iteration ) ); 138 | } 139 | } 140 | } 141 | 142 | private static class CostProperty extends Property 143 | { 144 | private final Random random = new Random(); 145 | 146 | @Override 147 | public void setProperty( PropertyContainer propertyContainer, GraphDatabaseService graphDatabaseService, 148 | String s, int i ) 149 | { 150 | propertyContainer.setProperty( "cost", random.nextInt( 10 ) + 1 ); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/SimpleSocialNetwork.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Test; 6 | 7 | import org.neo4j.graphdatabases.SimpleSocialNetworkConfig; 8 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 9 | import org.neo4j.graphdb.GraphDatabaseService; 10 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 11 | import org.neo4j.kernel.impl.util.FileUtils; 12 | import org.neo4j.neode.Dataset; 13 | import org.neo4j.neode.DatasetManager; 14 | import org.neo4j.neode.NodeCollection; 15 | import org.neo4j.neode.NodeSpecification; 16 | import org.neo4j.neode.RelationshipSpecification; 17 | import org.neo4j.neode.logging.Log; 18 | import org.neo4j.neode.logging.SysOutLog; 19 | import org.neo4j.neode.statistics.AsciiDocFormatter; 20 | import org.neo4j.neode.statistics.GraphStatistics; 21 | 22 | import static org.neo4j.neode.Range.minMax; 23 | import static org.neo4j.neode.RelationshipUniqueness.BOTH_DIRECTIONS; 24 | import static org.neo4j.neode.TargetNodesStrategy.getExisting; 25 | import static org.neo4j.neode.properties.Property.indexableProperty; 26 | 27 | public class SimpleSocialNetwork 28 | { 29 | @Test 30 | public void buildSocialNetwork() throws Exception 31 | { 32 | File dir = new File( SimpleSocialNetworkConfig.STORE_DIR ); 33 | FileUtils.deleteRecursively( dir ); 34 | 35 | GraphDatabaseService db = new GraphDatabaseFactory() 36 | .newEmbeddedDatabaseBuilder( SimpleSocialNetworkConfig.STORE_DIR ) 37 | .setConfig( DbUtils.dbConfig() ) 38 | .newGraphDatabase(); 39 | createSampleDataset( db ); 40 | 41 | GraphStatistics.create( db, SimpleSocialNetworkConfig.TITLE ) 42 | .describeTo( new AsciiDocFormatter( SysOutLog.INSTANCE ) ); 43 | 44 | db.shutdown(); 45 | } 46 | 47 | private void createSampleDataset( GraphDatabaseService db ) 48 | { 49 | DatasetManager dsm = new DatasetManager( db, new Log() 50 | { 51 | @Override 52 | public void write( String value ) 53 | { 54 | System.out.println( value ); 55 | } 56 | } ); 57 | 58 | NodeSpecification userSpec = dsm.nodeSpecification( 59 | "User", indexableProperty( db, "User", "name" ) ); 60 | RelationshipSpecification friend = 61 | dsm.relationshipSpecification( "FRIEND" ); 62 | 63 | Dataset dataset = 64 | dsm.newDataset( "Simple social network example" ); 65 | 66 | NodeCollection users = 67 | userSpec.create( SimpleSocialNetworkConfig.NUMBER_USERS ) 68 | .update( dataset ); 69 | 70 | users.createRelationshipsTo( 71 | getExisting( users ) 72 | .numberOfTargetNodes( minMax( SimpleSocialNetworkConfig.MIN_NUMBER_OF_FRIENDS, 73 | SimpleSocialNetworkConfig.MAX_NUMBER_OF_FRIENDS ) ) 74 | .relationship( friend ) 75 | .relationshipConstraints( BOTH_DIRECTIONS ) ) 76 | .updateNoReturn( dataset, 20000 ); 77 | 78 | dataset.end(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/SocialNetwork.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Test; 6 | 7 | import org.neo4j.graphdatabases.SocialNetworkConfig; 8 | import org.neo4j.graphdatabases.dataset_builders.properties.DurationOnProjectProperty; 9 | import org.neo4j.graphdatabases.dataset_builders.properties.ProjectDurationProperty; 10 | import org.neo4j.graphdatabases.dataset_builders.traversers.FindAllColleagues; 11 | import org.neo4j.graphdatabases.dataset_builders.traversers.IsCompanyProject; 12 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 13 | import org.neo4j.graphdb.Direction; 14 | import org.neo4j.graphdb.GraphDatabaseService; 15 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 16 | import org.neo4j.graphdb.traversal.TraversalDescription; 17 | import org.neo4j.kernel.Traversal; 18 | import org.neo4j.kernel.Uniqueness; 19 | import org.neo4j.kernel.impl.util.FileUtils; 20 | import org.neo4j.neode.Dataset; 21 | import org.neo4j.neode.DatasetManager; 22 | import org.neo4j.neode.NodeCollection; 23 | import org.neo4j.neode.NodeSpecification; 24 | import org.neo4j.neode.RelationshipSpecification; 25 | import org.neo4j.neode.RelationshipUniqueness; 26 | import org.neo4j.neode.logging.SysOutLog; 27 | import org.neo4j.neode.properties.Property; 28 | import org.neo4j.neode.statistics.AsciiDocFormatter; 29 | import org.neo4j.neode.statistics.GraphStatistics; 30 | 31 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 32 | import static org.neo4j.neode.GraphQuery.traversal; 33 | import static org.neo4j.neode.Range.minMax; 34 | import static org.neo4j.neode.TargetNodesStrategy.getExisting; 35 | import static org.neo4j.neode.TargetNodesStrategy.getOrCreate; 36 | import static org.neo4j.neode.TargetNodesStrategy.queryBasedGetOrCreate; 37 | import static org.neo4j.neode.probabilities.ProbabilityDistribution.flatDistribution; 38 | import static org.neo4j.neode.probabilities.ProbabilityDistribution.normalDistribution; 39 | import static org.neo4j.neode.properties.Property.indexableProperty; 40 | import static org.neo4j.neode.properties.Property.property; 41 | 42 | public class SocialNetwork 43 | { 44 | @Test 45 | public void buildSocialNetwork() throws Exception 46 | { 47 | File dir = new File( SocialNetworkConfig.STORE_DIR ); 48 | FileUtils.deleteRecursively( dir ); 49 | 50 | GraphDatabaseService db = new GraphDatabaseFactory() 51 | .newEmbeddedDatabaseBuilder( SocialNetworkConfig.STORE_DIR ) 52 | .setConfig( DbUtils.dbConfig() ) 53 | .newGraphDatabase(); 54 | DatasetManager dsm = new DatasetManager( db, SysOutLog.INSTANCE ); 55 | 56 | TraversalDescription findCompanyProjects = createFindCompanyProjectsTraversalDescription(); 57 | Property projectDuration = new ProjectDurationProperty(); 58 | Property durationOnProject = new DurationOnProjectProperty(); 59 | 60 | NodeSpecification userSpec = dsm.nodeSpecification( "User", indexableProperty(db, "User", "name" ) ); 61 | NodeSpecification topicSpec = dsm.nodeSpecification( "Topic", indexableProperty(db, "Topic", "name" ) ); 62 | NodeSpecification companySpec = dsm.nodeSpecification( "Company", indexableProperty(db, "company", "name" ) ); 63 | NodeSpecification projectSpec = dsm.nodeSpecification( "Project", 64 | property( "name" ), 65 | projectDuration ); 66 | 67 | RelationshipSpecification interested_in = dsm.relationshipSpecification( "INTERESTED_IN" ); 68 | RelationshipSpecification works_for = dsm.relationshipSpecification( "WORKS_FOR" ); 69 | RelationshipSpecification worked_on = dsm.relationshipSpecification( "WORKED_ON", durationOnProject ); 70 | RelationshipSpecification worked_with = dsm.relationshipSpecification( "WORKED_WITH" ); 71 | 72 | Dataset dataset = dsm.newDataset( "Social network example" ); 73 | 74 | NodeCollection users = userSpec.create( SocialNetworkConfig.NUMBER_USERS ).update( dataset ); 75 | 76 | users.createRelationshipsTo( 77 | getOrCreate( topicSpec, SocialNetworkConfig.NUMBER_TOPICS, normalDistribution() ) 78 | .numberOfTargetNodes( minMax( 1, 3 ) ) 79 | .relationship( interested_in ) 80 | .exactlyOneRelationship() ) 81 | .updateNoReturn( dataset ); 82 | 83 | users.createRelationshipsTo( 84 | getOrCreate( companySpec, SocialNetworkConfig.NUMBER_COMPANIES, flatDistribution() ) 85 | .numberOfTargetNodes( 1 ) 86 | .relationship( works_for ) 87 | .exactlyOneRelationship() ) 88 | .updateNoReturn( dataset ); 89 | 90 | NodeCollection allProjects = users.createRelationshipsTo( 91 | queryBasedGetOrCreate( projectSpec, traversal( findCompanyProjects ), 5.0 ) 92 | .numberOfTargetNodes( minMax( 1, 5 ), normalDistribution() ) 93 | .relationship( worked_on ) 94 | .exactlyOneRelationship() ) 95 | .update( dataset ); 96 | 97 | users.approxPercentage( 30 ).createRelationshipsTo( 98 | getExisting( allProjects ) 99 | .numberOfTargetNodes( minMax( 1, 2 ), normalDistribution() ) 100 | .relationship( worked_on ) 101 | .relationshipConstraints( RelationshipUniqueness.BOTH_DIRECTIONS ) ) 102 | .update( dataset ); 103 | 104 | users.createRelationshipsTo( 105 | getExisting( new FindAllColleagues() ) 106 | .numberOfTargetNodes( 1 ) 107 | .relationship( worked_with ) 108 | .exactlyOneRelationship() ) 109 | .updateNoReturn( dataset, 5000 ); 110 | 111 | 112 | dataset.end(); 113 | 114 | GraphStatistics.create( db, SocialNetworkConfig.TITLE ).describeTo( 115 | new AsciiDocFormatter( SysOutLog.INSTANCE ) ); 116 | 117 | db.shutdown(); 118 | } 119 | 120 | private TraversalDescription createFindCompanyProjectsTraversalDescription() 121 | { 122 | return Traversal.description() 123 | .depthFirst() 124 | .uniqueness( Uniqueness.NODE_GLOBAL ) 125 | .relationships( withName( "WORKS_FOR" ), Direction.BOTH ) 126 | .relationships( withName( "WORKED_ON" ), Direction.OUTGOING ) 127 | .evaluator( new IsCompanyProject() ); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/helpers/SevenDays.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.helpers; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Random; 9 | 10 | import org.joda.time.DateTime; 11 | import org.joda.time.Interval; 12 | 13 | public class SevenDays 14 | { 15 | private final DateTime start; 16 | private final Random random; 17 | 18 | @SuppressWarnings( "unchecked" ) 19 | private static final List> days = asList( 20 | asList( 1, 1, 5 ), 21 | asList( 1, 2, 4 ), 22 | asList( 1, 3, 3 ), 23 | asList( 2, 2, 3 ) ); 24 | 25 | public SevenDays( DateTime start ) 26 | { 27 | this.start = start; 28 | this.random = new Random(); 29 | } 30 | 31 | public Iterable calculateIntervals( int numberOfIntervals ) 32 | { 33 | if ( numberOfIntervals < 1 || numberOfIntervals > 3 ) 34 | { 35 | throw new IllegalArgumentException( "numberOfIntervals must be 1 or 3" ); 36 | } 37 | 38 | List intervals = new ArrayList(); 39 | 40 | if ( numberOfIntervals == 1 ) 41 | { 42 | intervals.add( new Interval( start, start.plusDays( 7 ) ) ); 43 | } 44 | else if ( numberOfIntervals == 2 ) 45 | { 46 | int numberOfDays = random.nextInt( 6 ) + 1; 47 | DateTime mid = start.plusDays( numberOfDays ); 48 | intervals.add( new Interval( start, mid ) ); 49 | intervals.add( new Interval( mid, start.plusDays( 7 ) ) ); 50 | } 51 | else 52 | { 53 | int i = random.nextInt( days.size() ); 54 | List plusDays = days.get( i ); 55 | Collections.shuffle( plusDays, random ); 56 | 57 | DateTime mid1 = start.plusDays( plusDays.get( 0 ) ); 58 | DateTime mid2 = mid1.plusDays( plusDays.get( 1 ) ); 59 | 60 | intervals.add( new Interval( start, mid1 ) ); 61 | intervals.add( new Interval( mid1, mid2 ) ); 62 | intervals.add( new Interval( mid2, start.plusDays( 7 ) ) ); 63 | } 64 | 65 | return intervals; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/properties/DurationOnProjectProperty.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.properties; 2 | 3 | import org.neo4j.graphdb.GraphDatabaseService; 4 | import org.neo4j.graphdb.Node; 5 | import org.neo4j.graphdb.PropertyContainer; 6 | import org.neo4j.graphdb.Relationship; 7 | import org.neo4j.neode.properties.Property; 8 | 9 | public class DurationOnProjectProperty extends Property 10 | { 11 | @Override 12 | public void setProperty( PropertyContainer propertyContainer, GraphDatabaseService graphDatabaseService, 13 | String s, int i ) 14 | { 15 | Node endNode = ((Relationship) propertyContainer).getEndNode(); 16 | 17 | Long startDateTime = (Long) endNode.getProperty( "start_date" ); 18 | Long endDateTime = (Long) endNode.getProperty( "end_date" ); 19 | ProjectDuration projectDuration = new ProjectDuration( startDateTime, endDateTime ); 20 | ProjectDuration durationOnProject = projectDuration.getSubDuration(); 21 | 22 | propertyContainer.setProperty( "duration", durationOnProject.toString() ); 23 | propertyContainer.setProperty( "start_date", durationOnProject.getStartDateMs() ); 24 | propertyContainer.setProperty( "end_date", durationOnProject.getEndDateMs() ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/properties/ProjectDuration.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.properties; 2 | 3 | import static org.neo4j.neode.Range.minMax; 4 | import static org.neo4j.neode.probabilities.ProbabilityDistribution.normalDistribution; 5 | 6 | import org.joda.time.DateTime; 7 | import org.joda.time.DateTimeZone; 8 | import org.joda.time.Duration; 9 | import org.joda.time.format.DateTimeFormat; 10 | import org.joda.time.format.DateTimeFormatter; 11 | import org.neo4j.neode.probabilities.ProbabilityDistribution; 12 | 13 | public class ProjectDuration 14 | { 15 | private static final ProbabilityDistribution normalDistribution = normalDistribution(); 16 | private static final DateTimeFormatter fmt = DateTimeFormat.forPattern( "dd-MM-yyyy" ); 17 | 18 | private final Long startMs; 19 | private final Long endMs; 20 | 21 | public ProjectDuration( Long startMs, Long endMs ) 22 | { 23 | this.endMs = endMs; 24 | this.startMs = startMs; 25 | } 26 | 27 | public Long getStartDateMs() 28 | { 29 | return startMs; 30 | } 31 | 32 | public Long getEndDateMs() 33 | { 34 | return endMs; 35 | } 36 | 37 | public ProjectDuration getSubDuration() 38 | { 39 | DateTime startDateTime = new DateTime( startMs, DateTimeZone.UTC ); 40 | DateTime endDateTime = new DateTime( endMs, DateTimeZone.UTC ); 41 | 42 | int durationInDays = (int) new Duration( startDateTime, endDateTime ).getStandardDays(); 43 | int offsetDaysFromStart = normalDistribution.generateSingle( minMax( 0, (int) (durationInDays * 0.75) ) ); 44 | int remainingDays = durationInDays - offsetDaysFromStart; 45 | int subDurationInDays = (int) ((remainingDays * 0.75) + 46 | (normalDistribution.generateSingle( minMax( 0, (int) (remainingDays * (0.25)) ) ))); 47 | 48 | DateTime subDurationStartDateTime = startDateTime.plusDays( offsetDaysFromStart ); 49 | DateTime subDurationEndDateTime = subDurationStartDateTime.plusDays( subDurationInDays ); 50 | 51 | return new ProjectDuration( subDurationStartDateTime.getMillis(), subDurationEndDateTime.getMillis() ); 52 | } 53 | 54 | public String toString() 55 | { 56 | return "Start: " + new DateTime( startMs, DateTimeZone.UTC ).toString( fmt ) 57 | + ", End : " + new DateTime( endMs, DateTimeZone.UTC ).toString( fmt ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/properties/ProjectDurationGenerator.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.properties; 2 | 3 | import java.util.Random; 4 | 5 | import org.joda.time.DateTime; 6 | import org.joda.time.DateTimeZone; 7 | 8 | public class ProjectDurationGenerator 9 | { 10 | private final static DateTime durationLowerLimit = new DateTime(2000, 1, 1, 0, 0, DateTimeZone.UTC); 11 | private final Random rand = new Random(); 12 | 13 | public ProjectDuration getNextProjectDuration() 14 | { 15 | DateTime startDateTime = durationLowerLimit.plusMonths( rand.nextInt( 9 *12 ) ); 16 | DateTime endDateTime = startDateTime.plusMonths( 3 + (rand.nextInt(33)) ) ; 17 | return new ProjectDuration( startDateTime.getMillis(), endDateTime.getMillis() ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/properties/ProjectDurationProperty.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.properties; 2 | 3 | import org.neo4j.graphdb.GraphDatabaseService; 4 | import org.neo4j.graphdb.PropertyContainer; 5 | import org.neo4j.neode.properties.Property; 6 | 7 | public class ProjectDurationProperty extends Property 8 | { 9 | private final ProjectDurationGenerator generator = new ProjectDurationGenerator(); 10 | 11 | @Override 12 | public void setProperty( PropertyContainer propertyContainer, GraphDatabaseService graphDatabaseService, 13 | String s, int i ) 14 | { 15 | ProjectDuration projectDuration = generator.getNextProjectDuration(); 16 | propertyContainer.setProperty( "duration", projectDuration.toString() ); 17 | propertyContainer.setProperty( "start_date", projectDuration.getStartDateMs() ); 18 | propertyContainer.setProperty( "end_date", projectDuration.getEndDateMs() ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/traversers/FindAllColleagues.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.traversers; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import org.neo4j.graphalgo.GraphAlgoFactory; 6 | import org.neo4j.graphalgo.PathFinder; 7 | import org.neo4j.graphdb.Direction; 8 | import org.neo4j.graphdb.Node; 9 | import org.neo4j.graphdb.Path; 10 | import org.neo4j.graphdb.PathExpander; 11 | import org.neo4j.graphdb.Relationship; 12 | import org.neo4j.graphdb.RelationshipExpander; 13 | import org.neo4j.graphdb.RelationshipType; 14 | import org.neo4j.graphdb.traversal.BranchState; 15 | import org.neo4j.graphdb.traversal.Evaluation; 16 | import org.neo4j.graphdb.traversal.Evaluator; 17 | import org.neo4j.graphdb.traversal.TraversalDescription; 18 | import org.neo4j.kernel.Traversal; 19 | import org.neo4j.kernel.Uniqueness; 20 | import org.neo4j.neode.GraphQuery; 21 | 22 | public class FindAllColleagues extends GraphQuery 23 | { 24 | private static final RelationshipType WORKED_ON = withName( "WORKED_ON" ); 25 | private static PathFinder workedWithPathFinder = GraphAlgoFactory.shortestPath( Traversal.expanderForTypes( withName( "WORKED_WITH" )), 1 ); 26 | private static final TraversalDescription traversal = Traversal.description() 27 | .depthFirst() 28 | .uniqueness( Uniqueness.NODE_GLOBAL ) 29 | .expand( new WorkOnPathExpander() ) 30 | .evaluator( new Evaluator() 31 | { 32 | @Override 33 | public Evaluation evaluate( Path path ) 34 | { 35 | if ( path.length() == 2 ) 36 | { 37 | if ( workedWithPathFinder.findSinglePath( path.startNode(), path.endNode() ) == null) 38 | { 39 | return Evaluation.INCLUDE_AND_PRUNE; 40 | } 41 | else 42 | { 43 | return Evaluation.EXCLUDE_AND_PRUNE; 44 | } 45 | } 46 | return Evaluation.EXCLUDE_AND_CONTINUE; 47 | } 48 | } ); 49 | 50 | @Override 51 | public Iterable execute( Node node ) 52 | { 53 | return traversal.traverse( node ).nodes(); 54 | } 55 | 56 | private static class WorkOnPathExpander implements PathExpander 57 | { 58 | @Override 59 | public Iterable expand( Path path, BranchState branchState ) 60 | { 61 | if (path.length() == 0) 62 | { 63 | return path.endNode().getRelationships( WORKED_ON, Direction.OUTGOING ); 64 | } 65 | else 66 | { 67 | return path.endNode().getRelationships( WORKED_ON, Direction.INCOMING ); 68 | } 69 | } 70 | 71 | @Override 72 | public PathExpander reverse() 73 | { 74 | return null; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/traversers/FindColleagues.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.traversers; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.joda.time.Duration; 9 | import org.joda.time.Interval; 10 | import org.joda.time.Period; 11 | import org.neo4j.graphdb.Direction; 12 | import org.neo4j.graphdb.DynamicRelationshipType; 13 | import org.neo4j.graphdb.Node; 14 | import org.neo4j.graphdb.Path; 15 | import org.neo4j.graphdb.PathExpander; 16 | import org.neo4j.graphdb.Relationship; 17 | import org.neo4j.graphdb.traversal.BranchState; 18 | import org.neo4j.graphdb.traversal.Evaluation; 19 | import org.neo4j.graphdb.traversal.Evaluator; 20 | import org.neo4j.graphdb.traversal.TraversalDescription; 21 | import org.neo4j.kernel.Traversal; 22 | import org.neo4j.kernel.Uniqueness; 23 | import org.neo4j.neode.GraphQuery; 24 | 25 | public class FindColleagues extends GraphQuery 26 | { 27 | private static final TraversalDescription traversal = Traversal.description() 28 | .depthFirst() 29 | .uniqueness( Uniqueness.NODE_GLOBAL ) 30 | .relationships( withName( "WORKED_ON" ), Direction.BOTH ) 31 | .expand( new OverlappingWorkedOnRels() ) 32 | .evaluator( new IsColleague() ); 33 | 34 | @Override 35 | public Iterable execute( Node node ) 36 | { 37 | return traversal.traverse( node ).nodes(); 38 | } 39 | 40 | private static class IsColleague implements Evaluator 41 | { 42 | @Override 43 | public Evaluation evaluate( Path path ) 44 | { 45 | if ( path.length() == 2 ) 46 | { 47 | return Evaluation.INCLUDE_AND_PRUNE; 48 | } 49 | 50 | return Evaluation.EXCLUDE_AND_CONTINUE; 51 | } 52 | } 53 | 54 | private static class OverlappingWorkedOnRels implements PathExpander 55 | { 56 | private static final DynamicRelationshipType WORKED_ON = withName( "WORKED_ON" ); 57 | private static final Duration ONE_YEAR = new Period( 0, 0, 0, 365, 0, 0, 0, 0 ).toStandardDuration(); 58 | 59 | 60 | @Override 61 | public Iterable expand( Path path, BranchState branchState ) 62 | { 63 | 64 | if ( path.length() == 1 ) 65 | { 66 | List rels = new ArrayList(); 67 | 68 | 69 | Long start_date = (Long) path.lastRelationship().getProperty( "start_date" ); 70 | Long end_date = (Long) path.lastRelationship().getProperty( "end_date" ); 71 | Interval interval = new Interval( start_date, end_date ); 72 | 73 | 74 | for ( Relationship rel : path.endNode().getRelationships( WORKED_ON, Direction.INCOMING ) ) 75 | { 76 | if ( !rel.equals( path.lastRelationship() ) ) 77 | { 78 | Long rel_start_date = (Long) rel.getProperty( "start_date" ); 79 | Long rel_end_date = (Long) rel.getProperty( "end_date" ); 80 | Interval rel_interval = new Interval( rel_start_date, rel_end_date ); 81 | 82 | if ( intervalsOverlapByDuration( interval, rel_interval ) ) 83 | { 84 | rels.add( rel ); 85 | } 86 | } 87 | } 88 | 89 | return rels; 90 | } 91 | 92 | return path.endNode().getRelationships( WORKED_ON, Direction.OUTGOING ); 93 | 94 | } 95 | 96 | @Override 97 | public PathExpander reverse() 98 | { 99 | return null; 100 | } 101 | 102 | private boolean intervalsOverlapByDuration( Interval myInterval, Interval otherInterval ) 103 | { 104 | return otherInterval.overlaps( myInterval ) && 105 | otherInterval.overlap( myInterval ).toDuration().compareTo( ONE_YEAR ) > 0; 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /data-generation/src/test/java/org/neo4j/graphdatabases/dataset_builders/traversers/IsCompanyProject.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.dataset_builders.traversers; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import org.neo4j.graphdb.Path; 6 | import org.neo4j.graphdb.RelationshipType; 7 | import org.neo4j.graphdb.traversal.Evaluation; 8 | import org.neo4j.graphdb.traversal.Evaluator; 9 | 10 | public class IsCompanyProject implements Evaluator 11 | { 12 | private static final RelationshipType WORKED_ON = withName( "WORKED_ON" ); 13 | 14 | @Override 15 | public Evaluation evaluate( Path path ) 16 | { 17 | if ( path.length() == 0 ) 18 | { 19 | return Evaluation.EXCLUDE_AND_CONTINUE; 20 | } 21 | if ( path.lastRelationship().isType( WORKED_ON ) ) 22 | { 23 | return Evaluation.INCLUDE_AND_PRUNE; 24 | } 25 | return Evaluation.EXCLUDE_AND_CONTINUE; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /performance-testing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.neo4j.graphdatabases 8 | performance-testing 9 | 2.0-SNAPSHOT 10 | jar 11 | 12 | 13 | 1.7 14 | 1.7 15 | UTF-8 16 | 2.0.1 17 | 18 | 19 | 20 | 21 | org.neo4j 22 | neo4j-enterprise 23 | ${neo4j.version} 24 | 25 | 26 | org.neo4j.graphdatabases 27 | queries 28 | 2.0-SNAPSHOT 29 | 30 | 31 | org.neo4j.graphdatabases 32 | configuration 33 | 2.0-SNAPSHOT 34 | 35 | 36 | neode 37 | neode 38 | 2.0 39 | 40 | 41 | junit 42 | junit 43 | 4.11 44 | test 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/DefaultExecutionEngineWrapper.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import java.util.Map; 4 | 5 | import org.neo4j.cypher.javacompat.ExecutionEngine; 6 | import org.neo4j.cypher.javacompat.ExecutionResult; 7 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 8 | import org.neo4j.graphdb.GraphDatabaseService; 9 | 10 | public class DefaultExecutionEngineWrapper implements ExecutionEngineWrapper 11 | { 12 | private final ExecutionEngine executionEngine; 13 | 14 | public DefaultExecutionEngineWrapper( GraphDatabaseService db ) 15 | { 16 | this.executionEngine = new ExecutionEngine( db ); 17 | } 18 | 19 | @Override 20 | public ExecutionResult execute( String query, Map params ) 21 | { 22 | return executionEngine.execute( query, params ); 23 | } 24 | 25 | @Override 26 | public ExecutionResult execute( String query, Map params, int index ) 27 | { 28 | return execute( query, params ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/DoNothingWithTestResults.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 4 | 5 | public class DoNothingWithTestResults implements TestResultsHandler 6 | { 7 | public static TestResultsHandler doNothing() 8 | { 9 | return new DoNothingWithTestResults(); 10 | } 11 | 12 | @Override 13 | public void handle( String queryType, Object results, SingleTestRunResultHandler singleTestRunResultHandler ) 14 | { 15 | //Do nothing 16 | } 17 | 18 | @Override 19 | public void writeTo( TestOutputWriter writer ) 20 | { 21 | // Do nothing 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/MultipleTestRuns.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import static org.neo4j.neode.Range.minMax; 4 | import static org.neo4j.neode.probabilities.ProbabilityDistribution.flatDistribution; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 11 | 12 | public class MultipleTestRuns 13 | { 14 | private final int numberOfRuns; 15 | private final TestOutputWriter writer; 16 | 17 | public MultipleTestRuns( int numberOfRuns, TestOutputWriter writer ) 18 | { 19 | this.numberOfRuns = numberOfRuns; 20 | this.writer = writer; 21 | } 22 | 23 | public void execute( String title, 24 | ParamsGenerator paramsGenerator, 25 | SingleTestRunResultHandlerFactory singleTestRunResultHandlerFactory, 26 | TestResultsHandler testResultsHandler, 27 | SingleTest... tests ) 28 | { 29 | writer.writeln( title ); 30 | testResultsHandler.writeTo( writer ); 31 | 32 | Map totalTimes = new HashMap(); 33 | for ( SingleTest singleTest : tests ) 34 | { 35 | totalTimes.put( singleTest.queryType(), 0L ); 36 | } 37 | 38 | for ( long i = 0; i < numberOfRuns; i++ ) 39 | { 40 | SingleTestRunResultHandler singleTestRunResultHandler = singleTestRunResultHandlerFactory 41 | .createSingleTestRunResultHandler(); 42 | 43 | writer.writeln( String.format( "\nTest run %s of %s", i + 1, numberOfRuns ) ); 44 | Map params = paramsGenerator.generateParams(); 45 | 46 | if ( !params.isEmpty() ) 47 | { 48 | writer.write( "Params: " ); 49 | } 50 | for ( String key : params.keySet() ) 51 | { 52 | writer.write( String.format( "[%s: %s] ", key, params.get( key ) ) ); 53 | } 54 | 55 | writer.writeln( "" ); 56 | 57 | //Randomize the order in which tests are executed each run 58 | List testIndexes = flatDistribution() 59 | .generateList( tests.length, minMax( 0, tests.length - 1 ) ); 60 | 61 | for ( Integer testIndex : testIndexes ) 62 | { 63 | SingleTest singleTest = tests[testIndex]; 64 | writer.writeln( String.format( "\n %s", singleTest.queryType() ) ); 65 | long startTime = System.nanoTime(); 66 | Object lastResult = singleTest.execute( params ); 67 | testResultsHandler.handle( singleTest.queryType(), lastResult, singleTestRunResultHandler ); 68 | long endTime = System.nanoTime(); 69 | long duration = endTime - startTime; 70 | writer.writeln( String.format( " Duration (ms): %s", duration / 1000000 ) ); 71 | Long currentTotalTime = totalTimes.get( singleTest.queryType() ); 72 | totalTimes.put( singleTest.queryType(), currentTotalTime + duration ); 73 | } 74 | 75 | singleTestRunResultHandler.summarize( writer ); 76 | 77 | } 78 | 79 | writer.writeln( "\n======================================" ); 80 | writer.writeln( title ); 81 | writer.writeln( "Average times (ms)" ); 82 | 83 | for ( SingleTest singleTest : tests ) 84 | { 85 | long avgTime = totalTimes.get( singleTest.queryType() ) / numberOfRuns / 1000000; 86 | writer.writeln( String.format( " %s: %s", singleTest.queryType(), avgTime ) ); 87 | } 88 | writer.writeln( "======================================" ); 89 | } 90 | 91 | public void execute( String title, 92 | ParamsGenerator paramsGenerator, 93 | TestResultsHandler testResultsHandler, 94 | SingleTest... tests ) 95 | { 96 | execute( title, paramsGenerator, new NullSingleTestRunResultHandlerFactory(), testResultsHandler, tests ); 97 | } 98 | 99 | private static class NullSingleTestRunResultHandler implements SingleTestRunResultHandler 100 | { 101 | @Override 102 | public void handle( String queryType, String formattedResult ) 103 | { 104 | // Do nothing 105 | } 106 | 107 | @Override 108 | public void summarize( TestOutputWriter writer ) 109 | { 110 | // Do nothing 111 | } 112 | } 113 | 114 | private static class NullSingleTestRunResultHandlerFactory implements SingleTestRunResultHandlerFactory 115 | { 116 | private final SingleTestRunResultHandler instance = new NullSingleTestRunResultHandler(); 117 | 118 | @Override 119 | public SingleTestRunResultHandler createSingleTestRunResultHandler() 120 | { 121 | return instance; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/ParamsGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | import java.util.Map; 8 | 9 | public interface ParamsGenerator 10 | { 11 | Map generateParams(); 12 | } 13 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/PrintTestResults.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import java.util.Iterator; 4 | 5 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 6 | 7 | public class PrintTestResults implements TestResultsHandler 8 | { 9 | private static ResultFormatter DEFAULT_FORMATTER = new ResultFormatter() 10 | { 11 | @Override 12 | public String format( Object result ) 13 | { 14 | return result.toString(); 15 | } 16 | }; 17 | 18 | public static TestResultsHandler printResults( int numberOfResults, ResultFormatter resultFormatter, 19 | TestOutputWriter writer ) 20 | { 21 | return new PrintTestResults( numberOfResults, resultFormatter, writer ); 22 | } 23 | 24 | public static TestResultsHandler printResults( int numberOfResults, TestOutputWriter writer ) 25 | { 26 | return new PrintTestResults( numberOfResults, DEFAULT_FORMATTER, writer ); 27 | } 28 | 29 | private final int numberOfResults; 30 | private final ResultFormatter resultFormatter; 31 | private final TestOutputWriter writer; 32 | 33 | private PrintTestResults( int numberOfResults, ResultFormatter resultFormatter, TestOutputWriter writer ) 34 | { 35 | this.numberOfResults = numberOfResults; 36 | this.resultFormatter = resultFormatter; 37 | this.writer = writer; 38 | } 39 | 40 | @Override 41 | public void handle( String queryType, Object results, SingleTestRunResultHandler singleTestRunResultHandler ) 42 | { 43 | if ( Iterable.class.isAssignableFrom( results.getClass() ) ) 44 | { 45 | Iterator iterator = ((Iterable) results).iterator(); 46 | int count = 0; 47 | 48 | if ( !iterator.hasNext() ) 49 | { 50 | writer.write( " {EMPTY}" ); 51 | } 52 | else 53 | { 54 | while ( iterator.hasNext() && count < numberOfResults ) 55 | { 56 | String formattedResult = resultFormatter.format( iterator.next() ); 57 | singleTestRunResultHandler.handle( queryType, formattedResult ); 58 | writer.writeln( String.format( " [%s]", formattedResult ) ); 59 | count++; 60 | } 61 | writer.writeln(""); 62 | writer.writeln(String.format( " Total: %s", count ) ); 63 | writer.writeln(""); 64 | } 65 | } 66 | else 67 | { 68 | String formattedResult = resultFormatter.format( results ); 69 | singleTestRunResultHandler.handle( queryType, formattedResult ); 70 | writer.writeln( formattedResult ); 71 | } 72 | } 73 | 74 | @Override 75 | public void writeTo( TestOutputWriter writer ) 76 | { 77 | writer.writeln( String.format( "NUMBER_OF_RESULTS: %s", numberOfResults ) ); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/QueryType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | public enum QueryType 8 | { 9 | CoreAPI, 10 | Cypher, 11 | AltCypher, 12 | Gremlin, 13 | Traversal, 14 | GraphAlgo 15 | } 16 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/ResultFormatter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | public interface ResultFormatter 8 | { 9 | String format(Object result); 10 | } 11 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/ResultsContainSameElementsUnordered.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.TreeMap; 11 | 12 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 13 | 14 | public class ResultsContainSameElementsUnordered implements SingleTestRunResultHandler 15 | { 16 | public static SingleTestRunResultHandlerFactory newFactory(final String... cleanResultRegExes) 17 | { 18 | return new SingleTestRunResultHandlerFactory() 19 | { 20 | @Override 21 | public SingleTestRunResultHandler createSingleTestRunResultHandler() 22 | { 23 | return new ResultsContainSameElementsUnordered(cleanResultRegExes); 24 | } 25 | }; 26 | } 27 | 28 | private final List cleanResultRegExes; 29 | private final Map> results; 30 | private boolean newlineWritten = false; 31 | 32 | public ResultsContainSameElementsUnordered( String... cleanResultRegExes ) 33 | { 34 | this.cleanResultRegExes = asList( cleanResultRegExes ); 35 | results = new TreeMap>(); 36 | } 37 | 38 | @Override 39 | public void handle( String queryType, String formattedResult ) 40 | { 41 | if ( !results.containsKey( queryType ) ) 42 | { 43 | results.put( queryType, new ArrayList() ); 44 | } 45 | 46 | for ( String cleanResultRegEx : cleanResultRegExes ) 47 | { 48 | formattedResult = formattedResult.replaceAll( cleanResultRegEx, "" ); 49 | } 50 | 51 | results.get( queryType ).add( formattedResult ); 52 | } 53 | 54 | @Override 55 | public void summarize( TestOutputWriter writer ) 56 | { 57 | List queryTypes = new ArrayList( results.keySet() ); 58 | for ( int i = 0; i < queryTypes.size() - 1; i++ ) 59 | { 60 | String queryType1 = queryTypes.get( i ); 61 | for ( int j = i + 1; j < queryTypes.size(); j++ ) 62 | { 63 | String queryType2 = queryTypes.get( j ); 64 | compareCollections( queryType1, results.get( queryType1 ), queryType2, results.get( queryType2 ), 65 | writer ); 66 | } 67 | } 68 | } 69 | 70 | private void compareCollections( String queryType1, Collection results1, String queryType2, 71 | Collection results2, TestOutputWriter writer ) 72 | { 73 | compare( queryType1, results1, queryType2, results2, writer ); 74 | compare( queryType2, results2, queryType1, results1, writer ); 75 | } 76 | 77 | private void compare( String queryType1, Collection results1, String queryType2, 78 | Collection results2, TestOutputWriter writer ) 79 | { 80 | Collection copyOfResults1 = new HashSet( results1 ); 81 | copyOfResults1.removeAll( results2 ); 82 | if ( !copyOfResults1.isEmpty() ) 83 | { 84 | if (!newlineWritten) 85 | { 86 | writer.writeln( "" ); 87 | newlineWritten = true; 88 | } 89 | 90 | writer.writeln( String.format( " %s v. %s: %s contains additional elements: %s", queryType1, queryType2, 91 | queryType1, copyOfResults1 ) ); 92 | 93 | } 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/SingleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | import java.util.Map; 8 | 9 | public interface SingleTest 10 | { 11 | String queryType(); 12 | Object execute( Map params ); 13 | } 14 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/SingleTestRunResultHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 8 | 9 | public interface SingleTestRunResultHandler 10 | { 11 | void handle( String queryType, String formattedResult ); 12 | void summarize( TestOutputWriter writer ); 13 | } 14 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/SingleTestRunResultHandlerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | public interface SingleTestRunResultHandlerFactory 8 | { 9 | SingleTestRunResultHandler createSingleTestRunResultHandler(); 10 | } 11 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/SysOutWriter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 4 | 5 | public class SysOutWriter implements TestOutputWriter 6 | { 7 | public static final TestOutputWriter INSTANCE = new SysOutWriter(); 8 | 9 | private SysOutWriter(){} 10 | 11 | @Override 12 | public void begin() 13 | { 14 | } 15 | 16 | @Override 17 | public void write( String value ) 18 | { 19 | System.out.print(value); 20 | } 21 | 22 | @Override 23 | public void writeln( String value ) 24 | { 25 | System.out.println( value ); 26 | } 27 | 28 | @Override 29 | public void flush() 30 | { 31 | } 32 | 33 | @Override 34 | public void end() 35 | { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/TakeXTestResults.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | 4 | import java.util.Iterator; 5 | 6 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 7 | 8 | public class TakeXTestResults implements TestResultsHandler 9 | { 10 | public static TestResultsHandler take( int quantity ) 11 | { 12 | return new TakeXTestResults( quantity ); 13 | } 14 | 15 | private final int quantity; 16 | 17 | public TakeXTestResults( int quantity ) 18 | { 19 | this.quantity = quantity; 20 | } 21 | 22 | @Override 23 | public void handle( String queryType, Object results, SingleTestRunResultHandler singleTestRunResultHandler ) 24 | { 25 | int i = 0; 26 | if ( Iterable.class.isAssignableFrom( results.getClass() ) ) 27 | { 28 | Iterator iterator = ((Iterable) results).iterator(); 29 | while ( iterator.hasNext() && ++i < quantity ) 30 | { 31 | iterator.next(); 32 | } 33 | } 34 | } 35 | 36 | @Override 37 | public void writeTo( TestOutputWriter writer ) 38 | { 39 | writer.writeln( String.format( "NUMBER_OF_RESULTS: %s", quantity ) ); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /performance-testing/src/main/java/org/neo4j/graphdatabases/performance_tests/testing/TestResultsHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.performance_tests.testing; 6 | 7 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 8 | 9 | public interface TestResultsHandler 10 | { 11 | void handle( String queryType, Object results, SingleTestRunResultHandler singleTestRunResultHandler ); 12 | void writeTo(TestOutputWriter writer); 13 | } 14 | -------------------------------------------------------------------------------- /performance-testing/src/test/java/org/neo4j/graphdatabases/performance_tests/AccessControl.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.Random; 7 | 8 | import org.junit.AfterClass; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import org.neo4j.cypher.javacompat.ExecutionResult; 13 | import org.neo4j.graphdatabases.AccessControlConfig; 14 | import org.neo4j.graphdatabases.AccessControlWithRelationshipPropertiesConfig; 15 | import org.neo4j.graphdatabases.performance_tests.testing.DefaultExecutionEngineWrapper; 16 | import org.neo4j.graphdatabases.performance_tests.testing.MultipleTestRuns; 17 | import org.neo4j.graphdatabases.performance_tests.testing.ParamsGenerator; 18 | import org.neo4j.graphdatabases.performance_tests.testing.SingleTest; 19 | import org.neo4j.graphdatabases.performance_tests.testing.SysOutWriter; 20 | import org.neo4j.graphdatabases.queries.AccessControlQueries; 21 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 22 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 23 | import org.neo4j.graphdb.GraphDatabaseService; 24 | 25 | import static org.neo4j.graphdatabases.performance_tests.testing.PrintTestResults.printResults; 26 | 27 | public class AccessControl 28 | { 29 | private static final int NUMBER_OF_TEST_RUNS = 20; 30 | private static final int NUMBER_OF_RESULTS = 15; 31 | 32 | private static int numberOfAccounts; 33 | private static int numberOfEmployees; 34 | 35 | private static GraphDatabaseService db; 36 | private static AccessControlQueries queries; 37 | private static MultipleTestRuns multipleTestRuns; 38 | private static Random random; 39 | private static TestOutputWriter writer = SysOutWriter.INSTANCE; 40 | 41 | @BeforeClass 42 | public static void init() 43 | { 44 | try 45 | { 46 | db = DbUtils.existingDB( AccessControlConfig.STORE_DIR ); 47 | queries = new AccessControlQueries( new DefaultExecutionEngineWrapper( db ) ); 48 | multipleTestRuns = new MultipleTestRuns( NUMBER_OF_TEST_RUNS, writer ); 49 | 50 | random = new Random(); 51 | 52 | numberOfAccounts = DbUtils.numberOfItemsWithLabel(db, "Account"); 53 | numberOfEmployees = DbUtils.numberOfItemsWithLabel(db, "Employee"); 54 | } 55 | catch ( Exception ex ) 56 | { 57 | System.out.println( ex.getMessage() ); 58 | } 59 | } 60 | 61 | @AfterClass 62 | public static void teardown() 63 | { 64 | db.shutdown(); 65 | } 66 | 67 | @Test 68 | public void findAccessibleResources() throws Exception 69 | { 70 | // when 71 | multipleTestRuns.execute( "Find accessible resources for admin", 72 | createParams(), 73 | printResults( NUMBER_OF_RESULTS, writer ), 74 | new SingleTest() 75 | { 76 | @Override 77 | public String queryType() 78 | { 79 | return "Cypher"; 80 | } 81 | 82 | @Override 83 | public ExecutionResult execute( Map params ) 84 | { 85 | return queries.findAccessibleResources( params.get( "admin" ) ); 86 | } 87 | } ); 88 | } 89 | 90 | @Test 91 | public void findAccessibleCompanies() throws Exception 92 | { 93 | // when 94 | multipleTestRuns.execute( "Find accessible companies for admin", 95 | createParams(), 96 | printResults( NUMBER_OF_RESULTS, writer ), 97 | new SingleTest() 98 | { 99 | @Override 100 | public String queryType() 101 | { 102 | return "Cypher"; 103 | } 104 | 105 | @Override 106 | public ExecutionResult execute( Map params ) 107 | { 108 | return queries.findAccessibleCompanies( params.get( "admin" ) ); 109 | } 110 | } ); 111 | } 112 | 113 | @Test 114 | public void findAccessibleAccountsForCompany() throws Exception 115 | { 116 | // when 117 | multipleTestRuns.execute( "Find accessible accounts for company for admin", 118 | createParams(), 119 | printResults( NUMBER_OF_RESULTS, writer ), 120 | new SingleTest() 121 | { 122 | @Override 123 | public String queryType() 124 | { 125 | return "Cypher"; 126 | } 127 | 128 | @Override 129 | public ExecutionResult execute( Map params ) 130 | { 131 | return queries.findAccessibleAccountsForCompany( 132 | params.get( "admin" ), 133 | params.get( "company" ) ); 134 | } 135 | } ); 136 | } 137 | 138 | @Test 139 | public void findAdminForCompany() throws Exception 140 | { 141 | // when 142 | multipleTestRuns.execute( "Find admins for company", 143 | createParams(), 144 | printResults( NUMBER_OF_RESULTS, writer ), 145 | new SingleTest() 146 | { 147 | @Override 148 | public String queryType() 149 | { 150 | return "Cypher"; 151 | } 152 | 153 | @Override 154 | public ExecutionResult execute( Map params ) 155 | { 156 | return queries.findAdminForCompany( params.get( "company" ) ); 157 | } 158 | } ); 159 | } 160 | 161 | @Test 162 | public void findAdminForResource() throws Exception 163 | { 164 | // when 165 | multipleTestRuns.execute( "Find admins for resource", 166 | createParams(), 167 | printResults( NUMBER_OF_RESULTS, writer ), 168 | new SingleTest() 169 | { 170 | @Override 171 | public String queryType() 172 | { 173 | return "Cypher"; 174 | } 175 | 176 | @Override 177 | public ExecutionResult execute( Map params ) 178 | { 179 | return queries.findAdminForResource( params.get( "resource" ) ); 180 | } 181 | } 182 | ); 183 | } 184 | 185 | @Test 186 | public void hasAccessToResource() throws Exception 187 | { 188 | // when 189 | multipleTestRuns.execute( "Does admin have access to resource?", 190 | createParams(), 191 | printResults( NUMBER_OF_RESULTS, writer ), 192 | new SingleTest() 193 | { 194 | @Override 195 | public String queryType() 196 | { 197 | return "Cypher (indexed resources)"; 198 | } 199 | 200 | @Override 201 | public ExecutionResult execute( Map params ) 202 | { 203 | return queries.hasAccessToIndexedResource( params.get( "admin" ), params.get( "resource" ) ); 204 | } 205 | } 206 | ); 207 | } 208 | 209 | @Test 210 | public void hasAccessToResourceBakeoff() throws Exception 211 | { 212 | // when 213 | multipleTestRuns.execute( "Does admin have access to resource?", 214 | createParams(), 215 | printResults( NUMBER_OF_RESULTS, writer ), 216 | new SingleTest() 217 | { 218 | @Override 219 | public String queryType() 220 | { 221 | return "Cypher"; 222 | } 223 | 224 | @Override 225 | public ExecutionResult execute( Map params ) 226 | { 227 | return queries.hasAccessToResource( params.get( "admin" ), params.get( "resource" ) ); 228 | } 229 | }, new SingleTest() 230 | { 231 | @Override 232 | public String queryType() 233 | { 234 | return "Cypher (indexed resources)"; 235 | } 236 | 237 | @Override 238 | public ExecutionResult execute( Map params ) 239 | { 240 | return queries.hasAccessToIndexedResource( params.get( "admin" ), params.get( "resource" ) ); 241 | } 242 | } 243 | ); 244 | } 245 | 246 | private ParamsGenerator createParams() 247 | { 248 | return new ParamsGenerator() 249 | { 250 | @Override 251 | public Map generateParams() 252 | { 253 | HashMap params = new HashMap(); 254 | 255 | String adminName = String.format( "Administrator-%s", 256 | random.nextInt( AccessControlWithRelationshipPropertiesConfig.NUMBER_OF_ADMINS ) + 1 ); 257 | 258 | String resourceName; 259 | if ( random.nextInt( 2 ) < 1 ) 260 | { 261 | resourceName = String.format( "Account-%s", random.nextInt( numberOfAccounts ) + 1 ); 262 | } 263 | else 264 | { 265 | resourceName = String.format( "Customer-%s", random.nextInt( numberOfEmployees ) + 1 ); 266 | } 267 | 268 | ExecutionResult result = queries.findAccessibleCompanies( adminName ); 269 | Iterator> iterator = result.iterator(); 270 | String companyName = (String) iterator.next().get( "company" ); 271 | 272 | params.put( "admin", adminName ); 273 | params.put( "company", companyName ); 274 | params.put( "resource", resourceName ); 275 | 276 | return params; 277 | } 278 | }; 279 | } 280 | 281 | 282 | } 283 | 284 | -------------------------------------------------------------------------------- /performance-testing/src/test/java/org/neo4j/graphdatabases/performance_tests/AccessControlWithRelationshipProperties.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.Random; 7 | 8 | import org.junit.AfterClass; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import org.neo4j.graphdatabases.AccessControlWithRelationshipPropertiesConfig; 13 | import org.neo4j.graphdatabases.performance_tests.testing.DefaultExecutionEngineWrapper; 14 | import org.neo4j.graphdatabases.performance_tests.testing.MultipleTestRuns; 15 | import org.neo4j.graphdatabases.performance_tests.testing.ParamsGenerator; 16 | import org.neo4j.graphdatabases.performance_tests.testing.SingleTest; 17 | import org.neo4j.graphdatabases.performance_tests.testing.SysOutWriter; 18 | import org.neo4j.graphdatabases.queries.AccessControlWithRelationshipPropertiesQueries; 19 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 20 | import org.neo4j.graphdatabases.queries.helpers.QueryUnionExecutionResult; 21 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 22 | import org.neo4j.graphdb.GraphDatabaseService; 23 | import org.neo4j.graphdb.Node; 24 | 25 | import static org.neo4j.graphdatabases.performance_tests.testing.PrintTestResults.printResults; 26 | 27 | public class AccessControlWithRelationshipProperties 28 | { 29 | private static final int NUMBER_OF_TEST_RUNS = 20; 30 | private static final int NUMBER_OF_RESULTS = 15; 31 | 32 | private static int numberOfAccounts; 33 | private static int numberOfCustomers; 34 | 35 | private static GraphDatabaseService db; 36 | private static AccessControlWithRelationshipPropertiesQueries queries; 37 | private static MultipleTestRuns multipleTestRuns; 38 | private static Random random; 39 | private static TestOutputWriter writer = SysOutWriter.INSTANCE; 40 | 41 | @BeforeClass 42 | public static void init() 43 | { 44 | db = DbUtils.existingDB( AccessControlWithRelationshipPropertiesConfig.STORE_DIR ); 45 | 46 | queries = new AccessControlWithRelationshipPropertiesQueries( new DefaultExecutionEngineWrapper( db ) ); 47 | multipleTestRuns = new MultipleTestRuns( NUMBER_OF_TEST_RUNS, writer ); 48 | 49 | random = new Random(); 50 | 51 | numberOfAccounts = DbUtils.numberOfItemsWithLabel(db, "Account"); 52 | numberOfCustomers = DbUtils.numberOfItemsWithLabel(db, "Employee"); 53 | 54 | } 55 | 56 | @AfterClass 57 | public static void teardown() 58 | { 59 | db.shutdown(); 60 | } 61 | 62 | @Test 63 | public void findAccessibleResources() throws Exception 64 | { 65 | // when 66 | multipleTestRuns.execute( "Find accessible resources for admin", 67 | createParams(), 68 | printResults( NUMBER_OF_RESULTS, writer ), 69 | new SingleTest() 70 | { 71 | @Override 72 | public String queryType() 73 | { 74 | return "Cypher"; 75 | } 76 | 77 | @Override 78 | public QueryUnionExecutionResult execute( Map params ) 79 | { 80 | return queries.findAccessibleResources( params.get( "admin" ) ); 81 | } 82 | } ); 83 | } 84 | 85 | @Test 86 | public void findAccessibleCompanies() throws Exception 87 | { 88 | // when 89 | multipleTestRuns.execute( "Find accessible companies for admin", 90 | createParams(), 91 | printResults( NUMBER_OF_RESULTS, writer ), 92 | new SingleTest() 93 | { 94 | @Override 95 | public String queryType() 96 | { 97 | return "Cypher"; 98 | } 99 | 100 | @Override 101 | public QueryUnionExecutionResult execute( Map params ) 102 | { 103 | return queries.findAccessibleCompanies( params.get( "admin" ) ); 104 | } 105 | } ); 106 | } 107 | 108 | @Test 109 | public void findAccessibleAccountsForCompany() throws Exception 110 | { 111 | // when 112 | multipleTestRuns.execute( "Find accessible accounts for company for admin", 113 | createParams(), 114 | printResults( NUMBER_OF_RESULTS, writer ), 115 | new SingleTest() 116 | { 117 | @Override 118 | public String queryType() 119 | { 120 | return "Cypher"; 121 | } 122 | 123 | @Override 124 | public QueryUnionExecutionResult execute( Map params ) 125 | { 126 | return queries.findAccessibleAccountsForCompany( 127 | params.get( "admin" ), 128 | params.get( "company" ) ); 129 | } 130 | } ); 131 | } 132 | 133 | @Test 134 | public void findAdminForCompany() throws Exception 135 | { 136 | // when 137 | multipleTestRuns.execute( "Find admins for company", 138 | createParams(), 139 | printResults( NUMBER_OF_RESULTS, writer ), 140 | new SingleTest() 141 | { 142 | @Override 143 | public String queryType() 144 | { 145 | return "Cypher"; 146 | } 147 | 148 | @Override 149 | public QueryUnionExecutionResult execute( Map params ) 150 | { 151 | return queries.findAdminForCompany( params.get( "company" ) ); 152 | } 153 | } ); 154 | } 155 | 156 | @Test 157 | public void findAdminForResource() throws Exception 158 | { 159 | // when 160 | multipleTestRuns.execute( "Find admins for resource", 161 | createParams(), 162 | printResults( NUMBER_OF_RESULTS, writer ), 163 | new SingleTest() 164 | { 165 | @Override 166 | public String queryType() 167 | { 168 | return "Cypher"; 169 | } 170 | 171 | @Override 172 | public QueryUnionExecutionResult execute( Map params ) 173 | { 174 | return queries.findAdminForResource( params.get( "resource" ) ); 175 | } 176 | } 177 | ); 178 | } 179 | 180 | @Test 181 | public void hasAccessToResource() throws Exception 182 | { 183 | // when 184 | multipleTestRuns.execute( "Does admin have access to resource?", 185 | createParams(), 186 | printResults( NUMBER_OF_RESULTS, writer ), 187 | new SingleTest() 188 | { 189 | @Override 190 | public String queryType() 191 | { 192 | return "Cypher (indexed resources)"; 193 | } 194 | 195 | @Override 196 | public QueryUnionExecutionResult execute( Map params ) 197 | { 198 | return queries.hasAccessToIndexedResource( params.get( "admin" ), 199 | params.get( "resource" ) ); 200 | } 201 | } 202 | ); 203 | } 204 | 205 | @Test 206 | public void hasAccessToResourceBakeoff() throws Exception 207 | { 208 | // when 209 | multipleTestRuns.execute( "Does admin have access to resource?", 210 | createParams(), 211 | printResults( NUMBER_OF_RESULTS, writer ), 212 | new SingleTest() 213 | { 214 | @Override 215 | public String queryType() 216 | { 217 | return "Cypher"; 218 | } 219 | 220 | @Override 221 | public QueryUnionExecutionResult execute( Map params ) 222 | { 223 | return queries.hasAccessToResource( params.get( "admin" ), params.get( "resource" ) ); 224 | } 225 | }, new SingleTest() 226 | { 227 | @Override 228 | public String queryType() 229 | { 230 | return "Cypher (indexed resources)"; 231 | } 232 | 233 | @Override 234 | public QueryUnionExecutionResult execute( Map params ) 235 | { 236 | return queries.hasAccessToIndexedResource( params.get( "admin" ), 237 | params.get( "resource" ) ); 238 | } 239 | } 240 | ); 241 | } 242 | 243 | private ParamsGenerator createParams() 244 | { 245 | return new ParamsGenerator() 246 | { 247 | @Override 248 | public Map generateParams() 249 | { 250 | HashMap params = new HashMap(); 251 | 252 | String adminName = String.format( "Administrator-%s", 253 | random.nextInt( AccessControlWithRelationshipPropertiesConfig.NUMBER_OF_ADMINS ) + 1 ); 254 | 255 | String resourceName; 256 | if ( random.nextInt( 2 ) < 1 ) 257 | { 258 | resourceName = String.format( "Account-%s", random.nextInt( numberOfAccounts ) + 1 ); 259 | } 260 | else 261 | { 262 | resourceName = String.format( "Customer-%s", random.nextInt( numberOfCustomers ) + 1 ); 263 | } 264 | 265 | QueryUnionExecutionResult result = queries.findAccessibleCompanies( adminName ); 266 | Iterator> iterator = result.iterator(); 267 | String companyName = ((Node) iterator.next().get( "company" )).getProperty( "name" ).toString(); 268 | 269 | params.put( "admin", adminName ); 270 | params.put( "company", companyName ); 271 | params.put( "resource", resourceName ); 272 | 273 | return params; 274 | } 275 | }; 276 | } 277 | 278 | } 279 | -------------------------------------------------------------------------------- /performance-testing/src/test/java/org/neo4j/graphdatabases/performance_tests/Logistics.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Random; 7 | 8 | import org.joda.time.DateTime; 9 | import org.joda.time.Interval; 10 | import org.junit.After; 11 | import org.junit.AfterClass; 12 | import org.junit.BeforeClass; 13 | import org.junit.Test; 14 | 15 | import org.neo4j.cypher.javacompat.ExecutionEngine; 16 | import org.neo4j.cypher.javacompat.ExecutionResult; 17 | import org.neo4j.graphdatabases.LogisticsConfig; 18 | import org.neo4j.graphdatabases.performance_tests.testing.DefaultExecutionEngineWrapper; 19 | import org.neo4j.graphdatabases.performance_tests.testing.MultipleTestRuns; 20 | import org.neo4j.graphdatabases.performance_tests.testing.ParamsGenerator; 21 | import org.neo4j.graphdatabases.performance_tests.testing.SingleTest; 22 | import org.neo4j.graphdatabases.performance_tests.testing.SysOutWriter; 23 | import org.neo4j.graphdatabases.queries.LogisticsQueries; 24 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 25 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 26 | import org.neo4j.graphdb.DynamicLabel; 27 | import org.neo4j.graphdb.GraphDatabaseService; 28 | import org.neo4j.graphdb.Transaction; 29 | import org.neo4j.helpers.collection.IteratorUtil; 30 | import org.neo4j.tooling.GlobalGraphOperations; 31 | 32 | import static java.util.Arrays.asList; 33 | 34 | import static org.neo4j.graphdatabases.performance_tests.testing.PrintTestResults.printResults; 35 | 36 | public class Logistics 37 | { 38 | public static final int NUMBER_OF_TEST_RUNS = 20; 39 | private static final int NUMBER_OF_RESULTS = 15; 40 | 41 | private static GraphDatabaseService db; 42 | private static LogisticsQueries queries; 43 | private static MultipleTestRuns multipleTestRuns; 44 | private static Random random; 45 | private static TestOutputWriter writer = SysOutWriter.INSTANCE; 46 | 47 | @BeforeClass 48 | public static void init() 49 | { 50 | db = DbUtils.existingDB( LogisticsConfig.STORE_DIR ); 51 | 52 | queries = new LogisticsQueries( db, new DefaultExecutionEngineWrapper( db ) ); 53 | multipleTestRuns = new MultipleTestRuns( NUMBER_OF_TEST_RUNS, writer ); 54 | 55 | random = new Random(); 56 | 57 | } 58 | 59 | @AfterClass 60 | public static void teardown() 61 | { 62 | if ( db != null ) 63 | { 64 | db.shutdown(); 65 | } 66 | } 67 | 68 | 69 | @Test 70 | public void queryTest() throws Exception 71 | { 72 | List customIds = asList( 6053, 210, 6, 56, 8, 87, 2, 95, 9, 256, 7476, 545580 ); 73 | List cypherIds = asList( 6053, 210, 6, 192, 9, 256, 7476, 545580 ); 74 | Interval interval = Interval.parse( "2012-10-17T00:00:00.000+01:00/2012-10-18T00:00:00.000+01:00" ); 75 | 76 | getPath( customIds, interval ); 77 | getPath( cypherIds, interval ); 78 | 79 | } 80 | 81 | private void getPath( List ids, Interval interval ) 82 | { 83 | StringBuilder sbWhere = new StringBuilder(); 84 | StringBuilder sbMatch = new StringBuilder(); 85 | 86 | for ( int i = 0; i < ids.size(); i++ ) 87 | { 88 | sbWhere.append("id(n"); 89 | sbWhere.append(i); 90 | sbWhere.append(")="); 91 | sbWhere.append(ids.get(i)); 92 | if ( i < (ids.size() - 1) ) 93 | { 94 | sbWhere.append(" AND "); 95 | } 96 | sbWhere.append(" "); 97 | 98 | sbMatch.append( "n" ); 99 | sbMatch.append( i ); 100 | if ( i < (ids.size() - 1) ) 101 | { 102 | sbMatch.append( "--" ); 103 | } 104 | } 105 | 106 | String q = String.format( 107 | "MATCH p = %s %n" + 108 | "WHERE %s AND ALL(r in relationships(p) where r.start_date <= %s and r.end_date >= %s) %n" + 109 | "RETURN REDUCE(weight=0, r in relationships(p) | weight+r.cost) AS score, p", 110 | sbMatch.toString(), 111 | sbWhere.toString(), 112 | interval.getStartMillis(), 113 | interval.getEndMillis()); 114 | writer.writeln(q); 115 | 116 | 117 | ExecutionResult result = new ExecutionEngine( db ).execute( q ); 118 | writer.writeln(result.toString()); 119 | } 120 | 121 | @After 122 | public void flush() 123 | { 124 | writer.flush(); 125 | } 126 | 127 | @Test 128 | public void shortestRoute() throws Exception 129 | { 130 | TestRunParams testRunParams = new TestRunParams( db, writer ); 131 | 132 | // when 133 | multipleTestRuns.execute( "Shortest route through the parcel system", 134 | testRunParams.createParams(), 135 | printResults( NUMBER_OF_RESULTS, writer ), 136 | 137 | new SingleTest() 138 | { 139 | @Override 140 | public String queryType() 141 | { 142 | return "Cypher"; 143 | } 144 | 145 | @Override 146 | public Object execute( Map params ) 147 | { 148 | return queries.findShortestPathWithCypherReduce( 149 | params.get( "start" ), 150 | params.get( "end" ), 151 | Interval.parse( params.get( "interval" ) ) ); 152 | 153 | } 154 | }, 155 | new SingleTest() 156 | { 157 | @Override 158 | public String queryType() 159 | { 160 | return "ParcelRouteCalculator"; 161 | } 162 | 163 | @Override 164 | public Object execute( Map params ) 165 | { 166 | return queries.findShortestPathWithParcelRouteCalculator( 167 | params.get( "start" ), 168 | params.get( "end" ), 169 | Interval.parse( params.get( "interval" ) ) ); 170 | 171 | } 172 | } 173 | ); 174 | } 175 | 176 | @Test 177 | public void testSingleCypherQuery() throws Exception 178 | { 179 | Map params = new HashMap(); 180 | params.put( "start", "delivery-segment-181622" ); 181 | params.put( "end", "delivery-segment-611694" ); 182 | params.put( "interval", "2012-10-17T00:00:00.000-07:00/2012-10-18T00:00:00.000-07:00" ); 183 | 184 | 185 | Interval interval = Interval.parse( params.get( "interval" ) ); 186 | System.out.println( "Start: " + interval.getStartMillis() ); 187 | System.out.println( "End: " + interval.getEndMillis() ); 188 | ExecutionResult result = queries.findShortestPathWithCypherReduce( 189 | params.get( "start" ), 190 | params.get( "end" ), 191 | interval ); 192 | 193 | writer.writeln( result.toString() ); 194 | } 195 | 196 | private class TestRunParams 197 | { 198 | private int deliveryAreaCount; 199 | private int deliverySegmentCount; 200 | 201 | public TestRunParams( GraphDatabaseService db, TestOutputWriter writer ) 202 | { 203 | GlobalGraphOperations ops = GlobalGraphOperations.at(db); 204 | try ( Transaction tx = db.beginTx()) 205 | { 206 | deliveryAreaCount = IteratorUtil.count(ops.getAllNodesWithLabel(DynamicLabel.label("DeliveryArea"))); 207 | deliverySegmentCount = IteratorUtil.count(ops.getAllNodesWithLabel(DynamicLabel.label("DeliverySegment"))); 208 | 209 | writer.writeln( "deliveryAreaCount " + deliveryAreaCount ); 210 | writer.writeln( "deliverySegmentCount " + deliverySegmentCount ); 211 | tx.success(); 212 | } 213 | } 214 | 215 | public ParamsGenerator createParams() 216 | { 217 | return new ParamsGenerator() 218 | { 219 | @Override 220 | public final Map generateParams() 221 | { 222 | Map params = new HashMap(); 223 | if ( random.nextInt( 2 ) < 1 ) 224 | { 225 | params.put( "start", 226 | String.format( "DeliverySegment-%s", random.nextInt( deliverySegmentCount ) + 1 ) ); 227 | } 228 | else 229 | { 230 | params.put( "start", 231 | String.format( "DeliveryArea-%s", random.nextInt( deliveryAreaCount ) + 1 ) ); 232 | } 233 | params.put( "end", 234 | String.format( "DeliverySegment-%s", random.nextInt( deliverySegmentCount ) + 1 ) ); 235 | DateTime startDtm = LogisticsConfig.START_DATE.plusDays( random.nextInt( 6 ) ); 236 | params.put( "interval", new Interval( startDtm, startDtm.plusDays( 1 ) ).toString() ); 237 | return params; 238 | } 239 | }; 240 | } 241 | 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /performance-testing/src/test/java/org/neo4j/graphdatabases/performance_tests/SimpleSocialNetwork.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Random; 6 | 7 | import org.junit.AfterClass; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | 11 | import org.neo4j.cypher.javacompat.ExecutionResult; 12 | import org.neo4j.graphdatabases.SimpleSocialNetworkConfig; 13 | import org.neo4j.graphdatabases.performance_tests.testing.MultipleTestRuns; 14 | import org.neo4j.graphdatabases.performance_tests.testing.ParamsGenerator; 15 | import org.neo4j.graphdatabases.performance_tests.testing.SingleTest; 16 | import org.neo4j.graphdatabases.performance_tests.testing.SysOutWriter; 17 | import org.neo4j.graphdatabases.queries.SimpleSocialNetworkQueries; 18 | import org.neo4j.graphdatabases.queries.helpers.DbUtils; 19 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 20 | import org.neo4j.graphdatabases.queries.traversals.FriendOfAFriendDepth4; 21 | import org.neo4j.graphdb.GraphDatabaseService; 22 | import org.neo4j.graphdb.Node; 23 | import org.neo4j.graphdb.Transaction; 24 | 25 | import static org.neo4j.graphdatabases.performance_tests.testing.PrintTestResults.printResults; 26 | 27 | public class SimpleSocialNetwork 28 | { 29 | private static GraphDatabaseService db; 30 | private static SimpleSocialNetworkQueries queries; 31 | private static MultipleTestRuns multipleTestRuns; 32 | private static Random random; 33 | private static TestOutputWriter writer = SysOutWriter.INSTANCE; 34 | 35 | public static final int NUMBER_OF_TEST_RUNS = 20; 36 | 37 | @BeforeClass 38 | public static void init() 39 | { 40 | db = DbUtils.existingDB( SimpleSocialNetworkConfig.STORE_DIR ); 41 | 42 | queries = new SimpleSocialNetworkQueries( db ); 43 | multipleTestRuns = new MultipleTestRuns( NUMBER_OF_TEST_RUNS, writer ); 44 | 45 | random = new Random(); 46 | } 47 | 48 | @AfterClass 49 | public static void teardown() 50 | { 51 | db.shutdown(); 52 | } 53 | 54 | @Test 55 | public void foafToDepthFour() throws Exception 56 | { 57 | try ( Transaction tx = db.beginTx() ) 58 | { 59 | // when 60 | multipleTestRuns.execute( "Foaf to depth 4", createParams(), printResults( 1, writer ), new SingleTest() 61 | { 62 | @Override 63 | public String queryType() 64 | { 65 | return "Cypher"; 66 | } 67 | 68 | @Override 69 | public ExecutionResult execute( Map params ) 70 | { 71 | return queries.pathBetweenTwoFriends( params.get( "first-user" ), params.get( "second-user" ) ); 72 | } 73 | } ); 74 | tx.success(); 75 | } 76 | } 77 | 78 | @Test 79 | public void friendOfAFriendToDepth4() throws Exception 80 | { 81 | try ( Transaction tx = db.beginTx() ) 82 | { 83 | // when 84 | multipleTestRuns.execute( "Friend of a friend to depth 4", createParams(), printResults( 100, writer ), 85 | new SingleTest() 86 | { 87 | @Override 88 | public String queryType() 89 | { 90 | return "Cypher"; 91 | } 92 | 93 | @Override 94 | public ExecutionResult execute( Map params ) 95 | { 96 | return queries.friendOfAFriendToDepth4( params.get( "first-user" ) ); 97 | } 98 | } ); 99 | tx.success(); 100 | } 101 | } 102 | 103 | @Test 104 | public void onlyFriendsAtDepth4UsingTraversalFramework() throws Exception 105 | { 106 | try ( Transaction tx = db.beginTx() ) 107 | { 108 | final FriendOfAFriendDepth4 traversal = new FriendOfAFriendDepth4( db ); 109 | 110 | // when 111 | multipleTestRuns.execute( "Only friends at depth 4 using Traversal Framework", createParams(), 112 | printResults( 300000, writer ), 113 | new SingleTest() 114 | { 115 | @Override 116 | public String queryType() 117 | { 118 | return "Traversal Framework (custom class)"; 119 | } 120 | 121 | @Override 122 | public Iterable execute( Map params ) 123 | { 124 | return traversal.getFriends( params.get( "first-user" ) ); 125 | } 126 | } ); 127 | tx.success(); 128 | } 129 | } 130 | 131 | private ParamsGenerator createParams() 132 | { 133 | return new ParamsGenerator() 134 | { 135 | @Override 136 | public Map generateParams() 137 | { 138 | Map params = new HashMap(); 139 | params.put( "first-user", String.format( "User-%s", random.nextInt( SimpleSocialNetworkConfig 140 | .NUMBER_USERS 141 | ) + 1 ) ); 142 | params.put( "second-user", String.format( "User-%s", random.nextInt( SimpleSocialNetworkConfig 143 | .NUMBER_USERS 144 | ) + 1 ) ); 145 | return params; 146 | } 147 | }; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /performance-testing/src/test/java/org/neo4j/graphdatabases/performance_tests/testing/ResultsContainSameElementsUnorderedTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.performance_tests.testing; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 7 | 8 | public class ResultsContainSameElementsUnorderedTest 9 | { 10 | @Test 11 | public void shouldReportDiscrepanciesBetweenTwoQueries() throws Exception 12 | { 13 | // given 14 | ResultsContainSameElementsUnordered handler = new ResultsContainSameElementsUnordered( ); 15 | 16 | // when 17 | handler.handle( "queryType1", "a" ); 18 | handler.handle( "queryType2", "C" ); 19 | handler.handle( "queryType1", "b" ); 20 | handler.handle( "queryType2", "b" ); 21 | handler.handle( "queryType1", "c" ); 22 | handler.handle( "queryType2", "a" ); 23 | 24 | MyTestOutputWriter writer = new MyTestOutputWriter(); 25 | handler.summarize( writer ); 26 | 27 | // then 28 | String expected = "\n" + 29 | " queryType1 v. queryType2: queryType1 contains additional elements: [c]\n" + 30 | " queryType2 v. queryType1: queryType2 contains additional elements: [C]\n"; 31 | 32 | assertEquals( expected, writer.toString()); 33 | 34 | } 35 | 36 | @Test 37 | public void shouldReportDiscrepanciesBetweenThreeQueries() throws Exception 38 | { 39 | // given 40 | ResultsContainSameElementsUnordered handler = new ResultsContainSameElementsUnordered( ); 41 | 42 | // when 43 | handler.handle( "queryType1", "a" ); 44 | handler.handle( "queryType2", "b" ); 45 | handler.handle( "queryType3", "c" ); 46 | 47 | MyTestOutputWriter writer = new MyTestOutputWriter(); 48 | handler.summarize( writer ); 49 | 50 | // then 51 | String expected = "\n" + 52 | " queryType1 v. queryType2: queryType1 contains additional elements: [a]\n" + 53 | " queryType2 v. queryType1: queryType2 contains additional elements: [b]\n" + 54 | " queryType1 v. queryType3: queryType1 contains additional elements: [a]\n" + 55 | " queryType3 v. queryType1: queryType3 contains additional elements: [c]\n" + 56 | " queryType2 v. queryType3: queryType2 contains additional elements: [b]\n" + 57 | " queryType3 v. queryType2: queryType3 contains additional elements: [c]\n"; 58 | 59 | assertEquals( expected, writer.toString()); 60 | } 61 | 62 | private static class MyTestOutputWriter implements TestOutputWriter 63 | { 64 | private final StringBuilder builder = new StringBuilder( ); 65 | 66 | @Override 67 | public void begin() 68 | { 69 | } 70 | 71 | @Override 72 | public void write( String value ) 73 | { 74 | builder.append( value ); 75 | } 76 | 77 | @Override 78 | public void writeln( String value ) 79 | { 80 | builder.append( value ); 81 | builder.append( "\n" ); 82 | } 83 | 84 | @Override 85 | public void flush() 86 | { 87 | } 88 | 89 | @Override 90 | public void end() 91 | { 92 | } 93 | 94 | @Override 95 | public String toString() 96 | { 97 | return builder.toString(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | graph-databases-use-cases 8 | graph-databases-use-cases 9 | 2.0-SNAPSHOT 10 | pom 11 | 12 | 13 | 1.7 14 | 1.7 15 | UTF-8 16 | 17 | 18 | 19 | queries 20 | neode 21 | configuration 22 | data-generation 23 | performance-testing 24 | 25 | 26 | -------------------------------------------------------------------------------- /queries/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.neo4j.graphdatabases 8 | queries 9 | 2.0-SNAPSHOT 10 | jar 11 | 12 | 13 | 1.7 14 | 1.7 15 | UTF-8 16 | 2.0.1 17 | 18 | 19 | 20 | 21 | org.neo4j 22 | neo4j 23 | ${neo4j.version} 24 | 25 | 26 | org.neo4j 27 | neo4j-kernel 28 | ${neo4j.version} 29 | test-jar 30 | test 31 | 32 | 33 | org.neo4j 34 | neo4j-graphviz 35 | ${neo4j.version} 36 | 37 | 38 | org.neo4j.app 39 | neo4j-server 40 | ${neo4j.version} 41 | 42 | 43 | 44 | org.neo4j.app 45 | neo4j-server 46 | ${neo4j.version} 47 | test-jar 48 | 49 | 50 | 51 | junit 52 | junit 53 | 4.11 54 | test 55 | 56 | 57 | com.sun.jersey 58 | jersey-server 59 | 1.17 60 | 61 | 62 | com.sun.jersey 63 | jersey-servlet 64 | 1.17 65 | 66 | 67 | com.sun.jersey 68 | jersey-client 69 | 1.17 70 | 71 | 72 | com.sun.jersey 73 | jersey-core 74 | 1.17 75 | 76 | 77 | org.eclipse.jetty 78 | jetty-server 79 | 9.0.5.v20130815 80 | 81 | 82 | joda-time 83 | joda-time 84 | 2.1 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/AccessControlQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.cypher.javacompat.ExecutionResult; 7 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 8 | 9 | public class AccessControlQueries 10 | { 11 | private final ExecutionEngineWrapper executionEngine; 12 | 13 | public AccessControlQueries( ExecutionEngineWrapper executionEngineWrapper ) 14 | { 15 | this.executionEngine = executionEngineWrapper; 16 | } 17 | 18 | public ExecutionResult findAccessibleResources( String adminName ) 19 | { 20 | String query = "MATCH (admin:Administrator {name:{adminName}})\n" + 21 | "MATCH paths=(admin)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()\n" + 22 | " <-[:CHILD_OF*0..3]-(company)<-[:WORKS_FOR]-(employee)\n" + 23 | " -[:HAS_ACCOUNT]->(account)\n" + 24 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 25 | "RETURN employee.name AS employee, account.name AS account\n" + 26 | "UNION\n" + 27 | "MATCH (admin:Administrator {name:{adminName}})\n" + 28 | "MATCH paths=(admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->()\n" + 29 | " <-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)\n" + 30 | "RETURN employee.name AS employee, account.name AS account"; 31 | 32 | Map params = new HashMap<>(); 33 | params.put( "adminName", adminName ); 34 | 35 | return executionEngine.execute( query, params ); 36 | } 37 | 38 | public ExecutionResult findAccessibleCompanies( String adminName ) 39 | { 40 | String query = "MATCH (admin:Administrator {name:{adminName}})\n" + 41 | "MATCH (admin)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()<-[:CHILD_OF*0..3]-(company)\n" + 42 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 43 | "RETURN company.name AS company\n" + 44 | "UNION\n" + 45 | "MATCH (admin:Administrator {name:{adminName}})\n" + 46 | "MATCH (admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->(company)\n" + 47 | "RETURN company.name AS company"; 48 | 49 | Map params = new HashMap<>(); 50 | params.put( "adminName", adminName ); 51 | 52 | return executionEngine.execute( query, params ); 53 | } 54 | 55 | public ExecutionResult findAccessibleAccountsForCompany( String adminName, String companyName ) 56 | { 57 | String query = 58 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 59 | " (company:Company {name:{companyName}})\n" + 60 | "MATCH (admin)-[:MEMBER_OF]->(group)-[:ALLOWED_INHERIT]->(company)\n" + 61 | " <-[:CHILD_OF*0..3]-(subcompany)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)\n" + 62 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(subcompany))\n" + 63 | "RETURN account.name AS account\n" + 64 | "UNION\n" + 65 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 66 | " (company:Company {name:{companyName}})\n" + 67 | "MATCH (admin)-[:MEMBER_OF]->(group)-[:ALLOWED_DO_NOT_INHERIT]->(company)\n" + 68 | " <-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)\n" + 69 | "RETURN account.name AS account"; 70 | 71 | Map params = new HashMap<>(); 72 | params.put( "adminName", adminName ); 73 | params.put( "companyName", companyName ); 74 | 75 | return executionEngine.execute( query, params ); 76 | } 77 | 78 | public ExecutionResult findAdminForResource( String resourceName ) 79 | { 80 | String query = "MATCH (resource:Resource {name:{resourceName}})\n" + 81 | "MATCH p=(resource)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(company)\n" + 82 | " -[:CHILD_OF*0..3]->()<-[:ALLOWED_INHERIT]-()<-[:MEMBER_OF]-(admin)\n" + 83 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 84 | "RETURN admin.name AS admin\n" + 85 | "UNION\n" + 86 | "MATCH (resource:Resource {name:{resourceName}})\n" + 87 | "MATCH p=(resource)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(company)\n" + 88 | " <-[:ALLOWED_DO_NOT_INHERIT]-()<-[:MEMBER_OF]-(admin)\n" + 89 | "RETURN admin.name AS admin"; 90 | 91 | Map params = new HashMap<>(); 92 | params.put( "resourceName", resourceName ); 93 | 94 | return executionEngine.execute( query, params ); 95 | } 96 | 97 | public ExecutionResult findAdminForCompany( String companyName ) 98 | { 99 | String query = "MATCH (company:Company {name:{companyName}})\n" + 100 | "MATCH (company)-[:CHILD_OF*0..3]->()<-[:ALLOWED_INHERIT]-()<-[:MEMBER_OF]-(admin)\n" + 101 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 102 | "RETURN admin.name AS admin\n" + 103 | "UNION\n" + 104 | "MATCH (company:Company {name:{companyName}})\n" + 105 | "MATCH (company)<-[:ALLOWED_DO_NOT_INHERIT]-()<-[:MEMBER_OF]-(admin)\n" + 106 | "RETURN admin.name AS admin"; 107 | 108 | Map params = new HashMap<>(); 109 | params.put( "companyName", companyName ); 110 | 111 | return executionEngine.execute( query, params ); 112 | } 113 | 114 | public ExecutionResult hasAccessToResource( String adminName, String resourceName ) 115 | { 116 | String query = 117 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 118 | " (resource:Resource {name:{resourceName}})\n" + 119 | "MATCH p=(admin)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()<-[:CHILD_OF*0." + 120 | ".3]-(company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource)\n" + 121 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 122 | "RETURN count(p) AS accessCount\n" + 123 | "UNION\n" + 124 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 125 | " (resource:Resource {name:{resourceName}})\n" + 126 | "MATCH p=(admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->(company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource)\n" + 127 | "RETURN count(p) AS accessCount"; 128 | 129 | Map params = new HashMap<>(); 130 | params.put( "adminName", adminName ); 131 | params.put( "resourceName", resourceName ); 132 | 133 | return executionEngine.execute( query, params ); 134 | } 135 | 136 | 137 | public ExecutionResult hasAccessToIndexedResource( String adminName, String resourceName ) 138 | { 139 | String query = 140 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 141 | " c1=(company)<-[:CHILD_OF*0..3]-(:Company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource:Resource {name:{resourceName}})\n" + 142 | "MATCH p=(admin)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->(company)\n" + 143 | "WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->(company))\n" + 144 | "RETURN count(p) AS accessCount\n" + 145 | // "RETURN p, company, admin, resource,c1\n" + 146 | "UNION\n" + 147 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 148 | " c1=(company:Company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource:Resource {name:{resourceName}})\n" + 149 | "MATCH p=(admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->(company)\n" + 150 | "RETURN count(p) AS accessCount\n"; 151 | // "RETURN p, company, admin, resource,c1\n"; 152 | 153 | Map params = new HashMap<>(); 154 | params.put( "adminName", adminName ); 155 | params.put( "resourceName", resourceName ); 156 | 157 | return executionEngine.execute( query, params ); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/AccessControlWithRelationshipPropertiesQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 7 | import org.neo4j.graphdatabases.queries.helpers.QueryUnionExecutionEngine; 8 | import org.neo4j.graphdatabases.queries.helpers.QueryUnionExecutionResult; 9 | 10 | public class AccessControlWithRelationshipPropertiesQueries 11 | { 12 | private final QueryUnionExecutionEngine executionEngine; 13 | 14 | public AccessControlWithRelationshipPropertiesQueries( ExecutionEngineWrapper executionEngine ) 15 | { 16 | this.executionEngine = new QueryUnionExecutionEngine( executionEngine ); 17 | } 18 | 19 | public QueryUnionExecutionResult findAccessibleResources( String adminName ) 20 | { 21 | String inheritedQuery = "MATCH (admin:Administrator {name:{adminName}})\n" + 22 | "MATCH paths=(admin)-[:MEMBER_OF]->()-[permission:ALLOWED]->()<-[:CHILD_OF*0..3]-()" + 23 | "<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)\n" + 24 | "WHERE (permission.inherit=true) AND NOT (admin-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-()" + 25 | "<-[:WORKS_FOR]-employee-[:HAS_ACCOUNT]->account)\n" + 26 | "RETURN paths"; 27 | String notInheritedQuery = "MATCH (admin:Administrator {name:{adminName}})\n" + 28 | "MATCH paths=(admin)-[:MEMBER_OF]->()-[permission:ALLOWED]->()" + 29 | "<-[:WORKS_FOR]-employee-[:HAS_ACCOUNT]->account\n" + 30 | "WHERE (permission.inherit=false)\n" + 31 | "RETURN paths"; 32 | 33 | Map params = new HashMap<>(); 34 | params.put( "adminName", adminName ); 35 | 36 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 37 | 38 | } 39 | // todo no result for query1 ? 40 | public QueryUnionExecutionResult findAccessibleCompanies( String adminName ) 41 | { 42 | String inheritedQuery = "MATCH (admin:Administrator {name:{adminName}})\n" + 43 | "MATCH admin-[:MEMBER_OF]->()-[permission:ALLOWED]->()<-[:CHILD_OF*0..3]-company\n" + 44 | "WHERE (permission.inherit=true) AND NOT (admin-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0." + 45 | ".3]-company)\n" + 46 | "RETURN company"; 47 | 48 | String notInheritedQuery = "MATCH (admin:Administrator {name:{adminName}})\n" + 49 | "MATCH admin-[:MEMBER_OF]->()-[permission:ALLOWED]->(company)\n" + 50 | "WHERE (permission.inherit=false)\n" + 51 | "RETURN company"; 52 | 53 | Map params = new HashMap<>(); 54 | params.put( "adminName", adminName ); 55 | 56 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 57 | } 58 | 59 | public QueryUnionExecutionResult findAccessibleAccountsForCompany( String adminName, 60 | String companyName ) 61 | { 62 | String inheritedQuery = "MATCH (admin:Administrator {name:{adminName}}),\n" + 63 | " (company:Company{name:{companyName}})\n" + 64 | "MATCH admin-[:MEMBER_OF]->group-[permission:ALLOWED]->company<-[:CHILD_OF*0." + 65 | ".3]-subcompany<-[:WORKS_FOR]-employee-[:HAS_ACCOUNT]->account\n" + 66 | "WHERE (permission.inherit=true) AND NOT (admin-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0." + 67 | ".3]-subcompany)\n" + 68 | "RETURN account"; 69 | 70 | String notInheritedQuery = "MATCH (admin:Administrator {name:{adminName}}),\n" + 71 | " (company:Company{name:{companyName}})\n" + 72 | "MATCH admin-[:MEMBER_OF]->group-[permission:ALLOWED]->company<-[:WORKS_FOR]-employee-[:HAS_ACCOUNT" + 73 | "]->account\n" + 74 | "WHERE (permission.inherit=false)\n" + 75 | "RETURN account"; 76 | 77 | Map params = new HashMap<>(); 78 | params.put( "adminName", adminName ); 79 | params.put( "companyName", companyName ); 80 | 81 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 82 | } 83 | 84 | // todo no result for query2 85 | public QueryUnionExecutionResult findAdminForResource( String resourceName ) 86 | { 87 | String inheritedQuery = "MATCH (resource:Resource {name:{resourceName}}) \n" + 88 | "MATCH p=resource-[:WORKS_FOR|HAS_ACCOUNT*1..2]-company-[:CHILD_OF*0..3]->()<-[permission:ALLOWED]-()" + 89 | "<-[:MEMBER_OF]-admin\n" + 90 | "WHERE (permission.inherit=true) AND NOT (admin-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-company)\n" + 91 | "RETURN DISTINCT admin, p"; 92 | 93 | String notInheritedQuery = "MATCH (resource:Resource{name:{resourceName}})\n" + 94 | "MATCH p=resource-[:WORKS_FOR|HAS_ACCOUNT*1..2]-company<-[permission:ALLOWED]-()" + 95 | "<-[:MEMBER_OF]-admin\n" + 96 | "WHERE (permission.inherit=false)\n" + 97 | "RETURN DISTINCT admin, p"; 98 | 99 | Map params = new HashMap<>(); 100 | params.put( "resourceName", resourceName ); 101 | 102 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 103 | } 104 | 105 | public QueryUnionExecutionResult findAdminForCompany( String companyName ) 106 | { 107 | String inheritedQuery = "MATCH (company:Company{name:{companyName}})\n" + 108 | "MATCH p=company-[:CHILD_OF*0..3]->()<-[permission:ALLOWED]-()<-[:MEMBER_OF]-admin\n" + 109 | "WHERE (permission.inherit=true) AND NOT (admin-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-company)\n" + 110 | "RETURN DISTINCT admin, p"; 111 | 112 | String notInheritedQuery = "MATCH (company:Company{name:{companyName}})\n" + 113 | "MATCH p=company<-[permission:ALLOWED]-()<-[:MEMBER_OF]-admin\n" + 114 | "WHERE (permission.inherit=false)\n" + 115 | "RETURN DISTINCT admin, p"; 116 | 117 | Map params = new HashMap<>(); 118 | params.put( "companyName", companyName ); 119 | 120 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 121 | } 122 | 123 | public QueryUnionExecutionResult hasAccessToResource( String adminName, String resourceName ) 124 | { 125 | String inheritedQuery = 126 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 127 | " (resource:Resource{name:{resourceName}})\n" + 128 | "MATCH p=(admin)-[:MEMBER_OF]->()-[permission:ALLOWED]->()<-[:CHILD_OF*0." + 129 | ".3]-(company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource)\n" + 130 | "WHERE (permission.inherit=true) AND NOT (admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company)\n" + 131 | "RETURN COUNT(p) AS accessCount"; 132 | 133 | String notInheritedQuery = 134 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 135 | " (resource:Resource{name:{resourceName}})\n" + 136 | "MATCH p=admin-[:MEMBER_OF]->()-[permission:ALLOWED]->company-[:WORKS_FOR|HAS_ACCOUNT*1..2]-resource\n" + 137 | "WHERE (permission.inherit=false)\n" + 138 | "RETURN COUNT(p) AS accessCount"; 139 | 140 | Map params = new HashMap<>(); 141 | params.put( "adminName", adminName ); 142 | params.put( "resourceName", resourceName ); 143 | 144 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 145 | } 146 | 147 | public QueryUnionExecutionResult hasAccessToIndexedResource( String adminName, String resourceName ) 148 | { 149 | String inheritedQuery = 150 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 151 | " (company)<-[:CHILD_OF*0..3]-(:Company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource:Resource {name:{resourceName}})\n" + 152 | "MATCH p=(admin)-[:MEMBER_OF]->()-[permission:ALLOWED]->(company)\n" + 153 | "WHERE (permission.inherit=true) AND NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))\n" + 154 | "RETURN COUNT(p) AS accessCount"; 155 | 156 | String notInheritedQuery = 157 | "MATCH (admin:Administrator {name:{adminName}}),\n" + 158 | " (company)<-[:CHILD_OF*0..3]-(:Company)-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(resource:Resource {name:{resourceName}})\n" + 159 | "MATCH p=(admin)-[:MEMBER_OF]->()-[permission:ALLOWED]->(company)\n" + 160 | "WHERE (permission.inherit=false)\n" + 161 | "RETURN COUNT(p) AS accessCount"; 162 | 163 | Map params = new HashMap<>(); 164 | params.put( "adminName", adminName ); 165 | params.put( "resourceName", resourceName ); 166 | 167 | return executionEngine.execute( params, inheritedQuery, notInheritedQuery ); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/EmailQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.cypher.javacompat.ExecutionResult; 7 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 8 | import org.neo4j.graphdb.GraphDatabaseService; 9 | 10 | public class EmailQueries 11 | { 12 | private final GraphDatabaseService db; 13 | private final ExecutionEngineWrapper executionEngineWrapper; 14 | 15 | public EmailQueries( GraphDatabaseService db, ExecutionEngineWrapper executionEngineWrapper ) 16 | { 17 | this.db = db; 18 | this.executionEngineWrapper = executionEngineWrapper; 19 | } 20 | 21 | public ExecutionResult suspectBehaviour() 22 | { 23 | String query = 24 | "MATCH (bob:User {username:'Bob'})-[:SENT]->(email)-[:CC]->(alias),\n" + 25 | " (alias)-[:ALIAS_OF]->(bob)\n" + 26 | "RETURN email.id"; 27 | 28 | Map params = new HashMap(); 29 | 30 | return executionEngineWrapper.execute( query, params ); 31 | } 32 | 33 | public ExecutionResult suspectBehaviour2() 34 | { 35 | String query = 36 | "MATCH p=(email:Email {id:'6'})<-[:REPLY_TO*1..4]-()<-[:SENT]-(replier)\n" + 37 | "RETURN replier.username AS replier, length(p) - 1 AS depth ORDER BY depth"; 38 | 39 | Map params = new HashMap(); 40 | 41 | return executionEngineWrapper.execute( query, params ); 42 | } 43 | 44 | public ExecutionResult suspectBehaviour3() 45 | { 46 | String query = 47 | "MATCH (email:Email {id:'11'})<-[f:FORWARD_OF*]-() \n" + 48 | "RETURN count(f)"; 49 | 50 | Map params = new HashMap(); 51 | 52 | return executionEngineWrapper.execute( query, params ); 53 | } 54 | 55 | public ExecutionResult lossyDb() 56 | { 57 | String query = 58 | "MATCH (bob:User {username:'Bob'})-[e:EMAILED]->(charlie:User {username:'Charlie'})\n" + 59 | "RETURN e"; 60 | 61 | Map params = new HashMap(); 62 | 63 | return executionEngineWrapper.execute( query, params ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/LogisticsQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.joda.time.Interval; 7 | import org.neo4j.cypher.javacompat.ExecutionResult; 8 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 9 | import org.neo4j.graphdatabases.queries.traversals.ParcelRouteCalculator; 10 | import org.neo4j.graphdatabases.queries.traversals.SimpleParcelRouteCalculator; 11 | import org.neo4j.graphdb.GraphDatabaseService; 12 | import org.neo4j.graphdb.Node; 13 | 14 | public class LogisticsQueries 15 | { 16 | private final ExecutionEngineWrapper executionEngineWrapper; 17 | private final ParcelRouteCalculator parcelRouteCalculator; 18 | private final SimpleParcelRouteCalculator simpleParcelRouteCalculator; 19 | 20 | public LogisticsQueries( GraphDatabaseService db, ExecutionEngineWrapper executionEngineWrapper ) 21 | { 22 | this.executionEngineWrapper = executionEngineWrapper; 23 | this.parcelRouteCalculator = new ParcelRouteCalculator( db ); 24 | this.simpleParcelRouteCalculator = new SimpleParcelRouteCalculator( db ); 25 | } 26 | 27 | public Iterable findShortestPathWithParcelRouteCalculator( String start, String end, Interval interval ) 28 | { 29 | return parcelRouteCalculator.calculateRoute( start, end, interval ); 30 | } 31 | 32 | public Iterable findShortestPathWithSimpleParcelRouteCalculator( String start, String end, Interval interval ) 33 | { 34 | return simpleParcelRouteCalculator.calculateRoute( start, end, interval ); 35 | } 36 | 37 | 38 | public ExecutionResult findShortestPathWithCypherReduce( String start, String end, Interval interval ) 39 | { 40 | String query = 41 | "MATCH (s:Location {name:{startLocation}}),\n" + 42 | " (e:Location {name:{endLocation}})\n" + 43 | "MATCH upLeg = (s)<-[:DELIVERY_ROUTE*1..2]-(db1)\n" + 44 | "WHERE all(r in relationships(upLeg)\n" + 45 | " WHERE r.start_date <= {intervalStart}\n" + 46 | " AND r.end_date >= {intervalEnd})\n" + 47 | "WITH e, upLeg, db1\n" + 48 | "MATCH downLeg = (db2)-[:DELIVERY_ROUTE*1..2]->(e)\n" + 49 | "WHERE all(r in relationships(downLeg)\n" + 50 | " WHERE r.start_date <= {intervalStart}\n" + 51 | " AND r.end_date >= {intervalEnd})\n" + 52 | "WITH db1, db2, upLeg, downLeg\n" + 53 | "MATCH topRoute = (db1)<-[:CONNECTED_TO]-()-[:CONNECTED_TO*1..3]-(db2)\n" + 54 | "WHERE all(r in relationships(topRoute)\n" + 55 | " WHERE r.start_date <= {intervalStart}\n" + 56 | " AND r.end_date >= {intervalEnd})\n" + 57 | "WITH upLeg, downLeg, topRoute,\n" + 58 | " reduce(weight=0, r in relationships(topRoute) | weight+r.cost) AS score\n" + 59 | " ORDER BY score ASC\n" + 60 | " LIMIT 1\n" + 61 | "RETURN (nodes(upLeg) + tail(nodes(topRoute)) + tail(nodes(downLeg))) AS n"; 62 | 63 | Map params = new HashMap(); 64 | params.put( "startLocation", start ); 65 | params.put( "endLocation", end ); 66 | params.put( "intervalStart", interval.getStartMillis() ); 67 | params.put( "intervalEnd", interval.getEndMillis() ); 68 | 69 | 70 | return executionEngineWrapper.execute( query, params ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/ShakespeareQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.cypher.javacompat.ExecutionResult; 7 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 8 | 9 | public class ShakespeareQueries 10 | { 11 | private final ExecutionEngineWrapper executionEngineWrapper; 12 | 13 | public ShakespeareQueries( ExecutionEngineWrapper executionEngineWrapper ) 14 | { 15 | this.executionEngineWrapper = executionEngineWrapper; 16 | } 17 | 18 | public ExecutionResult theatreCityBard() 19 | { 20 | String query = 21 | "MATCH (theater:Venue {name:'Theatre Royal'}), \n" + 22 | " (newcastle:City {name:'Newcastle'}), \n" + 23 | " (bard:Author {lastname:'Shakespeare'})\n" + 24 | "RETURN theater.name AS theater, newcastle.name AS city, bard.lastname AS bard"; 25 | 26 | Map params = new HashMap(); 27 | 28 | return executionEngineWrapper.execute( query, params ); 29 | } 30 | 31 | public ExecutionResult allPlays() 32 | { 33 | String query = 34 | "MATCH (theater:Venue {name:'Theatre Royal'}), \n" + 35 | " (newcastle:City {name:'Newcastle'}), \n" + 36 | " (bard:Author {lastname:'Shakespeare'})\n" + 37 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)\n" + 38 | " <-[:VENUE]-()-[:PERFORMANCE_OF]->()-[:PRODUCTION_OF]->\n" + 39 | " (play)<-[:WROTE_PLAY]-(bard)\n" + 40 | "RETURN DISTINCT play.title AS play"; 41 | 42 | Map params = new HashMap(); 43 | 44 | return executionEngineWrapper.execute( query, params ); 45 | } 46 | 47 | public ExecutionResult latePeriodPlays() 48 | { 49 | String query = 50 | "MATCH (theater:Venue {name:'Theatre Royal'}), \n" + 51 | " (newcastle:City {name:'Newcastle'}), \n" + 52 | " (bard:Author {lastname:'Shakespeare'})\n" + 53 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)<-[:VENUE]-()-[:PERFORMANCE_OF]->()\n" + 54 | " -[:PRODUCTION_OF]->(play)<-[w:WROTE_PLAY]-(bard)\n" + 55 | "WHERE w.year > 1608\n" + 56 | "RETURN DISTINCT play.title AS play"; 57 | 58 | Map params = new HashMap(); 59 | 60 | return executionEngineWrapper.execute( query, params ); 61 | } 62 | 63 | public ExecutionResult orderedByPerformance() 64 | { 65 | String query = 66 | "MATCH (theater:Venue {name:'Theatre Royal'}), \n" + 67 | " (newcastle:City {name:'Newcastle'}), \n" + 68 | " (bard:Author {lastname:'Shakespeare'})\n" + 69 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)<-[:VENUE]-()-[p:PERFORMANCE_OF]->()\n" + 70 | " -[:PRODUCTION_OF]->(play)<-[:WROTE_PLAY]-(bard)\n" + 71 | "RETURN play.title AS play, count(p) AS performance_count \n" + 72 | "ORDER BY performance_count DESC"; 73 | 74 | Map params = new HashMap(); 75 | 76 | return executionEngineWrapper.execute( query, params ); 77 | } 78 | 79 | public ExecutionResult exampleOfWith() 80 | { 81 | String query = 82 | "MATCH (bard:Author {lastname:'Shakespeare'})\n" + 83 | "MATCH (bard)-[w:WROTE_PLAY]->(play)\n" + 84 | "WITH play \n" + 85 | "ORDER BY w.year DESC \n" + 86 | "RETURN collect(play.title) AS plays"; 87 | 88 | Map params = new HashMap(); 89 | 90 | return executionEngineWrapper.execute( query, params ); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/ShakespeareQueriesUsingAutoIndexes.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.cypher.javacompat.ExecutionResult; 7 | import org.neo4j.graphdatabases.queries.helpers.ExecutionEngineWrapper; 8 | 9 | public class ShakespeareQueriesUsingAutoIndexes 10 | { 11 | private final ExecutionEngineWrapper executionEngineWrapper; 12 | 13 | public ShakespeareQueriesUsingAutoIndexes( ExecutionEngineWrapper executionEngineWrapper ) 14 | { 15 | this.executionEngineWrapper = executionEngineWrapper; 16 | } 17 | 18 | public ExecutionResult theatreCityBard() 19 | { 20 | String query = 21 | "START theater=node:node_auto_index(name='Theatre Royal'), \n" + 22 | " newcastle=node:node_auto_index(name='Newcastle'), \n" + 23 | " bard=node:node_auto_index(lastname='Shakespeare')\n" + 24 | "RETURN theater.name AS theater, newcastle.name AS city, bard.lastname AS bard"; 25 | 26 | Map params = new HashMap(); 27 | 28 | return executionEngineWrapper.execute( query, params ); 29 | } 30 | 31 | public ExecutionResult allPlays() 32 | { 33 | String query = 34 | "START theater=node:node_auto_index(name='Theatre Royal'), \n" + 35 | " newcastle=node:node_auto_index(name='Newcastle'), \n" + 36 | " bard=node:node_auto_index(lastname='Shakespeare')\n" + 37 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)\n" + 38 | " <-[:VENUE]-()-[:PERFORMANCE_OF]->()-[:PRODUCTION_OF]->\n" + 39 | " (play)<-[:WROTE_PLAY]-(bard)\n" + 40 | "RETURN DISTINCT play.title AS play"; 41 | 42 | Map params = new HashMap(); 43 | 44 | return executionEngineWrapper.execute( query, params ); 45 | } 46 | 47 | public ExecutionResult latePeriodPlays() 48 | { 49 | String query = 50 | "START theater=node:node_auto_index(name='Theatre Royal'), \n" + 51 | " newcastle=node:node_auto_index(name='Newcastle'), \n" + 52 | " bard=node:node_auto_index(lastname='Shakespeare')\n" + 53 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)<-[:VENUE]-()-[:PERFORMANCE_OF]->()\n" + 54 | " -[:PRODUCTION_OF]->(play)<-[w:WROTE_PLAY]-(bard)\n" + 55 | "WHERE w.year > 1608\n" + 56 | "RETURN DISTINCT play.title AS play"; 57 | 58 | Map params = new HashMap(); 59 | 60 | return executionEngineWrapper.execute( query, params ); 61 | } 62 | 63 | public ExecutionResult orderedByPerformance() 64 | { 65 | String query = 66 | "START theater=node:node_auto_index(name='Theatre Royal'), \n" + 67 | " newcastle=node:node_auto_index(name='Newcastle'), \n" + 68 | " bard=node:node_auto_index(lastname='Shakespeare')\n" + 69 | "MATCH (newcastle)<-[:STREET|CITY*1..2]-(theater)<-[:VENUE]-()-[p:PERFORMANCE_OF]->()\n" + 70 | " -[:PRODUCTION_OF]->(play)<-[:WROTE_PLAY]-(bard)\n" + 71 | "RETURN play.title AS play, count(p) AS performance_count \n" + 72 | "ORDER BY performance_count DESC"; 73 | 74 | Map params = new HashMap(); 75 | 76 | return executionEngineWrapper.execute( query, params ); 77 | } 78 | 79 | public ExecutionResult exampleOfWith() 80 | { 81 | String query = 82 | "START bard=node:node_auto_index(lastname='Shakespeare')\n" + 83 | "MATCH (bard)-[w:WROTE_PLAY]->(play)\n" + 84 | "WITH play \n" + 85 | "ORDER BY w.year DESC \n" + 86 | "RETURN collect(play.title) AS plays"; 87 | 88 | Map params = new HashMap(); 89 | 90 | return executionEngineWrapper.execute( query, params ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/SimpleSocialNetworkQueries.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.cypher.javacompat.ExecutionEngine; 7 | import org.neo4j.cypher.javacompat.ExecutionResult; 8 | import org.neo4j.graphdb.GraphDatabaseService; 9 | 10 | public class SimpleSocialNetworkQueries 11 | { 12 | private final ExecutionEngine executionEngine; 13 | 14 | public SimpleSocialNetworkQueries( GraphDatabaseService db ) 15 | { 16 | this.executionEngine = new ExecutionEngine( db ); 17 | } 18 | 19 | public ExecutionResult pathBetweenTwoFriends( String firstUser, String secondUser ) 20 | { 21 | String query = "MATCH (first:User{name:{firstUser}}),\n" + 22 | " (second:User{name:{secondUser}})\n" + 23 | "MATCH p=shortestPath(first-[*..4]-second)\n" + 24 | "RETURN length(p) AS depth"; 25 | 26 | Map params = new HashMap(); 27 | params.put( "firstUser", firstUser ); 28 | params.put( "secondUser", secondUser ); 29 | 30 | return executionEngine.execute( query, params ); 31 | } 32 | 33 | public ExecutionResult friendOfAFriendToDepth4(String name) 34 | { 35 | String query = 36 | "MATCH (person:User {name:{name}})-[:FRIEND]-()-[:FRIEND]-()-[:FRIEND]-()-[:FRIEND]-(friend)\n" + 37 | "RETURN friend.name AS name"; 38 | 39 | Map params = new HashMap(); 40 | params.put( "name", name ); 41 | 42 | return executionEngine.execute( query, params ); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/DbUtils.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.neo4j.graphdatabases.queries.testing.TestOutputWriter; 7 | import org.neo4j.graphdb.*; 8 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 9 | import org.neo4j.tooling.GlobalGraphOperations; 10 | 11 | import static org.neo4j.helpers.collection.IteratorUtil.count; 12 | 13 | public class DbUtils 14 | { 15 | public static GraphDatabaseService existingDB( String dir ) 16 | { 17 | GraphDatabaseService db = new GraphDatabaseFactory() 18 | .newEmbeddedDatabaseBuilder( dir ) 19 | .setConfig( DbUtils.dbConfig() ) 20 | .newGraphDatabase(); 21 | 22 | if ( countRelTypes(db) == 0 ) 23 | { 24 | throw new IllegalStateException( "Performance dataset does not exist. See the Readme for instructions on " + 25 | "generating a sample dataset." ); 26 | } 27 | 28 | return db; 29 | } 30 | 31 | public static int countRelTypes(GraphDatabaseService db) { 32 | try ( Transaction tx = db.beginTx() ) 33 | { 34 | int count = count(GlobalGraphOperations.at(db).getAllRelationshipTypes()); 35 | tx.success(); 36 | return count; 37 | } 38 | } 39 | 40 | public static Map dbConfig() 41 | { 42 | Map params = new HashMap(); 43 | params.put( "dump_configuration", "true" ); 44 | params.put( "cache_type", "gcr" ); 45 | params.put( "allow_store_upgrade", "true" ); 46 | params.put( "online_backup_enabled", "false" ); 47 | return params; 48 | } 49 | 50 | public static void warmCache( GraphDatabaseService db, TestOutputWriter writer ) 51 | { 52 | writer.writeln( "BEGIN: Warming cache" ); 53 | 54 | try ( Transaction tx = db.beginTx() ) 55 | { 56 | for ( Relationship r : GlobalGraphOperations.at( db ).getAllRelationships() ) 57 | { 58 | r.getPropertyKeys(); 59 | r.getStartNode(); 60 | } 61 | for ( Node n : GlobalGraphOperations.at( db ).getAllNodes() ) 62 | { 63 | n.getPropertyKeys(); 64 | for ( Relationship relationship : n.getRelationships() ) 65 | { 66 | relationship.getStartNode(); 67 | } 68 | } 69 | tx.success(); 70 | } 71 | writer.writeln( "\nEND : Warming cache\n" ); 72 | } 73 | 74 | public static int numberOfItemsWithLabel(GraphDatabaseService db, String labelName) 75 | { 76 | try ( Transaction tx = db.beginTx() ) 77 | { 78 | GlobalGraphOperations ops = GlobalGraphOperations.at(db); 79 | int count = count(ops.getAllNodesWithLabel(DynamicLabel.label(labelName))); 80 | tx.success(); 81 | return count; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/ExecutionEngineWrapper.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.util.Map; 4 | 5 | import org.neo4j.cypher.javacompat.ExecutionResult; 6 | 7 | 8 | public interface ExecutionEngineWrapper 9 | { 10 | ExecutionResult execute(String query, Map params); 11 | ExecutionResult execute(String query, Map params, int index); 12 | } 13 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/ExecutionResultIterator.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Queue; 8 | 9 | import org.neo4j.cypher.javacompat.ExecutionResult; 10 | 11 | public class ExecutionResultIterator 12 | { 13 | public static ExecutionResultIterator newQueryIterators( List queries, 14 | ExecutionEngineWrapper executionEngine, 15 | Map params ) 16 | { 17 | Queue queue = new LinkedList( queries ); 18 | String query = queue.poll(); 19 | ExecutionResult executionResult = executionEngine.execute( query, params, 1 ); 20 | return new ExecutionResultIterator( executionResult, queue, executionEngine, params, 2 ); 21 | } 22 | 23 | private final ExecutionResult currentResult; 24 | private final Queue queries; 25 | private final ExecutionEngineWrapper executionEngine; 26 | private final Map params; 27 | private final int queryIndex; 28 | 29 | private ExecutionResultIterator( ExecutionResult currentResult, 30 | Queue queries, 31 | ExecutionEngineWrapper executionEngine, 32 | Map params, 33 | int queryIndex ) 34 | { 35 | this.currentResult = currentResult; 36 | this.queries = queries; 37 | this.executionEngine = executionEngine; 38 | this.params = params; 39 | this.queryIndex = queryIndex; 40 | } 41 | 42 | public Iterator> iterator() 43 | { 44 | return currentResult.iterator(); 45 | } 46 | 47 | public boolean hasNextIterator() 48 | { 49 | return !queries.isEmpty(); 50 | } 51 | 52 | public ExecutionResultIterator getNextIterator() 53 | { 54 | String query = queries.poll(); 55 | ExecutionResult executionResult = executionEngine.execute( query, params, queryIndex ); 56 | return new ExecutionResultIterator( executionResult, queries, executionEngine, params, queryIndex + 1 ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/ExecutionResultsIterator.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.NoSuchElementException; 7 | 8 | public class ExecutionResultsIterator implements Iterator> 9 | { 10 | private ExecutionResultIterator executionResultIterator; 11 | 12 | public ExecutionResultsIterator( List queries, 13 | ExecutionEngineWrapper executionEngine, 14 | Map params ) 15 | { 16 | executionResultIterator = ExecutionResultIterator.newQueryIterators( queries, executionEngine, params ); 17 | } 18 | 19 | @Override 20 | public boolean hasNext() 21 | { 22 | if ( executionResultIterator.iterator().hasNext() ) 23 | { 24 | return true; 25 | } 26 | 27 | if ( !executionResultIterator.hasNextIterator() ) 28 | { 29 | return false; 30 | } 31 | 32 | executionResultIterator = executionResultIterator.getNextIterator(); 33 | 34 | return hasNext(); 35 | } 36 | 37 | @Override 38 | public Map next() 39 | { 40 | if ( hasNext() ) 41 | { 42 | return executionResultIterator.iterator().next(); 43 | } 44 | 45 | throw new NoSuchElementException(); 46 | } 47 | 48 | @Override 49 | public void remove() 50 | { 51 | throw new UnsupportedOperationException(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/IndexNodeByOtherNodeIndexer.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import org.neo4j.graphdb.*; 4 | import org.neo4j.graphdb.index.Index; 5 | 6 | public class IndexNodeByOtherNodeIndexer 7 | { 8 | private final GraphTraversal findIndexableNodes; 9 | private final GraphTraversal findOtherNodesForIndexableNode; 10 | private final String indexName; 11 | private final String indexKey; 12 | private final String nodeToIndexByPropertyName; 13 | 14 | public IndexNodeByOtherNodeIndexer( GraphTraversal findIndexableNodes, GraphTraversal 15 | findOtherNodesForIndexableNode, 16 | String indexName, String indexKey, String nodeToIndexByPropertyName ) 17 | 18 | { 19 | this.findIndexableNodes = findIndexableNodes; 20 | this.findOtherNodesForIndexableNode = findOtherNodesForIndexableNode; 21 | this.indexName = indexName; 22 | this.indexKey = indexKey; 23 | this.nodeToIndexByPropertyName = nodeToIndexByPropertyName; 24 | } 25 | 26 | public void execute( GraphDatabaseService db, Node startNode, int batchSize ) 27 | { 28 | 29 | Transaction tx = db.beginTx(); 30 | 31 | Label label = DynamicLabel.label(indexName); 32 | Iterable indexableNodes = findIndexableNodes.execute( startNode ); 33 | int currentBatchSize = 0; 34 | 35 | try 36 | { 37 | for ( Node indexableNode : indexableNodes ) 38 | { 39 | Iterable nodesToIndexBy = findOtherNodesForIndexableNode.execute( indexableNode ); 40 | for ( Node node : nodesToIndexBy ) 41 | { 42 | indexableNode.addLabel(label); 43 | indexableNode.setProperty(indexKey, node.getProperty( nodeToIndexByPropertyName ) ); 44 | if ( currentBatchSize++ > batchSize ) 45 | { 46 | tx.success(); 47 | tx.close(); 48 | tx = db.beginTx(); 49 | currentBatchSize = 0; 50 | } 51 | } 52 | } 53 | tx.success(); 54 | } 55 | finally 56 | { 57 | tx.close(); 58 | } 59 | 60 | } 61 | 62 | public interface GraphTraversal 63 | { 64 | Iterable execute( Node startNode ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/QueryUnionExecutionEngine.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class QueryUnionExecutionEngine 9 | { 10 | private final ExecutionEngineWrapper executionEngine; 11 | 12 | public QueryUnionExecutionEngine( ExecutionEngineWrapper executionEngine ) 13 | { 14 | this.executionEngine = executionEngine; 15 | } 16 | 17 | public QueryUnionExecutionResult execute( final Map params, final String... queries ) 18 | { 19 | if ( queries.length == 0 ) 20 | { 21 | throw new IllegalArgumentException( "Must supply one or more queries." ); 22 | } 23 | 24 | return new QueryUnionExecutionResult( asList( queries ), executionEngine, params ); 25 | } 26 | 27 | public Iterable> execute( final String... queries ) 28 | { 29 | return execute( new HashMap(), queries ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/helpers/QueryUnionExecutionResult.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | public class QueryUnionExecutionResult implements Iterable> 8 | { 9 | private final List queries; 10 | private final ExecutionEngineWrapper executionEngine; 11 | private final Map params; 12 | 13 | public QueryUnionExecutionResult( List queries, 14 | ExecutionEngineWrapper executionEngine, 15 | Map params ) 16 | { 17 | this.queries = queries; 18 | this.executionEngine = executionEngine; 19 | this.params = params; 20 | } 21 | 22 | @Override 23 | public Iterator> iterator() 24 | { 25 | return new ExecutionResultsIterator( queries, executionEngine, params ); 26 | } 27 | 28 | @Override 29 | public String toString() 30 | { 31 | StringBuilder builder = new StringBuilder( ); 32 | for ( String query : queries ) 33 | { 34 | builder.append( executionEngine.execute( query, params ).dumpToString()); 35 | } 36 | return builder.toString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/server/SimpleSocialNetworkExtension.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.server; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | import javax.ws.rs.core.Context; 7 | 8 | import org.neo4j.cypher.javacompat.ExecutionResult; 9 | import org.neo4j.graphdatabases.queries.SimpleSocialNetworkQueries; 10 | import org.neo4j.graphdb.GraphDatabaseService; 11 | 12 | @Path("/distance") 13 | public class SimpleSocialNetworkExtension 14 | { 15 | private final SimpleSocialNetworkQueries queries; 16 | 17 | public SimpleSocialNetworkExtension( @Context GraphDatabaseService db ) 18 | { 19 | this.queries = new SimpleSocialNetworkQueries( db ); 20 | } 21 | 22 | @GET 23 | @Path("/{name1}/{name2}") 24 | public String getDistance ( @PathParam("name1") String name1, @PathParam("name2") String name2 ) 25 | { 26 | ExecutionResult result = queries.pathBetweenTwoFriends( name1, name2 ); 27 | 28 | return String.valueOf( result.columnAs( "depth" ).next() ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/testing/IndexParam.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.testing; 2 | 3 | public class IndexParam 4 | { 5 | public static IndexParam indexParam( String nodeLabel, String propertyName ) 6 | { 7 | return new IndexParam( nodeLabel, propertyName); 8 | } 9 | 10 | private final String nodeLabel; 11 | private final String propertyName; 12 | 13 | private IndexParam(String nodeLabel, String propertyName) 14 | { 15 | this.nodeLabel = nodeLabel; 16 | this.propertyName = propertyName; 17 | } 18 | 19 | public String nodeLabel() 20 | { 21 | return nodeLabel; 22 | } 23 | 24 | public String propertyName() 25 | { 26 | return propertyName; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/testing/IndexParams.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.testing; 2 | 3 | import static java.lang.String.format; 4 | import static java.util.Arrays.asList; 5 | 6 | import java.util.List; 7 | 8 | import org.neo4j.cypher.javacompat.ExecutionEngine; 9 | import org.neo4j.graphdb.DynamicLabel; 10 | import org.neo4j.graphdb.GraphDatabaseService; 11 | import org.neo4j.graphdb.Node; 12 | import org.neo4j.graphdb.Transaction; 13 | import org.neo4j.tooling.GlobalGraphOperations; 14 | 15 | public class IndexParams 16 | { 17 | private final List indexParams; 18 | 19 | public IndexParams( IndexParam... params ) 20 | { 21 | indexParams = asList( params ); 22 | } 23 | 24 | public void index(GraphDatabaseService db) 25 | { 26 | try (Transaction tx = db.beginTx()) { 27 | for (IndexParam indexParam : indexParams) { 28 | db.schema().indexFor(DynamicLabel.label(indexParam.nodeLabel())).on(indexParam.propertyName()).create(); 29 | // db.schema().constraintFor(DynamicLabel.label(indexParam.nodeLabel())).assertPropertyIsUnique(indexParam.propertyName()).create(); 30 | // engine.execute(format("CREATE INDEX ON :%s(%s)", indexParam.nodeLabel(), indexParam.propertyName())); 31 | } 32 | tx.success(); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/testing/TestOutputWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Neo Technology 3 | * All rights reserved 4 | */ 5 | package org.neo4j.graphdatabases.queries.testing; 6 | 7 | public interface TestOutputWriter 8 | { 9 | void begin(); 10 | void write(String value); 11 | void writeln( String value ); 12 | void flush(); 13 | void end(); 14 | } 15 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/traversals/FriendOfAFriendDepth4.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.traversals; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | import static org.neo4j.graphdb.traversal.Uniqueness.*; 5 | 6 | import org.neo4j.graphdb.*; 7 | import org.neo4j.graphdb.index.Index; 8 | import org.neo4j.graphdb.traversal.Evaluation; 9 | import org.neo4j.graphdb.traversal.Evaluator; 10 | import org.neo4j.graphdb.traversal.TraversalDescription; 11 | import org.neo4j.helpers.collection.IteratorUtil; 12 | import org.neo4j.kernel.Traversal; 13 | import org.neo4j.kernel.Uniqueness; 14 | 15 | public class FriendOfAFriendDepth4 16 | { 17 | public static final Label USER = DynamicLabel.label("User"); 18 | 19 | private final TraversalDescription traversalDescription; 20 | 21 | private final GraphDatabaseService db; 22 | 23 | public FriendOfAFriendDepth4( GraphDatabaseService db ) 24 | { 25 | this.db = db; 26 | traversalDescription = traversalDescription(db); 27 | } 28 | 29 | private TraversalDescription traversalDescription(GraphDatabaseService db) 30 | { 31 | return db.traversalDescription() 32 | .breadthFirst() 33 | .uniqueness( NODE_GLOBAL ) 34 | .relationships( withName( "FRIEND" ) ) 35 | .evaluator( new Evaluator() 36 | { 37 | @Override 38 | public Evaluation evaluate( Path path ) 39 | { 40 | if ( path.length() == 4 ) 41 | { 42 | return Evaluation.INCLUDE_AND_PRUNE; 43 | } 44 | return Evaluation.EXCLUDE_AND_CONTINUE; 45 | 46 | } 47 | } ); 48 | } 49 | 50 | public Iterable getFriends( String name ) 51 | { 52 | ResourceIterable users = db.findNodesByLabelAndProperty(USER, "name", name); 53 | Node startNode = IteratorUtil.single(users); 54 | return traversalDescription.traverse(startNode).nodes(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/traversals/IndexResources.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.traversals; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import org.neo4j.graphdatabases.queries.helpers.IndexNodeByOtherNodeIndexer; 6 | import org.neo4j.graphdb.*; 7 | import org.neo4j.graphdb.traversal.Evaluation; 8 | import org.neo4j.graphdb.traversal.Evaluator; 9 | import org.neo4j.graphdb.traversal.TraversalDescription; 10 | import org.neo4j.kernel.Traversal; 11 | import org.neo4j.tooling.GlobalGraphOperations; 12 | 13 | public class IndexResources 14 | { 15 | private final GraphDatabaseService db; 16 | private final TraversalDescription traversalDescription = Traversal.description() 17 | .breadthFirst() 18 | .relationships( withName( "WORKS_FOR" ), Direction.INCOMING ) 19 | .relationships( withName( "HAS_ACCOUNT" ), Direction.OUTGOING ) 20 | .evaluator( new Evaluator() 21 | { 22 | @Override 23 | public Evaluation evaluate( Path path ) 24 | { 25 | if ( path.endNode().equals( path.startNode() ) ) 26 | { 27 | return Evaluation.EXCLUDE_AND_CONTINUE; 28 | } 29 | return Evaluation.INCLUDE_AND_CONTINUE; 30 | } 31 | } ); 32 | 33 | public IndexResources( GraphDatabaseService db ) 34 | { 35 | this.db = db; 36 | } 37 | 38 | public void execute() 39 | { 40 | IndexNodeByOtherNodeIndexer.GraphTraversal traversal1 = new IndexNodeByOtherNodeIndexer.GraphTraversal() 41 | { 42 | @Override 43 | public Iterable execute( Node startNode ) 44 | { 45 | return GlobalGraphOperations.at(db).getAllNodesWithLabel(DynamicLabel.label("company")); 46 | } 47 | }; 48 | 49 | IndexNodeByOtherNodeIndexer.GraphTraversal traversal2 = new IndexNodeByOtherNodeIndexer.GraphTraversal() 50 | { 51 | @Override 52 | public Iterable execute( Node startNode ) 53 | { 54 | return traversalDescription.traverse( startNode ).nodes(); 55 | } 56 | }; 57 | 58 | IndexNodeByOtherNodeIndexer indexer = new IndexNodeByOtherNodeIndexer( traversal1, traversal2, "company", "resourceName", "name" ); 59 | indexer.execute( db, null, 1000 ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/traversals/ParcelRouteCalculator.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.traversals; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedHashSet; 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | import org.joda.time.Interval; 11 | import org.neo4j.graphalgo.CommonEvaluators; 12 | import org.neo4j.graphalgo.CostEvaluator; 13 | import org.neo4j.graphalgo.GraphAlgoFactory; 14 | import org.neo4j.graphalgo.PathFinder; 15 | import org.neo4j.graphalgo.WeightedPath; 16 | import org.neo4j.graphdb.*; 17 | import org.neo4j.graphdb.index.Index; 18 | import org.neo4j.graphdb.traversal.BranchState; 19 | import org.neo4j.graphdb.traversal.Evaluation; 20 | import org.neo4j.graphdb.traversal.Evaluator; 21 | import org.neo4j.graphdb.traversal.InitialBranchState; 22 | import org.neo4j.graphdb.traversal.TraversalDescription; 23 | import org.neo4j.helpers.collection.IteratorUtil; 24 | import org.neo4j.kernel.Traversal; 25 | 26 | public class ParcelRouteCalculator 27 | { 28 | private static final PathExpander DELIVERY_ROUTE_EXPANDER = new IntervalPathExpander( 29 | withName( "DELIVERY_ROUTE" ), 30 | Direction.INCOMING 31 | ); 32 | 33 | private static final PathExpander CONNECTED_TO_EXPANDER = new IntervalPathExpander( 34 | withName( "CONNECTED_TO" ), 35 | Direction.BOTH 36 | ); 37 | 38 | private static final TraversalDescription DELIVERY_BASE_FINDER = Traversal.description() 39 | .depthFirst() 40 | .evaluator( new Evaluator() 41 | { 42 | private final RelationshipType DELIVERY_ROUTE = withName( "DELIVERY_ROUTE"); 43 | 44 | @Override 45 | public Evaluation evaluate( Path path ) 46 | { 47 | if ( isDeliveryBase( path ) ) 48 | { 49 | return Evaluation.INCLUDE_AND_PRUNE; 50 | } 51 | 52 | return Evaluation.EXCLUDE_AND_CONTINUE; 53 | } 54 | 55 | private boolean isDeliveryBase( Path path ) 56 | { 57 | return !path.endNode().hasRelationship( DELIVERY_ROUTE, Direction.INCOMING ); 58 | } 59 | } ); 60 | 61 | private static final CostEvaluator COST_EVALUATOR = CommonEvaluators.doubleCostEvaluator( "cost" ); 62 | public static final Label LOCATION = DynamicLabel.label("Location"); 63 | private GraphDatabaseService db; 64 | 65 | public ParcelRouteCalculator( GraphDatabaseService db ) 66 | { 67 | this.db = db; 68 | } 69 | 70 | public Iterable calculateRoute( String start, String end, Interval interval ) 71 | { 72 | try ( Transaction tx = db.beginTx() ) 73 | { 74 | TraversalDescription deliveryBaseFinder = createDeliveryBaseFinder( interval ); 75 | 76 | Path upLeg = findRouteToDeliveryBase( start, deliveryBaseFinder ); 77 | Path downLeg = findRouteToDeliveryBase( end, deliveryBaseFinder ); 78 | 79 | Path topRoute = findRouteBetweenDeliveryBases( 80 | upLeg.endNode(), 81 | downLeg.endNode(), 82 | interval ); 83 | 84 | Set routes = combineRoutes(upLeg, downLeg, topRoute); 85 | tx.success(); 86 | return routes; 87 | } 88 | } 89 | 90 | private TraversalDescription createDeliveryBaseFinder( Interval interval ) 91 | { 92 | return DELIVERY_BASE_FINDER.expand( DELIVERY_ROUTE_EXPANDER, 93 | new InitialBranchState.State( interval, interval ) ); 94 | } 95 | 96 | private Set combineRoutes( Path upLeg, Path downLeg, Path topRoute ) 97 | { 98 | LinkedHashSet results = new LinkedHashSet(); 99 | results.addAll( IteratorUtil.asCollection( upLeg.nodes() )); 100 | results.addAll( IteratorUtil.asCollection( topRoute.nodes() )); 101 | results.addAll( IteratorUtil.asCollection( downLeg.reverseNodes() )); 102 | return results; 103 | } 104 | 105 | private Path findRouteBetweenDeliveryBases( Node deliveryBase1, Node deliveryBase2, Interval interval ) 106 | { 107 | PathFinder routeBetweenDeliveryBasesFinder = GraphAlgoFactory.dijkstra( 108 | CONNECTED_TO_EXPANDER, 109 | new InitialBranchState.State( interval, interval ), 110 | COST_EVALUATOR ); 111 | return routeBetweenDeliveryBasesFinder.findSinglePath( deliveryBase1, deliveryBase2 ); 112 | } 113 | 114 | private Path findRouteToDeliveryBase( String startPosition, TraversalDescription deliveryBaseFinder ) 115 | { 116 | Node startNode = IteratorUtil.single(db.findNodesByLabelAndProperty(LOCATION, "name", startPosition)); 117 | return deliveryBaseFinder.traverse( startNode ).iterator().next(); 118 | } 119 | 120 | private static class IntervalPathExpander implements PathExpander 121 | { 122 | 123 | private final RelationshipType relationshipType; 124 | private final Direction direction; 125 | 126 | private IntervalPathExpander( RelationshipType relationshipType, Direction direction ) 127 | { 128 | this.relationshipType = relationshipType; 129 | this.direction = direction; 130 | } 131 | 132 | @Override 133 | public Iterable expand( Path path, BranchState deliveryInterval ) 134 | { 135 | List results = new ArrayList(); 136 | for ( Relationship r : path.endNode().getRelationships( relationshipType, direction ) ) 137 | { 138 | Interval relationshipInterval = new Interval( 139 | (Long) r.getProperty( "start_date" ), 140 | (Long) r.getProperty( "end_date" ) ); 141 | if ( relationshipInterval.contains( deliveryInterval.getState() ) ) 142 | { 143 | results.add( r ); 144 | } 145 | } 146 | 147 | return results; 148 | } 149 | 150 | @Override 151 | public PathExpander reverse() 152 | { 153 | return null; 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /queries/src/main/java/org/neo4j/graphdatabases/queries/traversals/SimpleParcelRouteCalculator.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.traversals; 2 | 3 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.joda.time.Interval; 9 | import org.neo4j.graphalgo.CommonEvaluators; 10 | import org.neo4j.graphalgo.CostEvaluator; 11 | import org.neo4j.graphalgo.GraphAlgoFactory; 12 | import org.neo4j.graphalgo.PathFinder; 13 | import org.neo4j.graphalgo.WeightedPath; 14 | import org.neo4j.graphdb.*; 15 | import org.neo4j.graphdb.index.Index; 16 | import org.neo4j.graphdb.traversal.BranchState; 17 | import org.neo4j.graphdb.traversal.InitialBranchState; 18 | import org.neo4j.helpers.collection.IteratorUtil; 19 | 20 | public class SimpleParcelRouteCalculator 21 | { 22 | private static final CostEvaluator COST_EVALUATOR = CommonEvaluators.doubleCostEvaluator( "cost" ); 23 | private static final PathExpander PATH_EXPANDER = new ValidPathExpander(); 24 | public static final Label LOCATION = DynamicLabel.label("Location"); 25 | private GraphDatabaseService db; 26 | 27 | public SimpleParcelRouteCalculator( GraphDatabaseService db ) 28 | { 29 | this.db = db; 30 | } 31 | 32 | public Iterable calculateRoute( String start, String end, Interval interval ) 33 | { 34 | Node startNode = findByLocation ( start ); 35 | Node endNode = findByLocation( end ); 36 | 37 | PathFinder routeBetweenDeliveryBasesFinder = GraphAlgoFactory.dijkstra( 38 | PATH_EXPANDER, 39 | new InitialBranchState.State( interval, interval ), 40 | COST_EVALUATOR ); 41 | return IteratorUtil.asCollection( 42 | routeBetweenDeliveryBasesFinder.findSinglePath( startNode, endNode ).nodes() ); 43 | } 44 | 45 | private Node findByLocation(String location) 46 | { 47 | return IteratorUtil.single( db.findNodesByLabelAndProperty( LOCATION, "name", location ) ); 48 | } 49 | 50 | private static class ValidPathExpander implements PathExpander 51 | { 52 | @Override 53 | public Iterable expand( Path path, BranchState deliveryInterval ) 54 | { 55 | List results = new ArrayList(); 56 | for ( Relationship r : path.endNode().getRelationships( Direction.BOTH, withName( "CONNECTED_TO" ), 57 | withName( "DELIVERY_ROUTE" ) ) ) 58 | { 59 | Interval relationshipInterval = new Interval( 60 | (Long) r.getProperty( "start_date" ), 61 | (Long) r.getProperty( "end_date" ) ); 62 | if ( relationshipInterval.contains( deliveryInterval.getState() ) ) 63 | { 64 | results.add( r ); 65 | } 66 | } 67 | 68 | return results; 69 | } 70 | 71 | @Override 72 | public PathExpander reverse() 73 | { 74 | return null; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /queries/src/main/resources/META_INF/services/javax.script.ScriptEngineFactory: -------------------------------------------------------------------------------- 1 | com.tinkerpop.gremlin.jsr223.GremlinGroovyScriptEngineFactory -------------------------------------------------------------------------------- /queries/src/main/resources/META_INF/services/org.neo4j.server.plugins.ServerPlugin: -------------------------------------------------------------------------------- 1 | org.neo4j.graphdatabases.queries.server.SimpleSocialNetworkExtension -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/EmailQueriesTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.junit.rules.TestName; 9 | 10 | import org.neo4j.cypher.javacompat.ExecutionResult; 11 | import org.neo4j.graphdatabases.queries.helpers.PrintingExecutionEngineWrapper; 12 | import org.neo4j.graphdatabases.queries.testing.IndexParam; 13 | import org.neo4j.graphdb.GraphDatabaseService; 14 | import org.neo4j.graphdb.Node; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertFalse; 18 | 19 | import static org.neo4j.graphdatabases.queries.helpers.Db.createFromCypher; 20 | import static org.neo4j.helpers.collection.IteratorUtil.count; 21 | 22 | public class EmailQueriesTest 23 | { 24 | @Rule 25 | public TestName name = new TestName(); 26 | 27 | @Test 28 | public void suspectBehaviour() throws Exception 29 | { 30 | GraphDatabaseService db = createDatabase(); 31 | EmailQueries queries = new EmailQueries( db, new PrintingExecutionEngineWrapper( db, "email", name ) ); 32 | 33 | ExecutionResult result = queries.suspectBehaviour(); 34 | Iterator> iterator = result.iterator(); 35 | Map next = iterator.next(); 36 | assertEquals( "1", next.get( "email.id" )); 37 | assertFalse( iterator.hasNext() ); 38 | 39 | db.shutdown(); 40 | } 41 | 42 | @Test 43 | public void suspectBehaviour2() throws Exception 44 | { 45 | GraphDatabaseService db = createDatabase2(); 46 | EmailQueries queries = new EmailQueries( db, new PrintingExecutionEngineWrapper( db, "email", name ) ); 47 | 48 | ExecutionResult result = queries.suspectBehaviour2(); 49 | 50 | Iterator> iterator = result.iterator(); 51 | Map next = iterator.next(); 52 | assertEquals( 1L, next.get( "depth" ) ); 53 | assertEquals( "Davina", next.get( "replier" ) ); 54 | 55 | next = iterator.next(); 56 | assertEquals( 1L, next.get( "depth" ) ); 57 | assertEquals( "Bob", next.get( "replier" ) ); 58 | 59 | next = iterator.next(); 60 | assertEquals( 2L, next.get( "depth" ) ); 61 | assertEquals( "Charlie", next.get( "replier" ) ); 62 | 63 | next = iterator.next(); 64 | assertEquals( 3L, next.get( "depth" ) ); 65 | assertEquals( "Bob", next.get( "replier" ) ); 66 | 67 | assertFalse( iterator.hasNext() ); 68 | 69 | 70 | db.shutdown(); 71 | } 72 | 73 | @Test 74 | public void suspectBehaviour3() throws Exception 75 | { 76 | GraphDatabaseService db = createDatabase3(); 77 | EmailQueries queries = new EmailQueries( db, new PrintingExecutionEngineWrapper( db, "email", name ) ); 78 | 79 | ExecutionResult result = queries.suspectBehaviour3(); 80 | 81 | Iterator objectIterator = result.columnAs( "count(f)" ); 82 | assertEquals( 2L, objectIterator.next() ); 83 | 84 | assertFalse( objectIterator.hasNext() ); 85 | 86 | db.shutdown(); 87 | } 88 | 89 | @Test 90 | public void lossyDb() throws Exception 91 | { 92 | GraphDatabaseService db = createDatabase4(); 93 | EmailQueries queries = new EmailQueries( db, new PrintingExecutionEngineWrapper( db, "email", name ) ); 94 | 95 | ExecutionResult result = queries.lossyDb(); 96 | 97 | assertEquals(1, count(result.iterator())); 98 | 99 | db.shutdown(); 100 | } 101 | 102 | private static GraphDatabaseService createDatabase() 103 | { 104 | String cypher = "CREATE \n" + 105 | "(charlie:User {username:'Charlie'}),\n" + 106 | "(davina:User {username:'Davina'}),\n" + 107 | "(edward:User {username:'Edward'}),\n" + 108 | "(alice:User {username:'Alice'}),\n" + 109 | "(bob:User {username:'Bob'}),\n" + 110 | "(alice)-[:ALIAS_OF]->(bob),\n" + 111 | "\n" + 112 | "(email_1:Email {id: '1', content: 'email contents'}),\n" + 113 | "(bob)-[:SENT]->(email_1),\n" + 114 | "(email_1)-[:TO]->(charlie),\n" + 115 | "(email_1)-[:CC]->(davina),\n" + 116 | "(email_1)-[:CC]->(alice),\n" + 117 | "(email_1)-[:BCC]->(edward),\n" + 118 | "\n" + 119 | "(email_2:Email {id: '2', content: 'email contents'}),\n" + 120 | "(bob)-[:SENT]->(email_2),\n" + 121 | "(email_2)-[:TO]->(davina),\n" + 122 | "(email_2)-[:BCC]->(edward),\n" + 123 | "\n" + 124 | "(email_3:Email {id: '3', content: 'email contents'}),\n" + 125 | "(davina)-[:SENT]->(email_3),\n" + 126 | "(email_3)-[:TO]->(bob),\n" + 127 | "(email_3)-[:CC]->(edward),\n" + 128 | "\n" + 129 | "(email_4:Email {id: '4', content: 'email contents'}),\n" + 130 | "(charlie)-[:SENT]->(email_4),\n" + 131 | "(email_4)-[:TO]->(bob),\n" + 132 | "(email_4)-[:TO]->(davina),\n" + 133 | "(email_4)-[:TO]->(edward),\n" + 134 | "\n" + 135 | "(email_5:Email {id: '5', content: 'email contents'}),\n" + 136 | "(davina)-[:SENT]->(email_5),\n" + 137 | "(email_5)-[:TO]->(alice),\n" + 138 | "(email_5)-[:BCC]->(bob),\n" + 139 | "(email_5)-[:BCC]->(edward)"; 140 | 141 | return createFromCypher( 142 | "Email", 143 | cypher, 144 | IndexParam.indexParam( "User", "username" ), 145 | IndexParam.indexParam( "Email", "id" ) 146 | ); 147 | } 148 | 149 | private static GraphDatabaseService createDatabase2() 150 | { 151 | String cypher = "CREATE \n" + 152 | "(charlie:User {username:'Charlie'}),\n" + 153 | "(davina:User {username:'Davina'}),\n" + 154 | "(edward:User {username:'Edward'}),\n" + 155 | "(alice:User {username:'Alice'}),\n" + 156 | "(bob:User {username:'Bob'}),\n" + 157 | "(alice)-[:ALIAS_OF]->(bob),\n" + 158 | "\n" + 159 | "(email_6:Email {id: '6', content: 'email'}),\n" + 160 | "(bob)-[:SENT]->(email_6),\n" + 161 | "(email_6)-[:TO]->(charlie),\n" + 162 | "(email_6)-[:TO]->(davina),\n" + 163 | "\n" + 164 | "(reply_1:Email {id: '7', content: 'response'}),\n" + 165 | "(reply_1)-[:REPLY_TO]->(email_6),\n" + 166 | "(davina)-[:SENT]->(reply_1),\n" + 167 | "(reply_1)-[:TO]->(bob),\n" + 168 | "(reply_1)-[:TO]->(charlie),\n" + 169 | "\n" + 170 | "(reply_2:Email {id: '8', content: 'response'}),\n" + 171 | "(reply_2)-[:REPLY_TO]->(email_6),\n" + 172 | "(bob)-[:SENT]->(reply_2),\n" + 173 | "(reply_2)-[:TO]->(davina),\n" + 174 | "(reply_2)-[:TO]->(charlie),\n" + 175 | "(reply_2)-[:CC]->(alice),\n" + 176 | "\n" + 177 | "(reply_3:Email {id: '9', content: 'response'}),\n" + 178 | "(reply_3)-[:REPLY_TO]->(reply_1),\n" + 179 | "(charlie)-[:SENT]->(reply_3),\n" + 180 | "(reply_3)-[:TO]->(bob),\n" + 181 | "(reply_3)-[:TO]->(davina),\n" + 182 | "\n" + 183 | "(reply_4:Email {id: '10', content: 'response'}),\n" + 184 | "(reply_4)-[:REPLY_TO]->(reply_3),\n" + 185 | "(bob)-[:SENT]->(reply_4),\n" + 186 | "(reply_4)-[:TO]->(charlie),\n" + 187 | "(reply_4)-[:TO]->(davina)"; 188 | 189 | return createFromCypher( 190 | "Email", 191 | cypher, 192 | IndexParam.indexParam( "User", "username" ), 193 | IndexParam.indexParam( "Email", "id" ) 194 | ); 195 | } 196 | 197 | private static GraphDatabaseService createDatabase3() 198 | { 199 | String cypher = "CREATE \n" + 200 | "(charlie:User {username:'Charlie'}),\n" + 201 | "(davina:User {username:'Davina'}),\n" + 202 | "(edward:User {username:'Edward'}),\n" + 203 | "(alice:User {username:'Alice'}),\n" + 204 | "(bob:User {username:'Bob'}),\n" + 205 | "(alice)-[:ALIAS_OF]->(bob),\n" + 206 | "\n" + 207 | "(email_11:Email {id: '11', content: 'email'}),\n" + 208 | " (alice)-[:SENT]->(email_11)-[:TO]->(bob),\n" + 209 | "\n" + 210 | "(email_12:Email {id: '12', content: 'email'}),\n" + 211 | " (email_12)-[:FORWARD_OF]->(email_11),\n" + 212 | " (bob)-[:SENT]->(email_12)-[:TO]->(charlie),\n" + 213 | "\n" + 214 | "(email_13:Email {id: '13', content: 'email'}),\n" + 215 | " (email_13)-[:FORWARD_OF]->(email_12),\n" + 216 | " (charlie)-[:SENT]->(email_13)-[:TO]->(davina)"; 217 | 218 | return createFromCypher( 219 | "Email", 220 | cypher, 221 | IndexParam.indexParam( "User", "username" ), 222 | IndexParam.indexParam( "Email", "id" ) 223 | ); 224 | } 225 | 226 | private static GraphDatabaseService createDatabase4() 227 | { 228 | String cypher = "CREATE (alice:User {username: 'Alice'}),\n" + 229 | "(bob:User {username: 'Bob'}),\n" + 230 | "(charlie:User {username: 'Charlie'}),\n" + 231 | "(davina:User {username: 'Davina'}),\n" + 232 | "(edward:User {username: 'Edward'}),\n" + 233 | "(alice)-[:ALIAS_OF]->(bob),\n" + 234 | "(bob)-[:EMAILED]->(charlie),\n" + 235 | "(bob)-[:CC]->(davina),\n" + 236 | "(bob)-[:BCC]->(edward)"; 237 | 238 | return createFromCypher( 239 | "Email", 240 | cypher, 241 | IndexParam.indexParam( "User", "username" ) 242 | ); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/SimpleSocialNetworkQueriesTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | import static org.neo4j.graphdatabases.queries.helpers.Db.createFromCypher; 7 | 8 | import org.junit.AfterClass; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | import org.neo4j.cypher.javacompat.ExecutionResult; 12 | import org.neo4j.graphdatabases.queries.testing.IndexParam; 13 | import org.neo4j.graphdb.GraphDatabaseService; 14 | 15 | public class SimpleSocialNetworkQueriesTest 16 | { 17 | private static GraphDatabaseService db; 18 | private static SimpleSocialNetworkQueries queries; 19 | 20 | @BeforeClass 21 | public static void init() 22 | { 23 | db = createDatabase(); 24 | queries = new SimpleSocialNetworkQueries( db ); 25 | } 26 | 27 | @AfterClass 28 | public static void shutdown() 29 | { 30 | db.shutdown(); 31 | } 32 | 33 | @Test 34 | public void shouldReturnShortestPathBetweenTwoFriends() throws Exception 35 | { 36 | // when 37 | ExecutionResult results = queries.pathBetweenTwoFriends( "Ben", "Mike" ); 38 | 39 | // then 40 | assertTrue( results.iterator().hasNext() ); 41 | assertEquals( 4, results.iterator().next().get( "depth" ) ); 42 | } 43 | 44 | @Test 45 | public void friendOfAFriendToDepth4() throws Exception 46 | { 47 | // when 48 | ExecutionResult results = queries.friendOfAFriendToDepth4( "Ben" ); 49 | 50 | // then 51 | assertTrue( results.iterator().hasNext() ); 52 | assertEquals( "Mike", results.iterator().next().get( "name" ) ); 53 | assertFalse( results.iterator().hasNext() ); 54 | } 55 | 56 | @Test 57 | public void shouldReturnNoResultsWhenThereIsNotAPathBetweenTwoFriends() throws Exception 58 | { 59 | // when 60 | ExecutionResult results = queries.pathBetweenTwoFriends( "Ben", "Arnold" ); 61 | 62 | // then 63 | assertFalse( results.iterator().hasNext() ); 64 | } 65 | 66 | private static GraphDatabaseService createDatabase() 67 | { 68 | String cypher = "CREATE\n" + 69 | "(ben:User {name:'Ben'}),\n" + 70 | "(arnold:User {name:'Arnold'}),\n" + 71 | "(charlie:User {name:'Charlie'}),\n" + 72 | "(gordon:User {name:'Gordon'}),\n" + 73 | "(lucy:User {name:'Lucy'}),\n" + 74 | "(emily:User {name:'Emily'}),\n" + 75 | "(sarah:User {name:'Sarah'}),\n" + 76 | "(kate:User {name:'Kate'}),\n" + 77 | "(mike:User {name:'Mike'}),\n" + 78 | "(paula:User {name:'Paula'}),\n" + 79 | "ben-[:FRIEND]->charlie,\n" + 80 | "charlie-[:FRIEND]->lucy,\n" + 81 | "lucy-[:FRIEND]->sarah,\n" + 82 | "sarah-[:FRIEND]->mike,\n" + 83 | "arnold-[:FRIEND]->gordon,\n" + 84 | "gordon-[:FRIEND]->emily,\n" + 85 | "emily-[:FRIEND]->kate,\n" + 86 | "kate-[:FRIEND]->paula"; 87 | 88 | return createFromCypher( 89 | "Simple Social Network", 90 | cypher, 91 | IndexParam.indexParam( "User", "name" ) ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/helpers/Db.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.neo4j.cypher.javacompat.ExecutionEngine; 10 | import org.neo4j.graphdatabases.queries.testing.IndexParam; 11 | import org.neo4j.graphdatabases.queries.testing.IndexParams; 12 | import org.neo4j.graphdb.GraphDatabaseService; 13 | import org.neo4j.graphdb.Node; 14 | import org.neo4j.graphdb.NotFoundException; 15 | import org.neo4j.graphdb.factory.GraphDatabaseFactory; 16 | import org.neo4j.graphdb.index.AutoIndexer; 17 | import org.neo4j.test.AsciiDocGenerator; 18 | import org.neo4j.test.TestGraphDatabaseFactory; 19 | import org.neo4j.visualization.asciidoc.AsciidocHelper; 20 | 21 | public final class Db 22 | { 23 | private Db() 24 | { 25 | } 26 | 27 | public static GraphDatabaseService impermanentDb() 28 | { 29 | Map params = new HashMap(); 30 | params.put( "online_backup_enabled", "false" ); 31 | 32 | return new TestGraphDatabaseFactory().newImpermanentDatabaseBuilder().setConfig( params ).newGraphDatabase(); 33 | } 34 | 35 | public static GraphDatabaseService tempDb() 36 | { 37 | return new GraphDatabaseFactory().newEmbeddedDatabase( createTempDatabaseDir().getAbsolutePath() ); 38 | } 39 | 40 | public static GraphDatabaseService createFromCypher( String name, String cypher, IndexParam... indexParams ) 41 | { 42 | GraphDatabaseService db = Db.impermanentDb(); 43 | 44 | return createFromCypher( db, name, cypher, indexParams ); 45 | } 46 | 47 | public static GraphDatabaseService createFromCypherWithAutoIndexing( String name, String cypher, 48 | IndexParam... indexParams ) 49 | { 50 | GraphDatabaseService db = Db.impermanentDb(); 51 | 52 | AutoIndexer nodeAutoIndexer = db.index().getNodeAutoIndexer(); 53 | for ( IndexParam indexParam : indexParams ) 54 | { 55 | nodeAutoIndexer.startAutoIndexingProperty( indexParam.propertyName() ); 56 | } 57 | nodeAutoIndexer.setEnabled( true ); 58 | 59 | return createFromCypher( db, name, cypher, indexParams ); 60 | } 61 | 62 | public static GraphDatabaseService createFromCypher( GraphDatabaseService db, String name, String cypher, 63 | IndexParam... indexParams ) 64 | { 65 | ExecutionEngine engine = new ExecutionEngine( db ); 66 | engine.execute( cypher ); 67 | 68 | new IndexParams( indexParams ).index( db); 69 | 70 | printGraph( name, db ); 71 | 72 | return db; 73 | } 74 | 75 | private static void printGraph( String name, GraphDatabaseService db ) 76 | { 77 | try 78 | { 79 | printFile( name, AsciidocHelper.createGraphVizDeletingReferenceNode( name, db, "graph" ) ); 80 | } 81 | catch ( NotFoundException e ) 82 | { 83 | printFile( name, AsciidocHelper.createGraphViz( name, db, "graph" ) ); 84 | } 85 | } 86 | 87 | private static void printFile( String fileName, String contents ) 88 | { 89 | PrintWriter writer = AsciiDocGenerator.getPrintWriter( "../examples/", fileName ); 90 | try 91 | { 92 | writer.println( contents ); 93 | } 94 | finally 95 | { 96 | writer.close(); 97 | } 98 | } 99 | 100 | private static File createTempDatabaseDir() 101 | { 102 | 103 | File d; 104 | try 105 | { 106 | d = File.createTempFile( "gdb-", "dir" ); 107 | System.out.println( String.format( "Created a new Neo4j database at [%s]", d.getAbsolutePath() ) ); 108 | } 109 | catch ( IOException e ) 110 | { 111 | throw new RuntimeException( e ); 112 | } 113 | if ( !d.delete() ) 114 | { 115 | throw new RuntimeException( "temp config directory pre-delete failed" ); 116 | } 117 | if ( !d.mkdirs() ) 118 | { 119 | throw new RuntimeException( "temp config directory not created" ); 120 | } 121 | d.deleteOnExit(); 122 | return d; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/helpers/IndexNodeByOtherNodeIndexerTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.neo4j.graphdatabases.queries.helpers.Db.createFromCypher; 5 | import static org.neo4j.graphdb.DynamicRelationshipType.withName; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import org.junit.Ignore; 11 | import org.junit.Test; 12 | import org.neo4j.cypher.javacompat.ExecutionEngine; 13 | import org.neo4j.cypher.javacompat.ExecutionResult; 14 | import org.neo4j.graphdatabases.queries.testing.IndexParam; 15 | import org.neo4j.graphdb.*; 16 | import org.neo4j.graphdb.traversal.Evaluation; 17 | import org.neo4j.graphdb.traversal.Evaluator; 18 | import org.neo4j.graphdb.traversal.TraversalDescription; 19 | import org.neo4j.kernel.Traversal; 20 | import org.neo4j.tooling.GlobalGraphOperations; 21 | 22 | public class IndexNodeByOtherNodeIndexerTest 23 | { 24 | @Test 25 | @Ignore("Doesn't work like that, the code used to index multiple children under one parent, not possible with the new indexes") 26 | public void shouldIndexNodesByOtherNodes() throws Exception 27 | { 28 | // given 29 | String cypher = "CREATE (a:Parent {name:'a'}), \n" + 30 | "(b:Child {name:'b'}), \n" + 31 | "(c:Child {name:'c'}), \n" + 32 | "(d:Child {name:'d'}), \n" + 33 | "(e:Child {name:'e'}), \n" + 34 | "(f:Child {name:'f'}),\n" + 35 | "(g:Child {name:'g'}),\n" + 36 | "(h:Child {name:'h'}),\n" + 37 | "a-[:CONNECTED_TO]->b,\n" + 38 | "a-[:CONNECTED_TO]->c,\n" + 39 | "a-[:CONNECTED_TO]->g,\n" + 40 | "d-[:CONNECTED_TO]->e,\n" + 41 | "d-[:CONNECTED_TO]->f,\n" + 42 | "d-[:CONNECTED_TO]->h"; 43 | 44 | final GraphDatabaseService db = createFromCypher( 45 | "Example", 46 | cypher, 47 | IndexParam.indexParam( "Parent", "name" ) ); 48 | ExecutionEngine executionEngine = new ExecutionEngine(db); 49 | 50 | IndexNodeByOtherNodeIndexer.GraphTraversal traversal1 = new IndexNodeByOtherNodeIndexer.GraphTraversal(){ 51 | @Override 52 | public Iterable execute( Node startNode ) 53 | { 54 | return GlobalGraphOperations.at(db).getAllNodesWithLabel(DynamicLabel.label("Parent")); 55 | } 56 | }; 57 | 58 | IndexNodeByOtherNodeIndexer.GraphTraversal traversal2 = new IndexNodeByOtherNodeIndexer.GraphTraversal(){ 59 | @Override 60 | public Iterable execute( Node startNode ) 61 | { 62 | TraversalDescription traversalDescription = db.traversalDescription().breadthFirst().relationships( 63 | withName( "CONNECTED_TO" ), Direction.OUTGOING ).evaluator( new Evaluator() 64 | { 65 | @Override 66 | public Evaluation evaluate( Path path ) 67 | { 68 | if ( path.endNode().equals( path.startNode() ) ) 69 | { 70 | return Evaluation.EXCLUDE_AND_CONTINUE; 71 | } 72 | return Evaluation.INCLUDE_AND_CONTINUE; 73 | } 74 | } ); 75 | return traversalDescription.traverse( startNode ).nodes(); 76 | } 77 | }; 78 | 79 | IndexNodeByOtherNodeIndexer indexer = new IndexNodeByOtherNodeIndexer( traversal1, traversal2, "Parent", "child", "name" ); 80 | 81 | // when 82 | indexer.execute( db, null, 2 ); 83 | 84 | // then 85 | Map indexValueToResult = new HashMap<>( ); 86 | indexValueToResult.put( "b", "a" ); 87 | indexValueToResult.put( "c", "a" ); 88 | indexValueToResult.put( "g", "a" ); 89 | indexValueToResult.put( "e", "d" ); 90 | indexValueToResult.put( "f", "d" ); 91 | indexValueToResult.put( "h", "d" ); 92 | 93 | for ( String indexValue : indexValueToResult.keySet() ) 94 | { 95 | String query = "MATCH (n:Parent {child:'"+indexValue+"'}) RETURN n.name AS parent"; 96 | 97 | ExecutionResult result = executionEngine.execute(query); 98 | assertEquals(indexValueToResult.get( indexValue ), result.iterator().next().get( "parent" )); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/helpers/PrintingExecutionEngineWrapper.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.helpers; 2 | 3 | import java.io.PrintWriter; 4 | import java.util.Map; 5 | 6 | import org.junit.rules.TestName; 7 | import org.neo4j.cypher.javacompat.ExecutionEngine; 8 | import org.neo4j.cypher.javacompat.ExecutionResult; 9 | import org.neo4j.graphdb.GraphDatabaseService; 10 | import org.neo4j.test.AsciiDocGenerator; 11 | 12 | public class PrintingExecutionEngineWrapper implements ExecutionEngineWrapper 13 | { 14 | private final ExecutionEngine executionEngine; 15 | private final String useCase; 16 | private final TestName testName; 17 | 18 | public PrintingExecutionEngineWrapper( GraphDatabaseService db, String useCase, TestName testName ) 19 | { 20 | this.useCase = useCase; 21 | this.executionEngine = new ExecutionEngine( db ); 22 | this.testName = testName; 23 | } 24 | 25 | @Override 26 | public ExecutionResult execute( String query, Map params ) 27 | { 28 | return execute( query, params, 1 ); 29 | } 30 | 31 | @Override 32 | public ExecutionResult execute( String query, Map params, int index ) 33 | { 34 | printQuery( query, index ); 35 | ExecutionResult returnResult = executionEngine.execute( query, params ); 36 | // For CREATE queries, this may not return the same results 37 | ExecutionResult printResult = executionEngine.execute( query, params ); 38 | printResult( printResult, index ); 39 | return returnResult; 40 | } 41 | 42 | private void printResult( org.neo4j.cypher.javacompat.ExecutionResult results, int index ) 43 | { 44 | String output = "[queryresult]\n----\n" + results.dumpToString() 45 | + "\n----\n"; 46 | printFile( useCase + "-" + testName.getMethodName() + "-result-" + index, output ); 47 | } 48 | 49 | private void printQuery( String query, int index ) 50 | { 51 | String output = "----\n" + query + "\n----\n"; 52 | printFile( useCase + "-" + testName.getMethodName() + "-query-" + index, output ); 53 | } 54 | 55 | private static void printFile( String fileName, String contents ) 56 | { 57 | try (PrintWriter writer = AsciiDocGenerator.getPrintWriter("../examples", fileName)) { 58 | writer.println(contents); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /queries/src/test/java/org/neo4j/graphdatabases/queries/server/SimpleSocialNetworkExtensionTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.graphdatabases.queries.server; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.neo4j.graphdatabases.queries.helpers.Db.createFromCypher; 5 | 6 | import java.io.IOException; 7 | 8 | import javax.ws.rs.core.MediaType; 9 | 10 | import com.sun.jersey.api.client.Client; 11 | import com.sun.jersey.api.client.ClientResponse; 12 | import com.sun.jersey.api.client.WebResource; 13 | import com.sun.jersey.api.client.config.ClientConfig; 14 | import com.sun.jersey.api.client.config.DefaultClientConfig; 15 | import org.junit.AfterClass; 16 | import org.junit.BeforeClass; 17 | import org.junit.Test; 18 | import org.neo4j.graphdatabases.queries.testing.IndexParam; 19 | import org.neo4j.graphdb.GraphDatabaseService; 20 | import org.neo4j.server.CommunityNeoServer; 21 | import org.neo4j.server.helpers.CommunityServerBuilder; 22 | 23 | public class SimpleSocialNetworkExtensionTest 24 | { 25 | private static CommunityNeoServer server; 26 | private static GraphDatabaseService db; 27 | 28 | @BeforeClass 29 | public static void init() throws IOException 30 | { 31 | server = CommunityServerBuilder.server() 32 | .withThirdPartyJaxRsPackage( 33 | "org.neo4j.graphdatabases.queries.server", 34 | "/socnet" ) 35 | .build(); 36 | server.start(); 37 | 38 | db = server.getDatabase().getGraph(); 39 | populateDatabase( db ); 40 | } 41 | 42 | @AfterClass 43 | public static void teardown() 44 | { 45 | server.stop(); 46 | } 47 | 48 | @Test 49 | public void serverShouldReturnDistance() throws Exception 50 | { 51 | ClientConfig config = new DefaultClientConfig(); 52 | Client client = Client.create( config ); 53 | 54 | WebResource resource = client 55 | .resource( "http://localhost:7474/socnet/distance/Ben/Mike" ); 56 | ClientResponse response = resource 57 | .accept( MediaType.TEXT_PLAIN ) 58 | .get( ClientResponse.class ); 59 | 60 | assertEquals( 200, response.getStatus() ); 61 | assertEquals( "text/plain", 62 | response.getHeaders().get( "Content-Type" ).get( 0 ) ); 63 | assertEquals( "4", response.getEntity( String.class ) ); 64 | } 65 | 66 | @Test 67 | public void extensionShouldReturnDistance() throws Exception 68 | { 69 | // given 70 | SimpleSocialNetworkExtension extension = new SimpleSocialNetworkExtension( db ); 71 | 72 | // when 73 | String distance = extension.getDistance( "Ben", "Mike" ); 74 | 75 | // then 76 | assertEquals( "4", distance ); 77 | } 78 | 79 | private static GraphDatabaseService populateDatabase( GraphDatabaseService db ) 80 | { 81 | String cypher = "CREATE\n" + 82 | "(ben:User {name:'Ben'}),\n" + 83 | "(arnold:User {name:'Arnold'}),\n" + 84 | "(charlie:User {name:'Charlie'}),\n" + 85 | "(gordon:User {name:'Gordon'}),\n" + 86 | "(lucy:User {name:'Lucy'}),\n" + 87 | "(emily:User {name:'Emily'}),\n" + 88 | "(sarah:User {name:'Sarah'}),\n" + 89 | "(kate:User {name:'Kate'}),\n" + 90 | "(mike:User {name:'Mike'}),\n" + 91 | "(paula:User {name:'Paula'}),\n" + 92 | "ben-[:FRIEND]->charlie,\n" + 93 | "charlie-[:FRIEND]->lucy,\n" + 94 | "lucy-[:FRIEND]->sarah,\n" + 95 | "sarah-[:FRIEND]->mike,\n" + 96 | "arnold-[:FRIEND]->gordon,\n" + 97 | "gordon-[:FRIEND]->emily,\n" + 98 | "emily-[:FRIEND]->kate,\n" + 99 | "kate-[:FRIEND]->paula"; 100 | 101 | return createFromCypher( db, 102 | "Simple Social Network", 103 | cypher, 104 | IndexParam.indexParam( "User", "name" ) ); 105 | } 106 | } 107 | --------------------------------------------------------------------------------