1

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

目标:

  1. 该层应该提供类似于Facebook Graph API的支持,它为每个实体/对象定义相关的属性和连接,可以从 URL 引用。
    FB 图形 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
  • 方面J 1.6.12
  • 杰克逊1.8.5

为了简单起见,我们有ProfileStory节点和它们之间的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 吗?


现在就是这样......欢迎对我上面提出的任何方法发表任何评论......谢谢。

4

1 回答 1

3

开始回答,绝不完整:

也许升级到 .RELEASE 版本?

问题 1

如果要将 AspectJ 实体序列化为 JSON,则必须排除高级映射生成的内部字段(请参阅此论坛讨论)。

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

问题2

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

问题 3

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

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

问题 5

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

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

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

问题 6

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

于 2013-01-03T12:15:27.670 回答