diff --git a/doc/antora.yml b/doc/antora.yml index 42f01753e1..6784f5a39a 100644 --- a/doc/antora.yml +++ b/doc/antora.yml @@ -5,6 +5,11 @@ prerelease: true asciidoc: attributes: cass_url: 'http://cassandra.apache.org/' + product: Cassandra + cassandra: Apache Cassandra + 30_version: '3.0' + 22_version: '2.2' + 21_version: '2.1' nav: - modules/ROOT/nav.adoc -- modules/cassandra/nav.adoc +- modules/cassandra/nav.adoc \ No newline at end of file diff --git a/doc/modules/ROOT/nav.adoc b/doc/modules/ROOT/nav.adoc index 74c129c5a2..3d367ad242 100644 --- a/doc/modules/ROOT/nav.adoc +++ b/doc/modules/ROOT/nav.adoc @@ -2,3 +2,15 @@ ** xref:master@_:ROOT:glossary.adoc[Glossary] ** xref:master@_:ROOT:bugs.adoc[How to report bugs] ** xref:master@_:ROOT:contactus.adoc[Contact us] +** xref:master@_:ROOT:development/index.adoc[Development] +*** xref:master@_:ROOT:development/gettingstarted.adoc[Getting started] +*** xref:master@_:ROOT:development/ide.adoc[Building and IDE integration] +*** xref:master@_:ROOT:development/testing.adoc[Testing] +*** xref:master@_:ROOT:development/patches.adoc[Contributing code changes] +*** xref:master@_:ROOT:development/code_style.adoc[Code style] +*** xref:master@_:ROOT:development/how_to_review.adoc[Review checklist] +*** xref:master@_:ROOT:development/how_to_commit.adoc[How to commit] +*** xref:master@_:ROOT:development/documentation.adoc[Working on documentation] +*** xref:master@_:ROOT:development/ci.adoc[Jenkins CI environment] +*** xref:master@_:ROOT:development/dependencies.adoc[Dependency management] +*** xref:master@_:ROOT:development/release_process.adoc[Release process] diff --git a/doc/modules/cassandra/assets/images/sai/dmlCompaction.png b/doc/modules/cassandra/assets/images/sai/dmlCompaction.png new file mode 100644 index 0000000000..6a9787ae0a Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/dmlCompaction.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiAge44StateCAExample.png b/doc/modules/cassandra/assets/images/sai/saiAge44StateCAExample.png new file mode 100644 index 0000000000..a9c097a2e6 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiAge44StateCAExample.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadEstimateConcurrencyFactor.png b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadEstimateConcurrencyFactor.png new file mode 100644 index 0000000000..eb233bbbbf Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadEstimateConcurrencyFactor.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUntilLimit.png b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUntilLimit.png new file mode 100644 index 0000000000..49c64915c8 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUntilLimit.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUpdateConcurrencyFactor.png b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUpdateConcurrencyFactor.png new file mode 100644 index 0000000000..09134091a9 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiCoordinatorRangeReadUpdateConcurrencyFactor.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiOnDiskStructureWithOffsets.png b/doc/modules/cassandra/assets/images/sai/saiOnDiskStructureWithOffsets.png new file mode 100644 index 0000000000..382ecb00dc Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiOnDiskStructureWithOffsets.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiReadpathOverview.png b/doc/modules/cassandra/assets/images/sai/saiReadpathOverview.png new file mode 100644 index 0000000000..51934a5120 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiReadpathOverview.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiWritePath.png b/doc/modules/cassandra/assets/images/sai/saiWritePath.png new file mode 100644 index 0000000000..586ff3fb90 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiWritePath.png differ diff --git a/doc/modules/cassandra/assets/images/sai/saiWritePathFlow.png b/doc/modules/cassandra/assets/images/sai/saiWritePathFlow.png new file mode 100644 index 0000000000..4eb0572e39 Binary files /dev/null and b/doc/modules/cassandra/assets/images/sai/saiWritePathFlow.png differ diff --git a/doc/modules/cassandra/examples/BASH/docker-kill-and-remove.sh b/doc/modules/cassandra/examples/BASH/docker-kill-and-remove.sh new file mode 100644 index 0000000000..3ea511c4c4 --- /dev/null +++ b/doc/modules/cassandra/examples/BASH/docker-kill-and-remove.sh @@ -0,0 +1,2 @@ +docker kill cassandra +docker network rm cassandra \ No newline at end of file diff --git a/doc/modules/cassandra/examples/BASH/docker-network-run.sh b/doc/modules/cassandra/examples/BASH/docker-network-run.sh new file mode 100644 index 0000000000..2ca9c9bde7 --- /dev/null +++ b/doc/modules/cassandra/examples/BASH/docker-network-run.sh @@ -0,0 +1,3 @@ +docker network create cassandra + +docker run --rm -d --name cassandra --hostname cassandra --network cassandra cassandra \ No newline at end of file diff --git a/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-load-data.sh b/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-load-data.sh new file mode 100644 index 0000000000..ff4d619b55 --- /dev/null +++ b/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-load-data.sh @@ -0,0 +1,4 @@ +docker run --rm --network cassandra \ +-v "$(pwd)/data.cql:/scripts/data.cql" \ +-e CQLSH_HOST=cassandra -e CQLSH_PORT=9042 \ +-e CQLVERSION=3.4.6 nuvo/docker-cqlsh \ No newline at end of file diff --git a/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-quickstart.sh b/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-quickstart.sh new file mode 100644 index 0000000000..c75954924a --- /dev/null +++ b/doc/modules/cassandra/examples/BASH/docker-run-cqlsh-quickstart.sh @@ -0,0 +1,3 @@ +docker run --rm -it --network \ +cassandra nuvo/docker-cqlsh cqlsh cassandra \ +9042 --cqlversion='3.4.5' \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/2i/2i-check.cql b/doc/modules/cassandra/examples/CQL/2i/2i-check.cql new file mode 100644 index 0000000000..08a9df8755 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/2i/2i-check.cql @@ -0,0 +1 @@ +DESCRIBE TABLE cycling.birthday_list; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/2i/2i-drop.cql b/doc/modules/cassandra/examples/CQL/2i/2i-drop.cql new file mode 100644 index 0000000000..cd9f81a617 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/2i/2i-drop.cql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS cycling.teams_idx; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/2i/bad_cql_examples.cql b/doc/modules/cassandra/examples/CQL/2i/bad_cql_examples.cql new file mode 100644 index 0000000000..251b32f243 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/2i/bad_cql_examples.cql @@ -0,0 +1,13 @@ +// This file contains CQL statements that generate errors. +// This file can be run after the cycling keyspace is set up. + +// InvalidRequest: Error from server: code=2200 [Invalid query] +// message=“Altering of types is not allowed” +ALTER TABLE cycling.cyclist_alt_stats ALTER favorite_color TYPE text; + +// tag::select_all_from_cyclist_alt_stats_error[] +SELECT * +FROM cycling.cyclist_alt_stats +WHERE birthday = '1982-01-29' + AND nationality = 'Russia'; +// end::select_all_from_cyclist_alt_stats_error[] diff --git a/doc/modules/cassandra/examples/CQL/2i/cyclist_alt_stats.cql b/doc/modules/cassandra/examples/CQL/2i/cyclist_alt_stats.cql new file mode 100644 index 0000000000..cbf8e2f98d --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/2i/cyclist_alt_stats.cql @@ -0,0 +1,130 @@ +// QUERY USING MULTIPLE INDEXES +// DISCUSSION OF THE NEED FOR ALLOW FILTERING +// Showing date upserts and queries +// avg + +SOURCE '0_create_keyspace.cql'; + +// tag::drop_cyclist_alt_stats[] +DROP TABLE IF EXISTS cycling.cyclist_alt_stats; +// end::drop_cyclist_alt_stats[] + +// tag::cyclist_alt_stats[] +CREATE TABLE IF NOT EXISTS cycling.cyclist_alt_stats ( + id UUID PRIMARY KEY, + lastname text, + birthday date, + nationality text, + weight float, + w_units text, + height float, + first_race date, + last_race date +); +// end::cyclist_alt_stats[] + +// tag::index_bday[] +CREATE INDEX IF NOT EXISTS birthday_idx +ON cycling.cyclist_alt_stats (birthday); +// end::index_bday[] + +// tag::index_nationality[] +CREATE INDEX IF NOT EXISTS nationality_idx +ON cycling.cyclist_alt_stats (nationality); +// end::index_nationality[] + +USE cycling; + +// tag::insertnow[] +INSERT INTO cycling.cyclist_alt_stats ( + id, + last_race +) VALUES ( + ed584e99-80f7-4b13-9a90-9dc5571e6821, + todate(now()) +); +// end::insertnow[] + +// tag::insertdate[] +INSERT INTO cycling.cyclist_alt_stats ( + id, + first_race +) VALUES ( + ed584e99-80f7-4b13-9a90-9dc5571e6821, + '2006-03-15' +); +// end::insertdate[] + +CAPTURE 'select_dates_from_cyclist_alt_stats.result'; +// tag::selectrace[] +SELECT first_race, last_race, birthday +FROM cycling.cyclist_alt_stats +WHERE id = ed584e99-80f7-4b13-9a90-9dc5571e6821; +// end::selectrace[] +CAPTURE OFF; + +// tag::updatestring[] +UPDATE cycling.cyclist_alt_stats +SET birthday = '1987-03-07' +WHERE id = ed584e99-80f7-4b13-9a90-9dc5571e6821; +// end::updatestring[] + +// tag::updatenow[] +UPDATE cycling.cyclist_alt_stats +SET last_race = toDate(now()) +WHERE id = ed584e99-80f7-4b13-9a90-9dc5571e6821; +// end::updatenow[] + +// tag::insert[] +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (ed584e99-80f7-4b13-9a90-9dc5571e6821,'TSATEVICH', '1989-07-05', 'Russia', 64, 'kg', 1.69, '2006-03-15','2017-04-16'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (a9e96714-2dd0-41f9-8bd0-557196a44ecf,'ISAYCHEV', '1986-04-21', 'Russia', 80, 'kg', 1.88,'2003-04-22','2017-03-05'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (823ec386-2a46-45c9-be41-2425a4b7658e,'BELKOV', '1985-01-09', 'Russia', 71, 'kg', 1.84,'2002-03-22','2017-04-16'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (e0953617-07eb-4c82-8f91-3b2757981625,'BRUTT', '1982-01-29', 'Russia', 68, 'kg', 1.78,'1998-02-15','2017-04-16'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (078654a6-42fa-4142-ae43-cebdc67bd902,'LAGUTIN', '1981-01-14', 'Russia', 63, 'kg', 1.82,'1996-05-21','2010-10-02'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (d74d6e70-7484-4df5-8551-f5090c37f617,'GRMAY', '1991-08-25', 'Ethiopia', 63, 'kg', 1.75, '2006-05-21','2017-04-16'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (c09e9451-50da-483d-8108-e6bea2e827b3,'VEIKKANEN', '1981-03-29', 'Finland', 66, 'kg', 1.78,'1996-05-21','2012-10-02'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (f1deff54-7d96-4981-b14a-b70be4da82d2,'TLEUBAYEV', null, 'Kazakhstan', null, null, null, '2003-04-22','2017-04-16'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (1ba0417d-62da-4103-b710-de6fb227db6f,'PAULINHO', '1990-05-27', 'Portugal', null, null, null, '2006-03-15','2017-03-05'); +INSERT INTO cycling.cyclist_alt_stats (id, lastname, birthday, nationality, weight, w_units, height, first_race, last_race) VALUES (4ceb495c-55ab-4f71-83b9-81117252bb13,'DUVAL', '1990-05-27','France', null, null, null, '2006-03-15','2017-04-16'); +// end::insert[] + +CAPTURE 'select_all_from_cyclist_alt_stats_filtering.result'; +// tag::select_success[] +SELECT * +FROM cycling.cyclist_alt_stats +WHERE birthday = '1982-01-29' + AND nationality = 'Russia' +ALLOW FILTERING; +// end::select_success[] +CAPTURE OFF; + +// tag::select_portugal[] +SELECT * +FROM cycling.cyclist_alt_stats +WHERE birthday = '1990-05-27' + AND nationality = 'Portugal' +ALLOW FILTERING; +// end::select_portugal[] + +// tag::add[] +ALTER TABLE cycling.cyclist_alt_stats +ADD cyclist_age int; +// end::add[] + +CAPTURE 'select_id_age_from_cyclist_alt_stats.result'; +// tag::sadd[] +SELECT id, cyclist_age AS age +FROM cycling.cyclist_alt_stats +LIMIT 3; +// end::sadd[] +CAPTURE OFF; + +// tag::delete[] +ALTER TABLE cycling.cyclist_alt_stats +DROP cyclist_age; +// end::delete[] + +// tag::rename[] +ALTER TABLE cycling.cyclist_alt_stats +RENAME id TO cyclist_id; +// end::rename[] diff --git a/doc/modules/cassandra/examples/CQL/create-keyspace-store.cql b/doc/modules/cassandra/examples/CQL/create-keyspace-store.cql new file mode 100644 index 0000000000..7a4f87a183 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/create-keyspace-store.cql @@ -0,0 +1,4 @@ +CREATE KEYSPACE IF NOT EXISTS store WITH REPLICATION = +{ 'class' : 'SimpleStrategy', +'replication_factor' : '1' +}; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/create-table-compaction-options.cql b/doc/modules/cassandra/examples/CQL/create-table-compaction-options.cql new file mode 100644 index 0000000000..a15da332fa --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/create-table-compaction-options.cql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS my_keyspace.my_table +. +. +. + WITH compaction = { + 'class' : 'LeveledCompactionStrategy', + 'sstable_size_in_mb' : '320' }; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/create-table-shopping-cart.cql b/doc/modules/cassandra/examples/CQL/create-table-shopping-cart.cql new file mode 100644 index 0000000000..e7d32035fa --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/create-table-shopping-cart.cql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS store.shopping_cart ( + userid text PRIMARY KEY, + item_count int, + last_update_timestamp timestamp +); \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/cyclist_semi_pro_select_country.cql b/doc/modules/cassandra/examples/CQL/cyclist_semi_pro_select_country.cql new file mode 100644 index 0000000000..e93d0c2620 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/cyclist_semi_pro_select_country.cql @@ -0,0 +1,5 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::cyclistSelectCountry[] +SELECT * FROM cycling.cyclist_semi_pro WHERE country = 'GBR'; +// end::cyclistSelectCountry[] diff --git a/doc/modules/cassandra/examples/CQL/insert-more-data-shopping-cart.cql b/doc/modules/cassandra/examples/CQL/insert-more-data-shopping-cart.cql new file mode 100644 index 0000000000..80fe2ea7ee --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/insert-more-data-shopping-cart.cql @@ -0,0 +1,3 @@ +INSERT INTO store.shopping_cart + (userid, item_count) + VALUES ('4567', 20); \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/insert-shopping-cart-data.cql b/doc/modules/cassandra/examples/CQL/insert-shopping-cart-data.cql new file mode 100644 index 0000000000..4b5fdf9248 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/insert-shopping-cart-data.cql @@ -0,0 +1,6 @@ +INSERT INTO store.shopping_cart + (userid, item_count, last_update_timestamp) + VALUES ('9876', 2, toTimeStamp(now())); +INSERT INTO store.shopping_cart + (userid, item_count, last_update_timestamp) + VALUES ('1234', 5, toTimeStamp(now())); \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/birthday_list_map_entries-table.cql b/doc/modules/cassandra/examples/CQL/sai/birthday_list_map_entries-table.cql new file mode 100644 index 0000000000..eee20f776c --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/birthday_list_map_entries-table.cql @@ -0,0 +1,98 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::drop[] +DROP TABLE IF EXISTS cycling.birthday_list; +// end::drop[] + +DROP INDEX IF EXISTS cycling.blist_idx; +DROP INDEX IF EXISTS cycling.blist_values_idx; + +/* Map entries and regular index map fields example */ + +// tag::blisttable[] +CREATE TABLE IF NOT EXISTS cycling.birthday_list ( + cyclist_name text PRIMARY KEY, + blist map +); +// end::blisttable[] + +// Create index on map ENTRIES +// tag::entriesidx[] +CREATE INDEX IF NOT EXISTS blist_idx +ON cycling.birthday_list ( ENTRIES(blist) ); +// end::entriesidx[] + +// Create index on map VALUES +// tag::mapvaluesidx[] +CREATE INDEX IF NOT EXISTS blist_values_idx +ON cycling.birthday_list ( VALUES(blist) ); +// end::mapvaluesidx[] + +// tag::insertentries[] +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Allan DAVIS', { 'age':'35', 'bday':'27/07/1980', 'nation':'AUSTRALIA' } +); + +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Claudio VANDELLI', { 'age':'54', 'bday':'27/07/1961', 'nation':'ITALY' } +); + +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Laurence BOURQUE', { 'age':'23', 'bday':'27/07/1992', 'nation':'CANADA' } +); + +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Claudio HEINEN', { 'age':'23', 'bday':'27/07/1992', 'nation':'GERMANY' } +); + +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Luc HAGENAARS', { 'age':'28', 'bday':'27/07/1987', 'nation':'NETHERLANDS' } +); + +INSERT INTO cycling.birthday_list ( + cyclist_name, blist +) VALUES ( + 'Toine POELS', { 'age':'52', 'bday':'27/07/1963', 'nation':'NETHERLANDS' } +); +// end::insertentries[] + +// Query entries - find cyclist same age +CAPTURE 'select_from_birthday_list_where_age_23.result'; +// tag::ageentryquery[] +SELECT * +FROM cycling.birthday_list +WHERE blist[ 'age' ] = '23'; +// end::ageentryquery[] +CAPTURE OFF; + +// Query entries - find cyclist same nation map entry +CAPTURE 'select_from_birthday_list_where_nation_netherlands.result'; +// tag::nationentryquery[] +SELECT * +FROM cycling.birthday_list +WHERE blist[ 'nation' ] = 'NETHERLANDS'; +// end::nationentryquery[] +CAPTURE OFF; + +// Query entries - find cyclist same nation with map VALUES CONTAINS +CAPTURE 'select_from_birthday_list_where_nation_netherlands_2.result'; +// tag::nationvaluesquery[] +SELECT * +FROM cycling.birthday_list +WHERE blist CONTAINS 'NETHERLANDS'; +// end::nationvaluesquery[] +CAPTURE OFF; + +// tag::dropentriesindex[] +DROP INDEX IF EXISTS cycling.blist_idx; +// end::dropentriesindex[] diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-index-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-index-cycling.cql new file mode 100644 index 0000000000..f5379f1d2a --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-index-cycling.cql @@ -0,0 +1,2 @@ +CREATE CUSTOM INDEX IF NOT EXISTS ann_index + ON cycling.comments_vs(comment_vector) USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-index.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-index.cql new file mode 100644 index 0000000000..e379365c62 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-index.cql @@ -0,0 +1,2 @@ +CREATE CUSTOM INDEX IF NOT EXISTS ann_index + ON vsearch.products(item_vector) USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace-cycling.cql new file mode 100644 index 0000000000..e0eaac08dc --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace-cycling.cql @@ -0,0 +1,2 @@ +CREATE KEYSPACE IF NOT EXISTS cycling + WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : '1' }; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace.cql new file mode 100644 index 0000000000..2d4ce28fb5 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-keyspace.cql @@ -0,0 +1,2 @@ +CREATE KEYSPACE IF NOT EXISTS vsearch + WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : '1' }; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-table-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-table-cycling.cql new file mode 100644 index 0000000000..625ae68b9e --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-table-cycling.cql @@ -0,0 +1,17 @@ +// tag::createvstable[] +CREATE TABLE IF NOT EXISTS cycling.comments_vs ( + record_id timeuuid, + id uuid, + commenter text, + comment text, + comment_vector VECTOR , + created_at timestamp, + PRIMARY KEY (id, created_at) +) +WITH CLUSTERING ORDER BY (created_at DESC); +// end::createvstable[] + +// tag::altervstable[] +ALTER TABLE cycling.comments_vs + ADD comment_vector VECTOR ; //<1> +// end::altervstable[] \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/create-vector-table.cql b/doc/modules/cassandra/examples/CQL/sai/create-vector-table.cql new file mode 100644 index 0000000000..bfe20afe2c --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/create-vector-table.cql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS cycling.products ( + id int PRIMARY KEY, + name TEXT, + description TEXT, + item_vector VECTOR //<1> +); diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_career_teams-table.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_career_teams-table.cql new file mode 100644 index 0000000000..661eae38ac --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_career_teams-table.cql @@ -0,0 +1,91 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.cyclist_career_teams; + +// Find all teams that a cyclist has been a member of +// CREATE TABLE WITH SET +// tag::setColumn[] +CREATE TABLE IF NOT EXISTS cycling.cyclist_career_teams ( + id UUID PRIMARY KEY, + lastname text, + teams set +); +// end::setColumn[] + +DROP INDEX IF EXISTS cycling.teams_idx; + +// Create an index on the set collection +// tag::createidxset[] +CREATE INDEX IF NOT EXISTS teams_idx +ON cycling.cyclist_career_teams (teams); +// end::createidxset[] + +// tag::insertdatasetvos[] +INSERT INTO cycling.cyclist_career_teams ( + id, lastname, teams + ) VALUES ( + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2, + 'VOS', + { + 'Rabobank-Liv Woman Cycling Team', + 'Rabobank-Liv Giant', + 'Rabobank Women Team', + 'Nederland bloeit' + } +); +// end::insertdatasetvos[] + +INSERT INTO cycling.cyclist_career_teams (id,lastname,teams) VALUES (e7cd5752-bc0d-4157-a80f-7523add8dbcd, 'VAN DER BREGGEN', { 'Rabobank-Liv Woman Cycling Team','Sengers Ladies Cycling Team','Team Flexpoint' } ); +INSERT INTO cycling.cyclist_career_teams (id,lastname,teams) VALUES (cb07baad-eac8-4f65-b28a-bddc06a0de23, 'ARMITSTEAD', { 'Boels-Dolmans Cycling Team','AA Drink - Leontien.nl','Team Garmin - Cervelo' } ); +INSERT INTO cycling.cyclist_career_teams (id,lastname,teams) VALUES (1c9ebc13-1eab-4ad5-be87-dce433216d40, 'BRAND', { 'Rabobank-Liv Woman Cycling Team','Rabobank-Liv Giant','AA Drink - Leontien.nl','Leontien.nl' } ); + +CAPTURE 'select_all_from_cyclist_career_teams.result'; +// tag::select[] +SELECT * +FROM cycling.cyclist_career_teams; +// end::select[] +CAPTURE OFF; + +// tag::add[] +UPDATE cycling.cyclist_career_teams +SET teams = teams + {'Team DSB - Ballast Nedam'} +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::add[] + +// tag::remove[] +UPDATE cycling.cyclist_career_teams +SET teams = teams - {'DSB Bank Nederland bloeit'} +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::remove[] + +// tag::clear[] +UPDATE cycling.cyclist_career_teams +SET teams = {} +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; + +DELETE teams +FROM cycling.cyclist_career_teams +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::clear[] + +CAPTURE 'select_from_cyclist_career_teams_empty.result'; +// tag::selectwithpartitionkey[] +SELECT id, lastname, teams +FROM cycling.cyclist_career_teams +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::selectwithpartitionkey[] +CAPTURE OFF; + +CAPTURE 'select_all_from_cyclist_career_teams_contains_value.result'; +// tag::select_with_contains_value[] +SELECT * +FROM cycling.cyclist_career_teams +WHERE teams CONTAINS 'Rabobank-Liv Giant'; +// end::select_with_contains_value[] +CAPTURE OFF; + +// tag::select_with_contains_key[] +SELECT * +FROM cycling.cyclist_career_teams +WHERE teams CONTAINS 'Rabobank-Liv Giant'; +// end::select_with_contains_key[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_races-table.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_races-table.cql new file mode 100644 index 0000000000..58524e5231 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_races-table.cql @@ -0,0 +1,61 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.cyclist_races; + +// Find all races for a particular cyclist +// CREATE TYPE - User-Defined Type, race +// CREATE TABLE WITH LIST, SIMPLE PRIMARY KEY +SOURCE 'race-type.cql'; + +// tag::frozenlist[] +CREATE TABLE IF NOT EXISTS cycling.cyclist_races ( + id UUID PRIMARY KEY, + lastname text, + firstname text, + races list> +); +// end::frozenlist[] + +// tag::insertFL[] +INSERT INTO cycling.cyclist_races ( + id, + lastname, + firstname, + races +) VALUES ( + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2, + 'VOS', + 'Marianne', + [ { + race_title:'Rabobank 7-Dorpenomloop Aalburg', + race_date:'2015-05-09', + race_time:'02:58:33'}, + { + race_title:'Ronde van Gelderland', + race_date:'2015-04-19', + race_time:'03:22:23' + } + ] +); +// end::insertFL[] + +INSERT INTO cycling.cyclist_races ( + id, lastname, firstname, races +) VALUES ( + e7cd5752-bc0d-4157-a80f-7523add8dbcd, 'VAN DER BREGGEN', 'Anna', [ {race_title:'Festival Luxembourgeois du cyclisme feminin Elsy Jacobs - Prologue - Garnich > Garnich',race_date:'2015-05-01',race_time:'08:13:00'},{race_title:'Festival Luxembourgeois du cyclisme feminin Elsy Jacobs - Stage 2 - Garnich > Garnich',race_date:'2015-05-02',race_time:'02:41:52'},{race_title:'Festival Luxembourgeois du cyclisme feminin Elsy Jacobs - Stage 3 - Mamer > Mamer',race_date:'2015-05-03',race_time:'02:31:24'} ] +); + +// tag::add[] +ALTER TABLE cycling.cyclist_races +ADD manager UUID; +// end::add[] + +// tag::list[] +ALTER TABLE cycling.cyclist_races +ADD completed list; +// end::list[] + +// tag::drop[] +ALTER TABLE cycling.cyclist_races +DROP manager; +// end::drop[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro-table.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro-table.cql new file mode 100644 index 0000000000..ab656670ab --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro-table.cql @@ -0,0 +1,15 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.cyclist_semi_pro; + +// tag::createCyclistSemiProTable[] +CREATE TABLE IF NOT EXISTS cycling.cyclist_semi_pro ( + id int, + firstname text, + lastname text, + age int, + affiliation text, + country text, + registration date, + PRIMARY KEY (id)); +// end::createCyclistSemiProTable[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_inserts.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_inserts.cql new file mode 100644 index 0000000000..4f5224d6b0 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_inserts.cql @@ -0,0 +1,24 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::createQuickStartIndices[] +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (1, 'Carlos', 'Perotti', 22, 'Recco Club', 'ITA', '2020-01-12'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (2, 'Giovani', 'Pasi', 19, 'Venezia Velocità', 'ITA', '2016-05-15'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (3, 'Frances', 'Giardello', 24, 'Menaggio Campioni', 'ITA', '2018-07-29'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (4, 'Mark', 'Pastore', 19, 'Portofino Ciclisti', 'ITA', '2017-06-16'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (5, 'Irene', 'Cantona', 24, 'Como Velocità', 'ITA', '2012-07-22'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (6, 'Hugo', 'Herrera', 23, 'Bellagio Ciclisti', 'ITA', '2004-02-12'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (7, 'Marcel', 'Silva', 21, 'Paris Cyclistes', 'FRA', '2018-04-28'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (8, 'Theo', 'Bernat', 19, 'Nice Cavaliers', 'FRA', '2007-05-15'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (9, 'Richie', 'Draxler', 24, 'Normandy Club', 'FRA', '2011-02-26'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (10, 'Agnes', 'Cavani', 22, 'Chamonix Hauteurs', 'FRA', '2020-01-02'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (11, 'Pablo', 'Verratti', 19, 'Chamonix Hauteurs', 'FRA', '2006-05-15'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (12, 'Charles', 'Eppinger', 24, 'Chamonix Hauteurs', 'FRA', '2018-07-29'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (13, 'Stanley', 'Trout', 30, 'Bolder Boulder', 'USA', '2016-02-12'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (14, 'Juan', 'Perez', 31, 'Rutgers Alumni Riders', 'USA', '2017-06-16'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (15, 'Thomas', 'Fulton', 27, 'Exeter Academy', 'USA', '2012-12-15'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (16, 'Jenny', 'Hamler', 28, 'CU Alums Crankworkz', 'USA', '2012-07-22'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (17, 'Alice', 'McCaffrey', 26, 'Pennan Power', 'GBR', '2020-02-12'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (18, 'Nicholas', 'Burrow', 26, 'Aberdeen Association', 'GBR', '2016-02-12'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (19, 'Tyler', 'Higgins', 24, 'Highclere Agents', 'GBR', '2019-07-31'); +INSERT INTO cycling.cyclist_semi_pro (id, firstname, lastname, age, affiliation, country, registration) VALUES (20, 'Leslie', 'Boyd', 18, 'London Cyclists', 'GBR', '2012-12-15'); +// end::createQuickStartIndices[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_sai_indices.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_sai_indices.cql new file mode 100644 index 0000000000..c239f176c7 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_sai_indices.cql @@ -0,0 +1,22 @@ +SOURCE '0_create_keyspace.cql'; + +DROP INDEX IF EXISTS cycling.lastname_sai_idx; +DROP INDEX IF EXISTS cycling.age_sai_idx; +DROP INDEX IF EXISTS cycling.country_sai_idx; +DROP INDEX IF EXISTS cycling.registration_sai_idx; + +// tag::createQuickStartIndices[] +CREATE CUSTOM INDEX lastname_sai_idx ON cycling.cyclist_semi_pro (lastname) +USING 'StorageAttachedIndex' +WITH OPTIONS = {'case_sensitive': 'false', 'normalize': 'true', 'ascii': 'true'}; + +CREATE CUSTOM INDEX age_sai_idx ON cycling.cyclist_semi_pro (age) +USING 'StorageAttachedIndex'; + +CREATE CUSTOM INDEX country_sai_idx ON cycling.cyclist_semi_pro (country) +USING 'StorageAttachedIndex' +WITH OPTIONS = {'case_sensitive': 'false', 'normalize': 'true', 'ascii': 'true'}; + +CREATE CUSTOM INDEX registration_sai_idx ON cycling.cyclist_semi_pro (registration) +USING 'StorageAttachedIndex'; +// end::createQuickStartIndices[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_age.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_age.cql new file mode 100644 index 0000000000..6c15d2bdc4 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_age.cql @@ -0,0 +1,5 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::cyclistSelectAge[] +SELECT * FROM cycling.cyclist_semi_pro WHERE age <= 23; +// end::cyclistSelectAge[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_country.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_country.cql new file mode 100644 index 0000000000..e93d0c2620 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_country.cql @@ -0,0 +1,5 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::cyclistSelectCountry[] +SELECT * FROM cycling.cyclist_semi_pro WHERE country = 'GBR'; +// end::cyclistSelectCountry[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_date_range.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_date_range.cql new file mode 100644 index 0000000000..597c0ef4d3 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_date_range.cql @@ -0,0 +1,5 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::cyclistSelectDateRange[] +SELECT * FROM cycling.cyclist_semi_pro WHERE registration > '2010-01-01' AND registration < '2015-12-31' LIMIT 10; +// end::cyclistSelectDateRange[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_specific_rider.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_specific_rider.cql new file mode 100644 index 0000000000..d4107809ea --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_semi_pro_select_specific_rider.cql @@ -0,0 +1,5 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::cyclistSelectSpecificRider[] +SELECT * FROM cycling.cyclist_semi_pro WHERE lastname = 'Eppinger'; +// end::cyclistSelectSpecificRider[] diff --git a/doc/modules/cassandra/examples/CQL/sai/cyclist_teams-table.cql b/doc/modules/cassandra/examples/CQL/sai/cyclist_teams-table.cql new file mode 100644 index 0000000000..f8fa8683d6 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/cyclist_teams-table.cql @@ -0,0 +1,120 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.cyclist_teams; + +// Create a table with a map +// tag::mapColumn[] +CREATE TABLE IF NOT EXISTS cycling.cyclist_teams ( + id uuid PRIMARY KEY, + firstname text, + lastname text, + teams map +); +// end::mapColumn[] + +DROP INDEX IF EXISTS cycling.team_year_idx; + +// Create an index on a map key to find all cyclist/team combos for a year +// tag::keysidx[] +CREATE INDEX IF NOT EXISTS team_year_keys_idx +ON cycling.cyclist_teams ( KEYS (teams) ); +// end::keysidx[] + +// Create an index on a map key to find all cyclist/team combos for a year +// tag::valuesidx[] +CREATE INDEX IF NOT EXISTS team_year_values_idx +ON cycling.cyclist_teams ( VALUES (teams) ); +// end::valuesidx[] + +// Create an index on a map key to find all cyclist/team combos for a year +// tag::entriesidx[] +CREATE INDEX IF NOT EXISTS team_year_entries_idx +ON cycling.cyclist_teams ( ENTRIES (teams) ); +// end::entriesidx[] + +// Insert team data into map for cyclist Vos +// tag::insertmapdata[] +INSERT INTO cycling.cyclist_teams ( + id, firstname, lastname, teams +) VALUES ( + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2, + 'Marianne', + 'VOS', + { + 2015 : 'Rabobank-Liv Woman Cycling Team', + 2014 : 'Rabobank-Liv Woman Cycling Team' + } +); +// end::insertmapdata[] + +// View data +CAPTURE 'select_all_from_cyclist_teams.result'; +// tag::select[] +SELECT * +FROM cycling.cyclist_teams; +// end::select[] +CAPTURE OFF; + +// Delete an element from the map +// tag::deletemapdata[] +DELETE teams[2014] +FROM cycling.cyclist_teams +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::deletemapdata[] + +// View data again, 2014 team gone +SELECT * +FROM cycling.cyclist_teams; + +// Insert more cyclists +INSERT INTO cycling.cyclist_teams ( + id,firstname,lastname,teams +) VALUES ( + cb07baad-eac8-4f65-b28a-bddc06a0de23, + 'Elizabeth', + 'ARMITSTEAD', + { + 2015 : 'Boels:Dolmans Cycling Team', + 2014 : 'Boels:Dolmans Cycling Team', + 2013 : 'Boels:Dolmans Cycling Team', + 2012 : 'AA Drink - Leontien.nl', + 2011 : 'Team Garmin - Cervelo' + } +); + +// View data +SELECT * +FROM cycling.cyclist_teams; + +// Query for KEY year 2015 +CAPTURE 'cyclist_team-queries.result'; +// tag::queryindexkey[] +SELECT * +FROM cycling.cyclist_teams +WHERE teams CONTAINS KEY 2015; +// end::queryindexkey[] +CAPTURE OFF; + +// tag::update_DSB[] +UPDATE cycling.cyclist_teams +SET teams = teams + { 2009 : 'DSB Bank - Nederland bloeit' } +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::update_DSB[] + +// tag::update_Ballast[] +UPDATE cycling.cyclist_teams +SET teams[2006] = 'Team DSB - Ballast Nedam' +WHERE id = 5b6962dd-3f90-4c93-8f61-eabfa4a803e2; +// end::update_Ballast[] + +// tag::delete_teams[] +DELETE teams[2009] +FROM cycling.cyclist_teams +WHERE id=e7cd5752-bc0d-4157-a80f-7523add8dbcd; +// end::delete_teams[] + +// tag::update_set[] +UPDATE cycling.cyclist_teams +SET teams = teams - { 2013, 2014 } +WHERE id = e7cd5752-bc0d-4157-a80f-7523add8dbcd; +// end::update_set[] diff --git a/doc/modules/cassandra/examples/CQL/sai/drop-sai-index.cql b/doc/modules/cassandra/examples/CQL/sai/drop-sai-index.cql new file mode 100644 index 0000000000..ce35197fc3 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/drop-sai-index.cql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS cycling.lastname_sai_idx; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-case-sensitive.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-case-sensitive.cql new file mode 100644 index 0000000000..71a1d2b413 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-case-sensitive.cql @@ -0,0 +1,3 @@ +CREATE CUSTOM INDEX commenter_cs_idx ON cycling.comments_vs (commenter) +USING 'StorageAttachedIndex' +WITH OPTIONS = {'case_sensitive': 'true', 'normalize': 'true', 'ascii': 'true'}; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-composite-partition-key-index-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-composite-partition-key-index-match.cql new file mode 100644 index 0000000000..e8f4e3a89c --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-composite-partition-key-index-match.cql @@ -0,0 +1,6 @@ +CREATE CUSTOM INDEX race_name_idx + ON cycling.rank_by_year_and_name (race_name) + USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX race_year_idx + ON cycling.rank_by_year_and_name (race_year) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-from-list-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-list-match.cql new file mode 100644 index 0000000000..7019b9d6e4 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-list-match.cql @@ -0,0 +1,3 @@ +CREATE CUSTOM INDEX events_idx + ON cycling.upcoming_calendar (events) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-from-map-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-map-match.cql new file mode 100644 index 0000000000..5d0b0274c8 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-map-match.cql @@ -0,0 +1,17 @@ +// Create an index on a map key to find all cyclist/team combos for a year +// tag::keysidx[] +CREATE INDEX IF NOT EXISTS team_year_keys_idx +ON cycling.cyclist_teams ( KEYS (teams) ); +// end::keysidx[] + +// Create an index on a map key to find all cyclist/team combos for a year +// tag::valuesidx[] +CREATE INDEX IF NOT EXISTS team_year_values_idx +ON cycling.cyclist_teams ( VALUES (teams) ); +// end::valuesidx[] + +// Create an index on a map key to find all cyclist/team combos for a year +// tag::entriesidx[] +CREATE INDEX IF NOT EXISTS team_year_entries_idx +ON cycling.cyclist_teams ( ENTRIES (teams) ); +// end::entriesidx[] \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-from-set-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-set-match.cql new file mode 100644 index 0000000000..ba2bfd9930 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-from-set-match.cql @@ -0,0 +1,3 @@ +CREATE CUSTOM INDEX teams_idx + ON cycling.cyclist_career_teams (teams) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-multiple-index-match-with-and.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-multiple-index-match-with-and.cql new file mode 100644 index 0000000000..8c0f9b8ad0 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-multiple-index-match-with-and.cql @@ -0,0 +1,10 @@ +CREATE CUSTOM INDEX commenter_idx + ON cycling.comments_vs (commenter) + USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX created_at_idx + ON cycling.comments_vs (created_at) + USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX ann_index + ON cycling.comments_vs (comment_vector) + USING 'StorageAttachedIndex'; + diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-bad.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-bad.cql new file mode 100644 index 0000000000..02bdb32dcf --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-bad.cql @@ -0,0 +1 @@ +SELECT * FROM comments_vs WHERE commenter ='alex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-good.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-good.cql new file mode 100644 index 0000000000..3f280969f5 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-case-sensitive-good.cql @@ -0,0 +1 @@ +SELECT comment,commenter FROM comments_vs WHERE commenter ='Alex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-name.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-name.cql new file mode 100644 index 0000000000..d98dd599be --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-name.cql @@ -0,0 +1,2 @@ + SELECT * FROM cycling.rank_by_year_and_name + WHERE race_name = 'Tour of Japan - Stage 4 - Minami > Shinshu'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-year.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-year.cql new file mode 100644 index 0000000000..62b9dbc09a --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-composite-partition-key-race-year.cql @@ -0,0 +1,2 @@ + SELECT * FROM cycling.rank_by_year_and_name + WHERE race_year = 2014; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list-two-columns.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list-two-columns.cql new file mode 100644 index 0000000000..f07dcadfad --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list-two-columns.cql @@ -0,0 +1,3 @@ +SELECT * FROM cycling.upcoming_calendar + WHERE events CONTAINS 'Criterium du Dauphine' + OR month = 7; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list.cql new file mode 100644 index 0000000000..8a06de0b44 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-list.cql @@ -0,0 +1,2 @@ +SELECT * FROM cycling.upcoming_calendar + WHERE events CONTAINS 'Criterium du Dauphine'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-entries.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-entries.cql new file mode 100644 index 0000000000..78c9d7dc1d --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-entries.cql @@ -0,0 +1,4 @@ +SELECT * FROM cyclist_teams +WHERE + teams[2014] = 'Boels:Dolmans Cycling Team' + AND teams[2015] = 'Boels:Dolmans Cycling Team'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-key.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-key.cql new file mode 100644 index 0000000000..68188c3546 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-key.cql @@ -0,0 +1 @@ +SELECT * FROM cyclist_teams WHERE teams CONTAINS KEY 2014; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-value.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-value.cql new file mode 100644 index 0000000000..0ea9fb3dd9 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-map-value.cql @@ -0,0 +1 @@ +SELECT * FROM cyclist_teams WHERE teams CONTAINS 'Team Garmin - Cervelo'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-set.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-set.cql new file mode 100644 index 0000000000..3896f5e5d3 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-from-set.cql @@ -0,0 +1,2 @@ +SELECT * FROM cycling.cyclist_career_teams + WHERE teams CONTAINS 'Rabobank-Liv Giant'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-and.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-and.cql new file mode 100644 index 0000000000..6348d1999d --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-and.cql @@ -0,0 +1,4 @@ +SELECT * FROM cycling.comments_vs + WHERE + created_at='2017-03-21 21:11:09.999000+0000' + AND commenter = 'Alex'; diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-in.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-in.cql new file mode 100644 index 0000000000..72a2079ab1 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-in.cql @@ -0,0 +1,4 @@ +SELECT * FROM cycling.comments_vs + WHERE created_at IN + ('2017-03-21 21:11:09.999000+0000' + ,'2017-03-22 01:16:59.001000+0000'); diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-or.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-or.cql new file mode 100644 index 0000000000..687af6c3e8 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-multiple-index-match-with-or.cql @@ -0,0 +1,4 @@ +SELECT * FROM cycling.comments_vs + WHERE + created_at='2017-03-21 21:11:09.999000+0000' + OR created_at='2017-03-22 01:16:59.001000+0000'; diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-single-index-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-single-index-match.cql new file mode 100644 index 0000000000..8f7403376c --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-single-index-match.cql @@ -0,0 +1,2 @@ + SELECT * FROM cycling.comments_vs + WHERE commenter = 'Alex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-select-udt-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-udt-match.cql new file mode 100644 index 0000000000..3b92dd9cd9 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-select-udt-match.cql @@ -0,0 +1,5 @@ +SELECT * FROM cycling.cyclist_races + WHERE races CONTAINS { + race_title:'Rabobank 7-Dorpenomloop Aalburg', + race_date:'2015-05-09', + race_time:'02:58:33'}; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-similarity-function.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-similarity-function.cql new file mode 100644 index 0000000000..76508d9a22 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-similarity-function.cql @@ -0,0 +1,4 @@ +CREATE CUSTOM INDEX sim_comments_idx + ON cycling.comments_vs (comment_vector) + USING 'StorageAttachedIndex' + WITH OPTIONS = { 'similarity_function': 'DOT_PRODUCT'}; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-single-index-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-single-index-match.cql new file mode 100644 index 0000000000..8a9208faf5 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-single-index-match.cql @@ -0,0 +1,3 @@ +CREATE CUSTOM INDEX commenter_idx + ON cycling.comments_vs (commenter) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/index-sai-udt-match.cql b/doc/modules/cassandra/examples/CQL/sai/index-sai-udt-match.cql new file mode 100644 index 0000000000..30a86c770e --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/index-sai-udt-match.cql @@ -0,0 +1,3 @@ +CREATE CUSTOM INDEX races_idx + ON cycling.cyclist_races (races) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/insert-vector-data-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/insert-vector-data-cycling.cql new file mode 100644 index 0000000000..3a3ad271b5 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/insert-vector-data-cycling.cql @@ -0,0 +1,66 @@ +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector + VALUES ( + now(), + e7ae5cf3-d358-4d99-b900-85902fda9bb0, + '2017-02-14 12:43:20-0800', + 'Raining too hard should have postponed', + 'Alex', + [0.45, 0.09, 0.01, 0.2, 0.11] +); +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + e7ae5cf3-d358-4d99-b900-85902fda9bb0, + '2017-03-21 13:11:09.999-0800', + 'Second rest stop was out of water', + 'Alex', + [0.99, 0.5, 0.99, 0.1, 0.34] +); +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + e7ae5cf3-d358-4d99-b900-85902fda9bb0, + '2017-04-01 06:33:02.16-0800', + 'LATE RIDERS SHOULD NOT DELAY THE START', + 'Alex', + [0.9, 0.54, 0.12, 0.1, 0.95] +); + +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + c7fceba0-c141-4207-9494-a29f9809de6f, + totimestamp(now()), + 'The gift certificate for winning was the best', + 'Amy', + [0.13, 0.8, 0.35, 0.17, 0.03] +); + +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + c7fceba0-c141-4207-9494-a29f9809de6f, + '2017-02-17 12:43:20.234+0400', + 'Glad you ran the race in the rain', + 'Amy', + [0.3, 0.34, 0.2, 0.78, 0.25] +); + +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + c7fceba0-c141-4207-9494-a29f9809de6f, + '2017-03-22 5:16:59.001+0400', + 'Great snacks at all reststops', + 'Amy', + [0.1, 0.4, 0.1, 0.52, 0.09] +); +INSERT INTO cycling.comments_vs (record_id, id, created_at, comment, commenter, comment_vector) + VALUES ( + now(), + c7fceba0-c141-4207-9494-a29f9809de6f, + '2017-04-01 17:43:08.030+0400', + 'Last climb was a killer', + 'Amy', + [0.3, 0.75, 0.2, 0.2, 0.5] +); \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/race-type.cql b/doc/modules/cassandra/examples/CQL/sai/race-type.cql new file mode 100644 index 0000000000..b6c68541c9 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/race-type.cql @@ -0,0 +1,13 @@ +SOURCE '0_create_keyspace.cql'; + +// tag::drop[] +DROP TYPE IF EXISTS cycling.race; +// end::drop[] + +// tag::racetype[] +CREATE TYPE IF NOT EXISTS cycling.race ( + race_title text, + race_date timestamp, + race_time text +); +// end::racetype[] diff --git a/doc/modules/cassandra/examples/CQL/sai/race_starts-table.cql b/doc/modules/cassandra/examples/CQL/sai/race_starts-table.cql new file mode 100644 index 0000000000..b476b4177e --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/race_starts-table.cql @@ -0,0 +1,38 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.race_starts; + +// create a table with a frozen list of ints +// tag::frozenlist[] +CREATE TABLE IF NOT EXISTS cycling.race_starts ( + cyclist_name text PRIMARY KEY, + rnumbers FROZEN> +); +// end::frozenlist[] + +// View created table +DESCRIBE TABLE cycling.race_starts; + +DROP INDEX IF EXISTS cycling.rnumbers_idx; + +// Create index +// tag::fullindex[] +CREATE INDEX IF NOT EXISTS rnumbers_idx +ON cycling.race_starts ( FULL(rnumbers) ); +// end::fullindex[] + +// Insert data +INSERT INTO cycling.race_starts ( + cyclist_name, rnumbers +) VALUES ( + 'John DEGENKOLB', [39, 7, 14] +); + +// Select data with WHERE clause +CAPTURE 'race_starts-queries.result'; +// tag::selectrnumbers[] +SELECT * +FROM cycling.race_starts +WHERE rnumbers = [39, 7, 14]; +// end::selectrnumbers[] +CAPTURE OFF; diff --git a/doc/modules/cassandra/examples/CQL/sai/rank_by_year_and_name-table.cql b/doc/modules/cassandra/examples/CQL/sai/rank_by_year_and_name-table.cql new file mode 100644 index 0000000000..472d7d1db2 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/rank_by_year_and_name-table.cql @@ -0,0 +1,134 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.rank_by_year_and_name; + +// Store race information by year and race name using a COMPOSITE PARTITION KEY + +// tag::use_and_compositepk[] +USE cycling; +CREATE TABLE rank_by_year_and_name ( + race_year int, + race_name text, + cyclist_name text, + rank int, + PRIMARY KEY ((race_year, race_name), rank) +); +// end::use_and_compositepk[] + +DROP TABLE IF EXISTS cycling.rank_by_year_and_name; + +// tag::compositepk[] +CREATE TABLE IF NOT EXISTS cycling.rank_by_year_and_name ( + race_year int, + race_name text, + cyclist_name text, + rank int, + PRIMARY KEY ((race_year, race_name), rank) +); +// end::compositepk[] + +// tag::dropindex[] +DROP INDEX IF EXISTS cycling.rank_idx; +// end::dropindex[] + +// tag::createindex[] +CREATE INDEX IF NOT EXISTS rank_idx +ON cycling.rank_by_year_and_name (rank); +// end::createindex[] + +// tag::drop_race_year_idx[] +DROP INDEX IF EXISTS cycling.race_year_idx; +// end::drop_race_year_idx[] + +// tag::create_race_year_idx[] +CREATE INDEX IF NOT EXISTS race_year_idx ON +cycling.rank_by_year_and_name (race_year); +// end::create_race_year_idx[] + +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2015, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Benjamin PRADES', 1); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2015, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Adam PHELAN', 2); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2015, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Thomas LEBAS', 3); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Benjamin PRADES', 3); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Daniel MARTIN', 1); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, 'Tour of Japan - Stage 4 - Minami > Shinshu', 'Johan Esteban CHAVES', 2); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2015, 'Giro d''Italia - Stage 11 - Forli > Imola', 'Ilnur ZAKARIN', 1); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2015, 'Giro d''Italia - Stage 11 - Forli > Imola', 'Carlos BETANCUR', 2); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Phillippe GILBERT', 1); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Daniel MARTIN', 2); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Johan Esteban CHAVES', 3); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Phillippe GILBERT', 1); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Daniel MARTIN', 2); +INSERT INTO cycling.rank_by_year_and_name (race_year, race_name, cyclist_name, rank) VALUES (2014, '4th Tour of Beijing', 'Johan Esteban CHAVES', 3); + +// Show all inserted data +CAPTURE 'select_all_from_rank_by_year_and_name.result'; +SELECT * +FROM cycling.rank_by_year_and_name; +CAPTURE OFF; + +CAPTURE 'select_all_from_rank_by_year_and_name_Japan_2014.result'; +// tag::select_with_name_and_year[] +SELECT * +FROM cycling.rank_by_year_and_name +WHERE race_year = 2014 + AND race_name = 'Tour of Japan - Stage 4 - Minami > Shinshu'; +// end::select_with_name_and_year[] +CAPTURE OFF; + +// tag::sepstatementswithand[] +SELECT + rank, + cyclist_name AS name +FROM cycling.rank_by_year_and_name +WHERE "race_name" = 'Tour of Japan - Stage 4 - Minami > Shinshu' + AND race_year = 2014; +// end::sepstatementswithand[] + +// tag::columnalias[] +CAPTURE 'select_best_rank_from_rank_by_year_and_name.result'; +SELECT + MIN(rank) AS best_rank, + cyclist_name +FROM cycling.rank_by_year_and_name +WHERE "race_name" = 'Tour of Japan - Stage 4 - Minami > Shinshu' + AND race_year = 2014; +// end::columnalias[] +CAPTURE OFF; + +// The following query generates a warning, which is normal +// tag::countrows[] +SELECT COUNT(*) +FROM cycling.rank_by_year_and_name; +// end::countrows[] + +// tag::limitrows[] +SELECT cyclist_name +FROM cycling.rank_by_year_and_name +LIMIT 50000; +// end::limitrows[] + +// Query by partition +CAPTURE 'select_all_from_rank_by_year_and_name_partition_limit.result'; +// tag::partlimit[] +SELECT * +FROM cycling.rank_by_year_and_name +PER PARTITION LIMIT 2; +// end::partlimit[] +CAPTURE OFF; + +// Select rank - filter on a clustering column +CAPTURE 'select_all_from_rank_by_year_and_name_rank_1.result'; +// tag::selectrank[] +SELECT * +FROM cycling.rank_by_year_and_name +WHERE rank = 1; +// end::selectrank[] +CAPTURE OFF; + +CAPTURE 'select_all_from_rank_by_year_and_name_2014.result'; +// tag::select_with_year[] +SELECT * +FROM cycling.rank_by_year_and_name +WHERE race_year = 2014; +// end::select_with_year[] +CAPTURE OFF; diff --git a/doc/modules/cassandra/examples/CQL/sai/sai-check.cql b/doc/modules/cassandra/examples/CQL/sai/sai-check.cql new file mode 100644 index 0000000000..78aa234e5a --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/sai-check.cql @@ -0,0 +1 @@ +DESCRIBE TABLE cycling.cyclist_semi_pro; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/sai-error.cql b/doc/modules/cassandra/examples/CQL/sai/sai-error.cql new file mode 100644 index 0000000000..bcb79d6a22 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/sai-error.cql @@ -0,0 +1,2 @@ +CREATE CUSTOM INDEX ON demo2.person_id_name_primarykey (id) + USING 'StorageAttachedIndex'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/select-vsearch-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/select-vsearch-cycling.cql new file mode 100644 index 0000000000..b3572e3c43 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/select-vsearch-cycling.cql @@ -0,0 +1,3 @@ +SELECT * FROM cycling.comments_vs + ORDER BY comment_vector ANN OF [0.15, 0.1, 0.1, 0.35, 0.55] + LIMIT 3; diff --git a/doc/modules/cassandra/examples/CQL/sai/select_all_from_cyclist_career_teams-team.cql b/doc/modules/cassandra/examples/CQL/sai/select_all_from_cyclist_career_teams-team.cql new file mode 100644 index 0000000000..1cafb0569b --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/select_all_from_cyclist_career_teams-team.cql @@ -0,0 +1 @@ +SELECT * FROM cyclist_career_teams WHERE teams CONTAINS 'Rabobank-Liv Woman Cycling Team'; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/select_all_from_rank_by_year_and_name-rank.cql b/doc/modules/cassandra/examples/CQL/sai/select_all_from_rank_by_year_and_name-rank.cql new file mode 100644 index 0000000000..c074f246a0 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/select_all_from_rank_by_year_and_name-rank.cql @@ -0,0 +1 @@ +SELECT * FROM rank_by_year_and_name WHERE rank = 1; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/sai/upcoming_calendar-table.cql b/doc/modules/cassandra/examples/CQL/sai/upcoming_calendar-table.cql new file mode 100644 index 0000000000..8148de39ba --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/upcoming_calendar-table.cql @@ -0,0 +1,145 @@ +SOURCE '0_create_keyspace.cql'; + +DROP TABLE IF EXISTS cycling.upcoming_calendar; + +// Find all calendar events for a particular year and month +// tag::listColumn[] +CREATE TABLE IF NOT EXISTS cycling.upcoming_calendar ( + year int, + month int, + events list, + PRIMARY KEY (year, month) +); +// end::listColumn[] + +// tag::add_tour[] +INSERT INTO cycling.upcoming_calendar ( + year, month, events +) VALUES ( + 2015, 06, [ 'Criterium du Dauphine', 'Tour de Suisse' ] +); +// end::add_tour[] + +INSERT INTO cycling.upcoming_calendar ( + year, month, events +) VALUES ( + 2015, 07, [ 'Tour de France' ] +); + +// tag::delete[] +DELETE events[0] +FROM cycling.upcoming_calendar +WHERE year = 2015 + AND month = 07; +// end::delete[] + +// tag::remove[] +UPDATE cycling.upcoming_calendar +SET events = events - ['Tour de France Stage 10'] +WHERE year = 2015 + AND month = 07; +// end::remove[] + +INSERT INTO cycling.upcoming_calendar ( + year, month, events +) VALUES ( + 2015, 07, [ 'Tour de France' ] +); + +CAPTURE 'select_all_from_upcoming_calendar.result'; +// tag::select[] +SELECT * +FROM cycling.upcoming_calendar; +// end::select[] +CAPTURE OFF; + +// tag::insert[] +UPDATE cycling.upcoming_calendar +SET events = [ 'Criterium du Dauphine', 'Tour de Suisse' ] +WHERE year = 2015 + AND month = 06; +// end::insert[] + +// tag::prepend[] +UPDATE cycling.upcoming_calendar +SET events = [ 'Tour de France' ] + events +WHERE year = 2015 + AND month = 06; +// end::prepend[] + +// tag::append[] +UPDATE cycling.upcoming_calendar +SET events = events + [ 'Tour de France' ] +WHERE year = 2017 + AND month = 05; +// end::append[] + +// tag::position[] +UPDATE cycling.upcoming_calendar +SET events[2] = 'Tour de France' +WHERE year = 2015 + AND month = 06; +// end::position[] + +// tag::set[] +UPDATE cycling.upcoming_calendar +SET events[2] = 'Vuelta Ciclista a Venezuela' +WHERE year = 2015 + AND month = 06; +// end::set[] + +// tag::ttl[] +UPDATE cycling.upcoming_calendar +USING TTL 10000000 +SET events[2] = 'Vuelta Ciclista a Venezuela' +WHERE year = 2015 + AND month = 06; +// end::ttl[] + +// tag::addcolumn[] +ALTER TABLE cycling.upcoming_calendar +ADD description map; +// end::addcolumn[] + +// tag::example[] +UPDATE cycling.upcoming_calendar +SET description = description + { + 'Criterium du Dauphine' : 'Easy race', 'Tour du Suisse' : 'Hard uphill race' +} +WHERE year = 2015 + AND month = 6; +// end::example[] + +// tag::newrow[] +UPDATE cycling.upcoming_calendar +SET description = { + 'Criterium du Dauphine' : 'Easy race', 'Tour du Suisse' : 'Hard uphill race' +} +WHERE year = 2015 + AND month = 6; +// end::newrow[] + +CAPTURE 'select_description_from_upcoming_calendar.result'; +// tag::select_description[] +SELECT description +FROM cycling.upcoming_calendar +WHERE year = 2015 + AND month = 6; +// end::select_description[] +CAPTURE OFF; + +// tag::value[] +UPDATE cycling.upcoming_calendar +SET events = events - [ 'Tour de France' ] +WHERE year = 2015 + AND month = 06; +// end::value[] + +// tag::map[] +UPDATE cycling.upcoming_calendar +SET description = description + { + 'Criterium du Dauphine' : 'Easy race' +} +WHERE year = 2015 + AND month = 06; +// end::map[] diff --git a/doc/modules/cassandra/examples/CQL/sai/use-vector-keyspace-cycling.cql b/doc/modules/cassandra/examples/CQL/sai/use-vector-keyspace-cycling.cql new file mode 100644 index 0000000000..de47727798 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/sai/use-vector-keyspace-cycling.cql @@ -0,0 +1 @@ +USE cycling; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/select-data-from-shopping-cart.cql b/doc/modules/cassandra/examples/CQL/select-data-from-shopping-cart.cql new file mode 100644 index 0000000000..bfe6001a52 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/select-data-from-shopping-cart.cql @@ -0,0 +1 @@ +SELECT * FROM store.shopping_cart; \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/2i/2i-check.result b/doc/modules/cassandra/examples/RESULTS/2i/2i-check.result new file mode 100644 index 0000000000..2fd9f95700 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/2i/2i-check.result @@ -0,0 +1 @@ +TBD \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/2i/select_all_from_cyclist_alt_stats_filtering.result b/doc/modules/cassandra/examples/RESULTS/2i/select_all_from_cyclist_alt_stats_filtering.result new file mode 100644 index 0000000000..192cc588fa --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/2i/select_all_from_cyclist_alt_stats_filtering.result @@ -0,0 +1,5 @@ + id | birthday | first_race | height | last_race | lastname | nationality | w_units | weight +--------------------------------------+------------+------------+--------+------------+----------+-------------+---------+-------- + e0953617-07eb-4c82-8f91-3b2757981625 | 1982-01-29 | 1998-02-15 | 1.78 | 2017-04-16 | BRUTT | Russia | kg | 68 + +(1 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/curl_verify_sha.result b/doc/modules/cassandra/examples/RESULTS/curl_verify_sha.result new file mode 100644 index 0000000000..eafd828547 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/curl_verify_sha.result @@ -0,0 +1 @@ +28757dde589f70410f9a6a95c39ee7e6cde63440e2b06b91ae6b200614fa364d \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/cyclist_team-queries.results b/doc/modules/cassandra/examples/RESULTS/cyclist_team-queries.results new file mode 100644 index 0000000000..c7af8468b3 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/cyclist_team-queries.results @@ -0,0 +1,6 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | Elizabeth | ARMITSTEAD | {2011: 'Team Garmin - Cervelo', 2012: 'AA Drink - Leontien.nl', 2013: 'Boels:Dolmans Cycling Team', 2014: 'Boels:Dolmans Cycling Team', 2015: 'Boels:Dolmans Cycling Team'} + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | Marianne | VOS | {2015: 'Rabobank-Liv Woman Cycling Team'} + +(2 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/docker-run-cqlsh-quickstart.result b/doc/modules/cassandra/examples/RESULTS/docker-run-cqlsh-quickstart.result new file mode 100644 index 0000000000..047a1b4147 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/docker-run-cqlsh-quickstart.result @@ -0,0 +1,4 @@ +Connected to Test Cluster at cassandra:9042. +[cqlsh 5.0.1 | Cassandra 4.0.4 | CQL spec 3.4.5 | Native protocol v5] +Use HELP for help. +cqlsh> \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_describe.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_describe.result new file mode 100644 index 0000000000..84e9ed0355 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_describe.result @@ -0,0 +1,29 @@ +// tag::cyclistSemiProDescribeResults[] +CREATE TABLE cycling.cyclist_semi_pro ( + id int PRIMARY KEY, + affiliation text, + age int, + country text, + firstname text, + lastname text, + registration date +) WITH additional_write_policy = '99PERCENTILE' + AND bloom_filter_fp_chance = 0.01 + AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} + AND comment = '' + AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'} + AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'} + AND crc_check_chance = 1.0 + AND default_time_to_live = 0 + AND gc_grace_seconds = 864000 + AND max_index_interval = 2048 + AND memtable_flush_period_in_ms = 0 + AND min_index_interval = 128 + AND nodesync = {'enabled': 'true', 'incremental': 'true'} + AND read_repair = 'BLOCKING' + AND speculative_retry = '99PERCENTILE'; +CREATE CUSTOM INDEX registration_sai_idx ON cycling.cyclist_semi_pro (registration) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX country_sai_idx ON cycling.cyclist_semi_pro (country) USING 'StorageAttachedIndex' WITH OPTIONS = {'normalize': 'true', 'case_sensitive': 'false', 'ascii': 'true'}; +CREATE CUSTOM INDEX age_sai_idx ON cycling.cyclist_semi_pro (age) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX lastname_sai_idx ON cycling.cyclist_semi_pro (lastname) USING 'StorageAttachedIndex' WITH OPTIONS = {'normalize': 'true', 'case_sensitive': 'false', 'ascii': 'true'}; +// end::cyclistSemiProDescribeResults[] diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_age.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_age.result new file mode 100644 index 0000000000..a950cc585b --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_age.result @@ -0,0 +1,19 @@ +SOURCE '0_create_keyspace.cql'; + +// SELECT * FROM cycling.cyclist_semi_pro WHERE age <= 23; + +// tag::cyclistSelectAgeResults[] + id | affiliation | age | country | firstname | lastname | registration +----+--------------------+-----+---------+-----------+----------+-------------- + 10 | Chamonix Hauteurs | 22 | FRA | Agnes | Cavani | 2020-01-02 + 11 | Chamonix Hauteurs | 19 | FRA | Pablo | Verratti | 2006-05-15 + 1 | Recco Club | 22 | ITA | Carlos | Perotti | 2020-01-12 + 8 | Nice Cavaliers | 19 | FRA | Theo | Bernat | 2007-05-15 + 2 | Venezia Velocità | 19 | ITA | Giovani | Pasi | 2016-05-15 + 4 | Portofino Ciclisti | 19 | ITA | Mark | Pastore | 2017-06-16 + 20 | London Cyclists | 18 | GBR | Leslie | Boyd | 2012-12-15 + 7 | Paris Cyclistes | 21 | FRA | Marcel | Silva | 2018-04-28 + 6 | Bellagio Ciclisti | 23 | ITA | Hugo | Herrera | 2004-02-12 + +(9 rows) +// end::cyclistSelectAgeResults[] diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_country.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_country.result new file mode 100644 index 0000000000..1df2f5ed9e --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_country.result @@ -0,0 +1,14 @@ +SOURCE '0_create_keyspace.cql'; + +// SELECT * FROM cycling.cyclist_semi_pro WHERE country = 'GBR'; + +// tag::cyclistSelectCountryResults[] + id | affiliation | age | country | firstname | lastname | registration +----+----------------------+-----+---------+-----------+-----------+-------------- + 19 | Highclere Agents | 24 | GBR | Tyler | Higgins | 2019-07-31 + 18 | Aberdeen Association | 26 | GBR | Nicholas | Burrow | 2016-02-12 + 20 | London Cyclists | 18 | GBR | Leslie | Boyd | 2012-12-15 + 17 | Pennan Power | 26 | GBR | Alice | McCaffrey | 2020-02-12 + +(4 rows) +// end::cyclistSelectCountryResults[] diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_date_range.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_date_range.result new file mode 100644 index 0000000000..25e4a60e22 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_date_range.result @@ -0,0 +1,16 @@ +SOURCE '0_create_keyspace.cql'; + +// SELECT * FROM cycling.cyclist_semi_pro WHERE registration > '2010-01-01' AND registration < '2015-12-31' LIMIT 10; + + +// tag::cyclistSelectDateRangeResults[] + id | affiliation | age | country | firstname | lastname | registration +----+---------------------+-----+---------+-----------+----------+-------------- + 5 | Como Velocità | 24 | ITA | Irene | Cantona | 2012-07-22 + 16 | CU Alums Crankworkz | 28 | USA | Jenny | Hamler | 2012-07-22 + 15 | Exeter Academy | 27 | USA | Thomas | Fulton | 2012-12-15 + 20 | London Cyclists | 18 | GBR | Leslie | Boyd | 2012-12-15 + 9 | Normandy Club | 24 | FRA | Richie | Draxler | 2011-02-26 + +(5 rows) +// end::cyclistSelectDateRangeResults[] diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_specific_rider.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_specific_rider.result new file mode 100644 index 0000000000..d2f233359b --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_semi_pro_select_specific_rider.result @@ -0,0 +1,11 @@ +SOURCE '0_create_keyspace.cql'; + +// SELECT * FROM cycling.cyclist_semi_pro WHERE lastname = 'Eppinger'; + +// tag::cyclistSelectSpecificRiderResults[] + id | affiliation | age | country | firstname | lastname | registration +----+-------------------+-----+---------+-----------+----------+-------------- + 12 | Chamonix Hauteurs | 24 | FRA | Charles | Eppinger | 2018-07-29 + +(1 rows) +// end::cyclistSelectSpecificRiderResults[] diff --git a/doc/modules/cassandra/examples/RESULTS/sai/cyclist_team-queries.result b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_team-queries.result new file mode 100644 index 0000000000..c7af8468b3 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/cyclist_team-queries.result @@ -0,0 +1,6 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | Elizabeth | ARMITSTEAD | {2011: 'Team Garmin - Cervelo', 2012: 'AA Drink - Leontien.nl', 2013: 'Boels:Dolmans Cycling Team', 2014: 'Boels:Dolmans Cycling Team', 2015: 'Boels:Dolmans Cycling Team'} + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | Marianne | VOS | {2015: 'Rabobank-Liv Woman Cycling Team'} + +(2 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-bad.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-bad.result new file mode 100644 index 0000000000..e36104e3c0 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-bad.result @@ -0,0 +1,4 @@ + id | created_at | comment | comment_vector | commenter | record_id +----+------------+---------+----------------+-----------+----------- + +(0 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-good.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-good.result new file mode 100644 index 0000000000..6291c888d9 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-case-sensitive-good.result @@ -0,0 +1,5 @@ + comment | commenter +----------------------------------------+----------- + LATE RIDERS SHOULD NOT DELAY THE START | Alex + Second rest stop was out of water | Alex +(2 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-name.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-name.result new file mode 100644 index 0000000000..8b2b10ce3a --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-name.result @@ -0,0 +1,8 @@ + race_year | race_name | rank | cyclist_name +-----------+--------------------------------------------+------+---------------------- + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Daniel MARTIN + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 2 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 3 | Benjamin PRADES + 2015 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Benjamin PRADES + 2015 | Tour of Japan - Stage 4 - Minami > Shinshu | 2 | Adam PHELAN + 2015 | Tour of Japan - Stage 4 - Minami > Shinshu | 3 | Thomas LEBAS \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-year.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-year.result new file mode 100644 index 0000000000..bac756fb94 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-composite-partition-key-race-year.result @@ -0,0 +1,9 @@ + + race_year | race_name | rank | cyclist_name +-----------+--------------------------------------------+------+---------------------- + 2014 | 4th Tour of Beijing | 1 | Phillippe GILBERT + 2014 | 4th Tour of Beijing | 2 | Daniel MARTIN + 2014 | 4th Tour of Beijing | 3 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Daniel MARTIN + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 2 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 3 | Benjamin PRADES \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list-two-columns.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list-two-columns.result new file mode 100644 index 0000000000..fc43d133ef --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list-two-columns.result @@ -0,0 +1,4 @@ + year | month | events +------+-------+----------------------------------------------- + 2015 | 6 | ['Criterium du Dauphine', 'Tour de Sui\nsse'] + 2015 | 7 | ['Tour de France'] \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list.result new file mode 100644 index 0000000000..f8346049f7 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-list.result @@ -0,0 +1,3 @@ + year | month | events +------+-------+----------------------------------------------- + 2015 | 6 | ['Criterium du Dauphine', 'Tour de Sui\nsse'] \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-entries.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-entries.result new file mode 100644 index 0000000000..0e0b8a906b --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-entries.result @@ -0,0 +1,3 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | Elizabeth | ARMITSTEAD | {2011: 'Team Garmin - Cervelo', 2012: 'AA Drink - Leontien.nl', 2013: 'Boels:Dolmans Cycling Team', 2014: 'Boels:Dolmans Cycling Team', 2015: 'Boels:Dolmans Cycling Team'} \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-key.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-key.result new file mode 100644 index 0000000000..2f0a8a2a7e --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-key.result @@ -0,0 +1,4 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | Elizabeth | ARMITSTEAD | {2011: 'Team Garmin - Cervelo', 2012: 'AA Drink - Leontien.nl', 2013: 'Boels:Dolmans Cycling Team', 2014: 'Boels:Dolmans Cycling Team', 2015: 'Boels:Dolmans Cycling Team'} + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | Marianne | VOS | {2014: 'Rabobank-Liv Woman Cycling Team', 2015: 'Rabobank-Liv Woman Cycling Team'} \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-value.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-value.result new file mode 100644 index 0000000000..0e0b8a906b --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-map-value.result @@ -0,0 +1,3 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | Elizabeth | ARMITSTEAD | {2011: 'Team Garmin - Cervelo', 2012: 'AA Drink - Leontien.nl', 2013: 'Boels:Dolmans Cycling Team', 2014: 'Boels:Dolmans Cycling Team', 2015: 'Boels:Dolmans Cycling Team'} \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-set.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-set.result new file mode 100644 index 0000000000..9139dc390e --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-from-set.result @@ -0,0 +1,3 @@ + id | lastname | teams +--------------------------------------+----------+------------------------------------------------------------------------------------------------------ + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | VOS | {'Nederland bloeit', 'Rabobank Women Team', 'Rabobank-Liv Giant', 'Rabobank-Liv Woman Cycling Team'} \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-and.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-and.result new file mode 100644 index 0000000000..b694c68470 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-and.result @@ -0,0 +1,3 @@ + id | created_at | comment | comment_vector | commenter | record_id +--------------------------------------+---------------------------------+-----------------------------------+------------------------------+-----------+-------------------------------------- + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-03-21 21:11:09.999000+0000 | Second rest stop was out of water | [0.99, 0.5, 0.99, 0.1, 0.34] | Alex | 6d0b7b10-272b-11ee-859f-b9098002fcac \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-in.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-in.result new file mode 100644 index 0000000000..c4399017f9 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-in.result @@ -0,0 +1,4 @@ + id | created_at | comment | comment_vector | commenter | record_id +--------------------------------------+---------------------------------+-----------------------------------+------------------------------+-----------+-------------------------------------- + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-03-21 21:11:09.999000+0000 | Second rest stop was out of water | [0.99, 0.5, 0.99, 0.1, 0.34] | Alex | 6d0b7b10-272b-11ee-859f-b9098002fcac + c7fceba0-c141-4207-9494-a29f9809de6f | 2017-03-22 01:16:59.001000+0000 | Great snacks at all reststops | [0.1, 0.4, 0.1, 0.52, 0.09] | Amy | 6d0fc0d0-272b-11ee-859f-b9098002fcac \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-or.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-or.result new file mode 100644 index 0000000000..c4399017f9 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-multiple-index-match-with-or.result @@ -0,0 +1,4 @@ + id | created_at | comment | comment_vector | commenter | record_id +--------------------------------------+---------------------------------+-----------------------------------+------------------------------+-----------+-------------------------------------- + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-03-21 21:11:09.999000+0000 | Second rest stop was out of water | [0.99, 0.5, 0.99, 0.1, 0.34] | Alex | 6d0b7b10-272b-11ee-859f-b9098002fcac + c7fceba0-c141-4207-9494-a29f9809de6f | 2017-03-22 01:16:59.001000+0000 | Great snacks at all reststops | [0.1, 0.4, 0.1, 0.52, 0.09] | Amy | 6d0fc0d0-272b-11ee-859f-b9098002fcac \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match-failure.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match-failure.result new file mode 100644 index 0000000000..65c1b00b63 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match-failure.result @@ -0,0 +1,3 @@ +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" \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match.result new file mode 100644 index 0000000000..8732c96d27 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-single-index-match.result @@ -0,0 +1,4 @@ + id | created_at | comment | comment_vector | commenter | record_id +--------------------------------------+---------------------------------+----------------------------------------+------------------------------+-----------+-------------------------------------- + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-04-01 14:33:02.160000+0000 | LATE RIDERS SHOULD NOT DELAY THE START | [0.9, 0.54, 0.12, 0.1, 0.95] | Alex | 6d0cdaa0-272b-11ee-859f-b9098002fcac + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-03-21 21:11:09.999000+0000 | Second rest stop was out of water | [0.99, 0.5, 0.99, 0.1, 0.34] | Alex | 6d0b7b10-272b-11ee-859f-b9098002fcac \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-udt-match.result b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-udt-match.result new file mode 100644 index 0000000000..ace6c96d55 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/index-sai-select-udt-match.result @@ -0,0 +1,5 @@ + id | firstname | lastname | races +--------------------------------------+-----------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | Marianne | VOS | [{race_title: 'Rabobank 7-Dorpenomloop Aalburg', race_date: '2015-05-09 00:00:00.000000+0000', race_time: '02:58:33'}, {race_title: 'Ronde van Gelderland', race_date: '2015-04-19 00:00:00.000000+0000', race_time: '03:22:23'}] + +(1 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/race_starts-queries.result b/doc/modules/cassandra/examples/RESULTS/sai/race_starts-queries.result new file mode 100644 index 0000000000..4ba948d253 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/race_starts-queries.result @@ -0,0 +1,5 @@ + cyclist_name | rnumbers +----------------+------------- + John DEGENKOLB | [39, 7, 14] + +(1 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/sai-check.result b/doc/modules/cassandra/examples/RESULTS/sai/sai-check.result new file mode 100644 index 0000000000..7396c52b07 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/sai-check.result @@ -0,0 +1 @@ +TBD \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/sai-error.result b/doc/modules/cassandra/examples/RESULTS/sai/sai-error.result new file mode 100644 index 0000000000..56acdc3fc4 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/sai-error.result @@ -0,0 +1 @@ +InvalidRequest: Error from server: code=2200 [Invalid query] message="Cannot create secondary index on the only partition key column id" \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select-vsearch-cycling.result b/doc/modules/cassandra/examples/RESULTS/sai/select-vsearch-cycling.result new file mode 100644 index 0000000000..46f0265c72 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select-vsearch-cycling.result @@ -0,0 +1,5 @@ + id | created_at | comment | comment_vector | commenter | record_id +--------------------------------------+---------------------------------+----------------------------------------+------------------------------+-----------+-------------------------------------- + e7ae5cf3-d358-4d99-b900-85902fda9bb0 | 2017-04-01 14:33:02.160000+0000 | LATE RIDERS SHOULD NOT DELAY THE START | [0.9, 0.54, 0.12, 0.1, 0.95] | Alex | 616e77e0-22a2-11ee-b99d-1f350647414a + c7fceba0-c141-4207-9494-a29f9809de6f | 2017-02-17 08:43:20.234000+0000 | Glad you ran the race in the rain | [0.3, 0.34, 0.2, 0.78, 0.25] | Amy | 6170c1d0-22a2-11ee-b99d-1f350647414a + c7fceba0-c141-4207-9494-a29f9809de6f | 2017-04-01 13:43:08.030000+0000 | Last climb was a killer | [0.3, 0.75, 0.2, 0.2, 0.5] | Amy | 62105d30-22a2-11ee-b99d-1f350647414a \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams-team.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams-team.result new file mode 100644 index 0000000000..b6507484e6 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams-team.result @@ -0,0 +1,7 @@ + id | lastname | teams +--------------------------------------+-----------------+------------------------------------------------------------------------------------------------------ + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | VOS | {'Nederland bloeit', 'Rabobank Women Team', 'Rabobank-Liv Giant', 'Rabobank-Liv Woman Cycling Team'} + 1c9ebc13-1eab-4ad5-be87-dce433216d40 | BRAND | {'AA Drink - Leontien.nl', 'Leontien.nl', 'Rabobank-Liv Giant', 'Rabobank-Liv Woman Cycling Team'} + e7cd5752-bc0d-4157-a80f-7523add8dbcd | VAN DER BREGGEN | {'Rabobank-Liv Woman Cycling Team', 'Sengers Ladies Cycling Team', 'Team Flexpoint'} + +(3 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams.result new file mode 100644 index 0000000000..d4e0c42e12 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams.result @@ -0,0 +1,13 @@ + id | lastname | teams +--------------------------------------+-----------------+-------------------------------------------------------------------------------- +---------------------- + cb07baad-eac8-4f65-b28a-bddc06a0de23 | ARMITSTEAD | {'AA Drink - Leontien.nl', 'Boels-Dolmans Cycling Team', 'Te +am Garmin - Cervelo'} + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | VOS | {'Nederland bloeit', 'Rabobank Women Team', 'Rabobank-Liv Giant', 'Rabobank-Liv + Woman Cycling Team'} + 1c9ebc13-1eab-4ad5-be87-dce433216d40 | BRAND | {'AA Drink - Leontien.nl', 'Leontien.nl', 'Rabobank-Liv Giant', 'Rabobank-Liv + Woman Cycling Team'} + e7cd5752-bc0d-4157-a80f-7523add8dbcd | VAN DER BREGGEN | {'Rabobank-Liv Woman Cycling Team', 'Sengers Ladies Cycling Tea +m', 'Team Flexpoint'} + +(4 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams_contains_value.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams_contains_value.result new file mode 100644 index 0000000000..3bbd73e8a0 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_career_teams_contains_value.result @@ -0,0 +1,7 @@ + id | lastname | teams +--------------------------------------+----------+----------------------------------------------------------------------------- +----------------------- + 1c9ebc13-1eab-4ad5-be87-dce433216d40 | BRAND | {'AA Drink - Leontien.nl', 'Leontien.nl', 'Rabobank-Liv Giant', 'Rabobank-Li +v Woman Cycling Team'} + +(1 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_teams.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_teams.result new file mode 100644 index 0000000000..119a6b98b4 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_cyclist_teams.result @@ -0,0 +1,7 @@ + id | firstname | lastname | teams +--------------------------------------+-----------+----------+--------------------------------------------------------------------------- +--------- + 5b6962dd-3f90-4c93-8f61-eabfa4a803e2 | Marianne | VOS | {2014: 'Rabobank-Liv Woman Cycling Team', 2015: 'Rabobank-Liv Woman Cyclin +g Team'} + +(1 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name-rank.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name-rank.result new file mode 100644 index 0000000000..1da98769ab --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name-rank.result @@ -0,0 +1,8 @@ + race_year | race_name | rank | cyclist_name +-----------+--------------------------------------------+------+------------------- + 2014 | 4th Tour of Beijing | 1 | Phillippe GILBERT + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Daniel MARTIN + 2015 | Giro d'Italia - Stage 11 - Forli > Imola | 1 | Ilnur ZAKARIN + 2015 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Benjamin PRADES + +(4 rows) \ No newline at end of file diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_2014.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_2014.result new file mode 100644 index 0000000000..329043c217 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_2014.result @@ -0,0 +1,10 @@ + race_year | race_name | rank | cyclist_name +-----------+--------------------------------------------+------+---------------------- + 2014 | 4th Tour of Beijing | 1 | Phillippe GILBERT + 2014 | 4th Tour of Beijing | 2 | Daniel MARTIN + 2014 | 4th Tour of Beijing | 3 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Daniel MARTIN + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 2 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 3 | Benjamin PRADES + +(6 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_Japan_2014.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_Japan_2014.result new file mode 100644 index 0000000000..2ca1d9802a --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_rank_by_year_and_name_Japan_2014.result @@ -0,0 +1,7 @@ + race_year | race_name | rank | cyclist_name +-----------+--------------------------------------------+------+---------------------- + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 1 | Daniel MARTIN + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 2 | Johan Esteban CHAVES + 2014 | Tour of Japan - Stage 4 - Minami > Shinshu | 3 | Benjamin PRADES + +(3 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_upcoming_calendar.result b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_upcoming_calendar.result new file mode 100644 index 0000000000..f33bf6d231 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_all_from_upcoming_calendar.result @@ -0,0 +1,6 @@ + year | month | events +------+-------+--------------------------------------------- + 2015 | 6 | ['Criterium du Dauphine', 'Tour de Suisse'] + 2015 | 7 | ['Tour de France'] + +(2 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_age_23.result b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_age_23.result new file mode 100644 index 0000000000..4ca7426890 --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_age_23.result @@ -0,0 +1,6 @@ + cyclist_name | blist +------------------+---------------------------------------------------------- + Claudio HEINEN | {'age': '23', 'bday': '27/07/1992', 'nation': 'GERMANY'} + Laurence BOURQUE | {'age': '23', 'bday': '27/07/1992', 'nation': 'CANADA'} + +(2 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result new file mode 100644 index 0000000000..587219de8f --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result @@ -0,0 +1,6 @@ + cyclist_name | blist +---------------+-------------------------------------------------------------- + Luc HAGENAARS | {'age': '28', 'bday': '27/07/1987', 'nation': 'NETHERLANDS'} + Toine POELS | {'age': '52', 'bday': '27/07/1963', 'nation': 'NETHERLANDS'} + +(2 rows) diff --git a/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result new file mode 100644 index 0000000000..587219de8f --- /dev/null +++ b/doc/modules/cassandra/examples/RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result @@ -0,0 +1,6 @@ + cyclist_name | blist +---------------+-------------------------------------------------------------- + Luc HAGENAARS | {'age': '28', 'bday': '27/07/1987', 'nation': 'NETHERLANDS'} + Toine POELS | {'age': '52', 'bday': '27/07/1963', 'nation': 'NETHERLANDS'} + +(2 rows) diff --git a/doc/modules/cassandra/nav.adoc b/doc/modules/cassandra/nav.adoc index 48419bbbe2..bacf5073db 100644 --- a/doc/modules/cassandra/nav.adoc +++ b/doc/modules/cassandra/nav.adoc @@ -1,104 +1,114 @@ * Cassandra -** xref:cassandra:new/index.adoc[] -** xref:cassandra:overview/index.adoc[] -*** xref:cassandra:overview/terminology.adoc[] -*** xref:cassandra:overview/faq/index.adoc[] -** xref:cassandra:getting-started/index.adoc[] + +** xref:cassandra:overview/faq/index.adoc[] + +** xref:cassandra:getting-started/index.adoc[] +*** xref:cassandra:getting-started/cassandra-quickstart.adoc[] +*** xref:cassandra:getting-started/sai-quickstart.adoc[] *** xref:cassandra:installing/installing.adoc[] *** xref:cassandra:getting-started/configuring.adoc[] *** xref:cassandra:getting-started/querying.adoc[] *** xref:cassandra:getting-started/drivers.adoc[] -*** xref:cassandra:getting-started/java11.adoc[] + *** xref:cassandra:getting-started/production.adoc[] + +** xref:cassandra:new/index.adoc[] +*** xref:cassandra:reference/java17.adoc[] + ** xref:cassandra:architecture/index.adoc[] *** xref:cassandra:architecture/overview.adoc[] -*** xref:cassandra:architecture/dynamo.adoc[] +*** xref:cassandra:architecture/dynamo.adoc[] *** xref:cassandra:architecture/storage-engine.adoc[] *** xref:cassandra:architecture/guarantees.adoc[] *** xref:cassandra:architecture/messaging.adoc[] *** xref:cassandra:architecture/streaming.adoc[] -** xref:cassandra:installing/installing.adoc[] -** xref:cassandra:developing/index.adoc[] -*** xref:cassandra:developing/data-modeling/index.adoc[] -**** xref:cassandra:developing/data-modeling/intro.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_conceptual.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_rdbms.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_queries.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_logical.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_physical.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_refining.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_schema.adoc[] -**** xref:cassandra:developing/data-modeling/data-modeling_tools.adoc[] -*** xref:cassandra:developing/cql/index.adoc[] -**** xref:cassandra:developing/cql/definitions.adoc[] -**** xref:cassandra:developing/cql/types.adoc[] -**** xref:cassandra:developing/cql/ddl.adoc[] -**** xref:cassandra:developing/cql/dml.adoc[] -**** xref:cassandra:developing/cql/operators.adoc[] -**** xref:cassandra:developing/cql/indexes.adoc[] -**** xref:cassandra:developing/cql/mvs.adoc[] -**** xref:cassandra:developing/cql/functions.adoc[] -**** xref:cassandra:developing/cql/json.adoc[] -**** xref:cassandra:developing/cql/security.adoc[] -**** xref:cassandra:developing/cql/triggers.adoc[] -**** xref:cassandra:developing/cql/appendices.adoc[] -**** xref:cassandra:developing/cql/changes.adoc[] -**** xref:cassandra:developing/cql/SASI.adoc[SASI] -**** xref:cassandra:developing/cql/cql_singlefile.adoc[] -** xref:cassandra:integrating/plugins/index.adoc[Plug-ins] -** xref:cassandra:managing/index.adoc[] -*** xref:cassandra:managing/configuration/index.adoc[] -**** xref:cassandra:managing/configuration/cass_yaml_file.adoc[] -**** xref:cassandra:managing/configuration/cass_rackdc_file.adoc[] -**** xref:cassandra:managing/configuration/cass_env_sh_file.adoc[] -**** xref:cassandra:managing/configuration/cass_topo_file.adoc[] -**** xref:cassandra:managing/configuration/cass_cl_archive_file.adoc[] -**** xref:cassandra:managing/configuration/cass_logback_xml_file.adoc[] -**** xref:cassandra:managing/configuration/cass_jvm_options_file.adoc[] -**** xref:cassandra:managing/configuration/configuration.adoc[] -*** xref:cassandra:managing/operating/index.adoc[] -**** xref:cassandra:managing/operating/snitch.adoc[] -**** xref:cassandra:managing/operating/topo_changes.adoc[] -**** xref:cassandra:managing/operating/repair.adoc[] -**** xref:cassandra:managing/operating/read_repair.adoc[] -**** xref:cassandra:managing/operating/hints.adoc[] -**** xref:cassandra:managing/operating/bloom_filters.adoc[] -**** xref:cassandra:managing/operating/compression.adoc[] -**** xref:cassandra:managing/operating/cdc.adoc[] -**** xref:cassandra:managing/operating/backups.adoc[] -**** xref:cassandra:managing/operating/bulk_loading.adoc[] -**** xref:cassandra:managing/operating/metrics.adoc[] -**** xref:cassandra:managing/operating/security.adoc[] -**** xref:cassandra:managing/operating/hardware.adoc[] -**** xref:cassandra:managing/operating/compaction/index.adoc[] -**** xref:cassandra:managing/operating/virtualtables.adoc[] -**** xref:cassandra:managing/operating/auditlogging.adoc[] -**** xref:cassandra:managing/operating/audit_logging.adoc[] -**** xref:cassandra:managing/operating/fqllogging.adoc[] -**** xref:cassandra:managing/operating/transientreplication.adoc[] -*** xref:cassandra:managing/tools/index.adoc[] -**** xref:cassandra:managing/tools/cqlsh.adoc[] -**** xref:cassandra:managing/tools/nodetool/nodetool.adoc[] -**** xref:cassandra:managing/tools/sstable/index.adoc[] -** xref:cassandra:tooling/index.adoc[] -*** xref:cassandra:tooling/hash-password.adoc[] -*** xref:cassandra:tooling/generate-tokens.adoc[] -*** xref:cassandra:tooling/cassandra-stress.adoc[] -** xref:cassandra:troubleshooting/index.adoc[] -*** xref:cassandra:troubleshooting/finding_nodes.adoc[] -*** xref:cassandra:troubleshooting/reading_logs.adoc[] -*** xref:cassandra:troubleshooting/use_nodetool.adoc[] -*** xref:cassandra:troubleshooting/use_tools.adoc[] -** xref:master@_:ROOT:development/index.adoc[Development] -*** xref:master@_:ROOT:development/gettingstarted.adoc[Getting started] -*** xref:master@_:ROOT:development/ide.adoc[Building and IDE integration] -*** xref:master@_:ROOT:development/testing.adoc[Testing] -*** xref:master@_:ROOT:development/patches.adoc[Contributing code changes] -*** xref:master@_:ROOT:development/code_style.adoc[Code style] -*** xref:master@_:ROOT:development/how_to_review.adoc[Review checklist] -*** xref:master@_:ROOT:development/how_to_commit.adoc[How to commit] -*** xref:master@_:ROOT:development/documentation.adoc[Working on documentation] -*** xref:master@_:ROOT:development/ci.adoc[Jenkins CI environment] -*** xref:master@_:ROOT:development/dependencies.adoc[Dependency management] -*** xref:master@_:ROOT:development/release_process.adoc[Release process] \ No newline at end of file +** xref:cassandra:developing/data-modeling/index.adoc[] +*** xref:cassandra:developing/data-modeling/intro.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_conceptual.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_rdbms.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_queries.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_logical.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_physical.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_refining.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_schema.adoc[] +*** xref:cassandra:developing/data-modeling/data-modeling_tools.adoc[] + +** xref:cassandra:developing/cql/index.adoc[Cassandra Query Language (CQL)] +*** xref:cassandra:developing/cql/definitions.adoc[Definitions] +*** xref:cassandra:developing/cql/types.adoc[Data types] +*** xref:cassandra:developing/cql/ddl.adoc[Data definition (DDL)] +*** xref:cassandra:developing/cql/dml.adoc[Data manipulation (DML)] +*** xref:cassandra:developing/cql/operators.adoc[Operators] +*** xref:cassandra:developing/cql/indexing/indexing-concepts.adoc[] +// SAI +**** xref:cassandra:developing/cql/indexing/sai/sai-overview.adoc[] +***** xref:cassandra:developing/cql/indexing/sai/sai-concepts.adoc[] +***** xref:cassandra:getting-started/sai-quickstart.adoc[] +***** xref:cassandra:developing/cql/indexing/sai/sai-faq.adoc[] +***** xref:cassandra:developing/cql/indexing/sai/sai-working-with.adoc[] +***** xref:cassandra:developing/cql/indexing/sai/operations/sai-operations.adoc[] +// 2i +**** xref:cassandra:developing/cql/indexing/2i/2i-overview.adoc[] +***** xref:cassandra:developing/cql/indexing/2i/2i-concepts.adoc[] +***** xref:cassandra:developing/cql/indexing/2i/2i-working-with.adoc[] +***** xref:cassandra:developing/cql/indexing/2i/operations/2i-build.adoc[] +*** xref:cassandra:developing/cql/mvs.adoc[Materialized views] +*** xref:cassandra:developing/cql/functions.adoc[Functions] +*** xref:cassandra:developing/cql/json.adoc[JSON] +*** xref:cassandra:developing/cql/security.adoc[Security] +*** xref:cassandra:developing/cql/triggers.adoc[Triggers] +*** xref:cassandra:developing/cql/appendices.adoc[Appendices] +*** xref:cassandra:developing/cql/changes.adoc[Changes] +*** xref:cassandra:developing/cql/SASI.adoc[SASI] +*** xref:cassandra:developing/cql/cql_singlefile.adoc[Single file of CQL information] +.Managing +** xref:cassandra:managing/configuration/index.adoc[Configuration] +*** xref:cassandra:managing/configuration/cass_yaml_file.adoc[cassandra.yaml] +*** xref:cassandra:managing/configuration/cass_rackdc_file.adoc[cassandra-rackdc.properties] +*** xref:cassandra:managing/configuration/cass_env_sh_file.adoc[cassandra-env.sh] +*** xref:cassandra:managing/configuration/cass_topo_file.adoc[cassandra-topologies.properties] +*** xref:cassandra:managing/configuration/cass_cl_archive_file.adoc[commitlog-archiving.properties] +*** xref:cassandra:managing/configuration/cass_logback_xml_file.adoc[logback.xml] +*** xref:cassandra:managing/configuration/cass_jvm_options_file.adoc[jvm-* files] +*** xref:cassandra:managing/configuration/configuration.adoc[Liberating cassandra.yaml Parameters' Names from Their Units] +** xref:cassandra:managing/operating/index.adoc[Operating] +*** xref:cassandra:managing/operating/snitch.adoc[Snitches] +*** xref:cassandra:managing/operating/topo_changes.adoc[Topology changes] +*** xref:cassandra:managing/operating/repair.adoc[Repair] +*** xref:cassandra:managing/operating/read_repair.adoc[Read repair] +*** xref:cassandra:managing/operating/hints.adoc[Hints] +*** xref:cassandra:managing/operating/bloom_filters.adoc[Bloom filters] +*** xref:cassandra:managing/operating/compression.adoc[Compression] +*** xref:cassandra:managing/operating/cdc.adoc[Change Data Capture (CDC)] +*** xref:cassandra:managing/operating/backups.adoc[Backups] +*** xref:cassandra:managing/operating/bulk_loading.adoc[Bulk loading] +*** xref:cassandra:managing/operating/metrics.adoc[Metrics] +*** xref:cassandra:managing/operating/security.adoc[Security] +*** xref:cassandra:managing/operating/hardware.adoc[Hardware] +*** xref:cassandra:managing/operating/compaction/index.adoc[Compaction] +*** xref:cassandra:managing/operating/virtualtables.adoc[Virtual tables] +*** xref:cassandra:managing/operating/auditlogging.adoc[Audit logging] +*** xref:cassandra:managing/operating/audit_logging.adoc[Audit logging 2] +*** xref:cassandra:managing/operating/fqllogging.adoc[Full query logging] +*** xref:cassandra:managing/operating/transientreplication.adoc[Transient replication] + +** xref:cassandra:managing/tools/index.adoc[Tools] +*** xref:cassandra:managing/tools/cqlsh.adoc[cqlsh: the CQL shell] +*** xref:cassandra:managing/tools/nodetool/nodetool.adoc[nodetool] +*** xref:cassandra:managing/tools/sstable/index.adoc[SSTable tools] +*** xref:cassandra:managing/tools/cassandra_stress.adoc[cassandra-stress] + +** xref:cassandra:troubleshooting/index.adoc[Troubleshooting] +*** xref:cassandra:troubleshooting/finding_nodes.adoc[Finding misbehaving nodes] +*** xref:cassandra:troubleshooting/reading_logs.adoc[Reading Cassandra logs] +*** xref:cassandra:troubleshooting/use_nodetool.adoc[Using nodetool] +*** xref:cassandra:troubleshooting/use_tools.adoc[Using external tools to deep-dive] + +** xref:cassandra:reference/index.adoc[Reference] +*** xref:cassandra:reference/cql-commands/commands-toc.adoc[] +**** xref:cassandra:reference/cql-commands/create-custom-index.adoc[] +**** xref:cassandra:reference/cql-commands/create-index.adoc[] +**** xref:cassandra:reference/cql-commands/drop-index.adoc[] + +** xref:cassandra:integrating/plugins/index.adoc[] diff --git a/doc/modules/cassandra/pages/developing/cql/SASI.adoc b/doc/modules/cassandra/pages/developing/cql/SASI.adoc index c24009ad24..705cf1d337 100644 --- a/doc/modules/cassandra/pages/developing/cql/SASI.adoc +++ b/doc/modules/cassandra/pages/developing/cql/SASI.adoc @@ -1,15 +1,15 @@ -== SASIIndex +== SASI Index https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/SASIIndex.java[`SASIIndex`], or ``SASI`` for short, is an implementation of Cassandra's `Index` interface that can be used as an alternative to the existing implementations. SASI's indexing and querying improves on existing -implementations by tailoring it specifically to Cassandra’s needs. SASI +implementations by tailoring it specifically to Cassandra's needs. SASI has superior performance in cases where queries would previously require filtering. In achieving this performance, SASI aims to be significantly less resource intensive than existing implementations, in memory, disk, and CPU usage. In addition, SASI supports prefix and contains queries on -strings (similar to SQL’s `LIKE = "foo*"` or `LIKE = "*foo*"'`). +strings (similar to SQL's `LIKE = "foo*"` or `LIKE = "*foo*"'`). The following goes on describe how to get up and running with SASI, demonstrates usage with examples, and provides some details on its @@ -77,7 +77,7 @@ the default `PREFIX` mode and no case-sensitivity or text analysis options are specified since the field is numeric. After inserting the following data and performing a `nodetool flush`, -SASI performing index flushes to disk can be seen in Cassandra’s logs – +SASI performing index flushes to disk can be seen in Cassandra's logs – although the direct call to flush is not required (see link:#indexmemtable[IndexMemtable] for more details). @@ -350,12 +350,12 @@ cqlsh:demo> SELECT * FROM sasi WHERE bio LIKE 'soft eng'; While SASI, at the surface, is simply an implementation of the `Index` interface, at its core there are several data structures and algorithms used to satisfy it. These are described here. Additionally, the changes -internal to Cassandra to support SASI’s integration are described. +internal to Cassandra to support SASI's integration are described. The `Index` interface divides responsibility of the implementer into two parts: Indexing and Querying. Further, Cassandra makes it possible to divide those responsibilities into the memory and disk components. SASI -takes advantage of Cassandra’s write-once, immutable, ordered data model +takes advantage of Cassandra's write-once, immutable, ordered data model to build indexes along with the flushing of the memtable to disk – this is the origin of the name ``SSTable Attached Secondary Index''. @@ -366,7 +366,7 @@ sequential writes to disk. In some cases, partial flushes are performed, and later stitched back together, to reduce memory usage. These data structures are optimized for this use case. -Taking advantage of Cassandra’s ordered data model, at query time, +Taking advantage of Cassandra's ordered data model, at query time, candidate indexes are narrowed down for searching, minimizing the amount of work done. Searching is then performed using an efficient method that streams data off disk as needed. @@ -400,7 +400,7 @@ https://en.wikipedia.org/wiki/Suffix_array[Suffix Array] data structure. The https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/disk/OnDiskIndex.java[`OnDiskIndex`] is comprised of page-size blocks of sorted terms and pointers to the -terms’ associated data, as well as the data itself, stored also in one +terms' associated data, as well as the data itself, stored also in one or more page-sized blocks. The https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/disk/OnDiskIndex.java[`OnDiskIndex`] is structured as a tree of arrays, where each level describes the terms @@ -414,7 +414,7 @@ https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/ind The terms written to the https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/disk/OnDiskIndex.java[`OnDiskIndex`] vary depending on its ``mode'': either `PREFIX`, `CONTAINS`, or -`SPARSE`. In the `PREFIX` and `SPARSE` cases, terms’ exact values are +`SPARSE`. In the `PREFIX` and `SPARSE` cases, terms' exact values are written exactly once per `OnDiskIndex`. For example, when using a `PREFIX` index with terms `Jason`, `Jordan`, `Pavel`, all three will be included in the index. A `CONTAINS` index writes additional terms for @@ -491,17 +491,17 @@ is built on top of `java.util.concurrent.ConcurrentSkipListSet`. ==== Querying Responsible for converting the internal `IndexExpression` representation -into SASI’s +into SASI's https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/Operation.java[`Operation`] and https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/Expression.java[`Expression`] trees, optimizing the trees to reduce the amount of work done, and driving the query itself, the https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryPlan.java[`QueryPlan`] -is the work horse of SASI’s querying implementation. To efficiently +is the work horse of SASI's querying implementation. To efficiently perform union and intersection operations, SASI provides several -iterators similar to Cassandra’s `MergeIterator`, but tailored -specifically for SASI’s use while including more features. The +iterators similar to Cassandra's `MergeIterator`, but tailored +specifically for SASI's use while including more features. The https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/utils/RangeUnionIterator.java[`RangeUnionIterator`], like its name suggests, performs set unions over sets of tokens/keys matching the query, only reading as much data as it needs from each set @@ -513,13 +513,13 @@ similar to its counterpart, performs set intersections over its data. The https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryPlan.java[`QueryPlan`] -instantiated per search query is at the core of SASI’s querying +instantiated per search query is at the core of SASI's querying implementation. Its work can be divided in two stages: analysis and execution. During the analysis phase, https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryPlan.java[`QueryPlan`] -converts from Cassandra’s internal representation of `IndexExpression`s, +converts from Cassandra's internal representation of `IndexExpression`s, which has also been modified to support encoding queries that contain ORs and groupings of expressions using parentheses (see the link:#cassandra-internal-changes[Cassandra Internal Changes] section @@ -563,7 +563,7 @@ specified by the user via the range slice timeout. All indexes are accessed via the https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryController.java[`QueryController`] so that they can be safely released by it later. The -https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryController.java[`QueryController`]’s +https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryController.java[`QueryController`]'s `checkpoint` function is called in specific places in the execution path to ensure the time-bound is enforced. @@ -766,9 +766,9 @@ https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/ind components, controls writing of all indexes for an SSTable via its https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/disk/PerSSTableIndexWriter.java[`PerSSTableIndexWriter`], and initiates searches with `Searcher`. These classes glue the -previously mentioned indexing components together with Cassandra’s -SSTable life-cycle ensuring indexes are not only written when Memtable’s -flush, but also as SSTable’s are compacted. For querying, the `Searcher` +previously mentioned indexing components together with Cassandra's +SSTable life-cycle ensuring indexes are not only written when Memtable's +flush, but also as SSTable's are compacted. For querying, the `Searcher` does little but defer to https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/plan/QueryPlan.java[`QueryPlan`] and update e.g. latency metrics exposed by SASI. @@ -785,7 +785,7 @@ The `SSTableFlushObserver` is an observer pattern-like interface, whose sub-classes can register to be notified about events in the life-cycle of writing out a SSTable. Sub-classes can be notified when a flush begins and ends, as well as when each next row is about to be written, -and each next column. SASI’s `PerSSTableIndexWriter`, discussed above, +and each next column. SASI's `PerSSTableIndexWriter`, discussed above, is the only current subclass. ==== Limitations and Caveats @@ -795,7 +795,7 @@ not available in this repository or are not currently implemented. * The cluster must be configured to use a partitioner that produces `LongToken`s, e.g. `Murmur3Partitioner`. Other existing partitioners -which don’t produce LongToken e.g. `ByteOrderedPartitioner` and +which don't produce LongToken e.g. `ByteOrderedPartitioner` and `RandomPartitioner` will not work with SASI. * Not Equals and OR support have been removed in this release while changes are made to Cassandra itself to support them. diff --git a/doc/modules/cassandra/pages/developing/cql/appendices.adoc b/doc/modules/cassandra/pages/developing/cql/appendices.adoc index 28b113bb1d..895dcf9e5e 100644 --- a/doc/modules/cassandra/pages/developing/cql/appendices.adoc +++ b/doc/modules/cassandra/pages/developing/cql/appendices.adoc @@ -8,7 +8,7 @@ Reserved keywords cannot be used as identifier, they are truly reserved for the language (but one can enclose a reserved keyword by double-quotes to use it as an identifier). Non-reserved keywords however only have a specific meaning in certain context but can used as -identifier otherwise. The only _raison d’être_ of these non-reserved +identifier otherwise. The only _raison d'être_ of these non-reserved keywords is convenience: some keyword are non-reserved when it was always easy for the parser to decide whether they were used as keywords or not. diff --git a/doc/modules/cassandra/pages/developing/cql/collections/collection-create.adoc b/doc/modules/cassandra/pages/developing/cql/collections/collection-create.adoc new file mode 100644 index 0000000000..1dff7cf3c0 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/collections/collection-create.adoc @@ -0,0 +1,45 @@ += Creating collections +:description: Collection types provide a way to group and store data together in a table column. + +CQL defines the following collection data types: + +* xref:developing/cql/collections/set.adoc[set: store unordered items] +* xref:developing/cql/collections/list.adoc[list: store ordered items] +* xref:developing/cql/collections/map.adoc[map: store key-value pairs] + +Collections are intended for insertion and retrieval as a collection. +Thus, {product} reads collections in their entirety, and can affect retrieval performance. +A good rule of thumb is that sets are more performant than lists, so use a set if you can. +Collections should be smaller than the following maximum size to prevent querying delays. + +// DISCUSS FROZEN VS NON-FROZEN!!! + +Guard rails for non-frozen collections: + +* No more than 2 billion items in a collection. +* Maximum size of an item in a `set` is 65,535 bytes. +* Maximum size of an item in a `list` or `map` is 2 GB. +* Maximum number of keys in a `map` is 65,535. +* Lists can incur a read-before-write operation for some insertions. + +[IMPORTANT] +==== +Collections are not paged internally. +==== + +Collections cannot be _sliced_; + + +[NOTE] +==== +The limits specified for collections are for non-frozen collections. +==== + +// You can xref:developing/cql/deleting/data-expire-with-ttl.adoc[expire each element] of a collection by setting an individual time-to-live (TTL) property. + +// Also, see xref:reference:collection-type.adoc#using-frozen-in-collection[Using frozen in a collection]. + +''' + +// xref:reference:collection-type.adoc[Freezing collection types] :: +// A collection column is declared using the collection type, followed by another type. diff --git a/doc/modules/cassandra/pages/developing/cql/collections/collections-overview.adoc b/doc/modules/cassandra/pages/developing/cql/collections/collections-overview.adoc new file mode 100644 index 0000000000..736949268d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/collections/collections-overview.adoc @@ -0,0 +1,20 @@ += Collection data types overview + +{product} provides collection data types as a way to group and store data together in a column. +For example, in a relational database, a grouping such as a user's multiple email addresses is related with a many-to-one joined relationship between a user table and an email table. + +{product} avoids joins between two tables by storing the user's email addresses in a collection column in the user table. +Each collection specifies the data type of the data held. + +A collection is appropriate if the data for collection storage is limited. +If the data has unbounded growth potential, like messages sent or sensor events registered every second, do not use collections. +Instead, use a table with a xref:developing/cql/table-create.adoc[compound primary key] where data is stored in the clustering columns. + +// The following example illustrates each collection type, but is not designed for an actual query: + +// ---- +// CREATE TABLE cycling.whimsey ( id UUID PRIMARY KEY, lastname text, cyclist_teams set, events list, teams map ); +// ---- +// Collection types cannot be nested. +// Collections can include frozen data types. +// For examples and usage, see xref:reference:collection-type.adoc[Freezing collection types]. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/collections/list.adoc b/doc/modules/cassandra/pages/developing/cql/collections/list.adoc new file mode 100644 index 0000000000..bf792053cc --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/collections/list.adoc @@ -0,0 +1,39 @@ += Using list type +:description: Use a list when the order of elements matter or when you need to store same value multiple times. + +A `list` is similar to a `set`; it groups and stores values. +Unlike a `set`, the values stored in a `list` do not need to be unique and can be duplicated. +In addition, a `list` stores the elements in a particular order and may be inserted or retrieved according to an index value. + +Use the `list` data type to store data that has a possible many-to-many relationship with another column. + +== Prerequisite + +* xref:developing/cql/keyspace-check.adoc[Keyspace] must exist + + In the following example, a `list` called `events` stores all the race events on an upcoming calendar. + The table is called `upcoming_calendar`. + Each event listed in the `list` will have a `text` data type. +Events can have several events occurring in a particular month and year, so duplicates can occur. +The `list` can be ordered so that the races appear in the order that they will take place, rather than alphabetical order. + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/upcoming_calendar-table.cql[tag=listColumn] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_all_from_upcoming_calendar.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/collections/map.adoc b/doc/modules/cassandra/pages/developing/cql/collections/map.adoc new file mode 100644 index 0000000000..f3ce072bf2 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/collections/map.adoc @@ -0,0 +1,39 @@ += Using map type +:description: Use a map when pairs of related elements must be stored as a key-value pair. + +A map relates one item to another with a key-value pair. +For each key, only one value may exist, and duplicates cannot be stored. +Both the key and the value are designated with a data type. + +Using the map type, you can store timestamp-related information in user profiles. +Each element of the map is internally stored as a single column that you can modify, replace, delete, and query. +Each element can have an individual time-to-live and expire when the TTL ends. + +== Prerequisite + +* xref:developing/cql/keyspace-check.adoc[Keyspace] must exist + +In the following example, each team listed in the `map` called `teams` will have a `year` of integer type and a `team name` of text type. +The table is named `cyclist_teams`. +The map collection is specified with a map column name and the pair of data types enclosed in angle brackets. + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=mapColumn] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_all_from_cyclist_teams.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/collections/set.adoc b/doc/modules/cassandra/pages/developing/cql/collections/set.adoc new file mode 100644 index 0000000000..4834c8f21a --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/collections/set.adoc @@ -0,0 +1,38 @@ += `set` column +:description: Use the set data type to store unordered multiple items. + +A `set` consists of a unordered group of elements with unique values. +Duplicate values will not be stored distinctly. +The values of a `set` are stored unordered, but will return the elements in sorted order when queried. +Use the `set` data type to store data that has a many-to-one relationship with another column. + +== Prerequisite + +* xref:developing/cql/keyspace-check.adoc[Keyspace] must exist + +In the following example, a `set` called `teams` stores all the teams that a cyclist has been a member of during their career. +The table is `cyclist_career_teams`. +Each team listed in the `set` will have a `text` data type. + +The following example shows the table and the initial rows. + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=setColumn] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_all_from_cyclist_career_teams.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/create-custom-index.adoc b/doc/modules/cassandra/pages/developing/cql/create-custom-index.adoc new file mode 100644 index 0000000000..d1b5fda6b6 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/create-custom-index.adoc @@ -0,0 +1,430 @@ += CREATE CUSTOM INDEX +:description: Creates a storage-attached index (SAI). + +include::cassandra:partial$sai/support-databases.adoc[] + +Creates a Storage-Attached Indexing (SAI) index. +You can create multiple secondary indexes on the same database table, with each SAI index based on any column in the table. +All column date types except the following are supported for SAI indexes: + +* `counter` +* geospatial types: `PointType`, `LineStringType`, `PolygonType` +* non-frozen user-defined type (UDT) + +.One exception +**** +You cannot define an SAI index based on the partition key when it's comprised of only one column. +If you attempt to create an SAI index in this case, SAI issues an error message. +**** + +However,you can define an SAI index on one of the columns in a table's composite partition key, i.e., a partition key comprised of multiple columns. +If you need to query based on one of those columns, an SAI index is a helpful option. In fact, you can define an SAI index on each column in a composite partition key, if needed. + +Defining one or more SAI indexes based on any column in a database table (with the rules noted above) subsequently gives you the ability to run performant queries that use the indexed column to filter results. + +See the xref:cassandra:developing/cql/indexing/sai/sai-overview.adoc[SAI section]. + +== Synopsis + +// tag::syntax[] +---- +CREATE CUSTOM INDEX [ IF NOT EXISTS ] [ ] + ON [ .] () + | [ (KEYS()) ] + | [ (VALUES()) ] + | [ (ENTRIES()) ] + USING 'StorageAttachedIndex' + [ WITH OPTIONS = { } ] ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include::cassandra:partial$cql-syntax-legend.adoc[] +==== + +index_name:: +Optional identifier for index. +If no name is specified, the default is used, `__idx`. +Enclose in quotes to use special characters or to preserve capitalization. + +column_name:: +The name of the table column on which the SAI index is being defined. +SAI allows only alphanumeric characters and underscores in names. +SAI returns `InvalidRequestException` if you try to define an index on a column name that contains other characters, and does not create the index. + +map_name:: +Used with xref:cassandra:developing/collections/collection-create.adoc[collections], identifier of the `map_name` specified in `CREATE TABLE` ... +`map()`. +The regular column syntax applies for collection types `list` and `set`. + +option_map:: +Define options in JSON simple format. ++ +[cols="100,223"] +|=== +| Option | Description + +| `case_sensitive` +| Ignore case in matching string values. +Default: `true`. +| `normalize` +| When set to `true`, perform https://unicode.org/faq/normalization.html[Unicode normalization] on indexed strings. +SAI supports Normalization Form C (NFC) Unicode. +When set to `true`, SAI normalizes the different versions of a given Unicode character to a single version, retaining all the marks and symbols in the index. +For example, SAI would change the character Å (U+212B) to Å (U+00C5). + +When implementations keep strings in a normalized form, equivalent strings have a unique binary representation. +See https://unicode.org/reports/tr15/[Unicode Standard Annex #15, Unicode Normalization Forms]. + +Default: `false`. + +| `ascii` +| When set to `true`, SAI converts alphabetic, numeric, and symbolic characters that are not in the Basic Latin Unicode block (the first 127 ASCII characters) to the ASCII equivalent, if one exists. +For example, this option changes à to a. +Default: `false`. +ifeval::["{evalproduct}" == "astra"] +| similarity_function +| Vector search relies on computing the similarity or distance between vectors to identify relevant matches. +The similarity function is used to compute the similarity between two vectors. +Valid options are: EUCLIDEAN, DOT_PRODUCT, COSINE +Default: `COSINE` +endif::[] +|=== + +== Query operators + +SAI supports the following query operators for tables with SAI indexes: + +include::cassandra:partial$sai/supported-query-operators-list.adoc[] + +SAI does not supports the following query operators for tables with SAI indexes: + +include::cassandra:partial$sai/notSupportedOperators.adoc[] + +== Examples + +These examples define SAI indexes for the `cycling.cyclist_semi_pro` table, which is demonstrated in the xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_semi_pro_sai_indices.cql[tag=createQuickStartIndices] +---- + +For sample queries that find data in `cycling.cyclist_semi_pro` via these sample SAI indexes, see xref:cassandra:getting-started/sai-quickstart.adoc#saiQuickStart__saiQuickStartSubmitQueries[Submit CQL queries]. +Also refer xref:cassandra:developing/cql/indexing/sai/sai-query.adoc[Examine SAI column index and query rules]. + +[[saiCollectionsExamples]] +=== SAI collection map examples with keys, values, and entries + +The following examples demonstrate using collection maps of multiple types (`keys`, `values`, `entries`) in SAI indexes. +For related information, see xref:cassandra:developing/collections/collection-create.adoc[Creating collections] and xref:cassandra:developing/collections/map.adoc[Using map type]. + +Also refer to the SAI collection examples of type xref:#saiCreateCustomIndexCollectionsListAndSetExamples[list and set] in this topic. + +ifeval::["{evalproduct}" != "astra"] +First, create the keyspace: + +[source,language-cql] +---- +CREATE KEYSPACE demo3 WITH REPLICATION = + {'class': 'SimpleStrategy', 'replication_factor': '1'}; +---- +endif::[] + +Next, use the keyspace: + +[source,language-cql] +---- +USE demo3; +---- + +Create an `audit` table, with a collection map named `text_map`: + +[source,language-cql] +---- +CREATE TABLE audit ( id int PRIMARY KEY , text_map map); +---- + +Create multiple SAI indexes on the same `map` column, each using `KEYS`, `VALUES`, and `ENTRIES`. + +// ifeval::["{evalproduct}" == "dse"] +// [NOTE] +// ==== +// Creating multiple SAI indexes with different map types *on the same column* requires Cassandra 5.0 or later. +// If you're using DSE 6.8.3, submit a `DROP INDEX index-name;` command before adding the next map type on the same column. +// ==== +// endif::[] + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON audit (KEYS(text_map)) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX ON audit (VALUES(text_map)) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX ON audit (ENTRIES(text_map)) USING 'StorageAttachedIndex'; +---- + +Insert some data: + +[source,language-cql] +---- +INSERT INTO audit (id, text_map) values (1, {'Carlos':'Perotti', 'Marcel':'Silva'}); +INSERT INTO audit (id, text_map) values (2, {'Giovani':'Pasi', 'Frances':'Giardello'}); +INSERT INTO audit (id, text_map) values (3, {'Mark':'Pastore', 'Irene':'Cantona'}); +---- + +Query all data: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+--------------------------------------------- + 1 | {'Carlos': 'Perotti', 'Marcel': 'Silva'} + 2 | {'Frances': 'Giardello', 'Giovani': 'Pasi'} + 3 | {'Irene': 'Cantona', 'Mark': 'Pastore'} + +(3 rows) +---- +-- +==== + +Query using the SAI index for specific entries in the `map` column: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map['Irene'] = 'Cantona' AND text_map['Mark'] = 'Pastore'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+----------------------------------------- + 3 | {'Irene': 'Cantona', 'Mark': 'Pastore'} + +(1 rows) +---- +-- +==== + +Query using the SAI index for specific keys in the `map` column using `CONTAINS KEY`: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map CONTAINS KEY 'Giovani'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+--------------------------------------------- + 2 | {'Frances': 'Giardello', 'Giovani': 'Pasi'} + +(1 rows) +---- +-- +==== + +Query using the SAI index for specific values in the `map` column with `CONTAINS`: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map CONTAINS 'Silva'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+------------------------------------------ + 1 | {'Carlos': 'Perotti', 'Marcel': 'Silva'} + +(1 rows) +---- +-- +==== + +// tag::saiCollectionsReferenceNote[] +Remember that in CQL queries using SAI indexes, the `CONTAINS` clauses are supported with, and specific to: + +* SAI *collection maps* with `keys`, `values`, and `entries` +* SAI *collections* with `list` and `set` types +// end::saiCollectionsReferenceNote[] + +[[saiCreateCustomIndexCollectionsListAndSetExamples]] +=== SAI collection examples with list and set types + +These examples demonstrate using collections with the `list` and `set` types in SAI indexes. +For related information, see: + +* xref:cassandra:developing/collections/collection-create.adoc[Creating collections] +* xref:cassandra:developing/collections/list.adoc[Using list type] +* xref:cassandra:developing/collections/set.adoc[Using set type] + +[source,language-cql] +---- +CREATE KEYSPACE IF NOT EXISTS demo3 WITH REPLICATION = + {'class': 'SimpleStrategy', 'replication_factor': '1'}; +---- + +[source,language-cql] +---- +USE demo3; +---- + +==== Using the list type + +Create a `calendar` table with a collection of type `list`. + +[source,language-cql] +---- +CREATE TABLE calendar (key int PRIMARY KEY, years list); +---- + +Create an SAI index using the collection's `years` column. + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON calendar(years) USING 'StorageAttachedIndex'; +---- + +Insert some random `int` list data for `years`, just for demo purposes. + +[TIP] +==== +Notice the `INSERT` command's square brackets syntax for list values. + +[source,language-cql] +---- +INSERT INTO calendar (key, years) VALUES (0, [1990,1996]); +INSERT INTO calendar (key, years) VALUES (1, [2000,2010]); +INSERT INTO calendar (key, years) VALUES (2, [2001,1990]); +---- +==== + +Query with `CONTAINS` example: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM calendar WHERE years CONTAINS 1990; +---- +-- + +Result:: ++ +-- +[source,results] +---- + key | years +-----+-------------- + 0 | [1990, 1996] + 2 | [2001, 1990] +(2 rows) +---- +-- +==== + +This example created the `calendar` table with `years list`. +Of course, you could have created the table with `years list`, for example, inserted 'string' values, and queried on the strings. + +==== Using the set type + +Now create a `calendar2` table with a collection of type `set`. + +[source,language-cql] +---- +CREATE TABLE calendar2 (key int PRIMARY KEY, years set); +---- + +Create an SAI index using the collection's `years` column -- this time for the `calendar2` table. + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON calendar2(years) USING 'StorageAttachedIndex'; +---- + +Insert some random `int` set data for `years`, again just for demo purposes. + +[TIP] +-- +Notice the `INSERT` command's curly braces syntax for set values. + +[source,language-cql] +---- +INSERT INTO calendar2 (key, years) VALUES (0, {1990,1996}); +INSERT INTO calendar2 (key, years) VALUES (1, {2000,2010}); +INSERT INTO calendar2 (key, years) VALUES (2, {2001,1990,2020}); +---- +-- + +Query with `CONTAINS` example from the list: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM calendar2 WHERE years CONTAINS 1990; +---- +-- + +Result:: ++ +-- +[source,results] +---- + key | years +-----+-------------------- + 0 | {1990, 1996} + 2 | {1990, 2001, 2020} + +(2 rows) +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/create-index.adoc b/doc/modules/cassandra/pages/developing/cql/create-index.adoc new file mode 100644 index 0000000000..88721030f0 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/create-index.adoc @@ -0,0 +1,193 @@ += CREATE INDEX +:description: Defines a new index for a single column of a table. + +Define a new index on a single column of a table. +If the column already contains data, it is indexed during the execution of this statement. +After an index has been created, it is automatically updated when data in the column changes. +{product} supports creating an index on most columns, including the partition and cluster columns of a PRIMARY KEY, collections, and static columns. +Indexing via this `CREATE INDEX` command can impact performance. +Before creating an index, be aware of when and xref:cassandra:developing/cql/indexing/2i/2i-when-to-use.adoc#when-no-index[when not to create an index]. + +Use xref:cassandra:developing/cql/indexing/create-custom-index.adoc[CREATE CUSTOM INDEX] for Storage-Attached Indexes (SAI). + +*Restriction:* Indexing counter columns is not supported. +For maps, index the key, value, or entries. + +== Synopsis + +// tag::syntax[] +---- +CREATE INDEX [ IF NOT EXISTS ] + ON [.] + ([ ( KEYS | FULL ) ] ) + (ENTRIES ) ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include:cassandra:partial$cql-syntax-legend.adoc[] +==== + +*index_name*:: +Optional identifier for index. +If no name is specified, DataStax Enterprise +// audience="astra" DataStax Astra +names the index: `__idx`. +Enclose in quotes to use special characters or preserve capitalization. + +== Examples + +=== Creating an index on a clustering column + +Define a table having a xref:cassandra:reference/cql-commands/create-table.adoc#cqlPKcomposite[composite partition key], and then create an index on a clustering column. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=compositepk] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=createindex] +---- + +=== Creating an index on a set or list collection + +Create an index on a set or list collection column as you would any other column. +Enclose the name of the collection column in parentheses at the end of the `CREATE INDEX` statement. +For example, add a collection of teams to the `cyclist_career_teams` table to index the data in the teams set. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=setColumn] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=createidxset] +---- + +[[CreatIdxCollKey]] +=== Creating an index on map keys + +You can create an index on xref:cassandra:developingindexing/2i/2i-create-on-collection.adoc[map collection keys]. +If an index of the map values of the collection exists, drop that index before creating an index on the map collection keys. +Assume a cyclist table contains this map data: + +[source,no-highlight] +---- +{'nation':'CANADA' } +---- + +The map key is located to the left of the colon, and the map value is located to the right of the colon. + +To index map keys, use the `KEYS` keyword and map name in nested parentheses: + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=keysidx] +---- + +To query the table, you can use xref:cassandra:reference/cql-commands/select.adoc#filtering-on-collections[CONTAINS KEY] in `WHERE` clauses. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=queryindexkey] +---- + +The example returns cyclist teams that have an entry for the year 2015. + +[source,results] +---- +include::cassandra:example$RESULTS/sai/cyclist_team-queries.result[] +---- + +=== Creating an index on map entries + +You can create an index on map entries. +An `ENTRIES` index can be created only on a map column of a table that doesn't have an existing index. + +To index collection entries, use the `ENTRIES` keyword and map name in nested parentheses: + +[source,language-cql] +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=entriesidx] +---- + +To query the map entries in the table, use a `WHERE` clause with the map name and a value. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=ageentryquery] +---- + +The example finds cyclists who are the same age. + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_age_23.result[] +---- + +Use the same index to find cyclists from the same country. + +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationentryquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result[] +---- + +=== Creating an index on map values + +To create an index on map values, use the `VALUES` keyword and map name in nested parentheses: + +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=mapvaluesidx] +---- + +To query the table, use a `WHERE` clause with the map name and the value it contains. + +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationvaluesquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result[] +---- + +=== Creating an index on the full content of a frozen collection + +You can create an index on a full `FROZEN` collection. +A `FULL` index can be created on a set, list, or map column of a table that doesn't have an existing index. + +Create an index on the full content of a `FROZEN` `list`. +The table in this example stores the number of Pro wins, Grand Tour races, and Classic races that a cyclist has competed in. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=frozenlist] +---- + +To index collection entries, use the `FULL` keyword and collection name in nested parentheses. +For example, index the frozen list `rnumbers`. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=fullindex] +---- + +To query the table, use a `WHERE` clause with the collection name and values: + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=selectrnumbers] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/race_starts-queries.result[] +---- diff --git a/doc/modules/cassandra/pages/developing/cql/ddl.adoc b/doc/modules/cassandra/pages/developing/cql/ddl.adoc index eab49ca531..7f20663e9c 100644 --- a/doc/modules/cassandra/pages/developing/cql/ddl.adoc +++ b/doc/modules/cassandra/pages/developing/cql/ddl.adoc @@ -790,7 +790,7 @@ If the table does not exist, the statement will return an error, unless `IF EXISTS` is used, when the operation is a no-op. [[truncate-statement]] -== TRUNCATE +== TRUNCATE TABLE A table can be truncated using the `TRUNCATE` statement: diff --git a/doc/modules/cassandra/pages/developing/cql/drop-index.adoc b/doc/modules/cassandra/pages/developing/cql/drop-index.adoc new file mode 100644 index 0000000000..cbb18053d7 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/drop-index.adoc @@ -0,0 +1,29 @@ += DROP INDEX +:page-aliases: cql_reference:cql_commands/cqlDropIndex.adoc +:description: Removes an index from a table. + +Removes an existing index. +The default index name is `table_name_column_name_idx`. + +== Synopsis + +// tag::syntax[] +---- +DROP INDEX [ IF EXISTS ] [.] ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include:cassandra:partial$cql-syntax-legend.adoc[] +==== + +== Example + +Drop the index `rank_idx` from the `cycling.rank_by_year_and_name` table. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=dropindex] +---- diff --git a/doc/modules/cassandra/pages/developing/cql/index.adoc b/doc/modules/cassandra/pages/developing/cql/index.adoc index 775e56fe02..73056d6dc8 100644 --- a/doc/modules/cassandra/pages/developing/cql/index.adoc +++ b/doc/modules/cassandra/pages/developing/cql/index.adoc @@ -9,18 +9,17 @@ CQL offers a model similar to SQL. The data is stored in *tables* containing *rows* of *columns*. For that reason, when used in this document, these terms (tables, rows and columns) have the same definition that they have in SQL. - -* xref:cassandra:developing/cql/definitions.adoc[Definitions] -* xref:cassandra:developing/cql/types.adoc[Data types] -* xref:cassandra:developing/cql/ddl.adoc[Data definition language] -* xref:cassandra:developing/cql/dml.adoc[Data manipulation language] -* xref:cassandra:developing/cql/operators.adoc[Operators] -* xref:cassandra:developing/cql/indexes.adoc[Secondary indexes] -* xref:cassandra:developing/cql/mvs.adoc[Materialized views] -* xref:cassandra:developing/cql/functions.adoc[Functions] -* xref:cassandra:developing/cql/json.adoc[JSON] -* xref:cassandra:developing/cql/security.adoc[CQL security] -* xref:cassandra:developing/cql/dynamic_data_masking.adoc[Dynamic data masking] -* xref:cassandra:developing/cql/triggers.adoc[Triggers] -* xref:cassandra:developing/cql/appendices.adoc[Appendices] -* xref:cassandra:developing/cql/changes.adoc[Changes] +* xref:developing/cql/definitions.adoc[Definitions] +* xref:developing/cql/types.adoc[Data types] +* xref:developing/cql/ddl.adoc[Data definition language] +* xref:developing/cql/dml.adoc[Data manipulation language] +* xref:developing/cql/operators.adoc[Operators] +* xref:developing/cql/indexing/indexing-concepts.adoc[] +* xref:developing/cql/mvs.adoc[Materialized views] +* xref:developing/cql/functions.adoc[Functions] +* xref:developing/cql/json.adoc[JSON] +* xref:developing/cql/security.adoc[CQL security] +* xref:developing/cql/dynamic_data_masking.adoc[Dynamic data masking] +* xref:developing/cql/triggers.adoc[Triggers] +* xref:developing/cql/appendices.adoc[Appendices] +* xref:developing/cql/changes.adoc[Changes] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-concepts.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-concepts.adoc new file mode 100644 index 0000000000..e8f6ccf8d0 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-concepts.adoc @@ -0,0 +1,14 @@ += Secondary index (2i) concepts +:navtitle: Concepts +:description: Use secondary indexing (2i) to create secondary indexes on the same table. + +Secondary indexing (2i) is a globally-distributed index for {cassandra} databases. + +2i is the original secondary indexing of {product}, but today, it suffers from poor performance and latency. +If you are building new indexing, use xref:developing/cql/indexing/sai/sai-concepts.adoc[SAI indexing] instead. + +2i adds column-level indexes to any CQL table column of any CQL data type, except for a counter column. +However, the indexes are locally built on each {product} node in a cluster, so using 2i for queries results in poor performance. +A number of https://www.datastax.com/dev/blog/improving-secondary-index-write-performance-in-1-2[techniques] exist for guarding against the undesirable scenario where data might be incorrectly retrieved during a query based on stale values in an index. + +There are distinct conditions about xref:developing/cql/indexing/2i/2i-when-to-use.adoc[when and when not to use a 2i index]. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-overview.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-overview.adoc new file mode 100644 index 0000000000..f8bb5e6e90 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-overview.adoc @@ -0,0 +1,21 @@ += Secondary indexes (2i) overview +:description: Secondary indexes (2i). + +Secondary indexes (2i) allow you create one or multiple secondary indexes on the same database table, with each 2i based on any column. + +*Exception:* There is no need to define an 2i based on a single-column partition key. + +xref:developing/cql/indexing/2i/2i-concepts.adoc[Concepts]:: +How 2i works and when to use this type of indexing. + +// LLP: Should add a quickstart for 2i here. +// xref:getting-started/2i-quickstart.adoc[Quick start]:: +// Quickstart for creating and using secondary indexes (2i). + +xref:developing/cql/indexing/2i/2i-working-with.adoc[Working with 2i]:: +Create, check, alter, drop, and query secondary indexes (2i). + +xref:developing/cql/indexing/2i/operations/2i-build.adoc[2i operations]:: +Rebuilding and maintaining 2i indexes. + +*Reference:* xref:cassandra:reference/cql-commands/create-index.adoc[CREATE INDEX], xref:cassandra:reference/cql-commands/drop-index.adoc[DROP INDEX] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-when-to-use.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-when-to-use.adoc new file mode 100644 index 0000000000..690c92aac6 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-when-to-use.adoc @@ -0,0 +1,51 @@ += When to use an index +:description: When to use and when not to use a 2i index. + +Built-in indexes are best on a table having many rows that contain the indexed value. +The more unique values that exist in a particular column, the more overhead on average is required to query and maintain the index. +For example, suppose you had a races table with a billion entries for cyclists in hundreds of races and wanted to look up rank by the cyclist. +Many cyclists' ranks will share the same column value for race year. +The `race_year` column is a good candidate for an index. + +If secondary indexes are required, based on one or more table columns other than its partition key, use Storage-Attached Indexing (SAI). +For details, see xref:cassandra:reference/cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX]. + +[[when-no-index]] +== When _not_ to use an index + +Do not use an index in these situations: + +* On high-cardinality columns for a query of a huge volume of records for a small number of results. +See xref:#highCardCol[Problems using a high-cardinality column index] below. +* In tables that use a counter column. +* On a frequently updated or deleted column. +See xref:#upDatIndx[Problems using an index on a frequently updated or deleted column] below. +* To look for a row in a large partition unless narrowly queried. +See xref:#largCluster[Problems using an index to look for a row in a large partition unless narrowly queried] below. +* Do not add a secondary index and a search index to the same table. + +[[highCardCol]] +=== Problems using a high-cardinality column index + +If you create an index on a high-cardinality column, which has many distinct values, a query between the fields incurs many seeks for very few results. +In the table with a billion songs, looking up songs by writer (a value that is typically unique for each song) instead of by their recording artist is likely to be very inefficient. + +It would probably be more efficient to manually maintain the table as a form of an index instead of using the built-in index. +For columns containing unique data, it is sometimes better for performance to use an index for convenience, as long as the query volume to the table having an indexed column is moderate and not under constant load. + +Conversely, creating an index on an extremely low-cardinality column, such as a boolean column, does not make sense. +Each value in the index becomes a single row in the index, resulting in a huge row for all the false values, for example. +Indexing a multitude of indexed columns having foo = true and foo = false is not useful. + +[[upDatIndx]] +=== Problems using an index on a frequently updated or deleted column + +The database stores tombstones in the index until the tombstone limit reaches 100K cells. +After exceeding the tombstone limit, the query that uses the indexed value will fail. + +[[largCluster]] +=== Problems using an index to look for a row in a large partition unless narrowly queried + +A query on an indexed column in a large cluster typically requires collating responses from multiple data partitions. +The query response slows down as more machines are added to the cluster. +When looking for a row in a large partition, narrow the search to avoid query performance degradation. diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-working-with.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-working-with.adoc new file mode 100644 index 0000000000..09fd5a638c --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/2i-working-with.adoc @@ -0,0 +1,18 @@ += Working with secondary indexing (2i) +:navtitle: Working with 2i +:description: CRUD operations on 2i + querying with 2i + +== Prerequisites + +* xref:developing/keyspace-create.adoc[Keyspace created] +* xref:developing/table-create.adoc[Table created] + +include::_2i-create.adoc[leveloffset=+1] + +include::_2i-check.adoc[leveloffset=+1] + +include::_2i-alter.adoc[leveloffset=+1] + +include::_2i-drop.adoc[leveloffset=+1] + +include::_2i-query.adoc[leveloffset=+1] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-alter.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-alter.adoc new file mode 100644 index 0000000000..35d2516cc5 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-alter.adoc @@ -0,0 +1,4 @@ += Alter a secondary index (2i) + +Secondary indexes cannot be altered. +If you wish to change a 2i, you need to xref:developing/cql/indexing/2i/2i-drop.adoc[drop the index] and xref:developing/cql/indexing/2i/2i-create.adoc[create a new one]. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-check.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-check.adoc new file mode 100644 index 0000000000..1ef55c3a59 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-check.adoc @@ -0,0 +1,24 @@ += Check secondary index (2i) existence + +Verify that an index exists: + +[tabs] +==== +CQL:: ++ +-- +[source,language-bash] +---- +include::cassandra:example$CQL/2i/2i-check.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/2i/2i-check.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create-on-collection.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create-on-collection.adoc new file mode 100644 index 0000000000..4cb9904831 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create-on-collection.adoc @@ -0,0 +1,132 @@ += Create a 2i on a collection column +:description: How to index collections and query the database to find a collection containing a particular value. + +Collections can be indexed and queried to find a collection containing a particular value. +Sets and lists are indexed a bit differently from maps, given the key-value nature of maps. + +Sets and lists can index all values found by indexing the collection column. +Maps can index a map key, map value, or map entry using the methods shown below. +Multiple indexes can be created on the same map column in a table so that map keys, values, or entries can be queried. +In addition, frozen collections can be indexed using `FULL` to index the full content of a frozen collection. + +[NOTE] +==== +All the xref:developing/cql/indexing/2i/2i-when-to-use.adoc#when-no-index[cautions] about using secondary indexes apply to indexing collections. +==== + +* For set and list collections, create an index on the column name. +Create an index on a set to find all the cyclists that have been on a particular team. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=createidxset] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=select_with_contains_value] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_all_from_cyclist_career_teams_contains_value.result[] +---- + +* For map collections, create an index on the map key, map value, or map entry. +Create an index on a map key to find all cyclist/team combinations for a particular year. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=keysidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=queryindexkey] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/cyclist_team-queries.result[] +---- + +* Create an index on the map entries and find cyclists who are the same age. +An index using `ENTRIES` is only valid for maps. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=entriesidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=ageentryquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_age_23.result[] +---- + +* Using the same index, find cyclists from the same country. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationentryquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result[] +---- + +* Create an index on the map values and find cyclists who have a particular value found in the specified map. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=mapvaluesidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationvaluesquery] +---- ++ +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result[] +---- + +* Create an index on the full content of a `FROZEN` map. +The table in this example stores the number of Pro wins, Grand Tour races, and Classic races that a cyclist has competed in. +The SELECT statement finds any cyclist who has 39 Pro race wins, 7 Grand Tour starts, and 14 Classic starts. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=frozenlist] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=fullindex] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=selectrnumbers] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/race_starts-queries.result[] +---- diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create.adoc new file mode 100644 index 0000000000..359b89fc23 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-create.adoc @@ -0,0 +1,223 @@ += Create a secondary index (2i) +:description: Use CQL to create a secondary index on a column after defining a table. + +Create indexes on one or more columns after defining a table. +Secondary indexes created with 2i can be used to query a table using a column other than the table's partition key. + +In a production environment, certain columns might not be good choices, depending on their xref:developing/cql/indexing/2i/2i-when-to-use.adoc#when-no-index[cardinality]. + +[IMPORTANT] +==== +Do not add an storage-attached index (SAI) +to the same table. See the difference between these index types in the xref:developing/cql/indexing/indexing-concepts.adoc[overview]. +==== + +== Create simple 2i + +Create simple 2i indexes on a table to see how indexing works. +Start by creating a table, `cycling.alt_stats`, that yields statistics about cyclists: + +[source,language-cql] +---- +include::cassandra:example$CQL/2i/cyclist_alt_stats.cql[tag=cyclist_alt_stats] +---- + +Now create indexes on the columns `birthday` and `nationality`: + +[source,language-cql] +---- +include::cassandra:example$CQL/2i/cyclist_alt_stats.cql[tag=index_bday] +include::cassandra:example$CQL/2i/cyclist_alt_stats.cql[tag=index_nationality] +---- + +The following query attempts to retrieve the cyclists with a specified `birthday` and `nationality`. +The query returns an error: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/2i/bad_cql_examples.cql[tag=select_all_from_cyclist_alt_stats_error] +---- +-- + +Result:: ++ +-- +[source,results] +---- +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" +---- +-- +==== + +The indexes have been created on appropriate low-cardinality columns, but the previous query still fails. +Why? + +The answer lies with the partition key, which has not been defined. +When you attempt a potentially expensive query, such as searching a range of rows, the database requires the `ALLOW FILTERING` directive. +The error is not due to multiple indexes, but the lack of a partition key definition in the query. + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/2i/cyclist_alt_stats.cql[tag=select_success] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/2i/select_all_from_cyclist_alt_stats_filtering.result[] +---- +-- +==== + +Thus, one of the difficulties of using 2is is illustrated. +xref:developing/cql/indexing/sai/sai-concepts.adoc[SAI] is almost always a better option. + +== Create a 2i on a collection column + +Collections can be indexed and queried to find a collection containing a particular value. +Sets and lists are indexed a bit differently from maps, given the key-value nature of maps. + +Sets and lists can index all values found by indexing the collection column. +Maps can index a map key, map value, or map entry using the methods shown below. +Multiple indexes can be created on the same map column in a table so that map keys, values, or entries can be queried. +In addition, frozen collections can be indexed using `FULL` to index the full content of a frozen collection. + +[NOTE] +==== +All the xref:developing/cql/indexing/2i/2i-when-to-use.adoc#when-no-index[cautions] about using secondary indexes apply to indexing collections. +==== + +* For set and list collections, create an index on the column name. +Create an index on a set to find all the cyclists that have been on a particular team. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=createidxset] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=select_with_contains_value] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_all_from_cyclist_career_teams_contains_value.result[] +---- + +* For map collections, create an index on the map key, map value, or map entry. +Create an index on a map key to find all cyclist/team combinations for a particular year. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=keysidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=queryindexkey] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/cyclist_team-queries.result[] +---- + +* Create an index on the map entries and find cyclists who are the same age. +An index using `ENTRIES` is only valid for maps. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=entriesidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=ageentryquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_age_23.result[] +---- + +* Using the same index, find cyclists from the same country. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationentryquery] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result[] +---- + +* Create an index on the map values and find cyclists who have a particular value found in the specified map. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=mapvaluesidx] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationvaluesquery] +---- ++ +[source,results] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result[] +---- + +* Create an index on the full content of a `FROZEN` map. +The table in this example stores the number of Pro wins, Grand Tour races, and Classic races that a cyclist has competed in. +The SELECT statement finds any cyclist who has 39 Pro race wins, 7 Grand Tour starts, and 14 Classic starts. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=frozenlist] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=fullindex] +---- + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=selectrnumbers] +---- + +[source,results] +---- +include::cassandra:example$RESULTS/sai/race_starts-queries.result[] +---- + diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-drop.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-drop.adoc new file mode 100644 index 0000000000..56bc93a0c4 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-drop.adoc @@ -0,0 +1,8 @@ += Drop a secondary index (2i) + +Drop a 2i: + +[source,language-bash] +---- +include::cassandra:example$CQL/2i/2i-drop.cql[] +---- diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-query.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-query.adoc new file mode 100644 index 0000000000..52a07ec764 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/_2i-query.adoc @@ -0,0 +1,3 @@ += Querying using secondary indexes (2i) + +//TBD - fill in from other files \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/2i/operations/2i-build.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/2i/operations/2i-build.adoc new file mode 100644 index 0000000000..80201b1338 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/2i/operations/2i-build.adoc @@ -0,0 +1,10 @@ += Rebuilding and maintaining secondary indexes (2i) +:navtitle: Rebuild 2i +:description: Indexes provide operational ease for populating and maintaining the index. + +An advantage of indexes is the operational ease of populating and maintaining the index. +Indexes are built in the background automatically, without blocking reads or writes. +Client-maintained _tables as indexes_ must be created manually; +for example, if the artists column had been indexed by creating a table such as `songs_by_artist`, your client application would have to populate the table with data from the songs table. + +To perform a hot rebuild of an index, use the xref:cassandra:tools/nodetool/rebuild_index.adoc[nodetool rebuild_index] command. diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/indexing-concepts.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/indexing-concepts.adoc new file mode 100644 index 0000000000..40d4e3902d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/indexing-concepts.adoc @@ -0,0 +1,45 @@ += Indexing concepts +:page-aliases: developing:cql/indexes.adoc +:description: How to query data from tables using indexes. +:y: ✓ +:n: 𐄂 + +The data stored in CQL tables can be queried by a variety of methods. +The main method uses the partition key defined for a table, and is called primary indexing. +Often, however, a query must use another column of a table to select the rows desired, and secondary indexing is required. +Secondary indexing use fast, efficient lookup of data that matches a given condition. +After any index is created, data can be queried using that index. + +{product} has the following types of indexing available: + +[cols="1,^1",options=header] +|=== +| Indexing type +| Versions + +a| xref:developing/cql/ddl.adoc#primary-key[Primary indexing] +| All + +a| xref:developing/cql/indexing/sai/sai-overview.adoc[Storage-attached indexing (SAI)] +| 5.0 + +a| xref:developing/cql/indexing/2i/2i-overview.adoc[Secondary indexing (2i)] +| All +|=== + +== Primary indexing + +The primary index is the partition key in {product}. The storage engine of {product} uses the partition key to store rows of data, and the most efficient and fast lookup of data matches the partition key. + +== Storage-attached indexing (SAI) + +SAI uses indexes for non-partition columns, and attaches the indexing information to the SSTables that store the rows of data. +The indexes are located on the same node as the SSTable, and are updated when the SSTable is updated. +SAI is the most appropriate indexing method for most use cases. + +== Secondary indexing (2i) + +Secondary indexing is the original built-in indexing written for {product}. +These indexes are all local indexes, stored in a hidden table on each node of a {product} cluster, separate from the table that contains the values being indexed. +The index must be read from the node. +This indexing method is only recommended when used in conjunction with a partition key. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/.index-table.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/.index-table.adoc new file mode 100644 index 0000000000..61434e0ec2 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/.index-table.adoc @@ -0,0 +1,69 @@ +// LLP: 09.21.2023 useful table I built but decided not to use +Table 1 describes the table and index schema used throughout the SAI examples. + +.Table and index schema +[cols="1,3,3"] +|=== + +| Table name | Table | Indexes + +|[[vector_search]]comments_vs for vector search +a|[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-index-cycling.cql[] +---- + +|[[comments_vs]]comments_vs +a|[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +|[[rank-by-year-and-name]]rank_by_year_and_name +a|[source,sql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=compositepk] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +|[[cyclist_career_teams]]cyclist_career_teams +a|[source,sql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=setColumn] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/index-sai-from-set-match.cql[] +---- + +|[[upcoming_calendar]]upcoming_calendar +a|[source,sql] +---- +include::cassandra:example$CQL/sai/upcoming_calendar-table.cql[tag=listColumn] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/index-sai-from-list-match.cql[] +---- + +|[[cyclist_teams]]cyclist_teams +a|[source,sql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=mapColumn] +---- +a|[source,sql] +---- +include::cassandra:example$CQL/sai/index-sai-from-map-match.cql[] +---- +|=== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-list.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-list.adoc new file mode 100644 index 0000000000..53e215f051 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-list.adoc @@ -0,0 +1,57 @@ += Using the list type + +This example uses the following table and index: + +[source,sql] +---- +include::cassandra:example$CQL/sai/upcoming_calendar-table.cql[tag=listColumn] +include::cassandra:example$CQL/sai/index-sai-from-list-match.cql[] +---- + +An index is created on the list column `events` in the `upcoming_calendar` table. + +Query with `CONTAINS` from the list `events` column: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-list.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-list.result[] +---- +-- +==== + +A slightly more complex query selects rows that either contain a particular event or have a particular month date: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-list-two-columns.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-list-two-columns.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-map.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-map.adoc new file mode 100644 index 0000000000..93c2ccc2b3 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-map.adoc @@ -0,0 +1,83 @@ +[[saiUsingCollectionsMapExamples]] += Using the map type + +This example uses the following table and indexes: + +[source,sql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=mapColumn] +include::cassandra:example$CQL/sai/index-sai-from-map-match.cql[] +---- + +Indexes created on the map column `teams` in the `cyclist_career_teams` table target the keys, values, and full entries of the column data. + +Query with `KEYS` from the map `teams` column: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-map-key.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-map-key.result[] +---- +-- +==== + +Query a value from the map `teams` column, noting that only the keyword `CONTAINS` is included: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-map-value.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-map-value.result[] +---- +-- +==== + +Query entries from the map `teams` column, noting the difference in the `WHERE` clause: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-map-entries.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-map-entries.result[] +---- +-- +==== + +This example looks for a row where two entries are present in the map `teams` column. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-set.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-set.adoc new file mode 100644 index 0000000000..1fe14b43b9 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections-set.adoc @@ -0,0 +1,34 @@ += Using the set type + +This example uses the following table and index: + +[source,sql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=setColumn] +include::cassandra:example$CQL/sai/index-sai-from-set-match.cql[] +---- + +An index is created on the set column `teams` in the `cyclist_career_teams` table. + +Query with `CONTAINS` from the set `teams` column: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-from-set.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-from-set.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections.adoc new file mode 100644 index 0000000000..08493df2e2 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_collections.adoc @@ -0,0 +1,37 @@ += SAI indexing with collections +:description: Understand the columns on which you can define SAI indexes and run queries. + +[[saiUsingCollections]] + +SAI supports collections of type `map`, `list`, and `set`. +Collections allow you to group and store data together in a column. + +In a relational database, a grouping such as a user's multiple email addresses is achieved via many-to-one joined relationship between (for example) a `user` table and an `email` table. +DSE avoids joins between two tables by storing the user's email addresses in a collection column in the `user` table. +Each collection specifies the data type of the data held. + +A collection is appropriate if the data for collection storage is limited. +If the data has unbounded growth potential, like messages sent or sensor events registered every second, do not use collections. +Instead, use a table with a compound primary key where data is stored in the clustering columns. + +[TIP] +==== +In CQL queries of database tables with SAI indexes, the `CONTAINS` clauses are supported with, and specific to: + +* SAI *collection maps* with `keys`, `values`, and `entries` +* SAI *collections* with `list` and `set` types +==== + +include::_collections-set.adoc[leveloffset=+1] + +include::_collections-list.adoc[leveloffset=+1] + +include::_collections-map.adoc[leveloffset=+1] + +For more information, see: + +* xref:developing/cql/create-custom-index.adoc[CREATE CUSTOM INDEX] +* xref:developing/cql/collections/collection-create.adoc[Creating collections] +* xref:developing/cql/collections/set.adoc[Using set type] +* xref:developing/cql/collections/list.adoc[Using list type] +* xref:developing/cql/collections/map.adoc[Using map type] diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_composite-partition-key-index.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_composite-partition-key-index.adoc new file mode 100644 index 0000000000..163feb0b44 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_composite-partition-key-index.adoc @@ -0,0 +1,65 @@ += Index match on a composite partition key column + +This example uses the following table and indexes: + +[source,sql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=compositepk] +include::cassandra:example$CQL/sai/index-sai-composite-partition-key-index-match.cql[] +---- + +Composite partition keys have a partition defined by multiple columns in a table. +Normally, you would need to specify all the columns in the partition key to query the table with a `WHERE` clause. +However, an SAI index makes it possible to define an index using a single column in the table's composite partition key. +You can create an SAI index on each column in the composite partition key, if you need to query based on just one column. + +SAI indexes also allow you to query tables without using the inefficient `ALLOW FILTERING` directive. +The `ALLOW FILTERING` directive requires scanning all the partitions in a table, leading to poor performance. + +The `race_year` and `race_name` columns comprise the composite partition key for the `cycling.rank_by_year_and_name` table. + +Query for a match on the column `race_name`: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-composite-partition-key-race-name.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-composite-partition-key-race-name.result[] +---- +-- +==== + +Query for a match on the column `race_year`: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-composite-partition-key-race-year.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-composite-partition-key-race-year.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-and.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-and.adoc new file mode 100644 index 0000000000..c0c11605ef --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-and.adoc @@ -0,0 +1,34 @@ += Multiple indexes matched with AND + +This example uses the following table and indexes: + +[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +Several indexes are created for the table to demonstrate how to query for matches on more than one column. + +Query for matches on more than one column, and both columns must match: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-multiple-index-match-with-and.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-multiple-index-match-with-and.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-in.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-in.adoc new file mode 100644 index 0000000000..7b34313a57 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-in.adoc @@ -0,0 +1,34 @@ += Multiple indexes matched with IN + +This example uses the following table and indexes: + +[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +Several indexes are created for the table to demonstrate how to query for matches on more than one column. + +Query for match with column values in a list of values: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-multiple-index-match-with-in.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-multiple-index-match-with-in.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-or.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-or.adoc new file mode 100644 index 0000000000..52aafffe5d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_multiple-index-match-with-or.adoc @@ -0,0 +1,34 @@ += Multiple indexes matched with OR + +This example uses the following table and indexes: + +[source,sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +Several indexes are created for the table to demonstrate how to query for matches on more than one column. + +Query for a match on either one column or the other: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-multiple-index-match-with-or.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-multiple-index-match-with-or.result[] +---- +-- +==== diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-alter.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-alter.adoc new file mode 100644 index 0000000000..b56c624f9a --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-alter.adoc @@ -0,0 +1,20 @@ += Alter SAI index +:description: Discuss why an SAI index for a CQL table cannot be modified. + +SAI indexes cannot be altered. +If you need to modify an SAI index, you will need to drop the current index, create a new index, and rebuild the cycling. + +. Drop index ++ +[source, language-cql] +---- +include::cassandra:example$CQL/sai/drop-sai-index.cql[] +---- + +. Create new index ++ +[source, language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_semi_pro_sai_indices.cql[tag=createQuickStartIndices] +---- + diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-check.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-check.adoc new file mode 100644 index 0000000000..730feae828 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-check.adoc @@ -0,0 +1,25 @@ += Check Storage-attached index (SAI)) existence +:navtitle: Check SAI + +Verify that an index exists: + +[tabs] +==== +CQL:: ++ +-- +[source,language-bash] +---- +include::cassandra:example$CQL/sai/sai-check.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/sai-check.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-create.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-create.adoc new file mode 100644 index 0000000000..aaa279e0fe --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-create.adoc @@ -0,0 +1,77 @@ += Create SAI index +:description: Create SAI index for CQL table schema using `cqlsh`. + +To create an SAI index, you must define the index name, table name, and column name for the column to be indexed. + +To create a simple SAI index: + +[source, language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_semi_pro_sai_indices.cql[tag=createQuickStartIndices] +---- + +For most SAI indexes, the column name is defined in the `CREATE CUSTOM INDEX` statement that also uses `USING 'StorageAttachedIndex'`. +The SAI index options are defined in the `WITH OPTIONS` clause. +The `case_sensitive` option is set to `false` to allow case-insensitive searches. +The `normalize` option is set to `true` to allow searches to be normalized for Unicode characters. +The `ascii_only` option is set to `true` to allow searches to be limited to ASCII characters. + +The `map` collection data type is the one exception, as shown in the xref:#map-collection-in-sai-index[example below]. + +== Partition key SAI error + +SAI indexes cannot be created on the partition key, as a primary index already exists and is used for queries. +If you attempt to create an SAI on the partition key column, an error will be returned: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/sai-error.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/sai-error.result[] +---- +-- +==== + +== `map` collection in SAI index + +Map collections do have a different format than other SAI indexes: + +[source, sql] +---- +include::cassandra:example$CQL/sai/index-sai-from-map-match.cql[] +---- + +== similarity-function for vector search + +This example uses the following table: + +[source, sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +---- + +To check if `comment_vector` has a particular similarity function set, use the `similarity-function` option set to one of the supported similarity functions: DOT_PRODUCT, COSINE, or EUCLIDEAN. The default similarity function is COSINE. + +This index creates an index on the `comment_vector` column with the similarity function set to DOT_PRODUCT: + +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-similarity-function.cql[] +---- + +''' +Other resources + +See xref:developing/cql/indexing/create-custom-index.adoc[CREATE CUSTOM INDEX] for more information about creating SAI indexes. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-drop.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-drop.adoc new file mode 100644 index 0000000000..5dd7d7015d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-drop.adoc @@ -0,0 +1,13 @@ += Drop SAI index +:description: Drop an SAI index for a CQL table. + +SAI indexes can be dropped (deleted). + +To drop an SAI index: + +[source, language-cql] +---- +include::cassandra:example$CQL/sai/drop-sai-index.cql[] +---- + +This command does not return a result. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-query.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-query.adoc new file mode 100644 index 0000000000..97062cf294 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-query.adoc @@ -0,0 +1,38 @@ += Querying with SAI +:description: Understand the columns on which you can define SAI indexes and run queries. + +The xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart] focuses only on defining multiple indexes based on non-primary key columns (a very useful feature). +Let's explore other options using some examples of how you can run queries on tables that have differently defined SAI indexes. + +// IS THERE AN EXAMPLE OF +// WITH OPTIONS = {'case_sensitive': false, 'normalize': true }; +// case_sensitive Ignore case in matching string values. +// Default: true. + +// normalize When set to true, perform Unicode normalization on indexed strings. +// SAI supports Normalization Form C (NFC) Unicode. When set to true, SAI normalizes the different versions of a given Unicode character to a single version, retaining all the marks and symbols in the index. For example, SAI would change the character Å (U+212B) to Å (U+00C5). + +// When implementations keep strings in a normalized form, equivalent strings have a unique binary representation. See Unicode Standard Annex #15, Unicode Normalization Forms. + +// Default: false. + +// ascii When set to true, SAI converts alphabetic, numeric, and symbolic characters that are not in the Basic Latin Unicode block (the first 127 ASCII characters) to the ASCII equivalent, if one exists. For example, this option changes à to a. +// Default: false. + +include::_vector-search.adoc[leveloffset=+1] + +include::_single-index-match.adoc[leveloffset=+1] + +include::_single-index-with-case-sensitive.adoc[leveloffset=+1] + +include::_composite-partition-key-index.adoc[leveloffset=+1] + +include::_multiple-index-match-with-and.adoc[leveloffset=+1] + +include::_multiple-index-match-with-or.adoc[leveloffset=+1] + +include::_multiple-index-match-with-in.adoc[leveloffset=+1] + +include::_user-defined-type-match.adoc[leveloffset=+1] + +include::_collections.adoc[leveloffset=+1] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-read-write-paths.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-read-write-paths.adoc new file mode 100644 index 0000000000..e735a9d210 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_sai-read-write-paths.adoc @@ -0,0 +1,198 @@ += SAI write path and read path + +SAI is deeply integrated with the storage engine of the underlying database. +SAI does not abstractly index tables. +Instead, SAI indexes *Memtables* and Sorted String Tables (*SSTables*) as they are written, resolving the differences between those indexes at read time. +Each Memtable is an in-memory data structure that is specific to a particular database table. +A Memtable resembles a write-back cache. +Each SSTable is an immutable data file to which the database writes Memtables periodically. +SSTables are stored on disk sequentially and maintained for each database table. + +This topic discusses the details of the SAI read and write paths, examining the SAI indexing lifecycle. + +== SAI write path + +An SAI index can be created either before any data is written to a CQL table, or after data has been written. +As a refresher, data written to a CQL table will first be written to a Memtable, and then to an SSTable once the data is flushed from the Memtable. +After an SAI index is created, SAI is notified of all mutations against the current Memtable. +Like any other data, SAI updates the indexes for inserts and updates, which {product} treats in exactly the same way. +SAI also supports partition deletions, range tombstones, and row removals. +If a delete operation is executed in a query, SAI handles index changes in a post-filtering step. +As a result, SAI imposes no special penalties when indexing frequently deleted columns. + +image::sai/saiWritePath.png[alt=SAI write path overview, as described in surrounding text, width=640,height=480] + +If an insert or update contains valid content for the indexed column, the content is added to a *Memtable index*, and the primary key of the updated row is associated with the indexed value. +SAI calculates an estimate of the incremental heap consumption of the new entry. +This estimate counts against the heap usage of the underlying Memtable. +This feature also means that as more columns are indexed on a table, the Memtable flush rate will increase, and the size of flushed SSTables will decrease. +The number of total writes and the estimated heap usage of all live Memtable indexes are exposed as metrics. +See xref:cassandra:developing/cql/indexing/sai/monitoring.adoc#saiMonitorMetrics[SAI metrics]. + +=== Memtable flush + +SAI flushes Memtable index contents directly to disk when the flush threshold is reached, rather than creating an additional in-memory representation. +This is possible because Memtable indexes are sorted by term/value and then by primary key. +When the flush occurs, SAI writes a new SSTable index for each indexed column, as the SSTable is being written. + +image::sai/saiWritePathFlow.png[alt=Write path flow as detailed in subsequent text,width=640,height=480] + +The flush operation is a two-phase process. +In the first phase, rows are written to the new SSTable. +For each row, a row ID is generated and three index components are created. +The components are: + +* On-disk mappings of row IDs to their corresponding token values -- SAI supports the Murmur3Partitioner +* SSTable partition offsets +* A temporary mapping of primary keys to their row IDs, which is used in a subsequent phase + +The contents of the first and second component files are compressed arrays whose ordinals correspond to row IDs. + +In the second phase, after all rows are written to the new SSTable and the shared SSTable-level index components have been completed, SAI begins its indexing work on each indexed column. +Specifically in the second phase, SAI iterates over the Memtable index to produce pairs of terms and their token-sorted row IDs. +This iterator translates primary keys to row IDs using the temporary mapping structure built in the first phase. +The terms iterator (with postings) is then passed to separate writing components based on whether each indexed element is for a string or numeric column. + +In the string case, the SAI index writer iterates over each term, first writing its postings to disk, and then recording the offset of those postings in the postings file as the payload of a new entry (for the term itself) in an on-disk, byte-ordered trie. +In the numeric case, SAI separates the writing of a numeric index into two steps: + +The terms are passed to a balanced kd-tree writer, which writes the kd-tree to disk. +As the leaf blocks of the tree are written, their postings are recorded temporarily in memory. +Those temporary postings are then used to build postings on-disk, at the leaves, and at various levels of the index nodes. + +When a column index flush completes, a special empty marker file is flagged to indicate success. +This procedure is used on startup and incremental rebuild operations to differentiate case where: + +* SSTable index files are missing for a column. +* There is no indexable data -- such as when an SSTable only contains tombstones. +(A tombstone is a marker in a row that indicates a column was deleted. +During compaction, marked columns are deleted.) + +SAI then increments a counter on the number of Memtable indexes flushed for the column, and adds to a histogram the number of cells flushed per second. + +=== When compaction is triggered + +Recall that {product} uses compaction to merge SSTables. +Compaction collects all versions of each unique row and assembles one complete row, using the most up-to-date version (by timestamp) of each of the row's columns from the SSTables. +The merge process is performant, because rows are sorted by partition key within each SSTable, and the merge process does not use random I/O. +The new versions of each row is written to a new SSTable. +The old versions, along with any rows that are ready for deletion, are left in the old SSTables, and are deleted when any pending reads are completed. + +image::sai/dmlCompaction.png[alt=DML compaction,width=640,height=480] + +For SAI, when compaction is triggered, each index group creates an SSTable Flush Observer to coordinate the process of writing all attached column indexes from the newly compacted data in their respective SSTable writer instances. +Unlike Memtable flush (where indexed terms are already sorted), when iterating merged data during compaction, SAI buffers indexed values and their row ids, which are added in token order. + +To avoid issues such as exhausting available heap resources, SAI uses an accumulated segment buffer, which is flushed to disk synchronously by using a proprietary calculation. +Then each segment records a segment row ID *offset* and only stores the segment row ID (SSTable row ID minus segment row ID offset). +SAI flushes segments into the same file synchronously to avoid the cost of rewriting all segments and to reduce the cost of partition-restricted queries and paging range queries, as it reduces the search space. + +The on-disk layout from the per-column indexed posting, to the SSTable offset, to the SSTable partition: + +image::sai/saiOnDiskStructureWithOffsets.png[alt=SAI on-disk layout as described in surrounding text,width=640,height=480] + +The actual segment flushing process is very similar to a Memtable flush. +However, buffered terms are sorted before they can be written with their postings to their respective type-specific on-disk structures. +At the end of compaction for a given index, a special empty marker file is flagged to indicate success, and the number of segments is recorded in SAI metrics. +See xref:developing:indexing/sai/monitoring.adoc#saiGlobalIndexingMetrics[Global indexing metrics]. + +When the entire compaction task finishes, SAI receives an SSTable List Changed Notification that contains the SSTables added and removed during the transaction. +SSTable Context Manager and Index View Manager are responsible for replacing old SSTable indexes with new ones atomically. +At this point, new SSTable indexes are available for queries. + +== SAI read path + +This section explains how index queries are processed by the SAI coordinator and executed by replicas. +Unlike legacy secondary indexes, where at most one column index will be used per query, SAI implements a `Query Plan` that makes it possible to use all available column indexes in a single query. + +The overall flow of a SAI read operation is as follows: + +image::sai/saiReadpathOverview.png[alt=AI read path as described in subsequent sections,width=640,height=480] + +=== Index selection and Coordinator processing + +When presented with a query, the first action the SAI Coordinator performs, to take advantage of one or more indexes, is to identify the most selective index. +That most selective index is the index that will most aggressively narrow the filtering space and the number of ultimate results by returning the lowest value from an estimated results row calculation. +If multiple SAI indexes are present (that is, where each SAI index is based on a different column, but the query involves more than one column), it does not matter which SAI index is selected first. + +Once the best index for the read operation is selected, the index is embedded with the read command, which enters the distributed range read apparatus. +A distributed range read queries the {product} cluster in one or more rounds in token order. +The SAI Coordinator estimates the *concurrency factor*, the number of rows per range based on local data and the query limit to determine the number of ranges to contact. +For each round, a concurrency factor determines how many replicas will be queried in parallel. + +Before the first round commences, SAI estimates the initial concurrency factor via a proprietary calculation, shown here as Step 1. + +image::sai/saiCoordinatorRangeReadEstimateConcurrencyFactor.png[alt=SAI step to estimate a concurrency factor as described in surrounding text, width=640,height=480] + +Once the initial concurrency factor established, the range read begins. + +image::sai/saiCoordinatorRangeReadUpdateConcurrencyFactor.png[alt=SAI iterates through the ranges as described in surrounding text, width=640,height=480] + +In Step 2, the SAI Coordinator sends requests to the required ranges in parallel based on the Concurrency factor. +In Step 3, the SAI Coordinator waits for the responses from the requested replicas. +And in Step 4, SAI Coordinator collects the results and recomputes the concurrency factor based on returned rows and query limit. + +At the completion of each round, if the limit has not been reached, the concurrency factor is adjusted to take into account the shape of the results already read. +If no results are returned from the first round, the concurrency factor is immediately increased to the minimum calculation of remaining token ranges and the maximum calculation of the concurrency factor. +If results are returned, the concurrency factor is updated. +SAI repeats steps 2, 3, and 4 until the query limit is satisfied. + +image::sai/saiCoordinatorRangeReadUntilLimit.png[alt=SAI repeats the steps until the limit is satisfied as described in surrounding text, width=640,height=480] + +To avoid querying replicas with failed indexes, each node propagates its own local index status to peers via gossip. +At the coordinator, read requests will filter replicas that contain non-queryable indexes used in the request. +In most cases, the second round of replica queries should return all the necessary results. +Further rounds may be necessary if the distribution of results around the replicas is extremely imbalanced. + +=== A closer look: replica query planning and view acquisition + +Once a replica receives a token range read request from the SAI Coordinator, the local index query begins. +SAI implements an index searcher interface via a Query Plan that makes it possible to access all available SAI column indexes in a single query. + +The Query Plan performs an analysis of the expressions passed to it via the read command. +SAI determines which indexes should be used to satisfy the query clauses on the given columns. +Once column expressions are paired with indexes, a view of the active SSTable indexes for each column index is acquired by a Query Controller. +In order to avoid compaction removing index files used by in-flight queries, before reading any index files, the Query Controller tries to acquire references to the SSTables for index files that intersect with the query's token range, and releases them when the read request completes. + +At this point, a Token Flow is created to stream matches from each column index. +Those flows, along with the Boolean logic that determines how they are merged, is wrapped up in an Operation, which is returned to the Query Plan component. + +=== Role of the SAI Token Flow framework + +The SAI query engine revolves around a Token Flow framework that defines how SAI asynchronously iterates over, skips into, and merges streams of matching partitions from both individual SSTable indexes and entire column indexes. +SAI uses a token to describe a container for partition matches within a Cassandra ring token. + +Iteration is the simplest of the three operations. +Specifically, the iteration of postings involves sequential disk access -- via the chunk cache -- to row IDs, which are used to lookup ring token and partition key offset information. + +Token skipping is used to skip unmatched tokens when continuing from the previous paging boundary, or when a larger token is found during token intersection. + +[[saiMatchStreamingAndPostFiltering]] +=== Match streaming and post filtering example + +Consider an example with an individual column index (such as `age = 44`), the flow produced is the union of all Memtable indexes and all SSTable indexes. + +* SAI iterates over each Memtable index "lazily" (that is, one at a time) in token order through its individual token range-partitioned instances. +This feature reduces the overhead that would occur otherwise from unnecessary searches of data toward the end of the ring. +* On-disk index: SAI returns the union of all matching SSTable index. +Within one SSTable index, there can be multiple segments because of the memory limit during compaction. +Similar to the Memtable index, SAI lazily searches segments in token sorted order. + +When there are multiple indexed expressions in the query (such as `WHERE age=44 AND state='CA'`) connected with `AND` query operator, the results of indexed expressions are intersected, which returns partition keys that match all indexed expressions. + +image::sai/saiAge44StateCAExample.png[alt=SAI intersection of age and state columns, width=640,height=480] + +After the index search, SAI exposes a flow of partition keys. +For every single partition key, SAI executes a single partition read operation, which returns the rows in the given partition. +As rows are materialized, SAI uses a filter tree to apply another round of filtering. +SAI performs this subsequent filtering step to address the following: + +* Partition granularity: SAI keeps track of partition offsets. +In the case of a wide partition schema, not all rows in the partition will match the index expressions. +* Tombstones: SAI does not index tombstones. +It's possible that an indexed row has been shadowed by newly added tombstones. +* Non-indexed expressions: Operations may include non-index expressions for which there are no index structures. + +== What's next? + +See the blog, https://www.datastax.com/blog/2020/09/eliminate-trade-offs-between-database-ease-use-and-massive-scale-sai-storage-attached[Better Cassandra Indexes for a Better Data Model: Introducing Storage-Attached Indexing]. diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-match.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-match.adoc new file mode 100644 index 0000000000..09f4bbe14f --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-match.adoc @@ -0,0 +1,69 @@ += Single index match on a column + +This example uses the following table and indexes: + +[source, sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/index-sai-multiple-index-match-with-and.cql[] +---- + +The column `commenter` is not the partition key in this table, so an index is required to query on it. + +Query for a match on that column: +// +// == Create an index on a single column: +// +// [source,cql] +// ---- +// include::cassandra:example$CQL/sai/index-sai-single-index-match.cql[] +// ---- +// +// == Query for a match on that column: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-single-index-match.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-single-index-match.result[] +---- +-- +==== + +.Failure with index +**** +Note that a failure will occur if you try this query before creating the index: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-single-index-match.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-single-index-match-failure.result[] +---- +-- +==== +**** diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-with-case-sensitive.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-with-case-sensitive.adoc new file mode 100644 index 0000000000..c9b8bf2bb2 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_single-index-with-case-sensitive.adoc @@ -0,0 +1,60 @@ += Single index match on a column with options + +This example uses the following table and indexes: + +[source, sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/index-sai-case-sensitive.cql[] +---- + +== Case-sensitivty + +The column `commenter` is not the partition key in this table, so an index is required to query on it. +If we want to check `commenter` as a case-sensitive value, we can use the `case_sensitive` option set to `true`. + +Note that no results are returned if you use an inappropriately case-sensitive value in the query: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-case-sensitive-bad.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-case-sensitive-bad.result[] +---- +-- +==== + +When we switch the case of the cyclist's name to match the case in the index, the query succeeds: + +[tabs] +==== +Query:: ++ +-- +[source, console] +---- +include::cassandra:example$CQL/sai/index-sai-select-case-sensitive-good.cql[] +---- +-- + +Result:: ++ +-- +[source,results] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-case-sensitive-good.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_user-defined-type-match.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_user-defined-type-match.adoc new file mode 100644 index 0000000000..21946ed64b --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_user-defined-type-match.adoc @@ -0,0 +1,38 @@ += User-defined type + +SAI can index either a single field of a user-defined type (UDT) or a list of UDTs. +This example shows how to index a list of UDTs. + +This example uses the following user-defined type (UDT), table and index: + +[source,sql] +---- +include::cassandra:example$CQL/sai/race-type.cql[tag=racetype] +include::cassandra:example$CQL/sai/cyclist_races-table.cql[tag=frozenlist] +include::cassandra:example$CQL/sai/index-sai-udt-match.cql[] +---- + +An index is created on the list of UDTs column `races` in the `cycling.cyclist_races` table. + +Query with `CONTAINS` from the list `races` column: + +[tabs] +==== +CQL:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/index-sai-select-udt-match.cql[] +---- +-- + +Result:: ++ +-- +[source,console] +---- +include::cassandra:example$RESULTS/sai/index-sai-select-udt-match.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/_vector-search.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_vector-search.adoc new file mode 100644 index 0000000000..a5cffebd45 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/_vector-search.adoc @@ -0,0 +1,11 @@ += Vector search + +This example uses the following table and index: + +[source, sql] +---- +include::cassandra:example$CQL/sai/create-vector-table-cycling.cql[tag=createvstable] +include::cassandra:example$CQL/sai/create-vector-index-cycling.cql[] +---- + +include::cassandra:partial$sai/query-vector-data.adoc[leveloffset=+1] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/configuring.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/configuring.adoc new file mode 100644 index 0000000000..a618143e1d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/configuring.adoc @@ -0,0 +1,70 @@ += Configure SAI indexes +:description: Learn which configuration settings may affect SAI indexing performance. + +// LLP: *NOT DONE* + +Configuring your {product} environment for Storage-Attached Indexing (SAI) requires some important customization of the `cassandra.yaml` file. + +== Increase file cache above the default value + +By default, the file cache's xref:cassandra:managing/configuration/cass_yaml_file.adoc#file_cache_size[file_cache_size] value is calculated as 50% of the `MaxDirectMemorySize` setting. +This default for `file_cache_size` may result in suboptimal performance because Cassandra is not able to take full advantage of available memory. + +[TIP] +==== +File cache is also known as chunk cache. +==== + +The `file_cache_size` value can be defined explicitly in `cassandra.yaml`. +The recommendation is to: + +. Increase `--XX:MaxDirectMemorySize`, leaving approximately 15-20% of memory for the OS and other in-memory structures. +. In `cassandra.yaml`, explicitly set `file_cache_size` to 75% of that value. + +In testing, this configuration improves indexing performance across read, write, and mixed read/write scenarios. + +== Compaction strategies + +Read queries perform better with compaction strategies that produce fewer SSTables. + +For most environments that include SAI indexes, using the default `SizeTieredCompactionStrategy` (STCS) is recommended. +This strategy triggers a minor compaction when there are a number of similar sized SSTables on disk as configured by the table subproperty, `min_threshold`. +A minor compaction does not involve all the tables in a keyspace. +For details, see xref:cassandra:managing/operating/compaction/index.adoc[Configuring compaction]. + +For time series data, an alternative is the `TimeWindowCompactionStrategy` (TWCS). +TWCS compacts SSTables using a series of time windows. +While in a time window, TWCS compacts all SSTables flushed from memory into larger SSTables using STCS. +At the end of the time window, all of these SSTables are compacted into a single SSTable. +Then the next time window starts and the process repeats. +The duration of the time window is the only setting required. +See xref:reference:cql-commands/create-table.adoc#compactSubprop__TWCS[TimeWindowCompactionStrategy]. +For more information about TWCS, see xref:cassandra:managing/operating/compaction/twcs.adoc[Time Window Compaction Strategy]. + +In general, do not use `LeveledCompactionStrategy` (LCS) unless your index queries restrict the token range, either directly or by providing a restriction on the partition key. +However, if you decide to use LCS, use the following guidelines: + +* The `160` MB default for the `CREATE TABLE` command's `sstable_size_in_mb` option, described in this xref:reference:cql-commands/create-table.adoc#compactSubprop__LCS[topic], may result in suboptimal performance for index queries that do not restrict on token range or partition key. +* While even higher values may be appropriate, depending on your hardware, DataStax recommends at least doubling the default value of `sstable_size_in_mb`. + +Example: + +[source,language-cql] +---- +include::cassandra:example$CQL/create-table-compaction-options.cql[] +---- + +After increasing the MB value, observe whether the query performance improves on tables with SAI indexes. +To observe any performance deltas, per query, look at the `QueryLatency` and `SSTableIndexesHit` data in the Cassandra query metrics. + +Using a larger value reserves more disk space, because the SSTables are larger, and the ones destined for replacement will use more space while being compacted. +However, the larger value results in having fewer SSTables, which lowers query latencies. +Each SAI index should ultimately consume less space on disk because of better long-term compression with the larger indexes. + +If query performance degrades on large (`sstable_max_size` ~2GB) SAI indexed SSTables when the workload is not dominated by reads but is experiencing increased write amplification, consider using Unified Compaction Strategy (UCS). + +== About SAI encryption + +With SAI indexes, its on-disk components are simply additional SSTable data. +To protect sensitive user data, including any present in the table's partition key values, SAI will need to encrypt all parts of the index that contain user data,the trie index data for strings and the kd-tree data for numerics. +By design, SAI does not encrypt non-user data such as postings metadata or SSTable-level offsets and tokens. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/monitoring.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/monitoring.adoc new file mode 100644 index 0000000000..87780f652b --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/monitoring.adoc @@ -0,0 +1,245 @@ += Monitor SAI indexes +:description: Use metrics to monitor secondary indexes that were created with Storage-Attached Indexing (SAI). + +Both virtual tables and JMX-based metrics can be used to monitor the SAI indexes in your cluster. + +[[saiMonitorVirtualTables]] +== SAI virtual tables + +You can refer to data in the following {product} virtual tables to determine the status of indexes created with SAI: + +* `system_views.indexes` -- provides information at the column index level, including the index name, number of indexed SSTables, disk usage, and index state. +From the index state, the data reveals if the index is currently building, and whether the index can be queried. ++ +[TIP] +==== +include::cassandra:partial$sai/queryable-paragraph.adoc[] +==== + +* `system_views.sstable_indexes` -- describes individual SSTable indexes, and includes information around disk size, min/max row ID, the min/max ring token, and the write-time version of the index. +* `system_views.sstable_index_segments` -- describes the segments of the SSTable indexes. +It exposes the segment row ID offset and most of the information in the SSTable-level virtual table, specifically at a segment granularity. +For more details, refer to xref:cassandra:reference/sai-virtual-table-indexes.adoc[Virtual tables for SAI indexes and SSTables]. + +== SAI tracing + +SAI provides tracing capability just like other database components. +Information is captured by the `system_traces` keyspace. +You can enable tracing in CQLSH with `TRACING ON`, or in the Cassandra driver with `statement.enableTracing()`. + +The number of rows filtered by a particular query will show up in the CQL query trace. +Example: + +[source,no-highlight] +---- +Index query accessed memtable indexes, 2 SSTable indexes, and 2 segments, post-filtered 14 rows in 14 partitions, and took 88582 microseconds. +---- + +For details about tracing, refer to CQL xref:cassandra:managing/tools/cqlsh.adoc#tracing[TRACING]. + +[[saiMonitorMetrics]] +== SAI metrics + +SAI provides a number of metrics to help you monitor the health of your indexes. + +The categorized data: + +* Global indexing metrics +* Table query metrics +* Per query metrics +* Key fetch metrics +* Offset fetch metrics +* Token fetch metrics +* Column query metrics per index +* Terms metrics per index +* Range slice metrics + +For example, you can use metrics to get the current count of total partition reads since the node started for `cycling.cyclist_semi_pro`. +The keyspace and table were defined in xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]. +This metric's `ObjectName`: `org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=cycling,table=cyclist_semi_pro,scope=TableQueryMetrics,name=TotalPartitionReads`. + +The metrics are exposed via JMX, so any JMX-based tool can be used to monitor. + +[[saiGlobalIndexingMetrics]] +== Global indexing metrics + +---- +ObjectName: org.apache.cassandra.metrics,type=StorageAttachedIndex,name= +---- + +The global indexing metrics for this node are: + +* `ColumnIndexBuildsInProgress` -- The number of individual on-disk column indexes currently being built. +* `SegmentBufferSpaceLimitBytes` -- The limit on heap used to buffer SSTable index segments during compaction and index builds. ++ +[TIP] +==== +In cassandra.yaml, `segment_write_buffer_space_mb` limits the amount of heap used to build on-disk column indexes during compaction and initial builds. +The default is 1024 MB. +==== + +For example, if there is only one column index building, SAI can buffer up to `segment_write_buffer_space_mb`. +If there is one column index building per table across 8 compactors, each index will be eligible to flush once it reaches (`segment_write_buffer_space_mb / 8`) MBs. + +* `SegmentBufferSpaceUsedBytes` -- The heap currently being used to buffer SSTable index segments during compaction and index builds. + +[NOTE] +==== +At any given time, the minimum size for a flushing segment, in bytes, is (`SegmentBufferSpaceLimitBytes / ColumnIndexBuildsInProgress`). +==== + +[[saiIndexGroupMetrics]] +== Index group metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=,scope=IndexGroupMetrics,name= +---- + +The index group metrics for the given keyspace and table: + +* `DiskUsedBytes` -- Size in bytes on disk for the given table's SAI indices. +* `IndexFileCacheBytes` -- Size in bytes of memory used by the on-disk data structure of the per-column indices. +* `OpenIndexFiles` -- Number of open index files for the given table's SAI indices. + +== Key fetch metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=KeyFetch,name= +---- + +The key fetch metrics for the given keyspace and table: + +* `ChunkCacheHitRate` -- All-time chunk cache hit rate for keys during queries against the given table. +* `TotalChunkCacheLookups` -- All-time chunk cache lookups for keys during queries against the given table. +* `TotalChunkCacheMisses` -- All-time chunk cache misses for keys during queries against the given table. +* `ChunkCache(One|Five|Fifteen)HitRate` -- -minute chunk cache hit rate for keys during queries against the given table. + +== Offset fetch metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=OffsetFetch,name= +---- + +The offset fetch metrics for the given keyspace and table: + +* `ChunkCacheHitRate` -- All-time chunk cache hit rate for partition key SSTable offset fetches during queries against the given table. +* `TotalChunkCacheLookups` -- All-time chunk cache lookups for partition key SSTable offset fetches during queries against the given table. +* `TotalChunkCacheMisses` -- All-time chunk cache misses for partition key SSTable offset fetches during queries against the given table. +* `ChunkCache(One|Five|Fifteen)HitRate` -- -minute chunk cache hit rate for partition key SSTable offset fetches during queries against the given table. + +== Per query metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=PerQuery,name= +---- + +The per query metrics for the given keyspace and table include: + +* `RowsFiltered` -- A histogram of the number of rows post-filtered per query since the node started. +* `QueryLatency` -- Overall query latency percentiles (in microseconds) and one/five/fifteen minute query throughput. +* `PartitionReads` -- Histogram over the number of partitions read per query. +* `SSTableIndexesHit` -- Histogram over the number of SSTable indexes read per query. +* `KDTreeChunkCacheLookups` -- Histogram over the number of chunk cache lookups while reading kd-tree index files per query. +* `KDTreeChunkCacheMisses` -- Histogram over the number of chunk cache misses while reading kd-tree index files per query. + +== Table query metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=TableQueryMetrics,name= +---- + +The table query metrics for the given keyspace and table: + +* `TotalPartitionReads` -- Total partition reads by all queries since the node started. +* `TotalQueriesCompleted` -- Total number of successfully completed queries since the node started. +* `TotalQueryTimeouts` -- Total number of timeouts from queries since the node started. +* `TotalRowsFiltered` -- Total number of rows post-filtered by all queries since the node started. + +[[saiTableStateMetrics]] +== Table state metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=TableStateMetrics,name= +---- + +The table state metrics for the given keyspace and table: + +* `DiskPercentageOfBaseTable` -- SAI size on Disk as a percentage of table size per table. +* `DiskUsedBytes` -- Size on-disk in bytes of SAI indices per table. +* `TotalIndexBuildsInProgress` -- Status of SAI indices per table currently in the `is_building` state. +* `TotalIndexCount` -- Total number of SAI indices per table. +* `TotalQueryableIndexCount` -- Status of SAI indices per table currently in the `is_querable` state. + +== Token fetch metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=TokenFetch,name= +---- + +The token fetch metrics for the given keyspace and table: + +* `ChunkCacheHitRate` -- All-time chunk cache hit rate for partition key token fetches during queries against the given table. +* `TotalChunkCacheLookups` -- All-time chunk cache lookups for partition key token fetches during queries against the given table. +* `TotalChunkCacheMisses` -- All-time chunk cache misses for partition key token fetches during queries against the given table. +* `ChunkCache(One|Five|Fifteen)HitRate` -- -minute chunk cache hit rate for partition key token fetches during queries against the given table. + +== Token skipping metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,scope=TokenSkipping,name= +---- + +The token skippping metrics for the given keyspace and table: + +* `CacheHits` -- Number of cache hits from token skipping in a multi-index `AND` query. +* `Lookups` -- Number of lookups from token skipping a multi-index `AND` query. + +== Column query metrics for each numeric index + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,index=,scope=ColumnQueryMetrics,name= +---- + +The column query metrics for the given keyspace, table, and index include: + +* `KDTreeNiceTryLatency` -- For numeric indexes, such as `age_sai_idx` in the xref:cassandra:getting-started/sai-quickstart.adoc[quickstart] examples, this metric may be used to present a histogram of the times spent waiting for chunk cache misses during kd-tree intersection (in microseconds) and one/five/fifteen minute chunk miss throughputs. ++ +[NOTE] +==== +The throughputs are zero if there are no cache misses during kd-tree intersection. +==== + +== Column query metrics for each string index + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,index=,scope=ColumnQueryMetrics,name= +---- + +The column query metrics for the given keyspace, table, and index include: + +* `TermsLookupLatency` -- For string indexes, such as `country_sai_idx` in the xref:cassandra:getting-started/sai-quickstart.adoc[quickstart] examples, this metric shows terms lookup latency percentiles (in microseconds) per one/five/fifteen minute query throughput. + +== Terms metrics for each string index + +---- +ObjectName: org.apache.cassandra.metrics:type=StorageAttachedIndex,keyspace=,table=
,index=,scope=Terms,name= +---- + +For string indexes, the terms metrics for the given keyspace, table, and index: + +* `ChunkCacheHitRate` -- All-time chunk cache hit rate for terms during string index queries that used the given index. +* `TotalChunkCacheLookups` -- All-time chunk cache lookups for terms during string index queries that used the given index. +* `TotalChunkCacheMisses` -- All-time chunk cache misses for terms during string index queries that used the given index. +* `ChunkCache(One|Five|Fifteen)HitRate` -- -minute chunk cache hit rate for terms during string index queries that used the given index. + +== Range slice metrics + +---- +ObjectName: org.apache.cassandra.metrics:type=ClientRequest,scope=RangeSlice,name= +---- + +The `RoundTripsPerReadHistogram` metric tracks the number of round-trip requests sent for range query commands from the coordinator. +Fewer requests typically mean the server is operating more efficiently than ones requiring more requests to satisfy the same range queries. + +Latency metric tracks the min, max, mean as well as a set of percentiles for range read requests latency. +Timeouts metric tracks the number of timeouts for range read requests. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/sai-operations.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/sai-operations.adoc new file mode 100644 index 0000000000..42619df370 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/operations/sai-operations.adoc @@ -0,0 +1,5 @@ += SAI operations +:description: Describes how to configure and monitor SAI operations. + +* xref:cassandra:developing/cql/indexing/sai/operations/configuring.adoc[Configuring SAI operations] +* xref:cassandra:developing/cql/indexing/sai/operations/monitoring.adoc[Monitoring SAI operations] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-concepts.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-concepts.adoc new file mode 100644 index 0000000000..fb19f15561 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-concepts.adoc @@ -0,0 +1,56 @@ += Storage-attached indexing (SAI) concepts +:navtitle: Concepts +:description: Use Storage-Attached Indexing (SAI) to create multiple secondary indexes on the same table. + +Storage-Attached Indexing (SAI) is a highly-scalable, globally-distributed index for +{cassandra} databases. + +The main advantage of SAI over existing indexes for {product} are: + +* enables vector search for AI applications +* shares common index data across multiple indexes on same table +* alleviates write-time scalability issues +* significantly reduced disk usage +* great numeric range performance +* zero copy streaming of indexes + +In fact, SAI provides the most indexing functionality available for {product}. +SAI adds column-level indexes to any CQL table column of almost any CQL data type. + +SAI enables queries that filter based on: + +* vector embeddings +* AND/OR logic for numeric and text types +* IN logic (use an array of values) for numeric and text types +* numeric range +* non-variable length numeric types +* text type equality +* CONTAINs logic (for collections) +* tokenized data +* row-aware query path +* case sensitivity (optional) +* unicode normalization (optional) + +== Advantages + +Defining one or more SAI indexes based on any column in a database table subsequently gives you the ability to run performant queries that specify the indexed column. +Especially compared to relational databases and complex indexing schemes, SAI makes you more efficient by accelerating your path to developing apps. + +SAI is deeply integrated with the storage engine of Cassandra. +The SAI functionality indexes the in-memory memtables and the on-disk SSTables as they are written, and resolves the differences between those indexes at read time. +Consequently, the design of SAI has very little operational complexity on top of the core database. +From snapshot creation, to schema management, to data expiration, SAI integrates tightly with the capabilities and mechanisms that the core database already provides. + +SAI is also fully compatible with zero-copy streaming (ZCS). +Thus, when you bootstrap or decommission nodes in a cluster, the indexes are fully streamed with the SSTables and not serialized or rebuilt on the receiving node's end. + +At its core, SAI is a filtering engine, and simplifies data modeling and client applications that would otherwise rely heavily on maintaining multiple query-specific tables. + +== Performance + +SAI outperforms any other indexing method available for {product}. + +SAI provides more functionality than secondary indexing (2i), using a fraction of the disk space, and reducing the total cost of ownership (TCO) for disk, infrastructure, and operations. +For read path performance, SAI performs at least as well as the other indexing methods for throughput and latency. + +include::_sai-read-write-paths.adoc[leveloffset=+1] diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-faq.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-faq.adoc new file mode 100644 index 0000000000..45cec54441 --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-faq.adoc @@ -0,0 +1,353 @@ += SAI FAQ +:description: Frequently asked questions about Storage-Attached Indexing (SAI). + +Use this FAQ to find answers to common questions and get help with Storage-Attached Indexing (SAI). + +== What is SAI? + +Storage-Attached Indexing (SAI) is a highly-scalable, globally-distributed index for the {cassandra} database. +SAI combines: + +* the storage-attached architecture of open source SSTable Attached Secondary Indexes (SASI) +* a number of highly optimized on-disk index structures + +== Which databases are supported? + +include::cassandra:partial$sai/support-databases.adoc[] + +After creating your database, a keyspace, and one or more tables, use `+CREATE CUSTOM INDEX ... +USING 'StorageAttachedIndex'+` to define one or more SAI indexes on the table. +For Cassandra databases, use `cqlsh`. +The same `+CREATE CUSTOM INDEX ... +USING 'StorageAttachedIndex'+` command is available for both. +See xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]. + +== What configuration settings should I use with SAI? + +Compared with most indexing environments, SAI configuration and related settings are much simpler. +Key points: + +* Increase `--XX:MaxDirectMemorySize`, leaving approximately 15-20% of memory for the OS and other in-memory structures. +* In cassandra.yaml, explicitly set `file_cache_size_in_mb` to 75% of that value. +* Heavy mixed read/write workloads may want to: + ** Decrease `range_request_timeout_in_ms` + ** Increase `write_request_timeout_in_ms` +* If the `memtable_flush_writers` value is set too low, writes may stall. +If this occurs in your environment, increase `memtable_flush_writers`. + +Aside from memory, SAI uses the same tunable parameters for Cassandra, such as compaction throughput and compaction executors. +This matters for write performance. +For read performance, again, maximizing use of the Chunk Cache will benefit SAI reads because all on-disk index components are accessed through this mechanism. +Refer to xref:cassandra:developing/cql/indexing/sai/configuring.adoc[Configure SAI indexes]. + +== What computing challenges does SAI solve? + +Oftentimes, developers ask: "How can I query additional fields outside of the {product} partition key?" + +SAI implements efficient indexes based on a table's columns, such as parts of a composite partition key. +Before SAI, you could index clustering keys, but you could not index parts of a composite partition. +The development of SAI was inspired by SASI to achieve the goal of efficient and simpler filtering via the creation of secondary indexes. + +SAI also makes data modeling easier because you do not need to create custom tables just to cater to particular query patterns. +You can create a table that is most natural for you, write to just that table, and query it any way you want. + +== What are the advantages of using SAI? + +SAI makes it possible to define multiple indexes on the same database table. +Each SAI index can be based on any column in the table. +Exception: there is no need to define an SAI index based on the partition key when it's comprised of only one column; +in this case, SAI issues an `invalid query` message. +You can also define an SAI index using a single column in the table's composite partition key. +A composite partition key means that the partition is based on two or more columns. +In this case with an SAI index, you would specify just one of the columns that comprises the composite partition key. + +For developers, SAI removes several previous pain points, including the need to duplicate denormalized data to query non-PrimaryKey columns. + +For operators, SAI has several advantages, including the use of significantly less disk space for indexing; +fewer failure points; +easier uptime due to the simplified architecture of SAI; +and fewer copies of data to secure. + +== Is SAI a complete search solution? + +SAI is not an enterprise search engine. +While it does provide some of the same functionality, SAI is not a complete replacement for text-based search. +At its core, SAI is a filtering engine, and simplifies data modeling and client applications that would otherwise rely heavily on maintaining multiple query-specific tables. + +== How does schema management compare between SAI and text-based search? + +SAI is an index, not a search engine. +Unlike the text-based search, SAI has no need for schema management. +SAI configuration is simpler and is tuned with existing database parameters, such as in cassandra.yaml. +With SAI, there is no commit log to accept writes during bootstrap; +SAI does not need to wait for bootstrap to read the database configuration. +With SAI, schema/indexing options reside in the index metadata, which is handled by native database schema management. + +== How do I use SAI features? +Storage-Attached Indexing has queries are entirely CQL-based. +The features, by design, are intentionally simple and easy to use. + +At a high level, SAI indexes are: + +* Created and dropped per column via CQL `+CREATE CUSTOM INDEX ... +USING 'StorageAttachedIndex'+` commands and `DROP INDEX` commands. +Start in xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]. + +* Rebuilt and backed up via nodetool. +See xref:cassandra:managing/tools/nodetool/toolsNodetool.html[nodetool]. + +* Monitored via a combination of nodetool, CQL virtual tables, system metrics, and JMX. +See xref:cassandra:developing/cql/indexing/sai/monitoring.adoc[Monitor SAI indexes]. + +[[saiLimitsFaq]] +== Are there limits on the number of SAI indexes per table, and total per cluster? + +include::cassandra:partial$sai/config-limits.adoc[] + +== On which column in a database table can I base an SAI index? + +Define each SAI index on any table column. +Exception: there is no need to define an SAI index based on the partition key when it's comprised of only one column; +in this case, SAI issues an `invalid query` message. + +You can also define an SAI index using a single column in the table's composite partition key. +A composite partition key means that the partition is based on two or more columns. +In this case with an SAI index, you would specify just one of the columns that comprises the composite partition key. + +With collection maps, you can define one or more SAI indexes on the same column, specifying `keys`, `values`, and `entries` as map types. +SAI also supports `list` and `set` collections. + +-- +include::cassandra:partial$sai/collections-note.adoc[] +-- + +== When I `DROP` and recreate an SAI index on the same column, does that block any read operations? And is there a way to check the indexing status? + + +-- +include::cassandra:partial$sai/queryable-paragraph.adoc[] +-- + +See xref:cassandra:developing/cql/indexing/sai/monitoring.adoc#saiMonitorVirtualTables[Virtual tables] and xref:reference:system-virtual-tables/virtual-tables-sai-indexes.adoc[Virtual tables for SAI indexes and SSTables]. + +== What are the write and read paths used by SAI indexes? + +SAI indexes Memtables and SSTables as they are written, resolving the differences between those indexes at read time. +See xref:cassandra:developing/cql/indexing/sai/read-write-paths.adoc[SAI write path and read path]. + +== What on-disk index formats does SAI support? + +SAI supports two on-disk index formats, optimized for: + +* Equality and non-exact matching on *strings*. +** Strings are indexed on-disk using the https://en.wikipedia.org/wiki/Trie[trie] data structure, in conjunction with postings (term/row pairs) lists. +The trie is heap friendly, providing string prefix compression for terms, and can match any query that can be expressed as a deterministic finite automaton. +The feature minimizes on-disk footprint and supports simple token skipping. + +* Equality and range queries on *numeric and non-literal types*. +** Numeric values and the other non-literal CQL types (`timestamp`, `date`, `UUID`) are indexed on-disk using https://en.wikipedia.org/wiki/K-d_tree[k-dimensional tree], a balanced structure that provides fast lookups across one or more dimensions, and compression for both values and postings. + +== What is the disk footprint overhead for SAI indexes? + +SAI requires significantly lower disk usage compared to other native or bolt-on Cassandra index solutions. +SAI produces an additional 20-35% disk usage compared with *unindexed* data. +The SAI disk usage is largely dependent on the underlying data model and the number of columns indexed. + +== What are the supported column data types for SAI indexing? + +The supported types are: `ASCII, BIGINT, DATE, DECIMAL, DOUBLE, FLOAT, INET, INT, SMALLINT, TEXT, TIME, TIMESTAMP, TIMEUUID, TINYINT, UUID, VARCHAR, VARINT`. + +[NOTE] +==== +* `INET` support for IPv4 and IPv6 was new starting with Cassandra ???. +* The `DECIMAL` and `VARINT` support was new starting with Cassandra ???. +* SAI also supports collections -- see the xref:#saiCollectionColumnFaq[next FAQ]. +==== + +[[saiCollectionColumnFaq]] +== Does SAI support indexes on a collection column? + +Yes -- SAI supports collections of type `map`, `list`, and `set`. +See the following topics: + +* xref:cassandra:developing/cql/indexing/sai/collections.adoc#saiUsingCollections[Using collections with SAI] +* xref:cassandra:developing/cql/indexing/sai/collections.adoc#saiUsingCollectionsMapExamples[SAI collection map examples with keys, values, and entries] +* xref:cassandra:developing/cql/indexing/sai/collections.adoc#saiUsingCollectionsListAndSetExamples[SAI collection examples with list and set types] +// * xref:reference:cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX] + +include::cassandra:partial$sai/collections-note.adoc[] + +== What are the supported query operators? + +For queries on tables with SAI indexes: + +include::cassandra:partial$sai/supported-query-operators-list.adoc[] + +The unsupported query operators are: + +include::cassandra:partial$sai/notSupportedOperators.adoc[] + +Examples: + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_semi_pro_select_date_range.cql[tag=cyclistSelectDateRange] +---- + +[source,language-cql] +---- +SELECT * FROM audit WHERE text_map CONTAINS KEY 'Giovani'; +---- + +[TIP] +==== +For query examples with `CONTAINS` clauses that take advantage of SAI collection maps, lists, and sets, be sure to see xref:cassandra:developing/cql/indexing/sai/collections.adoc#saiUsingCollectionsMapExamples[SAI collection map examples with keys, values, and entries] and xref:cassandra:developing/cql/indexing/sai/collections.adoc#saiUsingCollectionsListAndSetExamples[SAI collection examples with list and set types]. +==== + +== On the `CREATE CUSTOM INDEX` command for SAI, what options are available? + +Use the `WITH OPTIONS` clause to indicate how SAI should handle case sensitivity and special characters in the index. +For example, given a string column `lastname`: + +[source,language-cql] +---- +CREATE CUSTOM INDEX lastname_sai_idx ON cycling.cyclist_semi_pro (lastname) + USING 'StorageAttachedIndex' WITH OPTIONS = + {'case_sensitive': 'false', 'normalize': 'true', 'ascii': 'true'}; +---- + +[TIP] +==== +SAI added the `ascii` option with the DSE 6.8.7 release. +The default is `false`. +When set to `true`, SAI converts alphabetic, numeric, and symbolic characters that are not in the Basic Latin Unicode block (the first 127 ASCII characters) to the ASCII equivalent, if one exists. +For example, this option changes à to a. + +See xref:reference:cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX] and examples in the xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart] topic. +==== + +== Does SAI support composite indexing: meaning, a single index on multiple columns? + +No. +There is a 1-to-1 mapping of an SAI index to a column. +However, you can create a separate index on each column in a given table. +Also, SAI can use multiple defined indexes within a single read query. + +== How can I view SAI memory usage metrics? + +SAI follows the Threads Per Core (TPC) memory model for DSE. +The SAI memory footprint is divided between the JVM heap and the Chunk Cache. +The heap stores memtable indexes, and the chunk cache stores recently accessed on-disk index components as well as other SSTable components. +SAI provides metrics for both the heap and the chunk cache. +For each index, SAI also provides metrics for determining the size in bytes of memory used by the on-disk data structure, as well as disk usage. +Refer to xref:cassandra:developing/cql/indexing/sai/monitoring.adoc#saiIndexGroupMetrics[Index group metrics]. +SAI also provides Table state metrics that give you visibility into the disk usage, the percentage of disk usage of the base table, the index builds in progress, and related metrics. +See xref:cassandra:developing/cql/indexing/sai/monitoring.adoc#saiTableStateMetrics[Table state metrics]. +These metrics and many others are accessible via DSE OpsCenter. + +[[saiAndQueriesFaq]] +== What is the performance impact of adding SAI columns to a read query? How many `AND` clauses can I add? + +There is no limit on the number of index columns that can be used in a single query. +The `sai_indexes_per_table_failure_threshold` setting in cassandra.yaml controls the maximum number of SAI indexes allowed in a single table (10, by default). +However, querying against multiple indexed columns incurs a cost that is related to the increased number of index components processed. +When evaluating multiple indexed columns in a query, SAI performs a workflow (1: Traverse. +2: Merged. +3: Intersect that ultimately coalesces data from multiple memtables and SSTables. + +[NOTE] +==== +In a query, AND queries will process up to two SAI indexes; +if more than two SAI indexes are used by the query, this circumstance will result in SAI performing post-filtering on the remaining clauses. +==== + +For related information, see the xref:cassandra:developing/cql/indexing/sai/read-write-paths.adoc#saiMatchStreamingAndPostFiltering[match streaming and post filtering] example. + +[[saiWritesSyncFaq]] +== Are SAI write operations asynchronous, or does SAI wait before acknowledging the write to the user? + +The SAI write path is actually very simple. +The indexes live with the data, both in memtables and SSTables. +When a write is acknowledged to the client, the data is already indexed. +This is a *synchronous* process. +When the memtable is flushed, the indexes are flushed as well. +See xref:cassandra:developing/cql/indexing/sai/read-write-paths.adoc[SAI write path and read path]. + +The on-disk index components are broken down into per-SSTable index files and per-column index files. +The column indexes do not store the primary keys or tokens; +instead, they store compressible row IDs. +The per-SSTable index files link the row IDs from the column-indexes to their backing SSTables. +This SAI design allows all column indexes within a single SSTable to share per-SSTable index files, which further helps reduce the disk footprint. + +== What are the guidelines regarding column cardinality with SAI indexes? + +Column https://en.wikipedia.org/wiki/Cardinality_(SQL_statements)[cardinality] can affect read performance when it comes to range queries among replicas. +The number of rows matching a value of a high-cardinality column, such as credit card numbers, is more likely to be isolated on very few nodes (or even isolated to one node), while the rows matching a value on a low-cardinality column are more likely to reside on numerous nodes. +If a query does not specify a partition key, the Cassandra coordinator scans the token ring and group token ranges by endpoints (nodes). +The coordinator then concurrently execute read commands for all participating endpoints. +In the worst case where the indexed column has very high cardinality, an entire cluster scan may be required before finding a match. +With low-cardinality columns, be aware that if your `LIMIT` is higher than the number of values in your targeted column, Cassandra has to search all replicas again before determining that the `LIMIT` cannot be satisfied. +In this case, Cassandra returns only the number of matching results. + +== What are the circumstances under which SAI applies post filtering? +SAI applies post-filtering in numerous scenarios. +For example, consider a simple table, and an SAI index on just one of the two non-PK columns: + +[source,language-cql] +---- +CREATE KEYSPACE test WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1}; +CREATE TABLE test.mytable (id int PRIMARY KEY, + col1 text, + col2 timestamp); +CREATE CUSTOM INDEX mytable_col1_idx ON test.mytable (col1) USING 'StorageAttachedIndex'; +---- + +Given a query such as the following: + +[source,language-cql] +---- +SELECT * FROM test.mytable WHERE col1 = 'hello world' and col2 < toTimestamp(now()) ALLOW FILTERING; +---- + +For this query, Cassandra narrows down the search by the indexed column (`col1`) first, then applies post-filtering on `col2`. +(Use the `ALLOW FILTERING` clause with caution.) In this scenario, no additional replica roundtrips are needed; +the post filtering on `col2` is carried out on the replicas themselves. + +Another case were post-filtering comes into play is when constructing a query that involves more than two SAI indexes. +Refer to this xref:#saiAndQueriesFaq[related FAQ] about `AND` queries. + +== Can I create an SAI index based on a xref:reference:static.adoc[static column]? + +Yes. +For example, consider a `transaction_by_customer` table where you have a primary key `customer_id`, plus static columns to contain each customer's `address`, `phone_number`, and `date_of_birth`. +Given a query like: + +[source,language-cql] +---- +SELECT * from transaction_by_customer where customer_id = 'xyz123'; +---- + +If there are 100,000 `transaction_by_customer` rows, because you defined those three static fields, this query runs against a table that uses significantly less disk space, as compared to an environment where writes had inserted the per-customer values (`address`, `phone_number`, `date_of_birth`) in every row. + +[NOTE] +==== +SAI delivers the option and advantage of creating indexes based on static columns, while also achieving the benefit of conserving table space. +==== + +== For indexed strings, how does SAI handle Unicode characters in the column data? + +When you create an SAI index based on a string column, set the `normalize` option to `true` if you want SAI to perform Unicode normalization on the column data. +SAI supports Normalization Form C (NFC) Unicode. +When set to `true`, SAI normalizes the different versions of a given Unicode character to a single version, retaining all the marks and symbols in the index. +For example, SAI would change the character Å (U+212B) to Å (U+00C5). +See xref:reference:cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX]. + +== Can the index's column name have special characters? + +SAI validates the column name on which an index is being defined. +SAI allows alphanumeric characters and underscores only. +SAI returns `InvalidRequestException` if you try to define an index on a column name that contains other characters, and does not create the index. + +== What partitioner does SAI support? + +SAI supports only the xref:cassandra:architecture/dbArch/archPartitioners.adoc[Murmur3Partitioner]. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-overview.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-overview.adoc new file mode 100644 index 0000000000..186e2ccbea --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-overview.adoc @@ -0,0 +1,27 @@ += Storage-Attached Indexing (SAI) Overview +:navtitle: SAI Overview +:description: Storage-attached indexes (SAI). + +Storage-Attached Indexing (SAI) lets you create one or multiple secondary indexes on the same database table, with each SAI index based on any single column. + +*Exception:* There is no need to define an SAI index based on a single-column partition key. + +xref:cassandra:developing/cql/indexing/sai/sai-concepts.adoc[SAI concepts]:: +Use Storage-Attached Indexing (SAI) to create multiple secondary indexes on the same table. + +xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]:: +Follow the steps to get started quickly with SAI. + +xref:cassandra:developing/cql/indexing/sai/sai-faq.adoc[SAI FAQs]:: +Frequently asked questions about SAI. + +xref:developing/cql/indexing/sai/sai-working-with.adoc[Working with SAI]:: +Create, check, alter, drop, and query SAI. + +xref:developing/cql/indexing/sai/operations/sai-operations.adoc[SAI operations]:: +Configuring and monitoring SAI indexes. + +xref:cassandra:developing/cql/indexing/sai/sai-query.adoc[Querying with SAI]:: +Understand the columns on which you can define SAI indexes and run queries. + +*Reference:* xref:cassandra:reference/cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX], xref:cassandra:reference/cql-commands/drop-index.adoc[DROP INDEX] diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-working-with.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-working-with.adoc new file mode 100644 index 0000000000..2b59e39d7d --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-working-with.adoc @@ -0,0 +1,16 @@ += Working with Storage-attached indexing (SAI) +:navtitle: Working with SAI +:description: CRUD operations on SAI + querying with SAI + +== Prerequisites + +* xref:developing/keyspace-create.adoc[Keyspace created] +* xref:developing/table-create.adoc[Table created] + +include::_sai-create.adoc[leveloffset=+1] + +include::_sai-alter.adoc[leveloffset=+1] + +include::_sai-drop.adoc[leveloffset=+1] + +include::_sai-query.adoc[leveloffset=+1] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/json.adoc b/doc/modules/cassandra/pages/developing/cql/json.adoc index eb5a6e81ed..c490de23fb 100644 --- a/doc/modules/cassandra/pages/developing/cql/json.adoc +++ b/doc/modules/cassandra/pages/developing/cql/json.adoc @@ -1,7 +1,7 @@ = JSON Support -Cassandra 2.2 introduces JSON support to `SELECT ` and -`INSERT ` statements. +Cassandra 2.2 introduced JSON support to `SELECT ` and +`INSERT ` statements. This support does not fundamentally alter the CQL API (for example, the schema is still enforced). It simply provides a convenient way to work with JSON documents. @@ -122,4 +122,4 @@ selection clause of a `SELECT` statement. The `to_json()` function may be used similarly to `SELECT JSON`, but for a single column value. It may only be used in the selection clause of a -`SELECT` statement. +`SELECT` statement. \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_conceptual.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_conceptual.adoc index 86fdd1d74a..ca59a38800 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_conceptual.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_conceptual.adoc @@ -1,4 +1,4 @@ -= Conceptual Data Modeling += Conceptual data modeling First, let’s create a simple domain model that is easy to understand in the relational world, and then see how you might map it from a diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_logical.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_logical.adoc index 0e1ad95f40..82aeb5d114 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_logical.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_logical.adoc @@ -1,4 +1,4 @@ -= Logical Data Modeling += Logical data modeling Now that you have defined your queries, you're ready to begin designing Cassandra tables. First, create a logical model containing a table for diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_physical.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_physical.adoc index d2cdcd7d34..1328e459be 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_physical.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_physical.adoc @@ -1,4 +1,4 @@ -= Physical Data Modeling += Physical data modeling Once you have a logical data model defined, creating the physical model is a relatively simple process. diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_queries.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_queries.adoc index c62972228e..3a4fb8d54a 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_queries.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_queries.adoc @@ -1,4 +1,4 @@ -= Defining Application Queries += Defining application queries Let's try the query-first approach to start designing the data model for a hotel application. The user interface design for the application is diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_rdbms.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_rdbms.adoc index c8361df246..3de1210a55 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_rdbms.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_rdbms.adoc @@ -1,4 +1,4 @@ -= RDBMS Design += RDBMS design When you set out to build a new data-driven application that will use a relational database, you might start by modeling the domain as a set of diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_refining.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_refining.adoc index e2f77c4385..d613c2cea8 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_refining.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_refining.adoc @@ -1,4 +1,4 @@ -= Evaluating and Refining Data Models += Evaluating and refining data models :stem: latexmath Once you've created a physical model, there are some steps you'll want diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_schema.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_schema.adoc index a2dc9f67ca..68c0cfcea7 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_schema.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_schema.adoc @@ -1,4 +1,4 @@ -= Defining Database Schema += Defining database schema Once you have finished evaluating and refining the physical model, you're ready to implement the schema in CQL. Here is the schema for the diff --git a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_tools.adoc b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_tools.adoc index 608caaaff2..879f3f5ff5 100644 --- a/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_tools.adoc +++ b/doc/modules/cassandra/pages/developing/data-modeling/data-modeling_tools.adoc @@ -1,4 +1,4 @@ -= Cassandra Data Modeling Tools += Cassandra data modeling tools There are several tools available to help you design and manage your Cassandra schema and build queries. diff --git a/doc/modules/cassandra/pages/getting-started/cassandra-quickstart.adoc b/doc/modules/cassandra/pages/getting-started/cassandra-quickstart.adoc new file mode 100644 index 0000000000..c0eb9070b5 --- /dev/null +++ b/doc/modules/cassandra/pages/getting-started/cassandra-quickstart.adoc @@ -0,0 +1,102 @@ += Cassandra Quickstart + +== STEP 1: GET CASSANDRA USING DOCKER + +You'll need to have Docker Desktop for Mac, Docker Desktop for Windows, or similar software installed on your computer. + +Apache Cassandra is also available as a tarball or package xref:_/download.adoc[download]. + +[source, console] +---- +include::cassandra:example$BASH/docker_pull.sh[] +---- + +== STEP 2: START CASSANDRA + +A Docker network allows us to access the container's ports without exposing them on the host. + +[source, console] +---- +include::cassandra:example$BASH/docker-network-run.sh[] +---- + +== STEP 3: CREATE FILES + +The Cassandra Query Language (CQL) is very similar to SQL but suited for the JOINless structure of Cassandra. + +Create a file named data.cql and paste the following CQL script in it. This script will create a keyspace, the layer at which Cassandra replicates its data, a table to hold the data, and insert some data into that table: + +[source, cql] +---- +include::cassandra:example$CQL/create-keyspace-store.cql[] + +include::cassandra:example$CQL/create-table-shopping-cart.cql[] + +include::cassandra:example$CQL/insert-shopping-cart-data.cql[] +---- + +== STEP 4: LOAD DATA WITH CQLSH + +The CQL shell, or `cqlsh`, is one tool to use in interacting with the database. +We'll use it to load some data into the database using the script you just saved. + +[source, console] +---- +include::cassandra:example$BASH/docker-run-cqlsh-load-data.sh[] +---- + +[NOTE] +==== +The cassandra server itself (the first docker run command you ran) takes a few seconds to start up. +The above command will throw an error if the server hasn't finished its init sequence yet, so give it a few seconds to spin up. +==== + +== STEP 5: INTERACTIVE CQLSH + +Much like an SQL shell, you can also of course use `cqlsh` to run CQL commands interactively. + +[source, console] +---- +include::cassandra:example$BASH/docker-run-cqlsh-quickstart.sh[] +---- + +This should get you a prompt like so: + +[source, console] +---- +include::cassandra:example$RESULTS/docker-run-cqlsh-quickstart.result[] +---- + +== STEP 6: READ SOME DATA + +[source, cql] +---- +include::cassandra:example$CQL/select-data-from-shopping-cart.cql[] +---- + +== STEP 7: WRITE SOME MORE DATA + +[source, cql] +---- +include::cassandra:example$CQL/insert-more-data-shopping-cart.cql[] +---- + +== STEP 8: CLEAN UP + +[source, console] +---- +include::cassandra:example$BASH/docker-kill-and-remove.sh[] +---- + +== CONGRATULATIONS! + +Hey, that wasn't so hard, was it? + +To learn more, we suggest the following next steps: + +* Read through the xref:master@_:ROOT:cassandra-basics.adoc[Cassandra Basics] to learn main concepts and how Cassandra works at a high level. +* Browse through the xref:master@_:ROOT:case-studies.adoc[Case Studies] to learn how other users in our worldwide community are getting value out of Cassandra. + + + + diff --git a/doc/modules/cassandra/pages/getting-started/index.adoc b/doc/modules/cassandra/pages/getting-started/index.adoc index de6f2c7a44..d03f2eaec5 100644 --- a/doc/modules/cassandra/pages/getting-started/index.adoc +++ b/doc/modules/cassandra/pages/getting-started/index.adoc @@ -1,5 +1,12 @@ = Getting Started +== Quickstarts + +* xref:getting-started/cassandra-quickstart.adoc[Quickstart]: A quick introduction to Cassandra +* xref:getting-started/sai-quickstart.adoc[SAI Quickstart]: A quick introduction to the Storage Attached Index (SAI) feature + +== Additional information + This section covers how to get started using Apache Cassandra and should be the first thing to read if you are new to Cassandra. diff --git a/doc/modules/cassandra/pages/getting-started/quickstart.adoc b/doc/modules/cassandra/pages/getting-started/quickstart.adoc deleted file mode 100644 index 963d269190..0000000000 --- a/doc/modules/cassandra/pages/getting-started/quickstart.adoc +++ /dev/null @@ -1,116 +0,0 @@ -= Apache Cassandra Quickstart -:tabs: - -_Interested in getting started with Cassandra? Follow these instructions._ - -*STEP 1: GET CASSANDRA USING DOCKER* - -You'll need to have Docker Desktop for Mac, Docker Desktop for Windows, or -similar software installed on your computer. - -[source, plaintext] ----- -docker pull cassandra:latest ----- - -Apache Cassandra is also available as a https://cassandra.apache.org/download/[tarball or package download]. - -*STEP 2: START CASSANDRA* - -[source, plaintext] ----- -docker run --name cassandra cassandra ----- - -*STEP 3: CREATE FILES* - -In the directory where you plan to run the next step, create these two files -so that some data can be automatically inserted in the next step. - -A _cqlshrc_ file will log into the Cassandra database with the default superuser: - -[source, plaintext] ----- -[authentication] - username = cassandra - password = cassandra ----- - -Create a _scripts_ directory and change to that directory. -The following _data.cql_ file will create a keyspace, the layer at which Cassandra -replicates its data, a table to hold the data, and insert some data: - -[source, plaintext] ----- -# Create a keyspace -CREATE KEYSPACE IF NOT EXISTS store WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : '1' }; - -# Create a table -CREATE TABLE IF NOT EXISTS store.shopping_cart ( - userid text PRIMARY KEY, - item_count int, - last_update_timestamp timestamp -); - -# Insert some data -INSERT INTO store.shopping_cart -(userid, item_count, last_update_timestamp) -VALUES ('9876', 2, to_timestamp(to_date(now)))); -INSERT INTO store.shopping_cart -(userid, item_count, last_update_timestamp) -VALUES (1234, 5, to_timestamp(toDate(now)))); ----- - -You should now have a _cqlshrc_ file and _/scripts/data.cql_ file. - -*STEP 4: RUN CQLSH TO INTERACT* - -Cassandra is a distributed database that can read and write data across multiple -nodes with peer-to-peer replication. The Cassandra Query Language (CQL) is -similar to SQL but suited for the JOINless structure of Cassandra. The CQL -shell, or `cqlsh`, is one tool to use in interacting with the database. - -[source, plaintext] ----- -docker run --rm -it -v //scripts:/scripts \ --v / ] + ON [ .] () + | [ (KEYS()) ] + | [ (VALUES()) ] + | [ (ENTRIES()) ] + USING 'StorageAttachedIndex' + [ WITH OPTIONS = { } ] ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include::cassandra:partial$cql-syntax-legend.adoc[] +==== + +index_name:: +Optional identifier for index. +If no name is specified, the default is used, `__idx`. +Enclose in quotes to use special characters or to preserve capitalization. + +column_name:: +The name of the table column on which the SAI index is being defined. +SAI allows only alphanumeric characters and underscores in names. +SAI returns `InvalidRequestException` if you try to define an index on a column name that contains other characters, and does not create the index. + +map_name:: +// LLP FIX +Used with xref:cassandra:developing/collections/collection-create.adoc[collections], identifier of the `map_name` specified in `CREATE TABLE` ... +`map()`. +The regular column syntax applies for collection types `list` and `set`. + +option_map:: +Define options in JSON simple format. ++ +[cols="100,223"] +|=== +| Option | Description + +| `case_sensitive` +| Ignore case in matching string values. +Default: `true`. +| `normalize` +| When set to `true`, perform https://unicode.org/faq/normalization.html[Unicode normalization] on indexed strings. +SAI supports Normalization Form C (NFC) Unicode. +When set to `true`, SAI normalizes the different versions of a given Unicode character to a single version, retaining all the marks and symbols in the index. +For example, SAI would change the character Å (U+212B) to Å (U+00C5). + +When implementations keep strings in a normalized form, equivalent strings have a unique binary representation. +See https://unicode.org/reports/tr15/[Unicode Standard Annex #15, Unicode Normalization Forms]. + +Default: `false`. + +| `ascii` +| When set to `true`, SAI converts alphabetic, numeric, and symbolic characters that are not in the Basic Latin Unicode block (the first 127 ASCII characters) to the ASCII equivalent, if one exists. +For example, this option changes à to a. +Default: `false`. +| similarity_function +| Vector search relies on computing the similarity or distance between vectors to identify relevant matches. +The similarity function is used to compute the similarity between two vectors. +Valid options are: EUCLIDEAN, DOT_PRODUCT, COSINE +Default: `COSINE` +|=== + +== Query operators + +SAI supports the following query operators for tables with SAI indexes: + +include::cassandra:partial$sai/supported-query-operators-list.adoc[] + +SAI does not supports the following query operators for tables with SAI indexes: + +include::cassandra:partial$sai/notSupportedOperators.adoc[] + +== Examples + +These examples define SAI indexes for the `cycling.cyclist_semi_pro` table, which is demonstrated in the xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart]. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_semi_pro_sai_indices.cql[tag=createQuickStartIndices] +---- + +For sample queries that find data in `cycling.cyclist_semi_pro` via these sample SAI indexes, see xref:cassandra:getting-started/sai-quickstart.adoc#saiQuickStart__saiQuickStartSubmitQueries[Submit CQL queries]. +Also refer xref:cassandra:developing/indexing/sai/sai-query.adoc[Examine SAI column index and query rules]. + +[[saiCollectionsExamples]] +=== SAI collection map examples with keys, values, and entries + +// LLP FIX +The following examples demonstrate using collection maps of multiple types (`keys`, `values`, `entries`) in SAI indexes. +For related information, see xref:cassandra:developing/collections/collection-create.adoc[Creating collections] and xref:cassandra:developing/collections/map.adoc[Using map type]. + +Also refer to the SAI collection examples of type xref:#saiCreateCustomIndexCollectionsListAndSetExamples[list and set] in this topic. + +First, create the keyspace: + +[source,language-cql] +---- +CREATE KEYSPACE demo3 WITH REPLICATION = + {'class': 'SimpleStrategy', 'replication_factor': '1'}; +---- + +Next, use the keyspace: + +[source,language-cql] +---- +USE demo3; +---- + +Create an `audit` table, with a collection map named `text_map`: + +[source,language-cql] +---- +CREATE TABLE audit ( id int PRIMARY KEY , text_map map); +---- + +Create multiple SAI indexes on the same `map` column, each using `KEYS`, `VALUES`, and `ENTRIES`. + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON audit (KEYS(text_map)) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX ON audit (VALUES(text_map)) USING 'StorageAttachedIndex'; +CREATE CUSTOM INDEX ON audit (ENTRIES(text_map)) USING 'StorageAttachedIndex'; +---- + +Insert some data: + +[source,language-cql] +---- +INSERT INTO audit (id, text_map) values (1, {'Carlos':'Perotti', 'Marcel':'Silva'}); +INSERT INTO audit (id, text_map) values (2, {'Giovani':'Pasi', 'Frances':'Giardello'}); +INSERT INTO audit (id, text_map) values (3, {'Mark':'Pastore', 'Irene':'Cantona'}); +---- + +Query all data: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+--------------------------------------------- + 1 | {'Carlos': 'Perotti', 'Marcel': 'Silva'} + 2 | {'Frances': 'Giardello', 'Giovani': 'Pasi'} + 3 | {'Irene': 'Cantona', 'Mark': 'Pastore'} + +(3 rows) +---- +-- +==== + +Query using the SAI index for specific entries in the `map` column: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map['Irene'] = 'Cantona' AND text_map['Mark'] = 'Pastore'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+----------------------------------------- + 3 | {'Irene': 'Cantona', 'Mark': 'Pastore'} + +(1 rows) +---- +-- +==== + +Query using the SAI index for specific keys in the `map` column using `CONTAINS KEY`: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map CONTAINS KEY 'Giovani'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+--------------------------------------------- + 2 | {'Frances': 'Giardello', 'Giovani': 'Pasi'} + +(1 rows) +---- +-- +==== + +Query using the SAI index for specific values in the `map` column with `CONTAINS`: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM audit WHERE text_map CONTAINS 'Silva'; +---- +-- + +Result:: ++ +-- +[source,results] +---- + id | text_map +----+------------------------------------------ + 1 | {'Carlos': 'Perotti', 'Marcel': 'Silva'} + +(1 rows) +---- +-- +==== + +// tag::saiCollectionsReferenceNote[] +Remember that in CQL queries using SAI indexes, the `CONTAINS` clauses are supported with, and specific to: + +* SAI *collection maps* with `keys`, `values`, and `entries` +* SAI *collections* with `list` and `set` types +// end::saiCollectionsReferenceNote[] + +[[saiCreateCustomIndexCollectionsListAndSetExamples]] +=== SAI collection examples with list and set types + +These examples demonstrate using collections with the `list` and `set` types in SAI indexes. +For related information, see: +// LLP FIX +* xref:cassandra:developing/collections/collection-create.adoc[Creating collections] +* xref:cassandra:developing/collections/list.adoc[Using list type] +* xref:cassandra:developing/collections/set.adoc[Using set type] + +If you have not already, create the keyspace. + +[source,language-cql] +---- +CREATE KEYSPACE IF NOT EXISTS demo3 WITH REPLICATION = + {'class': 'SimpleStrategy', 'replication_factor': '1'}; +---- + +[source,language-cql] +---- +USE demo3; +---- + +==== Using the list type + +Create a `calendar` table with a collection of type `list`. + +[source,language-cql] +---- +CREATE TABLE calendar (key int PRIMARY KEY, years list); +---- + +Create an SAI index using the collection's `years` column. + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON calendar(years) USING 'StorageAttachedIndex'; +---- + +Insert some random `int` list data for `years`, just for demo purposes. + +[TIP] +==== +Notice the `INSERT` command's square brackets syntax for list values. + +[source,language-cql] +---- +INSERT INTO calendar (key, years) VALUES (0, [1990,1996]); +INSERT INTO calendar (key, years) VALUES (1, [2000,2010]); +INSERT INTO calendar (key, years) VALUES (2, [2001,1990]); +---- +==== + +Query with `CONTAINS` example: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM calendar WHERE years CONTAINS 1990; +---- +-- + +Result:: ++ +-- +[source,results] +---- + key | years +-----+-------------- + 0 | [1990, 1996] + 2 | [2001, 1990] +(2 rows) +---- +-- +==== + +This example created the `calendar` table with `years list`. +Of course, you could have created the table with `years list`, for example, inserted 'string' values, and queried on the strings. + +==== Using the set type + +Now create a `calendar2` table with a collection of type `set`. + +[source,language-cql] +---- +CREATE TABLE calendar2 (key int PRIMARY KEY, years set); +---- + +Create an SAI index using the collection's `years` column -- this time for the `calendar2` table. + +[source,language-cql] +---- +CREATE CUSTOM INDEX ON calendar2(years) USING 'StorageAttachedIndex'; +---- + +Insert some random `int` set data for `years`, again just for demo purposes. + +[TIP] +-- +Notice the `INSERT` command's curly braces syntax for set values. + +[source,language-cql] +---- +INSERT INTO calendar2 (key, years) VALUES (0, {1990,1996}); +INSERT INTO calendar2 (key, years) VALUES (1, {2000,2010}); +INSERT INTO calendar2 (key, years) VALUES (2, {2001,1990,2020}); +---- +-- + +Query with `CONTAINS` example from the list: + +[tabs] +==== +Query:: ++ +-- +[source, sql] +---- +SELECT * FROM calendar2 WHERE years CONTAINS 1990; +---- +-- + +Result:: ++ +-- +[source,results] +---- + key | years +-----+-------------------- + 0 | {1990, 1996} + 2 | {1990, 2001, 2020} + +(2 rows) +---- +-- +==== diff --git a/doc/modules/cassandra/pages/reference/cql-commands/create-index.adoc b/doc/modules/cassandra/pages/reference/cql-commands/create-index.adoc new file mode 100644 index 0000000000..d2d9771468 --- /dev/null +++ b/doc/modules/cassandra/pages/reference/cql-commands/create-index.adoc @@ -0,0 +1,389 @@ += CREATE INDEX +:description: Defines a new index for a single column of a table. + +{description} + +{product} supports creating an index on most columns, including the partition and cluster columns of a `PRIMARY KEY`, collections, and static columns. For maps, you can index using the key, value, or entries (a key:value pair). + +*See also:* xref:cassandra:reference/cql-commands/create-custom-index.adoc[CREATE CUSTOM INDEX] for Storage-Attached Indexes (SAI), xref:cassandra:reference/cql-commands/drop-index.adoc[DROP INDEX] + +== Syntax + +BNF definition: + +[source,bnf] +---- +include::example$BNF/index_name.bnf[] +---- + +// tag::syntax[] +---- +CREATE INDEX [ IF NOT EXISTS ] + ON [.] + ([ ( KEYS | FULL ) ] ) + (ENTRIES ) ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include::cassandra:partial$cql-syntax-legend.adoc[] +==== + +== Required parameters + +*table_name*:: +Name of the table to index. + +*column_name*:: +Name of the column to index. + +== Optional parameters + +*index_name*:: +Name of the index. +Enclose in quotes to use special characters or preserve capitalization. +If no name is specified, {product} names the index: `__idx`. + +*keyspace_name*:: +Name of the keyspace that contains the table to index. +If no name is specified, the current keyspace is used. + +== Usage notes + +If the column already contains data, it is indexed during the execution of this statement. +After an index has been created, it is automatically updated when data in the column changes. + +Indexing with the `CREATE INDEX` command can impact performance. +Before creating an index, be aware of when and xref:cassandra:developing/indexing/2i/2i-when-to-use.adoc#when-no-index[when not to create an index]. + +*Restriction:* Indexing counter columns is not supported. + +== Examples + +=== Creating an index on a clustering column + +Define a table having a xref:cassandra:reference/cql-commands/create-table.adoc#cqlPKcomposite[composite partition key], and then create an index on a clustering column. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=compositepk] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=createindex] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/select_all_from_rank_by_year_and_name-rank.cql[] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/select_all_from_rank_by_year_and_name-rank.result[] +---- +-- +==== + +=== Creating an index on a set or list collection + +Create an index on a set or list collection column as you would any other column. +Enclose the name of the collection column in parentheses at the end of the `CREATE INDEX` statement. +For example, add a collection of teams to the `cyclist_career_teams` table to index the data in the teams set. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=setColumn] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_career_teams-table.cql[tag=createidxset] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/select_all_from_cyclist_career_teams-team.cql[] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/select_all_from_cyclist_career_teams-team.result[] +---- +-- +==== + +[[CreatIdxCollKey]] +=== Creating an index on map keys + +You can create an index on xref:cassandra:developing/indexing/2i/2i-create-on-collection.adoc[map collection keys]. +If an index of the map values of the collection exists, drop that index before creating an index on the map collection keys. +Assume a cyclist table contains this map data where `nation is the map key and `Canada` is the map value`: + +[source,no-highlight] +---- +{'nation':'CANADA' } +---- + +To index map keys, use the `KEYS` keyword and map name in nested parentheses in the CREATE INDEX statement. +To run a `SELECT` query on the table, use xref:cassandra:reference/cql-commands/select.adoc#filtering-on-collections[CONTAINS KEY] in `WHERE` clauses. +This query returns cyclist teams that have an entry for the year 2015. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=mapColumn] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=keysidx] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/cyclist_teams-table.cql[tag=queryindexkey] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/cyclist_team-queries.result[] +---- +-- +==== + +=== Creating an index on map entries + +You can create an index on map entries. +An `ENTRIES` index can be created only on a map column of a table that doesn't have an existing index. + +To index collection entries, use the `ENTRIES` keyword and map name in nested parentheses. +To query the map entries in the table, use a `WHERE` clause with the map name and a value. +This query finds cyclists who are the same age. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=entriesidx] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=ageentryquery] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_age_23.result[] +---- +-- +==== + +Use the same index to find cyclists from the same country: + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=entriesidx] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationentryquery] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands.result[] +---- +-- +==== + +=== Creating an index on map values + +To create an index on map values, use the `VALUES` keyword and map name in nested parentheses. +To query the table, use a `WHERE` clause with the map name and the value it contains. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=blisttable] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=mapvaluesidx] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/birthday_list_map_entries-table.cql[tag=nationvaluesquery] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/select_from_birthday_list_where_nation_netherlands_2.result[] +---- +-- +==== + +=== Creating an index on the full content of a frozen collection + +You can create an index on a full `FROZEN` collection. +A `FULL` index can be created on a set, list, or map column of a table that doesn't have an existing index. + +Create an index on the full content of a `FROZEN` `list`. +The table in this example stores the number of Pro wins, Grand Tour races, and Classic races that a cyclist has competed in. +To index collection entries, use the `FULL` keyword and collection name in nested parentheses. +For example, index the frozen list `rnumbers`. +To query the table, use a `WHERE` clause with the collection name and values. + +[tabs] +==== +CREATE TABLE:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=frozenlist] +---- +-- + +CREATE INDEX:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=fullindex] +---- +-- + +SELECT query:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$CQL/sai/race_starts-table.cql[tag=selectrnumbers] +---- +-- + +SELECT result:: ++ +-- +[source,language-cql] +---- +include::cassandra:example$RESULTS/sai/race_starts-queries.result[] +---- +-- +==== \ No newline at end of file diff --git a/doc/modules/cassandra/pages/reference/cql-commands/drop-index.adoc b/doc/modules/cassandra/pages/reference/cql-commands/drop-index.adoc new file mode 100644 index 0000000000..7894acbbd8 --- /dev/null +++ b/doc/modules/cassandra/pages/reference/cql-commands/drop-index.adoc @@ -0,0 +1,35 @@ += DROP INDEX +:description: Removes an index from a table. + +Removes an existing index. +The default index name is `table_name_column_name_idx`. + +== Syntax + +BNF definition: + +[source,bnf] +---- +include::example$BNF/drop_index_statement.bnf[] +---- + +// tag::syntax[] +---- +DROP INDEX [ IF EXISTS ] [.] ; +---- +// end::syntax[] + +.Syntax legend +[%collapsible] +==== +include::cassandra:partial$cql-syntax-legend.adoc[] +==== + +== Example + +Drop the index `rank_idx` from the `cycling.rank_by_year_and_name` table. + +[source,language-cql] +---- +include::cassandra:example$CQL/sai/rank_by_year_and_name-table.cql[tag=dropindex] +---- diff --git a/doc/modules/cassandra/pages/reference/index.adoc b/doc/modules/cassandra/pages/reference/index.adoc new file mode 100644 index 0000000000..28e17467a8 --- /dev/null +++ b/doc/modules/cassandra/pages/reference/index.adoc @@ -0,0 +1,4 @@ += Reference + +* xref:cassandra:reference/cql-commands/commands-toc.adoc[CQL commands] +* xref:cassandra:reference/java17.adoc[Java 17 usage] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/getting-started/java11.adoc b/doc/modules/cassandra/pages/reference/java17.adoc similarity index 65% rename from doc/modules/cassandra/pages/getting-started/java11.adoc rename to doc/modules/cassandra/pages/reference/java17.adoc index 810a08f8f7..540886104e 100644 --- a/doc/modules/cassandra/pages/getting-started/java11.adoc +++ b/doc/modules/cassandra/pages/reference/java17.adoc @@ -1,115 +1,101 @@ -= Support for Java 11 - -In the new Java release cadence a new Java version is made available -every six months. The more frequent release cycle is favored as it -brings new Java features to the developers as and when they are -developed without the wait that the earlier 3 year release model -incurred. Not every Java version is a Long Term Support (LTS) version. -After Java 8 the next LTS version is Java 11. Java 9, 10, 12 and 13 are -all non-LTS versions. - -One of the objectives of the Apache Cassandra 4.0 version is to support -the recent LTS Java versions 8 and 11 -(https://issues.apache.org/jira/browse/CASSANDRA-9608[CASSANDRA-9608]). -Java 8 and Java 11 may be used to build and run Apache Cassandra 4.0. Effective Cassandra -4.0.2 there is full Java 11 support, it is not experimental anymore. - -== Support Matrix += Support for Java The support matrix for the Java versions for compiling and running -Apache Cassandra 4.0 is detailed in Table 1. The build version is along +{product} is detailed in Table 1. The build version is along the vertical axis and the run version is along the horizontal axis. -Table 1 : Support Matrix for Java - +.Support Matrix for Java [width="68%",cols="34%,30%,36%",] |=== -| |Java 8 (Run) |Java 11 (Run) -|Java 8 (Build) |Supported |Supported -|Java 11(Build) |Not Supported |Experimental +| | Java 11 (Run) | Java 17 (Run) +| Java 11 (Build) | Supported | Supported +| Java 17(Build) | Not Supported | Experimental |=== -Apache 4.0 source code built with Java 11 cannot be run with -Java 8. +Apache 4.0 source code built with Java 17 cannot be run with Java 11. +All binary releases are built with Java 11. -All binary releases are built with Java 8. +== Using Java 17 to Build -Next, we shall discuss using each of Java 8 and 11 to build and -run Apache Cassandra 4.0. +To start with, install Java 17. +As an example, for installing Java 17 on RedHat Linux the command is as follows: -== Using Java 8 to Build - -To start with, install Java 8. As an example, for installing Java 8 on -RedHat Linux the command is as follows: - -.... -$ sudo yum install java-1.8.0-openjdk-devel -.... +[source, console] +---- +$ sudo yum install java-17-openjdk +---- Set the environment variables `JAVA_HOME` and `PATH`. -.... -$ export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk +[source, console] +---- +$ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk $ export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin -.... +---- -Download and install Apache Cassandra 4.0 source code from the Git along +Download and install Apache Cassandra 5.0 source code from the Git along with the dependencies. -.... +[source, console] +---- $ git clone https://github.com/apache/cassandra.git -.... +---- If Cassandra is already running stop Cassandra with the following command. -.... +[source, console] +---- $ ./nodetool stopdaemon -.... +---- Build the source code from the `cassandra` directory, which has the `build.xml` build script. The Apache Ant uses the Java version set in the `JAVA_HOME` environment variable. -.... +[source, console] +---- $ cd ~/cassandra $ ant -.... +---- -Apache Cassandra 4.0 gets built with Java 8. Set the environment +Apache Cassandra 5.0 gets built with Java 11. Set the environment variable for `CASSANDRA_HOME` in the bash script. Also add the `CASSANDRA_HOME/bin` to the `PATH` variable. -.... +[source, console] +---- $ export CASSANDRA_HOME=~/cassandra $ export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$CASSANDRA_HOME/bin -.... +---- -To run Apache Cassandra 4.0 with either of Java 8 or Java 11 run the +To run Apache Cassandra 5.0 with either of Java 11 or Java 17 run the Cassandra application in the `CASSANDRA_HOME/bin` directory, which is in the `PATH` env variable. -.... +[source, console] +---- $ cassandra -.... +---- The Java version used to run Cassandra gets output as Cassandra is getting started. As an example if Java 11 is used, the run output should include similar to the following output snippet: -.... +[source, console] +---- INFO [main] 2019-07-31 21:18:16,862 CassandraDaemon.java:480 - Hostname: ip-172-30-3- 146.ec2.internal:7000:7001 INFO [main] 2019-07-31 21:18:16,862 CassandraDaemon.java:487 - JVM vendor/version: OpenJDK 64-Bit Server VM/11.0.3 INFO [main] 2019-07-31 21:18:16,863 CassandraDaemon.java:488 - Heap size: 1004.000MiB/1004.000MiB -.... +---- -The following output indicates a single node Cassandra 4.0 cluster has -started. +The following output indicates a single node Cassandra 5.0 cluster has started. -.... +[source, console] +---- INFO [main] 2019-07-31 21:18:19,687 InboundConnectionInitiator.java:130 - Listening on address: (127.0.0.1:7000), nic: lo, encryption: enabled (openssl) ... @@ -127,28 +113,30 @@ bootstrap because it is configured to be a seed node. INFO [main] 2019-07-31 21:18:20,809 StorageService.java:1507 - JOINING: Finish joining ring INFO [main] 2019-07-31 21:18:20,921 StorageService.java:2508 - Node 127.0.0.1:7000 state jump to NORMAL -.... +---- == Using Java 11 to Build -If Java 11 is used to build Apache Cassandra 4.0, first Java 11 must be -installed and the environment variables set. As an example, to download -and install Java 11 on RedHat Linux run the following command. +If Java 17 is used to build Apache Cassandra 5.0, first Java 11 must be installed and the environment variables set. +As an example, to download and install Java 11 on RedHat Linux run the following command. -.... -$ yum install java-11-openjdk-devel -.... +[source, console] +---- +$ yum install java-11-openjdk +---- Set the environment variables `JAVA_HOME` and `PATH`. -.... +[source, console] +---- $ export JAVA_HOME=/usr/lib/jvm/java-11-openjdk $ export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin -.... +---- The build output should now include the following. -.... +[source, console] +---- [echo] Non default JDK version used: 11 ... ... @@ -177,19 +165,19 @@ jar: BUILD SUCCESSFUL Total time: 1 minute 3 seconds -.... +---- == Common Issues -The Java 11 built Apache Cassandra 4.0 source code may be run with Java -11 only. If a Java 11 built code is run with Java 8 the following error -message gets output. +The Java 17 built Apache Cassandra 5.0 source code may be run with Java 17 only. +If a Java 17 built code is run with Java 11 the following error message gets output. -.... +[source, console] +---- # ssh -i cassandra.pem ec2-user@ec2-3-85-85-75.compute-1.amazonaws.com Last login: Wed Jul 31 20:47:26 2019 from 75.155.255.51 $ echo $JAVA_HOME -/usr/lib/jvm/java-1.8.0-openjdk +/usr/lib/jvm/java-11-openjdk $ cassandra ... ... @@ -202,5 +190,4 @@ class file versions up to 52.0 at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at ... ... -.... - +---- \ No newline at end of file diff --git a/doc/modules/cassandra/pages/reference/sai-virtual-table-indexes.adoc b/doc/modules/cassandra/pages/reference/sai-virtual-table-indexes.adoc new file mode 100644 index 0000000000..b273988123 --- /dev/null +++ b/doc/modules/cassandra/pages/reference/sai-virtual-table-indexes.adoc @@ -0,0 +1,329 @@ += Virtual tables for SAI indexes and SSTables +:description: Provides details about virtual tables for Storage Attached Indexing (SAI) indexes and SSTables. + +Storage Attached Indexing (SAI) provides CQL-based virtual tables that enable you to discover the current state of system metadata for SAI indices and associated SSTables. +These virtual tables reside in the `system_views` keyspace. + +For related information, see the xref:cassandra:developing/indexing/sai/sai-overview.adoc[SAI information]. + +== system_views.indexes + +The `system_views.indexes` virtual table contains stateful information about SAI indexes. +This view provides information at the column index level, including the index name, number of indexed SSTables, disk usage, and index state. +From the index state, the data reveals if the index is currently building, and whether the index can be queried. + +Use CQL to view the table's description. +Example: + +[source,language-cql] +---- +DESCRIBE TABLE system_views.indexes; +---- + +[source,results] +---- +/* +Warning: Table system_views.indexes is a virtual table and cannot be recreated with CQL. +Structure, for reference: +VIRTUAL TABLE system_views.indexes ( + keyspace_name text, + index_name text, + analyzer text, + cell_count bigint, + column_name text, + indexed_sstable_count int, + is_building boolean, + is_queryable boolean, + is_string boolean, + per_column_disk_size bigint, + per_table_disk_size bigint, + table_name text, + PRIMARY KEY (keyspace_name, index_name) +) WITH CLUSTERING ORDER BY (index_name ASC) + AND comment = 'Storage-attached column index metadata'; +*/ +---- + +To view the current data, submit a query such as: + +[source,language-cql] +---- +SELECT * FROM system_views.indexes; +---- + +[source,results] +---- + keyspace_name | index_name | analyzer | cell_count | column_name | indexed_sstable_count | is_building | is_queryable | is_string | per_column_disk_size | per_table_disk_size | table_name +---------------+----------------------+-------------------------------------------------------------+------------+--------------+-----------------------+-------------+--------------+-----------+----------------------+---------------------+------------------ + cycling | age_sai_idx | NoOpAnalyzer{} | 0 | age | 0 | False | True | False | 0 | 0 | cyclist_semi_pro + cycling | country_sai_idx | NonTokenizingAnalyzer{caseSensitive=false, normalized=true} | 0 | country | 0 | False | True | True | 0 | 0 | cyclist_semi_pro + cycling | lastname_sai_idx | NonTokenizingAnalyzer{caseSensitive=false, normalized=true} | 0 | lastname | 0 | False | True | True | 0 | 0 | cyclist_semi_pro + cycling | registration_sai_idx | NoOpAnalyzer{} | 0 | registration | 0 | False | True | False | 0 | 0 | cyclist_semi_pro + +(4 rows) +---- + +.system_views.indexes metadata +[%header, cols="14,10,30"] +|=== +h| Column name | CQL type | Meaning + +| `keyspace_name` +| `text` +| The name of the keyspace to which the index belongs. + +| `index_name` +| `text` +| The name of the index. + +| `analyzer` +| `text` +| The `toString` representation of the analyzer used by the index. + +| `cell_count` +| `bigint` +| The number of indexed table cells, or the number of index value-key entries. +This is the sum of the number of index entries in each SSTable. + +| `column_name` +| `text` +| The name of the indexed column. + +| `indexed_sstable_count` +| `int` +| The number of indexed SSTables. +Note that SSTables without relevant data won't be indexed or counted here. + +| `is_building` +| `boolean` +| Whether there is a on going build for the index. + +| `is_queryable` +| `boolean` +| Whether it is possible to query the index. +It won't be possible if the initial task build hasn't finished yet. + +| `is_string` +| `boolean` +| Whether the index is for a text field (`ascii`, `text`, or `varchar`). + +| `per_column_disk_size` +| `bigint` +| The on-disk size of the index components that are exclusive to the column, in bytes. + +| `per_table_disk_size` +| `bigint` +| The on-disk size of the index components that are shared with other SAI indexes for the same table, in bytes. + +| `table_name` +| `text` +| The name of the table to which the indexed column belongs. +|=== + +== system_views.sstable_indexes + +The `system_views.sstable_indexes` virtual table has a row per SAI index and SSTable. +This view describes individual SSTable indexes, and includes information around disk size, min/max row ID, the min/max ring token, and the write-time version of the index. + +Use CQL to view the table's description. +Example: + +[source,language-cql] +---- +DESCRIBE TABLE system_views.sstable_indexes; +---- + +[source,results] +---- +/* +Warning: Table system_views.sstable_indexes is a virtual table and cannot be recreated with CQL. +Structure, for reference: +VIRTUAL TABLE system_views.sstable_indexes ( + keyspace_name text, + index_name text, + sstable_name text, + cell_count bigint, + column_name text, + end_token text, + format_version text, + max_row_id bigint, + min_row_id bigint, + per_column_disk_size bigint, + per_table_disk_size bigint, + start_token text, + table_name text, + PRIMARY KEY (keyspace_name, index_name, sstable_name) +) WITH CLUSTERING ORDER BY (index_name ASC, sstable_name ASC) + AND comment = 'SSTable index metadata'; +*/ +---- + +To view the current data, submit a query such as: + +[source,language-cql] +---- +SELECT * FROM system_views.sstable_indexes; +---- + +.system_views.sstable_indexes metadata< +[%header, cols="14,10,30"] +|=== +h| Column name | CQL type | Meaning + +| `keyspace_name` +| `text` +| The name of the keyspace to which the index belongs. + +| `index_name` +| `text` +| The name of the index. + +| `sstable_name` +| `text` +| The name of the SSTable. + +| `cell_count` +| `bigint` +| The number of indexed table cells, or the number of index value-key entries. + +| `column_name` +| `text` +| The name of the indexed column. + +| `start_token` +| `text` +| The start of the token range covered by the indexed SSTable. + +| `end_token` +| `text` +| The end of the token range covered by the indexed SSTable. + +| `min_row_id` +| `bigint` +| The minimum row id in the SSTable index. + +| `max_row_id` +| `bigint` +| The maximum row id in the SSTable index. + +| `per_column_disk_size` +| `bigint` +| The on-disk size of the SSTable index components that are exclusive to the column, in bytes. + +| `per_table_disk_size` +| `bigint` +| The on-disk size of the SSTable index components that are shared with other SAI indexes for the same table, in bytes. + +| `table_name` +| `text` +| The name of the table to which the indexed column belongs. +|=== + +== system_views.sstable_index_segments + +The `system_views.sstable_index_segments` virtual table has a row per SAI index and SSTable segment. +This view describes the segments of the SSTable indexes. +It exposes the segment row ID offset and most of the information in the SSTable-level virtual table, specifically at a segment granularity. + +Use CQL to view the table's description. +Example: + +[source,language-cql] +---- +DESCRIBE TABLE system_views.sstable_index_segments; +---- + +[source,results] +---- +/* +Warning: Table system_views.sstable_index_segments is a virtual table and cannot be recreated with CQL. +Structure, for reference: +VIRTUAL TABLE system_views.sstable_index_segments ( + keyspace_name text, + index_name text, + sstable_name text, + segment_row_id_offset bigint, + cell_count bigint, + column_name text, + component_metadata frozen>>, + end_token text, + max_sstable_row_id bigint, + max_term text, + min_sstable_row_id bigint, + min_term text, + start_token text, + table_name text, + PRIMARY KEY (keyspace_name, index_name, sstable_name, segment_row_id_offset) +) WITH CLUSTERING ORDER BY (index_name ASC, sstable_name ASC, segment_row_id_offset ASC) + AND comment = 'SSTable index segment metadata'; +*/ +---- + +To view the current data, submit a query such as: + +[source,language-cql] +---- +SELECT * FROM system_views.sstable_index_segments; +---- + +.system_views.sstable_index_segments metadata +[%header, cols="10,11,17"] +|=== +h| Column name | CQL type | Meaning + +| `keyspace_name` +| `text` +| The name of the keyspace to which the index belongs. + +| `index_name` +| `text` +| The name of the index. + +| `sstable_name` +| `text` +| The name of the SSTable. + +| `segment_row_id_offset` +| `bigint` +| The row id offset for the SSTable segment. + +| `cell_count` +| `bigint` +| The number of indexed segments, or the number of index segments value-key entries. + +| `column_name` +| `text` +| The name of the indexed column. + +| `component_metadata` +| `frozen>>` +| The component metadata in the SSTable segment. + +| `end_token` +| `text` +| The end of the token range covered by the SSTable segment. + +| `max_sstable_row_id` +| `bigint` +| The maximum row id in the SSTable segment. + +| `max_term` +| `text` +| The maximum term in the SSTable segment. + +| `min_sstable_row_id` +| `bigint` +| The minimum row id in the SSTable segment. + +| `min_term` +| `text` +| The minimum term in the SSTable segment. + +| `start_token` +| `text` +| The start of the token range covered by the SSTable segment. + +| `table_name` +| `text` +| The name of the table to which the SSTable segment belongs. +|=== diff --git a/doc/modules/cassandra/partials/cql-syntax-legend.adoc b/doc/modules/cassandra/partials/cql-syntax-legend.adoc new file mode 100644 index 0000000000..1b4d8e9006 --- /dev/null +++ b/doc/modules/cassandra/partials/cql-syntax-legend.adoc @@ -0,0 +1,64 @@ +.Legend +|=== +| Syntax conventions | Description + +| UPPERCASE +| Literal keyword. + +| Lowercase +| Not literal. + +| `< >` +| Variable value. +Replace with a user-defined value. + +| `[]` +| Optional. +Square brackets (`[]`) surround optional command arguments. +Do not type the square brackets. + +| `( )` +| Group. +Parentheses ( `( )` ) identify a group to choose from. +Do not type the parentheses. + +| `\|` +| Or. +A vertical bar (`\|`) separates alternative elements. +Type any one of the elements. +Do not type the vertical bar. + +| `+...+` +| Repeatable. +An ellipsis ( `+...+` ) indicates that you can repeat the syntax element as often as required. + +| `''` +| Single quotation (`'`) marks must surround literal strings in CQL statements. +Use single quotation marks to preserve upper case. + +| `{ : }` +| Map collection. +Braces (`{ }`) enclose map collections or key value pairs. +A colon separates the key and the value. + +| `<,>` +| Set, list, map, or tuple. +Angle brackets ( `< >` ) enclose data types in a set, list, map, or tuple. +Separate the data types with a comma. + +| `;` +| End CQL statement. +A semicolon (`;`) terminates all CQL statements. + +| `[--]` +| Separate the command line options from the command arguments with two hyphens ( `--` ). +This syntax is useful when arguments might be mistaken for command line options. + +| `+' < ... +> '+` +| Search CQL only: Single quotation marks (`'`) surround an entire XML schema declaration. + +| `@=''` +| Search CQL only: Identify the entity and literal value to overwrite the XML element in the schema and solrConfig files. +|=== + diff --git a/doc/modules/cassandra/partials/sai/.config-limits.adoc b/doc/modules/cassandra/partials/sai/.config-limits.adoc new file mode 100644 index 0000000000..7fc741d015 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/.config-limits.adoc @@ -0,0 +1,6 @@ +By default in {product}: + +* The maximum number of SAI indexes per table is 10. +The limit is set by `sai_indexes_per_table_failure_threshold` in cassandra.yaml. +* The maximum number of SAI indexes in the entire cluster is 100, as set by `sai_indexes_total_failure_threshold` in cassandra.yaml. +// See the https://docs.datastax.com/en/dse/6.8/dse-admin/datastax_enterprise/config/configCassandra_yaml.html#configCassandra_yaml__guardrailsYaml[guardrails] section of the cassandra.yaml reference topic. diff --git a/doc/modules/cassandra/partials/sai/collections-note.adoc b/doc/modules/cassandra/partials/sai/collections-note.adoc new file mode 100644 index 0000000000..2e8a81326b --- /dev/null +++ b/doc/modules/cassandra/partials/sai/collections-note.adoc @@ -0,0 +1,12 @@ +[TIP] +==== +In CQL queries of database tables with SAI indexes, the `CONTAINS` clauses +are supported with, and specific to: + +* SAI *collection maps* with `keys`, `values`, and `entries` + +* SAI *collections* with `list` and `set` types + +For examples, +see xref:cassandra:developing/cql/indexing/sai/sai-query.adoc#saiUsingCollections[Using collections with SAI]. +==== diff --git a/doc/modules/cassandra/partials/sai/create-vector-index.adoc b/doc/modules/cassandra/partials/sai/create-vector-index.adoc new file mode 100644 index 0000000000..d06089b871 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/create-vector-index.adoc @@ -0,0 +1,10 @@ +== Create vector search index + +Create the custom index called `comment_vector` with Storage Attached Indexing (SAI): + +[source,cql] +---- +include::cassandra:example$CQL/create-vector-index-cycling.cql[] +---- + +For more about SAI, see the xref:developing:indexing/sai/sai-overview.adoc[Storage Attached Index] documentation. diff --git a/doc/modules/cassandra/partials/sai/create-vector-keyspace.adoc b/doc/modules/cassandra/partials/sai/create-vector-keyspace.adoc new file mode 100644 index 0000000000..4038f0c055 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/create-vector-keyspace.adoc @@ -0,0 +1,8 @@ +== Create vector search keyspace + +Create a new vector search keyspace called `cycling`: + +[source,cql] +---- +include::cassandra:getting-started/example$CQL/create-vector-keyspace-cycling.cql[] +---- \ No newline at end of file diff --git a/doc/modules/cassandra/partials/sai/create-vector-table.adoc b/doc/modules/cassandra/partials/sai/create-vector-table.adoc new file mode 100644 index 0000000000..fa03cb8598 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/create-vector-table.adoc @@ -0,0 +1,16 @@ +== Create vector search table + +Create a new table called `comments_vs` to store comments information: + +[source,cql] +---- +include::cassandra:getting-started/example$CQL/create-vector-table-cycling.cql[tag=createvstable] +---- + +Alternatively, if you didn't have a vector column in your original table, you could alter the original table to add a vector column `comment_vector` to store the embeddings: + +[source,cql] +---- +include::cassandra:getting-started/example$CQL/create-vector-table-cycling.cql[tag=altervstable] +---- +<1> Notice that the vector uses the `float` data type and specifies the array dimension of 5 to store the embeddings. \ No newline at end of file diff --git a/doc/modules/cassandra/partials/sai/load-vector-data.adoc b/doc/modules/cassandra/partials/sai/load-vector-data.adoc new file mode 100644 index 0000000000..5785db60d2 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/load-vector-data.adoc @@ -0,0 +1,10 @@ +== Load Vector Search data into your database + +Insert data into the table: + +[source,cql] +---- +include::cassandra:getting-started/example$CQL/insert-vector-data-cycling.cql[] +---- + +Note the format of the new `vector` data type. \ No newline at end of file diff --git a/doc/modules/cassandra/partials/sai/notSupportedOperators.adoc b/doc/modules/cassandra/partials/sai/notSupportedOperators.adoc new file mode 100644 index 0000000000..e50ffd156a --- /dev/null +++ b/doc/modules/cassandra/partials/sai/notSupportedOperators.adoc @@ -0,0 +1,7 @@ +// LLP NEED TO CHECK FOR C* 5.0 +ifeval::["{evalproduct}" == "dse"] +* Strings or Numerics: `LIKE`, `OR`, `IN` +endif::[] +ifeval::["{evalproduct}" != "dse"] +* Strings or Numerics: `LIKE` +endif::[] diff --git a/doc/modules/cassandra/partials/sai/query-vector-data.adoc b/doc/modules/cassandra/partials/sai/query-vector-data.adoc new file mode 100644 index 0000000000..9ae9c8156e --- /dev/null +++ b/doc/modules/cassandra/partials/sai/query-vector-data.adoc @@ -0,0 +1,30 @@ += Query vector data with CQL + +To query data using Vector Search, use a `SELECT` query: + +[tabs] +==== +CQL:: ++ +-- +[source,cql] +---- +include::cassandra:example$CQL/sai/select-vsearch-cycling.cql[] +---- +-- +Result:: ++ +-- +[source,cql] +---- +include::cassandra:example$RESULTS/sai/select-vsearch-cycling.result[] +---- +-- +==== + +[NOTE] +==== +The limit has to be 1,000 or fewer. +==== + +Scrolling to the right on the results shows the comments from the table that most closely matched the embeddings used for the query. \ No newline at end of file diff --git a/doc/modules/cassandra/partials/sai/queryable-paragraph.adoc b/doc/modules/cassandra/partials/sai/queryable-paragraph.adoc new file mode 100644 index 0000000000..0ef92638a5 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/queryable-paragraph.adoc @@ -0,0 +1,10 @@ +When you `DROP` / recreate an SAI index, you are not blocked from entering queries that do not use the index. +However, you cannot use that SAI index (based on the same column) until it has finished building and is queryable. +To determine the current state of a given index, query the `system_views.indexes` virtual table. +Example: + +[source,language-cql] +---- +SELECT is_queryable,is_building FROM system_views.indexes WHERE keyspace_name='keyspace' + AND table_name='table' AND index_name='index'; +---- diff --git a/doc/modules/cassandra/partials/sai/support-databases.adoc b/doc/modules/cassandra/partials/sai/support-databases.adoc new file mode 100644 index 0000000000..028d55cdab --- /dev/null +++ b/doc/modules/cassandra/partials/sai/support-databases.adoc @@ -0,0 +1,4 @@ +Supported databases: + +* {cassandra} 5.0 + diff --git a/doc/modules/cassandra/partials/sai/supported-query-operators-list.adoc b/doc/modules/cassandra/partials/sai/supported-query-operators-list.adoc new file mode 100644 index 0000000000..3c90a41703 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/supported-query-operators-list.adoc @@ -0,0 +1,9 @@ +// LLP CHECK FOR C* 5.0 +ifeval::["{evalproduct}" == "dse"] +* Numerics: `=`, `<`, `>`, `<=`, `>=`, `AND` +* Strings: `=`, `CONTAINS`, `CONTAINS KEY`, `AND` +endif::[] +ifeval::["{evalproduct}" != "dse"] +* Numerics: `=`, `<`, `>`, `<=`, `>=`, `AND`, `OR`, `IN` +* Strings: `=`, `CONTAINS`, `CONTAINS KEY`, `AND`, `OR`, `IN` +endif::[] diff --git a/doc/modules/cassandra/partials/sai/use-vector-keyspace.adoc b/doc/modules/cassandra/partials/sai/use-vector-keyspace.adoc new file mode 100644 index 0000000000..f99ec353d2 --- /dev/null +++ b/doc/modules/cassandra/partials/sai/use-vector-keyspace.adoc @@ -0,0 +1,8 @@ +== Use vector search keyspace + +Select the keyspace `cycling` for creating the vector search example: + +[source,cql] +---- +include::cassandra:getting-started/example$CQL/use-vector-keyspace-cycling.cql[] +---- \ No newline at end of file diff --git a/doc/scripts/convert_yaml_to_adoc.py b/doc/scripts/convert_yaml_to_adoc.py index 5eff522a00..59620bb208 100644 --- a/doc/scripts/convert_yaml_to_adoc.py +++ b/doc/scripts/convert_yaml_to_adoc.py @@ -21,7 +21,7 @@ the online documentation. Usage: YAML_INPUT=conf/cassandra.yaml -YAML_OUTPUT=modules/cassandra/pages/configuration/cass_yaml_file.adoc +YAML_OUTPUT=modules/cassandra/pages/managing/configuration/cass_yaml_file.adoc convert_yaml_to_adoc.py $YAML_INPUT $YAML_OUTPUT """