AbutionGraph诸神图实现

前言

如果做知识图谱的大家都知道janusgraph,neo4j等等,janusgraph图数据库的分布式底层依赖于hbase,性能简直太差了。所以公司一直让我找一款性能比较好,而且上手容易的一款图库。最近在做图数据库的对比,发现了市场一款新概念的图数据仓库,AbutionGraph是通用的HOLAP大数据存储和分析平台,实时大数据图谱式查询分析;

我们以神图demo,做个语法上的对比

图中,对应的类型解释如下:

符号类型

含义

粗体key

图索引键

加粗 加星号的key

图唯一索引键

下划线key

顶点为中心的索引键,vertex-centric index

空心箭头edge

不可重复边,两个节点之间最多只能有一个该类型边

实心箭头edge

单向边,只能A–>B,不可以B–>A

包含类型

主要包含6种节点类型:

  • location:位置(sky:天空,sea:海,tartarus:塔耳塔洛斯)
  • titan:巨人(saturn:罗马神话中的农神)
  • god:神(jupiter,neptune,pluto)
  • demigod:半神(hercules)
  • human:人类(alcmene)
  • monster:怪物(nemean,hydra,cerberus)

主要包含6中边类型:

  • father:父亲
  • mother:母亲
  • brother:兄弟
  • battled:战斗
  • lives:生活在
  • pet:宠物

一.JanusGraph诸神图代码示例

1、获取图管理对象实例

if (graph instanceof StandardJanusGraph) {
            Preconditions.checkState(mixedIndexNullOrExists((StandardJanusGraph)graph, mixedIndexName), 
                    ERR_NO_INDEXING_BACKEND, mixedIndexName);
        }

        // Create Schema
        JanusGraphManagement management = graph.openManagement();

2、创建属性和对应索引

// ===创建name属性; String、唯一CompositeIndex、锁机制保证name的强一致性
        final PropertyKey name = management.makePropertyKey("name").dataType(String.class).make();
        JanusGraphManagement.IndexBuilder nameIndexBuilder = management.buildIndex("name", Vertex.class).addKey(name);
        if (uniqueNameCompositeIndex)
            nameIndexBuilder.unique();
        JanusGraphIndex nameIndex = nameIndexBuilder.buildCompositeIndex();
        // 此处的LOCK,在name索引上添加了LOCK标识,标识这在并发修改相同的name属性时,必须通过锁机制(本地锁+分布式锁)保证并发修改;
        management.setConsistency(nameIndex, ConsistencyModifier.LOCK);

        // ===创建age属性;Integer、mixed index
        final PropertyKey age = management.makePropertyKey("age").dataType(Integer.class).make();
        if (null != mixedIndexName)
            management.buildIndex("vertices", Vertex.class).addKey(age).buildMixedIndex(mixedIndexName);

        // ===创建time属性
        final PropertyKey time = management.makePropertyKey("time").dataType(Integer.class).make();
        // ===创建reason属性
        final PropertyKey reason = management.makePropertyKey("reason").dataType(String.class).make();
        // ===创建place属性
        final PropertyKey place = management.makePropertyKey("place").dataType(Geoshape.class).make();
        // 为reason 和 place属性创建mixed index索引edges
        if (null != mixedIndexName)
            management.buildIndex("edges", Edge.class).addKey(reason).addKey(place).buildMixedIndex(mixedIndexName);

3、创建edge类型和对应索引

// 创建边类型:father, many to one
   management.makeEdgeLabel("father").multiplicity(Multiplicity.MANY2ONE).make();
// 创建边类型:mother, many to one
   management.makeEdgeLabel("mother").multiplicity(Multiplicity.MANY2ONE).make();
// 创建边类型:battled, 签名密匙为time:争斗次数,
   EdgeLabel battled = management.makeEdgeLabel("battled").signature(time).make();
// 为battled边创建一个以顶点为中心的 中心索引(vertex-centric index),索引属性time; 双向索引,可以从 神->怪物 也可以 怪物->神
// 将查询节点对应的 battled 边时,可以使用这个vertex-centric索引,索引属性为 time;
// vertex-centric index为了解决大节点问题,一个节点存在过多的边!
   management.buildEdgeIndex(battled, "battlesByTime", Direction.BOTH, Order.desc, time);
// 创建边类型:lives,签名密匙为reason
   management.makeEdgeLabel("lives").signature(reason).make();
// 创建边类型:pet
   management.makeEdgeLabel("pet").make();
// 创建边类型:brother
   management.makeEdgeLabel("brother").make();

