10

Neo4j v1.9.x では、次のようなコードを使用しました。

private Category CreateNodeCategory(Category cat)
{
        var node = client.Create(cat,
            new IRelationshipAllowingParticipantNode<Category>[0],
            new[]
            {
                new IndexEntry(NeoConst.IDX_Category)
                {
                    { NeoConst.PRP_Name, cat.Name },
                    { NeoConst.PRP_Guid, cat.Nguid.ToString() }
                }
            });
        cat.Nid = node.Id;
        client.Update<Category>(node, cat);
        return cat;
}

その理由は、ノード ID が自動生成され、後ですばやく検索したり、他のクエリでビットを開始したりするために使用できるためです。次のように:

    private Node<Category> CategoryGet(long nodeId)
    {
        return client.Get<Category>((NodeReference<Category>)nodeId);
    }

これにより、うまく機能するように見えた次のことが可能になります。

    public Category CategoryAdd(Category cat)
    {
        cat = CategoryFind(cat);
        if (cat.Nid != 0) { return cat; }
        return CreateNodeCategory(cat);
    }

    public Category CategoryFind(Category cat)
    {
        if (cat.Nid != 0) { return cat; }
        var node = client.Cypher.Start(new { 
    n = Node.ByIndexLookup(NeoConst.IDX_Category, NeoConst.PRP_Name, cat.Name)})
            .Return<Node<Category>>("n")
            .Results.FirstOrDefault();
        if (node != null) { cat = node.Data; }
        return cat;
    }

現在、cypher Wiki、例、および悪い習慣は、すべての CRUD で .ExecuteWithoutResults() を使用することを推奨しています。

質問は、ノード ID の自動インクリメント値をどのように設定するかということです。

4

1 に答える 1

23

まず、Neo4j 2 以降では、常に「Cypher でこれを行うにはどうすればよいか?」という枠組みから始める必要があります。そのときだけ、C# について心配します。

さて、あなたの質問を要約すると、あなたの主な目標はノードを作成し、その後の作業のために参照を返すことのようです。

これを暗号で行うには、次のようにします。

CREATE (myNode)
RETURN myNode

C# では、次のようになります。

var categoryNode = graphClient.Cypher
    .Create("(category {cat})")
    .WithParams(new { cat })
    .Return(cat => cat.Node<Category>())
    .Results
    .Single();

ただし、これはまだ、元のCreateNodeCategory方法で行っていた 100% ではありません。DB にノードを作成し、Neo4j の内部識別子を取得してから、その識別子を同じノードに保存します。基本的に、Neo4j を使用して自動インクリメント番号を生成しています。それは機能的ですが、実際には良いアプローチではありません。もっと説明します...

まず、Neo4j がノード ID を返してくれるという概念はなくなります。これは、実際にはディスク上のファイル オフセットである内部識別子です。それは変わることができます。低レベルです。SQL について少し考えてみると、SQL クエリを使用して行のファイル バイト オフセットを取得し、将来の更新のためにそれを参照しますか? A:いいえ。行をすべて 1 回のヒットで検索して操作するクエリを作成します。

Nguidここで、ノードに既にプロパティがあることに気付きました。なぜそれをIDとして使用できないのですか?または、名前が常に一意である場合は、それを使用しますか? (ドメイン関連の ID は常にマジック ナンバーよりも望ましいです。) どちらも適切でない場合は、SnowMakerのようなプロジェクトを参考にしてください。

次に、索引付けについて検討する必要があります。使用しているインデックス作成のタイプは、2.0 のドキュメントでは「レガシー インデックス作成」と呼ばれており、Neo4j 2.0 のクールな機能のいくつかを見逃しています。

この回答の残りの部分では、Categoryクラスが次のようになっていると想定します。

public class Category
{
    public Guid UniqueId { get; set; }
    public string Name { get; set; }
}

ラベル付きのカテゴリ ノードを作成することから始めましょう。

var category = new Category { UnqiueId = Guid.NewGuid(), Name = "Spanners" };
graphClient.Cypher
    .Create("(category:Category {category})")
    .WithParams(new { category })
    .ExecuteWithoutResults();

そして、1 回限りの操作として、次のラベルが付いたノードのプロパティにスキーマベースのインデックスを作成しましょう。NameCategory

graphClient.Cypher
    .Create("INDEX ON :Category(Name)")
    .ExecuteWithoutResults();

これで、インデックスを手動で最新の状態に保つことを心配する必要がなくなりました。

にインデックスと一意の制約を導入することもできUniqueIdます。

graphClient.Cypher
    .Create("CONSTRAINT ON (category:Category) ASSERT category.UniqueId IS UNIQUE")
    .ExecuteWithoutResults();

クエリは非常に簡単になりました。

graphClient.Cypher
    .Match("(c:Category)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Return(c => c.As<Category>())
    .Results
    .Single();

カテゴリ ノードを検索してから別のクエリを実行するのではなく、すべてを一度に実行します。

var productsInCategory = graphClient.Cypher
    .Match("(c:Category)<-[:IN_CATEGORY]-(p:Product)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Return(p => p.As<Product>())
    .Results;

カテゴリを更新する場合は、それも一度に行います。

graphClient.Cypher
    .Match("(c:Category)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Update("c = {category}")
    .WithParams(new { category })
    .ExecuteWithoutResults();

最後に、あなたのCategoryAddメソッドは現在、1) 1 つの DB ヒットを実行して既存のノードを見つけ、2) 2 番目の DB ヒットで新しいノードを作成し、3) 3 番目の DB ヒットで ID を更新します。MERGE代わりに、キーワードを使用して、これらすべてを単一の呼び出しに圧縮することもできます。

public Category GetOrCreateCategoryByName(string name)
{
    return graphClient.Cypher
        .WithParams(new {
            name,
            newIdIfRequired = Guid.NewGuid()
        })
        .Merge("(c:Category { Name = {name})")
        .OnCreate("c")
        .Set("c.UniqueId = {newIdIfRequired}")
        .Return(c => c.As<Category>())
        .Results
        .Single();
}

基本的、

  1. 自分の ID を管理する方法として、Neo4j の内部 ID を使用しないでください。(しかし、彼らは将来何らかの形の自動番号付けをリリースするかもしれません。たとえリリースしたとしても、メールアドレス、SKU、空港コードなどのドメイン ID が好まれます。常に ID が必要なわけではありません。多くの場合、グラフ内の位置に基づくノード)。

  2. 通常、Node<T>時間の経過とともに消えます。今使用すると、レガシー コードが発生するだけです。

  3. ラベルとスキーマベースのインデックス作成を調べてください。彼らはあなたの人生を楽にします。

  4. 1 つのクエリで物事を試してみてください。それははるかに高速になります。

それが役立つことを願っています!

于 2013-10-23T07:39:59.850 に答える