Neo4j是目前最热门的图数据库之一,图数据库以计算机图结构为基础,擅长处理复杂的数据关系。比如我们常见的社交网络中的人与人的关系图。下面是一个用使用PHP客户端通过Neo4j的REST接口进行数据操作的例子。
原文链接:Neo4j for PHP
如果我们有如下一个电影角色表:
> desc roles; +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | actor_name | varchar(100) | YES | | NULL | | | role_name | varchar(100) | YES | | NULL | | | movie_title | varchar(100) | YES | | NULL | | +-------------+--------------+------+-----+---------+----------------+ > SELECT actor_name, role_name FROM roles WHERE movie_title IN (SELECT DISTINCT movie_title FROM roles WHERE actor_name='Kevin Bacon')
我们需要用上面的复杂SQL语句才能获取到和Kevin Bacon一起演出过的演员名单。
如果我们需要获取一个与和Kevin Bacon一起演出过的人一起演出过的演员名单(真拗口)就更麻烦了,再试想多一层,与(与(与Kevin Bacon一起演出过的演员)一起演出过的演员)一演出过的演员。那几乎是不可完成的任务了。
其实角色关系图就是如下的图结构,而这种应用其实正好是图类型数据库的典型应用场景,蓝色框表示演员,黄色框表示电影
下面我们直接使用Neo4j的PHP客户端来构建图谱:
$client = new Client(new Transport('localhost', 7474)); //构建演员节点 $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(); //建立关联关系 $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();
然后我们就能够在已经建立好的图结构上进行数据查询了。第一个查询是查找所有与Kevin Bacon距离为12的其它人(演员与演员间的距离只能是2的倍数,因为中间隔着电影)。
$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"; } }
你也可以用下面的语句查询所有与Laurence Fishburne相关的电影:
echo $laurence->getProperty('name') . " was in:\n"; $relationships = $laurence->getRelationships('IN'); foreach ($relationships as $relationship) { $movie = $relationship->getEndNode(); echo "\t" . $movie->getProperty('title') . "\n"; }