4、创建vertex类型

 // 创建节点label
    management.makeVertexLabel("titan").make();
    management.makeVertexLabel("location").make();
    management.makeVertexLabel("god").make();
    management.makeVertexLabel("demigod").make();
    management.makeVertexLabel("human").make();
    management.makeVertexLabel("monster").make();

5、提交创建的schema数据

 management.commit();

6、插入数据

获取图事务对象:

JanusGraphTransaction tx = graph.newTransaction();

插入节点数据:

 // 插入节点
    Vertex saturn = tx.addVertex(T.label, "titan", "name", "saturn", "age", 10000);
    Vertex sky = tx.addVertex(T.label, "location", "name", "sky");
    Vertex sea = tx.addVertex(T.label, "location", "name", "sea");
    Vertex jupiter = tx.addVertex(T.label, "god", "name", "jupiter", "age", 5000);
    Vertex neptune = tx.addVertex(T.label, "god", "name", "neptune", "age", 4500);
    Vertex hercules = tx.addVertex(T.label, "demigod", "name", "hercules", "age", 30);
    Vertex alcmene = tx.addVertex(T.label, "human", "name", "alcmene", "age", 45);
    Vertex pluto = tx.addVertex(T.label, "god", "name", "pluto", "age", 4000);      
    Vertex nemean = tx.addVertex(T.label, "monster", "name", "nemean");
    Vertex hydra = tx.addVertex(T.label, "monster", "name", "hydra");
    Vertex cerberus = tx.addVertex(T.label, "monster", "name", "cerberus");
    Vertex tartarus = tx.addVertex(T.label, "location", "name", "tartarus");

插入边数据:

// 插入边数据
   jupiter.addEdge("father", saturn);
   jupiter.addEdge("lives", sky, "reason", "loves fresh breezes");
   jupiter.addEdge("brother", neptune);
   jupiter.addEdge("brother", pluto);

   neptune.addEdge("lives", sea).property("reason", "loves waves");
   neptune.addEdge("brother", jupiter);
   neptune.addEdge("brother", pluto);

   hercules.addEdge("father", jupiter);
   hercules.addEdge("mother", alcmene);
   hercules.addEdge("battled", nemean, "time", 1, "place", Geoshape.point(38.1f, 23.7f));
   hercules.addEdge("battled", hydra, "time", 2, "place", Geoshape.point(37.7f, 23.9f));
   hercules.addEdge("battled", cerberus, "time", 12, "place", Geoshape.point(39f, 22f));

   pluto.addEdge("brother", jupiter);
   pluto.addEdge("brother", neptune);
   pluto.addEdge("lives", tartarus, "reason", "no fear of death");
   pluto.addEdge("pet", cerberus);

   cerberus.addEdge("lives", tartarus);

提交事务,持久化数据:

// 提交事务,持久化提交的数据到磁盘
   tx.commit();

二.AbutionGraph实现如下:

1.开启图链接

 Graph graph = G.Graph("god").schema(mkSchema()).build();

2.建模 

Schema schema = Schema.Builder()
    .entity(
        Dimension.label("titan", "太阳神").property("age", Integer.class).build(),
        Dimension.label("god", "上帝").property("age", Integer.class).build(),
        Dimension.label("demigod", "小神").property("age", Integer.class).build(),
        Dimension.label("human", "人类").property("age", Integer.class).build(),
        Dimension.label("monster", "怪物").build(),
        Dimension.label("location", "场景").build())
    .edge(Dimension.label("father", "父亲").build(),
        Dimension.label("brother", "兄弟").build(),
        Dimension.label("mother", "母亲").build(),
        Dimension.label("battled", "战争").property("time", Integer.class)
                .property("place", Geoshape.class).build(),
        Dimension.label("battledAggregation", "战争聚合").property("totalTime", Integer.class, Agg.Sum())
                .groupBy().build(),
        Dimension.label("pet", "宠物").build(),
        Dimension.label("lives", "生活").property("reason", String.class).build())
    .build();

注意:上面建模多了一个战争聚合是AbutionGraph独有的动态图技术,具有自动聚合特性。当指定groupBy()的时候,还需要指定相应聚合的方式,这里才用累加的方式。

3.插入数据

声明一个用户,这个是AbutionGraph独有的权限控制

User user = new User();

插入节点数据

