数据结构 有向图
一 概念
1、有向图存储-》其实本质并非是一个数据库,而是基于非关系数据库上的一种数据模型,其顶点和边的存储是存贮在如HBase的非关系型数据库中,如要进行一些全文搜索、geo查询需要集成如solr的搜索引擎来进行,而图操作则可以使用Tikerpop来进行具体的顶点(V)和边(E)操作。
a.其核心是根据一个切入点(顶点/边)的唯一操作入口进行数据的遍历查找,可使用图索引和顶点中心索引的查询方式
b.以顶点为出发点可以分为出(out)和进(in)的 有向图 遍历查找方式
c.可以通过增加出入边的label来筛选需要的数据结果
d.针对key可以进行 基数 设置 single set list关键值来保证数据的特性 ,这个配置是对图任何给定的顶点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()
默认是SINGLE
注:graph.openManagement()使用此方法返回的图实例,管理图的相关属性值
e.每个顶点可以设置边的属性值
AA:
MULTI
SIMPLE //边标签与对应的一对顶点是唯一的
MANY2ONE
ONE2MANY
ONE2ONE //对于给定的任何顶点,只允许一个出边和一个入边
mgmt = graph.openManagement()
follow = mgmt.makeEdgeLabel('follow').multiplicity(
AA
).make()
mgmt.commit()
默认是
MULTI
f.每个节点以键值对的形式存储数据
2、具有大量数据 动态弹性扩展
3、支持ACID,因为没有主从表 的关系,查询更加快速,不受限
二、关于方法命令
1、常用
服务启动
bin/titan.sh start
启动
gremlin
bin/gremlin.sh
graph = TitanFactory.open('conf/titan-cassandra-es.properties') //打开自己配置好的后端集成配置文件,其中包含数据库配置,缓存配置信息。
GraphOfTheGodsFactory.load(graph)
g = graph.traversal() 创建图实例
g.V() 操作图所有 顶点
g.E() 操作图 有向边
g.v(xxx) 获取目标顶点索引
g.v().has("xx",xx).next() 获取符合要求的第一个下标值
g.v().out("xx") //返回指定边下一个顶点
g.v().outE("xx") //返回指定边
2、事务支持
graph = TitanFactory.open("berkeleyje:/tmp/titan")
juno = graph.addVertex() //自动开启一个事务
juno.property("name", "juno")
graph.tx().commit() //事务提交
可以配合使用t
ry catch
3、order
查询
h = g..V().has('name', 'hercules').next()
g.V(h).local(outE('battled').order().by('time', decr).limit(10)).inV().values('name')
g.V(h).local(outE('battled').has('rating', 5.0).order().by('time', decr).limit(10)).values('place')
4.缓存
泰坦使用了多层数据缓存,以方便快速的图形遍历。它们是从一个泰坦事务中访问的。缓存越接近事务,缓存访问的速度越快,内存占用和维护开销也就越高。
a.事务级缓存
在一个开放的事务中,泰坦维护两个缓存:
顶点缓存:
缓存访问的顶点和它们的邻接表(或其子集),这样在同一事务中,后续访问就会明显加快。因此,这个缓存加速了迭代的遍历。
索引缓存:
缓存索引查询的结果,以便后续的索引调用可以从内存中服务,而不是调用索引后端和等待一个或多个网络往返。
这两种方法的大小都由事务缓存大小决定。事务缓存大小可以通过缓存进行配置
tx-cache-size或在每个事务基础上通过事务构建器
graph.
buildTransction()打开一个事务,并使用
setVertexCacheSize(int)
方法。
a.1
顶点缓存
顶点缓存包含在特定事务中检索到的顶点和它们的邻接表的子集。在这个缓存中维护的顶点的最大数量等于事务缓存大小。如果事务工作负载是一个迭代遍历,那么顶点缓存将显著加快它的速度。如果在事务中没有再次访问相同的顶点,事务级别的缓存将不会有任何影响。
注意,堆上的顶点缓存的大小不仅取决于它可能持有的顶点的数量,还取决于它们的邻接表的大小。换句话说,具有较大邻接表(即许多事件边)的顶点在缓存中消耗的空间要比那些较小的列表要大。
此外,修改后的顶点被固定在缓存中,这意味着它们不能被驱逐,因为这将导致它们的更改。因此,包含很多修改的事务最终可能会得到一个大于配置的顶点缓存。
a.2索引缓存
索引缓存包含在该事务上下文中执行的索引查询的结果。随后相同的索引调用将从这个缓存中提供,因此会显著地降低。如果相同的索引调用在相同的事务中从未发生过两次,那么索引缓存就没有区别。
索引缓存中的每个条目的权重为2+结果集的大小,而缓存的总重量不会超过事务缓存大小的一半。
b 数据库级缓存
数据库级缓存保留多个事务的邻接表(或子集),并且在单个事务的持续时间范围内。数据库级缓存由数据库中的所有事务共享。与事务级缓存相比,它的空间效率更高,但访问速度也稍微慢一些。与事务级缓存相反,数据库级缓存在关闭事务后不会立即过期。因此,数据库级缓存显著地加快了在事务中读取繁重工作负载的图遍历。
第12章,配置引用列出了与泰坦数据库级缓存相关的所有配置选项。
最重要的是,默认情况下,数据库级缓存在当前版本的泰坦上是禁用的。为了启用它,设置缓存。
db-cache=true
。
b.1缓存过期时间
性能和查询行为最重要的设置是通过缓存
.
db-cache-time配置的缓存过期时间。高速缓存将在大多数毫秒内保存图形元素。如果一个元素过期,数据将在下一次访问时从存储后端重新读取。
如果只有一个泰坦实例访问存储后端,或者这个实例是唯一修改图的实例,那么缓存过期可以设置为0,这将禁用缓存过期。这允许缓存无限期地保存元素(除非由于空间限制或更新而被逐出),这提供了最佳的缓存性能。由于没有其他的泰坦实例在修改图表,所以不存在保存陈旧数据的危险。
如果有多个泰坦实例访问存储后端,那么应该将时间设置为在另一个泰坦实例修改图和这个泰坦实例查看数据之间允许的最长时间。如果所有的泰坦实例都能立即看到任何更改,那么在分布式设置中应该禁用数据库级缓存。然而,对于大多数应用程序来说,一个特定的泰坦实例可以看到一些延迟的远程修改,这是可以接受的。最大允许的延迟越大,缓存性能就越好。
请注意,给定的泰坦实例总是会立即看到它自己对图的修改,而不管配置的缓存过期时间是什么。
b.2缓存大小
db-cache-size选项的配置控制了泰坦的数据库级缓存被允许消费的堆空间。缓存越大,它的效率就越高。但是,大的缓存大小可能导致过度的GC和糟糕的性能。
缓存大小可以被配置为百分比(表示为0到1之间的小数),可以使用JVM运行泰坦的总堆空间,也可以作为绝对的字节数。
请注意,缓存大小指的是缓存所占用的堆空间的数量。泰坦的其他数据结构和每个开放事务都将占用额外的堆空间。如果其他的软件层在同一个JVM中运行,这些可能会占用大量的堆空间(例如,Rexster、嵌入式Cassandra等)。在堆内存估算中保持保守。配置一个太大的缓存会导致内存溢出异常和过度GC。
b.3清理等待时间
当一个顶点被局部修改时(例如添加了一条边),所有顶点相关的数据库级缓存条目都被标记为过期并最终被清除。这将导致泰坦在下一次访问时从存储后端刷新顶点的数据,并重新填充缓存。
然而,当存储后端最终保持一致时,触发驱逐的修改可能还不可见。通过配置缓存。缓存将等待至少这么多毫秒,然后再用从存储后端检索到的条目重新填充缓存。
如果泰坦是在本地运行的,或者是在存储后端,它保证了对修改的立即可见性,那么这个值就可以设置为
0。
c
存储后端缓存
每个存储后端都维护自己的数据缓存层。这些缓存得益于压缩、数据紧凑、协调过期,并且经常被维护在堆中,这意味着可以使用大型缓存,而不会导致垃圾收集问题。虽然这些缓存可能比数据库级缓存大得多,但是访问速度也比较慢。
5.事务日志(2.11)
三、索引的创建方式
1、复合索引
Composite Index
graph.tx().rollback() //如果当前有事务正在执行,则创建索引失败
mgmt.buildIndex('byNameComposite',Vertex.class).addKey(name).
buildCompositeIndex()
mgmt.buildIndex('byNameAndAgeComposite',Vertex.class).addKey(name).addKey(age).buildCompositeInex() //索引绑定
mgmt.
awaitGraphIndexStatus(
graph, 'nameAndAge').call() //将索引注册到图中
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("byNameComposite"), SchemaAction.
REINDEX
).get()//索引重建
mgmt.updateIndex(mgmt.getGraphIndex("byNameAndAgeComposite"), SchemaAction.REINDEX).get()
mgmt.commit()
如:g.V().has('age', 30).has('name', 'hercules')
2、
单一索引
Index Uniqueness
graph.tx().rollback() //如果当前有事务正在执行
,则创建索引失败
name = mgmt.getPropertyKey('name')
mgmt.buildIndex('byNameUnique', Vertex.class).addKey(name).unique().buildCompositeIndex()
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("byNameUnique"), SchemaAction.REINDEX).get()
mgmt.commit()
3、
混合索引
Mixed Index
graph.tx().rollback() //如果当前有事务正在执行,则创建索引失败
name = mgmt.getPropertyKey('name')
age = mgmt.getPropertyKey('age')
mgmt.buildIndex('nameAndAge',Vertex.class).addKey(name).addKey(age).buildMixedIndex("search")
mgmt.awaitGraphIndexStatus(graph, 'nameAndAge').call() //将索引注册到图中,开始生效
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("nameAndAge"), SchemaAction.REINDEX).get() //索引重建
mgmt.commit()
如: g.V().has('name', textContains('hercules')).has('age', inside(20, 50))
关于复合和混合索引
a.使用复合索引来进行精确匹配索引检索。复合索引不需要配置或操作外部索引系统,并且通常比混合索引快得多。
b.作为一个例外,当查询约束的不同值的数量相对较小或者一个值被期望与图中的许多元素相关联时,使用混合索引来进行精确匹配(例如,在低选择性的情况下)。
使用混合索引来进行数值范围、全文或地理空间索引。另外,使用混合索引可以加速order().by()查询。
四、数据库操作
HBase为例
在BigTable数据模型下,每个表都是一组行。每一行由一个键惟一地标识。每一行由一个任意的(大的,但有限的)单元组成。单元格由列和值组成。单元格是由给定行内的列惟一标识的。BigTable模型中的行被称为“宽行”,因为它们支持大量的单元格,并且这些单元的列不必像关系数据库中所要求的那样预先定义。
泰坦对BigTable数据模型有一个额外的要求:单元格必须按照其列进行排序,而列范围指定的单元的子集必须有效地检索(例如使用索引结构、跳跃表或二进制搜索)。
此外,一个特定的BigTable实现可以保持按键顺序排列的行。泰坦可以利用这样的键序来有效地划分图形,从而为非常大的图形提供更好的加载和遍历性能。
1.创建-本地模式
$ ./bin/start-hbase.sh
TitanGraph graph = TitanFactory.build()
.set("storage.backend", "hbase")
.open();
2.远程集群模式
TitanGraph g = TitanFactory.build()
.set("storage.backend", "hbase")
.set("storage.hostname", "77.77.77.77, 77.77.77.78, 77.77.77.79")
.open();
如果要是用带有内存的后端存储形式,需配置storage.backend=inmemory
3.数据库字段设置的可变性等级
每个配置选项都有一个可修改的级别,它决定了在数据库首次打开之后是否可以修改它。下面的列表描述了可变性级别。
FIXED
一旦数据库被打开,这些配置选项就无法在数据库的整个生命周期内进行更改。
GLOBAL_OFFLINE
当所有的实例都被关闭时,这些选项只能对整个数据库集群进行一次更改。
GLOBAL
这些选项只能在整个数据库集群的全局范围内进行更改
MASKABLE
这些选项是全局的,但是可以由本地配置文件覆盖。
LOCAL
这些选项只能通过一个本地配置文件来提供
五、索引后端(主要以solr为例)
1、全文搜索
将一个属性值作为全文搜索索引时,需要设置映射的属性类型,才能被显式的查找 *
映射主要类型有:
Mapping.TEXT.asParameter() 以文本形式
Mapping.STRING.asParameter() 以整个字符串形式
Mapping.TEXTSTRING.asParameter() 字符串文本形式
Parameter.of('mapped-name', 'bookname') 特殊的字段形式
如:
mgmt = graph.openManagement()
summary = mgmt.makePropertyKey('booksummary').dataType(String.class).make()
mgmt.buildIndex('booksBySummary', Vertex.class).addKey(summary, Mapping.TEXT.asParameter()).buildMixedIndex("search")
mgmt.commit()
2、索引查找
a.索引直接查找
indexQue
ry("索引名称", "v.text:(查找内容)
")
for (Result<Vertex> result : graph.indexQuery("vertexByText", "v.text:(farm uncle berry)").vertices()) {
System.out.println(result.getElement() + ": " + result.getScore());
}
b.查找键名
graph.indexQuery("vertexByText", "v.\"first_name\":john").vertices()
c.查找元素定义冲突的处理
graph.indexQuery("vertexByText", "v.name:v.john").vertices() //DOES NOT WORK!
graph.indexQuery("vertexByText", "$v$name:v.john").setElementIdentifier("$v$").vertices()
3、solr连接
Solr是高度可靠的,可扩展性和容错性,提供分布式索引、复制和负载平衡查询、自动故障切换和恢复,集中配置和更多的搜索引擎。他提供了一系列基于索引的查询方法
a、连接:
Connecting to SolrCloud 连接到SolrCloud
index.search.backend=solr
index.search.solr.mode=cloud
index.search.solr.zookeeper-url=localhost:2181
Connecting via HTTR 通过httr连接
index.search.backend=solr
index.search.solr.mode=http
b、特性:
Titan支持Solr为 索引后端。这里有一些Solr对Titan的支持:
全文:支持所有文本谓词搜索与给定单词、前缀或正则表达式匹配的文本属性。
地理:支持geo.within条件搜索点属于一个给定的圆。只支持索引和查询的圆。
数值范围:支持所有数值的比较。
生命期:支持自动终止索引元素。
时态:毫秒粒度时间索引。
c、solr集合
c1、在springcloud配置中使用solr
集合初始化
之前为图定义了一个"Mixed index ",泰坦创造了一个在Solr中与索引名称相匹配的新的集合。为了创建一个新的集合,Solr的需要为集合配置集的定义,指定模式(SCHEMA.XML和其他文件)。Titan分布式包含默认配置集。“泰坦”提供的配置集必须从“泰坦”安装到“SolrCloud”中的一个Solr节点上。
将泰坦提供的默认配置集(core)复制到Solr节点:
确定要复制配置文件的目标Solr机器。
在“solr”目录下创建一个新的配置集目录。如果使用默认的Solr安装:$SOLR_HOME/server/solr/configsets/{config_set}
复制titan/conf/solr 下内容包括子目录$SOLR_HOME/server/solr/configsets/{config_set}/到solr新建目录
接下来,必须将缺省配置集加载到zookeeper。有两种推荐的方法来实现这一点:
选项1:
执行配置集的手动拷贝之后:
打开Solr web界面,选择核心管理添加核心(请记住,核心与配置集是相同的)
更改名称和实例dir以匹配您的configset名称
点击添加核心
选项2:
执行配置集的手动拷贝之后:
使用Solr命令行加载一个配置集,您的应用程序将定义第一个集合(索引)。
$JAVA_HOME/bin/java -Dsolr.install.dir=$SOLR_HOME -Dlog4j.configuration=file:$SOLR_HOME/server/scripts/cloud-scripts/log4j.properties -classpath $SOLR_HOME/server/solr-webapp/webapp/WEB-INF/lib/*:$SOLR_HOME/server/lib/ext/\* org.apache.solr.util.SolrCLI create_collection -name {index name} -shards 2 -replicationFactor 1 -confname {config_set} -confdir {config_set} -configsetsDir $SOLR_HOME/server/solr/configsets -solrUrl
http://<solrhostname>:8983/solr
泰坦提供了一个index.[X].solr.configset配置属性,如果指定的话,允许泰坦为它所创建的所有集合(索引)重用一个配置集。要使用该属性,请在泰坦配置参数中指定它,并将值设置为每个步骤手动复制的configset的名称。
index.search.solr.configset=titanconfigset
如:在上面的示例中,默认的泰坦配置设置文件将被复制到下一个solr节点
:$ SOLR_HOME /server/ solr / configsets / titanconfigset
c2、在HTTP配置中使用Solr
创造一个与泰坦相兼容的新核心:
确定要复制配置文件的目标Solr机器。
在“solr”目录下创建一个新的配置集目录。如果
使用默认的Solr安装:
$SOLR_HOME/server/solr/configsets/{config_set}
复制
titan/conf/solr 下内容包括子目录
$SOLR_HOME/server/solr/configsets/{config_set}/到solr新建目录
corename必须与用于构建索引的索引名称匹配,您需要为每个惟一索引创建一个新的核心,遵循上面的步骤。
mgmt.buildIndex('{core_name}', Vertex.class).addKey(name).buildMixedIndex('search')
4、
Lucene配置
Apache Lucene是一个高性能、全功能的文本搜索引擎库,完全用java写的。它是一种适用于几乎所有需要全文搜索的应用程序的技术,尤其是跨平台的。Apache Lucene是一个可以免费下载的开源项目。
配置:
index.search.backend=lucen
index.search.directory=/tmp/searchindex
六、高级设置
1、高级模式定义选项
static vertics 静态顶点的设置
设置边,属性,顶点的
TTL(有效期)
顶点标签可以定义为
静态,这意味着在创建它们的事务之外,带有该标签的顶点不能被修改。
如:
mgmt = graph.openManagement()
tweet = mgmt.makeVertexLabel('tweet').setStatic().make()
mgmt.setTTL(tweet, Duration.ofHours(36))
mgmt.commit()
2、数据一致性
a.加锁保证数据一致性
为了确保一致性,泰坦必须获得锁,因为底层存储后端不提供事务隔离。由于加锁会需要耗费其他的资源,所以在性能方面影响较大,默认是不加锁的,由用户决定是那些字段是需要加锁的
TitanManagement.setConsistency(element, ConsistencyModifier.LOCK)
如:
mgmt=graph.openManagement()
name=mgmt.makePropertyKey('consistentName').dataType(String.class).make()
index=mgmt.buildIndex('byConsistentName',Vertex.class).addKey(name).unique().buildCompositeIndex()
mgmt.setConsistency(name, ConsistencyModifier.LOCK) // Ensures only one name per vertex
mgmt.setConsistency(index,
ConsistencyModifier.LOCK
) // Ensures name uniqueness in the graphmgmt.commit()
b.不加锁保持数据一致性
由于加锁是比较昂贵的操作,并且容易造成死锁,在其他情况下,最好允许冲突的事务继续进行,并在读取时解决不一致的问题。这是一种常用于大规模数据系统的设计模式,当冲突的实际可能性很小时,这种设计模式最有效
mgmt = graph.openManagement()
related = mgmt.makeEdgeLabel('related').make()
mgmt.setConsistency(related,
ConsistencyModifier.FORK
)
mgmt.commit()
注:边缘分叉只适用于多边缘。具有多重约束的边缘标签不能使用此策略,因为在边缘标记定义中需要设置约束,该定义需要显式锁,也可以使用底层存储后端的冲突解决机制。*
3、数据非一致性
a、临时非一致性
b、Ghost Vertics
4、操作失败以及恢复
a、事务提交失败
配置事务提交日志
tx.log-tx = true
tx.max-commit-time = 10000
此外,必须设置一个单独的进程,读取日志以识别部分失败的事务并修复导致的任何不一致。建议在连接到集群的单独机器上运行事务修复过程,以隔离故障。配置一个单独控制的进程来运行以下操作:指定时间开始时间,因为恢复进程应该从读取日志开始写前时间。
recovery = TitanFactory.startTransactionRecovery(graph, startTime, TimeUnit.MILLISECONDS);
b.Titan实例化失败
mgmt = graph.openManagement()mgmt.getOpenInstances() //all open instances
==>7f0001016161-dunwich1(current)
==>7f0001016161-atlantis1mgmt.forceCloseInstance('7f0001016161-atlantis1') //remove an instancemgmt.commit()
注:当前泰坦实例的唯一标识符用后缀(当前)标记,以便易于识别。这种情况下不能关闭通过forcecloseinstance方法而应该通过g.close()关闭。
必须确保手动删除的实例确实不再活动。从集群中移除活动的泰坦实例可能会导致数据不一致。因此,当泰坦在自动重启实例的环境中操作时,特别要小心使用这个方法。
5、索引管理
a.索引重建
XX:
SchemaAction.REINDEX
重建索引
SchemaAction.DISABLE_INDEX
删除
使用MapReduce管理
graph = TitanFactory.open(...)
mgmt = graph.openManagement()
mr=newMapReduceIndexManagement(graph)
mr.updateIndex(mgmt.getRelationIndex(mgmt.getRelationType("battled"),"battlesByTime"),
XX
).get()
mgmt.commit()
使用TitanManagement管理
m = graph.openManagement()
i = m.getGraphIndex('indexName')
m.updateIndex(i,
XX
).get()
m.commit()
6、批量加载
a、批处理
使用storage.batch-loading要求用户确保加载数据的内部一致性和符合已经图形中的任何数据。特别是,当启用批处理加载时,并发类型的创建可能导致严重的数据完整性问题,同时当使用批处理时Titan是禁用锁定的。因此,我们强烈建议在配置文件中禁用自动类型创建
schema.default =none
b、优化id分配
id大小分配
每个新添加的顶点或边都分配一个唯一ID。id块获取过程非常昂贵,因为它需要保证块的全局唯一赋值。增加ids.block-size减少收购数量却有可能让许多ID分配和因此浪费。对于事务性工作负载,默认的块大小是合理的,但在批量加载时,顶点和边的添加要频繁得多,并且继承得很快。因此,一般情况下,根据每个机器添加的顶点数量,将块大小增加10倍或更多。
注:所有Titan的实例必须配置为ids.block-size确保ID分配相同的值。因此,在改变这个值之前要小心关闭所有的泰坦实例
i
d获取过程
当许多并行实例经常分配id块时,实例之间的分配冲突不可避免地会出现,并减慢分配过程。此外,由于批量加载而导致的写入负荷增加,可能会进一步减慢进程的速度,直至泰坦认为它失败并抛出异常。有三种配置选项可以调整以避免这种情况。
1)ids.authority.wait-time配置毫秒ID池管理等身份块应用被存储后端承认时间。这一次越短,应用程序在拥挤的存储集群上失败的可能性就越大。
按照以往经验 可将该值设置为在负载下存储后端集群上测量读写时间之和的九十五百分。
注:这个值在所有泰坦实例中应该相同。
2)ids.renew-timeout配置毫秒数Titan的ID池管理将等待总是尝试去获得一种新的ID块在失败前。
经验法则:将此值设置大一点,不必担心因故障恢复等太久。增加的唯一缺点是泰坦将在不可用的存储后端集群上进行长时间的尝试。
c、优化写和读
泰坦缓冲区以小批量的方式编写和执行它们,以减少对存储后端的请求数量。这些批次的大小是由storage.buffer-size。当在短时间内执行大量写入操作时,存储后端可能会因写入请求而过载。在这种情况下,增加
storage.buffer-size可以避免失败的数量增加,从而降低写入请求的请求数。
然而,增加缓冲区的大小会增加写入请求的延迟和失败的可能性。因此,增加事务负载的设置是不可取的,在批量加载过程中应该仔细地研究这个设置。
在批量加载期间,集群上的负载通常会增加,从而使读写操作更容易失败(特别是如果缓冲区大小如上所述增加)。Titan将根据storage.read-attempts和storage.write-attempts配置对后端存储多少次执行读或写操作在放弃之前。如果期望在批量加载时后端有高负载,通常应该增加这些配置选项。
storage.attempt-wait指定泰坦在再次尝试后台操作失败之前等待的毫秒数。较高的值可以确保重新运行的操作不会进一步增加后端的负载。
7、图的划分
当泰坦集群由多个存储后端实例组成时,在这些机器上划分图形。由于泰坦将图存储在邻接表中,所以顶点的分配决定了机器的划分。默认情况下,泰坦使用随机分区策略,随机将顶点分配给机器。随机分区是非常高效的,不需要配置,并产生平衡分区。然而,由于在检索查询结果集时需要增加跨实例通信,因此随机分区导致查询处理效率较低,因为泰坦集群增长以容纳更多的图形数据。显式图划分可以确保强连通子图频繁穿越存储在相同的实例,从而减少通信开销明显。
为了在泰坦中实现显式的图形分割,必须在泰坦集群初始化时设置以下配置选项。
cluster.partition = true
cluster.max-partitions = 32
ids.flush = false
边缘划分
顶点划分
8、数据类型的序列化
泰坦支持属性上属性值的许多类。泰坦有效序列化原语,原始数组、日期、ArrayList和HashMap。默认情况下,泰坦允许任意对象作为的属性值在,但使用默认序列化器的开销很大,可能效率不高。
七、Titan国际化
1.Bigtable数据模型
在BigTable数据模型下,每个表都是一组行。每一行由一个键惟一地标识。每一行由一个任意的(大的,但有限的)单元组成。单元格由列和值组成。单元格是由给定行内的列惟一标识的。BigTable模型中的行被称为“宽行”,因为它们支持大量的单元格,并且这些单元的列不必像关系数据库中所要求的那样预先定义。
泰坦对BigTable数据模型有一个额外的要求:单元格必须按照其列进行排序,而列范围指定的单元的子集必须有效地检索(例如使用索引结构、跳跃表或二进制搜索)。
此外,一个特定的BigTable实现可以保持按键顺序排列的行。泰坦可以利用这样的键序来有效地划分图形,从而为非常大的图形提供更好的加载和遍历性能。
2.Titan Data Layout数据模型
泰坦将每个邻接表存储为底层存储后端的一行。(64位)顶点id(泰坦唯一分配给每个顶点)是指向包含顶点邻接表的行的键。每条边和属性都被存储为一行中的单个单元,这样就可以进行有效的插入和删除操作。因此,在特定的存储后端,每个行允许的最大的单元格数,也就是泰坦可以支持这个后端的顶点的最大程度。
如果存储后端支持键序,那么邻接表将由顶点id来排序,而泰坦可以分配顶点id,这样就可以有效地划分图形。id被赋值,这样经常被访问的顶点都具有很小的绝对差异。
3.Individual Edge Layout数据模型
每条边和属性都存储在相邻顶点的行中。它们被序列化,因此列的字节顺序会遵照边缘标签的排序键。可变id编码方案和压缩对象序列化可以保持每个边/单元的存储空间尽可能小。
图中顶部一行中显示的单个边缘的存储布局。深蓝色的盒子表示数字,这些数字被编码成一个可变长度编码方案,以减少它们所消耗的字节数。红色框表示一个或多个属性值(即对象),这些属性值是在关联的属性键中引用的压缩的序列化的元数据。灰色框表示未压缩的属性值(即序列化对象)。
4.Titan的构建
要构建泰坦,需要git和Maven。
将泰坦库从GitHub复制到本地目录。
在该目录中,执行mvn clean install。这将构建泰坦,并运行内部测试套件。内部测试套件没有外部依赖项。注意,运行所有的测试用例需要大量的时间。要在构建泰坦时跳过测试,执行clean install -DskipTests。
对于全面的测试覆盖,执行 mvn clean test -P comprehensive。这将运行额外的测试,包括对外部存储后端、性能测试和并发测试的通信。综合测试套件使用Cassandra和HBase作为外部数据库,并要求Cassandra和HBase被安装。请注意,运行综合测试套件需要大量的时间(1小时)
。