【Cassandra】バージョン4.0~5.0で追加された機能の紹介

# はじめに
Apache Cassandraの最新メジャーバージョンである5.0.0が2024/09/05にめでたくリリースされました。
メジャーバージョンアップによって多くの新機能が追加されており、その中からいくつかピックアップして紹介していきたいと思います。

また、5.0.0のリリースに伴い3.0.xと3.11.xのバージョンがEOLを迎えることになりました。([Apache-Cassandra-3.0.x-and-3.11.x-End-of-Life-Announcement](https://cassandra.apache.org/_/blog/Apache-Cassandra-3.0.x-and-3.11.x-End-of-Life-Announcement.html))
2015年に3.0.x、2017年に3.11.xがリリースされてから長期に渡り利用されてきたバージョンとなりますが、今後はバージョンアップを考えていく必要があります。
3.0.x/3.11.xからのバージョンアップの際には一度4.0.x/4.1.xを経由する形になると思いますので、今回は4.0.x/4.1.xで追加された機能もあわせて紹介していきたいと思います。


# 4.0.x での新機能
4.0.xでの新機能にはノード間のメッセージング通信の改善やZero Copy StreamingによるStreamingの改善などがありますが、今回はロギング機能の強化を紹介します。

## Audit Logging
Audit LoggingではCassandraへのログイン試行やCQLリクエストを成功と失敗を含めてログに出力することができます。
Audit LogにはCQLに関係する操作は記録されますがサーバー上の設定ファイル(cassandra.yamlなど)の変更やCassandra運用ツールであるnodetoolコマンドによる操作は記録されないため注意が必要です。

### Audit Loggingの設定
cassandra.yamlにAudit Loggingに関する設定項目があります。
デフォルトでは以下のように`enabled: false`となっているため無効になっております。
こちらの設定項目でkeyspaceやユーザー、操作カテゴリをロギング対象に含めるか除外するかを設定することができます。

```
# Audit logging - Logs every incoming CQL command request, authentication to a node. See the docs
# on audit_logging for full details about the various configuration options.
audit_logging_options:
    enabled: false
    logger:
      - class_name: BinAuditLogger
    # audit_logs_dir:
    # included_keyspaces:
    # excluded_keyspaces: system, system_schema, system_virtual_schema
    # included_categories:
    # excluded_categories:
    # included_users:
    # excluded_users:
    # roll_cycle: HOURLY
    # block: true
    # max_queue_weight: 268435456 # 256 MiB
    # max_log_size: 17179869184 # 16 GiB
    ## archive command is "/path/to/script.sh %path" where %path is replaced with the file being rolled:
    # archive_command:
    # max_archive_retries: 10
```

### Audit Loggingを有効/無効にする
先ほどの設定ファイルで`enabled: false`と設定するとCassandra起動時にAudit Loggingが有効となります。
また、`nodetool enableauditlog`コマンドを使用することでノードを再起動せずにAudit Loggingを有効化することも可能です。

無効にする場合は`nodetool disableauditlog`コマンドを使用します。
Audit Loggingはそれぞれのノードごとに設定されるためクラスタ全体で設定する場合は全台で有効化する必要があります。

### Audit Logの確認
デフォルトのロガーである`BinAuditLogger`を設定した場合は、Audit Logを表示するための`auditlogviewer`というツールを利用してAudit Logを確認します。
`FileAuditLogger`を設定した場合はAudit Logがそのまま確認できる形式となっております。

出力されるAudit Logの例は以下のようになります。
（ログイン->SELECTクエリ->ログアウト->ログイン失敗）

```
Type: audit
LogMessage: user:cassandra|host:<hostname>/<IPアドレス>:7000|source:/<IPアドレス>|port:35114|timestamp:1725778217547|type:LOGIN_SUCCESS|category:AUTH|operation:LOGIN SUCCESSFUL
Type: audit
LogMessage: user:cassandra|host:<hostname>/<IPアドレス>:7000|source:/<IPアドレス>|port:35114|timestamp:1725778244932|type:SELECT|category:QUERY|ks:sample|scope:t|operation:SELECT * FROM sample.t WHERE id=0;
Type: audit
LogMessage: user:null|host:<hostname>/<IPアドレス>:7000|source:/<IPアドレス>|port:37664|timestamp:1725778258798|type:LOGIN_ERROR|category:AUTH|operation:LOGIN FAILURE; Provided username cassandra and/or password *******
```


## Full Query Logging
Full Query Loggingでは成功したCQLリクエストを記録し、ログからクエリを再実行することができます。
Audit Loggingと異なり失敗したクエリなどは記録されませんが、デバッグやパフォーマンステストなどで活用できます。

### Full Query Loggingの設定
cassandra.yamlにFull Query Loggingに関する設定項目があります。
デフォルトでは以下のようにコメントアウトされ無効の状態になっております。
ノードの起動時に有効化する場合はコメントアウトを外し、最低限`log_dir`を指定する必要があります。

```
# default options for full query logging - these can be overridden from command line
# when executing nodetool enablefullquerylog
#full_query_logging_options:
   # log_dir:
   # roll_cycle: HOURLY
   # block: true
   # max_queue_weight: 268435456 # 256 MiB
   # max_log_size: 17179869184 # 16 GiB
   # archive command is "/path/to/script.sh %path" where %path is replaced with the file being rolled:
   # archive_command:
   # max_archive_retries: 10
```

### Full Query Loggingを有効/無効にする
Audit Loggingと同様にこちらも`nodetool enablefullquerylog`コマンドを使用することでノードを再起動せずにFull Query Loggingを有効にできます。
ノード起動時にcassandra.yamlで`log_dir`を指定していない場合は`--path <cassandraが操作可能な権限を持つディレクトリ>`オプションを指定する必要があります。

無効にする場合は`nodetool disablefullquerylog`コマンドを使用します。
Full Query Loggingもそれぞれのノードごとに設定されるためクラスタ全体で設定する場合は全台で有効化する必要があります。

### Full Query Logの確認
Query Logを確認する際には`fqltool`コマンドを利用します。
こちらには以下のコマンドが用意されています

- fqltool dump
  - 取得したQuery Logを表示する
- fqltool replay
  - 取得したQuery Logを元にクエリをリプレイする
- fqltool compare
  - replay コマンドで生成された結果を比較する

出力されるQuery Logは以下のようになります。
※ log_dir: /var/log/cassandra/fql で設定しています

```
fqltool dump /var/log/cassandra/fql/

...

Type: single-query
Query start time: 1725865322651
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: CREATE KEYSPACE querylogkeyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
Values:

Type: single-query
Query start time: 1725865332220
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: CREATE TABLE querylogkeyspace.t (id int,k int,v text,PRIMARY KEY (id));
Values:

Type: single-query
Query start time: 1725865340952
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1725865340
Query: INSERT INTO querylogkeyspace.t (id, k, v) VALUES (0, 0, 'val0');
Values:

Type: single-query
Query start time: 1725865348750
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1725865348
Query: INSERT INTO querylogkeyspace.t (id, k, v) VALUES (0, 1, 'val1');
Values:

Type: single-query
Query start time: 1725865367722
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1725865367
Query: SELECT * FROM querylogkeyspace.t;
Values:
```

### Query Logからのリプレイ
※ 私の環境ではKeyspaceとTable作成のリプレイがうまくできなかったため、Tableを再作成しデータはない状態からリプレイしました

一度KeyspaceとTableを作り直す
```sql
DROP KEYSPACE querylogkeyspace;
CREATE KEYSPACE querylogkeyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
CREATE TABLE querylogkeyspace.t (id int,k int,v text,PRIMARY KEY (id));
SELECT * FROM querylogkeyspace.t;
 id | k | v
----+---+---

```

リプレイコマンド用のディレクトリを作成する
```
mkdir -p /var/log/cassandra/fql/results
mkdir -p /var/log/cassandra/fql/queries
chown -R cassandra:cassandra /var/log/cassandra/fql/
```


上記で生成されたログを使いリプレイを実施する
```
fqltool replay --keyspace querylogkeyspace --results /var/log/cassandra/fql/results --store-queries /var/log/cassandra/fql/queries --target <user>:<password>@<hostname>:9042 /var/log/cassandra/queryLog/
```

データを確認する
```sql
SELECT * FROM querylogkeyspace.t;

 id | k | v
----+---+------
  0 | 1 | val1
```


# 4.1.x での新機能
次に4.1.xでの新機能としてクラスタの安全性をサポートするGuardrailsについて紹介します。

## Guardrails
Cassandraにはいくつかアンチパターンとなる利用法があります。

アンチパターン例
- 大量のSecondary Indexが作成されリソース不足となる
- ALLOW FILTERINGを使用して巨大なデータを取得しクラスタ全体が高負荷となる
- 意図せず低いConsistency Levelを使用してしまいデータの不整合が発生する

Guardrailsによって運用者側でCassandraの機能を制限し、アンチパターンを抑止することが可能となります。

### Guardrailsの設定
cassandra.yamlでGuardrailsに関する設定を行うことができます。
設定を有効化する際はcassandra.yamlを修正し、ノードの再起動を行います。
将来的には動的に設定を更新する機能もサポートされる予定のようです。

Guradrailsの対象となるユーザーは通常のユーザーの操作のみとなっており、Super Userの操作や内部クエリはチェックの対象外となります。
また、Guradrailsでは機能を無効にするだけでなく、警告メッセージを表示する設定も可能です。

Guardrailsによる制限の多くはCQLクエリに関連しており実行時などにチェックされますが、直接クエリに関連しない要素もバックグラウンドでチェックすることができます。
バックグラウンドでチェックされる例としてはcollection型データのサイズやディスク使用率などがあります。

以下にGuardrailsの設定項目の一部を紹介します。

- テーブル毎のSecondary Indexの数
- Secondary Indexの作成
- ALLOW FILTERINGの使用
- Readで使用可能なConsistency Level
- Writeで使用可能なConsistency Level
- ディスク使用量

※ 他にもGuardrailsで設定可能な項目はたくさんあります
```
# Guardrail to warn or fail when creating more secondary indexes per table than threshold.
# The two thresholds default to -1 to disable.
# secondary_indexes_per_table_warn_threshold: -1
# secondary_indexes_per_table_fail_threshold: -1

# Guardrail to enable or disable the creation of secondary indexes
# secondary_indexes_enabled: true

# Guardrail to allow/disallow querying with ALLOW FILTERING. Defaults to true.
# allow_filtering_enabled: true

# Guardrail to warn about or reject read consistency levels. By default, all consistency levels are allowed.
# read_consistency_levels_warned: []
# read_consistency_levels_disallowed: []

# Guardrail to warn about or reject write consistency levels. By default, all consistency levels are allowed.
# write_consistency_levels_warned: []
# write_consistency_levels_disallowed: []

# Guardrail to warn or fail when local data disk usage percentage exceeds threshold. Valid values are in [1, 100].
# This is only used for the disks storing data directories, so it won't count any separate disks used for storing
# the commitlog, hints nor saved caches. The disk usage is the ratio between the amount of space used by the data
# directories and the addition of that same space and the remaining free space on disk. The main purpose of this
# guardrail is rejecting user writes when the disks are over the defined usage percentage, so the writes done by
# background processes such as compaction and streaming don't fail due to a full disk. The limits should be defined
# accordingly to the expected data growth due to those background processes, so for example a compaction strategy
# doubling the size of the data would require to keep the disk usage under 50%.
# The two thresholds default to -1 to disable.
# data_disk_usage_percentage_warn_threshold: -1
# data_disk_usage_percentage_fail_threshold: -1
# Min unit: B
# data_disk_usage_max_disk_size:
```

### Guardrailsの使用例
以下の設定を行い、いくつかのクエリを試してみます。

```yaml
secondary_indexes_per_table_warn_threshold: 1
secondary_indexes_per_table_fail_threshold: 2
read_consistency_levels_warned: [ONE]
read_consistency_levels_disallowed: [ALL]
write_consistency_levels_warned: [ONE]
write_consistency_levels_disallowed: [ALL]
allow_filtering_enabled: false
data_disk_usage_percentage_warn_threshold: 20
data_disk_usage_percentage_fail_threshold: 40
```

Secondary Indexの作成
-> 2つめのインデックスを作成した際にWarningが表示され、3つめのインデックスの作成に失敗

```sql
CREATE INDEX v_idx ON querylogkeyspace.t ( v );
CREATE INDEX k_idx ON querylogkeyspace.t ( k );

Warnings :
Guardrail secondary_indexes_per_table violated: Creating secondary index k_idx on table t, current number of indexes 2 exceeds warning threshold of 1.

CREATE INDEX k_idx2 ON querylogkeyspace.t ( k );
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail secondary_indexes_per_table violated: Tables cannot have more than 2 secondary indexes, aborting the creation of secondary index k_idx2 on table t"
```

ConsistencyLevel: ONEでのRead/Write
-> Warningが表示されるがクエリには成功
```sql
SELECT * FROM querylogkeyspace.t;

 id | k | v
----+---+------
  1 | 1 | val2
  0 | 1 | val1
  2 | 2 | val1

(3 rows)

Warnings :
Guardrail read_consistency_levels violated: Provided values [ONE] are not recommended for read consistency levels (warned values are: [ONE])

INSERT INTO querylogkeyspace.t (id, k, v) VALUES (3, 2, 'val3');

Warnings :
Guardrail write_consistency_levels violated: Provided values [ONE] are not recommended for write consistency levels (warned values are: [ONE])
```

ConsistencyLevel: ALLでのRead/Write
-> クエリに失敗する
```sql
CONSISTENCY ALL;
Consistency level set to ALL.

SELECT * FROM querylogkeyspace.t;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail read_consistency_levels violated: Provided values [ALL] are not allowed for read consistency levels (disallowed values are: [ALL])"

INSERT INTO querylogkeyspace.t (id, k, v) VALUES (4, 3, 'val2');
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail write_consistency_levels violated: Provided values [ALL] are not allowed for write consistency levels (disallowed values are: [ALL])"
```

ALLOW FILTERINGを使用したクエリ
-> クエリに失敗する

```sql
SELECT * FROM querylogkeyspace.t WHERE v = 'val1' ALLOW FILTERING;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail allow_filtering violated: Querying with ALLOW FILTERING is not allowed"
```

データディレクトリのディスク使用量が20%以上となった場合
-> cassandraのログにWARNメッセージが出力される
```
WARN  [ScheduledTasks:1] 2024-09-09 20:42:33,449 NoSpamLogger.java:108 - Guardrail local_data_disk_usage violated: Local data disk usage 24%(Stuffed) exceeds warning threshold of 20%
```

この状態で書き込みを行う
-> ディスク使用率が高いノードにレプリカが書き込まれる際に、Warningが表示されるがクエリには成功
```sql
INSERT INTO querylogkeyspace.t (id, k, v) VALUES (8, 4, 'val3');

Warnings :
Guardrail replica_disk_usage violated: Replica disk usage exceeds warning threshold
```

データディレクトリのディスク使用量が40%以上となった場合
-> cassandraのログにERRORメッセージが出力される
```
ERROR [ScheduledTasks:1] 2024-09-09 20:46:33,444 NoSpamLogger.java:111 - Guardrail local_data_disk_usage violated: Local data disk usage 55%(Full) exceeds failure threshold of 40%, will stop accepting writes
```

この状態で書き込みを行う
-> ディスク使用率が高いノードにレプリカが書き込まれる際に、クエリに失敗
```sql
INSERT INTO querylogkeyspace.t (id, k, v) VALUES (8, 4, 'val4');
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail replica_disk_usage violated: Write request failed because disk usage exceeds failure threshold"
```


# 5.0.x での新機能
5.0.xの新機能からピックアップして新しいインデックスであるStorage Attached Indexとそれを利用したVector Search、さらにUnified Compaction Strategyについて紹介します。

## Vector Search & Storage Attached Indexes(SAI)
近年AI技術が注目されており、Cassandraにもベクトルデータの類似性を比較するVector SearchとVector型が追加されました。

Vector Searchは以下の流れで行います。
（Storage Attached Indexについては後で紹介しますが、5.0.xで新しく追加されたインデックスです）

1. ベクトルデータを保存するテーブルの作成
2. ベクトルデータのカラムにインデックス(Storage Attached Index)を作成する
3. データを書き込む
4. インデックスを利用しベクトルを検索する

### Vector Searchの例
KeyspaceとTableの作成

ここでカラムvがVector型のデータとなっており浮動小数点型の固定長の配列となります。

```sql
CREATE KEYSPACE sample WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};

CREATE TABLE sample.t(
   id INT PRIMARY KEY, 
   name text,
   v VECTOR<float, 3>
);
```

インデックスの作成

saiを指定することでStorage Attached Indexを使用できます。

```sql
CREATE INDEX IF NOT EXISTS ann_index ON sample.t(v) USING 'sai';
```

データの書き込み

```sql
INSERT INTO sample.t (id, name, v) VALUES (1, 'Sato', [8, 2.3, 58]); 
INSERT INTO sample.t (id, name, v) VALUES (2, 'Tanaka', [1.2, 3.4, 5.6]);
INSERT INTO sample.t (id, name, v) VALUES (5, 'Sasaki', [23, 18, 3.9]); 
```

データの検索

以下のクエリでVector Searchができます。

```sql
SELECT * FROM sample.t ORDER BY v ANN OF [3.4, 7.8, 9.1] LIMIT 1;

 id | name   | v
----+--------+-----------------
  2 | Tanaka | [1.2, 3.4, 5.6]

```

また、類似度を計算する以下の新たな関数が追加されております

- similarity_dot_product
- similarity_cosine
- similarity_euclidean

類似度を使用してみた例が以下になります。
```sql
SELECT id, name, similarity_dot_product(v, [1.1, 3.8, 6.0]) FROM sample.t ORDER BY v ANN OF [3.4, 7.8, 9.1] LIMIT 2;

 id | name   | system.similarity_dot_product(v, [1.1, 3.8, 6.0])
----+--------+---------------------------------------------------
  2 | Tanaka |                                             24.42
  1 |   Sato |                                            183.27

SELECT id, name, similarity_cosine(v, [1.1, 3.8, 6.0]) FROM sample.t ORDER BY v ANN OF [3.4, 7.8, 9.1] LIMIT 2;

 id | name   | system.similarity_cosine(v, [1.1, 3.8, 6.0])
----+--------+----------------------------------------------
  2 | Tanaka |                                     0.999724
  1 |   Sato |                                     0.934025

SELECT id, name, similarity_euclidean(v, [1.1, 3.8, 6.0]) FROM sample.t ORDER BY v ANN OF [3.4, 7.8, 9.1] LIMIT 2;

 id | name   | system.similarity_euclidean(v, [1.1, 3.8, 6.0])
----+--------+-------------------------------------------------
  2 | Tanaka |                                         0.75188
  1 |   Sato |                                        0.000363
```

### Storage Attached Index
先ほどのVector Searchの中で使用されておりましたが、このStorage Attached Index(SAI)が新しく追加されたインデックスになります。
SAIは以下のような特徴があり既存のインデックスよりもパフォーマンスが向上しているようです。
- AIアプリケーションでのベクトル検索が可能
- 同じテーブル上の複数のインデックス間でインデックスデータを共有
- 書き込み時のスケーラビリティの問題を軽減
- ディスク使用量が大幅に削減
- インデックスのゼロコピーストリーミングが可能

従来のSecondary Indexの使用の際にはインデックスの肥大化やクラスタへの負荷など注意する点が多かったため、こちらの新しいインデックスは期待したいです。


## Unified Compaction Strategy
従来のCassandraでは以下のCompaction Strategyがありワークロードごとに向き不向きがありました。

| Compaction Strategy | 動作 | 特徴 |
| ---  | --- | --- |
| SizeTierdCompactionStrategy(STCS)  | 同程度のサイズのSSTableが一定数集まるとコンパクションが行われます。 | デフォルトのCompactionStrategyとなります。<br>他のCompactionStrategyが最適とならないケースでベターとなる場合が多いです。 |
| LeveledCompactionStrategy(LCS)     | 階層(レベル)ごとにSSTableが管理され、同じレベルには重複するSSTableが存在しないようにコンパクションされます。<br>各階層には上限サイズがあり、それ超えると次の階層へ移行していきます。 | データは各階層ごとに1つのSSTableにまとまっていることが保証されるため、読み取るSSTableの数が少なくてすみ、読み込みが多いワークローで有効となりやすいです。 |
| TimeWindowCompactionStrategy(TWCS) | ある期間内のデータを1つのSSTableにまとめるようにコンパクションが行われます。 | 時系列データでTTLを利用している場合、期限が切れたデータが他のCompactionStrategyより削除されやすく、ディスクスペースを活用しやすいです。 |

新しく追加される Unified Compaction Strategy(UCS)は以下の特徴があります。
- パラメータを調整することで従来のCompaction Strategyを再現することが可能
- これまでは別のCompaction Strategyへ切り替える場合、すべてのデータを再度Compactionする必要がありましたが、UCSではパラメータの変更のみで戦略を切り替えることが可能
- SSTableをトークンレンジごとにソートしたり、サイズだけでなく密度で分割することも可能になり柔軟なコンパクションが可能
  - 例：トークンレンジごとに並列でコンパクションするなど

これまでは各Compaction Strategyでクラスタを長期間運用していると問題となる場合がありましたが、UCSによってある程度チューニングできるようになると非常に嬉しいです。

問題の例
- STCSで一度大きなSSTableが生成されると次のコンパクション対象になりにくく、上書きされたデータや削除されたデータが圧迫しやすい
こちらを解消するため常にメジャーコンパクションを行う運用が必要となる
- LCSで上位の階層にあるSSTableはコンパクションされにくく不要なデータが残り続けやすい
garbagecollect などの対応が必要
- 後からCompactionStrategyを変更するのが難しい

UCSの詳細な内容や各パラメータの説明は以下のドキュメントをご参照ください。
[Unified Compaction Strategy (UCS) | Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/cassandra/managing/operating/compaction/ucs.html)

# おわりに
今回はバージョン4.0~5.0で追加された機能の一部を紹介させていただきました。
こちらで紹介したもの以外でも性能面での向上やセキュリティ面でのオプションの追加など多くの改善が行われております。
また、今後のバージョンで追加や修正が予定されている機能も多数存在し、以下のページやJiraなどから確認することができます。
[Cassandra Enhancement Proposals (CEP) - CASSANDRA - Apache Software Foundation ](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=95652201)
最新のCassandraの機能に興味がある方、Cassandraのバージョンアップを検討している方などの参考になれば幸いです。

# 参考
- [New Features in Apache Cassandra 4.0 | Apache Cassandra Documentation](https://cassandra.apache.org/doc/4.0/cassandra/new/index.html)
  - [Audit Logging | Apache Cassandra Documentation](https://cassandra.apache.org/doc/4.0/cassandra/new/auditlogging.html)
  - [Full Query Logging | Apache Cassandra Documentation](https://cassandra.apache.org/doc/4.0/cassandra/new/fqllogging.html)
- [New Features in Apache Cassandra 4.1 | Apache Cassandra Documentation ](https://cassandra.apache.org/doc/4.1/cassandra/new/index.html)
  - [Apache Cassandra 4.1 Features: Guardrails Framework | Apache Cassandra Documentation](https://cassandra.apache.org/_/blog/Apache-Cassandra-4.1-Features-Guardrails-Framework.html)
- [New Features | Apache Cassandra Documentation ](https://cassandra.apache.org/doc/latest/cassandra/new/index.html)
  - [Overview of Vector Search | Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/cassandra/vector-search/overview.html)
  - [Vector CQL data type | Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/cassandra/reference/vector-data-type.html)
  - [Storage-Attached Indexing (SAI) Overview | Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/cassandra/developing/cql/indexing/sai/sai-overview.html)
  - [Unified Compaction Strategy (UCS) | Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/cassandra/managing/operating/compaction/ucs.html)