Entity saturn = Knowledge.dimV("titan").vertex("saturn").property("age", 10000).build();
Entity sky = Knowledge.dimV("location").vertex("sky").build();
Entity sea = Knowledge.dimV("location").vertex("sea").build();
Entity jupiter = Knowledge.dimV("god").vertex("jupiter").property("age", 5000).build();
Entity neptune = Knowledge.dimV("god").vertex("neptune").property("age", 4500).build();
Entity hercules = Knowledge.dimV("demigod").vertex("hercules").property("age", 30).build();
Entity alcmene = Knowledge.dimV("human").vertex("alcmene").property("age", 45).build();
Entity pluto = Knowledge.dimV("god").vertex("pluto").property("age", 4000).build();
Entity nemean = Knowledge.dimV("monster").vertex("nemean").build();
Entity hydra = Knowledge.dimV("monster").vertex("hydra").build();
Entity cerberus = Knowledge.dimV("monster").vertex("cerberus").build();
Entity tartarus = Knowledge.dimV("location").vertex("tartarus").build();
//单条插入
graph.addKnowledge(saturn).exec(user);
//批量插入
graph.addKnowledge(sky,sea,jupiter,neptune,hercules,alcmene,pluto,nemean,hydra,cerberus,tartarus).exec(user);

插入边数据

//jupiter relation
Edge eg = Knowledge.dimE("father").edge("jupiter", "saturn").build();
Edge eg1 = Knowledge.dimE("lives").edge("jupiter", "sky").property("reason", "loves fresh breezes").build();
Edge eg2 = Knowledge.dimE("brother").edge("jupiter", "neptune").build();
Edge eg3 = Knowledge.dimE("brother").edge("jupiter", "pluto").build();

//neptune relation
Edge eg4 = Knowledge.dimE("lives").edge("neptune", "sea").property("reason", "loves waves").build();
Edge eg5 = Knowledge.dimE("brother").edge("neptune", "jupiter").build();
Edge eg6 = Knowledge.dimE("brother").edge("neptune", "pluto").build();

//hercules relation
Edge eg7 = Knowledge.dimE("father").edge("hercules", "jupiter").build();
Edge eg8 = Knowledge.dimE("mother").edge("hercules", "alcmene").build();
Edge eg9 = Knowledge.dimE("battled").edge("hercules", "nemean").property("time", 1).property("place", Geoshape.point(38.1,23.7)).build();
Edge eg10 = Knowledge.dimE("battled").edge("hercules", "hydra").property("time", 2).property("place", Geoshape.point(37.7, 23.9)).build();
Edge eg11 = Knowledge.dimE("battled").edge("hercules", "cerberus").property("time", 12).property("place", Geoshape.point(39,22)).build();

//pluto relation
Edge eg12 = Knowledge.dimE("brother").edge("pluto", "jupiter").build();
Edge eg13 = Knowledge.dimE("brother").edge("pluto", "neptune").build();
Edge eg14 = Knowledge.dimE("lives").edge("pluto", "tartarus").property("reason", "no fear of death").build();
Edge eg15 = Knowledge.dimE("pet").edge("pluto", "cerberus").build();

//cerberus relation
Edge eg16 = Knowledge.dimE("lives").edge("cerberus", "tartarus").build();

List<Edge> elements = Lists.newArrayList(eg, eg1, eg2, eg3, eg4, eg5, eg6, eg6, eg7, eg8, eg9, eg10, eg11, eg12, eg13, eg14, eg15, eg16);

4.提交数据

 AddKnowledge addKnowledge = new AddKnowledge.Builder().input(elements).build();
 graph.execute(addKnowledge, user);

注意:看到提交数据的时候创建了一个user对象,这个AbutionGraph独有的权限管理,这里不深入展开,如果想了解更多点我

三.janusGraph和AbutionGraph诸神图对比

1.建模

Janusgraph:需要单独点和边以及指定属性的索引

AbutionGraph:在维度上自动建立了索引,不需要单独指定,同时支持自定义id。可以通过正则等模糊匹配到vertex。

2.插入数据

JanusGraph:支持批量实时导入数据,但是仅支持小量的数据。

AbutionGraph:既支持单条插入,同时也支持多条插入。如果是聚合的属性,普通的插入即可,数据库会自动进行聚合。支持大量的数据实时导入。

性能对比请查看

3.语法对比

gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn

gremlin> g.V().has('name', 'hercules')
==>v[24]  //返回的是id

