Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Performance Issue] Generic relationship does not honor type when query #2941

Open
abccbaandy opened this issue Aug 20, 2024 · 3 comments
Open
Labels
status: waiting-for-triage An issue we've not yet triaged

Comments

@abccbaandy
Copy link

abccbaandy commented Aug 20, 2024

I have some node

@Data
@Node
public abstract class BaseNode {
    @Id
    @GeneratedValue
    private UUID id;
}

@EqualsAndHashCode(callSuper = true)
@Node
@Data
public class Child extends BaseNode{
}

@EqualsAndHashCode(callSuper = true)
@Node
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(callSuper = true)
public class Parent1 extends BaseNode{
    @Relationship(type = "Parent1_CONTAIN", direction = Relationship.Direction.OUTGOING)
    private List<BaseRelationship<BaseNode>> parent1Relationships;
}

@EqualsAndHashCode(callSuper = true)
@Node
@Data
@NoArgsConstructor
@ToString(callSuper = true)
public class Parent2 extends BaseNode {
    @Relationship(type = "Parent2_CONTAIN", direction = Relationship.Direction.OUTGOING)
    private List<BaseRelationship<BaseNode>> parent2Relationships;
}

When I get parent1 with find all:

        List<Parent1> all = parent1Repository.findAll();

The log shows

MATCH (parent1:`Parent1`:`BaseNode`) WITH collect(elementId(parent1)) AS __sn__ RETURN __sn__
MATCH (parent1:`Parent1`:`BaseNode`) OPTIONAL MATCH (parent1)-[__sr__:`Parent1_CONTAIN`]->(__srn__:`BaseNode`) WITH collect(elementId(parent1)) AS __sn__, collect(elementId(__srn__)) AS __srn__, collect(elementId(__sr__)) AS __sr__ RETURN __sn__, __srn__, __sr__
MATCH (baseNode:`BaseNode`) WHERE elementId(baseNode) IN $__ids__ OPTIONAL MATCH (baseNode)-[__sr__:`Parent2_CONTAIN`]->(__srn__:`BaseNode`) WITH collect(elementId(baseNode)) AS __sn__, collect(elementId(__srn__)) AS __srn__, collect(elementId(__sr__)) AS __sr__ RETURN __sn__, __srn__, __sr__
MATCH (baseNode:`BaseNode`) WHERE elementId(baseNode) IN $__ids__ OPTIONAL MATCH (baseNode)-[__sr__:`Parent1_CONTAIN`]->(__srn__:`BaseNode`) WITH collect(elementId(baseNode)) AS __sn__, collect(elementId(__srn__)) AS __srn__, collect(elementId(__sr__)) AS __sr__ RETURN __sn__, __srn__, __sr__
MATCH (rootNodeIds:`Parent1`) WHERE elementId(rootNodeIds) IN $rootNodeIds WITH collect(rootNodeIds) AS n OPTIONAL MATCH ()-[relationshipIds]-() WHERE elementId(relationshipIds) IN $relationshipIds WITH n, collect(DISTINCT relationshipIds) AS __sr__ OPTIONAL MATCH (relatedNodeIds) WHERE elementId(relatedNodeIds) IN $relatedNodeIds WITH n, __sr__ AS __sr__, collect(DISTINCT relatedNodeIds) AS __srn__ UNWIND n AS rootNodeIds WITH rootNodeIds AS parent1, __sr__, __srn__ RETURN parent1 AS __sn__, __sr__, __srn__

In the query log, shows it search for Parent2_CONTAIN but it shouldn't, because Parent2_CONTAIN is not in Parent1 node.
In real case, if I have 10 node extends the base node, it will end up query all 10 node's relationship, I think it is a performance issue.

Change to Child still have this issue

    @Relationship(type = "Parent1_CONTAIN", direction = Relationship.Direction.OUTGOING)
    private List<BaseRelationship<Child>> parent1Relationships;

Also, I think this issue is associate
#2933

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 20, 2024
@abccbaandy abccbaandy changed the title Generic relationship does not honor type when query [Performance Issue] Generic relationship does not honor type when query Aug 20, 2024
@meistermeier
Copy link
Collaborator

The person1Repository will query for :Parent1_CONTAIN nodes defined by parent1Relationships in Parent1.
Those relationships are of type BaseNode. The next iteration will than query for :Parent2_CONTAIN and :Parent1_CONTAIN defined in Parent2 and Parent1 as the implementations of BaseNode.
This behaviour is expected.

Looking at the other issue and the Child typed relationship, the same behaviour applies because the type definition is derived from the class public class BaseDbRelationship<T extends BaseNode> itself which is again "just" a BaseNode.

@abccbaandy
Copy link
Author

abccbaandy commented Aug 21, 2024

The person1Repository will query for :Parent1_CONTAIN nodes defined by parent1Relationships in Parent1. Those relationships are of type BaseNode. The next iteration will than query for :Parent2_CONTAIN and :Parent1_CONTAIN defined in Parent2 and Parent1 as the implementations of BaseNode. This behaviour is expected.

Looking at the other issue and the Child typed relationship, the same behaviour applies because the type definition is derived from the class public class BaseDbRelationship<T extends BaseNode> itself which is again "just" a BaseNode.

I can guess this behavior, but I think the design is wrong.
When I query parent1, SDN should search for Parent1_CONTAIN relationship only.

But I think the root cause is SDN treat the BaseNode as a Node.
In my domain, I don't really use the BaseNode, it just a base class for share common field and polymorphism.
In real case, I have many childes with same relationship type:

(:Parent1)-[r:Parent1_CONTAIN]->(:Child1)
(:Parent1)-[r:Parent1_CONTAIN]->(:Child2)

So, I have to use a base class to get all of them.

    @Relationship(type = "Parent1_CONTAIN", direction = Relationship.Direction.OUTGOING)
    private List<BaseRelationship<BaseNode>> parent1Relationships;

@meistermeier Is there any other way to achieve this requirement without base class issue?

@abccbaandy
Copy link
Author

Any update?
@michael-simons

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

3 participants