如何使用 ArangoDB 和 PHP 遍历一个图形数据结构

6
ArangoDB提供文档和边缘作为生成图形的低级方式。
假设我们设置了一些顶点和边缘的图形,该图形表示顶点之间的关系。
v2是v1的子节点,v3是v2的子节点,v4是v3的子节点,v5是v1的子节点,v6是v5的子节点。
我们想要查询:
1.从v4到v1的路径
2.v1的所有后代
3.v1的子节点
4.v4的所有祖先
5.v4的父节点。
如何在PHP中实现这个功能?
1个回答

12
这可以通过使用ArangoDB的AQL(ArangoDB查询语言)进行查询来实现。
在AQL中有一些用于处理图形的命令。 在PHP中,我们必须使用查询创建语句并执行它。
附带的代码使用TRAVERSAL函数来提供问题中提到的查询结果。
此脚本设置了文档和边缘集合,填充了顶点和连接边缘,最后执行查询以提供结果。
它可以按原样执行并打印出所有结果。
<?php

namespace triagens\ArangoDb;


    // use this and change it to the path to autoload.php of the arangodb-php client if you're using the client standalone...
    // require __DIR__ . '/../vendor/triagens/ArangoDb/autoload.php';

// ...or use this and change it to the path to autoload.php in the vendor directory if you're using Composer/Packagist
require __DIR__ . '/../vendor/autoload.php';

// This function will provide us with our pre-configured connection options.
function getConnectionOptions()
{
    $traceFunc = function ($type, $data) {
        print "TRACE FOR " . $type . PHP_EOL;
    };

    return array(
        ConnectionOptions::OPTION_ENDPOINT      => 'tcp://localhost:8529/',
        // endpoint to connect to
        ConnectionOptions::OPTION_CONNECTION    => 'Close',
        // can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections)
        ConnectionOptions::OPTION_AUTH_TYPE     => 'Basic',
        // use basic authorization
        /*
        ConnectionOptions::OPTION_AUTH_USER       => '',                      // user for basic authorization
        ConnectionOptions::OPTION_AUTH_PASSWD     => '',                      // password for basic authorization
        ConnectionOptions::OPTION_PORT            => 8529,                    // port to connect to (deprecated, should use endpoint instead)
        ConnectionOptions::OPTION_HOST            => "localhost",             // host to connect to (deprecated, should use endpoint instead)
        */
        ConnectionOptions::OPTION_TIMEOUT       => 5,
        // timeout in seconds
        //ConnectionOptions::OPTION_TRACE           => $traceFunc,              // tracer function, can be used for debugging
        ConnectionOptions::OPTION_CREATE        => false,
        // do not create unknown collections automatically
        ConnectionOptions::OPTION_UPDATE_POLICY => UpdatePolicy::LAST,
        // last update wins
    );
}

