hugegraph底层使用多张表来存储数据
cqlsh:hugegraph> describe tables;
graph_vertices system_edges_in graph_search_indexes
vertex_labels system_search_indexes edge_labels
system_range_indexes system_secondary_indexes system_edges_out
graph_edges_out graph_secondary_indexes index_labels
property_keys graph_range_indexes counters
system_vertices graph_edges_in
基本分为 graph_前缀开头的,以及分为system_前缀开头的表。还有一些共用的入counter。
graph_x开头的基本是给业务数据用的表,而system开头的基本是系统用的表。
使用图数据的第一步是定义schema,包括属性,节点,关系,索引。
先看最小单位为property
cqlsh:hugegraph> select * from property_Keys limit 1;
id | cardinality | data_type | name | properties | status | user_data
----+-------------+-----------+--------+------------+--------+-----------
23 | 1 | 8 | org_no | null | 1 | null
cardinality标识 这个属性是单个值还是集合,dataType 8 为string 类型,枚举值需要看代码。
节点
有了属性,把他们组合起来就是点了。
cqlsh:hugegraph> select * from vertex_labels where id = 3;
id | enable_label_index | id_strategy | index_labels | name | nullable_keys | primary_keys | properties | status | user_data
----+--------------------+-------------+--------------+------+---------------+--------------+------------+--------+-----------
3 | True | 3 | {38, 39} | News | {8, 30} | null | {8, 30} | 1 | null
可以看到一个 节点,有很多个配置, id_strategy为id生成策略,属性(ID)集合,每个属性对应的index_ID, 主键,nullable key等。 这些值都是通过一个 ID list 来引用其他的表,起到一个外键的作用。
前面介绍过property,下面看看,index_label 这个表。
index_Labels
cqlsh:hugegraph> select * from index_labels where id in (38,39);
id | base_type | base_value | fields | index_type | name | status
----+-----------+------------+---------+------------+----------------------+--------
38 | 1 | 3 | [30, 8] | 1 | News_news_id_user_id | 2
39 | 1 | 3 | [8] | 1 | News_user_id | 2
这个表说明了Id 为38,39的index情况,比如名字,依附的是节点或者边
到此一个节点的定义就完整了,下面可以看一下边的定义。
edge_lables
cqlsh:hugegraph> select * from edge_labels;
id | enable_label_index | frequency | index_labels | name | nullable_keys | properties | sort_keys | source_label | status | target_label | user_data
----+--------------------+-----------+--------------------------+---------------------------+-----------------------------+-----------------------------+-----------+--------------+--------+--------------+-----------
1 | True | 1 | {30, 31, 32} | Company_Invest_Company | {8, 28, 29} | {8, 28, 29} | null | 1 | 1 | 1 | null
2 | True | 1 | {33, 34, 35} | Person_Invest_Company | {8, 28, 29} | {8, 28, 29} | null | 2 | 1 | 1 | null
4 | True | 1 | {40, 41, 43, 44, 45, 46} | News_Related_Company | {8, 31, 32, 33, 34, 35, 36} | {8, 31, 32, 33, 34, 35, 36} | null | 3 | 1 | 1 | null
3 | True | 1 | {36, 37} | Person_PositionOf_Company | {8, 28} | {8, 28} | null | 2 | 1 | 1 | null
与节点相比,只是多出一个 frequency的概念,代表两个节点之间,是否支持多条具有同样label的边。
比如有人 和公司节点, 定义了边,叫做 关联关系。 这个关联关系可能存在多条,比如,任职,投资。此时这个frequency的type 就是multiple了。
如果定义了multiple,必须要指定 一个属性作为 sortKey,也就是 区分关联关系,是 任职还是投资。
定义好了schema之后可以来看看数据是怎么存的,schema的定义就像是 class,数据本身才是对象。
先看graph_vertices
cqlsh:hugegraph> select * from graph_vertices limit 1;
id | label | properties
---------------------+-------+--------------------------------------------------------------------------
S353623026048307200 | 2 | {8: '"admin"', 11: '"熊美斌"', 27: '"6a425966030e61cfec8ffb40958ee3d0"'}
其实很简单,就是 ID,Label ,以及properties数据。properties 使用map。key 为属性的Id。
在看下边 edge:
owner_vertex | direction | label | sort_values | other_vertex | properties
---------------------+-----------+-------+-------------+---------------------+-------------------------------------
S352108445291385111 | 2 | 3 | | S353604988217462784 | {8: '"admin"', 28: '"股东,董监高"'}
边分为 edges_in, 和edges_out, 这个是为了正向和反向查询的遍历。在图分割的章节会说明设计的原因。
这个边,存储了 开始节点和结束节点的ID,以及相应的属性,和节点的结构很相似。
存储了节点和边,当我们需要查询的时候如何定位目标呢?通过属性的值来查询?
在cassandra作为存储的结构里面,我们先看看 graph_vertices 定义:
CREATE TABLE hugegraph.graph_vertices (
id text PRIMARY KEY,
label int,
properties map<int, text>
) WITH bloom_filter_fp_chance = 0.01
有一个primary key,这个将会作为partition key,通常如果primary 为组合(a,b,C)
那么第一个键作为partition key,b c叫做 cluster key,查询的时候只能按照key 的前缀匹配来查询,如where a=1 b=2,而不能做c=1 b=2 这种。
但是我们查询节点,通常会根据任何属性的组合来查询,为了加快查询的速度和避免
cassandra存储引擎的限制,hugegraph 手动实现了索引。
怎么做的。 比如对一个节点,地区节点 D,有属性 name="中国",city="上海",我们可以在 name 和city上做索引,系统会在在一个叫做 graph_secondary_indexes 里面插入所有的 (name,city)-》node_ID 的倒排寻关系。查询的时候,查询这样一个倒排序表就可以了。
cqlsh:hugegraph> select * from graph_secondary_indexes where field_values='7778529' limit 1;
field_values | index_label_id | element_ids
--------------+----------------+---------------------
7778529 | 38 | S365024405421690880
除了二级索引,还有range 以及search index.
search index 支持对属性的全文检索,提供了类似lucene的功能
range index ,支持范围查询,这些都是hugegraph在系统层面实现的。
虽然增加了系统的复杂性,因为要管理索引的建立,更新和同步,但也提供了优秀的性能。
到目前位置,基本上对graph_前缀的表都过了一遍,
下面要看的是 system_前缀的表。
其实system_vertices, system_edge 这些表对应的节点和边的 schema 也是放在vertex_label 和 edge_label里面的。只是他们存储的数据不一样。
以system Vertices 为例,他存储的是整个系统的任务 task执行的情况。
说到 hugegraph task ,这里要插一句。 系统内部存在很多 异步任务。 比如新增节点,修改节点都会触发 rebuild index 这类任务。
这些任务都是异步执行的,任务的状态都存在 task 节点里面。 系统在重启或异常停止恢复时候,都会去读取任务的状态 决定是否需要restore等。
这个任务节点的schema, 是在系统启动的时候初始化的。整个hugegraph 初始化,基本上就是插入了 task 节点,为他创建了一些属性,和查询需要的index。
cqlsh:hugegraph> select * from system_vertices limit 1;
id | label | properties
-----+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
L35 | -13 | {-9: '0', -8: '1564109684704', -7: '1564109684694', -6: '0', -5: '5', -3: '"com.baidu.hugegraph.job.schema.RebuildIndexCallable"', -2: '"INDEX_LABEL:35:Person_Invest_Company_user_id"', -1: '"rebuild_index"'}
label = -13, 在 vertex_label 看一下:
cqlsh:hugegraph> select * from vertex_labels where id = -13;
id | enable_label_index | id_strategy | index_labels | name | nullable_keys | primary_keys | properties | status | user_data
-----+--------------------+-------------+--------------+-------+-------------------------+--------------+-----------------------------------------------------+--------+-----------
-13 | True | 4 | {-14} | ~task | {-12, -11, -10, -8, -4} | null | {-12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1} | 1 | null
他对应的 index 就存在 system_range_indexs, search_indexes, secondary_indexes 里面。
最后是counter 表
cqlsh:hugegraph> select * from counters;
schema_type | id
--------------+----
PROPERTY_KEY | 36
VERTEX_LABEL | 3
SYS_SCHEMA | 32
INDEX_LABEL | 53
EDGE_LABEL | 4
TASK | 59
存储的是全局ID,比如property_key 表,下一个id 就是 37.
至此,hugegraph 存储结构描述清楚,不同存储后端,都大同小异,比如mysql,也基本上使用了这一套表结构
网友评论