Graph database_neo4j 底层存储结构分析(7)
3.7 Relationship 的存储
下面是neo4j graph db 中,Relationship数据存储对应的文件:
neostore.relationshipgroupstore.db
neostore.relationshipgroupstore.db.id
neostore.relationshipstore.db
neostore.relationshipstore.db.id
neostore.relationshiptypestore.db
neostore.relationshiptypestore.db.id
neostore.relationshiptypestore.db.names
neostore.relationshiptypestore.db.names.id
neo4j 中, Relationship 的存储是由 RelationshipStore , RelationshipGroupStore, RelationshipTypeTokenStore和StringPropertyStore 4种类型的Store配合来完成的. 其中RelationshipStore 是Relationship最主要的存储结构;当一个Node 的关系数达到一定的阀值时,才会对关系分组(group), RelationshipGroupStore 用来保存关系分组数据;RelationshipTypeTokenStore和StringPropertyStore 配合用来存储关系的类型。
关系的类型的字符串描述值是存在StringPropertyStore这样的DynamicStore 中,如果长度超过一个block ,则分block存储,并将其在StringPropertyStore中的第1个block 的 block_id 保存到 RelationshipTypeTokenStore类型文件相应record 的name_id字段中。

ArrayPropertyStore的存储格式见< 3.3.2 DynamicStore 类型>,下面分别介绍一下RelationshipTypeTokenStore, RelationshipStore和RelationshipStore的文件存储格式。
3.7.1 RelationshipTypeTokenStore的主文件存储格式

类RelationshipTypeTokenStore对应的存储文件是neostore.relationshiptypestore.db,其对应的存储格式如上图所示:是一个长度为 RECORD_SIZE=5 Bytes 的 record 数组和和一个字符串描述符“RelationshipTypeStore v0.A.2”(文件类型描述TYPE_DESCRIPTOR和 neo4j 的 ALL_STORES_VERSION) 构成。访问时,可以通过 token_id 作为数组的下标进行访问。
record 是有 1Byte的 in_use 和 4Bytes 的 name_id 构成。
3.7.2 RelationshipStore的文件存储格式
类RelationshipTypeTokenStore对应的存储文件是neostore.relationshipstore.db,其文件存储格式示意图如下,整个文件是有一个 RECORD_SIZE=34Bytes 的定长数组和一个字符串描述符“RelationshipStore v0.A.2”(文件类型描述TYPE_DESCRIPTOR和 neo4j 的 ALL_STORES_VERSION构成)。访问时,可以通过 node_id 作为数组的下标进行访问。

