我有一个非常大且非常稀疏的矩阵,仅由0和1组成。然后我基本上处理(行 - 列)对。我每行/每列最多10k对。
我的需求如下:
(行 - 列)对的并行插入
快速检索整个行或列
快速查询是否存在(行 - 列)对
如果可能,请使用Ruby客户端
现有的数据库是否适合这种约束?
如果没有,那将是什么让我获得最佳表现:
row(indexed) | column(indexed)
(但索引必须不断刷新)
row => columns ordered list
column => rows ordered list
(但将元素并行插入列表)
感谢您的帮助!
答案 0 :(得分:4)
稀疏的0/1矩阵听起来像adjacency matrix,用于表示图形。基于此,您可能正在尝试解决某些图形问题,并且图形数据库可以满足您的需求。
图形数据库,如Neo4J,非常适合快速遍历图形,因为检索顶点的邻居需要O(给定顶点的邻居数),因此它与数字无关整个图中的顶点。 Neo4J也是事务性的,因此并行插入不是问题。您可以使用MRI Ruby中的REST API wrapper或JRuby library进行更加无缝的集成。
另一方面,如果您正在尝试分析图表中的连接,并且偶尔进行一次分析就足够了,只是让结果可用,您可以尝试使用图表框架基于Google Pregel的处理。它有点像Map-Reduce,但是针对图形处理。已有several open source implementations of that paper。
但是,如果图形数据库或图形处理框架不适合您的需求,我建议您查看HBase,这是一个基于{{3}的开源,面向列的数据存储}。它的数据模型实际上与您描述的(稀疏矩阵)非常相似,它具有行级事务,并且不需要您检索整行,只是为了检查某个对是否存在。有一些Google BigTable,但我想用JRuby代替MRI与它进行交互会更安全。
答案 1 :(得分:1)
如果您的矩阵非常稀疏(即节点只有少量互连),那么您将从RDBMS(如Oracle,PostgreSQL或SQL Server)获得合理有效的存储。基本上你会有一个包含两个字段(row,col)和单向索引或键的表。
单向设置主键(取决于您主要是按行还是列查询),然后在字段上反向创建另一个索引。这将仅存储连接存在的数据,并且它将与图中的边缘数量成比例。
索引将允许您有效地检索行或列,并始终保持同步。
如果每个节点有10,000个节点和10个连接,则数据库将只有100,000个条目。每个节点100个边缘将有1,000,000个条目,依此类推。对于稀疏连接,这应该是相当有效的。
fag-packet估计值
该表基本上有一个行和列字段。如果聚集索引(行,列,值),那么另一个覆盖索引将(列,行,值)。如果添加和删除是随机的(即不按行或列进行批处理),则I / O将大约是表格的两倍。
如果您按行或列对插入进行批处理,那么您将在其中一个索引上获得较少的I / O,因为记录实际上位于其中一个索引中。如果矩阵确实是稀疏的,那么这种邻接列表表示是迄今为止最紧凑的存储方式,这比将其存储为2D数组要快得多。
具有64位值的10,000 x 10,000矩阵将需要800MB加上行索引。更新一个值需要为每次写入写入至少80k(写出整行)。如果可以按插入行上的行对数据进行分组,则可以按行优化写入。如果插入是实时和随机的,那么你将为每个插入写出一个80k的行。
实际上,这些写入会有一定的效率,因为它们都会在一个大部分连续的区域中写出来,这取决于NoSQL平台物理存储其数据的方式。
我不知道您的连接是多么稀疏,但如果每个节点平均有100个连接,那么您将拥有1,000,000条记录。这将是每行约16个字节(Int4行,Int4列,Double值)加上聚簇表和覆盖索引的几个字节开销。这种结构需要大约32MB +一点点开销才能存储。
更新行或列上的单个记录将导致两个单磁盘块写入(8k,实际上是一个段)用于随机访问,假设插入不是行或列排序。
向数组表示中添加100万个随机排序的条目将导致大约80GB的写入+一点开销。将1m条目添加到邻接列表表示将导致大约32MB的写入(实际上16GB,因为将为每个索引叶节点写入整个块),加上一点开销。
对于该级别的连接(10,000个节点,每个节点100个边缘),邻接列表将 在存储空间中更高效,也可能在I / O中更高效。您将从平台获得一些优化,因此某种基准可能适合于确定哪种方法在实践中更快。