0

私は次のリストを持っています:

ここに画像の説明を入力してください

カテゴリ(コンピュータ、Mac、PCなど)が他の多くのカテゴリを持つことができる多対多の再帰的な関連付けです。また、カテゴリ(光学ドライブなど)はPCとMacに属することができます。ただし、「オプティカルドライブ」では、無限ループが発生するため、「PC」カテゴリとしてカテゴリを設定することはできません。

Railsで上記の検証を作成して最適化するにはどうすればよいですか?すべての親カテゴリを確認する必要がありますか?ただし、ネストされたカテゴリが多数ある場合(たとえば、子カテゴリの深さが200の場合)、これにより多くのSQLクエリが発生します。

もう1つの考えは、データベースに深度列を作成し、親カテゴリが子として持つことを許可してはならない検証を行うことでした。これは、自身の深度よりも深度が小さいカテゴリです。しかし、それでは、共通の親がないカテゴリを別の深さまで持つというシナリオは許可されません。たとえば、上記のリストの例では、光学式ドライブは、それが上記の深度レベルにある場合でも、カテゴリとしてMacを持つことができます。しかし、無限のループのために、PCを搭載できませんでした。

4

1 に答える 1

2

ノードは複数の親を持つことができるため、これはグラフであり、ツリーではありません。リレーショナルデータベースにはグラフを処理するためのパターンがありますが、私はそれらが面倒であることに気づきました。これは、グラフデータベースが優れているところです。

説明のために、プラグインを介してNeo4jで実行され、Neo4j RESTAPIを介して利用できるグラフ走査言語であるGremlinでの問題に対する潜在的な解決策を示します。

Neo4jに含まれているGremlinの最新バージョンはGremlin1.5です。このバージョンをGithubからダウンロードして、次のコードを試すことができます。

g = new Neo4jGraph('/tmp/so')

// add all vertices
categories = ['Computers', 'Mac', 'PCs', 'Hard Disks', 'Memory', 'Graphic Cards',
'Optical Drives', 'DVD-Reader', 'DVD-RW', 'Blue Ray', 'Blue Ray / DVD Combo']

categories.each { x -> g.addVertex(['name':x]) }

// show all of the vertices we just created with their properties
g.V.map
==>{name=Computers}
==>{name=Mac}
==>{name=PCs}
==>{name=Hard Disks}
==>{name=Memory}
==>{name=Graphic Cards}
==>{name=Optical Drives}
==>{name=DVD-Reader}
==>{name=DVD-RW}
==>{name=Blue Ray}
==>{name=Blue Ray / DVD Combo}

// for ease of this example, create a lookup table of these vertices
// in a production system, you would look up vertices in a Lucene index
i = [:]
g.V.transform {i[it.name] = it}

// create edges representing one category 'in' another
g.addEdge(i['Mac'], i['Computers'], 'in')
g.addEdge(i['PCs'], i['Computers'], 'in')

// PCs subgraph
g.addEdge(i['Hard Disks'], i['PCs'], 'in')
g.addEdge(i['Memory'], i['PCs'], 'in')
g.addEdge(i['Graphic Cards'], i['PCs'], 'in')

// optical drives subgraph
g.addEdge(i['Optical Drives'], i['PCs'], 'in')
g.addEdge(i['DVD-Reader'], i['Optical Drives'], 'in')
g.addEdge(i['DVD-RW'], i['Optical Drives'], 'in')
g.addEdge(i['Blue Ray'], i['Optical Drives'], 'in')
g.addEdge(i['Blue Ray / DVD Combo'], i['Optical Drives'], 'in')

// adding the optical drive subgraph to Mac is a one-liner
g.addEdge(i['Optical Drives'], i['Mac'], 'in')

// show the names of all vertices in the paths from Computers to child nodes three-levels down
i['Computers'].in.in.in.paths {it.name}
==>[Computers, PCs, Optical Drives, Blue Ray / DVD Combo]
==>[Computers, PCs, Optical Drives, Blue Ray]
==>[Computers, PCs, Optical Drives, DVD-RW]
==>[Computers, PCs, Optical Drives, DVD-Reader]
==>[Computers, Mac, Optical Drives, Blue Ray / DVD Combo]
==>[Computers, Mac, Optical Drives, Blue Ray]
==>[Computers, Mac, Optical Drives, DVD-RW]
==>[Computers, Mac, Optical Drives, DVD-Reader]

g.shutdown()

グレムリンは関数型プログラミングのアプローチであるため、慣れるまでに時間がかかる場合がありますが、慣れれば非常に強力です。

ただし、「オプティカルドライブ」では、無限ループが発生するため、「PC」カテゴリとしてカテゴリを設定することはできません。

この種の検証は、パスファインディングによって処理できます。現在の頂点から子頂点へのパスが存在する場合は、エッジの作成を許可しないでください。Neo4jには、この種の検索を容易にするPathfinderAPIが含まれています。

Railsを使用しているため、Neo4jがNeoographyのようなRESTfulラッパーとペアになって、必要なRailsとNeo4jの統合を提供していることに気付くかもしれません。Neo4jには、カスタムのRESTfulエンドポイントを作成する場合に、管理されていない拡張機能を作成する機能もあります。

于 2012-12-04T17:50:57.237 に答える