【问题标题】:Cassandra SELECT on 2ndary index always sorted on partition key?2ndary 索引上的 Cassandra SELECT 总是按分区键排序?
【发布时间】:2014-12-31 02:20:26
【问题描述】:

假设我定义了下表和二级索引:

CREATE TABLE ItemUpdates (
    time         timestamp,
    item_name    text,
    item_context text,
    item_descr   text,
    tags         map<text, int>,
    PRIMARY KEY ((time, item_name, item_context))
);

CREATE INDEX ItemUpdateByName
    ON ItemUpdates(item_name);

CREATE INDEX ItemUpdateByContext
    ON ItemUpdates(item_context);

CREATE INDEX ItemUpdateByTag
    ON ItemUpdates(KEYS(tags));

数据模型的一般背景信息:项目在上下文中具有唯一名称,因此 (item_name, item_context) 是项目的自然键。标签有一些与之相关的价值。

我的应用程序中的一个自然查询是“向我显示带有特定标签的项目 X 的​​所有更新”。这转化为:

SELECT * FROM ItemUpdates
    WHERE item_name='x'
        AND item_context='a'
        AND tags CONTAINS KEY 't';

当我尝试一些查询时,我注意到虽然集群使用了 Murmur3Partitioner,但结果是按时间排序的。当您考虑到 Cassandra 将二级索引存储为宽行并且列按其名称排序时,这是有道理的。

(1) Cassandra 在选择一个(n)(一组)索引列时是否总是返回按分区键排序的行?

我觉得这很有趣的原因是我的应用程序中的其他自然查询包括:

  • 获取项目 X 自 D 日以来的所有更新
  • 获取项目 X 的​​ 300 条最新更新

令我惊讶的是,在 ItemUpdates 上的 select 语句中添加子句 ORDER BY time DESC 会导致错误消息“不支持带有二级索引的 ORDER BY”。

(2)(如何)当我通过选择索引列来缩小查询范围时,如何对分区键进行范围查询?

【问题讨论】:

    标签: indexing cassandra cql3 range-query


    【解决方案1】:

    您应该在 cassandra 上获得的唯一自然“自动”排序是针对宽行中的列。使用 murmur3 时的分区没有“排序”,因为这会弄乱随机分布(afaik)。索引作为宽行存储在“隐藏”表中的每个节点上。当对索引进行过滤时,它会在“节点”上点击“分区”,并且值是该分区中的行(对应于该节点上的匹配行)。尝试使用不同的数据集和不同的列进行查询。也许您拥有的数据会导致对结果进行排序。

    (2) 就目前而言,您只能对集群键进行范围查询,而不能对分区键进行范围查询。一般来说,为了高效查询,您应该尝试点击一个(或几个)分区,并过滤索引/过滤集群键/集群键上的范围查询。如果你试图不命中一个分区,它就会变成一个集群范围的操作,这通常不是很好。如果您正在寻找进行集群范围的分析(ala map reduce 风格),请查看 Apache Spark。 Spark cassandra 集成相当不错,而且越来越好。

    【讨论】:

    • 谢谢。所以(1)的答案是“不”。检查了你的建议,确实:结果没有回来排序。在我看来,我仍然不完全了解二级索引的内部结构。我认为索引是宽行的 CF,索引值作为宽行的分区键,“目标”行的分区键作为列名(没有值)。结果将是索引查找的结果将是分区键的排序(!)列表(因为列按名称排序)。
    • ItemUpdates 的第一个版本将 ((item_name, item_context), time) 作为 PK。我的问题中的项目符号查询当然会很简单。但是做了一些计算,我了解到这些行在一段时间后会变得太宽,所以我需要进行不同的分区。有什么建议吗?
    • 你可以引入分桶。例如,((名称、上下文、年份)、时间)。那就是每年给你一个宽行。如果这太多了,您可以按月+年:((名称,上下文,月_年),时间)。可能意味着来自客户端的更多查询,但通常 n*2ms 查询比大型 map reduce 便宜。
    • 不错的见解。所以你是说高效查询的模式是:首先选择分区键,然后使用集群键或二级索引进一步过滤,对吧?
    • 最有效的是指定分区+集群键。下一个最有效的是分区键+(集群和/或索引)。然后下一个最有效的是几个分区键(使用 IN 语句)。这在一定程度上取决于宽行大小。不指定分区键是集群范围的操作,通常最好将 Spark 用于那些(分析类型)的事情。
    猜你喜欢
    • 2017-03-13
    • 2011-10-28
    • 1970-01-01
    • 2012-07-22
    • 2014-11-20
    • 1970-01-01
    • 2017-05-24
    • 2011-10-18
    • 2021-02-28
    相关资源
    最近更新 更多