2017-09-22 90 views
2

有没有简单的方法来替换或合并顶点并保持/合并现有边?或者只是手动复制顶点的所有属性,并重新创建现有边和所有(元)属性,然后删除多余的顶点?Tinkerpop/gremlin合并顶点(和边)

+0

你能否详细说明您的使用情况有点?你在谈论进口吗?如果是这样,你如何导入顶点?你正在使用哪个图形数据库? –

+0

我的用例是一个知识图,其中包含来自不同来源的数据。这些数据可以描述相同实体的不同方面。不同的来源并不总是具有这些实体的通用标识符。当有足够的数据时,我可以确定哪些顶点与同一个实体有关,因此我想合并这些顶点(包括它们的顶点)。我使用的数据库应该不重要,但我使用JanusGraph(与Cassandra和Elasticsearch)。 – user3508638

+0

数据库确实重要,否则我不会问。每个数据库都有其自己的额外功能。所以,对于Janus来说,编写一个自定义的顶点程序可能是一个好主意。你如何匹配顶点?您是否使用长时间运行的OLAP作业或OLTP中短暂的作业? –

回答

3

好的,正如上面评论中提到的那样,您将在OLTP中进行匹配。这意味着你可能会有一个具体的切入点。让我们做一个简单的示例图:

g = TinkerGraph.open().traversal() 

// Stackoverflow data 
g.addV("user").property("login", "user3508638").as("a"). 
    addV("user").property("login", "dkuppitz").property("age", 35).as("b"). 
    addV("question").property("title", "Tinkerpop/gremlin merge vertices (and edges)").as("c"). 
    addE("posted").from("a").to("c"). 
    addE("commented").from("b").to("c").property("time", 123).iterate() 

// Github data 
g.addV("user").property("login", "dkuppitz").property("name", "Daniel Kuppitz").as("a"). 
    addV("project").property("title", "TinkerPop").as("b"). 
    addE("contributed").from("a").to("b").iterate() 

要基于登录dkuppitz匹配的顶点,并将它们合并成一个单一的用户顶点:

g.V().has("login", "dkuppitz"). 
    fold().filter(count(local).is(gt(1))).unfold(). 
    sideEffect(properties().group("p").by(key).by(value())). 
    sideEffect(outE().group("o").by(label).by(project("p","iv").by(valueMap()).by(inV()).fold())). 
    sideEffect(inE().group("i").by(label).by(project("p","ov").by(valueMap()).by(outV()).fold())). 
    sideEffect(drop()). 
    cap("p","o","i").as("poi"). 
    addV("user").as("u"). 
    sideEffect(
    select("poi").select("p").unfold().as("kv"). 
    select("u").property(select("kv").select(keys), select("kv").select(values))). 
    sideEffect(
    select("poi").select("o").unfold().as("x"). 
    select("u").sideEffect { u -> 
     u.path("x").getValue().each { x -> 
     def e = u.get().addEdge(u.path("x").getKey(), x.get("iv")) 
     x.get("p").each { p -> 
      e.property(p.getKey(), p.getValue()) 
     } 
     } 
    }). 
    sideEffect(
    select("poi").select("i").unfold().as("x"). 
    select("u").sideEffect { u -> 
     u.path("x").getValue().each { x -> 
     def e = x.get("ov").addEdge(u.path("x").getKey(), u.get()) 
     x.get("p").each { p -> 
      e.property(p.getKey(), p.getValue()) 
     } 
     } 
    }).iterate() 

我知道,查询是疯狂的复杂,​​尤其是与深深嵌套的lambda表达式。但不幸的是,lambda没有办法解决,因为我们没有addE(<traversal>)过载(尽管我创建了ticket)。无论如何,执行上述查询之后,图形看起来像这样:

gremlin> g.V().valueMap() 
==>[login:[user3508638]] 
==>[title:[Tinkerpop/gremlin merge vertices (and edges)]] 
==>[title:[TinkerPop]] 
==>[name:[Daniel Kuppitz],login:[dkuppitz],age:[35]] 
gremlin> g.V().has("login", "dkuppitz").bothE() 
==>e[19][15-commented->5] 
==>e[20][15-contributed->12] 
gremlin> g.V().has("login", "dkuppitz").bothE().valueMap(true) 
==>[label:commented,time:123,id:19] 
==>[label:contributed,id:20] 

两个dkuppitz顶点被合并为一个(nameage性质是存在)和2层的边缘进行了相应的重新创建。

UPDATE:

随着TINKERPOP-1793我们都可以lambda表达式摆脱:

g.V().has("login", "dkuppitz"). 
    fold().filter(count(local).is(gt(1))).unfold(). 
    sideEffect(properties().group("p").by(key).by(value())). 
    sideEffect(outE().group("o").by(label).by(project("p","iv").by(valueMap()).by(inV()).fold())). 
    sideEffect(inE().group("i").by(label).by(project("p","ov").by(valueMap()).by(outV()).fold())). 
    sideEffect(drop()). 
    cap("p","o","i").as("poi"). 
    addV("user").as("u"). 
    sideEffect(
    select("poi").select("p").unfold().as("kv"). 
    select("u").property(select("kv").select(keys), select("kv").select(values))). 
    sideEffect(
    select("poi").select("o").unfold().as("x").select(values). 
    unfold().addE(select("x").select(keys)).from(select("u")).to(select("iv"))). 
    sideEffect(
    select("poi").select("i").unfold().as("x").select(values). 
    unfold().addE(select("x").select(keys)).from(select("ov")).to(select("u"))).iterate()