【问题标题】:Neo4j Spring data POC for social RESTful layer用于社交 RESTful 层的 Neo4j Spring 数据 POC
【发布时间】:2012-12-17 17:02:51
【问题描述】:

开始着手一个新项目... RESTful 层为社交网络平台提供服务。
Neo4j 是我主要数据存储的明显选择,我之前有机会与 Neo 合作,但没有利用 Spring Data 功能将 POJO 映射到似乎很方便的节点。

目标:

  1. 该层应该提供类似于 Facebook Graph API 的支持,它为每个 entity/object 定义了可以从 URL 引用的相关属性和连接。
    FB Graph API

  2. 如果可能,我想避免传输将被序列化到域实体/从域实体传输的对象,并使用我的域 pojo 作为 JSON 传输到/从客户端传输。

示例:

  • HTTP GET /profile/{id}/?fields=...&connections=... 响应将是 Profile 对象包含请求的 URL。

  • HTTP GET /profile/{id}/stories/?fields=..&connections=...&page=..&sort=...根据请求,响应将是 Story 对象的列表。

相关版本:

  • Spring 框架3.1.2
  • Spring Data Neo4j 2.1.0.RC3
  • Spring Data Mongodb 1.1.0.RC1
  • AspectJ 1.6.12
  • 杰克逊1.8.5

为了简单起见,我们有简介故事节点和角色 它们之间的关系。

public abstract class GraphEntity {
@GraphId
protected Long id;
}


配置文件节点

@NodeEntity
@Configurable
public class Profile extends GraphEntity {

// Profile fields
private String firstName;
private String lastName;

// Profile connections  
@RelatedTo(type = "FOLLOW", direction = Direction.OUTGOING)
private Set<Profile> followThem;

@RelatedTo(type = "BOOKMARK", direction = Direction.OUTGOING)
private Set<Story> bookmarks;

@Query("START profile=node({self}) match profile-[r:ROLE]->story where r.role = FOUNDER and story.status = PUBLIC")
private Iterable<Story> published;
}


故事节点

@NodeEntity
@Configurable
public class Story extends GraphEntity {

// Story fields
private String title;
private StoryStatusEnum status = StoryStatusEnum.PRIVATE;

// Story connections
@RelatedToVia(type = "ROLE", elementClass = Role.class, direction = Direction.INCOMING)
private Set<Role> roles;
}


角色关系

@RelationshipEntity(type = "ROLE")
public class Role extends GraphEntity {

@StartNode
private Profile profile;
@EndNode
private Story story;

private StoryRoleEnum role;
}


起初我没有使用 AspectJ 支持,但我发现它对我的用例非常有用,因为它在 POJO 和实际节点之间生成分隔符,因此我可以轻松请求属性/connections 根据请求和Domain Driven Design Approach 看起来很不错。

问题 1 - AspectJ:

假设我想为一个对象定义默认字段,无论是否在 URL 中请求,这些字段都将返回给客户端......所以我尝试了 @FETCH 注释这些字段,但它似乎在使用 AspectJ 时不起作用。 目前我是这样做的..

public Profile(Node n) {
    setPersistentState(n);
    this.id = getId();
    this.firstName = getFirstName();
    this.lastName = getLastName();  
}

这是实现这一目标的正确方法吗?即使使用 AspectJ,是否也应该支持 @FETCH 注释?
我很乐意看到有关 AspectJ + Neo4j 的示例/博客几乎没有找到任何东西....

问题 2 - 分页:

我想在请求特定连接时支持分页,例如

/profile/{id}/stories/,如果故事相关如下

// inside profile node
@RelatedTo(type = "BOOKMARK", direction = Direction.OUTGOING)
private Set<Story> bookmarks; 


/profile/{id}/stories/,如果故事相关如下

 // inside profile node
@Query("START profile=node({self}) match profile-[r:ROLE]->story where r.role = FOUNDER and story.status = PUBLIC")
private Iterable<Story> published;

@Query 是否支持开箱即用的分页 || @RelatedTo || @RelatedToVia 使用 Pageable 接口来检索 Page 而不是 Set/List/Iterable?限制和排序应该是动态的,具体取决于客户端的请求...我可以使用Cypher Query DSL 实现这一点,但更喜欢使用基本的.. 其他方法将被愉快地接受。

问题 3 - @Query 与 {self}:

有点愚蠢的问题,但我忍不住 :),似乎在节点实体内使用 @Query 时(使用 {self} 参数},返回类型必须是 Iterable,这很有意义.. 让我们举个例子......

