开始着手一个新项目...为社交网络平台提供服务的RESTful层。
Neo4j是我主要数据存储的明显选择,我之前有机会使用Neo,但没有利用Spring Data将POJO映射到节点的能力,这似乎很方便。
目标:
该层应该提供类似于Facebook Graph API的支持,它为每个实体/对象定义相关的属性和连接,可以从 URL 引用。
FB 图形 API如果可能的话,我想避免传输将被序列化到域实体/从域实体传输的对象,并将我的域 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
- 方面J 1.6.12
- 杰克逊1.8.5
为了简单起见,我们有Profile、Story节点和它们之间的Role关系。
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 和实际节点之间生成分隔线,因此我可以根据请求和域驱动轻松请求属性/连接设计方法看起来很不错。
问题 1 - AspectJ:
假设我想为一个对象定义默认字段,无论是否在 URL 中请求,这些字段都将返回给客户端......所以我在这些字段上尝试了 @FETCH注释,但它似乎在使用时不起作用方面J。目前我是这样做的。。
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 - 带有 {self} 的 @Query:
有点愚蠢的问题,但我无能为力:),似乎在节点实体中使用 @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 角色时,关系实体角色包含@EndNode story ,其中包含角色连接......其中之一是上面的上下文角色,它永远不会结束:) ...有没有办法配置弹簧数据引擎不创建这些永无止境的关系?
问题 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:
我需要存储不具有关系性质的数据.. 例如提要、评论、按摩。
我考虑过与MongoDB集成来存储这些.. 我可以将域 pojo 字段/连接拆分到具有跨存储支持的 mongo/neo4j 吗?它会支持 AspectJ 吗?
现在就是这样......欢迎对我上面提出的任何方法发表任何评论......谢谢。