# index.md

ScyllaDB online feature store

This tutorial walks you through a sample online feature store application with ScyllaDB Cloud. After completing the project, you will be able to use ScyllaDB as a feature store and integrate it with the Feast framework.
# about-feature-stores.md # Why should you consider ScyllaDB as a feature store? ScyllaDB is a real-time NoSQL database that is best suited for feature store use cases where you require **low latency** (e.g. model serving), **high throughout** (e.g. training) and need peta-byte scalability. Feature store is a central data store to power operational machine learning models. They help you store transformed feature values in a scalable and performant database. Real-time inference requires features to be returned to applications with low latency at scale. This is where ScyllaDB can play a crucial role in your machine learning infrastructure. [![](https://mermaid.ink/img/pako:eNptkLtuwzAMRX-F4NDJ_gEPBdq62bI0mWp7ICRaFqqHQckpgjj_XtVJOxTlxMe5xCUvqKJmbHB08VNNJBmObR-gxFN3FAppjOJZwwOQMcKGcik0ZRqgrh_hhr50B3V2jtpnqCEGZwNDylHIMAx3ZMPXHWc1QRaywQazLUqcV2i7ffHhfif_qUamvAjDiVXZnVZ4vYsSy-mvZte9Mbk6W89A85wGrNCzeLK6XHv5RnvME3vusSmpJvnosQ_XwtGS4-EcFDZZFq5wmYtPbi0ZIY_NSC6VLmtbbOxv79u-WOFM4T3GH-b6BaPtdAY?type=png)](https://mermaid.live/edit#pako:eNptkLtuwzAMRX-F4NDJ_gEPBdq62bI0mWp7ICRaFqqHQckpgjj_XtVJOxTlxMe5xCUvqKJmbHB08VNNJBmObR-gxFN3FAppjOJZwwOQMcKGcik0ZRqgrh_hhr50B3V2jtpnqCEGZwNDylHIMAx3ZMPXHWc1QRaywQazLUqcV2i7ffHhfif_qUamvAjDiVXZnVZ4vYsSy-mvZte9Mbk6W89A85wGrNCzeLK6XHv5RnvME3vusSmpJvnosQ_XwtGS4-EcFDZZFq5wmYtPbi0ZIY_NSC6VLmtbbOxv79u-WOFM4T3GH-b6BaPtdAY) What ScyllaDB brings to the table: * **Low-latency**: ScyllaDB can provide <1 ms P99 latency. For real-time machine learning apps, an online feature store is required to meet strict latency requirements. ScyllaDB is an excellent choice for an online store (Read how [Medium is using ScyllaDB](https://medium.engineering/scylladb-implementation-lists-in-mediums-feature-store-part-2-905299c89392) as a feature store.) * **High-throughput**: Training requires querying huge amounts of data and processing large datasets with possibly millions of operations per second - something that ScyllaDB excels at. * **Large-scale**: ScyllaDB can handle petabytes of data while still keeping latency low and predictable. * **High availability**: ScyllaDB is a highly available database. With its distributed architecture, ScyllaDB keeps your feature store database always up and running. * **Easy to migration**: ScyllaDB is compatible with DynamoDB API and Cassandra which means it’s simple to migrate over from legacy solutions. * **Integration with Feast**: ScyllaDB integrates well with the popular open-source feature store framework, Feast. Example architecture with Feast and ScyllaDB: ![scylla feast architecture](_static/img/scylla-feast-2.png) # credit-scoring-app.md # Real-time credit scoring application with Feast & ScyllaDB This repository is based on [this](https://github.com/feast-dev/feast-aws-credit-scoring-tutorial) existing Feast sample application. ![scylla feast architecture](_static/img/scylla-feast-2.png) This sample project is a real-time credit scoring application example that shows you how to set up Feast with ScyllaDB Cloud as an online store and parquet files as offline store. ## Requirements * Python 3 * [ScyllaDB Cloud account](https://cloud.scylladb.com/) ## Get started Clone the repository: ```default git clone https://github.com/zseta/scylladb-feast cd scylladb-feast ``` Project details: * The primary training dataset is in `loan_table.parquet`. This file contains historic loan data with accompanying features. The dataset also contains a target variable, namely whether a user has defaulted on their loan. * Feast is used during training to enrich the loan table with `zipcode` and `credit history` features from other parquet files. * Feast is also used to serve the latest `zipcode` and `credit history` features for online credit scoring using ScyllaDB Cloud. In this tutorial, you’ll do the following steps: 1. Create a new ScyllaDB Cloud cluster 2. Create a new keyspace for the feature store 3. Install dependencies and configure Feast 4. Deploy and test the feature store ## Create ScyllaDB Cloud cluster Go to [ScyllaDB Cloud](https://cloud.scylladb.com/) and create a new cluster (either “Free Tial” or “Dedicated VM”). You can use the smallest available machine for this sample app (`t3.micro`) ![choose machine type](_static/img/choose-machine.png) ## Create new keyspace Install CQLSH command line tool and connect to the ScyllaDB cluster: ```default pip install cqlsh cqlsh -u scylla -p ``` You can get the host address, username, and password from your ScyllaDB Cloud dashboard: ![scylla connect](_static/img/scylla-cloud-connect.png) Create a new keyspace called `feast` in ScyllaDB (this keyspace will be populated by Feast): ```default CREATE KEYSPACE feast WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '3'} ; ``` ## Install dependencies and configure Feast Create a new Python environment and install dependencies: ```default virtualenv env && source env/bin/activate pip install -r requirements.txt ``` Next, configure ScyllaDB Cloud as the online store for Feast. > [!TIP] > Feast ships with a native ScyllaDB online store connector, so no extra setup beyond `pip install feast[scylladb]` is required. Open the feature_store.yaml file and add the host addresses, username (`scylla`), password, and datacenter name for ScyllaDB: ```yaml project: repo # By default, the registry is a file (but can be turned into a more scalable SQL-backed registry) registry: data/registry.db # The provider primarily specifies default offline / online stores & storing the registry in a given cloud provider: local online_store: type: scylladb hosts: - x.x.x.x - x.x.x.x - x.x.x.x username: scylla password: pass keyspace: feast local_dc: AWS_US_EAST_1 entity_key_serialization_version: 3 ``` You can get the host addresses, username, and password from the ScyllaDB Cloud dashboard. `local_dc` should match the datacenter name of your cluster (visible in the ScyllaDB Cloud dashboard). ## Deploy and test the feature store Deploy the feature store by running `apply` from within the `feature_repo/` folder ```default cd feature_repo/ feast apply Deploying infrastructure for credit_history Deploying infrastructure for zipcode_features ``` This commmand also generates a `registry.db` file in your `data/` folder containing Feast configuration information. Next, load features into the online store using the `materialize-incremental` command. This command loads the latest feature values from a data source (parquet files, in our case) into the online store (ScyllaDB). ```default CURRENT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%S") feast materialize-incremental $CURRENT_TIME ``` The loading process starts: ```default 35%|███████████████████▋ | 9965/28844 [01:20<02:39, 118.37it/s] ``` When it’s completed, train the model using `run.py` (in the root folder of the repository) ```default cd .. python run.py ``` The script returns the result of a single loan application: ```default Loan rejected! ``` You can also run `feast ui` to explore your features: ```default feast ui ``` Open http://0.0.0.0:8888 ![feast ui](_static/img/feast-ui.png) ## Interactive demo Run the Streamlit app locally: ```default streamlit run app.py ``` Go to http://localhost:8501 ![streamlit app](_static/img/streamlit_app.png) You can modify the variables on the left sidebar then the app will automatically run the prediction using the model. # feast-scylladb-online-store.md # Integrate ScyllaDB and Feast [Feast](https://feast.dev/) is a popular open-source feature store for production ML. You can use several online stores when using Feast, including ScyllaDB. ScyllaDB, a low-latency and high-throughput database, serves perfectly as an online store. In this section, you’ll see how you can integrate your ScyllaDB Cloud database with Feast as an online store. If you want to learn more about Feast, read the [Feast documentation](https://docs.feast.dev/). ## Feast + ScyllaDB online store configuration example Feast ships with a native ScyllaDB online store connector, built on the `scylla-driver` Python package. To set up ScyllaDB as a Feast online store you need to 1. Install Feast with the ScyllaDB extra 2. Edit the Feast configuration file ### Install Feast with the ScyllaDB extra ```default pip install feast[scylladb] ``` ### Edit the Feast configuration file ```yaml # feature_store.yaml project: repo registry: data/registry.db provider: local online_store: type: scylladb hosts: - node-0.aws_us_east_1.xxxxxxx.clusters.scylla.cloud - node-1.aws_us_east_1.xxxxxxx.clusters.scylla.cloud - node-2.aws_us_east_1.xxxxxxx.clusters.scylla.cloud username: scylla password: xxxxxxx keyspace: feast local_dc: AWS_US_EAST_1 entity_key_serialization_version: 3 ``` Key configuration options for the `scylladb` online store: * `hosts`: contact-point addresses of your cluster (required) * `port`: CQL port (default: `9042`) * `keyspace`: target keyspace (default: `feast_keyspace`) * `username` / `password`: authentication credentials * `local_dc`: datacenter name used for DC-aware load balancing (required for ScyllaDB Cloud, e.g. `AWS_US_EAST_1`) * `read_concurrency` / `write_concurrency`: number of concurrent in-flight statements (default: `100` each) * `vector_similarity_function`: default similarity function for vector search — `COSINE`, `DOT_PRODUCT`, or `EUCLIDEAN` (default: `COSINE`) For more information, read the [Feast documentation](https://docs.feast.dev/reference/online-stores/scylladb). # getting-started.md # ScyllaDB for training data This example project demonstrates a machine learning feature store use case for ScyllaDB. You’ll set up a database with flight feature data and use ScyllaDB to train a model using decision tree classification. ## Clone the repository ```bash git clone https://github.com/scylladb/scylladb-feature-store.git ``` ## Sign up for a ScyllaDB Cloud account To complete this project, sign up for a free trial account on [ScyllaDB Cloud](https://cloud.scylladb.com/user/signup). This is the easiest way to start using ScyllaDB. If you prefer to use a self-hosted version of ScyllaDB, [see installation options here](https://www.scylladb.com/download/#open-source) (e.g. Docker). ## Prerequisites: * [cqlsh](https://pypi.org/project/cqlsh/) * [Python 3.7+](https://www.python.org/downloads/) ## Data model Run the `schema.cql` file to create keyspace `feature_store` and table `flight_features`: ```bash cqlsh "node-0.aws_us_east_1.xxxxxxxxx.clusters.scylla.cloud" 9042 -u scylla -p "password" -f schema.cql ``` This creates the following table in your database: ```sql create table feature_store.flight_features( FL_DATE TIMESTAMP, OP_CARRIER TEXT, OP_CARRIER_FL_NUM INT, ORIGIN TEXT, DEST TEXT, CRS_DEP_TIME INT, DEP_TIME FLOAT, DEP_DELAY FLOAT, TAXI_OUT FLOAT, WHEELS_OFF FLOAT, WHEELS_ON FLOAT, TAXI_IN FLOAT, CRS_ARR_TIME INT, ARR_TIME FLOAT, ARR_DELAY FLOAT, CANCELLED FLOAT, CANCELLATION_CODE TEXT, DIVERTED FLOAT, CRS_ELAPSED_TIME FLOAT, ACTUAL_ELAPSED_TIME FLOAT, AIR_TIME FLOAT, DISTANCE FLOAT, CARRIER_DELAY FLOAT, WEATHER_DELAY FLOAT, NAS_DELAY FLOAT, SECURITY_DELAY FLOAT, LATE_AIRCRAFT_DELAY FLOAT, PRIMARY KEY (OP_CARRIER_FL_NUM) ); ``` ## Import the dataset into ScyllaDB ```bash cqlsh "node-0.aws_us_east_1.xxxxxxxxx.clusters.scylla.cloud" 9042 -u scylla -p "password" scylla@cqlsh> COPY feature_store.flight_features FROM 'flight_features.csv'; ``` This will start ingesting data into your ScyllaDB instance: ```default op_carrier_fl_num|actual_elapsed_time|air_time|arr_delay|arr_time|cancellation_code|cancelled|carrier_delay|crs_arr_time|crs_dep_time|crs_elapsed_time|dep_delay|dep_time|dest|distance|diverted|fl_date |late_aircraft_delay|nas_delay|op_carrier|origin|security_delay|taxi_in|taxi_out|weather_delay|wheels_off|wheels_on| -----------------+-------------------+--------+---------+--------+-----------------+---------+-------------+------------+------------+----------------+---------+--------+----+--------+--------+-------------------+-------------------+---------+----------+------+--------------+-------+--------+-------------+----------+---------+ 4317| 96.0| 73.0| -19.0| 2113.0| | 0.0| | 2132| 2040| 112.0| -3.0| 2037.0|MLI | 373.0| 0.0|2018-12-31 02:00:00| | |OO |DTW | | 5.0| 18.0| | 2055.0| 2108.0| 3372| 94.0| 74.0| 81.0| 1500.0| | 0.0| 0.0| 1339| 1150| 109.0| 96.0| 1326.0|RNO | 564.0| 0.0|2018-12-31 02:00:00| 81.0| 0.0|OO |SEA | 0.0| 3.0| 17.0| 0.0| 1343.0| 1457.0| 1584| 385.0| 348.0| -21.0| 2023.0| | 0.0| | 2034| 1700| 394.0| -9.0| 1658.0|SFO | 2565.0| 0.0|2018-12-31 02:00:00| | |UA |EWR | | 13.0| 33.0| | 1731.0| 2019.0| 4830| 119.0| 85.0| -35.0| 1431.0| | 0.0| | 1437| 1245| 136.0| -13.0| 1232.0|MSP | 546.0| 0.0|2018-12-31 02:00:00| | |OO |MSP | | 16.0| 18.0| | 1250.0| 1415.0| 2731| 158.0| 146.0| -19.0| 1911.0| | 0.0| | 1930| 1800| 160.0| -8.0| 1800.0|MSP | 842.0| 0.0|2018-12-31 02:00:00| | |WN |PVD | | 7.0| 7.0| | 1807.0| 1904.0| ``` Now that you have some sample data to play with, let’s see a decision tree example. ## Decision tree classification Create a new virtual environment and activate it: ```bash virtualenv env source env/bin/activate ``` Install requirements: ```bash pip install scikit-learn pandas scylla-driver ``` > To follow the code examples below you can either create a new python file or just use the Jupyter notebook that’s in the repo. If you use the notebook make sure the edit the `config.py` file with your credentials. Connect to ScyllaDB: ```python import pandas as pd from sklearn.tree import DecisionTreeClassifier # Import Decision Tree Classifier from sklearn.model_selection import train_test_split # Import train_test_split function from sklearn import metrics #Import scikit-learn metrics module for accuracy calculation from sqlalchemy import create_engine from cassandra.cluster import Cluster, ExecutionProfile, EXEC_PROFILE_DEFAULT from cassandra.policies import DCAwareRoundRobinPolicy, TokenAwarePolicy from cassandra.auth import PlainTextAuthProvider def pandas_factory(colnames, rows): return pd.DataFrame(rows, columns=colnames) def getCluster(): profile = ExecutionProfile(load_balancing_policy=TokenAwarePolicy(DCAwareRoundRobinPolicy(local_dc='AWS_US_EAST_1')), row_factory=pandas_factory) return Cluster( execution_profiles={EXEC_PROFILE_DEFAULT: profile}, contact_points=[ "" ], port=9042, auth_provider = PlainTextAuthProvider(username="scylla", password="******")) cluster = getCluster() session = cluster.connect() ``` Query data into a dataframe: ```python query = "SELECT * FROM demo.flight_features;" rows = session.execute(query) df = rows._current_rows ``` Split the dataset into features and target variable: Feature attributes: * `actual_elapsed_time` * `air_time` * `arr_time` * `crs_arr_time` * `crs_dep_time` * `crs_elapsed_time` * `dep_time` * `distance` * `taxi_in` * `taxi_out` * `wheels_off` * `wheels_on` * `arr_delay` Target attribute: * `dep_delay` ```python #Features feature_cols = ["actual_elapsed_time", "air_time", "arr_time", "crs_arr_time", "crs_dep_time", "crs_elapsed_time", "dep_time", "distance", "taxi_in", "taxi_out", "wheels_off", "wheels_on", "arr_delay"] X = df[feature_cols] y = df.dep_delay # Target variable # Split dataset into training set and test set X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 70% training and 30% test ``` Create the classifier: ```python # Create Decision Tree classifer object clf = DecisionTreeClassifier() # Train Decision Tree Classifer clf = clf.fit(X_train,y_train) #Predict the response for test dataset y_pred = clf.predict(X_test) print("Accuracy:",metrics.accuracy_score(y_test, y_pred)) Accuracy: 0.052884615384615384 ``` Decision tree visualization in text form ```python from sklearn.tree import export_text tree_rules = export_text(clf, feature_names=feature_cols) print(tree_rules) ``` ```text | | | | |--- taxi_in > 5.50 | | | | | |--- crs_arr_time <= 1307.50 | | | | | | |--- crs_dep_time <= 514.00 | | | | | | | |--- dep_time <= 501.00 | | | | | | | | |--- dep_time <= 272.50 | | | | | | | | | |--- class: 14.0 | | | | | | | | |--- dep_time > 272.50 | | | | | | | | | |--- class: -5.0 | | | | | | | |--- dep_time > 501.00 | | | | | | | | |--- class: -3.0 | | | | | | |--- crs_dep_time > 514.00 | | | | | | | |--- wheels_off <= 553.50 | | | | | | | | |--- crs_dep_time <= 536.50 | | | | | | | | | |--- wheels_on <= 745.50 | | | | | | | | | | |--- air_time <= 55.00 | | | | | | | | | | | |--- class: 6.0 | | | | | | | | | | |--- air_time > 55.00 | | | | | | | | | | | |--- truncated branch of depth 3 | | | | | | | | | |--- wheels_on > 745.50 | | | | | | | | | | |--- class: -2.0 | | | | | | | | |--- crs_dep_time > 536.50 | | | | | | | | | |--- class: -6.0 | | | | | | | |--- wheels_off > 553.50 | | | | | | | | |--- wheels_on <= 1257.00 | | | | | | | | | |--- taxi_out <= 12.50 | | | | | | | | | | |--- arr_delay <= -2.50 | | | | | | | | | | | |--- truncated branch of depth 5 | | | | | | | | | | |--- arr_delay > -2.50 | | | | | | | | | | | |--- truncated branch of depth 6 | | | | | | | | | |--- taxi_out > 12.50 | | | | | | | | | | |--- crs_elapsed_time <= 271.50 | | | | | | | | | | | |--- truncated branch of depth 11 | | | | | | | | | | |--- crs_elapsed_time > 271.50 | | | | | | | | | | | |--- truncated branch of depth 2 | | | | | | | | |--- wheels_on > 1257.00 | | | | | | | | | |--- class: 3.0 | | | | | |--- crs_arr_time > 1307.50 | | | | | | |--- crs_dep_time <= 1746.00 | | | | | | | |--- taxi_out <= 16.50 | | | | | | | | |--- crs_arr_time <= 1349.50 | | | | | | | | | |--- arr_delay <= -5.00 | | | | | | | | | | |--- class: 9.0 | | | | | | | | | |--- arr_delay > -5.00 | | | | | | | | | | |--- actual_elapsed_time <= 100.50 | | | | | | | | | | | |--- class: 10.0 | | | | | | | | | | |--- actual_elapsed_time > 100.50 | | | | | | | | | | | |--- truncated branch of depth 4 | | | | | | | | |--- crs_arr_time > 1349.50 | | | | | | | | | |--- wheels_on <= 1337.50 | | | | | | | | | | |--- class: -2.0 | | | | | | | | | |--- wheels_on > 1337.50 | | | | | | | | | | |--- taxi_in <= 15.50 | | | | | | | | | | | |--- truncated branch of depth 13 | | | | | | | | | | |--- taxi_in > 15.50 | | | | | | | | | | | |--- truncated branch of depth 6 | | | | | | | |--- taxi_out > 16.50 | | | | | | | | |--- crs_dep_time <= 1521.50 | | | | | | | | | |--- crs_dep_time <= 1105.00 | | | | | | | | | | |--- actual_elapsed_time <= 175.50 | | | | | | | | | | | |--- class: 5.0 | | | | | | | | | | |--- actual_elapsed_time > 175.50 | | | | | | | | | | | |--- truncated branch of depth 3 ``` ## Jupyter notebook You can run and modify the classifier script using the Jupyter notebook file in the repository. Before running it locally, make sure to edit the `config.py` file with your proper (local or ScyllaDB Cloud) ScyllaDB configuration. ## Narrow table design Here’s an example table definiton that uses narrow table design: ```sql create table feature_store.flight_features_narrow ( OP_CARRIER_FL_NUM INT, FL_DATE TIMESTAMP, FEATURE_NAME TEXT, FEATURE_VALUE FLOAT, PRIMARY KEY (OP_CARRIER_FL_NUM) ) ``` In this example, you see just a few columns in the table. Aside from the `OP_CARRIER_FL_NUM` and `FL_DATE` columns, which are specific to this example use case, the two other columns are general feature columns that can be used to store any number of different features in just two columns. This type of design is more flexible and requires no schema changes in case of adding or removing features from the database. # used-cars-app.md # Price prediction inference app In this tutorial you’ll build a simplified feature store and real-time ML application with ScyllaDB. App predicts used car prices based on the car’s features. ## Create a ScyllaDB cluster In production, a ScyllaDB cluster should include at least three nodes. In this example, you’ll start with a single-node setup to keep things simple. Start up a ScyllaDB node: ```default docker run --name node1 --network scylla -p "9042:9042" -d scylladb/scylla-enterprise:2024.2 \ --overprovisioned 1 \ --smp 1 ``` Check the status of your node: ```default docker exec -it node1 nodetool status ``` The response you get back should be UN (Up and Normal). If it is not then wait a few seconds and try again as the node is not ready yet. You should see something that looks like this: ```default Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns Host ID Rack UN 172.17.0.2 204 KB 256 ? b26ab7f8-17ee-4e51-b28a-523697d16a60 rack1 ``` --- ## Create a feature store keyspace and tables In this part, you’ll create a new keyspace and a new table. Use cqlsh to interact with ScyllaDB: ```bash docker exec -it node1 cqlsh ``` Create a keyspace called `feature_store`: ```default CREATE KEYSPACE feature_store WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1 }; ``` With this CQL command, you set the following replication strategy: * `NetworkTopologyStrategy`: A production ready replication strategy that allows to set the replication factor independently for each data-center * `replication_factor:`: The number of nodes that will store the same data. In production you’d set this to 3 or higher, to ensure that if one node becomes unavailable, you can still query your data using another node. Activate the newly created keyspace: ```default use feature_store; ``` Next, create a table `used_cars` with the following columns: model, year, price, fuel_type, brand: ```sql CREATE TABLE used_cars ( car_id UUID, model TEXT, year INT, price FLOAT, brand TEXT, PRIMARY KEY (car_id) ); ``` You can confirm that the table has been created by using the following CQL command: ```sql DESC SCHEMA; ``` You can notice, that the table definiton has `car_id` as the PARTITION KEY. This allows efficient queries by the `car_id` column. --- ## Partition key, filtering Insert two rows into the newly created table: ```sql INSERT INTO used_cars(car_id, model, year, price, brand) VALUES (70f6d200-e9fb-4765-af05-f5ef668e82ee, 'A6', 2022, 43950, 'Audi'); INSERT INTO used_cars(car_id, model, year, price, brand) VALUES (9a0807eb-05df-47dc-9081-095f7881b470, 'Q5', 2024, 45300, 'Audi'); ``` Now, read the table: ```sql SELECT * FROM used_cars; ``` Query the table and add a `WHERE` clause: ```sql SELECT * FROM used_cars WHERE car_id = 70f6d200-e9fb-4765-af05-f5ef668e82ee; ``` This query is using the `car_id` column in the `WHERE` clause. This query is efficient and scalable because `car_id` is a PARTITION KEY. Let’s see what happens if you query by a non-PK column, `model`: ```sql SELECT * FROM used_cars WHERE model = 'Q5'; ``` You see an error message: `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"`. What this means is that you tried to query by a non-PK column which would require a table scan and have unpredictable performance. If you are willing to run a table scan, you can still execute the query using the `ALLOW FILTERING` extension: ```sql SELECT * FROM used_cars WHERE model = 'Q5' ALLOW FILTERING; ``` What happens if you try to `INSERT` a new product with the same ID but different price? ```sql INSERT INTO used_cars(car_id, model, year, price, brand) VALUES (70f6d200-e9fb-4765-af05-f5ef668e82ee, 'A6', 2022, 39000, 'Audi'); ``` ```sql SELECT * FROM used_cars WHERE car_id = 70f6d200-e9fb-4765-af05-f5ef668e82ee; ``` In this case, because the car_id already exists in the table, ScyllaDB will perform `UPDATE` instead of inserting a new row (executing an `UPSERT`, in other words). --- ## Clustering key Now, let’s see how clustering keys help you access your data. Create a new table, called `car_features`: ```sql CREATE TABLE car_features ( car_id uuid, feature_name text, feature_value text, PRIMARY KEY (car_id, feature_name) ); ``` Insert some sample data: ```sql INSERT INTO car_features(car_id, feature_name, feature_value) VALUES (8fb321c6-8ee0-4cd8-8568-3f149b7c298c, 'brand', 'Audi'); INSERT INTO car_features(car_id, feature_name, feature_value) VALUES (8fb321c6-8ee0-4cd8-8568-3f149b7c298c, 'model', 'A1'); INSERT INTO car_features(car_id, feature_name, feature_value) VALUES (8fb321c6-8ee0-4cd8-8568-3f149b7c298c, 'fuel_type', 'Diesel'); INSERT INTO car_features(car_id, feature_name, feature_value) VALUES (8fb321c6-8ee0-4cd8-8568-3f149b7c298c, 'price', '14950'); ``` This table contains features of used cars. Let’s breakdown the PRIMARY KEY: * `car_id`: PARTITION KEY - allows efficient queries using the `car_id` column * `feature_name`: CLUSTERING KEY - allows efficient queries using the `car_id` AND the `feature_name` columns Query by `car_id` to fetch all the features for one car: ```sql SELECT * FROM feature_store.car_features WHERE car_id = 8fb321c6-8ee0-4cd8-8568-3f149b7c298c; ``` By adding a CLUSTERING KEY, you can query one specific feature value, e.g. `model`: ```sql SELECT * FROM car_features WHERE car_id = 8fb321c6-8ee0-4cd8-8568-3f149b7c298c AND feature_name = 'model'; ``` Close cqlsh: ```sql exit ``` ## Real-time machine learning app example In this part, you’ll set up a simplified machine learning app that predicts used car prices based on user input and a pre-trained model. Connect to your ScyllaDB cluster using cqlsh and create the schema: ```bash docker exec -it node1 cqlsh ``` ```default CREATE KEYSPACE IF NOT EXISTS feature_store WITH replication = { 'class': 'NetworkTopologyStrategy', 'replication_factor': 1 }; CREATE TABLE IF NOT EXISTS feature_store.car_features ( car_id uuid, feature_name text, feature_value text, PRIMARY KEY (car_id, feature_name) ); CREATE TABLE IF NOT EXISTS feature_store.raw_car_features ( car_id UUID, brand TEXT, model TEXT, year INT, transmission TEXT, fuel_type TEXT, mpg FLOAT, engine_size FLOAT, mileage INT, tax FLOAT, PRIMARY KEY (car_id) ); ``` Exit cqlsh: ```sql exit ``` --- ## Test the app Create a new virtual environment in the app’s folder: ```bash cd labs/used-cars-feature-store/ virtualenv env --python=python3.11 && source env/bin/activate ``` Install Python requirements (scikit-learn, scylla-driver, streamlit): ```bash pip install scikit-learn scylla-driver streamlit ``` Use the `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' node1` command to get the ScyllaDB HOST address. ```bash NODE1=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' node1) echo $NODE1 ``` Find the `config.py` file: ```python SCYLLA_HOSTS = ["172.18.0.4"] SCYLLA_KEYSPACE = 'feature_store' SCYLLA_USER = 'scylla' SCYLLA_PASS = '' SCYLLA_DC = 'dc1' ``` Make sure the `HOST` value contains the output of: ```bash echo $NODE1 ``` If it doesn’t, fix it. Run streamlit: ```bash streamlit run app/app.py ``` Visit APP UI: http://localhost:8501 Hit `CTRL + C` to stop the server.