|
1
2
3
4
5
6
7
8
9
10
11
|
</pre><div>// record header size// directed|in_use(byte)+first_node(int)+second_node(int)+rel_type(int)+// first_prev_rel_id(int)+first_next_rel_id+second_prev_rel_id(int)+// second_next_rel_id+next_prop_id(int)+first-in-chain-markers(1)public static final int RECORD_SIZE = 34;</div><pre> |
下面介绍一下 relationship record 中每个字段的含义:
- in_use(1 Byte) : 第 1 字节, 分成3部分.
// [ , x] in use flag
// [ ,nnn ] first node high order bits
// [pppp, ] next prop high order bits
第1 bit 表示 record 是否在 use;
第2~4 bit 表示first_node的node_id的高3位;
第 5~8 bit表示 next_prop_id 的property_id 的 高4位
- first_node(4 Bytes) : 第2~5字节是RelationShip的from_node 的node_id 的低32位. 加上inUse 字节的第 2~4 bit 作为高3位,构成一个完整的35位node_id。
- second_node(4 Bytes) : 第6~9字节是RelationShip的to_node 的node_id 的低32位. 加上rel_type的第29~31 bit作为高3位,构成一个完整的35位node_id。
- rel_type(4 Bytes) : 第 10~13 字节, 分成6部分;
// [ , ][ , ][xxxx,xxxx][xxxx,xxxx] type
- 第29~31 位是second_node 的node_id高3位;
- 第26~28 位是first_next_rel_id 的 relationship_id高3位;
- 第23~25 位是first_next_rel_id 的relationship_id高3位;
- 第20~22 位是second_prev_rel_id 的relationship_id高3位;
- 第17~19 位是second_next_rel_id 的relationship_id高3位;
- 第 1~16 位 表示 RelationShipType;
- first_prev_rel_id(4 Bytes) : 第14~17字节是from_node 的排在本RelationShip 前面一个RelationShip的 relationship_id 的低32位. 加上rel_type的第 26~28 bit 作为高3位,构成一个完整的35位relationship_id。
- first_next_rel_id(4 Bytes) : 第18~21字节是from_node 的排在本RelationShip 前面一个RelationShip的 relationship_id 的低32位. 加上rel_type的第 23~25 bit 作为高3位,构成一个完整的35位relationship_id。
- second_prev_rel_id(4 Bytes) : 第22~25字节是from_node 的排在本RelationShip 前面一个RelationShip的 relationship_id 的低32位. 加上rel_type的第 20~22 bit 作为高3位,构成一个完整的35位relationship_id。
- second_next_rel_id(4 Bytes) : 第26~29字节是from_node 的排在本RelationShip 前面一个RelationShip的 relationship_id 的低32位. 加上rel_type的第 17~19 bit 作为高3位,构成一个完整的35位relationship_id。
- next_prop_id(4 Bytes) : 第30~33字节是本RelationShip第1个Property的property_id 的低32位. 加上in_use的第 5~8 bit 作为高3位,构成一个完整的36 位property_id。
- first-in-chain-markers(1 Byte) : 目前只用了第1位和第2位,其作用笔者还没搞清楚。
3.7.2.1 RelationshipStore.java
与neostore.relationshipstore.db文件相对应的类是RelationshipStore,负责RelationshipRecord从neostore.relationshipstore.db文件的读写。下面看一下 neostore.relationshipstore.db 中 getRecord 成员函数,可以帮助理解 Relationship Record 的存储格式。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
</pre><div>private RelationshipRecord getRecord( long id, PersistenceWindow window,RecordLoad load ){Buffer buffer = window.getOffsettedBuffer( id );// [ , x] in use flag// [ ,xxx ] first node high order bits// [xxxx, ] next prop high order bitslong inUseByte = buffer.get();boolean inUse = (inUseByte & 0x1) == Record.IN_USE.intValue();if ( !inUse ){switch ( load ){case NORMAL:throw new InvalidRecordException( "RelationshipRecord[" + id + "] not in use" );case CHECK:return null;}}long firstNode = buffer.getUnsignedInt();long firstNodeMod = (inUseByte & 0xEL) << 31;long secondNode = buffer.getUnsignedInt();// [ xxx, ][ , ][ , ][ , ] second node high order bits, 0x70000000// [ ,xxx ][ , ][ , ][ , ] first prev rel high order bits, 0xE000000// [ , x][xx , ][ , ][ , ] first next rel high order bits, 0x1C00000// [ , ][ xx,x ][ , ][ , ] second prev rel high order bits, 0x380000// [ , ][ , xxx][ , ][ , ] second next rel high order bits, 0x70000// [ , ][ , ][xxxx,xxxx][xxxx,xxxx] typelong typeInt = buffer.getInt();long secondNodeMod = (typeInt & 0x70000000L) << 4;int type = (int)(typeInt & 0xFFFF);RelationshipRecord record = new RelationshipRecord( id,longFromIntAndMod( firstNode, firstNodeMod ),longFromIntAndMod( secondNode, secondNodeMod ), type );record.setInUse( inUse );long firstPrevRel = buffer.getUnsignedInt();long firstPrevRelMod = (typeInt & 0xE000000L) << 7;record.setFirstPrevRel( longFromIntAndMod( firstPrevRel, firstPrevRelMod ) );long firstNextRel = buffer.getUnsignedInt();long firstNextRelMod = (typeInt & 0x1C00000L) << 10;record.setFirstNextRel( longFromIntAndMod( firstNextRel, firstNextRelMod ) );long secondPrevRel = buffer.getUnsignedInt();long secondPrevRelMod = (typeInt & 0x380000L) << 13;record.setSecondPrevRel( longFromIntAndMod( secondPrevRel, secondPrevRelMod ) );long secondNextRel = buffer.getUnsignedInt();long secondNextRelMod = (typeInt & 0x70000L) << 16;record.setSecondNextRel( longFromIntAndMod( secondNextRel, secondNextRelMod ) );long nextProp = buffer.getUnsignedInt();long nextPropMod = (inUseByte & 0xF0L) << 28;byte extraByte = buffer.get();record.setFirstInFirstChain( (extraByte & 0x1) != 0 );record.setFirstInSecondChain( (extraByte & 0x2) != 0 );record.setNextProp( longFromIntAndMod( nextProp, nextPropMod ) );return record;} |
3.7.3 RelationshipGroupStore类型的存储格式
当Node的Relationship数量超过一个阀值时,neo4j 会对 Relationship 进行分组,以便提供性能。neo4j 中用来实现这一功能的类是 RelationshipGroupStore.

其对应的文件存储格式如下:
整个文件是有一个 RECORD_SIZE=20Bytes 的定长数组和一个字符串“RelationshipGroupStore v0.A.2”(文件类型描述TYPE_DESCRIPTOR和 neo4j 的 ALL_STORES_VERSION构成)。访问时,可以通过 id 作为数组的下标进行访问。数组下标为0的 record 前4 Bytes 保存Relationship分组的阀值。
RelationshipGroupStore 的record 的格式如下:
- inUse(1 Byte):第1字节,共分成4部分
// [ , x] in use
// [ ,xxx ] high next id bits
// [ xxx, ] high firstOut bits
long inUseByte = buffer.get();
- 第1 bit: 表示 record 是否在 use;
- 第2~4 bit: 表示 next 的高3位;
- 第 5~7 bit:表示 firstOut高3位
- 第8 bit:没有用。
- highByte(1 Byte):第1字节,共分成4部分
// [ , x] in use
// [ ,xxx ] high next id bits
// [ xxx, ] high firstOut bits
long inUseByte = buffer.get();
- 第1 bit:没有用;
- 第2~4 bit: 表示 firstIn 的高3位;
- 第 5~7 bit:表示 firstLoop高3位
- 第8 bit:没有用。
- next :
- firstOut
- firstIn
- firstLoop
Graph database_neo4j 底层存储结构分析(7)的更多相关文章
- Graph database_neo4j 底层存储结构分析(8)
3.8 示例1:neo4j_exam 下面看一个简单的例子,然后看一下几个主要的存储文件,有助于理解<3–neo4j存储结构>描述的neo4j 的存储格式. 3.8.1 neo4j ...
- Graph database_neo4j 底层存储结构分析(6)
3.6 Node 数据存储 neo4j 中, Node 的存储是由 NodeStore 和 ArrayPropertyStore 2中类型配合来完成的. node 的label 内容是存在Array ...
- Graph database_neo4j 底层存储结构分析(5)
3.5 Property 的存储 下面是neo4j graph db 中,Property数据存储对应的文件: neostore.propertystore.db neostore.propertys ...
- Graph database_neo4j 底层存储结构分析(1)
1 neo4j 中节点和关系的物理存储模型 1.1 neo4j存储模型 The node records contain only a pointer to their first pr ...
- Graph database_neo4j 底层存储结构分析(4)
3.3.2 DynamicStore 类型 3.3.2.1 AbstractDynamicStore 的存储格式 neo4j 中对于字符串等变长值的保存策略是用一组定长的 block ...
- Graph database_neo4j 底层存储结构分析(3)
3.3 通用的Store 类型 3.3.1 id 类型 下面是 neo4j db 中,每种Store都有自己的ID文件(即后缀.id 文件),它们的格式都是一样的. [test00]$ls - ...
- Graph database_neo4j 底层存储结构分析(2)
3 neo4j存储结构 neo4j 中,主要有4类节点,属性,关系等文件是以数组作为核心存储结构:同时对节点,属性,关系等类型的每个数据项都会分配一个唯一的ID,在存储时以该ID 为数组的 ...
- Redis(一) 数据结构与底层存储 & 事务 & 持久化 & lua
参考文档:redis持久化:http://blog.csdn.net/freebird_lb/article/details/7778981 https://blog.csdn.net/jy69240 ...
- HBase底层存储原理
HBase底层存储原理——我靠,和cassandra本质上没有区别啊!都是kv 列存储,只是一个是p2p另一个是集中式而已! 首先HBase不同于一般的关系数据库, 它是一个适合于非结构化数据存储的数 ...
随机推荐
- CI邮箱中SMTP的一些端口
介绍其他几个常用邮箱设置,并以网易126邮箱为例,发图. 一.新浪邮箱(1)新浪邮箱自08年6月分服务器被攻击后开始对pop取件频率进行了严格**,同时新注册的用户需要手动才能开通pop ...
- codeforces B. Vasya and Public Transport 解题报告
题目链接:http://codeforces.com/problemset/problem/355/B 题目意思:给出四种票种,c1: 某一部bus或者trolley的单程票(暗含只可以乘坐一次):c ...
- maven的一些依赖
maven的一些依赖: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://w ...
- ASP.NET服务器端执行耗时操作的工作记录
公司之前有这样一个业务需求: 一名同事做出文件a0和b0,然后将a0加密为a1.b0加密为b1:再将文件a0.a1.b0和b1上传至服务器M:同时要将服务器N上的数据表添加一条记录,该记录的ID就是前 ...
- Java Hour8
有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. 本文作者Java 现经验约为7 Hour,请各位不吝赐教. Hour8 Jav ...
- ThinkPHP函数详解:session方法
ThinkPHP函数详解:session方法 Session方法用于Session 设置.获取.删除和管理操作. Session 用于Session 设置.获取.删除和管理操作 用法 sessi ...
- 使用MyEclipse Swing/Matisse
经常使用JBuilder开发工具的人都知道,在JBuilder中开发Swing应用程序是比较方便的,虽然比不上曾经红遍一时的Visual Basic,但开发界面的工作确实被大大简化了. JB ...
- 用sqlplus登陆数据库时,oracle 11g出现ORA-12514问题
转自:http://zhidao.baidu.com/question/144648216.html 启动服务 然后在sqlplus / as sysdba;执行启动startup nomount;a ...
- OD hit跟踪 run跟踪使用问题
刚学习OD不久,现在使用HIT跟踪 run跟踪功能,在我的程序里碰到点问题,还请赐教 选了一部分代码添加到HIT跟踪,在选的代码处设置断点,程序运行到断点,按单步跟踪,当执行到第二个PUSH时,程序就 ...
- Python开发的10个小贴士
下面是十个Python中很有用的贴士和技巧.其中一些是初学这门语言常常会犯的错误. 注意:假设我们都用的是Python 3 1. 列表推导式 你有一个list:bag = [1, 2, 3, 4, 5 ...