// This function tries to create vertices and edges for the example
function setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection)
{

echo "We are creating 6 vertices...<br> ";
    //create example documents for the vertices
    $nameV1     = 'v1';
    $documentV1 = Document::createFromArray(
        array('name' => $nameV1, '_key' => $nameV1)
    );
    $nameV2     = 'v2';
    $documentV2 = Document::createFromArray(
        array('name' => $nameV2, '_key' => $nameV2)
    );
    $nameV3     = 'v3';
    $documentV3 = Document::createFromArray(
        array('name' => $nameV3, '_key' => $nameV3)
    );
    $nameV4     = 'v4';
    $documentV4 = Document::createFromArray(
        array('name' => $nameV4, '_key' => $nameV4)
    );
    $nameV5     = 'v5';
    $documentV5 = Document::createFromArray(
        array('name' => $nameV5, '_key' => $nameV5)
    );
    $nameV6     = 'v6';
    $documentV6 = Document::createFromArray(
        array('name' => $nameV6, '_key' => $nameV6)
    );

    echo "We are creating 5 edges...<br> ";
    //create example documents for the edges
    $nameE1     = 'e1';
    $documentE1 = Edge::createFromArray(
        array('name' => $nameE1, 'label' => 'child_of')
    );
    $nameE2     = 'e2';
    $documentE2 = Edge::createFromArray(
        array('name' => $nameE2, 'label' => 'child_of')
    );
    $nameE3     = 'e3';
    $documentE3 = Edge::createFromArray(
        array('name' => $nameE3, 'label' => 'child_of')
    );
    $nameE4     = 'e4';
    $documentE4 = Edge::createFromArray(
        array('name' => $nameE4, 'label' => 'child_of')
    );
    $nameE5     = 'e5';
    $documentE5 = Edge::createFromArray(
        array('name' => $nameE5, 'label' => 'child_of')
    );


    // Get instances of the vertice- and edgehandlers
    $documentHandler = new DocumentHandler($connection);
    $edgeHandler     = new EdgeHandler($connection);

    // Save the vertices
    try {
        // query the given $collectionId by example using the previously declared $exampleDocument array
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV1);
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV2);
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV3);
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV4);
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV5);
        $result['v'][] = $documentHandler->save($vertexCollection, $documentV6);
    } catch (Exception $e) {
            // any other error
            echo ('An error occured. Exception: ' . $e);
    }


    // Save the edges
    try {
        echo "$nameV2 is a child of $nameV1<br> ";
        $result['e'][] = $edgeHandler->saveEdge(
            $edgeCollection,
            $vertexCollection . '/' . $nameV2,
            $vertexCollection . '/' . $nameV1,
            $documentE1,
            $options = array()
        );
        echo "$nameV3 is a child of $nameV2<br> ";
        $result['e'][] = $edgeHandler->saveEdge(
            $edgeCollection,
            $vertexCollection . '/' . $nameV3,
            $vertexCollection . '/' . $nameV2,
            $documentE2,
            $options = array()
        );
        echo "$nameV4 is a child of $nameV3<br> ";
        $result['e'][] = $edgeHandler->saveEdge(
            $edgeCollection,
            $vertexCollection . '/' . $nameV4,
            $vertexCollection . '/' . $nameV3,
            $documentE3,
            $options = array()
        );
        echo "$nameV5 is a child of $nameV1<br> ";
        $result['e'][] = $edgeHandler->saveEdge(
            $edgeCollection,
            $vertexCollection . '/' . $nameV5,
            $vertexCollection . '/' . $nameV1,
            $documentE4,
            $options = array()
        );
        echo "$nameV6 is a child of $nameV5<br> ";
        $result['e'][] = $edgeHandler->saveEdge(
            $edgeCollection,
            $vertexCollection . '/' . $nameV6,
            $vertexCollection . '/' . $nameV5,
            $documentE5,
            $options = array()
        );
        echo "<font style='font-family: monospace;'>";
        echo "$nameV1<br> ";
        echo "+ $nameV2<br> ";
        echo "|  + $nameV3<br> ";
        echo "|  |  + $nameV4<br> ";
        echo "+ $nameV5<br> ";
        echo "+ $nameV5<br> ";
        echo "|  + $nameV6<br> ";
        echo "</font>";

        // return the result;
        return $result;
    } catch (Exception $e) {
            // any other error
            echo ('An error occured. Exception: ' . $e);
    }
}


// helper function that takes the connection and the query to execute.
function doAQLQuery($connection, $query)
{
    // query through AQL

    $statement = new \triagens\ArangoDb\Statement($connection, array(
                                                                    "query"     => '',
                                                                    "count"     => true,
                                                                    "batchSize" => 1000,
                                                                    "_sanitize" => true,
                                                               ));
    $statement->setQuery($query);
    $cursor = $statement->execute();

    $result = $cursor->getAll();

    return $result;
}


// AQL query example functions


// Function that gets all paths from vertex v4 to v1
function getPathFromV4ToV1($connection)
{
    $query = 'FOR p IN PATHS(vertices_20130301_01, edges_20130301_01, "outbound")
  FILTER p.source._id == "vertices_20130301_01/v4" && p.destination._id == "vertices_20130301_01/v1"
  RETURN p';

    $result = doAQLQuery($connection, $query);

    return $result;
}

