Schema 和 DataModeling

每个JanusGraph 的图都有一个schema包含了边的label,属性的key,顶点的label。一个JanusGraph的schema可以被显式或者隐式的被定义。我们鼓励用户在程序开发的时候显式的定义graph schema。一个显式定义的schema是一个鲁棒的图程序的基础,并且有利于协同开发。需要注意的是,JanusGraph schema可以被跟新,不需要打断数据库操作。扩展schema不会降低查询时间,而且不需要停机。

Schema类型,边的label,属性的key,顶点的label都是被分配到图上的相关的元素上的。当它们第一次被创建后,就不能改变了。这样的强类型保证了以后推理。

除了schema的定义选项,schema里还提供了性能调优的配置。

定义边的Labels

每个边链接两个顶点。并且有一个label来定义这个链接的关系。比如,一个label为friend的边连接了A和B,那么表明A和B之间是朋友关系。

通过在一个打开的graph或者一个management transaction调用makeEdgeLabel(String)方法,传入label的名字来定义边的label。边的label在图的定义里必须是唯一的。这个方法返回一个builder,通过这个builder可以定义边的重复性。multiplicity。他限定了两个顶点之间这种label的边的个数。可以设置的为:
1. MULTI:任意个
2. SIMPLE:每两个顶点之间最多一个这种label的边
3. MANY2ONE:多对一,多个进入边,一个出边
4. ONE2MANY:一对多,一个进边,多个出边
5. ONE2ONE:最多只有一个连入和一个连出的用这个label的边。MarriedTo就是一个典型的ONE2ONE。如果MarriedTo是一个SIMPLE关系的话,那就存在A既和B是夫妻,A和C也是夫妻的情况。

默认的mulitiplicity关系是MULTI。边的label的定义是通过调用make()方法来完成的。

mgmt = graph.openManagement()
follow = mgmt.makeEdgeLabel('follow').multiplicity(MULTI).make()
mother = mgmt.makeEdgeLabel('mother').multiplicity(MANY2ONE).make()
mgmt.commit()

定义属性的key

顶点和边的属性是key-value对。比如,对于属性property name=”Daniel” ,它的key是name,value是Daniel。属性的key是JanusGraph schema的一部分。可以约束允许的数据类型和值得基数。

可以通过调用makePropertyKey(string)来定义一个属性的key。属性值的key必须是整个图里唯一的。建议不要用空格和特殊字符。这个方法返回一个property key的builder。

属性值的数据类型

通过dataType(Class)来定义一个property key的数据类型。JanusGraph会用这个数据类型来对数据进行约束。比如约束名字这个属性的类型是String。

可以通过定义类型为Object.class来允许任意类型的值被赋给这个属性。数据类型必须是具体的类,不能是接口或者抽象类。JanusGraph必须严格类的相等,用子类来给父类的属性赋值是不被允许的。

JanusGraph天然支持下边的数据类型:
String,Character,Boolean,Byte,Short,Integer,Long,Float,Double,Date,Geoshape,UUID

属性基数

可以使用cardinality(Cardinality)来定义允许的顶点属性的值。
支持的基数设置:
1. SINGLE:对于这种属性的key,只能有一个对应的value。
2. LIST:对一个key可以有任意多个值,值可以重复
3. SET:对一个key可以有多个值,但是不能有重复值

默认的基数设置是SINGLE。对于边和顶点都一样。

mgmt = graph.openManagement()
birthDate = mgmt.makePropertyKey('birthDate').dateType(Long.class).cardinality(Cardinality.SINGLE).make()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(Cardinality.SET).make()
sensorReading = mgmt.makePropertyKey('sensorReading').dataType(Double.class).cardinality(Cardinality.LIST).make()
mgmt.commit()

关系类型

边的label和属性key共同被称为关系类型。关系类型的名字在图里必须是唯一的,意味着属性的key和边的label不能重名。JanusGraph里有方法可以查询已经存在的关系类型或者根据属性的key和边的label来检索关系类型。

mgmt=graph.openManagement()
if(mgmt.containsRelationType('name'))
    name=mgmt.getPropertyKey('name')
