JanusGraph图是通过Schema定义,每个Schema包含边标签、属性、点标签。JanusGraph的Schema可以被显式或者隐式定义。 建议开发者在程序开发期间显式的定义图的Schema。显式的定义Schema可以提高程序的健壮性,也能够方便与同事的协作开发。注意,JanusGraph的Schema可以随着时间的推移而改变,而不会中断正常的数据库操作。扩展Schema不会减慢查询速度,也不需要数据库停机。
Schema第一次被创建时,需要指定他们的类型例如边的标签、属性的key、顶点的标签。无法更改特定元素的Schema类型。这是为了确保系统的稳定。
除了本节中介绍的Schema定义方式外,第30章高级教程中也讲了如何定义来提高性能。
连接两个顶点的每条边都有一个标签,用来描述他们之间的关系。例如:顶点A和顶点B之间具有朋友关系,那他们之间边的标签可以定义为friend。
要定义边的标签,通过graph实例或者management调用方法makeEdgeLabel(String),传入边标签的名称作为参数。边标签的名称必须是全局唯一的。这个方法返回一个边标签的builder,用来定义边的multiplicity。边标签的多重性定义了该标签在所有边上的多重约束,即顶点对之间的最大边数。 JanusGraph支持以下多重性设置。
默认的Multiplicity是MULTI。 边标签的定义是通过调用构建器上的make()方法完成的,该方法返回的是定义的边标签,如下例所示。
mgmt = graph.openManagement()
follow = mgmt.makeEdgeLabel('follow').multiplicity(MULTI).make()
mother = mgmt.makeEdgeLabel('mother').multiplicity(MANY2ONE).make()
mgmt.commit()
顶点和边的属性是键值对。 例如,属性name ='Daniel'具有键名和值'Daniel'。 属性键是JanusGraph架构的一部分,可以约束允许的数据类型和值的基数。
要定义属性键,请在打开的图形或管理事务上调用makePropertyKey(String),并提供属性键的名称作为参数。 属性键名称在图形中必须是唯一的,建议避免使用属性名称中的空格或特殊字符。 此方法返回属性键的构建器。
使用dataType(Class)定义属性的数据类型。 JanusGraph将使用已经定义的数据类型给属性赋值,来保证添加到图中的数据有效。 例如,可以定义属性name的数据类型是String。
允许把任何(可序列化的)的值赋值给数据类型为Object.class的属性。 但是,建议尽可能的使用具体的数据类型。 设置的数据类型必须是具体的类,而不能是接口或抽象类。 JanusGraph确保类相等,因此不允许添加已设置数据类型的子类。
JanusGraph支持以下数据类型。
类型 | 描述 |
---|---|
String | |
Character | |
Boolean | |
Byte | |
Short | |
Integer | |
Long | |
Float | |
Double | |
Date | |
Geoshape | |
UUID |
使用Cardinality来定义顶点上相关属性的Cardinality。
默认的cardinality值为SINGLE。 注意,边的属性和属性的cardinality是SINGLE。 不支持为边或属性上的单个key赋多个值。
mgmt = graph.openManagement()
birthDate = mgmt.makePropertyKey('birthDate').dataType(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()
边的标签和属性共同称为关系类型。 关系类型的名称在图中必须是唯一的,这意味着属性和边标签不能具有相同的名称。 JanusGraph API中有一些方法可以查询或检验关系类型中是否包含属性和边标签。
mgmt = graph.openManagement()
if (mgmt.containsRelationType('name'))
name = mgmt.getPropertyKey('name')
mgmt.getRelationTypes(EdgeLabel.class)
mgmt.commit()
像边一样,顶点也有标签。 与边标签不同,顶点标签是可选的。 顶点标签可用于区分不同类型的顶点,例如, 用户顶点和产品顶点。
虽然标签在概念和数据模型上是可选的,但JanusGraph在内部实现中会为所有顶点分配一个标签。 addVertex方法创建顶点时使用JanusGraph的默认标签。
要创建标签,请调用方法makeVertexLabel(String).make(),并提供顶点标签的name作为参数。 顶点标签的名称在图中必须是唯一的。
mgmt = graph.openManagement()
person = mgmt.makeVertexLabel('person').make()
mgmt.commit()
// Create a labeled vertex
person = graph.addVertex(label, 'person')
// Create an unlabeled vertex
v = graph.addVertex()
graph.tx().commit()
如果未明确定义边标签,属性或顶点标签,则在边,顶点或属性首次使用时,它会被隐式定义。 JanusGraph默认的的DefaultSchemaMaker配置会定义这些类型。
默认情况下,隐式创建的边标签具有多重性MULTI,隐式创建的属性具有基数SINGLE和数据类型是Object.class。 用户可以通过实现和注册自己的DefaultSchemaMaker来控制Schema的自动创建方式。
强烈建议显示的定义所有的Schema并且通过在JanusGraph配置中设置schema.default = none来禁用自动创建Schema。
边标签,属性键或顶点标签的定义一旦提交则无法更改。 但是,可以通过JanusGraphManagement.changeName(JanusGraphSchemaElement,String)来更改Schema中元素的名字,如以下示例所示,其中属性place被重命名为location。
mgmt = graph.openManagement()
place = mgmt.getPropertyKey('place')
mgmt.changeName(place, 'location')
mgmt.commit()
请注意,在正在运行的遍历查询和集群中的JanusGraph实例中,Schema名字的更改可能不会立即生效。虽然通过后端存储向所有JanusGraph实例通知了Schema名字更改,但它可能需要一段时间才能生效,并且如果遇到某些故障情况(如网络分区)可能需要重启实例。因此,用户必须确保满足以下任一条件:
如果需要重新定义现有的Schema类型,建议将此类型的名称更改为当前未使用并且永远不会使用的名称。之后,可以使用原来的name定义新标签或key,从而有效地替换旧标签或key。但注意,这不会影响使用先前的类型去写入顶点,边或属性。不支持在线重新定义现有图元素,必须通过图批量转换完成。
Schema的定义允许用户显式配置属性和连接约束。属性可以绑定到特定的顶点标签和/或边标签。此外,连接约束允许用户明确定义哪两个顶点标签被连接通过边缘标签。这些约束用于确保图与给定的模型匹配。例如,对于众神的图,god可以是另一个god的兄弟,而不是怪物,god可以拥有年龄属性,但位置不能具有年龄年龄。这些约束默认情况下是禁用的。
通过设置schema.constraints = true来启用这些schema约束。这个设置依赖schema.default配置。如果schema.default设置为none,则会因违反schema约束而抛出IllegalArgumentException。如果schema.default未设置为none,则会自动创建schema约束,而不会引发异常。激活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('follow').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,VertexLabel in)定义边的出点和入点的连接,例如:
mgmt = graph.openManagement()
person = mgmt.makeVertexLabel('person').make()
company = mgmt.makeVertexLabel('company').make()
works = mgmt.makeEdgeLabel('works').multiplicity(MULTI).make()
mgmt.addConnection(works, person, company)
mgmt.commit()