本文目录导读:

- 使用Neo4j图数据库进行子图查询
- 使用Cypher查询语言进行复杂子图查询
- 使用RedisGraph(Redis模块)
- 使用纯PHP实现内存子图查询
- 使用Neo4j PHP ODM(对象文档映射)
- 性能优化建议
- 可视化子图
在PHP项目中进行子图(Subgraph)查询通常涉及图数据库(如Neo4j、ArangoDB、JanusGraph等)或图结构数据的处理,以下是一些常见场景和实现方式:
使用Neo4j图数据库进行子图查询
安装依赖
composer require graphaware/neo4j-php-client
查询示例
<?php
require_once 'vendor/autoload.php';
use GraphAware\Neo4j\Client\ClientBuilder;
// 连接Neo4j
$client = ClientBuilder::create()
->addConnection('default', 'http://neo4j:password@localhost:7474')
->build();
// 查询子图:找到特定节点的所有直接关联节点和关系
$query = '
MATCH (n:Person {name: {name}})
OPTIONAL MATCH (n)-[r]-(connected)
RETURN n, r, connected
';
$result = $client->run($query, ['name' => 'Alice']);
$nodes = [];
$edges = [];
foreach ($result->getRecords() as $record) {
$node = $record->get('n');
$nodes[] = [
'id' => $node->identity(),
'labels' => $node->labels(),
'properties' => $node->values()
];
$relationship = $record->get('r');
if ($relationship) {
$edges[] = [
'id' => $relationship->identity(),
'type' => $relationship->type(),
'start' => $relationship->startNodeIdentity(),
'end' => $relationship->endNodeIdentity()
];
}
}
// 组合成子图结构
$subgraph = [
'nodes' => $nodes,
'edges' => $edges
];
使用Cypher查询语言进行复杂子图查询
多级子图查询
// 查询2层深度的子图
$query = '
MATCH (n:Person {name: {name}})
CALL apoc.path.subgraphAll(n, {
maxLevel: 2,
relationshipFilter: "KNOWS|WORKS_WITH"
}) YIELD nodes, relationships
RETURN nodes, relationships
';
使用RedisGraph(Redis模块)
安装和配置
composer require predis/predis
RedisGraph查询
<?php
use Predis\Client;
$redis = new Client([
'scheme' => 'tcp',
'host' => 'localhost',
'port' => 6379,
]);
// 创建图
$redis->executeRaw(['GRAPH.CREATE', 'social_graph']);
// 添加节点和关系
$redis->executeRaw([
'GRAPH.QUERY',
'social_graph',
"CREATE (:Person {name:'Alice', age:30})-[:KNOWS]->(:Person {name:'Bob', age:25})"
]);
// 查询子图
$result = $redis->executeRaw([
'GRAPH.QUERY',
'social_graph',
"MATCH (a:Person {name:'Alice'})-[*1..2]-(connected) RETURN a, connected"
]);
var_dump($result);
使用纯PHP实现内存子图查询
<?php
class SubgraphManager {
private $adjacencyList = [];
public function addEdge($from, $to, $type = 'connected') {
$this->adjacencyList[$from][$to] = ['type' => $type, 'weight' => 1];
$this->adjacencyList[$to][$from] = ['type' => $type, 'weight' => 1];
}
/**
* BFS查询子图
*/
public function getSubgraph($startNode, $maxDepth = 1) {
$visited = [$startNode => true];
$queue = [[$startNode, 0]];
$nodes = [$startNode];
$edges = [];
while ($queue) {
[$current, $depth] = array_shift($queue);
if ($depth >= $maxDepth) continue;
if (isset($this->adjacencyList[$current])) {
foreach ($this->adjacencyList[$current] as $neighbor => $relation) {
if (!isset($visited[$neighbor])) {
$visited[$neighbor] = true;
$nodes[] = $neighbor;
$edges[] = [
'from' => $current,
'to' => $neighbor,
'type' => $relation['type']
];
$queue[] = [$neighbor, $depth + 1];
}
}
}
}
return [
'nodes' => array_unique($nodes),
'edges' => $edges
];
}
}
// 使用示例
$graph = new SubgraphManager();
$graph->addEdge('Alice', 'Bob', 'friend');
$graph->addEdge('Bob', 'Charlie', 'colleague');
$graph->addEdge('Alice', 'David', 'family');
$subgraph = $graph->getSubgraph('Alice', 2);
print_r($subgraph);
使用Neo4j PHP ODM(对象文档映射)
<?php
use Neo4j\Neo4jBundle;
use GraphAware\Neo4j\Client\Formatter\Type\Node;
class UserRepository {
public function findSubgraph(User $user, int $depth = 2) {
$query = '
MATCH (user:User {id: {userId}})
CALL apoc.path.subgraphAll(user, {
maxLevel: {depth},
relationshipFilter: "FOLLOWS|FRIEND"
}) YIELD nodes, relationships
RETURN nodes, relationships
';
$result = $this->client->run($query, [
'userId' => $user->getId(),
'depth' => $depth
]);
// 处理结果...
}
}
性能优化建议
索引创建
// Neo4j中创建索引
$client->run('CREATE INDEX ON :Person(name)');
$client->run('CREATE INDEX ON :Company(id)');
分页和限制
// 限制子图大小
$query = '
MATCH (n:Person {name: {name}})
CALL apoc.path.subgraphAll(n, {
maxLevel: 2,
limit: 100
}) YIELD nodes, relationships
RETURN nodes, relationships
';
缓存结果
// 使用Redis缓存子图查询结果
$cacheKey = "subgraph:{$name}:{$depth}";
$cached = $redis->get($cacheKey);
if ($cached) {
return json_decode($cached, true);
}
// 执行查询...
$redis->setex($cacheKey, 3600, json_encode($subgraph));
可视化子图
<?php
function subgraphToVisJs($subgraph) {
$nodes = [];
$edges = [];
foreach ($subgraph['nodes'] as $node) {
$nodes[] = [
'id' => $node['id'],
'label' => $node['properties']['name'] ?? 'Node ' . $node['id'],
'group' => $node['labels'][0] ?? 'default'
];
}
foreach ($subgraph['edges'] as $edge) {
$edges[] = [
'from' => $edge['start'],
'to' => $edge['end'],
'label' => $edge['type']
];
}
return json_encode(['nodes' => $nodes, 'edges' => $edges]);
}
header('Content-Type: application/json');
echo subgraphToVisJs($subgraphResult);
选择哪种方式取决于你的具体需求:
- Neo4j:最成熟,适合复杂图查询
- RedisGraph:高性能,适合实时查询
- 纯PHP:适合小规模数据或学习
- ArangoDB:支持多模型(图+文档+键值)
对于生产环境,推荐使用Neo4j或ArangoDB配合相应的PHP客户端库。