Skip to content

Issue with graph depth #2659

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

Closed
Deimrus opened this issue Jan 18, 2023 · 6 comments
Closed

Issue with graph depth #2659

Deimrus opened this issue Jan 18, 2023 · 6 comments
Assignees
Labels
status: waiting-for-feedback We need additional information before we can continue

Comments

@Deimrus
Copy link

Deimrus commented Jan 18, 2023

Hey all.
I have a simple structure:
image
Cypher query in Browser works as expected but the same query in @query directive within Neo4jRepository returns just one random underlying node of label ObjectType so instead of getting one Company with two Sites with two ObjectTypes for each Site I got just one ObjectType:
image

Neo4jClient returns all the data I need btw.

Is this a bug or I do something wrong?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 18, 2023
@Deimrus
Copy link
Author

Deimrus commented Jan 18, 2023

Screenshots made on Spring Boot version 3.0.1 and related version of spring-boot-starter-data-neo4j. Also checked it on 2.7.* and 2.6.* with the same results.

@meistermeier meistermeier self-assigned this Jan 19, 2023
@meistermeier
Copy link
Collaborator

To investigate this, I would need the domain model for the three classes in question.
It should work with repositories. The Neo4jClient presents the correct data because it does not inspect the mappings but returns the values from the database before mapping.

@meistermeier meistermeier added blocked: awaiting feedback status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 19, 2023
@Deimrus
Copy link
Author

Deimrus commented Jan 19, 2023

@Node
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company {
    @Id @GeneratedValue
    private Long id;
    private String name;
    @Relationship(type = "IS_IN", direction = Relationship.Direction.INCOMING)
    private Set<Site> sites = new HashSet<>();
}
@Node
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Site {
    @Id @GeneratedValue
    private Long id;
    private Integer name;
    @Relationship(type = "IS_IN", direction = Relationship.Direction.INCOMING)
    private Set<ObjectType> types = new HashSet<>();
}
@Node
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ObjectType {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jan 19, 2023
@Deimrus
Copy link
Author

Deimrus commented Jan 19, 2023

Also List<Company> findAll(); method without @query returns all the data as expected but with warnings:

MATCH (company:`Company`) RETURN company{.id, .name, __nodeLabels__: labels(company), __internalNeo4jId__: id(company), __elementId__: toString(id(company)), Company_IS_IN_Site: [(company)<-[:`IS_IN`]-(company_sites:`Site`) | company_sites{.id, .name, __nodeLabels__: labels(company_sites), __internalNeo4jId__: id(company_sites), __elementId__: toString(id(company_sites)), Site_IS_IN_ObjectType: [(company_sites)<-[:`IS_IN`]-(company_sites_types:`ObjectType`) | company_sites_types{.id, .name, __nodeLabels__: labels(company_sites_types), __internalNeo4jId__: id(company_sites_types), __elementId__: toString(id(company_sites_types))}]}]}
  WARN 22120 --- [nio-8080-exec-1] org.springframework.data.neo4j.cypher    : Neo.ClientNotification.Statement.UnknownPropertyKeyWarning: The provided property key is not in the database
	MATCH (company:`Company`) RETURN company{.id, .name, __nodeLabels__: labels(company), __internalNeo4jId__: id(company), __elementId__: toString(id(company)), Company_IS_IN_Site: [(company)<-[:`IS_IN`]-(company_sites:`Site`) | company_sites{.id, .name, __nodeLabels__: labels(company_sites), __internalNeo4jId__: id(company_sites), __elementId__: toString(id(company_sites)), Site_IS_IN_ObjectType: [(company_sites)<-[:`IS_IN`]-(company_sites_types:`ObjectType`) | company_sites_types{.id, .name, __nodeLabels__: labels(company_sites_types), __internalNeo4jId__: id(company_sites_types), __elementId__: toString(id(company_sites_types))}]}]}
	                                          ^
One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: id)
  WARN 22120 --- [nio-8080-exec-1] org.springframework.data.neo4j.cypher    : Neo.ClientNotification.Statement.UnknownPropertyKeyWarning: The provided property key is not in the database
	MATCH (company:`Company`) RETURN company{.id, .name, __nodeLabels__: labels(company), __internalNeo4jId__: id(company), __elementId__: toString(id(company)), Company_IS_IN_Site: [(company)<-[:`IS_IN`]-(company_sites:`Site`) | company_sites{.id, .name, __nodeLabels__: labels(company_sites), __internalNeo4jId__: id(company_sites), __elementId__: toString(id(company_sites)), Site_IS_IN_ObjectType: [(company_sites)<-[:`IS_IN`]-(company_sites_types:`ObjectType`) | company_sites_types{.id, .name, __nodeLabels__: labels(company_sites_types), __internalNeo4jId__: id(company_sites_types), __elementId__: toString(id(company_sites_types))}]}]}
	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     ^
One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: id)
  WARN 22120 --- [nio-8080-exec-1] org.springframework.data.neo4j.cypher    : Neo.ClientNotification.Statement.UnknownPropertyKeyWarning: The provided property key is not in the database
	MATCH (company:`Company`) RETURN company{.id, .name, __nodeLabels__: labels(company), __internalNeo4jId__: id(company), __elementId__: toString(id(company)), Company_IS_IN_Site: [(company)<-[:`IS_IN`]-(company_sites:`Site`) | company_sites{.id, .name, __nodeLabels__: labels(company_sites), __internalNeo4jId__: id(company_sites), __elementId__: toString(id(company_sites)), Site_IS_IN_ObjectType: [(company_sites)<-[:`IS_IN`]-(company_sites_types:`ObjectType`) | company_sites_types{.id, .name, __nodeLabels__: labels(company_sites_types), __internalNeo4jId__: id(company_sites_types), __elementId__: toString(id(company_sites_types))}]}]}
	                                                                                                                                                                                                                                                 ^
One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: id)

@meistermeier
Copy link
Collaborator

The custom query will return multiple records not just "one path". Every branch will create an entry.
But since SDN uses a record-centric mapping to insure e.g. immutable mapping and reactive streaming, you need to aggregate the result on the database side.
Even though it looks a little bit complex, this is exactly what you want to have:

MATCH res = (c:Company)<--(:Site)--()
 WITH collect(res) as paths, c
 WITH c,
 reduce(a=[], node in reduce(b=[], c in [aa in paths | nodes(aa)] | b + c) | case when node in a then a else a + node end) as nodes,
 reduce(d=[], relationship in reduce(e=[], f in [dd in paths | relationships(dd)] | e + f) | case when relationship in d then d else d + relationship end) as relationships
 RETURN c, relationships, nodes;

It reduces all nodes and relationships into a single record to be returned.
More about this here:
https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#custom-queries.for-relationships.long-paths.database

For the warning, I just commented here how to mitigate this in your application config: #2660 (comment)

@meistermeier meistermeier added status: waiting-for-feedback We need additional information before we can continue and removed blocked: awaiting feedback status: feedback-provided Feedback has been provided labels Jan 19, 2023
@Deimrus
Copy link
Author

Deimrus commented Jan 19, 2023

Yep, result tree as it should be. I think I got the point.

Thank you for help.

@Deimrus Deimrus closed this as completed Jan 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-feedback We need additional information before we can continue
Projects
None yet
Development

No branches or pull requests

3 participants