ノードは複数の親を持つことができるため、これはグラフであり、ツリーではありません。リレーショナルデータベースにはグラフを処理するためのパターンがありますが、私はそれらが面倒であることに気づきました。これは、グラフデータベースが優れているところです。
説明のために、プラグインを介して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エンドポイントを作成する場合に、管理されていない拡張機能を作成する機能もあります。