// Function that gets the paths to all descendants of v1

function getPathToAllDescendantsOfV1($connection)
{
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", {
  strategy: "depthfirst",
  minDepth:1,
  paths: true,
  followEdges: [ { label: "child_of" } ]

})
RETURN p
';

    $result = doAQLQuery($connection, $query);

    return $result;
}

// Function that gets the paths to all children of v1
function getPathToChildrenOfV1($connection)
{
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", {
  strategy: "depthfirst",
  maxDepth: 1,
  minDepth:1,
  paths: true,
  followEdges: [ { label: "child_of" } ]

})
RETURN p
';

    $result = doAQLQuery($connection, $query);

    return $result;
}

// Function that gets the paths to all parents of v4
function getPathToParentsOfV4($connection)
{
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", {
  strategy: "depthfirst",
  maxDepth: 1,
  minDepth:1,
  paths: true,
  followEdges: [ { label: "child_of" } ]

})
RETURN p
';

    $result = doAQLQuery($connection, $query);

    return $result;
}

// Function that gets the paths to all ancestor of v4
function getPathToAllAncestorsOfV4($connection)
{
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", {
  strategy: "depthfirst",
  minDepth:1,
  paths: true,
  followEdges: [ { label: "child_of" } ]

})
RETURN p
';

    $result = doAQLQuery($connection, $query);

    return $result;
}

// Function that drops collections given
function dropCollections($connection, $collections)
{
    // register a collection handler to work with the 'users' collection
    $collectionHandler = new CollectionHandler($connection);
    echo "dropping collections...";
    try {
        foreach ($collections as $collection) {
            $collectionHandler->drop($collection);
        }
        echo "dropped.<br>";
    } catch (Exception $e) {
        die ('Could not drop collection. Exception: ' . $e . '<br>');
    }
}

// *********************************************************************************************************************
// Start example code


// register the connection to ArangoDB
$connection = new Connection(getConnectionOptions());


// register a collection handler to work with the 'users' collection
$collectionHandler = new CollectionHandler($connection);


// assign the collection names...
$vertexCollection = 'vertices_20130301_01';
$edgeCollection   = 'edges_20130301_01';

// finally drop the collections...
// remark this line if you want to drop the collections by hand.
dropCollections($connection, array($vertexCollection, $edgeCollection));


// create the vertices and edges collections...
// remark those lines if you want to create the collection by hand.
echo "creating the '$vertexCollection' vertex collection...";
try {
    $collection = new Collection();
    $collection->setName($vertexCollection);
    $collectionHandler->create($collection);
    echo "created.<br>";
} catch (Exception $e) {
    echo ('Could not create collection. Exception: ' . $e . '<br>');
}


echo "creating the '$edgeCollection' edge collection...";
try {
    $collection = new Collection();
    $collection->setName($edgeCollection);
    $collection->setType(3);
    $collectionHandler->create($collection);
    echo "created.<br>";
} catch (Exception $e) {
    echo ('Could not create collection. Exception: ' . $e . '<br>');
}


// setup our vertices and edges....
echo "trying to setup our vertices and edges... <br>";
$result = setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection);


// AQL Examples

// get the path from vertex v4 to v1
$result = getPathFromV4ToV1($connection);
echo "<br>*****************************************<br>";
echo "get all paths from vertex v4 to v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);


// get the paths to all descendants of v1
$result = getPathToAllDescendantsOfV1($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all descendants of v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);

//get the paths to all children of v1
$result = getPathToChildrenOfV1($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all children of v1<br>";
echo "<br>*****************************************<br>";
var_dump($result);


// get the paths to all ancestors of v4
$result = getPathToAllAncestorsOfV4($connection);
echo "<br>*****************************************<br>";
echo "get the paths to all ancestors of v4<br>";
echo "<br>*****************************************<br>";
var_dump($result);

//get all paths to all parents of v4
$result = getPathToParentsOfV4($connection);
echo "<br>*****************************************<br>";
echo "get all paths to all parents of v4<br>";
echo "<br>*****************************************<br>";
var_dump($result);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接