在cassandra中拥有多个聚类列是否有任何主要缺点?

时间:2015-03-03 04:33:27

标签: cassandra geohashing

我正在设计一个cassandra表,我需要能够通过geohash检索行。我有一些有用的东西,但我想避免范围查询比我现在能够做的更多。

当前表模式是这样的,geo_key包含geohash字符串的前五个字符。我使用geo_key查询,然后在完整的geohash上进行范围过滤,允许我根据5或更长的geohash为搜索添加前缀:

CREATE TABLE georecords (geo_key text,geohash text, data text) PRIMARY KEY (geo_key, geohash))

我的想法是,我可以将geohash的字符存储为单独的列,允许我指定尽可能多的字符,以便在geohash上进行前缀匹配。我担心的是使用多个群集列可能会产生什么影响:

CREATE TABLE georecords (g1 text,g2 text,g3 text,g4 text,g5 text,g6 text,g7 text,g8 text,geohash text, data text) PRIMARY KEY (g1,g2,g3,g4,g5,g6,g7,g8,geohash,pid))

(我并不真正关心分区键的基数 - g1会有至少30个值,我也有其他的解决方法)

除了分区键的基数和额外的存储要求之外,如果我使用了多个集群列方法,我应该注意什么?

2 个答案:

答案 0 :(得分:2)

  

除了分区键的基数和额外的存储要求之外,如果我使用了多个集群列方法,我应该注意什么?

这似乎是一个有趣的问题,因此我构建了一些具有不同PRIMARY KEY结构和选项的CQL表。然后我使用http://geohash.org/提出了几个端点,然后插入它们。

aploetz@cqlsh:stackoverflow> SELECT g1, g2, g3, g4, g5, g6, g7, g8, geohash, pid, data FROm georecords3;

 g1 | g2 | g3 | g4 | g5 | g6 | g7 | g8 | geohash      | pid  | data
----+----+----+----+----+----+----+----+--------------+------+---------------
  d |  p |  8 |  9 |  v |  c |  n |  e |  dp89vcnem4n | 1001 |    Beloit, WI
  d |  p |  8 |  c |  p |  w |  g |  v |    dp8cpwgv3 | 1003 |   Harvard, IL
  d |  p |  c |  8 |  g |  e |  k |  t | dpc8gektg8w7 | 1002 | Sheboygan, WI
  9 |  x |  j |  6 |  5 |  j |  5 |  1 |    9xj65j518 | 1004 |    Denver, CO

(4 rows)

如您所知,Cassandra旨在使用特定的精确密钥返回数据。在该方法中使用多个群集列帮助,因为您正在帮助Cassandra快速识别您想要检索的数据。

我唯一想要改变的是,看看你是否可以在PRIMARY KEY中没有geohashpid。我的直觉说要摆脱pid,因为它实际上并不是你要查询的任何东西。它提供的唯一值是唯一性,如果您计划多次存储相同的地理数据,则需要它。

在PRIMARY KEY中包含pid会留下一个非键列,并允许您使用WITH COMPACT STORAGE指令。实际上唯一真正的优势在于节省磁盘空间,因为聚类列名称不与值一起存储。从cassandra-cli工具中查看表格时,这一点就变得很明显了:

没有紧凑型存储空间:

[default@stackoverflow] list georecords3;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: d
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:, value=, timestamp=1428766191314431)
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:data, value=42656c6f69742c205749, timestamp=1428766191314431)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:, value=, timestamp=1428766191382903)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:data, value=486172766172642c20494c, timestamp=1428766191382903)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:, value=, timestamp=1428766191276179)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:data, value=536865626f7967616e2c205749, timestamp=1428766191276179)
-------------------
RowKey: 9
=> (name=x:j:6:5:j:5:1:9xj65j518:1004:, value=, timestamp=1428766191424701)
=> (name=x:j:6:5:j:5:1:9xj65j518:1004:data, value=44656e7665722c20434f, timestamp=1428766191424701)

