Gremlin合并顶点时如何将重名属性值存为列表并保留所有出入边
问题说明
我需要合并顶点,同时保留其入边、出边以及全部属性。我参考了相关技术方案,它几乎完全符合我的预期,但当两个待合并顶点存在同名属性时,最终生成的合并顶点仅会保留其中一个属性值。我希望能将同名的多个属性值存储为列表,与为已存在对应属性的顶点添加属性时的默认行为一致。
示例场景:
g.V().has("author","book_id", 987).fold(). coalesce(unfold(), addV("author").property("book_id", 987)) g.V().hasLabel("author").has("book_id",987).property("author_id",123) g.V().has("author","book_id", 654).fold(). coalesce(unfold(), addV("author").property("book_id", 654)) g.V().hasLabel("author").has("book_id",654).property("author_id",123)
执行以上4条查询后,会得到2个author_id=123的顶点。我使用如下查询合并这两个顶点:
g.V().has("author", "author_id", 123).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("author").as("a"). sideEffect( select("poi").select("p").unfold().as("kv"). select("a").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("a")).to(select("iv"))). sideEffect( select("poi").select("i").unfold().as("x").select(values). unfold().addE(select("x").select(keys)). from(select("ov")).to(select("a"))).iterate()
执行后确实得到了预期的单个顶点,但查询其valueMap可知,book_id属性仅保留了一个值:
{'book_id': [654], 'author_id': [123]}
我要如何操作才能保留两个book_id的值,得到如下结果:
{'book_id': [654,987], 'author_id': [123]}
解决方案
问题根源是原查询的属性分组阶段仅保留了每个属性键的单个值,只需修改两处逻辑即可实现需求:
修正后的完整合并查询
g.V().has("author", "author_id", 123).fold().filter(count(local).is(gt(1))).unfold(). sideEffect(properties().group("p").by(key).by(value().fold())). 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("author").as("a"). sideEffect( select("poi").select("p").unfold().as("kv"). select("kv").select(values).unfold().as("v"). select("a").property(select("kv").select(keys), select("v"))). sideEffect( select("poi").select("o").unfold().as("x").select(values). unfold().addE(select("x").select(keys)). from(select("a")).to(select("iv"))). sideEffect( select("poi").select("i").unfold().as("x").select(values). unfold().addE(select("x").select(keys)). from(select("ov")).to(select("a"))).iterate()
关键修改说明
- 将原查询中
sideEffect(properties().group("p").by(key).by(value()))里的.by(value())替换为.by(value().fold()):这一步会把所有待合并顶点的同名属性值收拢为列表,避免仅保留最后一个值。 - 调整属性写入逻辑:原逻辑直接把收拢后的列表作为单个值传入
property(),修改后先把列表展开为单个值逐个写入,和Gremlin给顶点追加属性的默认行为一致,同名属性会自动存储为列表格式。
执行修改后的查询后,再查询新顶点的valueMap即可得到预期结果。
内容的提问来源于stack exchange,提问作者Amitay Dror
相关产品推荐
相关产品推荐