// inside profile node
@Query("START profile=node({self}) match profile-[r:ROLE]->story where r.role = FOUNDER and story.status = PUBLIC")
private Iterable<Story> published;

当请求发布连接时:

    // retrieving the context profile
    Profile profile = profileRepo.findOne(id);
    // getting the publishe stories using AspectJ - will redirect to the backed node
    Iterable<Story> published = profile.getPublished();
    // set the result into the domain object - will throw exception of read only because the type is Iterable
    profile.setPublished(published);

有解决办法吗?这不会创建另一个属性,该属性将是 Profile 中的 @Transiant ..

问题 4 - 递归关系:

我在传递/递归关系方面遇到了一些问题,当在 Story 中分配新的 Profile Role 时,关系实体角色包含 @EndNode story ,其中包含 roles connection.. .其中之一是上面的上下文role,它永远不会结束:)... 有没有办法配置弹簧数据引擎不创建这些永无止境的关系?

问题 5 - 交易:

也许我之前应该提到过它,但我正在使用 Neo4j DB 的 REST 服务器,从之前的阅读中我了解到事务中不支持开箱即用?就像使用嵌入式服务器时一样 我有以下代码...

    Profile newProfile = new Profile();
    newProfile.getFollowThem().add(otherProfile);
    newProfile.getBookmarks().add(otherStory);
    newProfile.persist(); // or profileRepo.save(newProfile)

当使用 REST 服务器时,这会在事务中运行吗?这里的操作很少,如果一个失败就失败了?

问题 6 - Mongo + Neo4j:

我需要存储不具有关系性质的数据。例如 Feed、评论、按摩。
我考虑过与 MongoDB 集成来存储这些数据。我可以拆分域吗pojo 字段/连接到具有跨商店支持的 mongo/neo4j?它会支持 AspectJ 吗?


现在就是这样......任何关于我上面介绍的任何方法的 cmet 都将受到欢迎......谢谢。

【问题讨论】:

  • 哇,问题太多了。

标签: social-networking neo4j aspectj spring-data-neo4j spring-data-mongodb


【解决方案1】:

开始回答,未完待续:

也许升级到 .RELEASE 版本?

问题 1

如果您想将 AspectJ 实体序列化为 JSON,您必须排除由高级映射生成的内部字段(参见 forum discussion)。

当您使用高级映射时,@Fetch 不是必需的,因为无论如何数据都是从数据库中读取的。

问题 2

对于字段的分页,您可以尝试使用带有@QueryLIMIT 100 SKIP 10 作为固定参数的密码查询。否则,您可以使用存储库/模板在实体字段中使用分页信息实际填充集合。

问题 3

我不认为 @Query 的返回类型必须是 Iterable 它也应该与其他类型(集合或具体类型)一起使用。你遇到了什么问题?

为了创建递归关系 - 尝试先存储关系对象本身,然后再存储节点实体。或使用template.createRelationshipBetween(start, end, type, allowDuplicates) 创建关系。

问题 5

当您在 REST 上使用 SDN 时,它可能表现不佳,因为目前底层实现使用 RestGraphDatabase 进行细粒度操作,而高级映射使用非常细粒度的调用。你有什么理由不想使用嵌入式模式?对于 REST 服务器,我肯定会使用简单映射并尝试主要使用密码处理读取操作。

使用 REST APi,每个 http 调用只有一个 tx,拥有更大事务的唯一选择是使用 rest-batch-api

在底层rest-graph-database 中有一个伪事务支持,该支持将在“事务”中发出的批处理调用在一个批处理休息请求中执行。但是这些调用不能依赖于 tx 期间的读取结果,那些只会在 tx 完成后填充。在 SDN 中使用这种方法也存在一些问题,所以我为此禁用了它(它是 rest-graphdb 的配置选项/系统属性)。

问题 6

现在对 MongoDB 和 Neo4j 的跨存储支持仅用于 JPA / 关系存储。我们曾经讨论过在 spring-data 项目之间进行跨存储引用,但没有跟进。

【讨论】:

  • 嗨,Michael,感谢您对问题 1 的快速回复.....关于问题 1:我对 JSON 的序列化没有任何问题,我只希望自动加载几个特定字段。关于问题 3:我得到那个异常 java.lang.ClassCastException: org.springframework.data.neo4j.rest.SpringEndResult cannot be cast to java.util.Collection ...其余的答案很清楚..你能参考吗我到了一个使用 aspectJ + neo4j + spring data 的教程。最后一个问题是使用 REST 服务器的主要用例是什么?谢谢
猜你喜欢
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 2011-03-16
  • 2017-01-24
  • 2019-03-19
  • 1970-01-01
相关资源
最近更新 更多