PHPのNeo4jグラフデータベース

最近、私は特にNoSQLとグラフデータベースについてますます耳にします。 しかし、ハブロ検索を使用して、このトピックに関する記事がそれほど多くないことを知って驚きましたが、「Neo4j」のリクエストでは、一般に4つの結果があり、この名前は記事の本文で間接的に言及されています。



Neo4jとは何ですか?



画像

Neo4jは、高性能のNoSQLグラフベースのデータベースです。 厳密に定義されたフィールドを持つテーブルのようなものはありません;ノードとそれらの間の関係の形で柔軟な構造で動作します。



どうやってこれに到達しましたか?



1年以上、ドキュメント指向のDBMS " MongoDB "を試したときから、プロジェクトでSQLを使用していません。 MySQLの後、私の喜びは、MongoDBですべてを簡単かつ便利に実行できることに制限はありませんでした。 年間を通じて、当社のウェブサイト作成スタジオでは、Mongoの主要な機能とそのドキュメントを使用して3つのCMSを書き換えました。 すべてが順調だったので、データベースからの各アクションに対して50行でクエリを記述することを忘れ始めていました。ドキュメントに合わない関係がたくさんあるプロジェクトが私の頭に落ちるまで、何も起こりませんでした。 私は本当にSQLに戻りたくありませんでしたが、数日間、グラフDBMSへの柔軟な接続を可能にするNoSQLソリューションを純粋に探していました。 そして、いくつかの理由で、私の選択はNeo4jでした。主な理由の1つは、私のエンジンがPHPで書かれていることです。



要点をつかむ



グラフデータベースの主な目的は、複数のレベルにまたがる関係でデータが互いに密接に関連している問題を解決することです。 たとえば、リレーショナルデータベースでは、「ケビンベーコンと映画に出演していたすべての俳優のリストをください」という要求を満たすことは難しくありません。



> SELECT actor_name, role_name FROM roles WHERE movie_title IN (SELECT DISTINCT movie_title FROM roles WHERE actor_name='Kevin Bacon')
      
      







彼はクエリを使用して例を挙げました。「JOIN」を使用して頭の中で書き換えることができます。



しかし、ケビンベーコンと一緒に映画に出演した人と一緒に映画に出演したすべての俳優の名前を取得したいとします。 そして、ここに別のJOINがあります。 ここで、3度目の追加を試みてください。「誰かと映画の中にいる人、誰かと映画の中にいる人、ケビンベーコンと映画の中にいる人」。 JOINを追加すると、リクエストはより複雑になり、時間がかかり、生産性が低下します。



深いつながりは、さまざまなソーシャルプロジェクト、友人の友人を獲得する必要があるとき、ルートを見つけるタスクなどで特に重要です。 グラフデータベースは、2つ以上の関係によってデータを相互に削除できる場合に、これらの問題を解決するように設計されています。 データを「グラフの頂点」としてモデル化し、接続をこれらのノード間の「グラフのエッジ」としてモデル化すると、非常にエレガントに解決されます。 長く知られた効率的なアルゴリズムを使用して、グラフをたどることができます。



上記の例は、次のように簡単にモデル化できます。各俳優と映画はノードであり、役割は俳優から彼らが演じた映画に行く関係です:



画像



今では、ケビンベーコンから他の俳優への道を見つけるのは非常に簡単になります。



いくつかのコード



まず、データベースへの接続を確立する必要があります。 Neo4jPHPはRESTインターフェースを介してデータベースサーバーと連携するため、永続的な接続はなく、データの読み取りまたは書き込みが必要な場合にのみデータ転送が発生します。



 use Everyman\Neo4j\Client, Everyman\Neo4j\Transport, Everyman\Neo4j\Node, Everyman\Neo4j\Relationship; $client = new Client(new Transport('localhost', 7474));
      
      







次に、各俳優と映画のノードを作成する必要があります。 これは、従来のリレーショナルDBMSでINSERTを行う方法に似ています。



 $keanu = new Node($client); $keanu->setProperty('name', 'Keanu Reeves')->save(); $laurence = new Node($client); $laurence->setProperty('name', 'Laurence Fishburne')->save(); $jennifer = new Node($client); $jennifer->setProperty('name', 'Jennifer Connelly')->save(); $kevin = new Node($client); $kevin->setProperty('name', 'Kevin Bacon')->save(); $matrix = new Node($client); $matrix->setProperty('title', 'The Matrix')->save(); $higherLearning = new Node($client); $higherLearning->setProperty('title', 'Higher Learning')->save(); $mysticRiver = new Node($client); $mysticRiver->setProperty('title', 'Mystic River')->save();
      
      







各ノードにはsetProperty メソッドgetPropertyメソッドがあり、任意のデータをノードに書き込んで読み取ることができます。 ノードは特定の構造を持たず、ドキュメント指向のDBMSのドキュメントに似ていますが、埋め込みデータを行うことはできず、プロパティは文字列または数値の2つのタイプのいずれかのみです。

save()を呼び出したときにのみデータがサーバーに送信され、これは各ノードで実行する必要があります。



次に、俳優と彼らが演じた映画との関係を設定する必要があります。 このためのリレーショナルDBMSでは、外部キーを作成します。ここでは、ノードのようにパラメータを保存するために任意に呼び出すことができ、データベースにも保存されるリレーションを作成します。



 $keanu->relateTo($matrix, 'IN')->save(); $laurence->relateTo($matrix, 'IN')->save(); $laurence->relateTo($higherLearning, 'IN')->save(); $jennifer->relateTo($higherLearning, 'IN')->save(); $laurence->relateTo($mysticRiver, 'IN')->save(); $kevin->relateTo($mysticRiver, 'IN')->save();
      
      







ご覧のとおり、すべてのリレーションは「IN」と呼ばれますが、「ACTED IN」など、他の名前を付けることもできます。 また、映画から俳優への逆の関係を求め、それを映画「HAS」(俳優を持つ)として定式化することもできます。 作成する通信の方向に関係なく、パスを見つけることができます。 特定のサブジェクト領域の意味で適切な任意のセマンティクスを使用できます。 同時に、両方向のノード間に複数の関係がある場合があります。



すべての関係が設定され、システム内の任意のアクターとKevin Bacon間の任意の深さへの接続を見つける準備ができました。



 $path = $keanu->findPathsTo($kevin) ->setMaxDepth(12) ->getSinglePath(); foreach ($path as $i => $node) { if ($i % 2 == 0) { echo $node->getProperty('name'); if ($i+1 != count($path)) { echo " was in\n"; } } else { echo "\t" . $node->getProperty('title') . " with\n"; } }
      
      







また、ノード自体ではなく、ノード間の接続を選択することもできます。例:



 echo $laurence->getProperty('name') . " was in:\n"; $relationships = $laurence->getRelationships('IN'); foreach ($relationships as $relationship) { $movie = $relationship->getEndNode(); echo "\t" . $movie->getProperty('title') . "\n"; }
      
      







getRelationships-ノードのすべてのリレーションを返すことができます。特定のタイプのリレーションシップのみに制限する必要はありません。 また、通信ノードからのすべての着信または発信のみを受信できます。



とりあえずこの投稿を終了しますが、グラフデータベース、特にneo4jのテーマに関する記事を書くことに共鳴がもたらされることを願っています。



この記事では、 Neo4jPHP開発者サイトの例を使用し、私の個人的な経験に基づいて変更とコメントを加えました。



All Articles