最近在抓取一些社交网站的数据,抓下来的数据用MySql存储。问我为什么用MySql,那自然是入门简单,并且我当时只熟悉MySql。可是,随着数据量越来越大,有一个问题始终困扰着我,那就是社交关系的存储。
就以新浪微博举例,一个大V少则十几万,多则几千万的粉丝,这些关注关系要怎么存呢?在MySql中,一条关注关系(大V id,大V的一个粉丝 id)存为一条数据,那么当用户数量上来的时候,关注关系轻松破亿,破十亿,甚至上百亿,并且为了保证每条数据的唯一性,还需要设置联合索引,MySql就有些力不从心了。那么有人要说了:分表呀。嗯,没错,分表的确可以在插入端和读取端提升一些速度。比如我们可以根据id哈希到100张表中。查询一个用户有哪些粉丝是快了,但是查询一个用户关注了哪些人时仍然需要遍历全表。好,这时候我们还可以以(id,其关注的一个用户的id)再构造100张表,于是两种查询都快了。然而,后面那100张表是冗余数据,看着就不爽...并且生成一张子图也不方便(需要多次写SQL查表)。
于是,在搜索更好的方案时无意间发现了图形数据库,查阅一番资料后感觉确实是个不错的选择,毕竟业界的一些大佬,如twitter,Adobe等也在用。
那么,什么是图形数据库呢?在这里我贴上较为官方的定义:a database that uses graph structures for semantic queries with nodes, edges and properties to represent and store data – independent of the way the data is stored internally. It’s really the model and the implemented algorithms that matter.注意,这里只是说数据模型是图结构的,没有说数据的存储也一定要是图结构的。其数据模型如下图
进入今天的主题,我将以Neo4j为例,说明为什么选择图形数据库?
首先,先简要介绍一下Neo4j。Neo4j是由Java和Scala写成的一个NoSql数据库,专门用于网络图的存储。更详细的内容可见官网。作为一个图形数据库,Neo4j有以下优点:
更快的数据库操作。当然,有一个前提条件,那就是数据量较大,在MySql中存储的话需要许多表,并且表之间联系较多(即有不少的操作需要join表)。
数据更直观,相应的SQL语句也更好写(Neo4j使用Cypher语言,与传统SQL有很大不同)。
更灵活。不管有什么新的数据需要存储,都是一律的节点和边,只需要考虑节点属性和边属性。而MySql中即意味着新的表,还要考虑和其他表的关系。
数据库操作的速度并不会随着数据库的增大有明显的降低。这得益于Neo4j特殊的数据存储结构和专门优化的图算法。
接着,试着从更深一些的层次看图形数据库。我将从Neo4j的数据存储和数据读写两方面来说明为什么选它。
数据存储
Neo4j对于图的存储自然是经过特别优化的。不像传统数据库的一条记录一条数据的存储方式,Neo4j的存储方式是:节点的类别,属性,边的类别,属性等都是分开存储的,这将大大有助于提高图形数据库的性能。如下图:
数据读写
在Neo4j中,存储节点时使用了"index-free adjacency",即每个节点都有指向其邻居节点的指针,可以让我们在O(1) O(1) 的时间内找到邻居节点。另外,按照官方的说法,在Neo4j中边是最重要的,是"first-class entities",所以单独存储,这有利于在图遍历的时候提高速度,也可以很方便地以任何方向进行遍历。
更多的资料可以看参考资料第一条。
关于为什么选图形数据库就说到这。如今可供选择的图形数据库也不少,为什么就选择了Neo4j呢?我简要归结为以下几点:
作为较早的一批图形数据库之一,文档和各种技术博客较多。
最开始曾尝试过flockdb(据说操作简单+轻量级),但是败于安装过程...,依赖太多。