Как использовать базу данных графа для распространения репутации?

У меня есть проблема, которая, кажется, хорошо подходит для графической базы данных, но я не уверен, как лучше ее применить.

Во-первых, есть набор объектов, которые могут иметь направленные ссылки (несколько десятков миллионов из них, типичное число входных / выходных ссылок составляет несколько тысяч на объект). Затем каждый объект может накапливать репутацию (например, повышенную оценку, карму и т. Д.) У потенциально очень большого числа пользователей (также десятков миллионов).

Сложность в том, что всякий раз, когда пользователь корректирует репутацию объекта, я хотел бы обновить репутацию всех связанных с ним объектов (возможно, за пределами первой степени) на основе некоторых довольно сложных правил.

В SQL это будет выглядеть примерно так:

CREATE TABLE objects (id INTEGER PRIMARY KEY);
CREATE TABLE object_links (from_object_id INTEGER, to_object_id INTEGER);
CREATE TABLE users (id INTEGER PRIMARY KEY);
CREATE TABLE object_reputations (object_id INTEGER, user_id INTEGER, reputation FLOAT);

UPDATE
    object_reputations
SET
    object_reputations.reputation = object_reputations.reputation + ... # some formula goes here
FROM
    object_reputations
    INNER JOIN object_links
        ON object_reputations.object_id = object_links.to_object_id
WHERE
    object_links.from_object_id = ...;

Поскольку речь идет о графике, графическая база данных может показаться естественной, но из краткого прочтения API Neo4j / OrientDB / Blazegraph / Tinkerpop я не могу понять, как сопоставить эту проблему с тем, что они могут сделать вообще.

Используя Tinkerpop в качестве примера, объекты - это вершины, связи между объектами - это края (пока все хорошо), а репутация...? Возможно, VertexPropetries, но я не уверен, как все будет масштабироваться с потенциально большим количеством свойств на вершину, чем у пользователей. Или, возможно, репутация - это взвешенные ребра от пользовательских вершин... которые, похоже, имеют проблемы с производительностью другого рода.

Можете ли вы дать простой перевод проблемы такого рода в одну из популярных графовых баз данных?

2 ответа

Я бы сказал, что это действительно зависит от того, как вы хотите запросить ваши данные. Репутация также может быть вершиной, если она имеет конечное число значений и значения повторяются среди пользователей. Например, если это число от 1 до 10, тогда все пользователи, имеющие репутацию 7, могут ссылаться на эту вершину. Эта модель позволит вам начать запрос с вершины и легко найти всех пользователей с такой репутацией. Используя Гремлин, это будет примерно так.

g.V().has(label,"reputation").has("reputation","7").in()

Это вернуло бы все вершины, которые связаны с вершинами репутации с репутацией "7".

В качестве альтернативы вы также можете иметь репутацию свойства и искать все вершины с таким свойством.

g.V().has("reputation","7")

Количество свойств не должно быть проблемой. Titan рекомендует индексировать свойства, которые вы хотите запросить, что значительно улучшает поиск

Вы хотите всегда пытаться визуализировать запросы к графическим данным без использования больших таблиц (в основном, все, что больше, чем 2 или 3 свойства на вершину, должно использоваться почти исключительно для хранения данных, а не для запросов). Если вы не можете изменить такие сложные данные, чтобы они представлялись более длинным путем между вершинами, то они, вероятно, принадлежат реляционной базе данных.

Однако для таких перспективных данных, как ваша, неплохо подойдет графическая база данных. Вместо того чтобы хранить все ориентированные на пользователя репутации в качестве свойств объекта, переместите их на отдельные узлы, прикрепленные к объекту, чтобы их можно было превратить в часть пути от пользователя к объекту.

Итак, у вас есть вершина для пользователя, вершина для объекта, и у каждого есть ребро для третьей вершины, ObjectReputation. Каждый объект будет иметь несколько смежных вершин ObjectReputation (по одной на каждого пользователя, связанного с объектом), но существует только один путь по краям от любого пользователя к любому объекту. Чтобы найти связанные ObjectReputations, вы можете перемещаться вдоль ребер от пользователя к объекту, перемещаться по ребрам между объектами, а затем переходить назад от этих объектов через вершины UserReputation к исходному пользователю.

В neo4jЭто язык запросов Cypher, это будет выглядеть примерно так:

MERGE (u:User {id:1})
MERGE (o:Object {id:2})
MERGE (u) - [:KNOWS] -> (ur:ObjectReputation) - [:KNOWS] -> (o)
SET ur.score = 100
MATCH (o) - [:RELATED_TO*] - (:Object) <- [:KNOWS] - (related_ur:ObjectReputation) <- [:KNOWS] - (u)
SET related_ur.score = related_ur.score * 1.2
Другие вопросы по тегам