2 Rows Returned.
Elapsed time: 217 msec(s).

使用紧凑型存储空间:

[default@stackoverflow] list georecords2;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: d
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001, value=Beloit, WI, timestamp=1428765102994932)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003, value=Harvard, IL, timestamp=1428765717512832)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002, value=Sheboygan, WI, timestamp=1428765102919171)
-------------------
RowKey: 9
=> (name=x:j:6:5:j:5:1:9xj65j518:1004, value=Denver, CO, timestamp=1428766022126266)

2 Rows Returned.
Elapsed time: 39 msec(s).

但是,出于以下原因,我建议使用WITH COMPACT STORAGE 反对

  • 创建表格后无法添加或删除列。
  • 它可以防止您在表格中包含多个非键列。
  • 它真的打算用于旧的(已弃用的)基于thrift的列族(表)建模方法,并且不再需要使用/需要了。
  • 是的,它可以节省磁盘空间,但磁盘空间很便宜,所以我认为这是一个非常小的好处。

我知道你说过#34;除了分区键的基数",但无论如何我会在这里提到它。您将在我的示例数据集中注意到,几乎所有行都存储了d分区键值。如果我要为自己创建一个这样的应用程序,跟踪威斯康星州/伊利诺伊州州线区域的地理位置,我肯定会遇到大部分数据都存储在同一个分区中的问题(在我的集群中创建一个热点)。因此,了解我的用例和潜在数据,我可能会将前三个左右的列组合成一个分区键。

将所有内容存储在同一分区键中的另一个问题是每个分区最多可以存储大约20亿个列。因此,如果您的数据是否能够超过该标记,那么放置一些内容也是有意义的。显然,分区键的基数越高,遇到此问题的可能性就越小。

通过查看您的问题,在我看来,您已经查看了您的数据并且您理解了这一点......确定"加上。"分区键中的30个唯一值应提供足够的分布。我只是想花一些时间来说明可能会有多大的交易。

无论如何,我还想添加一个"很好地完成,"因为听起来你走在正确的轨道上。

修改

  

对我来说,尚未解决的问题是在哪种情况下哪种方法会更好地扩展。

可伸缩性与N个节点中有多少个R副本有关。作为Cassandra scales linearly;您添加的节点越多,您的应用程序可以处理的事务就越多。纯粹来自数据分发场景,您的第一个模型将具有更高的基数分区键,因此它将比第二个更均匀地分布。但是,第一个模型在查询灵活性方面提出了一个更具限制性的模型。

此外,如果您正在分区内进行范围查询(我相信您说过的话),那么第二个模型将以非常高效的方式实现。分区中的所有数据都存储在同一节点上。所以查询g1='d' AND g2='p' ...等的多个结果将会表现得非常好。

  

我可能只需要更多地使用数据并运行测试用例。

这是个好主意。我想你会发现第二个模型是要走的路(在查询灵活性和查询多行方面)。如果在单行查询中两者之间存在性能差异,我怀疑它应该可以忽略不计。

答案 1 :(得分:1)

这是我发现的最佳Cassandra建模指南:http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/

我已成功使用复合列(其中6个)用于非常高的写入/读取负载。使用紧凑型存储(http://docs.datastax.com/en/cql/3.0/cql/cql_reference/create_table_r.html)时,没有明显的性能损失。

紧凑型存储意味着数据内部存储在一行中,但您只能拥有一个数据列。无论您选择哪种数据模型,这似乎都很适合您的应用程序,并且会最大限度地利用您的geo_key过滤。

要考虑的另一个方面是列在Cassandra中排序。拥有更多聚类列将提高排序速度并可能提高查找速度。

但是,在您的情况下,我首先将geohash作为行键并打开行缓存以进行快速查找(http://www.datastax.com/dev/blog/row-caching-in-cassandra-2-1)。如果缺乏性能,我会对不同的数据表示进行性能测试。