Хранение промежуточных значений в графе
Я пытаюсь понять лучшие практики представления линии данных в виде графа (в частности, DAG) и хранения значений в нечто вроде neo4j.
Например, у меня есть конвейер многоэтапной обработки - механизм рекомендаций с различными входными значениями, промежуточными значениями и итоговым результатом. Я хотел бы представить историю любого данного счета в качестве компонентов его предыдущих значений, каждый узел представляет чистую функцию.
База данных графа не будет нести ответственность за сами вычисления, а только за представление входных данных для каждой чистой функции, представленной узлом. Давайте предположим, что некоторые узлы вычислительно дороги для вычисления, поэтому сохранение промежуточных значений имеет смысл. При изменении любого значения в графе дочерние узлы могут быть помечены как устаревшие для некоторого процесса, чтобы пересчитать их асинхронно.
Для тех, кто видел эту архитектуру, каковы некоторые лучшие практики, окружающие этот подход, и является ли база данных графов подходящим местом для хранения этих зависимостей данных?
2 ответа
Да, графическая база данных структурно отражает DAG и является идеальным местом для хранения, как вы описали. Что касается лучших практик, это зависит от того, какая база данных. Neo4j является направленным графом свойств, и вы можете назначать свойства и значения узлам и отношениям ("вершины" и "ребра" в графе-языке).
Таким образом, для вашего конвейера хорошей первой ставкой будет то, что каждый узел представляет функцию и может включать в себя такие свойства, как идентификатор и версию функции, время выполнения, конфигурацию сервера и т. Д.
Каждое отношение представляет сообщение от одной функции к другой. У вас есть выбор, и какой путь вы выберете, зависит от запросов. Основываясь на вашем описании, я мог бы сохранить значения входных и выходных параметров в функции. Но вы также можете описать их как полезную нагрузку отношений. Последнее является более точным представлением конвейера, но потребует некоторой несогласованности, если вам нужно сохранить ваш конечный результат.
Когда мне приходилось наматывать что-то подобное, я добавлял столбец dateUpdated в свою базу данных, чтобы сделать это очевидным при обновлении. Затем вы можете просмотреть список дочерних узлов, чтобы убедиться, что дочерний элемент всегда обновлялся после его родительского элемента. Я предполагаю, что:
- У вас всегда есть DAG
- Топология не меняется
затем вы можете один раз разделить график на непересекающиеся сегменты (по одному разу) внутри каждого сегмента - собрать все корни в кучу и обработать каждый корень и его дочерние элементы, обновляя столбец dataUpdated по мере необходимости для обновления узла.
Если вы хотите сохранить полную историю, сделайте INSERT, когда вы "обновите" dateUpdated (скопируйте все, что не изменилось, установите dateUpdated = NOW.) Если вы хотите представить только текущее обработанное состояние, выполните UPDATE.
Одна из проблем, связанных с выполнением UPDATE, заключается в том, что если у вас есть другие процессы, читающие эти данные, у вас может быть условие гонки, при котором вы обновляете родительский элемент, читаете неотобновленный дочерний элемент и получаете устаревшее значение. Другой подход заключается в том, что вы на самом деле не возвращаете значение до тех пор, пока все дочерние элементы не обновят времена, превышающие их родительские значения (или какие-либо входные данные в вашей функции.) Если вы выполняете INSERT, тогда дочерние узлы не будут существовать, пока они обрабатываются, но вам придется обрабатывать случай, когда вы запрашиваете узел, который не существует из-за перестройки, по сравнению со случаем, когда вы запрашиваете узел, который просто не существует.
Если топология изменится, вам, вероятно, потребуется применить ограничение DAG, а затем выполнять разбиение каждый раз.
Итак, я думаю, что этот вид зависит от того, какую историю вы хотите сохранить (полная история или история предварительно вычисленных значений) и как топология вашего графа изменяется со временем.
Я довольно хорошо разбираюсь в трех из четырех добавленных вами тегов, но ничего не знаю о neo4j, поэтому извините, если там уже есть структура данных для этого. Также всегда кажется, что должна быть какая-то система баз данных, которая может хранить данные по мере их изменения, в разных ревизиях, но я всегда возвращаюсь к дате обновления с MySQL...