传统关系型数据库以实体和关系为模型,过去长期占据绝对主导地位。但是,随着大数据的兴起,它的一些缺点也越来越明显,尤其是在需要处理非常复杂的实体关系时,关系型数据库就越来越无能为力了。当我们要表示实体之间的多对多关系时,一般会创建一个关系表。在查看实体之间的关系时,我们需要重新关联这种关系。这通常是一项非常耗费性能的工作,尤其是当关系非常复杂或关系有很多层次时。它需要关联很多表,甚至会产生非常庞大的中间结果,导致查询非常慢甚至无法运行。图数据库基于图论,数据本身以图(如邻接表)的形式存储,在处理与图相关的任务时具有先天优势。因此,在知识图谱、社交网络分析等领域的应用越来越多。常见的图数据库下面是三种流行的图数据库及其各自的特性对比。经过我们的对比和试用,OrientDB和Neo4j比Titan好用,社区也更活跃。但Neo4j最大的缺陷是它不是真正的分布式,当数据量超过单机承载能力时难以处理;而且Neo4j和OrientDB的底层存储是独立开发的,Titan支持HBase/Cassandra作为底层存储。Hadoop,我们目前主要的数据平台,可以很好的集成;此外,Titan除了支持OLTP操作外,还可以结合Spark进行OLAP相关的分析。所以我们最终决定使用Titan。Titan技术架构Titan整体技术架构如上图。存储、索引、OLAP计算引擎是可选的开源组件:底层存储支持HBase/Cassandra,存储可以并行扩展,几乎没有容量限制;支持Elasticsearch/Solr/Lucene作为外部索引插件,实现非等价查询时也可以使用索引;ManagementAPI负责Schema的创建、修改、删除、实例管理等操作;图上的操作接口通过TinkerpopAPI提供;InternalAPI、DatabaseLayer、Storage和IndexInterfaceLayer负责将Tinkerpop和ManagementAPI的图操作转化为对底层存储Cassandra和HBase的操作(如HBase中的put、get、scan)。GraphComputer以Spark/MR的形式提供图的OLAP操作,对子图或整图进行分析(如计算Pagerank)。Titan图表示Titan使用三种类型的信息:节点、边和属性来描述一个图,如上图所示。节点(Vertex):用来表示一个实体,节点通过指定不同的标签(LABEL)来区分具体的实体类型,比如Titan、Location;该节点由唯一的VertexID标识,该ID由Titan自动生成并管理。边:用于描述实体之前的关系,有出口节点和入口节点;边还有一个标签(LABEL),用来区分边的类型,比如上图中的father和lives;边有方向;一条边可以指定是否只允许单向查询;一条边可以指定MULTILICITY,表示可以存在多少条LABEL边;一条边也有一个唯一的EdgeID,它由Titan自动生成和管理。属性(property):可以在节点上,也可以在边上,用于描述节点和边的附加信息;attribute通过PROPERTYKEY表示该属性是什么属性,如上图name,age,place;属性还可以指定CARDILITY,用于表示该属性可以有多个属性;该属性还有一个唯一的PropertyID,由Titan自动生成和管理;节点和边的属性都可以添加索引,此时通过属性查询特定节点或边时,可以直接通过索引定位到对应节点或边的ID,减少扫描数据量,提高性能。Titan的图查询Titan通过Tinkerpop的Gremlin语言提供图的查询、修改等操作。一个Titan实例对应一个Tinkerpop的GremlinServer。多个GremlinServer对应同一个存储后台,组成一个Titan分布式集群。用户可以通过GremlinClient或RestfulAPI提交查询请求。示例查询如下:#createaclustergremlin>graph=TitanFactory.open('conf/titan-hbase.properties')==>standardtitangraph[hbase:[titan003,titan004,titan005]]gremlin>g=graph。traversal()==>graphtraversalsource[standardtitangraph[hbase:[titan003,titan004,titan005]],standard]#查询名字为'saturn'的节点gremlin>saturn=g.V().has('name','saturn').next()==>v[256]#查看土星节点有哪些属性gremlin>g.V(saturn).valueMap()==>[name:[saturn],age:[10000]]#saturn的爷爷名字gremlin>g.V(saturn).in('father').in('father').values('name')==>hercules#查询hercules的父母信息gremlin>g.V(hercules).out('father','mother')==>v[1024]==>v[1792]gremlin>g.V(hercules).out('father','mother').values('name')==>jupiter==>alcmenegremlin>g.V(hercules).out('father','mother').label()==>god==>humangremlin>hercules.label()==>demigodTitan底层存储格式Titan中的节点和边是根据每个节点的邻接表包含节点的所有相邻边和节点的属性,存储遵循大表数据模型。也就是说,表格是由多行组成的,每一行又是由很多Cell组成的,而每个Cell又是由Column和Value组成的。Rows由唯一的Key标识,每个Cell由Key+column标识。TitanLayout:Edge&PropertyLayout:如上图,针对Titan的实现。每行的Key是节点的VertexID,是Titan自动维护的一个64bit长整数。每个Cell是一个节点或连接到该节点的边的属性。边Cell的Column包含边的方向、边上指定的排序属性信息、相邻点的ID、边的ID;边缘的值包含边缘上的所有属性(签名属性在前)。属性Cell的Column包含属性的类型ID;Value包含属性的ID和属性的值。拍拍贷数据库应用我们目前基于用户信息、设备信息和社交关系构建异构网络,并将异构网络图应用于用户关联分析和反欺诈检测场景。传统方式下,我们的数据存储在RDMS中,当我们要查询用户之间的关系时,是通过关联多张表来实现的。但是这种方法存在很多问题:这些表比较大,做表关联的时候效率很低;对关系的层级支持非常有限,进出度大的节点产生的中间结果会非常大;对于图形查询不够灵活。这些都极大地限制了我们的分析能力和分析效率。针对以上痛点,我们引入了Titan图数据库。每天,10亿+节点信息和500亿+关系数据将通过重写的TitanBulkload导入Titan后台HBase,生成包含13类节点和15类边的复杂异构网络。通过这个网络,可以方便快捷地回答以下类似问题:用户A关联的用户是谁;与用户A关联的用户的特征是什么;用户A和用户B是如何关联的。下图是我们图数据库在反欺诈中的应用示例:根据原始数据图,我们可以对用户进行如下调查分析,判断特定用户是否为欺诈用户或是否与欺诈用户相关联user:通过特定规则过滤可疑用户查看与可疑用户有特定关联的用户查看所有与可疑用户有特定关联的用户组成的子网的网络特征和用户特征这样我们在调查过程中大大减少了工作量,整体效率提升25%+。笔者介绍的是拍拍贷资深数据工程专家冯金明。
