we are evaluating in our company the possibilities with neo4j, we are using Java (>1.8), Spring Boot (2.4.2) and SpringData-neo4j (2.4.2) to make simple queries and some performance tests, neo4j is running locally in a docker container using the official docker image.
This is our setup:
the json structure
{
"id": null,
"addresses": [
{
"id": null,
"city": "South Thresa",
"country": "Burundi",
"houseNumber": "861",
"street": "Auer Lake",
"zipCode": "03412"
}
],
"bankAccounts": [
{
"id": null,
"bankAccountNumber": null,
"bankName": null,
"bic": "QVWPKO5H",
"blz": null,
"countryCode": null,
"divergentAccountHolder": null,
"iban": "GB87DPZP84667918216002",
"sepaMandates": [
{
"id": null,
"bankAccount": null,
"signatureCity": "Lednerbury",
"signatureDate": "06.10.1984"
}
]
}
],
"contacts": [
{
"id": null,
"email": "[email protected]",
"faxNumber": "087-835-0885 x859",
"mobilePhoneNumber": "1-615-772-6922",
"phoneNumber": "(082) 785-8108 x6736"
}
],
"birthDate": "07.01.1966",
"firstName": "Daniel",
"lastName": "Hartmann",
"salutation": "Mrs.",
"title": "Lead Branding Orchestrator"
}
Entities:
@Node
public class Partner {
@Id
@GeneratedValue
public Long id;
@Relationship(type = "ADDRESS", direction = Relationship.Direction.INCOMING)
public List<Address> addresses;
@Relationship(type = "BANKACCOUNT", direction = Relationship.Direction.INCOMING)
public List<BankAccount> bankAccounts;
@Relationship(type = "CONTACTS", direction = Relationship.Direction.INCOMING)
public List<Contact> contacts;
@Property
public String birthDate;
@Property
public String firstName;
@Property
public String lastName;
@Property
public String salutation;
@Property
public String title;
}
@Node
public class Contact{
@Id
@GeneratedValue
public Long id;
@Property
public String email;
@Property
public String faxNumber;
@Property
public String mobilePhoneNumber;
@Property
public String phoneNumber;
@Node
public class BankAccount{
@Id
@GeneratedValue
public Long id;
@Property
public String bankAccountNumber;
@Property
public String bankName;
@Property
public String bic;
@Property
public String blz;
@Property
public String countryCode;
@Property
public String divergentAccountHolder;
@Property
public String iban;
@Relationship(type = "SEPA_MANDAT")
public List<SepaMandate> sepaMandates;
@Node
public class Address{
@Id
@GeneratedValue
public Long id;
@Property
public String city;
@Property
public String country;
@Property
public String houseNumber;
@Property
public String street;
@Property
public String zipCode;
@Node
public class SepaMandate{
@Id
@GeneratedValue
public Long id;
@Property
public BankAccount bankAccount;
@Property
public String signatureCity;
@Property
public String signatureDate;
Repository:
public interface PartnerRepository extends Neo4jRepository<Partner, Long> {
List<Partner> findByLastName(String name);
}
The controller has a endpoint to trigger a massinsert and stops the time
@PutMapping("/partner/initialInsert")
public void createPartner() {
List<Partner> partners = mockData();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
partnerRepository.saveAll(partners);
stopWatch.stop();
System.err.println("Created: 100000 partnerEntries ---->>> Duration ------------> " + stopWatch.toString());
}
And some simple query/update and insert endpoints
@GetMapping("/partner")
public List<Partner> getPartnerByLastName(@RequestParam(value = "lastname") String lastname) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
List<Partner> partners = partnerRepository.findByLastName(lastname);
stopWatch.stop();
System.err.println("Selecting partners by lastname: " +lastname + " took: " + stopWatch.toString() + " and returns: " + partners.size() + " partners");
return partners;
}
@PutMapping("/partner")
public void createPartner(@RequestBody Partner partner) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
partnerRepository.save(partner);
stopWatch.stop();
System.err.println("Updating/Inserting partner took: " + stopWatch.toString());
}
@PostMapping("/partner/bulk")
public void bulkUpdatePartner(@RequestBody List<Partner> partners) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
partnerRepository.saveAll(partners);
stopWatch.stop();
System.err.println("Updating/Inserting partner took: " + stopWatch.toString());
}
Here are our test results:
Inserting random data using which inserts via bulk saveAll().
- Created: 1000 partnerEntries ---->>> Duration ------> 00:00:29.775
- Created: 10000 partnerEntries ---->>> Duration ------> 00:04:40.259
- Created: 100000 partnerEntries ---->>> Duration ------> 00:53:48.862
Selecting data via lastname severals times
- Selecting partners by lastname: Borer took: 00:00:00.404 and returns: 257 partners
- Selecting partners by lastname: Borer took: 00:00:00.219 and returns: 257 partners
- Selecting partners by lastname: Borer took: 00:00:00.173 and returns: 257 partners
- Selecting partners by lastname: Borer took: 00:00:00.239 and returns: 257 partners
- Selecting partners by lastname: Borer took: 00:00:00.194 and returns: 257 partners
- Selecting partners by lastname: Borer took: 00:00:00.266 and returns: 257 partners
Updating/Inserting a single entry:
- Updating partner took: 00:00:00.297
- Inserting partner took: 00:00:00.124
Update bulk 256 partners using jpa:
- Updating partner took: 00:00:08.931
Update bulk 256 partner using Session-Object without jpa:
- Updating partner took: 00:00:00.090
We are really curious about that the mass-insert with the jpa function saveAll() is taking > 50min for inserting 100.000 objects and difference between updating 256 entries via jpa and the session-Object.
Now the question, are we doing something wrong, we tried to use a simple setup without any specialcases, is there a problem with the spring-data integration or do you guys have simular problems? I'm looking forward to here your experiences with neo4j :-)
Greets Dan :)
P.S: this is how we update with the session object
try (Session session = driver.session()) {
session.run("MATCH (a:Partner {lastName: 'Borer'}) SET a.firstName = '" + firstname + "'");
}
question from:
https://stackoverflow.com/questions/65903344/spring-boot-neo4j-performance