0

我有一个似乎很适合图形数据库的问题,但我不确定应用它的最佳方法。

首先,有一组对象可以有定向链接(几千万个,典型的链接输入/输出数是每个对象几千个)。然后,每个对象都可以从潜在的非常多的用户(也有数千万)那里积累声誉(想想赞成票、业力等)。

棘手的部分是,每当用户调整对象的声誉时,我想根据一些相当复杂的规则更新其所有链接对象的声誉(可能超过一级)。

在 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 = ...;

由于这是处理图形,图形数据库似乎很合适,但是通过快速阅读 Neo4j / OrientDB / Blazegraph / Tinkerpop API,我无法弄清楚如何将这个问题映射到他们可以解决的问题上做。

以 Tinkerpop 为例,对象是顶点,对象之间的链接是边(到目前为止一切都很好),声誉是......?可能是 VertexPropetries,但我不确定每个顶点的属性可能与用户数量一样多,事情将如何扩展。或者,声誉可能是来自用户顶点的加权边缘......这似乎有不同类型的性能问题。

您能否将此类问题简单翻译成流行的图形数据库之一?

4

2 回答 2

2

我会说这真的取决于如何查询您的数据。如果信誉具有有限数量的值并且这些值在用户之间重复,则它也可以是一个顶点。例如,如果它是一个从 1 到 10 的数字,那么我们可以让所有信誉为 7 的用户都链接到该顶点。此模型将允许您从顶点开始查询并轻松找到所有具有该声誉的用户。使用 Gremlin,它会是这样的。

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

这将返回与信誉为“7”的信誉顶点相关联的所有顶点。

或者,您也可以拥有作为属性的声誉,并且可以查找具有此类属性的所有顶点。

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

属性的数量应该不是问题。Titan 建议您索引要查询的属性,这会大大改善查找

于 2016-09-19T19:44:54.187 回答
1

您希望始终尝试在不使用任何大表的情况下可视化图形数据查询(基本上,每个顶点超过 2 或 3 个属性应该几乎专门用于数据存储,而不是查询)。如果您不能将如此复杂的数据更改为由顶点之间的更长路径表示,那么它可能属于关系数据库。

但是,对于像您这样的基于“透视”的数据,图形数据库非常适合。但是,不要将所有面向用户的信誉作为属性存储在对象上,而是将它们移动到附加到对象的单独节点上,以便它们可以变成从用户到对象的路径的一部分。

因此,您有一个用户的顶点,一个对象的顶点,并且每个顶点都有一个到第三个顶点的边,即 ObjectReputation。每个对象将有几个相邻的 ObjectReputation 顶点(与该对象相关的每个用户都有一个),但是从任何用户到任何对象的边缘只有一条路径。要查找相关的 ObjectReputation,您可以沿着从 User 到 Object 的边导航,沿着 Object 之间的边导航,然后通过 UserReputation 顶点从这些 Object 导航回原始 User。

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
于 2016-09-19T19:33:37.357 回答