列族概念和数据模型

27

我正在调查不同类型的NoSQL数据库,并试图理解列族存储的数据模型,比如Bigtable、HBase和Cassandra。

第一种模型

有些人将列族描述为一个行的集合,每一行包含多个列 [1], [2]。下面是这种模型的一个例子(列族使用大写):

{
  "USER":
  {
    "codinghorror": { "name": "Jeff", "blog": "http://codinghorror.com/" },
    "jonskeet": { "name": "Jon Skeet", "email": "jskeet@site.com" }
  },
  "BOOKMARK":
  {
    "codinghorror":
    {
      "http://codinghorror.com/": "My awesome blog",
      "http://unicorns.com/": "Weaponized ponies"
    },
    "jonskeet":
    {
      "http://msmvps.com/blogs/jon_skeet/": "Coding Blog",
      "http://manning.com/skeet2/": "C# in Depth, Second Edition"
    }
  }
}

第二个模型

其他网站将列族描述为一行内相关列的组合[3], [4]。按照这种方式建模的先前示例中的数据:

{
  "codinghorror":
  {
    "USER": { "name": "Jeff", "blog": "http://codinghorror.com/" },
    "BOOKMARK":
    {
      "http://codinghorror.com/": "My awesome blog",
      "http://unicorns.com/": "Weaponized ponies"
    }
  },
  "jonskeet":
  {
    "USER": { "name": "Jon Skeet", "email": "jskeet@site.com" },
    "BOOKMARK":
    {
      "http://msmvps.com/blogs/jon_skeet/": "Coding Blog",
      "http://manning.com/skeet2/": "C# in Depth, Second Edition"
    }
  }
}
可能第一个模型背后的理由是,并不是所有列族都像USER和BOOKMARK那样有关系。这意味着并非所有列族都包含相同的键。从这个角度看,将列族放在外层级别更自然。
“列族”的名称暗示了一组列。这正是第二个模型中展示列族的方式。
两种模型都是有效的数据表示形式。我意识到这些表示仅用于向人类传达数据;应用程序不会以这种方式“思考”数据。
问题:列族的“标准”定义是什么?它是一组行,还是一行内相关的列组?
我必须写一篇关于这个主题的论文,所以我也对人们通常如何向其他人解释“列族”概念感兴趣。这两个模型似乎相互矛盾。我想使用“正确的”或普遍接受的模型来描述列族存储。
更新:
我已经确定了第二个模型,用于解释我的论文中的数据模型。我仍然对你如何向他人说明列族存储的数据模型感兴趣。

+1 很棒的帖子,如果您的论文可以在线上获取,我很想阅读它(如果可以,请更新帖子)。 - tbone
@tbone 谢谢!这篇论文目前还没有在线上发布,但如果我有时间的话,我可能会将其中的部分内容转换成博客文章。 - Niels van der Rest
3个回答

15

Cassandra数据库遵循您提出的第一种模型。 ColumnFamily是一组行,可以以稀疏方式包含任何列(因此,如果需要,每个行可以具有不同的列名集合)。在Cassandra v0.7中,行中允许的列数几乎没有限制(为20亿)。

一个关键点是在定义上,行键必须在列族内唯一,但可以在其他列族中重新使用。因此,您可以在不同的ColumnFamilies中存储与同一键相关联的不相关数据。

在Cassandra中,这很重要,因为特定列族中的数据存储在相同的磁盘文件中,因此将可能一起检索的数据项放置在同一ColumnFamily中更加高效。这部分是实际速度问题,但也是将数据组织成明确架构的问题。这涉及到您提出的第二个定义-一个人可能认为关于特定键的所有数据都是“行”,但按列族分区。然而,在Cassandra中,它并不是真正的单行,因为同一行键的不同ColumnFamilies中的数据可以独立更改。


1
感谢您分享您的想法!我得出结论,这没有对错之分,而您的答案只是证实了这一点。它基本上是一个二维(或三维)矩阵,就像传统的数据库表格一样,但由于内容的稀疏性,它不适合通常的表格格式 :) - Niels van der Rest

11

您描述的两个模型是相同的。

列族是:

Key -> Key -> (Set of key/value pairs)

概念上,它变成了:

Table -> Row -> (Column1/Value1, Column2/Value2, ...)

把它看作是一个键/值对的Map嵌套Map。

UserProfile = {
    Cassandra = [emailAddress:"cassandra@apache.org", age:20],
    TerryCho = [emailAddress:"terry.cho@apache.org", gender:"male"],
    Cath = [emailAddress:"cath@apache.org", age:20, gender:"female", address:"Seoul"],
}

以上是列族的一个示例。如果您将其制表,您将得到一个名为UserProfile的表格,看起来像:

UserName | Email | Age | Gender | Address
Cassandra | cassandra@apache.org | 20 | null | null
TerryCho | terry.cho@apache.org | null | male | null
Cath | cath@apache.org | 20 | female | Seoul

让人感到困惑的是,与我们平常所想象的列或行不太一样。这里有许多“列族”可通过名称(键)进行查询。这些列族包含了许多键/值对的集合,也可以通过名称(行键)进行查询。最后,集合中的每个值也可以通过名称(列键)进行查找。

如果您需要一个表格参考点,“列族”将成为您的“表格”。其中的每个“键/值对集”将成为您的“行”。每个“键/值对集”的“键和值”将是“列名和其值”。

在内部,每个列族中的数据将被存储在一起,并按顺序存储,每行中的列也按顺序排列。因此,您将得到行1 -> 列1/值1,列2/值2,...,行2 -> 列1/值1 ...,...->...。因此,在这个意义上,数据的存储方式更像是一个行存储,而不像是一个列存储。

最后,这里使用的术语选择只是不幸而且容易引起误解。Column Families 中的 Columns 应该被称为 Attributes。Rows 应该被称为 Attribute Sets。Column Families 应该被称为 Attributes Families。与经典表格词汇的关系较弱且易于混淆,因为实际上它们之间存在相当大的不同。


2
据我所知,Cassandra列族不是行的集合,而是列的集群。 列基于聚簇键进行聚合。 例如, 让我们考虑下面的列族:
CREATE TABLE store (
  enrollmentId int,
  roleId int,
  name text,
  age int,
  occupation text,
  resume blob,
  PRIMARY KEY ((enrollmentId, roleId), name)
) ;


INSERT INTO store (enrollmentid, roleid, name, age, occupation, resume)
values (10293483, 01, 'John Smith', 26, 'Teacher', 0x7b22494d4549);

使用cassandra-cli获取插入的详细信息,它基于聚簇键进行很好的聚类,例如“name = John Smith”是聚簇键。

RowKey: 10293483:1
=> (name=John Smith:, value=, timestamp=1415104618399000)
=> (name=John Smith:age, value=0000001a, timestamp=1415104618399000)
=> (name=John Smith:occupation, value=54656163686572, timestamp=1415104618399000)
=> (name=John Smith:resume, value=7b22494d4549, timestamp=1415104618399000)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接