图数据schema定义语言1.0 郝伟 2021/03/20 [TOC]
1. 简介
为了便于图数据在不同的数据源进行转移时,能够形成统一的规范,所以特定制本文档。本文档主要参考HugeGraph的HugeGraph-Loader Quick Start。主要的变化是对定义进行了重新组织,并精简了一些内容,以便于更好地满足Ai.KG的项目需求。
对数据的描述分为两块内容:schema结构定义和数据本体两部分内容。前者是对数据格式信息的描述,后者是数据本体。本文档就是对前者进行描述。通过使用本文档协议,能够对支持范围内的任何数据进行描述,从而使程序能够以统一的方式进行数据的导入和导出。
2. 总体描述
文件采用Json格式进行描述,在根级别的结构基本如下所示:
{
"version": "1.1",
"structs": [{结构块1}, {结构块2}, ...]
}
根结构中包括两块内容:
- version, 版本号。
- structs, 结构块列表,包括多个结构块,每个结构块使用详细的结构描述数据。
2.1. structs 块定义
strcts 可能包括多个数据块,每个块的定义如下:
{
"id": "1",
"input": {},
"vertices": [{v1}, {v2}, {v3}...],
"edges": [ {e3}, {e2}, {e3}, ...]
}
键值的定义如下所示:
| 键名 | 作用 |
|---|---|
| id | 输入源的唯一编号,每个块的id必需不相同。 |
| skip | 相当于注释功能,如果某块的此属性为True,则忽略此结构体定义段。 |
| input | 对输入源的相关信息进行描述。 |
| vertices | 对节点进行定义。 |
| edges | 对关系进行定义。 |
3. 结构块的属性定义
每个结构块有 id 和 skip 用于描述基本特性,功能相对简单。除此外,还有以下结构比较复杂的属性定义:
3.1. input
此属性用于描述输入源的信息,输入源可以是文件类型(HDFS源或Java驱动也可支持,但暂不考虑),其定义主要包括以下属性:
| 键名 | 必选项 | 作用 |
|---|---|---|
| type | O | 值固定为 file 或 FILE。 |
| path | O | 输入文件的所在的绝对路径,用于定位。 |
| format | O | 输入文件的格式,可选值为 CSV、TEXT 及 JSON。 |
| header | X | 指定CSV或TXT各列列名。如不指定则会以数据文件第一行作为 header。 |
| delimiter | X | 文件行的列分隔符,默认以逗号作为分隔符,JSON文件不需要指定。 |
| end_symbol | X | 集合结构列的结束符,默认值为 \n。 |
| charset | X | 文件的编码字符集,默认UTF-8。 |
| date_format | X | 自定义的日期格式,默认值为 yyyy-MM-dd HH:mm:ss。 若日期是时间戳则固定值为 timestamp。 |
| time_zone | X | 设置日期数据是处于哪个时区的,默认值为GMT+8,选填。 |
| skipped_line | X | 可使用正则表达式指定某些行可以跳过,如 ^#.* 指定以#开始的行。 |
| compression | X | 压缩格式,默认为 NONE,表示非压缩文件。 |
注:暂不考虑某单元为集合元素的情况。如果需要支持则需要添加以下定义: | 键名 | 必选项 | 作用 | |:----:|:----:|:----| | list_format | O | 当文件的某列是集合结构时(对应图中的 PropertyKey 的 Cardinality 为 Set 或 List),可以用此项设置。列的起始符、分隔符、结束符,复合结构: | | start_symbol | O | 集合结构列的起始符。 | | elem_delimiter | O | 集合结构列的分隔符。 |
3.2. vertices & edges
此属性用于描述输入源的节点信息,主要定义内容如下所示:
3.2.1. 相同部分
以下属性为节点和边共有:
| 键名 | 必选项 | 作用 |
|---|---|---|
| label | O | 待导入的顶点/边数据所属的标签 label。 |
| field_mapping | 将输入源列的列名映射为顶点或边的属性名。 | |
| value_mapping | 将输入源的数据值映射为顶点或边的属性值。 | |
| selected | 选择某些列插入,其他未选中的不插入,不能与igred同时存在。 | |
| igred | 忽略某些列,使其不参与插入,不能与selected同时存在。 | |
| null_values | 可以指定一些字符串代表空值,比如"NULL",如果该列对应的顶点或边属性又是一个可空属性,那在构造顶点/边时不会设置该属性的值。 | |
| update_strategies | 如果数据需要按特定方式批量更新时可以对每个属性指定具体的更新策略 (具体见下)。 | |
| unld | 是否将列展开,展开的每一列都会与其他列一起组成一行,相当于是展开成了多行;比如文件的某一列(id 列)的值是[1,2,3],其他列的值是18,Beijing,当设置了 unld 之后,这一行就会变成 3 行,分别是:1,18,Beijing,2,18,Beijing和3,18,Beijing。需要注意的是此项只会展开被选作为 id 的列。默认 false。 |
3.2.2. 不同部分
顶点特有属性
- id: 指定某一列作为顶点的 id 列,当顶点 id 策略为CUSTOMIZE时,必填;当 id 策略为PRIMARY_KEY时,必须为空;
边特有属性
- source, 选择输入源某几列作为源顶点的 id 列,当源顶点的 id 策略为
CUSTOMIZE时,必须指定某一列作为顶点的id列;当策略为PRIMARY_KEY时,必须指定一列或多列用于拼接生成顶点的 id,也就是说,不管是哪种策略,此项必填。 - target, 指定某几列作为目标顶点的 id 列,与 source 类似。
3.2.3. 注意事项
- 在属性名中,使用
属性类型:属性名的方式表示属性的数据类型和名称,如str:name,int:age; - 属性名中不允许出现冒号;
- 属性类型是可选项,在不写数据类型,默认为字符串,如
name与str:name等价。
4. 一些图描述语言
- 本体语言学习笔记, https://blog.csdn.net/shendeguang/article/details/8241164
- OWL中基于具体化的多元关系表示研究, https://doc.mbalib.com/view/1754a797116a45923bfaa7a1db86ce0e.html
- 知识图谱---描述语言, https://blog.csdn.net/github_37002236/article/details/81908394
- 知识图谱基础之RDF,RDFS与OWL, https://blog.csdn.net/u011801161/article/details/78833958
- 语义Web简单综述(XML、RDF、OWL、知识库、知识图谱), https://blog.csdn.net/hohaizx/article/details/80043623
- HugeGraph,Neo4j,Titan三种图数据库性能对比, https://www.jianshu.com/p/c124f748877d
官网给了一个性能测试的报告:https://hugegraph.github.io/hugegraph-doc/performance/hugegraph-benchmark-0.5.6.html
总结起来就是:
- 批量插入性能:HugeGraph(RocksDB) > Neo4j > Titan(thrift+Cassandra)
- 遍历性能:Neo4j > HugeGraph(RocksDB) > Titan(thrift+Cassandra)
- 图常用分析方法性能:FS场景,HugeGraph性能优于Neo4j和Titan,K-neighbor和K-out场景,HugeGraph能够实现在5度范围内秒级返回结果
- 社区聚类算法性能 Neo4j > HugeGraph > Titan
5. 示例文件
5.1. 示例1
{
"version": "1.0",
"structs": [
{
"id": "1",
"input": {
"type": "FILE",
"path": "vertex_person.csv",
"format": "CSV",
"delimiter": ",",
"date_format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "GMT+8",
"skipped_line": { "regex": "(^#|^//).*|" },
"header": [
"name",
"age",
"city"
]
},
"vertices": [
{
"label": "person",
"skip": false,
"id": null,
}
],
"edges": []
}
}
5.2. 示例2
{
"version": "2.0",
"structs": [
{
"id": "1",
"skip": false,
"input": {
"type": "FILE",
"path": "vertex_person.csv",
"file_filter": {
"extensions": [
"*"
]
},
"format": "CSV",
"delimiter": ",",
"date_format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "GMT+8",
"skipped_line": {
"regex": "(^#|^//).*|"
},
"compression": "NONE",
"header": [
"name",
"age",
"city"
],
"charset": "UTF-8",
"list_format": null
},
"vertices": [
{
"label": "person",
"skip": false,
"id": null,
"field_mapping": {},
"value_mapping": {},
"selected": [],
"ignored": [],
"null_values": [
""
],
"update_strategies": {}
}
],
"edges": []
},
{
"id": "2",
"skip": false,
"input": {
"type": "FILE",
"path": "vertex_software.csv",
"file_filter": {
"extensions": [
"*"
]
},
"format": "CSV",
"delimiter": ",",
"date_format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "GMT+8",
"skipped_line": {
"regex": "(^#|^//).*|"
},
"compression": "NONE",
"header": null,
"charset": "UTF-8",
"list_format": null
},
"vertices": [
{
"label": "software",
"skip": false,
"id": null,
"field_mapping": {},
"value_mapping": {},
"selected": [],
"ignored": [],
"null_values": [
""
],
"update_strategies": {}
}
],
"edges": []
},
{
"id": "3",
"skip": false,
"input": {
"type": "FILE",
"path": "edge_knows.json",
"file_filter": {
"extensions": [
"*"
]
},
"format": "JSON",
"delimiter": null,
"date_format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "GMT+8",
"skipped_line": {
"regex": "(^#|^//).*|"
},
"compression": "NONE",
"header": null,
"charset": "UTF-8",
"list_format": null
},
"vertices": [],
"edges": [
{
"label": "knows",
"skip": false,
"source": [
"source_name"
],
"target": [
"target_name"
],
"field_mapping": {
"source_name": "name",
"target_name": "name"
},
"value_mapping": {},
"selected": [],
"ignored": [],
"null_values": [
""
],
"update_strategies": {}
}
]
},
{
"id": "4",
"skip": false,
"input": {
"type": "FILE",
"path": "edge_created.json",
"file_filter": {
"extensions": [
"*"
]
},
"format": "JSON",
"delimiter": null,
"date_format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "GMT+8",
"skipped_line": {
"regex": "(^#|^//).*|"
},
"compression": "NONE",
"header": null,
"charset": "UTF-8",
"list_format": null
},
"vertices": [],
"edges": [
{
"label": "created",
"skip": false,
"source": [
"source_name"
],
"target": [
"target_name"
],
"field_mapping": {
"source_name": "name",
"target_name": "name"
},
"value_mapping": {},
"selected": [],
"ignored": [],
"null_values": [
""
],
"update_strategies": {}
}
]
}
]
}
6. 暂不考虑的内容
6.1.1. HDFS文件输入源
HDFS文件,也是文件,所以继承以上文件类型的所有信息,但是有以下几点不同:
type的值为hdfs或HDFS。- 属性
core_site_path指定 HDFS 集群的 core-site.xml 文件路径。重点要指明 namenode 的地址(fs.default.name),以及文件系统的实现(fs.hdfs.impl)。
6.1.2. JDBC输入源
本类型用于支持多种关系型数据库。由于关系数据库的结构非常相似,故统称为 JDBC输入源。
主要属性如下所示:
| 键名 | 必选项 | 作用 |
|---|---|---|
| type | O | 输入源类型 jdbc 或 JDBC。 |
| vendor | O | 数据库类型,可选项为 MySQL、PostgreSQL、Oracle、SQLServer。 |
| driver | O | jdbc 使用的 driver 类型。 |
| url | O | 连接数据库的链接。 |
| schema | 要连接的 schema 名,不同的数据库要求不一样,下面详细说明。 | |
| database | O | 要连接的数据库名。 |
| table | O | 要连接的表名。 |
| username | O | 连接数据库的用户名。 |
| password | O | 连接数据库的密码。 |
| batch_size | 按页获取表数据时的一页的大小,默认为 500。 |
以下是一些数据库连接的典型示例:
MYSQL
{
"vendor": "MYSQL",
"driver": "com.mysql.cj.jdbc.Driver",
"url": "jdbc:mysql://127.0.0.1:3306"
}
POSTGRESQL
{
"vendor": "POSTGRESQL",
"driver": "org.postgresql.Driver",
"url": "jdbc:postgresql://127.0.0.1:5432"
}
ORACLE
{
"vendor": "ORACLE",
"driver": "oracle.jdbc.driver.OracleDriver",
"url": "jdbc:oracle:thin:@127.0.0.1:1521"
}
SQLSERVER
{
"vendor": "SQLSERVER",
"driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver",
"url": "jdbc:sqlserver://127.0.0.1:1433"
}