早在2010年,Cassandra 0.7引入了一项新功能:二级索引。 与关系数据库索引不同,它是与列值相关联的索引,该列为表中的所有行提供键。 例如,想象一下“用户”表。 它的主索引为“ user_id”。 现在,假设您要访问用户的电子邮件。 您必须按ID搜索,然后收集您感兴趣的值(例如,电子邮件)。 这对于任何形式的性能都是不切实际的。 见下图:
人类可以通过反操作一步一步地获取我们想要的信息。 给定电子邮件,恢复ID。 在计算方面,我们如何在数据库中实现类似的过程? 二级索引通过使用电子邮件,获取用户ID(充当查询的反函数)来解决这些情况。 此功能可能功能强大且实用。 对较小的数据集应用二级索引可以使查询非常高效。 在Cassandra中创建二级索引非常容易:
CREATE TABLE users (
userID uuid,
firstname text,
lastname text,
email text,
zip int,
PRIMARY KEY (userID)
);
CREATE INDEX users_email
ON users (email);
由于我们不仅限于一个索引,因此还可以通过表定义多个二级索引。
不幸的是,这不是灵丹妙药。 由于二级索引是在本地而不是作为常规索引全局管理的,因此它们可能会导致一些问题。 特别是当我们要处理包含稀疏和非常不同信息的大型数据集时。 对于我们的用户电子邮件示例,如果我们有大量用户。 我们可能会有同样数量的电子邮件,而且它们都是独一无二的。 为了在“电子邮件”列中使用辅助索引,Cassandra将不得不“联接”分布在环上的所有信息,因为该索引是本地的。 就性能而言,这可能是有害的。 如果有五个实例,则单个查询需要五个读数,包括五个磁盘操作。 另一方面,对于常规索引,这是不必要的,因为'user_id'是全局处理的。 由于这个原因,一些开发人员批评二级索引的使用。
提出了二级指标的几种策略
- [1](http://brianoneill.blogspot.com.br/2012/03/cassandra-indexing-good-bad-and-ugly.html),
- [2](http://blog.websudos.com/2014/08/23/a-series-on-cassandra-part-2-indexes-and-keys/),
- [3](http://www.slideshare.net/edanuff/indexing-in-cassandra)和
- [4](https://dzone.com/articles/cassandra-indexing-good-bad)都是很好的例子。
为了增强这一功能,Apple最近开放了自己的二级索引策略:SSTableAttachedSecondaryIndex或简称为[SASI](https://github.com/xedin/sasi)。 该策略已被证明极其有效和强大。 通过提供强大而灵活的查询,SASI可以正确管理CPU,I / O和内存,以节省计算资源。
让我们看一个简单的示例,以了解SASI的工作原理。 目前有Thrift和CQL3支持。 对于任意的“ foo”键空间:
cqlsh> CREATE KEYSPACE foo WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': '1'
};
cqlsh> USE foo;
然后我们创建“酒吧”表:
CREATE TABLE bar (
id uuid,
fname text,
lname text,
age int,
created_at bigint,
primary key (id)
);
我们使用“ CREATE CUSTOM INDEX”命令以使用SASI创建二级索引:
CREATE CUSTOM INDEX ON bar (fname) USING
'org.apache.cassandra.db.index.SSTableAttachedSecondaryIndex'
WITH OPTIONS = {
'analyzer_class':
'org.apache.cassandra.db.index.sasi.analyzer.NonTokenizingAnalyzer',
'case_sensitive': 'false'
};
注意配置'case_sensitive':'false'。 它可能会让您想起全文搜索工具。 看看类[Analyzer](https://github.com/xedin/sasi/blob/master/src/java/org/apache/cassandra/db/index/sasi/analyzer/StandardA
nalyzer.java)。 SASI允许您对索引进行一些有趣的自定义。 看下一个例子:
CREATE CUSTOM INDEX ON bar (lname) USING
'org.apache.cassandra.db.index.SSTableAttachedSecondaryIndex'
WITH OPTIONS = {'mode': 'SUFFIX'};
在这里,我们创建一个带有后缀分析器的索引。 这将按后缀而不是整个术语评估数据。
还有“ SPARSE”模式:
CREATE CUSTOM INDEX ON bar (created_at) USING
'org.apache.cassandra.db.index.SSTableAttachedSecondaryIndex'
WITH OPTIONS = {'mode': 'SPARSE'};
“ SPARSE”模式使我们能够以时间戳记间隔高效地进行查询。 如果未声明任何模式,则默认为'NORMAL',仅提供完全区分大小写的匹配项。
SASI分为两个部分:索引编制和搜索。 Cassandra提供了内存和磁盘资源之间的区别,SASI充分利用了这一点,并且只写不可变性和排序的数据即可正常运行。 然后,将已建立的索引从内存表刷新到磁盘。 在SSTable开始写过程的同时,在内存中创建SASI数据结构,并在过程终止之前刷新到磁盘。 这对性能很有好处,因为写入索引仅需要在磁盘上进行顺序写入。
对于每个SSTable,SASI为每个索引列写入一个索引文件。 文件内容由类[OnDiskIndexBuilder]构建在内存中(https://github.com/xedin/sasi/blob/master/src/java/org/apache/cassandra/db/index/sasi/disk/OnDiskIndexBuilder。 Java)。
刷新到磁盘后,该信息将由[OnDiskIndex]读取(https://github.com/xedin/sasi/blob/master/src/java/org/apache/cassandra/db/index/sasi/disk/OnDiskIndex (.java),其中包含优化的搜索数据结构。 创建用于SSTable位置的键值映射,然后在磁盘写入后,将此信息存储在内存中以加快索引访问。
当我们执行搜索时,还有另一组类将索引解析并解释为树形结构,对其进行优化并分析应搜索的内容。 为了执行联盟和数据的交点 ,SASI具有一组智能迭代器,如[RangeUnionIterator]的(https://github.com/xedin/sasi/blob/master/src/java/org/apache/cassandra/db/索引/ sasi / utils / RangeUnionIt
erator.java),可以跨哈希执行联合操作,仅读取每个集合中满足查询需求的最低要求。 还有[RangeIntersectionIterator](https://github.com/xedin/sasi/blob/master/src/java/org/apache/cassandra/db/index/sasi/utils/RangeIntersec
tionIterator.java)。
有了由优化的数据结构提供支持的索引和搜索工具箱,我们可以看到SASI并不是魔术。 SASI利用Cassandra架构和结构来处理数据并执行智能操作。
SASI有一些限制。 例如,它要求将集群配置为产生LongToken(例如:Murmur3Partitioner)。 ByteOrderedPartitioner和RandomPartitioner不适用于SASI,并且仅支持版本> 3.4的Cassandra。
本文的主要目的是提供有关Cassandra二级索引的快速且一般的想法,并介绍SASI的基础知识。 当然,仍然需要在此工具中完成一些工作。 但是,它已被证明是以前的二级索引实施的强大替代品。 访问[官方Github存储库](https://github.com/xedin/sasi),以获取有关项目,问题和发行版的详细信息。
翻译自: https://www.javacodegeeks.com/2016/04/sasi-empowering-secondary-indexes-2.html