У меня есть сайт, написанный на PHP. В настоящее время он использует MySQL для всех нужд своей базы данных (я открыт для дополнительных технологий БД).
Содержание системы взаимосвязано. Эти отношения могут быть представлены в виде графа, где вершины являются частями контента, а ребра - отношениями. Мне нужно иметь возможность пройти этот график. В частности мне нужно уметь:
- Получить количество детей на заданной глубине (например, сколько внуков имеет предмет)
- Получить совокупное количество детей на заданной глубине (например, сколько детей и внуков имеет предмет)
- Получить максимальную глубину для данного корня (например, какой самый длинный путь из этого элемента)
- Получить детей на заданной глубине (например, кто внуки этого предмета)
- Получить родителей на заданной глубине (например, кто является бабушкой и дедушкой этого элемента)
- Посмотрите, какие статусы (такие как «скрытый» или «заблокированный») были унаследованы от родителей.
Поскольку это график в динамической системе, а не дерево или традиционная иерархия, есть некоторые сложности, которые, как мне кажется, исключают обычные трюки на основе SQL (например, список смежности и перечисление пути).
Основные тонкости:
Контент может иметь более одного ребенка.
Контент может иметь более одного родителя.
График отношений элемента может отличаться для каждого пользователя. Например, определенный контент может быть скрыт для одного человека, но не для другого.
Элементы могут появляться более одного раза в дереве графиков и могут появляться с разной длиной пути (например, элемент 50 может быть непосредственным дочерним элементом, а также дочерним элементом 3-го поколения).
Графики могут содержать сотни тысяч элементов.
Некоторые дополнительные сложности:
Различные типы контента могут быть связаны (например, опрос может быть связан с сообщением на форуме, или пользователь может быть связан с сообществом)
Существует несколько различных типов отношений (например, отношения между родителями и детьми, отношения собственности, отношения между сверстниками)
В зависимости от типа отношений, разрешения и ограничения могут передаваться или не передаваться от родителя к потомку (например, если родитель скрыт, дочерний объект также будет скрыт, но если скрытый элемент скрыт, статус не передается)
Мои наивные (медленные) "решения"
В настоящее время я использую наивный подход с использованием SQL. У меня есть одна таблица «Отношения» с этими столбцами:
item1ID (int)
item1TypeID (int)
item2ID (int)
item2TypeID (int)
relationshipTypeID (int)
В PHP я динамически генерирую запросы, полные внутренних самообъединений, чтобы найти максимальную глубину, а затем, когда это выясняется, я генерирую один запрос, который пересекает иерархию и извлекает всю необходимую информацию. Это уже слишком медленно, даже при правильной индексации.
Моим вторым наивным подходом было перенести этот обход и поиск в глубину в хранимые процедуры. Я понятия не имею, приведет ли это к значительному улучшению скорости. Я также думал о том, чтобы включить какой-то механизм кэширования, чтобы избежать частого просмотра максимальной глубины, но похоже, что это просто позволяет избежать реальной проблемы.
Мой вопрос
Должен быть лучший способ. Что это? Я знаю, что на StackOverflow уже есть много вопросов и ответов, касающихся проблемы иерархической информации в SQL, но это не совсем иерархия - это полноценный график.
Поскольку у меня есть сильные модели, я могу смешать другую технологию БД, чтобы обрабатывать аспекты отношений, не разрушая существующую базу кода. Я изучал NoSQL-решения, но практически ничего о них не знаю. Я также слышал о «Графических базах данных» (таких как Neo4J), которые, исходя из названия и различных слайдов PowerPoint, которые я видел, звучат именно так, как мне нужно. Тем не менее, я не знаю, какие из них на самом деле достаточно устойчивы, или какие из них будут хорошо работать с PHP.
Помоги мне, StackOverflow, ты моя единственная надежда.