β¨ DataStax Astra: Stargate + SAI Workshop β¨
This workshop will show the modern developer APIs for Cassandra using Stargate's:
- REST API
π‘ - Developer friendly endpoints - GraphQL API
𧩠- Modern GraphQL standard - Document API
π - Use Cassandra like a Document Database
And in addition, we'll also use CQLsh to connect to the database:
- CQLsh
π - CQL Shell
The Stargate APIs are available by default on Astra (the Serverless Managed Cloud Cassandra Database by DataStax), Open Source Cassandra and DataStax Enterprise.
Additionally, we'll go into SAI indexes
β Prerequisites
Make sure to sign up for free on https://astra.datastax.com. And why not? You get $25 of credit every month! The $25 credit is good for approximately 30 million reads, 5 million writes, and 40GB of storage per month
β
Create a database
- Browse to https://astra.datastax.com and sign in using your account.
- Click "Create Database"
- Enter
datastax
asDatabase Name
andworkshop
asKeyspace Name
. - Choose any one of the cloud providers, areas and regions.
β
Load some sample data
Once the database comes out of the Pending state and becomes Active, proceed to loading some sample data:
- Click the database you just created (
datastax
). - Click Load Data.
- Click
Movies and TV Shows
and click Next. - Select
show_id
as the Partition Key and click Next. - Select the Target Database (
datastax
) and Target Keyspace (workshop
) and click Next.
The data will now be imported and you'll be notified through an e-mail.
β
Create an application token
An application token is required for connecting to the APIs.
- Browse to https://astra.datastax.com/settings/tokens.
- Select role
Admin User
and click Generate Token. - Click Download CSV to have a back-up of the token for later use.
REST API π‘
β‘ Here we'll interact with the REST API for Astra (based on Stargate.io) through the built-in Swagger UI in Astra.
- Browse to https://astra.datastax.com and sign in using your account.
- Click the Connect tab.
- Click on REST API.
- Click on the Swagger UI link on the right, this will open a new browser tab.
β
Keyspaces
We'll first use the keyspaces endpoint to understand more about the keyspaces in the database.
- Click "GET /v1/keyspaces".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Click Execute
You'll see a list of keyspaces available in the database without using any CQL!
β
Create a table
Now we'll create a table into our workshop
keyspace.
- Click "POST /v1/keyspaces/{keyspaceName}/tables".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
into the keyspaceName field. - Paste the following payload to create a new table:
{
"name": "users",
"primaryKey": {
"partitionKey": [
"userid"
]
},
"columnDefinitions": [
{
"name": "userid",
"typeDefinition": "int"
},
{
"name": "emailaddress",
"typeDefinition": "text"
}
]
}
- Click Execute
We just created our first table! You can check it out by clicking the CQL Console tab.
β
Load some data
Now we'll add some data into our newly created table.
- Click "POST /v1/keyspaces/{keyspaceName}/tables/{tableName}rows".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
into thekeyspaceName
field. - Type
users
into thetableName
field. - Paste the following payload to load one row of data:
{
"columns": [
{
"name": "userid",
"value": "1"
},
{
"name": "emailaddress",
"value": "michel.deru@company.com"
}
]
}
- Click Execute
β
Retrieve all data from the table
- Click "GET /v1/keyspaces/{keyspaceName}/tables/{tableName}rows".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
into thekeyspaceName
field. - Type
users
into thetableName
field. - Click Execute
Now you'll see the row we just added!
β’ GraphQL API π§©
Now we'll use the upcoming new API Query Language GraphQL to interact with Cassandra!
We'll interact with the GraphQL API for Astra (based on Stargate.io) through the built-in GraphQL UI in Astra.
- Browse to https://astra.datastax.com and sign in using your account.
- Click the Connect tab.
- Click on GraphQL API.
- Click on the GraphQL Playground link on the right. Make sure the first tab graphql-schema is selected.
- Click on HTTP Headers on the bottom-left and replace
populate_me
with theApplication Token
you previously generated.
β
Keyspaces
We'll first query for keyspaces in the database.
- Paste the following in the payload window on the left:
{
keyspaces {
name
}
}
- Click the Play (
βΆοΈ ) button.
You just ran your first GraphQL query and retrieved all keyspaces without using any CQL!
β
Create a table
Now we'll create two new tables into our workshop
keyspace. We'll create a books
table and a table called authors
. In order to do this we'll utilize the mutations createTable
structure.
- Paste the following in the payload window on the left:
mutation createTables {
table1: createTable(
keyspaceName: "workshop"
tableName: "books"
partitionKeys: [
# The keys required to access your data
{ name: "name", type: { basic: TEXT } }
]
clusteringKeys: [
# Secondary key used to access values within the partition
{ name: "author", type: { basic: TEXT } }
]
)
table2: createTable(
keyspaceName: "workshop"
tableName: "authors"
partitionKeys: [
# The keys required to access your data
{ name: "name", type: { basic: TEXT } }
]
values: [
# Additional fields
{ name: "country", type: { basic: TEXT } }
]
)
}
- Click the Play (
βΆοΈ ) button and observe the response.
You just created two tables using GraphQL!
β
Load some data
Before starting the next steps:
** First switch to the graphql tab, click on HTTP Headers on the bottom-left and replace populate_me
with your previously generated Application Token
.
** Then make sure you type workshop
after the slash .../graphql/
in the URL (replacing system
or yourKeyspace
).
Now we'll load data into the books
and authors
tables.
- Paste the following in the payload window on the left:
mutation insertData {
update1: insertbooks(
value: {
name: "Harry Potter and the Sorcerer's Stone"
author: "J.K. Rowling"
}
) {
value {
name
}
}
update2: insertbooks(
value: {
name: "Harry Potter and the Chamber of Secrets"
author: "J.K. Rowling"
}
) {
value {
name
}
}
update3: insertauthors(
value: {
name: "J.K. Rowling",
country: "UK"
}
) {
value {
name
}
}
}
- Click the Play (
βΆοΈ ) button and observe the response.
Notice the use of insertbooks
. This notation is used to insert
data into the books
table.
β
Query some data
Let's do some fancy querying now.
- Paste the following in the payload window on the left:
query allBooks {
books {
values {
name
author
}
}
}
- Click the Play (
βΆοΈ ) button and observe the response.
Now let's filter this data:
- Paste the following in the payload window on the left:
query someBook {
books(
filter: {
name: {
eq: "Harry Potter and the Sorcerer's Stone" }
}
) {
values {
name
author
}
}
}
- Click the Play (
βΆοΈ ) button and observe the response.
β
Drop the tables
Now let's drop the tables we just created.
Before we do that, first switch back the graphql-schema tab.
- Paste the following in the payload window on the left:
mutation dropAll {
dropTable1: dropTable(keyspaceName: "workshop", tableName: "books")
dropTable2: dropTable(keyspaceName: "workshop", tableName: "authors")
}
- Click the Play (
βΆοΈ ) button twice while selecting each table and observe the response.
β£ Document API π
Now let's make Cassandra the best of both worlds with not just wide-row modelling but also document modelling!
Here we'll interact with the Document API for Astra (based on Stargate.io) through the built-in Swagger UI in Astra.
- Browse to https://astra.datastax.com and sign in using your account.
- Click the Connect tab.
- Click on Document API.
- Click on the Swagger UI link on the right, this will open a new browser tab.
β
Namespaces
Namespaces in the document world are the equivalent of Keyspaces in the wide-row world.
We'll first use the namespaces endpoint to understand more about the namespaces in the database.
- Click "GET /v2/schemas/namespaces".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Click Execute
You'll see all Keyspaces in the database, however in the Document Realm they are calles Namespaces.
β
Collections
Let's create a collection where our documents will reside.
- Click "POST /v2/namespaces/{namespace-id}/collections".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
in thenamespace-id
field. - Paste the following payload to create a new table:
{
"name": "cars"
}
- Click Execute
You just created a new collection. Actually a collection is the equivalent of a table in the wide-row world.
β
Store a document
Let's create a collection where our documents will reside.
- Click "POST /v2/namespaces/{namespace-id}/collections/{collection-id}".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
in thenamespace-id
field. - Type
cars
in thecollection-id
field. - Paste the following payload to create a document:
{
"brand": "BMW",
"model": "535d xDrive",
"year": 2013,
"engine": {
"type": "diesel",
"cylinders": 6,
"turbo": 2
}
}
- Click Execute
You just created a new document! Note that you didn't have to define a model at all. Also note that you can use hierarchy in the document.
Let's add another document, just replace the payload with the following and press Execute:
{
"brand": "BMW",
"model": "X5 xDrive40e",
"year": 2015,
"engine": [
{
"type": "petrol",
"cylinders": 4,
"turbo": 1,
"compressor": 1
},
{
"type": "electric"
}
]
}
And again, we just schemalessly ingested a new document with different structure. Note that the response shows the document ID under which the document is saved.
β
Query a collection
Now let's query the data without the need for creating indexes!
- Click "GET /v2β/namespacesβ/{namespace-id}β/collectionsβ/{collection-id}".
- Click Try it out.
- Paste the
Application Token
you just generated intoX-Cassandra-Token
. - Type
workshop
in thenamespace-id
field. - Type
cars
in thecollection-id
field. - Type
{ "brand": {"$eq": "BMW"}}
in thewhere
field. - Type
20
in thepage-size
field. - Click Execute
You just retrieved all data for BMW cars. Notice the different document models you get back!
Now let's filter a bit better:
- Change the
where
field to show{ "brand": {"$eq": "BMW"}, "year": {"$gte": 2015}}
- Click Execute
You just filtered out to just one car!
β€ CQL Shell π
Apart from all these cool modern endpoints, there will always be a use-case for the plain old CQL Shell as well. There are two options for a CQLsh connection to Astra:
- Using the CQL Console on the Astra Dashboard (see below at β₯)
- Using the CQLsh binary provides by DataStax
Let's explore the second option.
- The Client ID
- The Client Secret
- The Secure Connect Bundle for the mutually encrypted TLS connection
cqlsh -u <client_id> -p <client_secret> -b <path-to-scb>
β₯ SAI Indexes π
Here we'll use the sample data you ingested during the prequisites steps.
In this lab you'll see how easy it is to leverage scalable indexes to allow "relational-type" indexing and searching in Cassandra without using a primary key. This allows you to prevent data duplication and denormalization you'd normally have to use to create new query entrances into your data!
Here we'll use the CQL Console that is available in Astra:
- Browse to https://astra.datastax.com and sign in using your account.
- Click the CQL Console tab.
β
Without indexes
Without the SAI index, we can only access the data through the primary key:
select show_id, title from movies_and_tv;
select show_id, title from movies_and_tv where show_id = 81093951;
Now if we want to search on the title
, the following query is going to fail:
select show_id, title from movies_and_tv where title = 'Oh! Baby';
The only way to search on the title
is to use allow filtering
. At scale however, that is not an option!
select show_id, title from movies_and_tv where title = 'Oh! Baby' allow filtering;
β
Using SAI
Let's first create the index and allow Cassandra some time to build up the index:
create custom index movies_and_tv_title on movies_and_tv(title) using 'StorageAttachedIndex';
And let the magic begin! Now you can filter on title
:
select show_id, title from movies_and_tv where title = 'Oh! Baby';
The nice thing is you can also allow for case-insensitive searching!
drop index movies_and_tv_title;
create custom index movies_and_tv_title on movies_and_tv(title) using 'StorageAttachedIndex' with options = {'case_sensitive': false, 'normalize': true};
select show_id, title from movies_and_tv where title = 'oh! baby';
Happy cass-ing!