mgmt.getRelationTypes(EdgeLabel.class)
mgmt.commit()

定义顶点的Label

就像边,顶点也有label,不像边的label,顶点的label是可以选的。顶点的label可以帮忙区别不同类型的顶点。比如用户顶点和商品顶点。

尽管对于顶点的label是可选的,JanusGraph内部在你不指明Label的时候还是给每个顶点赋值了默认的label。

可以通过调用makeVertexLabel(String).make()来创建一个顶点label。顶点label的名字在整个图里必须唯一。

mgmt = graph.openManagement()
person = mgmt.makeVertexLabel('persion').make()
mgmt.commit()

person = graph.addVertex(label,'person')
v = graph.addVertex()
graph.tx().commit()

自动的Schema生成

如果一个边的label,属性的key,或者顶点的label没有被明确定义。它会在添加边,顶点,或者定义属性时首次被使用时被隐式的定义。DefaultSchemaMaker配置了JanusGraph的这些类型。

默认情况下,隐式创建的边的label的multiplicity是MULTI,property key的基数是SINGLE。数据类型是Object.class。用户可以控制自动的schema生成,通过自己实现和注册他们自己的DefaultSchemaMaker。

强烈建议显式的定义所有的schema元素,并且关掉自动schema创建,关闭的办法是在JanusGraph的配置里设置schema.default=none。

修改Schema元素

对于边的label,属性的key,或者顶点的label一旦被提交到图就不能改变了。但是schema元素的name可以修改。通过方法JanusGraphManagment.changeName(JanusGraphSchemaElement,String).像下边这样,属性的key place可以重命名为location。

mgmt = graph.openManagement()
place = mgmt.getPropertyKey('place')
mgmt.changeName(place,'location')
mgmt.commit()

需要注意的是schema name的改变可以能不会马上在当前运行的事务上和集群上其他图上生效。

Schema 约束

在定义scheam时允许用户明确的配置属性和边的约束。比如定义对于特定的属性只能绑定到特定label的顶点和边上。而且连接的约束可以定义某种label的边必须连接在确定label类型的两个顶点之间。这些约束可以保证我们的图满足给定的领域模型。比如我们之前举例子的诸神图,神可以是神的兄弟,但不能是妖怪的兄弟。神可以有属性年龄,但是地点不能有年龄属性。这些约束默认都是不启用的。

需要设置schema.constraints = true来启用schema的约束。这个设置依赖于schema.default的设置。如果schema.default设置是none,那么当违反schema约束时,将会产生一个IllegalArgumentException。如果schema.default没有被设置为none,shema的约束被自动创建。但是没有异常抛出。启用schema的约束不会对已有的数据产生影响,因为schema的约束只有在插入数据时起作用。读取数据不会受这些约束影响。

多个属性可以被关联到一个顶点用JanusGraphManagement.addProperties(VertexLabel,PropertyKey…),比如:

mgmt = graph.openManagement()
person = mgmt.makeVertexLabel('person').make()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(Cardinality.SET).make()
birthDate = mgmt.makePropertyKey('birthDate').dataType(Long.class).cardinality(Cardinality.SINGLE).make()
mgmt.addProperties(person,name,birthDate)
mgmt.commit()

同理,也可以通过JanusGraphManagement.addProperties(EdgeLabel,PropertyKey…)来给边添加多个属性。比如:

mgmt = graph.openManagement()
follow = mgmt.makeEdgeLabel('fellow').multiplicity(MULTI).make()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(Cardinality.SET).make()
mgmt.addProperties(follow,name)
mgmt.commit()

可以通过JanusGraphManagement.addConnection(EdgeLabel,VertexLabel out,VertextLabel in)来约束一个出点,进点,和边。比如:

mgmt = graph.openManagement()
person = mgmt.makeVertexLabel('person').make()
company = mgmt.makeVertexLabel('compony').make()
works = mgmt.makeEdgeLabel('works').multiplicity(MULTI).make()
mgmt.addConnection(works,person,company)
mgmt.commit()

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: