我目前正在开始使用 Neo4j,我想创建一个基本的社交媒体(例如应用程序)来了解更多信息。
我正在使用 spring data neo4j 将我的 Spring Boot 后端与 Neo4j 连接。
我的应用程序非常简单,它只是让一个用户关注另一个用户。
使用 Cypher 查询,一切都非常简单。但我不想显式地编写任何查询并使用存储库来获取我想要的数据。
这是我的用户类
@Node
public class User {
@Id
private Long id;
private String name;
@Relationship(type="FOLLOWS", direction = Relationship.Direction.INCOMING)
private HashSet<User> followsReceived = new HashSet<>();
@Relationship(type="FOLLOWS", direction = Relationship.Direction.OUTGOING)
private HashSet<User> followsGiven = new HashSet<>();
}
这是我的关注课程
@RelationshipProperties
public class Follow {
@Id @GeneratedValue
private Long id;
@TargetNode
private User endNode;
}
这个设计有意义吗?
我现在有点困惑,因为例如,如果我想找到特定用户关注的用户,我会得到一个递归结构,尽管实现了分页,但它几乎加载了整个数据库。
有人可以建议我一个更简洁的设计,其中让我关注的用户和关注我的用户不会加载整个数据库。
如果可能的话,我想在没有@Query注释的情况下实现它。
首先,不需要
@RelationshipProeprties
类,也不需要在您的示例中使用。您必须将其作为泛型类型放入 User's
关系定义中。但由于您没有向其中添加任何属性,因此您可能 (*) 会跳过它。
关于您的主要问题:Spring Data Neo4j 默认加载从域模型角度可访问的所有内容。
User
和 User
之间的这种循环依赖(这在您正在工作的领域中有意义)预计会在这种情况下结束。
旧版本的 SDN 在获取数据时创建了 2 跳的虚拟屏障(如果没有参数化以加载更多数据)。
在较新的版本中,SDN 提升了预测概念,以更细粒度地定义这些障碍。 (https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#projections.interfaces)
考虑到加载
User
以及她/他的所有关注者的用例,您可能会考虑定义一个像 这样的投影
interface UserProjection {
String getName();
Set<Follower> getFollowsReceived();
Set<Follower> getFollowsGiven();
}
interface Follower {
String getName();
// no relationships defined here to break the circle
}
并在存储库中使用它,如下所示:
interface UserRepository extends Neo4jRepository<User, Long> {
UserProjection findByName(String name);
}
(从我的脑海中写下,请查看链接的文档以了解更多详细信息)
这里重要的一点是,您仅指“根”投影 (
Follower
) 内的另一个投影接口 (UserProjection
)。
如果您引用任何定义的实体(@Node
注释),SDN将退回到循环加载机制以再次找到可到达的所有内容。
* 对标识符进行包装可以为您带来性能优势,因为 Spring Data Neo4j 使用此信息来确定数据库中是否已存在关系。但为此,您必须在您的
Sets
中使用它,而不是与其他 Users
的直接关系。