简短回答:您可以使用二级索引按全名 UDT 进行查询。但是您不能仅通过 UDT 的一部分进行查询。
// create table, type and index
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 some data into it
insert into people (id, name) values (now(), {firstname: 'foo', lastname: 'bar'});
insert into people (id, name) values (now(), {firstname: 'baz', lastname: 'qux'});
// query it by fullname
select * from people where name = { firstname: 'baz', lastname: 'qux' };
// the following will NOT work:
select * from people where name = { firstname: 'baz'};
这种行为的原因是 C* 二级索引的实现方式。通常,它只是由 C* 维护的另一个隐藏表,在您的情况下定义为:
create table fname_index (name frozen <fullname> primary key, id uuid);
实际上,您的辅助键和主键在此表中交换。因此,您的案例被简化为一个更普遍的问题“为什么我不能只通过 PK 的一部分进行查询?”:
- 整个 PK 值(名字+姓氏)被散列,结果数字定义了存储你的行的分区。
- 对于那个分区,你的行被附加到一个内存表(然后在磁盘上刷新到 SSTable,一个按键排序的文件)
- 当您只想按 PK 的一部分(例如仅按名字)查询时,C* 无法猜测要查找的分区(因为它无法计算整个全名的哈希码,因为姓氏未知) ,因为您的匹配项可以在任何需要全表扫描的分区中的任何位置。C* 明确禁止这些扫描,所以你别无选择 :)
建议的解决方案:
- 将您的 UDT 拆分为名字和姓氏等基本部分,并在其上具有二级索引。
- 使用带有物化视图功能的 Cassandra 3.0(实际上强制 cassandra 为您的部分 UDT 维护自定义索引)
- 重新审视你的数据模型,使其不那么严格(当没有人强迫你在没有帮助的地方使用 UDT 时)