2

In My Neo4j 3.0.3 Spring Data Neo4j 4.2.0.SNAPSHOT project I have a following entities:

@NodeEntity
public abstract class BaseEntity {

    @GraphId
    private Long id;

    private Date createDate;

    private Date updateDate;

...
}

@NodeEntity
public class Decision extends BaseEntity {

    private final static String CONTAINS = "CONTAINS";
    private final static String DEFINED_BY = "DEFINED_BY";

    private String name;

    @Relationship(type = CONTAINS, direction = Relationship.INCOMING)
    private Set<Decision> parentDecisions = new HashSet<>();

    @Relationship(type = CONTAINS, direction = Relationship.OUTGOING)
    private Set<Decision> childDecisions = new HashSet<>();

    @Relationship(type = DEFINED_BY, direction = Relationship.INCOMING)
    private Set<CriterionGroup> criterionGroups = new HashSet<>();

    @Relationship(type = DEFINED_BY, direction = Relationship.INCOMING)
    private Set<Criterion> criteria = new HashSet<>();

...
}

@NodeEntity
public class Criterion extends BaseEntity {

    private final static String CONTAINS = "CONTAINS";
    private final static String DEFINED_BY = "DEFINED_BY";

    private String name;

    @Relationship(type = CONTAINS, direction = Relationship.INCOMING)
    private CriterionGroup group;

    @Relationship(type = DEFINED_BY, direction = Relationship.OUTGOING)
    private Decision owner;

...
}

@NodeEntity
public class Vote extends Authorable {

    private final static String CONTAINS = "CONTAINS";

    @Relationship(type = CONTAINS, direction = Relationship.INCOMING)
    private VoteGroup group;

    private double weight;

    private String description;

...
}

@NodeEntity
public class VoteGroup extends BaseEntity {

    private static final String VOTED_ON = "VOTED_ON";
    private final static String VOTED_FOR = "VOTED_FOR";
    private final static String CONTAINS = "CONTAINS";

    @Relationship(type = VOTED_FOR, direction = Relationship.OUTGOING)
    private Decision decision;

    @Relationship(type = VOTED_ON, direction = Relationship.OUTGOING)
    private Criterion criterion;

    @Relationship(type = CONTAINS, direction = Relationship.OUTGOING)
    private Set<Vote> votes = new HashSet<>();

    private double avgVotesWeight;

    private long totalVotesCount;

...
}

I have a test method that creates a test nodes in Embeded Ne04j Database. Right now after porting my code from Neo4j 2x to 3x and SDN3x to SDN4x I see a noticeable performance degradation during these nodes creation.

I'm more than sure this is related to some issues in my implementation and not to technology itself so I'd like to ask to help me find the reasons of a slow performance.

For example I have a following method:

@Override
public Vote createVote(Decision decision, Criterion criterion, User author, String description, double weight) {
    VoteGroup voteGroup = getVoteGroupForDecisionOnCriterion(decision.getId(), criterion.getId());
    if (voteGroup == null) {
        voteGroup = new VoteGroup(decision, criterion, weight, 1);
    } else {
        long newTotalVotesCount = voteGroup.getTotalVotesCount() + 1;
        double newAvgVotesWeight = (voteGroup.getAvgVotesWeight() * voteGroup.getTotalVotesCount() + weight) / newTotalVotesCount;
        voteGroup.setAvgVotesWeight(newAvgVotesWeight);
        voteGroup.setTotalVotesCount(newTotalVotesCount);
    }

    return voteRepository.save(new Vote(voteGroup, author, weight, description));
}

constructors:

public VoteGroup(Decision decision, Criterion criterion, double avgVotesWeight, long totalVotesCount) {
    this.decision = decision;
    this.criterion = criterion;
    this.avgVotesWeight = avgVotesWeight;
    this.totalVotesCount = totalVotesCount;
}

public Vote(VoteGroup group, User author, double weight, String description) {
    this.group = group;
    group.addVote(this);
    setAuthor(author);
    this.weight = weight;
    this.description = description;
}

and repository method:

@Query("MATCH (d:Decision)<-[:VOTED_FOR]-(vg:VoteGroup)-[:VOTED_ON]->(c:Criterion) WHERE id(d) = {decisionId} AND id(c) = {criterionId} RETURN vg")
VoteGroup getVoteGroupForDecisionOnCriterion(@Param("decisionId") Long decisionId, @Param("criterionId") Long criterionId);

Right now the performance of createVote method significantly degrades with a growth of amount of nodes.

The same code on Neo4j 2x and SDN3 worked much more faster. What can be wrong and how to fix the issue with performance?

UPDATED

This is profiler information:

enter image description here

Looks like methods:

CypherContext.deregisterOutgoingRelationships()
CypherContext.deregisterIncomingRelationships()

Right now I have 22397 total nodes at database:

845 Decisions 
2274 Criterion 
9387 Vote 
9387 VoteGroup

voteDao.createVote method executes 4194 - 8194 ms.

For example on a very small database it starts working with a following time:

getVoteGroupForDecisionOnCriterion  - 0-1ms
voteRepository.save - 9ms

and with a database growth getVoteGroupForDecisionOnCriterion works with a stable 0-1ms but performance of voteRepository.save very quickly significantly degrades.

So, looks like the bottleneck is voteRepository.save method.

This is my Neo4jConfig:

@Configuration
@EnableNeo4jRepositories(basePackages = "com.example")
@EnableTransactionManagement
public class Neo4jConfig extends Neo4jConfiguration {

    @Override
    public SessionFactory getSessionFactory() {
        return new SessionFactory("com.example");
    }

}

ogm.properties:

driver=org.neo4j.ogm.drivers.bolt.driver.BoltDriver
URI=bolt://neo4j:password@localhost

What can be wrong and how to fix it ?

alexanoid
  • 24,051
  • 54
  • 210
  • 410

0 Answers0