标记系统的关系数据库中的图形结构

时间:2020-06-15 07:59:27

标签: mysql sql graph-theory tagging

我正在使用MySQL 5.5.50

我正在尝试建立一个用于对博客进行标记和交叉引用的系统。

这些表的当前结构如下(大致):

    blog_table

    | id | blog        |
    | :- | :---------- |
    | 1  | Lorum Ipsum |
    | 2  | Lorum Ipsum |
    | 3  | Lorum Ipsum |
    tag_table
    | id | tag     |
    | :- | :------ |
    | 1  | Cats    |
    | 2  | Dogs    |
    | 3  | Animals |
    | 4  | Funny   |
    | 5  | Serious |
    tag_blog_table
    | id | tag_id | blog_id |
    | :- | :----- | :------ |
    | 1  | 1      | 1       |
    | 2  | 2      | 1       |
    | 3  | 4      | 1       |
    | 4  | 4      | 2       |
    | 5  | 5      | 3       |

从理论上讲,这是可行的。但是,现在我想交叉引用标签并将其分组。

例如,CatsDogsAnimals。因此,如果我想要所有“有趣的动物”博客,它将使用CatsDogsFunny来创建所有博客。此外,如果我添加了Non-Human标签,则可以将AnimalsNon-Human(如果存在)交叉引用/分组为Plants,等等。

我意识到要正确执行此操作,我需要一个图形数据库,因为上述关系实际上是标签(即顶点)的分组(即边)。但是我有这个关系数据库。

到目前为止,我唯一想出的解决方案是制作一个名为tag_tag_table的第四张表,它使我能够在每个“顶点”(标记)之间创建“ edges”。然后在服务器上遍历“图形”。该表如下所示:

    tag_tag_table
    | id | from_tag_id | to_tag_id |
    | :- | :---------- | :-------- |
    | 1  | 1           | 3         |
    | 2  | 2           | 3         |
    | 3  | 6           | 1         |
    | 4  | 7           | 2         |
    | 5  | 8           | 7         |

然后在PHP中(服务器正在运行):

// this is an example,
// the code isn't perfect
function traverse($start_id) {
    global $pdo_link;

    $final_ids = [];

    $traverse_stmt = $pdo_link->prepare(
        "SELECT `to_tag_id`
        FROM tag_tag_table
        WHERE `from_tag_id` = ?;"
    );

    $cyclic_check = [];

    // In this case, I a doing a
    // Breadth-First-Traverse.
    $traverse_queue = new SplQueue;
    $traverse_queue->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE);
    $traverse_queue->enqueue($start_id);

    foreach ($traverse_queue as $id) {
        // Prevent cyclic loops
        // NOTE: This might need to be
        // put at the end of the statement,
        // that's not fully tested.
        if (array_search($id, $cyclic_check) !== false) continue;
        else $cyclic_check[] = $id;

        // Look for any adjacent vertices
        $traverse_stmt->execute([$id]);
        $next_ids = $traverse_stmt->fetchAll(PDO::FETCH_COLUMN);

        // If there are adjacent vertices, enqueue them.
        // Else, we've reached an end.
        if (count($next_ids)) foreach ($next_ids as $next_id) $traverse_queue->enqueue($next_id);
        else $final_ids[] = $id;
    }

    $blog_lookup_tag_id_placeholders = implode(', ', array_map(function($tag_id) {
        return '?';
    }));

    $blog_lookup_stmt = $pdo_link->prepare(
        "SELECT `blog_id`
        FROM tag_blog_table
        WHERE `tag_id` IN ($blog_lookup_tag_id_placeholders);"
    );
    $blog_lookup_stmt->execute($final_ids);
    return $blog_lookup_stmt->fetchAll(PDO:FETCH_ASSOC);
}

我目前看到的两个缺点是:

  1. Blogs完全在“图形”之外。您必须将博客链接到至少一个标签。也许这实际上是完全正确的...

  2. 严格来说,这不是在数据库中运行的查询,它需要服务器遍历“边缘”和“顶点”。

我正在尝试找到更好的解决方案来完成此标记系统。

0 个答案:

没有答案
相关问题