1

新しいプロジェクトに取り組み始めています...ソーシャルネットワークプラットフォームにサービスを提供するRESTfulレイヤー。
Neo4jはメインデータストアの私の明白な選択でした。以前はNeoを使用する機会がありましたが、 SpringDataの機能を利用してPOJOをノードにマッピングすることは非常に便利でした。

目標:

  1. レイヤーは、URLから参照できるエンティティ/オブジェクト関連のプロパティと接続を定義するFacebookGraphAPIに似たサポートを提供する必要があります。FBグラフAPI

  2. 可能であれば、ドメインエンティティとの間でシリアル化される転送オブジェクトを避け、クライアントとの間で転送されるJSONとしてドメインpojoを使用したいと思います。

例:

  • HTTP GET / profile / {id} /?fields = ...&connections = ...応答は、要求されたURLを含むプロファイルオブジェクトになります。

  • HTTP GET / profile / {id} / stories /?fields = ..&connections = ...&page = ..&sort = ...応答は、要求されたストーリーオブジェクトのリストになります。

関連するバージョン:

  • Spring Framework 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と実際のノードの間に仕切りを生成するため、ユースケースに非常に役立ちます。したがって、リクエストとドメイン駆動型に応じてプロパティ/接続を簡単にリクエストできます。デザインアプローチはとてもいいようです。

質問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は、Set / List / Iterableの代わりにPageableインターフェイスを使用してPageを取得しますか制限と並べ替えは、クライアントからの要求に応じて動的である必要があります... 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-漸化式:

推移的/再帰的関係に問題があります。ストーリーで新しいプロファイルロールを割り当てると、リレーションエンティティロールに@EndNodeストーリーが含まれ、ロール接続が含まれます...そのうちの1つは上記のコンテキストロールであり、終了することはありません:) ...これらの終わりのない関係を作成しないようにSpringデータエンジンを構成する方法はありますか?

質問5-トランザクション:

前に言及したはずですが、Neo4j DBにRESTサーバーを使用しています。以前の記事から、トランザクションですぐに使用できるサポートがないことを理解していますか?組み込みサーバーを使用するときのように、私は次のコードを持っています...

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

これはRESTサーバーを使用するときにトランザクションで実行されますか?ここにはいくつかの操作がありますが、1つが失敗した場合、すべてが失敗しますか?

質問6-Mongo+Neo4j:

フィード、コメント、マッサージなど、リレーショナルな性質を持たないデータを保存する必要があります。これらを保存するためにMongoDB
との統合を考えました。クロスストアサポートを使用して、ドメインpojoフィールド/接続をmongo / neo4jの両方に分割できますか?AspectJをサポートしますか?


今のところは以上です....上記で提示したアプローチに関するコメントは大歓迎です..ありがとうございます。

4

1 に答える 1

3

答え始めて、決して完全ではありません:

おそらく.RELEASEバージョンにアップグレードしますか?

質問1

AspectJエンティティをJSONにシリアル化する場合は、高度なマッピングによって生成された内部フィールドを除外する必要があります(このフォーラムのディスカッションを参照してください)。

Advanced Mappingを使用する場合、データはデータベースから読み飛ばされるため、@Fetchは必要ありません。

質問2

フィールドのページネーションについては、固定パラメーターとして@Queryとを使用してcypher-queryを使用してみることができます。LIMIT 100 SKIP 10それ以外の場合は、リポジトリ/テンプレートを使用して、エンティティのフィールドのコレクションにページ情報を実際に入力できます。

質問3

のreturn-typeは、他のタイプ(コレクションまたは具象型)でも機能する必要@Queryがあるとは思いません。Iterableあなたが遭遇する問題は何ですか?

再帰的な関係を作成するには、関係オブジェクト自体を最初に保存し、次にノードエンティティのみを保存するようにします。またはtemplate.createRelationshipBetween(start, end, type, allowDuplicates)、関係を作成するために使用します。

質問5

SDN over RESTを使用しているため、パフォーマンスが低下する可能性があります。現在、基盤となる実装ではRestGraphDatabaseを使用してきめ細かい操作を行い、高度なマッピングでは非常にきめ細かい呼び出しを使用しています。埋め込みモードを使用したくない理由はありますか?RESTサーバーに対して、私は間違いなく単純なマッピングを使用し、主に暗号を使用して読み取り操作を処理しようとします。

REST APiでは、http呼び出しごとに1つのtxしかありません。より大きなトランザクションを持つ唯一のオプションは、rest-batch-apiを使用することです。

基盤となるrest-graph-databaseには疑似トランザクションのサポートがあり、「トランザクション」内で発行された呼び出しをバッチ処理して、1つのbatch-rest-requestで実行します。ただし、これらの呼び出しは、tx中の読み取り結果に依存してはならず、txが終了した後にのみ入力されます。SDNでこのアプローチを使用する際にもいくつかの問題があったため、そのために無効にしました(rest-graphdbのconfig-option / system-propertyです)。

質問6

現在、MongoDBとNeo4jの両方のクロスストアサポートは、JPA/リレーショナルストアに対して使用されています。春のデータプロジェクト間でストア間の参照を行うことについて一度話し合いましたが、これについてはフォローアップしませんでした。

于 2013-01-03T12:15:27.670 に答える