【问题标题】:How to select rows filtered by more than one entry in map colum (Cassandra 3.9)如何选择由地图列中的多个条目过滤的行(Cassandra 3.9)
【发布时间】:2017-02-07 18:46:57
【问题描述】:

我有一张这样的桌子:

CREATE TABLE test.products (
id uuid PRIMARY KEY,
name text,
params map<text, text>);

我在 params 字段上创建了一个条目索引,如下所示:

CREATE INDEX products_params_idx ON test.products (entries(params));

假设我在该表中有 3 个具有此类参数值的产品:

1. {'param1' : 'value1', 'param2' : 'value2'}
2. {'param1' : 'value1', 'param2' : 'othervalue'}
3. {'param3' : 'value3', 'param2' : 'value2'}

每个产品的每个参数只能有一个值,但在整个数据库中,每个参数可以有 N 个参数和 X 个值。

我可以毫无问题地进行这样的查询:

SELECT * FROM products WHERE params['param1'] = 'value1';

但主要问题是我怎样才能进行这样的查询:

SELECT * FROM products WHERE params['param1'] = 'value1' AND params['param2'] = 'value2';

现在我收到一个错误,警告我效率:

InvalidRequest: Error from server: code=2200 [Invalid query] message="Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING"

我对 Cassandra 和 NoSQL 很陌生。我从 Datastax 课程中知道,使用 ALLOW FILTERING 是我在 Cassandra 中应该做的最后一件事。有没有一种有效的方法可以在 Cassandra 中实现我想要的?也许我应该以完全不同的方式对此进行建模?我会很高兴在这个主题上得到一些帮助。

【问题讨论】:

  • 是的,您更改模型是正确的,因为您不能使用参数(地图类型的列)作为主键或作为材料视图创建表(集合类型不能是主键的一部分,也不能计数器类型。)。所以如果你想跳过“允许过滤”,你需要在查询中包含主键。
  • 集合是您一次性获取的一小组数据。如果您想在更精细的级别访问元组,并且仍然能够询问“给定键的所有数据对是什么”,您应该使用这样的表:CREATE TABLE details (key TEXT, detail_key text, detail_value文本,主键(键,detail_key));这将允许 SELECT * FROM details WHERE key = ?以及 SELECT * FROM detail WHERE key = ? AND detail_key = ?.

标签: cassandra query-optimization data-modeling


【解决方案1】:

如果要根据产品属性和值选择数据,根据参数和值列对主键进行建模,针对此类需求创建附加表。

    create table name_by_param{
    param text,
    value text,
    uuid text,
    name text
    primary key ((param,value),uuid)
    } 

产品插入示例 - Darthvedar

    insert into name_by_param (param,value,uuid,name) values ('birthname','ani','uuid1','darthvedar');
    insert into name_by_param (param,value,uuid,name) values ('side','darkside','uuid1','darthvedar');
    insert into name_by_param (param,value,uuid,name) values ('age','40','uuid1','darthvedar');

产品插入示例 - Obi-wan-kenobi

insert into name_by_param (param,value,uuid,name) values ('birthname','O-ben','uuid2','Obi-wan-kenobi');
insert into name_by_param (param,value,uuid,name) values ('side','force','uuid2','Obi-wan-kenobi');
insert into name_by_param (param,value,uuid,name) values ('age','40','uuid2','Obi-wan-kenobi');

选择查询 --

select * from name_by_param where token(param,value) = token('birthname','ani') and token(param,value) =  token('side','force');

上面的查询应该返回两行,我自己没有尝试过,但它应该可以工作,希望这会有所帮助。

【讨论】:

  • 我真的很喜欢这个想法,但它似乎不能与相等运算符一起使用:param, value cannot be restricted by more than one relation if it includes an Equal - 如果我将其更改为 gt 或 lt,它会起作用,但这显然没有那就解决问题吧。
  • 您是否在该查询中尝试过“OR”,例如 -token(param,value) = token('birthname','ani') { OR } token(param,value) = token( '边','力');
  • 还有一个尝试 IN 运算符示例 - token(..) IN (token(...),token(...))
  • 对不起,Cassandra afaik 中没有或等效的,但我试图确定并得到语法错误。当使用“in”select * from name_by_param where token(param,value) IN (token('birthname','ani'), token('side','force')); 时,我也会收到错误,但略有不同:no viable alternative at input 'IN' (... where token(param,value) [IN]...) - 也许这只是一些愚蠢的 sytnax 错误,但我无法弄清楚。
  • 在文档之后 (cassandra.apache.org/doc/latest/cql/dml.html#select) - Moreover, the IN relation is only allowed on the last column of the partition key and on the last column of the full primary key. :/
猜你喜欢
  • 1970-01-01
  • 2021-12-19
  • 2012-06-28
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多