gremlin> g.V().has('name', 'hercules').out('father')
==>v[16]
gremlin> g.V().has('name', 'hercules').out('father').out('father')
==>v[20]
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
gremlin> g.V().has('name', 'hercules').values('name')
==>hercules
gremlin> g.V().has('name', 'hercules').out('father').values('name')
==>jupiter
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
请注意下面的遍历显示了'hercules'的整个父系树分支。提供这种复杂的遍历是为了展示Gremlin语言的灵活性和表现力。对Gremlin的熟练掌握为JanusGraph用户提供了流畅地获取Janusgraph图形结构的能力。

gremlin> g.V().has('name', 'hercules').repeat(out('father')).emit().values('name')
==>jupiter
==>saturn

下面提供了一些更多的遍历示例。

gremlin> hercules = g.V().has('name', 'hercules').next()
==>v[1536]
gremlin> g.V(hercules).out('father', 'mother').label()
==>god
==>human
gremlin> g.V(hercules).out('battled').label()
==>monster
==>monster
==>monster
gremlin> g.V(hercules).out('battled').valueMap()
==>{name=nemean}
==>{name=hydra}
==>{name=cerberus}
添加语法:
gremlin> theseus = graph.addVertex('human')
==>v[3328]
gremlin> theseus.property('name', 'theseus')
==>null
gremlin> cerberus = g.V().has('name', 'cerberus').next()
==>v[2816]
gremlin> battle = theseus.addEdge('battled', cerberus, 'time', 22)
==>e[7eo-2kg-iz9-268][3328-battled->2816]
gremlin> battle.values('time')
==>22

AbutionGraph:

//查询所有点
jshell> var exec = g.V().exec(user);
==> [Entity[vertex=hercules,dimension=demigod,properties=Properties[age=<java.lang.Integer>30]], Entity[vertex=hydra,dimension=monster,properties=Properties[]], Entity[vertex=cerberus,dimension=monster,properties=Properties[]], Entity[vertex=nemean,dimension=monster,properties=Properties[]], Entity[vertex=saturn,dimension=titan,properties=Properties[age=<java.lang.Integer>10000]], Entity[vertex=sky,dimension=location,properties=Properties[]], Entity[vertex=tartarus,dimension=location,properties=Properties[]], Entity[vertex=sea,dimension=location,properties=Properties[]], Entity[vertex=jupiter,dimension=god,properties=Properties[age=<java.lang.Integer>5000]], Entity[vertex=neptune,dimension=god,properties=Properties[age=<java.lang.Integer>4500]], Entity[vertex=pluto,dimension=god,properties=Properties[age=<java.lang.Integer>4000]], Entity[vertex=alcmene,dimension=human,properties=Properties[age=<java.lang.Integer>45]]]

//查询年龄小于50的顶点
jshell> var exec = g.V().dims().has("age").by(P.LessThan(50)).exec(user);
==> [Entity[vertex=hercules,dimension=demigod,properties=Properties[age=<java.lang.Integer>30]], Entity[vertex=alcmene,dimension=human,properties=Properties[age=<java.lang.Integer>45]]]

//查询年龄小于50并且维度是human的顶点
jshell> var exec = g.V().dim("human").has("age").by(P.LessThan(50)).exec(user);
==>[{"class":"cn.thutmose.abution.graph.data.knowhow.Entity","dimension":"human","vertex":"alcmene","properties":{"age":45}}]

//查询 hercules 的一度顶点id
jshell> var exec = g.V("hercules").Out().exec(user);
==> [nemean, cerberus, hydra, jupiter, alcmene]

//查询 hercules 的爸爸
jshell> var exec = g.V("hercules").Out().dim("father").exec(user);
==> [jupiter]

//查询 hercules 的爸爸的爸爸

jshell> var exec = g.V("hercules").Out().dim("father").Out().dim("father").exec(user);
==> [saturn]

//查询 hercules的爸爸的爸爸另一种写法

jshell> var exec1 = g.V("hercules").While().gql(G.GetNeighborIds().ToSet().ToEntityIds().Out().dim("father").getChain()).maxRepeats(2).exec(user);
==> [{"class":"cn.thutmose.abution.graph.data.knowhow.id.EntityKey","vertex":"saturn"}]

四.总结

1.语法方面:janusGraph使用了gremlin语言,abutionGraph使用了类似gremlin的语法。语法比较相似,风格也差不多。好处是AbutionGraph支持原子级别的权限,上手还是比较简单。

2.性能方面:我从AbutionGraph官方文档上看性能是吊打JanusGraph,由于目前还是在写demo看是否容易上手,接下来会对AbutionGraph进行性能测试。

如果你也是正在使用AbutionGraph希望您和我一样少走弯路,多多交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值