简短回答:您可以使用二级索引通过fullname UDT进行查询。但是,您不能仅查询UDT的一部分。
create type fullname ( firstname text, lastname text );
create table people ( id UUID primary key, name frozen <fullname> );
create index fname_index on your_keyspace.people (name);
insert into people (id, name) values (now(), {firstname: 'foo', lastname: 'bar'});
insert into people (id, name) values (now(), {firstname: 'baz', lastname: 'qux'});
select * from people where name = { firstname: 'baz', lastname: 'qux' };
select * from people where name = { firstname: 'baz'};
这种行为的原因是由C*二级索引的实现方式所决定的。一般来说,它只是由C*维护的另一个隐藏表,在您的情况下定义为:
这种行为的原因是由于C*二级索引的实现方式。通常情况下,这只是由C*维护的另一个隐藏表,在您的情况下的定义如下:
create table fname_index (name frozen <fullname> primary key, id uuid);
实际上,在这张表中,你的主键和次要键被交换了。因此,你的情况被简化为一个更普遍的问题:‘为什么我不能只查询主键的一部分?’:
- 整个主键值(名字+姓氏)被哈希,得出的数字定义了存储行的分区。
- 对于该分区,将在memtable中添加您的行(稍后将其刷新到SSTable上,这是按键排序的文件)
- 当您只想通过PK的一部分进行查询(例如仅按名字查询),C*无法猜测要查找的分区(因为它无法计算出全名的哈希码,因为姓氏未知),因为您的匹配可以出现在任何分区中并需要进行全表扫描。C*明确禁止这些扫描,所以您别无选择 :)
建议的解决方案:
- 将您的UDT拆分为基本部分,如名字和姓氏,并在其上建立辅助索引。
- 使用具有Materialized Views功能的Cassandra 3.0(实际上是强制Cassandra为您的UDT的一部分维护自定义索引)
- 重新审视您的数据模型,使其更加灵活(当没有人强制您在不需要的地方使用UDT时)