\n",
- "
\n",
- "
\n",
+ "
\n",
"\n",
- "\n",
- " \n",
- "
\n",
- "
\n",
- " "
+ "
"
],
"text/plain": [
" event_timestamp driver_id conv_rate acc_rate \\\n",
- "0 2022-05-30 19:00:00+00:00 1005 0.061944 0.517414 \n",
- "1 2022-05-30 20:00:00+00:00 1005 0.265881 0.636260 \n",
- "2 2022-05-30 21:00:00+00:00 1005 0.830253 0.461117 \n",
- "3 2022-05-30 22:00:00+00:00 1005 0.828208 0.520325 \n",
- "4 2022-05-30 23:00:00+00:00 1005 0.375715 0.084719 \n",
+ "0 2022-07-24 14:00:00+00:00 1005 0.423913 0.082831 \n",
+ "1 2022-07-24 15:00:00+00:00 1005 0.507126 0.427470 \n",
+ "2 2022-07-24 16:00:00+00:00 1005 0.139810 0.129743 \n",
+ "3 2022-07-24 17:00:00+00:00 1005 0.383574 0.071728 \n",
+ "4 2022-07-24 18:00:00+00:00 1005 0.959131 0.440051 \n",
"... ... ... ... ... \n",
- "1802 2022-06-14 17:00:00+00:00 1001 0.016256 0.293051 \n",
- "1803 2022-06-14 18:00:00+00:00 1001 0.651631 0.855919 \n",
- "1804 2021-04-12 07:00:00+00:00 1001 0.828805 0.375509 \n",
- "1805 2022-06-07 07:00:00+00:00 1003 0.324065 0.970185 \n",
- "1806 2022-06-07 07:00:00+00:00 1003 0.324065 0.970185 \n",
+ "1802 2022-08-08 12:00:00+00:00 1001 0.994883 0.020145 \n",
+ "1803 2022-08-08 13:00:00+00:00 1001 0.663844 0.864639 \n",
+ "1804 2021-04-12 07:00:00+00:00 1001 0.068696 0.624977 \n",
+ "1805 2022-08-01 02:00:00+00:00 1003 0.980869 0.244420 \n",
+ "1806 2022-08-01 02:00:00+00:00 1003 0.980869 0.244420 \n",
"\n",
" avg_daily_trips created \n",
- "0 467 2022-06-14 19:00:52.584 \n",
- "1 709 2022-06-14 19:00:52.584 \n",
- "2 731 2022-06-14 19:00:52.584 \n",
- "3 919 2022-06-14 19:00:52.584 \n",
- "4 874 2022-06-14 19:00:52.584 \n",
+ "0 201 2022-08-08 14:14:11.200 \n",
+ "1 690 2022-08-08 14:14:11.200 \n",
+ "2 845 2022-08-08 14:14:11.200 \n",
+ "3 839 2022-08-08 14:14:11.200 \n",
+ "4 2 2022-08-08 14:14:11.200 \n",
"... ... ... \n",
- "1802 908 2022-06-14 19:00:52.584 \n",
- "1803 685 2022-06-14 19:00:52.584 \n",
- "1804 106 2022-06-14 19:00:52.584 \n",
- "1805 824 2022-06-14 19:00:52.584 \n",
- "1806 824 2022-06-14 19:00:52.584 \n",
+ "1802 650 2022-08-08 14:14:11.200 \n",
+ "1803 359 2022-08-08 14:14:11.200 \n",
+ "1804 624 2022-08-08 14:14:11.200 \n",
+ "1805 790 2022-08-08 14:14:11.200 \n",
+ "1806 790 2022-08-08 14:14:11.200 \n",
"\n",
"[1807 rows x 6 columns]"
]
},
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -499,69 +433,88 @@
},
"source": [
"### Step 3a: Inspecting feature definitions\n",
- "Let's inspect what `example.py` looks like (the only python file in the repo):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/"
- },
- "id": "DPqXCoNpL0SX",
- "outputId": "a31a40c4-e60a-4f62-ae1c-227ce0aedea4"
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\u001b[38;2;64;128;128;03m# This is an example feature definition file\u001b[39;00m\n",
- "\n",
- "\u001b[38;2;0;128;0;01mfrom\u001b[39;00m \u001b[38;2;0;0;255;01mdatetime\u001b[39;00m \u001b[38;2;0;128;0;01mimport\u001b[39;00m timedelta\n",
- "\n",
- "\u001b[38;2;0;128;0;01mfrom\u001b[39;00m \u001b[38;2;0;0;255;01mfeast\u001b[39;00m \u001b[38;2;0;128;0;01mimport\u001b[39;00m Entity, FeatureService, FeatureView, Field, FileSource, ValueType\n",
- "\u001b[38;2;0;128;0;01mfrom\u001b[39;00m \u001b[38;2;0;0;255;01mfeast\u001b[39;00m\u001b[38;2;0;0;255;01m.\u001b[39;00m\u001b[38;2;0;0;255;01mtypes\u001b[39;00m \u001b[38;2;0;128;0;01mimport\u001b[39;00m Float32, Int64\n",
- "\n",
- "\u001b[38;2;64;128;128;03m# Read data from parquet files. Parquet is convenient for local development mode. For\u001b[39;00m\n",
- "\u001b[38;2;64;128;128;03m# production, you can use your favorite DWH, such as BigQuery. See Feast documentation\u001b[39;00m\n",
- "\u001b[38;2;64;128;128;03m# for more info.\u001b[39;00m\n",
- "driver_hourly_stats \u001b[38;2;102;102;102m=\u001b[39m FileSource(\n",
- " path\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33m/content/feature_repo/data/driver_stats.parquet\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m,\n",
- " timestamp_field\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mevent_timestamp\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m,\n",
- " created_timestamp_column\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mcreated\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m,\n",
- ")\n",
- "\n",
- "\u001b[38;2;64;128;128;03m# Define an entity for the driver. You can think of entity as a primary key used to\u001b[39;00m\n",
- "\u001b[38;2;64;128;128;03m# fetch features.\u001b[39;00m\n",
- "driver \u001b[38;2;102;102;102m=\u001b[39m Entity(name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mdriver\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m, join_keys\u001b[38;2;102;102;102m=\u001b[39m[\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mdriver_id\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m], value_type\u001b[38;2;102;102;102m=\u001b[39mValueType\u001b[38;2;102;102;102m.\u001b[39mINT64,)\n",
- "\n",
- "\u001b[38;2;64;128;128;03m# Our parquet files contain sample data that includes a driver_id column, timestamps and\u001b[39;00m\n",
- "\u001b[38;2;64;128;128;03m# three feature column. Here we define a Feature View that will allow us to serve this\u001b[39;00m\n",
- "\u001b[38;2;64;128;128;03m# data to our model online.\u001b[39;00m\n",
- "driver_hourly_stats_view \u001b[38;2;102;102;102m=\u001b[39m FeatureView(\n",
- " name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mdriver_hourly_stats\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m,\n",
- " entities\u001b[38;2;102;102;102m=\u001b[39m[\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mdriver\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m],\n",
- " ttl\u001b[38;2;102;102;102m=\u001b[39mtimedelta(days\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;102;102;102m1\u001b[39m),\n",
- " schema\u001b[38;2;102;102;102m=\u001b[39m[\n",
- " Field(name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mconv_rate\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m, dtype\u001b[38;2;102;102;102m=\u001b[39mFloat32),\n",
- " Field(name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33macc_rate\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m, dtype\u001b[38;2;102;102;102m=\u001b[39mFloat32),\n",
- " Field(name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mavg_daily_trips\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m, dtype\u001b[38;2;102;102;102m=\u001b[39mInt64),\n",
- " ],\n",
- " online\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;0;128;0;01mTrue\u001b[39;00m,\n",
- " source\u001b[38;2;102;102;102m=\u001b[39mdriver_hourly_stats,\n",
- " tags\u001b[38;2;102;102;102m=\u001b[39m{},\n",
- ")\n",
- "\n",
- "driver_stats_fs \u001b[38;2;102;102;102m=\u001b[39m FeatureService(\n",
- " name\u001b[38;2;102;102;102m=\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m\u001b[38;2;186;33;33mdriver_activity\u001b[39m\u001b[38;2;186;33;33m\"\u001b[39m, features\u001b[38;2;102;102;102m=\u001b[39m[driver_hourly_stats_view]\n",
- ")\n"
- ]
- }
- ],
- "source": [
- "!pygmentize -f terminal16m example.py"
+ "Let's inspect what `example_repo.py` looks like:\n",
+ "\n",
+ "```python\n",
+ "# This is an example feature definition file\n",
+ "\n",
+ "from datetime import timedelta\n",
+ "\n",
+ "import pandas as pd\n",
+ "\n",
+ "from feast import Entity, FeatureService, FeatureView, Field, FileSource, RequestSource, PushSource\n",
+ "from feast.on_demand_feature_view import on_demand_feature_view\n",
+ "from feast.types import Float32, Int64, Float64\n",
+ "\n",
+ "# Read data from parquet files. Parquet is convenient for local development mode. For\n",
+ "# production, you can use your favorite DWH, such as BigQuery. See Feast documentation\n",
+ "# for more info.\n",
+ "driver_hourly_stats = FileSource(\n",
+ " name=\"driver_hourly_stats_source\",\n",
+ " path=\"/content/feature_repo/data/driver_stats.parquet\",\n",
+ " timestamp_field=\"event_timestamp\",\n",
+ " created_timestamp_column=\"created\",\n",
+ ")\n",
+ "\n",
+ "# Define an entity for the driver. You can think of entity as a primary key used to\n",
+ "# fetch features.\n",
+ "driver = Entity(name=\"driver\", join_keys=[\"driver_id\"])\n",
+ "\n",
+ "# Our parquet files contain sample data that includes a driver_id column, timestamps and\n",
+ "# three feature column. Here we define a Feature View that will allow us to serve this\n",
+ "# data to our model online.\n",
+ "driver_hourly_stats_view = FeatureView(\n",
+ " name=\"driver_hourly_stats\",\n",
+ " entities=[driver],\n",
+ " ttl=timedelta(days=1),\n",
+ " schema=[\n",
+ " Field(name=\"conv_rate\", dtype=Float32),\n",
+ " Field(name=\"acc_rate\", dtype=Float32),\n",
+ " Field(name=\"avg_daily_trips\", dtype=Int64),\n",
+ " ],\n",
+ " online=True,\n",
+ " source=driver_hourly_stats,\n",
+ " tags={},\n",
+ ")\n",
+ "\n",
+ "# Defines a way to push data (to be available offline, online or both) into Feast.\n",
+ "driver_stats_push_source = PushSource(\n",
+ " name=\"driver_stats_push_source\",\n",
+ " batch_source=driver_hourly_stats,\n",
+ ")\n",
+ "\n",
+ "# Define a request data source which encodes features / information only\n",
+ "# available at request time (e.g. part of the user initiated HTTP request)\n",
+ "input_request = RequestSource(\n",
+ " name=\"vals_to_add\",\n",
+ " schema=[\n",
+ " Field(name=\"val_to_add\", dtype=Int64),\n",
+ " Field(name=\"val_to_add_2\", dtype=Int64),\n",
+ " ],\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# Define an on demand feature view which can generate new features based on\n",
+ "# existing feature views and RequestSource features\n",
+ "@on_demand_feature_view(\n",
+ " sources=[driver_hourly_stats_view, input_request],\n",
+ " schema=[\n",
+ " Field(name=\"conv_rate_plus_val1\", dtype=Float64),\n",
+ " Field(name=\"conv_rate_plus_val2\", dtype=Float64),\n",
+ " ],\n",
+ ")\n",
+ "def transformed_conv_rate(inputs: pd.DataFrame) -> pd.DataFrame:\n",
+ " df = pd.DataFrame()\n",
+ " df[\"conv_rate_plus_val1\"] = inputs[\"conv_rate\"] + inputs[\"val_to_add\"]\n",
+ " df[\"conv_rate_plus_val2\"] = inputs[\"conv_rate\"] + inputs[\"val_to_add_2\"]\n",
+ " return df\n",
+ "\n",
+ "\n",
+ "# This groups features into a model version\n",
+ "driver_stats_fs = FeatureService(\n",
+ " name=\"driver_activity\", features=[driver_hourly_stats_view, transformed_conv_rate]\n",
+ ")\n",
+ "```"
]
},
{
@@ -571,12 +524,12 @@
},
"source": [
"### Step 3b: Applying feature definitions\n",
- "Now we run `feast apply` to register the feature views and entities defined in `example.py`, and sets up SQLite online store tables. Note that we had previously specified SQLite as the online store in `feature_store.yaml` by specifying a `local` provider."
+ "Now we run `feast apply` to register the feature views and entities defined in `example_repo.py`, and sets up SQLite online store tables. Note that we had previously specified SQLite as the online store in `feature_store.yaml` by specifying a `local` provider."
]
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -589,12 +542,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/usr/local/lib/python3.7/dist-packages/scipy/fft/__init__.py:97: DeprecationWarning: The module numpy.dual is deprecated. Instead of using dual, use the functions directly from numpy or scipy.\n",
- " from numpy.dual import register_func\n",
- "/usr/local/lib/python3.7/dist-packages/scipy/sparse/sputils.py:17: DeprecationWarning: `np.typeDict` is a deprecated alias for `np.sctypeDict`.\n",
- " supported_dtypes = [np.typeDict[x] for x in supported_dtypes]\n",
+ "RuntimeWarning: On demand feature view is an experimental feature. This API is stable, but the functionality does not scale well for offline retrieval\n",
+ " warnings.warn(\n",
"Created entity \u001b[1m\u001b[32mdriver\u001b[0m\n",
"Created feature view \u001b[1m\u001b[32mdriver_hourly_stats\u001b[0m\n",
+ "Created on demand feature view \u001b[1m\u001b[32mtransformed_conv_rate\u001b[0m\n",
"Created feature service \u001b[1m\u001b[32mdriver_activity\u001b[0m\n",
"\n",
"Created sqlite table \u001b[1m\u001b[32mfeature_repo_driver_hourly_stats\u001b[0m\n",
@@ -612,17 +564,24 @@
"id": "uV7rtRQgzyf0"
},
"source": [
- "## Step 4: Generate training data\n",
+ "## Step 4: Generating training data or powering batch scoring models\n",
+ "\n",
+ "To train a model, we need features and labels. Often, this label data is stored separately (e.g. you have one table storing user survey results and another set of tables with feature values). Feast can help generate the features that map to these labels.\n",
+ "\n",
+ "Feast needs a list of **entities** (e.g. driver ids) and **timestamps**. Feast will intelligently join relevant \n",
+ "tables to create the relevant feature vectors. There are two ways to generate this list:\n",
+ "1. The user can query that table of labels with timestamps and pass that into Feast as an _entity dataframe_ for \n",
+ "training data generation. \n",
+ "2. The user can also query that table with a *SQL query* which pulls entities. See the documentation on [feature retrieval](https://docs.feast.dev/getting-started/concepts/feature-retrieval) for details \n",
"\n",
- "To train a model, we need features and labels. Often, this label data is stored separately (e.g. you have one table storing user survey results and another set of tables with feature values). \n",
+ "* Note that we include timestamps because we want the features for the same driver at various timestamps to be used in a model.\n",
"\n",
- "The user can query that table of labels with timestamps and pass that into Feast as an *entity dataframe* for training data generation. In many cases, Feast will also intelligently join relevant tables to create the relevant feature vectors.\n",
- "- Note that we include timestamps because want the features for the same driver at various timestamps to be used in a model."
+ "### Step 4a: Generating training data"
]
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -631,16 +590,6 @@
"outputId": "58c4c3dd-7a10-4f56-901d-1bb879ebbcb8"
},
"outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/usr/local/lib/python3.7/dist-packages/scipy/fft/__init__.py:97: DeprecationWarning: The module numpy.dual is deprecated. Instead of using dual, use the functions directly from numpy or scipy.\n",
- " from numpy.dual import register_func\n",
- "/usr/local/lib/python3.7/dist-packages/scipy/sparse/sputils.py:17: DeprecationWarning: `np.typeDict` is a deprecated alias for `np.sctypeDict`.\n",
- " supported_dtypes = [np.typeDict[x] for x in supported_dtypes]\n"
- ]
- },
{
"name": "stdout",
"output_type": "stream",
@@ -648,50 +597,67 @@
"----- Feature schema -----\n",
"\n",
"
\n",
- "Int64Index: 3 entries, 1080 to 359\n",
- "Data columns (total 6 columns):\n",
+ "RangeIndex: 3 entries, 0 to 2\n",
+ "Data columns (total 10 columns):\n",
" # Column Non-Null Count Dtype \n",
"--- ------ -------------- ----- \n",
" 0 driver_id 3 non-null int64 \n",
- " 1 label_driver_reported_satisfaction 3 non-null int64 \n",
- " 2 event_timestamp 3 non-null datetime64[ns, UTC]\n",
- " 3 conv_rate 3 non-null float32 \n",
- " 4 acc_rate 3 non-null float32 \n",
- " 5 avg_daily_trips 3 non-null int32 \n",
- "dtypes: datetime64[ns, UTC](1), float32(2), int32(1), int64(2)\n",
- "memory usage: 132.0 bytes\n",
+ " 1 event_timestamp 3 non-null datetime64[ns, UTC]\n",
+ " 2 label_driver_reported_satisfaction 3 non-null int64 \n",
+ " 3 val_to_add 3 non-null int64 \n",
+ " 4 val_to_add_2 3 non-null int64 \n",
+ " 5 conv_rate 3 non-null float32 \n",
+ " 6 acc_rate 3 non-null float32 \n",
+ " 7 avg_daily_trips 3 non-null int32 \n",
+ " 8 conv_rate_plus_val1 3 non-null float64 \n",
+ " 9 conv_rate_plus_val2 3 non-null float64 \n",
+ "dtypes: datetime64[ns, UTC](1), float32(2), float64(2), int32(1), int64(4)\n",
+ "memory usage: 332.0 bytes\n",
"None\n",
"\n",
"----- Example features -----\n",
"\n",
- " driver_id label_driver_reported_satisfaction \\\n",
- "1080 1003 3 \n",
- "720 1002 5 \n",
- "359 1001 1 \n",
+ " driver_id event_timestamp label_driver_reported_satisfaction \\\n",
+ "0 1001 2021-04-12 10:59:42+00:00 1 \n",
+ "1 1002 2021-04-12 08:12:10+00:00 5 \n",
+ "2 1003 2021-04-12 16:40:26+00:00 3 \n",
+ "\n",
+ " val_to_add val_to_add_2 conv_rate acc_rate avg_daily_trips \\\n",
+ "0 1 10 0.356766 0.051319 93 \n",
+ "1 2 20 0.130452 0.359439 522 \n",
+ "2 3 30 0.666570 0.343380 266 \n",
"\n",
- " event_timestamp conv_rate acc_rate avg_daily_trips \n",
- "1080 2022-06-14 17:48:10.734341+00:00 0.525623 0.217880 488 \n",
- "720 2022-06-14 18:25:10.734338+00:00 0.181652 0.659991 974 \n",
- "359 2022-06-14 18:50:10.734322+00:00 0.651631 0.855919 685 \n"
+ " conv_rate_plus_val1 conv_rate_plus_val2 \n",
+ "0 1.356766 10.356766 \n",
+ "1 2.130452 20.130452 \n",
+ "2 3.666570 30.666570 \n"
]
}
],
"source": [
- "from datetime import datetime, timedelta\n",
+ "from datetime import datetime\n",
"import pandas as pd\n",
"\n",
"from feast import FeatureStore\n",
"\n",
"# The entity dataframe is the dataframe we want to enrich with feature values\n",
+ "# Note: see https://docs.feast.dev/getting-started/concepts/feature-retrieval for more details on how to retrieve\n",
+ "# for all entities in the offline store instead\n",
"entity_df = pd.DataFrame.from_dict(\n",
" {\n",
+ " # entity's join key -> entity values\n",
" \"driver_id\": [1001, 1002, 1003],\n",
- " \"label_driver_reported_satisfaction\": [1, 5, 3], \n",
+ " # \"event_timestamp\" (reserved key) -> timestamps\n",
" \"event_timestamp\": [\n",
- " datetime.now() - timedelta(minutes=11),\n",
- " datetime.now() - timedelta(minutes=36),\n",
- " datetime.now() - timedelta(minutes=73),\n",
+ " datetime(2021, 4, 12, 10, 59, 42),\n",
+ " datetime(2021, 4, 12, 8, 12, 10),\n",
+ " datetime(2021, 4, 12, 16, 40, 26),\n",
" ],\n",
+ " # (optional) label name -> label values. Feast does not process these\n",
+ " \"label_driver_reported_satisfaction\": [1, 5, 3],\n",
+ " # values we're using for an on-demand transformation\n",
+ " \"val_to_add\": [1, 2, 3],\n",
+ " \"val_to_add_2\": [10, 20, 30],\n",
" }\n",
")\n",
"\n",
@@ -703,6 +669,8 @@
" \"driver_hourly_stats:conv_rate\",\n",
" \"driver_hourly_stats:acc_rate\",\n",
" \"driver_hourly_stats:avg_daily_trips\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val1\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val2\",\n",
" ],\n",
").to_df()\n",
"\n",
@@ -714,6 +682,65 @@
"print(training_df.head())"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GFiXVdhz04t0"
+ },
+ "source": [
+ "### Step 4b: Run offline inference (batch scoring)\n",
+ "To power a batch model, we primarily need to generate features with the `get_historical_features` call, but using the current timestamp"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "rGR_xgIs04t0",
+ "outputId": "3496e5a1-79ff-4f3c-e35d-22b594992708"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "----- Example features -----\n",
+ "\n",
+ " driver_id event_timestamp \\\n",
+ "0 1001 2022-08-08 18:22:06.555018+00:00 \n",
+ "1 1002 2022-08-08 18:22:06.555018+00:00 \n",
+ "2 1003 2022-08-08 18:22:06.555018+00:00 \n",
+ "\n",
+ " label_driver_reported_satisfaction val_to_add val_to_add_2 conv_rate \\\n",
+ "0 1 1 10 0.663844 \n",
+ "1 5 2 20 0.151189 \n",
+ "2 3 3 30 0.769165 \n",
+ "\n",
+ " acc_rate avg_daily_trips conv_rate_plus_val1 conv_rate_plus_val2 \n",
+ "0 0.864639 359 1.663844 10.663844 \n",
+ "1 0.695982 311 2.151189 20.151189 \n",
+ "2 0.949191 789 3.769165 30.769165 \n"
+ ]
+ }
+ ],
+ "source": [
+ "entity_df[\"event_timestamp\"] = pd.to_datetime(\"now\", utc=True)\n",
+ "training_df = store.get_historical_features(\n",
+ " entity_df=entity_df,\n",
+ " features=[\n",
+ " \"driver_hourly_stats:conv_rate\",\n",
+ " \"driver_hourly_stats:acc_rate\",\n",
+ " \"driver_hourly_stats:avg_daily_trips\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val1\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val2\",\n",
+ " ],\n",
+ ").to_df()\n",
+ "\n",
+ "print(\"\\n----- Example features -----\\n\")\n",
+ "print(training_df.head())"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {
@@ -729,21 +756,21 @@
"id": "KCXUpiQ_pmDk"
},
"source": [
- "### Step 5a: Using `feast materialize-incremental`\n",
+ "### Step 5a: Using `materialize_incremental`\n",
"\n",
- "We now serialize the latest values of features since the beginning of time to prepare for serving (note: `materialize-incremental` serializes all new features since the last `materialize` call).\n",
+ "We now serialize the latest values of features since the beginning of time to prepare for serving (note: `materialize_incremental` serializes all new features since the last `materialize` call).\n",
"\n",
"An alternative to using the CLI command is to use Python:\n",
"\n",
- "```python\n",
- "from datetime import datetime\n",
- "store.materialize_incremental(datetime.datetime.now())\n",
+ "```bash\n",
+ "CURRENT_TIME=$(date -u +\"%Y-%m-%dT%H:%M:%S\")\n",
+ "feast materialize-incremental $CURRENT_TIME\n",
"```"
]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -756,20 +783,22 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/usr/local/lib/python3.7/dist-packages/scipy/fft/__init__.py:97: DeprecationWarning: The module numpy.dual is deprecated. Instead of using dual, use the functions directly from numpy or scipy.\n",
- " from numpy.dual import register_func\n",
- "/usr/local/lib/python3.7/dist-packages/scipy/sparse/sputils.py:17: DeprecationWarning: `np.typeDict` is a deprecated alias for `np.sctypeDict`.\n",
- " supported_dtypes = [np.typeDict[x] for x in supported_dtypes]\n",
- "Materializing \u001b[1m\u001b[32m1\u001b[0m feature views to \u001b[1m\u001b[32m2022-06-14 19:01:13+00:00\u001b[0m into the \u001b[1m\u001b[32msqlite\u001b[0m online store.\n",
+ "Materializing \u001b[1m\u001b[32m1\u001b[0m feature views to \u001b[1m\u001b[32m2022-08-08 14:19:04-04:00\u001b[0m into the \u001b[1m\u001b[32msqlite\u001b[0m online store.\n",
"\n",
- "\u001b[1m\u001b[32mdriver_hourly_stats\u001b[0m from \u001b[1m\u001b[32m2022-06-13 19:01:14+00:00\u001b[0m to \u001b[1m\u001b[32m2022-06-14 19:01:13+00:00\u001b[0m:\n",
- "100%|████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 403.44it/s]\n"
+ "\u001b[1m\u001b[32mdriver_hourly_stats\u001b[0m from \u001b[1m\u001b[32m2022-08-07 18:19:04-04:00\u001b[0m to \u001b[1m\u001b[32m2022-08-08 14:19:04-04:00\u001b[0m:\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 346.47it/s]\n"
]
}
],
"source": [
"from datetime import datetime\n",
- "!feast materialize-incremental {datetime.now().isoformat()}"
+ "store.materialize_incremental(datetime.now())"
]
},
{
@@ -785,7 +814,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -799,7 +828,7 @@
"output_type": "stream",
"text": [
"--- Data directory ---\n",
- "driver_stats.parquet online_store.db registry.db\n",
+ "driver_stats.parquet online_store.db registry.db\n",
"\n",
"--- Schema of online store ---\n",
"['entity_key', 'feature_name', 'value', 'event_ts', 'created_ts']\n"
@@ -838,7 +867,7 @@
"id": "GNecKOaI0J2Z"
},
"source": [
- "## Step 6: Fetching feature vectors for inference"
+ "## Step 6: Fetching real-time feature vectors for online inference"
]
},
{
@@ -852,7 +881,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -865,10 +894,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "{'acc_rate': [0.11573542654514313, 0.19155333936214447],\n",
- " 'avg_daily_trips': [814, 64],\n",
- " 'conv_rate': [0.5311259031295776, 0.9771925806999207],\n",
- " 'driver_id': [1004, 1005]}\n"
+ "{'acc_rate': [0.86463862657547, 0.6959823369979858],\n",
+ " 'avg_daily_trips': [359, 311],\n",
+ " 'conv_rate_plus_val1': [1000.6638441681862, 1001.1511893719435],\n",
+ " 'conv_rate_plus_val2': [2000.6638441681862, 2002.1511893719435],\n",
+ " 'driver_id': [1001, 1002]}\n"
]
}
],
@@ -880,13 +910,23 @@
"\n",
"feature_vector = store.get_online_features(\n",
" features=[\n",
- " \"driver_hourly_stats:conv_rate\",\n",
" \"driver_hourly_stats:acc_rate\",\n",
" \"driver_hourly_stats:avg_daily_trips\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val1\",\n",
+ " \"transformed_conv_rate:conv_rate_plus_val2\",\n",
" ],\n",
" entity_rows=[\n",
- " {\"driver_id\": 1004},\n",
- " {\"driver_id\": 1005},\n",
+ " # {join_key: entity_value}\n",
+ " {\n",
+ " \"driver_id\": 1001,\n",
+ " \"val_to_add\": 1000,\n",
+ " \"val_to_add_2\": 2000,\n",
+ " },\n",
+ " {\n",
+ " \"driver_id\": 1002,\n",
+ " \"val_to_add\": 1001,\n",
+ " \"val_to_add_2\": 2002,\n",
+ " },\n",
" ],\n",
").to_dict()\n",
"\n",
@@ -913,7 +953,7 @@
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -926,10 +966,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "{'acc_rate': [0.11573542654514313, 0.19155333936214447],\n",
- " 'avg_daily_trips': [814, 64],\n",
- " 'conv_rate': [0.5311259031295776, 0.9771925806999207],\n",
- " 'driver_id': [1004, 1005]}\n"
+ "{'acc_rate': [0.86463862657547, 0.6959823369979858],\n",
+ " 'avg_daily_trips': [359, 311],\n",
+ " 'conv_rate': [0.6638441681861877, 0.15118937194347382],\n",
+ " 'conv_rate_plus_val1': [1000.6638441681862, 1001.1511893719435],\n",
+ " 'conv_rate_plus_val2': [2000.6638441681862, 2002.1511893719435],\n",
+ " 'driver_id': [1001, 1002]}\n"
]
}
],
@@ -942,13 +984,77 @@
" features=feature_service,\n",
" entity_rows=[\n",
" # {join_key: entity_value}\n",
- " {\"driver_id\": 1004},\n",
- " {\"driver_id\": 1005},\n",
+ " {\n",
+ " \"driver_id\": 1001,\n",
+ " \"val_to_add\": 1000,\n",
+ " \"val_to_add_2\": 2000,\n",
+ " },\n",
+ " {\n",
+ " \"driver_id\": 1002,\n",
+ " \"val_to_add\": 1001,\n",
+ " \"val_to_add_2\": 2002,\n",
+ " },\n",
" ],\n",
").to_dict()\n",
"pprint(feature_vector)"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "PvPOSPV904t7"
+ },
+ "source": [
+ "## Step 7: Making streaming features available in Feast\n",
+ "Feast does not directly ingest from streaming sources. Instead, Feast relies on a push-based model to push features into Feast. You can write a streaming pipeline that generates features, which can then be pushed to the offline store, the online store, or both (depending on your needs).\n",
+ "\n",
+ "This relies on the `PushSource` defined above. Pushing to this source will populate all dependent feature views with the pushed feature values."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "uAg5xKDF04t7",
+ "outputId": "8288b911-125f-4141-b286-f6f84bcb24ea"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "--- Simulate a stream event ingestion of the hourly stats df ---\n",
+ " driver_id event_timestamp created conv_rate acc_rate \\\n",
+ "0 1001 2021-05-13 10:59:42 2021-05-13 10:59:42 1.0 1.0 \n",
+ "\n",
+ " avg_daily_trips \n",
+ "0 1000 \n"
+ ]
+ }
+ ],
+ "source": [
+ "from feast.data_source import PushMode\n",
+ "\n",
+ "print(\"\\n--- Simulate a stream event ingestion of the hourly stats df ---\")\n",
+ "event_df = pd.DataFrame.from_dict(\n",
+ " {\n",
+ " \"driver_id\": [1001],\n",
+ " \"event_timestamp\": [\n",
+ " datetime(2021, 5, 13, 10, 59, 42),\n",
+ " ],\n",
+ " \"created\": [\n",
+ " datetime(2021, 5, 13, 10, 59, 42),\n",
+ " ],\n",
+ " \"conv_rate\": [1.0],\n",
+ " \"acc_rate\": [1.0],\n",
+ " \"avg_daily_trips\": [1000],\n",
+ " }\n",
+ ")\n",
+ "print(event_df)\n",
+ "store.push(\"driver_stats_push_source\", event_df, to=PushMode.ONLINE_AND_OFFLINE)"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {
@@ -967,17 +1073,32 @@
"metadata": {
"colab": {
"collapsed_sections": [],
- "name": "Feast Codelab",
+ "name": "quickstart.ipynb",
"provenance": []
},
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python 3.8.10 64-bit ('python-3.8')",
+ "language": "python",
"name": "python3"
},
"language_info": {
- "name": "python"
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.10"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "7d634b9af180bcb32a446a43848522733ff8f5bbf0cc46dba1a83bede04bf237"
+ }
}
},
"nbformat": 4,
"nbformat_minor": 0
-}
+}
\ No newline at end of file
diff --git a/go/internal/feast/onlinestore/sqliteonlinestore_test.go b/go/internal/feast/onlinestore/sqliteonlinestore_test.go
index e5e6e85e56..9a56f4df1a 100644
--- a/go/internal/feast/onlinestore/sqliteonlinestore_test.go
+++ b/go/internal/feast/onlinestore/sqliteonlinestore_test.go
@@ -16,17 +16,18 @@ import (
func TestSqliteAndFeatureRepoSetup(t *testing.T) {
dir := t.TempDir()
- feature_repo_path := filepath.Join(dir, "feature_repo")
+ feature_repo_path := filepath.Join(dir, "my_project", "feature_repo")
err := test.SetupCleanFeatureRepo(dir)
assert.Nil(t, err)
config, err := registry.NewRepoConfigFromFile(feature_repo_path)
assert.Nil(t, err)
- assert.Equal(t, "feature_repo", config.Project)
+ assert.Equal(t, "my_project", config.Project)
assert.Equal(t, "data/registry.db", config.GetRegistryConfig().Path)
assert.Equal(t, "local", config.Provider)
assert.Equal(t, map[string]interface{}{
"path": "data/online_store.db",
+ "type": "sqlite",
}, config.OnlineStore)
assert.Empty(t, config.OfflineStore)
assert.Empty(t, config.FeatureServer)
@@ -35,12 +36,12 @@ func TestSqliteAndFeatureRepoSetup(t *testing.T) {
func TestSqliteOnlineRead(t *testing.T) {
dir := t.TempDir()
- feature_repo_path := filepath.Join(dir, "feature_repo")
+ feature_repo_path := filepath.Join(dir, "my_project", "feature_repo")
test.SetupCleanFeatureRepo(dir)
config, err := registry.NewRepoConfigFromFile(feature_repo_path)
assert.Nil(t, err)
- store, err := NewSqliteOnlineStore("feature_repo", config, config.OnlineStore)
+ store, err := NewSqliteOnlineStore("my_project", config, config.OnlineStore)
defer store.Destruct()
assert.Nil(t, err)
entity_key1 := types.EntityKey{
diff --git a/go/internal/feast/registry/local.go b/go/internal/feast/registry/local.go
index 8b35e5756b..124fcba3ed 100644
--- a/go/internal/feast/registry/local.go
+++ b/go/internal/feast/registry/local.go
@@ -12,15 +12,15 @@ import (
"github.com/feast-dev/feast/go/protos/feast/core"
)
-// A LocalRegistryStore is a file-based implementation of the RegistryStore interface.
-type LocalRegistryStore struct {
+// A FileRegistryStore is a file-based implementation of the RegistryStore interface.
+type FileRegistryStore struct {
filePath string
}
-// NewLocalRegistryStore creates a LocalRegistryStore with the given configuration and infers
+// NewFileRegistryStore creates a FileRegistryStore with the given configuration and infers
// the file path from the repo path and registry path.
-func NewLocalRegistryStore(config *RegistryConfig, repoPath string) *LocalRegistryStore {
- lr := LocalRegistryStore{}
+func NewFileRegistryStore(config *RegistryConfig, repoPath string) *FileRegistryStore {
+ lr := FileRegistryStore{}
registryPath := config.Path
if filepath.IsAbs(registryPath) {
lr.filePath = registryPath
@@ -31,7 +31,7 @@ func NewLocalRegistryStore(config *RegistryConfig, repoPath string) *LocalRegist
}
// GetRegistryProto reads and parses the registry proto from the file path.
-func (r *LocalRegistryStore) GetRegistryProto() (*core.Registry, error) {
+func (r *FileRegistryStore) GetRegistryProto() (*core.Registry, error) {
registry := &core.Registry{}
in, err := ioutil.ReadFile(r.filePath)
if err != nil {
@@ -43,15 +43,15 @@ func (r *LocalRegistryStore) GetRegistryProto() (*core.Registry, error) {
return registry, nil
}
-func (r *LocalRegistryStore) UpdateRegistryProto(rp *core.Registry) error {
+func (r *FileRegistryStore) UpdateRegistryProto(rp *core.Registry) error {
return r.writeRegistry(rp)
}
-func (r *LocalRegistryStore) Teardown() error {
+func (r *FileRegistryStore) Teardown() error {
return os.Remove(r.filePath)
}
-func (r *LocalRegistryStore) writeRegistry(rp *core.Registry) error {
+func (r *FileRegistryStore) writeRegistry(rp *core.Registry) error {
rp.VersionId = uuid.New().String()
rp.LastUpdated = timestamppb.Now()
bytes, err := proto.Marshal(rp)
diff --git a/go/internal/feast/registry/registry.go b/go/internal/feast/registry/registry.go
index c67a50a5a6..9d0684d023 100644
--- a/go/internal/feast/registry/registry.go
+++ b/go/internal/feast/registry/registry.go
@@ -16,8 +16,8 @@ var REGISTRY_SCHEMA_VERSION string = "1"
var REGISTRY_STORE_CLASS_FOR_SCHEME map[string]string = map[string]string{
"gs": "GCSRegistryStore",
"s3": "S3RegistryStore",
- "file": "LocalRegistryStore",
- "": "LocalRegistryStore",
+ "file": "FileRegistryStore",
+ "": "FileRegistryStore",
}
/*
@@ -335,8 +335,8 @@ func getRegistryStoreFromScheme(registryPath string, registryConfig *RegistryCon
func getRegistryStoreFromType(registryStoreType string, registryConfig *RegistryConfig, repoPath string) (RegistryStore, error) {
switch registryStoreType {
- case "LocalRegistryStore":
- return NewLocalRegistryStore(registryConfig, repoPath), nil
+ case "FileRegistryStore":
+ return NewFileRegistryStore(registryConfig, repoPath), nil
}
- return nil, errors.New("only LocalRegistryStore as a RegistryStore is supported at this moment")
+ return nil, errors.New("only FileRegistryStore as a RegistryStore is supported at this moment")
}
diff --git a/go/internal/test/feature_repo/example.py b/go/internal/test/feature_repo/example.py
index 2b1d74ad32..7084361007 100644
--- a/go/internal/test/feature_repo/example.py
+++ b/go/internal/test/feature_repo/example.py
@@ -1,10 +1,11 @@
# This is an example feature definition file
-from google.protobuf.duration_pb2 import Duration
+from datetime import timedelta
-from feast import Entity, Feature, FeatureView, FileSource, ValueType, FeatureService
+from feast import Entity, Feature, FeatureView, Field, FileSource, FeatureService
from feast.feature_logging import LoggingConfig
from feast.infra.offline_stores.file_source import FileLoggingDestination
+from feast.types import Float32, Int64
# Read data from parquet files. Parquet is convenient for local development mode. For
# production, you can use your favorite DWH, such as BigQuery. See Feast documentation
@@ -15,24 +16,24 @@
created_timestamp_column="created",
)
-# Define an entity for the driver. You can think of entity as a primary key used to
+# Define an entity for the driver. You can think of an entity as a primary key used to
# fetch features.
-driver = Entity(name="driver_id", value_type=ValueType.INT64, description="driver id",)
+driver = Entity(name="driver_id", description="driver id")
# Our parquet files contain sample data that includes a driver_id column, timestamps and
# three feature column. Here we define a Feature View that will allow us to serve this
# data to our model online.
driver_hourly_stats_view = FeatureView(
name="driver_hourly_stats",
- entities=["driver_id"],
- ttl=Duration(seconds=86400 * 365 * 10),
- features=[
- Feature(name="conv_rate", dtype=ValueType.FLOAT),
- Feature(name="acc_rate", dtype=ValueType.FLOAT),
- Feature(name="avg_daily_trips", dtype=ValueType.INT64),
+ entities=[driver],
+ ttl=timedelta(seconds=86400 * 365 * 10),
+ schema=[
+ Field(name="conv_rate", dtype=Float32),
+ Field(name="acc_rate", dtype=Float32),
+ Field(name="avg_daily_trips", dtype=Int64),
],
online=True,
- batch_source=driver_hourly_stats,
+ source=driver_hourly_stats,
tags={},
)
diff --git a/go/internal/test/go_integration_test_utils.go b/go/internal/test/go_integration_test_utils.go
index 275edc7b98..3ec9aa2a4c 100644
--- a/go/internal/test/go_integration_test_utils.go
+++ b/go/internal/test/go_integration_test_utils.go
@@ -88,7 +88,7 @@ func GetLatestFeatures(Rows []*Row, entities map[int64]bool) map[int64]*Row {
}
func SetupCleanFeatureRepo(basePath string) error {
- cmd := exec.Command("feast", "init", "feature_repo")
+ cmd := exec.Command("feast", "init", "my_project")
path, err := filepath.Abs(basePath)
cmd.Env = os.Environ()
@@ -102,7 +102,7 @@ func SetupCleanFeatureRepo(basePath string) error {
}
applyCommand := exec.Command("feast", "apply")
applyCommand.Env = os.Environ()
- featureRepoPath, err := filepath.Abs(filepath.Join(path, "feature_repo"))
+ featureRepoPath, err := filepath.Abs(filepath.Join(path, "my_project", "feature_repo"))
if err != nil {
return err
}
diff --git a/infra/charts/feast-feature-server/Chart.yaml b/infra/charts/feast-feature-server/Chart.yaml
index 6c1afc9540..81970bc1a8 100644
--- a/infra/charts/feast-feature-server/Chart.yaml
+++ b/infra/charts/feast-feature-server/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
name: feast-feature-server
description: Feast Feature Server in Go or Python
type: application
-version: 0.22.0
+version: 0.24.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast-feature-server/README.md b/infra/charts/feast-feature-server/README.md
index a55451e788..1ee114d9c8 100644
--- a/infra/charts/feast-feature-server/README.md
+++ b/infra/charts/feast-feature-server/README.md
@@ -1,24 +1,33 @@
-# feast-feature-server
+# Feast Python / Go Feature Server Helm Charts
- 
+Current chart version is `0.24.0`
-Feast Feature Server in Go or Python
+## Installation
-**Homepage:**
+Run the following commands to add the repository
-## Source Code
+```
+helm repo add feast-charts https://feast-helm-charts.storage.googleapis.com
+helm repo update
+```
+
+Install Feast
-*
+A base64 encoded version of the `feature_store.yaml` file is needed. Helm install example:
+```
+helm install feast-feature-server feast-charts/feast-feature-server --set feature_store_yaml_base64=$(base64 feature_store.yaml)
+```
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | |
+| feature_store_yaml_base64 | string | `""` | [required] a base64 encoded version of feature_store.yaml |
| fullnameOverride | string | `""` | |
| image.pullPolicy | string | `"IfNotPresent"` | |
-| image.repository | string | `""` | |
-| image.tag | string | `""` | |
+| image.repository | string | `"feastdev/feature-server"` | Docker image for Feature Server repository |
+| image.tag | string | `"0.23.0"` | The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) |
| imagePullSecrets | list | `[]` | |
| livenessProbe.initialDelaySeconds | int | `30` | |
| livenessProbe.periodSeconds | int | `30` | |
@@ -33,50 +42,4 @@ Feast Feature Server in Go or Python
| securityContext | object | `{}` | |
| service.port | int | `80` | |
| service.type | string | `"ClusterIP"` | |
-| tolerations | list | `[]` | |
-
-----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
-
-
-Docker repository and tag are required. Helm install example:
-```
-helm install feast-feature-server . --set image.repository=REPO --set image.tag=TAG
-```
-
-Deployment assumes that `feature_store.yaml` exists on docker image. Example docker image:
-```
-FROM python:3.8
-
-RUN apt update && \
- apt install -y jq
-
-RUN pip install pip --upgrade
-
-RUN pip install feast
-
-COPY feature_store.yaml /feature_store.yaml
-```
-
-Furthermore, if you wish to use the Go feature server, then you must install the Apache Arrow C++ libraries, and your `feature_store.yaml` should include `go_feature_server: True`.
-For more details, see the [docs](https://docs.feast.dev/reference/feature-servers/go-feature-server).
-The docker image might look like:
-```
-FROM python:3.8
-
-RUN apt update && \
- apt install -y jq
-
-RUN pip install pip --upgrade
-
-RUN pip install feast
-
-RUN apt update
-RUN apt install -y -V ca-certificates lsb-release wget
-RUN wget https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
-RUN apt install -y -V ./apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
-RUN apt update
-RUN apt -y install libarrow-dev
-
-COPY feature_store.yaml /feature_store.yaml
-```
\ No newline at end of file
+| tolerations | list | `[]` | |
\ No newline at end of file
diff --git a/infra/charts/feast-feature-server/README.md.gotmpl b/infra/charts/feast-feature-server/README.md.gotmpl
new file mode 100644
index 0000000000..75f2827466
--- /dev/null
+++ b/infra/charts/feast-feature-server/README.md.gotmpl
@@ -0,0 +1,23 @@
+# Feast Python / Go Feature Server Helm Charts
+
+Current chart version is `{{ template "chart.version" . }}`
+
+## Installation
+
+Run the following commands to add the repository
+
+```
+helm repo add feast-charts https://feast-helm-charts.storage.googleapis.com
+helm repo update
+```
+
+Install Feast
+
+A base64 encoded version of the `feature_store.yaml` file is needed. Helm install example:
+```
+helm install feast-feature-server feast-charts/feast-feature-server --set feature_store_yaml_base64=$(base64 feature_store.yaml)
+```
+
+{{ template "chart.requirementsSection" . }}
+
+{{ template "chart.valuesSection" . }}
\ No newline at end of file
diff --git a/infra/charts/feast-feature-server/templates/deployment.yaml b/infra/charts/feast-feature-server/templates/deployment.yaml
index 69cf92f6c0..94c56de9dd 100644
--- a/infra/charts/feast-feature-server/templates/deployment.yaml
+++ b/infra/charts/feast-feature-server/templates/deployment.yaml
@@ -30,6 +30,9 @@ spec:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
+ env:
+ - name: FEATURE_STORE_YAML_BASE64
+ value: {{ .Values.feature_store_yaml_base64 }}
command: ["feast", "serve", "-h", "0.0.0.0"]
ports:
- name: http
diff --git a/infra/charts/feast-feature-server/values.yaml b/infra/charts/feast-feature-server/values.yaml
index f62f95a757..257cf03bfa 100644
--- a/infra/charts/feast-feature-server/values.yaml
+++ b/infra/charts/feast-feature-server/values.yaml
@@ -5,14 +5,19 @@
replicaCount: 1
image:
- repository: ""
+ # image.repository -- Docker image for Feature Server repository
+ repository: feastdev/feature-server
pullPolicy: IfNotPresent
- tag: ""
+ # image.tag -- The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms)
+ tag: 0.24.0
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
+# feature_store_yaml_base64 -- [required] a base64 encoded version of feature_store.yaml
+feature_store_yaml_base64: ""
+
podAnnotations: {}
podSecurityContext: {}
diff --git a/infra/charts/feast-python-server/Chart.yaml b/infra/charts/feast-python-server/Chart.yaml
index 6ab82b7a65..d2b45ee8b6 100644
--- a/infra/charts/feast-python-server/Chart.yaml
+++ b/infra/charts/feast-python-server/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
name: feast-python-server
description: Feast Feature Server in Python
type: application
-version: 0.23.0
+version: 0.24.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast-python-server/README.md b/infra/charts/feast-python-server/README.md
index e3da9b1d29..acdf527531 100644
--- a/infra/charts/feast-python-server/README.md
+++ b/infra/charts/feast-python-server/README.md
@@ -1,14 +1,28 @@
-# feast-python-server
+# Feast Python Feature Server Helm Charts (deprecated)
- 
+> Note: this helm chart is deprecated in favor of [feast-feature-server](../feast-feature-server/README.md)
-Feast Feature Server in Python
+Current chart version is `0.24.0`
-**Homepage:**
+## Installation
+Docker repository and tag are required. Helm install example:
+```
+helm install feast-python-server . --set image.repository=REPO --set image.tag=TAG
+```
+
+Deployment assumes that `feature_store.yaml` exists on docker image. Example docker image:
+```
+FROM python:3.8
+
+RUN apt update && \
+ apt install -y jq
-## Source Code
+RUN pip install pip --upgrade
-*
+RUN pip install feast
+
+COPY feature_store.yaml /feature_store.yaml
+```
## Values
@@ -33,27 +47,4 @@ Feast Feature Server in Python
| securityContext | object | `{}` | |
| service.port | int | `80` | |
| service.type | string | `"ClusterIP"` | |
-| tolerations | list | `[]` | |
-
-----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0)
-
-
-Docker repository and tag are required. Helm install example:
-```
-helm install feast-python-server . --set image.repository=REPO --set image.tag=TAG
-```
-
-Deployment assumes that `feature_store.yaml` exists on docker image. Example docker image:
-```
-FROM python:3.8
-
-RUN apt update && \
- apt install -y jq
-
-RUN pip install pip --upgrade
-
-RUN pip install feast
-
-COPY feature_store.yaml /feature_store.yaml
-```
\ No newline at end of file
+| tolerations | list | `[]` | |
\ No newline at end of file
diff --git a/infra/charts/feast-python-server/README.md.gotmpl b/infra/charts/feast-python-server/README.md.gotmpl
new file mode 100644
index 0000000000..cb264c0066
--- /dev/null
+++ b/infra/charts/feast-python-server/README.md.gotmpl
@@ -0,0 +1,29 @@
+# Feast Python Feature Server Helm Charts (deprecated)
+
+> Note: this helm chart is deprecated in favor of [feast-feature-server](../feast-feature-server/README.md)
+
+Current chart version is `{{ template "chart.version" . }}`
+
+## Installation
+Docker repository and tag are required. Helm install example:
+```
+helm install feast-python-server . --set image.repository=REPO --set image.tag=TAG
+```
+
+Deployment assumes that `feature_store.yaml` exists on docker image. Example docker image:
+```
+FROM python:3.8
+
+RUN apt update && \
+ apt install -y jq
+
+RUN pip install pip --upgrade
+
+RUN pip install feast
+
+COPY feature_store.yaml /feature_store.yaml
+```
+
+{{ template "chart.requirementsSection" . }}
+
+{{ template "chart.valuesSection" . }}
\ No newline at end of file
diff --git a/infra/charts/feast-python-server/values.yaml b/infra/charts/feast-python-server/values.yaml
index f62f95a757..6d0ab9c0ae 100644
--- a/infra/charts/feast-python-server/values.yaml
+++ b/infra/charts/feast-python-server/values.yaml
@@ -5,8 +5,10 @@
replicaCount: 1
image:
+ # image.repository -- [required] The repository for the Docker image
repository: ""
pullPolicy: IfNotPresent
+ # image.tag -- [required] The Docker image tag
tag: ""
imagePullSecrets: []
diff --git a/infra/charts/feast/Chart.yaml b/infra/charts/feast/Chart.yaml
index f4e33de7f3..a657298b52 100644
--- a/infra/charts/feast/Chart.yaml
+++ b/infra/charts/feast/Chart.yaml
@@ -1,7 +1,7 @@
apiVersion: v1
description: Feature store for machine learning
name: feast
-version: 0.23.0
+version: 0.24.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md
index f71dcf6124..7a0f5f77aa 100644
--- a/infra/charts/feast/README.md
+++ b/infra/charts/feast/README.md
@@ -8,7 +8,7 @@ This repo contains Helm charts for Feast components that are being installed on
## Chart: Feast
-Feature store for machine learning Current chart version is `0.23.0`
+Feature store for machine learning Current chart version is `0.24.0`
## Installation
@@ -54,9 +54,9 @@ For more details, please see: https://docs.feast.dev/how-to-guides/running-feast
| Repository | Name | Version |
|------------|------|---------|
-| https://charts.helm.sh/stable | redis | 10.5.6 |
-| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.23.0 |
-| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.23.0 |
+| https://charts.helm.sh/stable | redis | 10.5.6 |
+| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.24.0 |
+| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.24.0 |
## Values
diff --git a/infra/charts/feast/README.md.gotmpl b/infra/charts/feast/README.md.gotmpl
index acb4e830e7..e215858fe0 100644
--- a/infra/charts/feast/README.md.gotmpl
+++ b/infra/charts/feast/README.md.gotmpl
@@ -1,7 +1,5 @@
# Feast Helm Charts
-> :warning: **Disclaimer**: Since Feast 0.10 our vision is to manage all infrastructure for feature store from one place - Feast SDK. But while this new paradigm is still in development, we are planning to support the installation of some Feast components (like Java feature server) through Helm chart presented in this repository. However, we do not expect helm chart to become a long-term solution for deploying Feast components to production, and some frictions still might exist. For example, you will need to manually sync some configurations from [feature_store.yaml](https://docs.feast.dev/reference/feature-repository/feature-store-yaml) into the chart context (like path to the registry file or project name).
-
This repo contains Helm charts for Feast components that are being installed on Kubernetes:
* Feast (root chart): The complete Helm chart containing all Feast components and dependencies. Most users will use this chart, but can selectively enable/disable subcharts using the values.yaml file.
* [Feature Server](charts/feature-server): High performant JVM-based implementation of feature server.
diff --git a/infra/charts/feast/charts/feature-server/Chart.yaml b/infra/charts/feast/charts/feature-server/Chart.yaml
index ee08b0b0f8..f238b6aee4 100644
--- a/infra/charts/feast/charts/feature-server/Chart.yaml
+++ b/infra/charts/feast/charts/feature-server/Chart.yaml
@@ -1,8 +1,8 @@
apiVersion: v1
description: "Feast Feature Server: Online feature serving service for Feast"
name: feature-server
-version: 0.23.0
-appVersion: v0.23.0
+version: 0.24.0
+appVersion: v0.24.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/charts/feature-server/README.md b/infra/charts/feast/charts/feature-server/README.md
index 4717cfff3a..465665fb3b 100644
--- a/infra/charts/feast/charts/feature-server/README.md
+++ b/infra/charts/feast/charts/feature-server/README.md
@@ -1,6 +1,6 @@
# feature-server
- 
+ 
Feast Feature Server: Online feature serving service for Feast
@@ -8,63 +8,60 @@ Feast Feature Server: Online feature serving service for Feast
## Values
-| Key | Type | Default | Description |
-|-----|------|-------------------------------------------------------|-------------|
-| "application-generated.yaml".enabled | bool | `true` | Flag to include Helm generated configuration. Please set `application-override.yaml` to override this configuration. |
-| "application-override.yaml" | object | `{"enabled":true}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a ConfigMap. `application-override.yaml` has a higher precedence than `application-secret.yaml` |
-| "application-secret.yaml" | object | `{"enabled":true}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a Secret. `application-override.yaml` has a higher precedence than `application-secret.yaml`. It is recommended to either set `application-override.yaml` or `application-secret.yaml` only to simplify config management. |
-| "application.yaml".enabled | bool | `true` | Flag to include the default [configuration](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Please set `application-override.yaml` to override this configuration. |
-| envOverrides | object | `{}` | Extra environment variables to set |
-| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
-| image.repository | string | `"feastdev/feature-server-java"` | Docker image for Feature Server repository |
-| image.tag | string | `"0.23.0"` | Image tag |
-| ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress |
-| ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth |
-| ingress.grpc.class | string | `"nginx"` | Which ingress controller to use |
-| ingress.grpc.enabled | bool | `false` | Flag to create an ingress resource for the service |
-| ingress.grpc.hosts | list | `[]` | List of hostnames to match when routing requests |
-| ingress.grpc.https.enabled | bool | `true` | Flag to enable HTTPS |
-| ingress.grpc.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
-| ingress.grpc.whitelist | string | `""` | Allowed client IP source ranges |
-| ingress.http.annotations | object | `{}` | Extra annotations for the ingress |
+| Key | Type | Default | Description |
+|-----|------|---------|-------------|
+| "application-generated.yaml".enabled | bool | `true` | Flag to include Helm generated configuration. Please set `application-override.yaml` to override this configuration. |
+| "application-override.yaml" | object | `{"enabled":true}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a ConfigMap. `application-override.yaml` has a higher precedence than `application-secret.yaml` |
+| "application-secret.yaml" | object | `{"enabled":false}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a Secret. `application-override.yaml` has a higher precedence than `application-secret.yaml`. It is recommended to either set `application-override.yaml` or `application-secret.yaml` only to simplify config management. |
+| "application.yaml".enabled | bool | `true` | Flag to include the default [configuration](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Please set `application-override.yaml` to override this configuration. |
+| envOverrides | object | `{}` | Extra environment variables to set |
+| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
+| image.repository | string | `"feastdev/feature-server-java"` | Docker image for Feature Server repository |
+| image.tag | string | `"0.24.0"` | Image tag |
+| ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress |
+| ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth |
+| ingress.grpc.class | string | `"nginx"` | Which ingress controller to use |
+| ingress.grpc.enabled | bool | `false` | Flag to create an ingress resource for the service |
+| ingress.grpc.hosts | list | `[]` | List of hostnames to match when routing requests |
+| ingress.grpc.https.enabled | bool | `true` | Flag to enable HTTPS |
+| ingress.grpc.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
+| ingress.grpc.whitelist | string | `""` | Allowed client IP source ranges |
+| ingress.http.annotations | object | `{}` | Extra annotations for the ingress |
| ingress.http.auth.authUrl | string | `"http://auth-server.auth-ns.svc.cluster.local/auth"` | URL to an existing authentication service |
-| ingress.http.auth.enabled | bool | `false` | Flag to enable auth |
-| ingress.http.class | string | `"nginx"` | Which ingress controller to use |
-| ingress.http.enabled | bool | `false` | Flag to create an ingress resource for the service |
-| ingress.http.hosts | list | `[]` | List of hostnames to match when routing requests |
-| ingress.http.https.enabled | bool | `true` | Flag to enable HTTPS |
-| ingress.http.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
-| ingress.http.whitelist | string | `""` | Allowed client IP source ranges |
-| javaOpts | string | `nil` | [JVM options](https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html). For better performance, it is advised to set the min and max heap:
`-Xms2048m -Xmx2048m` |
-| livenessProbe.enabled | bool | `true` | Flag to enabled the probe |
-| livenessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
-| livenessProbe.initialDelaySeconds | int | `60` | Delay before the probe is initiated |
-| livenessProbe.periodSeconds | int | `10` | How often to perform the probe |
-| livenessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
-| livenessProbe.timeoutSeconds | int | `5` | When the probe times out |
-| logLevel | string | `"WARN"` | Default log level, use either one of `DEBUG`, `INFO`, `WARN` or `ERROR` |
-| logType | string | `"Console"` | Log format, either `JSON` or `Console` |
-| nodeSelector | object | `{}` | Node labels for pod assignment |
-| podAnnotations | object | `{}` | Annotations to be added to Feast Serving pods |
-| podLabels | object | `{}` | Labels to be added to Feast Serving pods |
-| readinessProbe.enabled | bool | `true` | Flag to enabled the probe |
-| readinessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
-| readinessProbe.initialDelaySeconds | int | `15` | Delay before the probe is initiated |
-| readinessProbe.periodSeconds | int | `10` | How often to perform the probe |
-| readinessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
-| readinessProbe.timeoutSeconds | int | `10` | When the probe times out |
-| replicaCount | int | `1` | Number of pods that will be created |
-| resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) |
-| secrets | list | `[]` | List of Kubernetes secrets to be mounted. These secrets will be mounted on /etc/secrets/. |
-| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to |
-| service.grpc.port | int | `6566` | Service port for GRPC requests |
-| service.grpc.targetPort | int | `6566` | Container port serving GRPC requests |
-| service.http.nodePort | string | `nil` | Port number that each cluster node will listen to |
-| service.http.port | int | `80` | Service port for HTTP requests |
-| service.http.targetPort | int | `8080` | Container port serving HTTP requests and Prometheus metrics |
-| service.type | string | `"ClusterIP"` | Kubernetes service type |
-| transformationService.host | string | `""` | |
-| transformationService.port | int | `6566` | |
+| ingress.http.auth.enabled | bool | `false` | Flag to enable auth |
+| ingress.http.class | string | `"nginx"` | Which ingress controller to use |
+| ingress.http.enabled | bool | `false` | Flag to create an ingress resource for the service |
+| ingress.http.hosts | list | `[]` | List of hostnames to match when routing requests |
+| ingress.http.https.enabled | bool | `true` | Flag to enable HTTPS |
+| ingress.http.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
+| ingress.http.whitelist | string | `""` | Allowed client IP source ranges |
+| javaOpts | string | `nil` | [JVM options](https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html). For better performance, it is advised to set the min and max heap:
`-Xms2048m -Xmx2048m` |
+| livenessProbe.enabled | bool | `true` | Flag to enabled the probe |
+| livenessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
+| livenessProbe.initialDelaySeconds | int | `60` | Delay before the probe is initiated |
+| livenessProbe.periodSeconds | int | `10` | How often to perform the probe |
+| livenessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
+| livenessProbe.timeoutSeconds | int | `5` | When the probe times out |
+| logLevel | string | `"WARN"` | Default log level, use either one of `DEBUG`, `INFO`, `WARN` or `ERROR` |
+| logType | string | `"Console"` | Log format, either `JSON` or `Console` |
+| nodeSelector | object | `{}` | Node labels for pod assignment |
+| podAnnotations | object | `{}` | Annotations to be added to Feast Serving pods |
+| podLabels | object | `{}` | Labels to be added to Feast Serving pods |
+| readinessProbe.enabled | bool | `true` | Flag to enabled the probe |
+| readinessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
+| readinessProbe.initialDelaySeconds | int | `15` | Delay before the probe is initiated |
+| readinessProbe.periodSeconds | int | `10` | How often to perform the probe |
+| readinessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
+| readinessProbe.timeoutSeconds | int | `10` | When the probe times out |
+| replicaCount | int | `1` | Number of pods that will be created |
+| resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) |
+| secrets | list | `[]` | List of Kubernetes secrets to be mounted. These secrets will be mounted on /etc/secrets/. |
+| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to |
+| service.grpc.port | int | `6566` | Service port for GRPC requests |
+| service.grpc.targetPort | int | `6566` | Container port serving GRPC requests |
+| service.type | string | `"ClusterIP"` | Kubernetes service type |
+| transformationService.host | string | `""` | |
+| transformationService.port | int | `6566` | |
----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0)
+Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
diff --git a/infra/charts/feast/charts/feature-server/templates/configmap.yaml b/infra/charts/feast/charts/feature-server/templates/configmap.yaml
index fbf2633e8e..c172e9e288 100644
--- a/infra/charts/feast/charts/feature-server/templates/configmap.yaml
+++ b/infra/charts/feast/charts/feature-server/templates/configmap.yaml
@@ -28,9 +28,6 @@ data:
config:
host: {{ .Release.Name }}-redis-master
port: 6379
- rest:
- server:
- port: {{ .Values.service.http.targetPort }}
grpc:
server:
port: {{ .Values.service.grpc.targetPort }}
diff --git a/infra/charts/feast/charts/feature-server/templates/deployment.yaml b/infra/charts/feast/charts/feature-server/templates/deployment.yaml
index 1d1bc40029..ad0a12b3fc 100644
--- a/infra/charts/feast/charts/feature-server/templates/deployment.yaml
+++ b/infra/charts/feast/charts/feature-server/templates/deployment.yaml
@@ -106,8 +106,6 @@ spec:
{{- end }}
ports:
- - name: http
- containerPort: {{ .Values.service.http.targetPort }}
- name: grpc
containerPort: {{ .Values.service.grpc.targetPort }}
diff --git a/infra/charts/feast/charts/feature-server/templates/service.yaml b/infra/charts/feast/charts/feature-server/templates/service.yaml
index 037fe03870..c2455bd9f7 100644
--- a/infra/charts/feast/charts/feature-server/templates/service.yaml
+++ b/infra/charts/feast/charts/feature-server/templates/service.yaml
@@ -22,12 +22,6 @@ spec:
{{ toYaml .Values.service.loadBalancerSourceRanges | indent 2 }}
{{- end }}
ports:
- - name: http
- port: {{ .Values.service.http.port }}
- targetPort: {{ .Values.service.http.targetPort }}
- {{- if .Values.service.http.nodePort }}
- nodePort: {{ .Values.service.http.nodePort }}
- {{- end }}
- name: grpc
port: {{ .Values.service.grpc.port }}
targetPort: {{ .Values.service.grpc.targetPort }}
diff --git a/infra/charts/feast/charts/feature-server/values.yaml b/infra/charts/feast/charts/feature-server/values.yaml
index 011ce9dc33..b014d8cee7 100644
--- a/infra/charts/feast/charts/feature-server/values.yaml
+++ b/infra/charts/feast/charts/feature-server/values.yaml
@@ -5,7 +5,7 @@ image:
# image.repository -- Docker image for Feature Server repository
repository: feastdev/feature-server-java
# image.tag -- Image tag
- tag: 0.23.0
+ tag: 0.24.0
# image.pullPolicy -- Image pull policy
pullPolicy: IfNotPresent
@@ -71,13 +71,6 @@ readinessProbe:
service:
# service.type -- Kubernetes service type
type: ClusterIP
- http:
- # service.http.port -- Service port for HTTP requests
- port: 80
- # service.http.targetPort -- Container port serving HTTP requests and Prometheus metrics
- targetPort: 8080
- # service.http.nodePort -- Port number that each cluster node will listen to
- nodePort:
grpc:
# service.grpc.port -- Service port for GRPC requests
port: 6566
diff --git a/infra/charts/feast/charts/transformation-service/Chart.yaml b/infra/charts/feast/charts/transformation-service/Chart.yaml
index 07055730c5..4c650544f5 100644
--- a/infra/charts/feast/charts/transformation-service/Chart.yaml
+++ b/infra/charts/feast/charts/transformation-service/Chart.yaml
@@ -1,8 +1,8 @@
apiVersion: v1
description: "Transformation service: to compute on-demand features"
name: transformation-service
-version: 0.23.0
-appVersion: v0.23.0
+version: 0.24.0
+appVersion: v0.24.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/charts/transformation-service/README.md b/infra/charts/feast/charts/transformation-service/README.md
index 9bc7a1e5d6..7b55e1a10c 100644
--- a/infra/charts/feast/charts/transformation-service/README.md
+++ b/infra/charts/feast/charts/transformation-service/README.md
@@ -1,6 +1,6 @@
# transformation-service
- 
+ 
Transformation service: to compute on-demand features
@@ -8,20 +8,21 @@ Transformation service: to compute on-demand features
## Values
-| Key | Type | Default | Description |
-|-----|------|--------------------------------------------|-------------|
-| envOverrides | object | `{}` | Extra environment variables to set |
-| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
+| Key | Type | Default | Description |
+|-----|------|---------|-------------|
+| envOverrides | object | `{}` | Extra environment variables to set |
+| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"feastdev/feature-transformation-server"` | Docker image for Transformation Server repository |
-| image.tag | string | `"0.23.0"` | Image tag |
-| nodeSelector | object | `{}` | Node labels for pod assignment |
-| podLabels | object | `{}` | Labels to be added to Feast Serving pods |
-| replicaCount | int | `1` | Number of pods that will be created |
-| resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) |
-| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to |
-| service.grpc.port | int | `6566` | Service port for GRPC requests |
-| service.grpc.targetPort | int | `6566` | Container port serving GRPC requests |
-| service.type | string | `"ClusterIP"` | Kubernetes service type |
+| image.tag | string | `"0.24.0"` | Image tag |
+| nodeSelector | object | `{}` | Node labels for pod assignment |
+| podLabels | object | `{}` | Labels to be added to Feast Serving pods |
+| replicaCount | int | `1` | Number of pods that will be created |
+| resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) |
+| secrets | list | `[]` | List of Kubernetes secrets to be mounted. These secrets will be mounted on /etc/secrets/. |
+| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to |
+| service.grpc.port | int | `6566` | Service port for GRPC requests |
+| service.grpc.targetPort | int | `6566` | Container port serving GRPC requests |
+| service.type | string | `"ClusterIP"` | Kubernetes service type |
----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0)
+Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
diff --git a/infra/charts/feast/charts/transformation-service/config/feature_store.yaml b/infra/charts/feast/charts/transformation-service/config/feature_store.yaml
index 555e93a306..c003b87cc2 100644
--- a/infra/charts/feast/charts/transformation-service/config/feature_store.yaml
+++ b/infra/charts/feast/charts/transformation-service/config/feature_store.yaml
@@ -2,7 +2,4 @@ registry:
path: {{ .Values.global.registry.path }}
cache_ttl_seconds: {{ .Values.global.registry.cache_ttl_seconds }}
provider: local
-project: {{ .Values.global.project }}
-flags:
- on_demand_transforms: true
- alpha_features: true
\ No newline at end of file
+project: {{ .Values.global.project }}
\ No newline at end of file
diff --git a/infra/charts/feast/charts/transformation-service/values.yaml b/infra/charts/feast/charts/transformation-service/values.yaml
index c1e506a476..149d613e9f 100644
--- a/infra/charts/feast/charts/transformation-service/values.yaml
+++ b/infra/charts/feast/charts/transformation-service/values.yaml
@@ -5,7 +5,7 @@ image:
# image.repository -- Docker image for Transformation Server repository
repository: feastdev/feature-transformation-server
# image.tag -- Image tag
- tag: 0.23.0
+ tag: 0.24.0
# image.pullPolicy -- Image pull policy
pullPolicy: IfNotPresent
diff --git a/infra/charts/feast/requirements.yaml b/infra/charts/feast/requirements.yaml
index c88fb7a4fa..5dd4a4bce1 100644
--- a/infra/charts/feast/requirements.yaml
+++ b/infra/charts/feast/requirements.yaml
@@ -1,12 +1,12 @@
dependencies:
- name: feature-server
alias: feature-server
- version: 0.23.0
+ version: 0.24.0
condition: feature-server.enabled
repository: https://feast-helm-charts.storage.googleapis.com
- name: transformation-service
alias: transformation-service
- version: 0.23.0
+ version: 0.24.0
condition: transformation-service.enabled
repository: https://feast-helm-charts.storage.googleapis.com
- name: redis
diff --git a/infra/scripts/cleanup_dynamo_ci.py b/infra/scripts/cleanup_dynamo_ci.py
new file mode 100644
index 0000000000..2dda36cc5a
--- /dev/null
+++ b/infra/scripts/cleanup_dynamo_ci.py
@@ -0,0 +1,22 @@
+import boto3
+from tqdm import tqdm
+
+
+def main() -> None:
+ db = boto3.resource("dynamodb")
+
+ num_to_delete = 0
+ all_tables = db.tables.all()
+ for table in all_tables:
+ if "integration_test" in table.name:
+ num_to_delete += 1
+ with tqdm(total=num_to_delete) as progress:
+ for table in all_tables:
+ if "integration_test" in table.name:
+ table.delete()
+ progress.update()
+ print(f"Deleted {num_to_delete} CI DynamoDB tables")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/infra/scripts/helm/push-helm-charts.sh b/infra/scripts/helm/push-helm-charts.sh
index 08753adb3c..1c32ee985b 100755
--- a/infra/scripts/helm/push-helm-charts.sh
+++ b/infra/scripts/helm/push-helm-charts.sh
@@ -17,7 +17,9 @@ helm repo add feast-helm-chart-repo $bucket
cd infra/charts
helm package feast
helm package feast-python-server
+helm package feast-feature-server
helm gcs push --public feast-${1}.tgz feast-helm-chart-repo --force
helm gcs push --public feast-python-server-${1}.tgz feast-helm-chart-repo --force
+helm gcs push --public feast-feature-server-${1}.tgz feast-helm-chart-repo --force
rm -f ./*.tgz
\ No newline at end of file
diff --git a/infra/scripts/helm/validate-helm-chart-versions.sh b/infra/scripts/helm/validate-helm-chart-versions.sh
index 0ba75bd744..aac79d9315 100755
--- a/infra/scripts/helm/validate-helm-chart-versions.sh
+++ b/infra/scripts/helm/validate-helm-chart-versions.sh
@@ -3,7 +3,7 @@
set -e
# Amount of file locations that need to be bumped in unison when versions increment
-UNIQUE_VERSIONS_COUNT=18
+UNIQUE_VERSIONS_COUNT=20
if [ $# -ne 1 ]; then
echo "Please provide a single semver version (without a \"v\" prefix) to test the repository against, e.g 0.99.0"
diff --git a/infra/scripts/publish-java-sdk.sh b/infra/scripts/publish-java-sdk.sh
index 68174db17a..0e8b62478f 100755
--- a/infra/scripts/publish-java-sdk.sh
+++ b/infra/scripts/publish-java-sdk.sh
@@ -69,4 +69,4 @@ gpg --import --batch --yes $GPG_KEY_IMPORT_DIR/private-key
echo "============================================================"
echo "Deploying Java SDK with revision: $REVISION"
echo "============================================================"
-mvn -f java/pom.xml --projects .,datatypes,sdk -Drevision=$REVISION --batch-mode clean deploy
+mvn -f java/pom.xml --projects .,datatypes,serving-client -Drevision=$REVISION --batch-mode clean deploy
diff --git a/infra/scripts/create-cluster.sh b/infra/scripts/redis-cluster.sh
similarity index 100%
rename from infra/scripts/create-cluster.sh
rename to infra/scripts/redis-cluster.sh
diff --git a/infra/scripts/release/files_to_bump.txt b/infra/scripts/release/files_to_bump.txt
index a1e2d29623..e94ec88db0 100644
--- a/infra/scripts/release/files_to_bump.txt
+++ b/infra/scripts/release/files_to_bump.txt
@@ -8,5 +8,9 @@ infra/charts/feast/charts/feature-server/README.md 3 20
infra/charts/feast/charts/feature-server/values.yaml 8
infra/charts/feast/README.md 11 58 59
infra/charts/feast-python-server/Chart.yaml 5
-infra/charts/feast-python-server/README.md 3
-java/pom.xml 41
+infra/charts/feast-python-server/README.md 5
+infra/charts/feast-feature-server/Chart.yaml 5
+infra/charts/feast-feature-server/README.md 3
+infra/charts/feast-feature-server/values.yaml 12
+java/pom.xml 38
+ui/package.json 3
diff --git a/infra/templates/README.md.jinja2 b/infra/templates/README.md.jinja2
index 6a8ebdbab7..e59a364d81 100644
--- a/infra/templates/README.md.jinja2
+++ b/infra/templates/README.md.jinja2
@@ -21,7 +21,7 @@ Feast (**Fea**ture **St**ore) is an open source feature store for machine learni
Feast allows ML platform teams to:
-* **Make features consistently available for training and serving** by managing an _offline store_ (to process historical data for scale-out batch scoring or model training), a low-latency _online store_ (to power real-time prediction)_,_ and a battle-tested _feature server_ (for serving pre-computed features online).
+* **Make features consistently available for training and serving** by managing an _offline store_ (to process historical data for scale-out batch scoring or model training), a low-latency _online store_ (to power real-time prediction)_,_ and a battle-tested _feature server_ (to serve pre-computed features online).
* **Avoid data leakage** by generating point-in-time correct feature sets so data scientists can focus on feature engineering rather than debugging error-prone dataset joining logic. This ensure that future feature values do not leak to models during training.
* **Decouple ML from data infrastructure** by providing a single data access layer that abstracts feature storage from feature retrieval, ensuring models remain portable as you move from training models to serving models, from batch models to realtime models, and from one data infra system to another.
diff --git a/java/CONTRIBUTING.md b/java/CONTRIBUTING.md
index f6c789d984..7ccfe108c0 100644
--- a/java/CONTRIBUTING.md
+++ b/java/CONTRIBUTING.md
@@ -2,17 +2,40 @@
> The higher level [Development Guide](https://docs.feast.dev/v/master/project/development-guide)
> gives contributing to Feast codebase as a whole.
-### Overview
+## Overview
This guide is targeted at developers looking to contribute to Feast components in
the feast-java Repository:
- [Feast Serving](#feast-serving)
-- [Feast Java Client](#feast-java-client)
+- [Feast Serving Client](#feast-serving-client)
> Don't see the Feast component that you want to contribute to here?
> Check out the [Development Guide](https://docs.feast.dev/v/master/project/development-guide)
> to learn how Feast components are distributed over multiple repositories.
-#### Common Setup
+### Repository structure
+There are four key top level packages:
+- `serving`: Feast Serving (a gRPC service to serve features)
+- `serving-client`: Feast Serving Client (a thin Java client to communicate with Feast serving via gRPC )
+- `datatypes`: A symlink to the overall project protos. These include the core serving gRPC protos, proto representations of all objects in the Feast registry.
+- `coverage`: Generates JaCoCo coverage reports
+
+#### Feast Serving
+> **Note:** there are references to metrics collection in the code. These are unused and exist for legacy reasons (from when this used Spring Boot), but remain in the code until published to StatsD / Prometheus Pushgateway.
+
+The primary entrypoint into the Feast Serving server is `ServingGuiceApplication`, which connects to the rest of the packages:
+- `connectors`: Contains online store connectors (e.g. Redis)
+- `exception`: Contains user-facing exceptions thrown by Feast Serving
+- `registry`: Logic to parse a Feast file-based registry (in GCS, S3, or local) into the `Registry` proto object, and automatically re-sync the registry.
+- `service`: Core logic that exposes and backs the serving APIs. This includes communication with a feature transformation server to execute on demand transformations
+ - The root code in this package creates the main entrypoint (`ServingServiceV2`) which is injected into `OnlineServingGrpcServiceV2` in `grpc/` implement the gRPC service.
+ - `config`: Guice modules to power the server and config
+ - Includes server config / guice modules in `ServerModule`
+ - Maps overall Feast Serving user configuration from Java to YAML in `ApplicationPropertiesModule` and `ApplicationProperties`
+ - `controller`: server controllers (right now, only a gRPC health check)
+ - `grpc`: Implementation of the gRPC serving service
+ - `interceptors`: gRPC interceptors (currently used to produce metrics around each gRPC request)
+
+### Common Setup
Common Environment Setup for all feast-java Feast components:
Ensure following development tools are installed:
@@ -20,7 +43,7 @@ Ensure following development tools are installed:
- Maven 3.6
- `make`
-#### Code Style
+### Code Style
Feast's Java codebase conforms to the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html).
Automatically format the code to conform the style guide by:
@@ -33,27 +56,28 @@ mvn spotless:apply
> If you're using IntelliJ, you can import these [code style settings](https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml)
> if you'd like to use the IDE's reformat function.
-#### Project Makefile
+### Project Makefile
The Project Makefile provides useful shorthands for common development tasks:
+> Note: These commands rely on a local version of `feast` (Python) to be installed
Run all Unit tests:
```
make test-java
```
-Run all Integration tests:
+Run all Integration tests (note: this also runs GCS + S3 based tests which should fail):
```
make test-java-integration
```
-Building Docker images for Feast Core & Feast Serving:
+Building Docker images for Feast Serving:
```
make build-docker REGISTRY=gcr.io/kf-feast VERSION=develop
```
-#### IDE Setup
+### IDE Setup
If you're using IntelliJ, some additional steps may be needed to make sure IntelliJ autocomplete works as expected.
Specifically, proto-generated code is not indexed by IntelliJ. To fix this, navigate to the following window in IntelliJ:
`Project Structure > Modules > datatypes-java`, and mark the following folders as `Source` directorys:
@@ -64,12 +88,12 @@ Specifically, proto-generated code is not indexed by IntelliJ. To fix this, navi
## Feast Serving
See instructions [here](serving/README.md) for developing.
-## Feast Java Client
+## Feast Serving Client
### Environment Setup
-Setting up your development environment for Feast Java SDK:
+Setting up your development environment:
1. Complete the feast-java [Common Setup](#common-setup)
-> Feast Java Client is a Java Client for retrieving Features from a running Feast Serving instance.
+> Feast Serving Client is a Serving Client for retrieving Features from a running Feast Serving instance.
> See the [Feast Serving Section](#feast-serving) section for how to get a Feast Serving instance running.
### Building
diff --git a/java/README.md b/java/README.md
index 8c3d93628e..53573a6fed 100644
--- a/java/README.md
+++ b/java/README.md
@@ -3,8 +3,8 @@
### Overview
This repository contains the following Feast components.
-* Feast Serving: A service used to serve the latest feature values to models.
-* Feast Java SDK: A client used to retrieve features from Feast Serving.
+* Feast Serving: A gRPC service used to serve the latest feature values to models.
+* Feast Serving Client: A client used to retrieve features from Feast Serving.
### Architecture
@@ -16,6 +16,7 @@ Guides on Contributing:
- [Contribution Process for Feast](https://docs.feast.dev/v/master/project/contributing)
- [Development Guide for Feast](https://docs.feast.dev/v/master/project/development-guide)
- [Development Guide for feast-java (this repository)](CONTRIBUTING.md)
+ - **Note**: includes installing without using Helm
### Installing using Helm
Please see the Helm charts in [infra/charts/feast](../infra/charts/feast).
diff --git a/java/common/pom.xml b/java/common/pom.xml
deleted file mode 100644
index 6b580880f1..0000000000
--- a/java/common/pom.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-
-
-
- 4.0.0
-
-
- feast-parent
- dev.feast
- ${revision}
-
-
- Feast Common
- Feast common module with functionality that can be reused
- feast-common
-
-
-
- dev.feast
- feast-datatypes
- ${project.version}
- compile
-
-
- com.google.protobuf
- protobuf-java-util
- ${protobuf.version}
-
-
-
- org.apache.commons
- commons-lang3
- 3.6
-
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
- com.google.auto.value
- auto-value-annotations
- ${auto.value.version}
-
-
-
-
- com.google.code.gson
- gson
- ${gson.version}
-
-
- io.gsonfire
- gson-fire
- ${gson.fire.version}
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.12.6.1
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- ${jackson.version}
-
-
-
-
- org.slf4j
- slf4j-api
-
-
- org.fluentd
- fluent-logger
- 0.3.1
-
-
-
- javax.xml.bind
- jaxb-api
-
-
- javax.validation
- validation-api
-
-
-
-
- com.google.code.findbugs
- jsr305
- 3.0.2
-
-
-
-
- org.hamcrest
- hamcrest-library
- test
- ${hamcrest.version}
-
-
-
- junit
- junit
- 4.13.2
-
-
- org.mockito
- mockito-core
- ${mockito.version}
- test
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
-
-
-
-
- org.jacoco
- jacoco-maven-plugin
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M4
-
- -Xms2048m -Xmx2048m -Djdk.net.URLClassPath.disableClassPathURLCheck=true
-
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
-
- true
-
-
-
-
-
diff --git a/java/common/src/main/java/feast/common/logging/AuditLogger.java b/java/common/src/main/java/feast/common/logging/AuditLogger.java
deleted file mode 100644
index f3538a794b..0000000000
--- a/java/common/src/main/java/feast/common/logging/AuditLogger.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.util.JsonFormat;
-import feast.common.logging.config.LoggingProperties;
-import feast.common.logging.config.LoggingProperties.AuditLogProperties;
-import feast.common.logging.entry.*;
-import feast.common.logging.entry.LogResource.ResourceType;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.Map;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.fluentd.logger.FluentLogger;
-import org.slf4j.Marker;
-import org.slf4j.MarkerFactory;
-import org.slf4j.event.Level;
-
-@Slf4j
-public class AuditLogger {
- private static final String FLUENTD_DESTINATION = "fluentd";
- private static final Marker AUDIT_MARKER = MarkerFactory.getMarker("AUDIT_MARK");
- private static FluentLogger fluentLogger;
- private static AuditLogProperties properties;
- private static String artifact;
- private static String version;
-
- public AuditLogger(LoggingProperties loggingProperties, String artifact, String version) {
- // Spring runs this constructor when creating the AuditLogger bean,
- // which allows us to populate the AuditLogger class with dependencies.
- // This allows us to use the dependencies in the AuditLogger's static methods
- AuditLogger.properties = loggingProperties.getAudit();
- AuditLogger.artifact = artifact;
- AuditLogger.version = version;
- if (AuditLogger.properties.getMessageLogging() != null
- && AuditLogger.properties.getMessageLogging().isEnabled()) {
- AuditLogger.fluentLogger =
- FluentLogger.getLogger(
- "feast",
- AuditLogger.properties.getMessageLogging().getFluentdHost(),
- AuditLogger.properties.getMessageLogging().getFluentdPort());
- }
- }
-
- /**
- * Log the handling of a Protobuf message by a service call.
- *
- * @param level log level
- * @param entryBuilder with all fields set except instance.
- */
- public static void logMessage(Level level, MessageAuditLogEntry.Builder entryBuilder) {
- log(level, entryBuilder.setComponent(artifact).setVersion(version).build());
- }
-
- /**
- * Log an action being taken on a specific resource
- *
- * @param level describing the severity of the log.
- * @param action name of the action being taken on specific resource.
- * @param resourceType the type of resource being logged.
- * @param resourceId resource specific identifier identifing the instance of the resource.
- */
- public static void logAction(
- Level level, String action, ResourceType resourceType, String resourceId) {
- log(
- level,
- ActionAuditLogEntry.of(
- artifact, version, LogResource.of(resourceType, resourceId), action));
- }
-
- /**
- * Log a transition in state/status in a specific resource.
- *
- * @param level describing the severity of the log.
- * @param status name of end status which the resource transition to.
- * @param resourceType the type of resource being logged.
- * @param resourceId resource specific identifier identifing the instance of the resource.
- */
- public static void logTransition(
- Level level, String status, ResourceType resourceType, String resourceId) {
- log(
- level,
- TransitionAuditLogEntry.of(
- artifact, version, LogResource.of(resourceType, resourceId), status));
- }
-
- /**
- * Log given {@link AuditLogEntry} at the given logging {@link Level} to the Audit log.
- *
- * @param level describing the severity of the log.
- * @param entry the {@link AuditLogEntry} to push to the audit log.
- */
- private static void log(Level level, AuditLogEntry entry) {
- // Check if audit logging is of this specific log entry enabled.
- if (!properties.isEnabled()) {
- return;
- }
-
- // Either forward log to logging layer or log to console
- String destination = properties.getMessageLogging().getDestination();
- if (destination.equals(FLUENTD_DESTINATION)) {
- if (entry.getKind() == AuditLogEntryKind.MESSAGE) {
- Map fluentdLogs = new HashMap<>();
- MessageAuditLogEntry messageAuditLogEntry = (MessageAuditLogEntry) entry;
- String releaseName;
-
- try {
- releaseName =
- StringUtils.defaultIfEmpty(
- System.getenv("RELEASE_NAME"), InetAddress.getLocalHost().getHostAddress());
- } catch (UnknownHostException e) {
- releaseName = StringUtils.defaultIfEmpty(System.getenv("RELEASE_NAME"), "");
- }
-
- fluentdLogs.put("id", messageAuditLogEntry.getId());
- fluentdLogs.put("identity", messageAuditLogEntry.getIdentity());
- fluentdLogs.put("service", messageAuditLogEntry.getService());
- fluentdLogs.put("status_code", messageAuditLogEntry.getStatusCode());
- fluentdLogs.put("method", messageAuditLogEntry.getMethod());
- fluentdLogs.put("release_name", releaseName);
- try {
- fluentdLogs.put("request", JsonFormat.printer().print(messageAuditLogEntry.getRequest()));
- fluentdLogs.put(
- "response", JsonFormat.printer().print(messageAuditLogEntry.getResponse()));
- } catch (InvalidProtocolBufferException e) {
- }
- fluentLogger.log("fluentd", fluentdLogs);
- }
- } else {
- // Log event to audit log through enabled formats
- String entryJSON = entry.toJSON();
- switch (level) {
- case TRACE:
- log.trace(AUDIT_MARKER, entryJSON);
- break;
- case DEBUG:
- log.debug(AUDIT_MARKER, entryJSON);
- break;
- case INFO:
- log.info(AUDIT_MARKER, entryJSON);
- break;
- case WARN:
- log.warn(AUDIT_MARKER, entryJSON);
- break;
- case ERROR:
- log.error(AUDIT_MARKER, entryJSON);
- break;
- }
- }
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/config/LoggingProperties.java b/java/common/src/main/java/feast/common/logging/config/LoggingProperties.java
deleted file mode 100644
index 06e62f71af..0000000000
--- a/java/common/src/main/java/feast/common/logging/config/LoggingProperties.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2019 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.config;
-
-import feast.common.validators.OneOfStrings;
-import javax.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class LoggingProperties {
- @NotNull private AuditLogProperties audit;
-
- @Getter
- @Setter
- public static class AuditLogProperties {
- // Whether to enable/disable audit logging entirely.
- private boolean enabled;
-
- private MessageLogging messageLogging;
-
- @Getter
- @Setter
- public static class MessageLogging {
- // Whether to enable/disable message level (ie request/response) audit logging.
- private boolean enabled;
-
- // Whether to log to console or fluentd
- @OneOfStrings({"console", "fluentd"})
- private String destination;
-
- // fluentD service host for external (request/response) logging.
- private String fluentdHost;
-
- // fluentD service port for external (request/response) logging.
- private Integer fluentdPort;
- }
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/ActionAuditLogEntry.java b/java/common/src/main/java/feast/common/logging/entry/ActionAuditLogEntry.java
deleted file mode 100644
index 4fdeaee32a..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/ActionAuditLogEntry.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import com.google.auto.value.AutoValue;
-
-/** ActionAuditLogEntry records an action being taken on a specific resource */
-@AutoValue
-public abstract class ActionAuditLogEntry extends AuditLogEntry {
- /** @return The name of the action taken on the resource. */
- public abstract String getAction();
-
- /** @return The target resource of which the action was taken on. */
- public abstract LogResource getResource();
-
- /**
- * Create an {@link AuditLogEntry} that records an action being taken on a specific resource.
- *
- * @param component The name of th Feast component producing this {@link AuditLogEntry}.
- * @param version The version of Feast producing this {@link AuditLogEntry}.
- * @param resource The target resource of which the action was taken on.
- * @param action The name of the action being taken on the given resource.
- * @return log entry that records an action being taken on a specific resource
- */
- public static ActionAuditLogEntry of(
- String component, String version, LogResource resource, String action) {
- return new AutoValue_ActionAuditLogEntry(
- component, version, AuditLogEntryKind.ACTION, action, resource);
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/AuditLogEntry.java b/java/common/src/main/java/feast/common/logging/entry/AuditLogEntry.java
deleted file mode 100644
index 8148c474b0..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/AuditLogEntry.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2019 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import com.google.gson.Gson;
-
-/**
- * AuditLogEntry represents a single audit Log Entry. Audit log entry can converted into string with
- * {{@link #toString()} for human readable representation. Or structured JSON with {{@link
- * #toJSON()} for a machine parsable representation.
- */
-public abstract class AuditLogEntry {
- /** Declare Log Type to allow external Logging systems to filter out {@link AuditLogEntry} */
- public final String logType = "FeastAuditLogEntry";
-
- public final String application = "Feast";
-
- /**
- * The name of the Feast component producing this {@link AuditLogEntry}
- *
- * @return the component
- */
- public abstract String getComponent();
-
- /**
- * The version of Feast producing this {@link AuditLogEntry}
- *
- * @return version
- */
- public abstract String getVersion();
-
- public abstract AuditLogEntryKind getKind();
-
- /**
- * Return a structured JSON representation of this {@link AuditLogEntry}
- *
- * @return structured JSON representation
- */
- public String toJSON() {
- Gson gson = new Gson();
- return gson.toJson(this);
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/AuditLogEntryKind.java b/java/common/src/main/java/feast/common/logging/entry/AuditLogEntryKind.java
deleted file mode 100644
index d673f6bdb3..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/AuditLogEntryKind.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2019 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-/** AuditLogEntryKind lists the various kinds of {@link AuditLogEntry} */
-public enum AuditLogEntryKind {
- MESSAGE,
- ACTION,
- TRANSITION,
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/LogResource.java b/java/common/src/main/java/feast/common/logging/entry/LogResource.java
deleted file mode 100644
index 1d0345a404..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/LogResource.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2019 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import com.google.auto.value.AutoValue;
-
-@AutoValue
-/**
- * LogResource is used in {@link AuditLogEntry} to reference a specific resource as the subject of
- * the log
- */
-public abstract class LogResource {
- public enum ResourceType {
- JOB,
- FEATURE_TABLE
- }
-
- public abstract ResourceType getType();
-
- public abstract String getId();
-
- public static LogResource of(ResourceType type, String id) {
- return new AutoValue_LogResource(type, id);
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/MessageAuditLogEntry.java b/java/common/src/main/java/feast/common/logging/entry/MessageAuditLogEntry.java
deleted file mode 100644
index 8ad428a3a3..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/MessageAuditLogEntry.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import com.google.auto.value.AutoValue;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonSerializer;
-import com.google.protobuf.Empty;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.Message;
-import com.google.protobuf.util.JsonFormat;
-import io.grpc.Status.Code;
-import java.util.UUID;
-
-/** MessageAuditLogEntry records the handling of a Protobuf message by a service call. */
-@AutoValue
-public abstract class MessageAuditLogEntry extends AuditLogEntry {
- /** @return Id used to identify the service call that the log entry is recording */
- public abstract UUID getId();
-
- /** @return The name of the service that was used to handle the service call. */
- public abstract String getService();
-
- /** @return The name of the method that was used to handle the service call. */
- public abstract String getMethod();
-
- /**
- * @return The request Protobuf {@link Message} that was passed to the Service in the service
- * call.
- */
- public abstract Message getRequest();
-
- /**
- * @return The response Protobuf {@link Message} that was passed to the Service in the service
- * call. May be an {@link Empty} protobuf no request could be collected due to an error.
- */
- public abstract Message getResponse();
-
- /**
- * @return The authenticated identity that was assumed during the handling of the service call.
- * For example, the user id or email that identifies the user making the call. Empty if the
- * service call is not authenticated.
- */
- public abstract String getIdentity();
-
- /** @return The result status code of the service call. */
- public abstract Code getStatusCode();
-
- @AutoValue.Builder
- public abstract static class Builder {
- public abstract Builder setId(UUID id);
-
- public abstract Builder setComponent(String component);
-
- public abstract Builder setVersion(String component);
-
- public abstract Builder setKind(AuditLogEntryKind kind);
-
- public abstract Builder setService(String name);
-
- public abstract Builder setMethod(String name);
-
- public abstract Builder setRequest(Message request);
-
- public abstract Builder setResponse(Message response);
-
- public abstract Builder setIdentity(String identity);
-
- public abstract Builder setStatusCode(Code statusCode);
-
- public abstract MessageAuditLogEntry build();
- }
-
- public static MessageAuditLogEntry.Builder newBuilder() {
- return new AutoValue_MessageAuditLogEntry.Builder()
- .setKind(AuditLogEntryKind.MESSAGE)
- .setId(UUID.randomUUID());
- }
-
- @Override
- public String toJSON() {
- // GSON requires custom typeadapter (serializer) to convert Protobuf messages to JSON properly
- Gson gson =
- new GsonBuilder()
- .registerTypeAdapter(
- Message.class,
- (JsonSerializer)
- (message, type, context) -> {
- try {
- String messageJSON = JsonFormat.printer().print(message);
- return new JsonParser().parse(messageJSON);
- } catch (InvalidProtocolBufferException e) {
-
- throw new RuntimeException(
- "Unexpected exception converting Protobuf to JSON", e);
- }
- })
- .create();
- return gson.toJson(this);
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/entry/TransitionAuditLogEntry.java b/java/common/src/main/java/feast/common/logging/entry/TransitionAuditLogEntry.java
deleted file mode 100644
index 224f10e0b5..0000000000
--- a/java/common/src/main/java/feast/common/logging/entry/TransitionAuditLogEntry.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import com.google.auto.value.AutoValue;
-
-/** TransitionAuditLogEntry records a transition in state/status in a specific resource. */
-@AutoValue
-public abstract class TransitionAuditLogEntry extends AuditLogEntry {
- /** @return The resource which the state/status transition occured. */
- public abstract LogResource getResource();
-
- /** @return The end status with the resource transition to. */
- public abstract String getStatus();
-
- /**
- * Construct a new {@link AuditLogEntry} to record a transition in state/status in a specific
- * resource.
- *
- * @param component The name of th Feast component producing this {@link AuditLogEntry}.
- * @param version The version of Feast producing this {@link AuditLogEntry}.
- * @param resource the resource which the transtion occured
- * @param status the end status which the resource transitioned to.
- * @return log entry to record a transition in state/status in a specific resource
- */
- public static TransitionAuditLogEntry of(
- String component, String version, LogResource resource, String status) {
- return new AutoValue_TransitionAuditLogEntry(
- component, version, AuditLogEntryKind.TRANSITION, resource, status);
- }
-}
diff --git a/java/common/src/main/java/feast/common/logging/interceptors/GrpcMessageInterceptor.java b/java/common/src/main/java/feast/common/logging/interceptors/GrpcMessageInterceptor.java
deleted file mode 100644
index e34fefd115..0000000000
--- a/java/common/src/main/java/feast/common/logging/interceptors/GrpcMessageInterceptor.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2019 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.interceptors;
-
-import com.google.protobuf.Empty;
-import com.google.protobuf.Message;
-import feast.common.logging.AuditLogger;
-import feast.common.logging.config.LoggingProperties;
-import feast.common.logging.entry.MessageAuditLogEntry;
-import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;
-import io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener;
-import io.grpc.Metadata;
-import io.grpc.ServerCall;
-import io.grpc.ServerCall.Listener;
-import io.grpc.ServerCallHandler;
-import io.grpc.ServerInterceptor;
-import io.grpc.Status;
-import org.slf4j.event.Level;
-
-/**
- * GrpcMessageInterceptor intercepts a GRPC calls to log handling of GRPC messages to the Audit Log.
- * Intercepts the incoming and outgoing messages logs them to the audit log, together with method
- * name and assumed authenticated identity (if authentication is enabled). NOTE:
- * GrpcMessageInterceptor assumes that all service calls are unary (ie single request/response).
- */
-public class GrpcMessageInterceptor implements ServerInterceptor {
- private final LoggingProperties loggingProperties;
-
- /**
- * Construct GrpcMessageIntercetor.
- *
- * @param loggingProperties properties used to configure logging interceptor.
- */
- public GrpcMessageInterceptor(LoggingProperties loggingProperties) {
- this.loggingProperties = loggingProperties;
- }
-
- @Override
- public Listener interceptCall(
- ServerCall call, Metadata headers, ServerCallHandler next) {
- // Disable the message logging interceptor entirely if message logging is disabled.
- if (!loggingProperties.getAudit().getMessageLogging().isEnabled()) {
- return next.startCall(call, headers);
- }
-
- MessageAuditLogEntry.Builder entryBuilder = MessageAuditLogEntry.newBuilder();
- // default response/request message to empty proto in log entry.
- // request could be empty when the client closes the connection before sending a request
- // message.
- // response could be unset when the service encounters an error when processsing the service
- // call.
- entryBuilder.setRequest(Empty.newBuilder().build());
- entryBuilder.setResponse(Empty.newBuilder().build());
-
- // Unpack service & method name from call
- // full method name is in format ./
- String fullMethodName = call.getMethodDescriptor().getFullMethodName();
- entryBuilder.setService(
- fullMethodName.substring(fullMethodName.lastIndexOf(".") + 1, fullMethodName.indexOf("/")));
- entryBuilder.setMethod(fullMethodName.substring(fullMethodName.indexOf("/") + 1));
-
- // Attempt Extract current authenticated identity.
- entryBuilder.setIdentity("");
-
- // Register forwarding call to intercept outgoing response and log to audit log
- call =
- new SimpleForwardingServerCall<>(call) {
- @Override
- public void sendMessage(RespT message) {
- // 2. Track the response & Log entry to audit logger
- super.sendMessage(message);
- entryBuilder.setResponse((Message) message);
- }
-
- @Override
- public void close(Status status, Metadata trailers) {
- super.close(status, trailers);
- // 3. Log the message log entry to the audit log
- Level logLevel = (status.isOk()) ? Level.INFO : Level.ERROR;
- entryBuilder.setStatusCode(status.getCode());
- AuditLogger.logMessage(logLevel, entryBuilder);
- }
- };
-
- ServerCall.Listener listener = next.startCall(call, headers);
- return new SimpleForwardingServerCallListener<>(listener) {
- @Override
- // Register listener to intercept incoming request messages and log to audit log
- public void onMessage(ReqT message) {
- super.onMessage(message);
- // 1. Track the request.
- entryBuilder.setRequest((Message) message);
- }
- };
- }
-}
diff --git a/java/common/src/main/java/feast/common/validators/OneOfStringValidator.java b/java/common/src/main/java/feast/common/validators/OneOfStringValidator.java
deleted file mode 100644
index 924953a2c4..0000000000
--- a/java/common/src/main/java/feast/common/validators/OneOfStringValidator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.validators;
-
-import java.util.Arrays;
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-
-/** Validates whether a string value is found within a collection. */
-public class OneOfStringValidator implements ConstraintValidator {
-
- /** Values that are permitted for a specific instance of this validator */
- String[] allowedValues;
-
- /**
- * Initialize the OneOfStringValidator with a collection of allowed String values.
- *
- * @param constraintAnnotation constraint annotation
- */
- @Override
- public void initialize(OneOfStrings constraintAnnotation) {
- allowedValues = constraintAnnotation.value();
- }
-
- /**
- * Validates whether a string value is found within the collection defined in the annotation.
- *
- * @param value String value that should be validated
- * @param context Provides contextual data and operation when applying a given constraint
- * validator
- * @return Boolean value indicating whether the string is found within the allowed values.
- */
- @Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
- return Arrays.asList(allowedValues).contains(value);
- }
-}
diff --git a/java/common/src/main/java/feast/common/validators/OneOfStrings.java b/java/common/src/main/java/feast/common/validators/OneOfStrings.java
deleted file mode 100644
index b236f6f1af..0000000000
--- a/java/common/src/main/java/feast/common/validators/OneOfStrings.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.validators;
-
-import java.lang.annotation.*;
-import javax.validation.Constraint;
-import javax.validation.Payload;
-
-/**
- * Annotation for String "one of" validation. Allows for the definition of a collection through an
- * annotation. The collection is used to test values defined in the object.
- */
-@Target({
- ElementType.METHOD,
- ElementType.FIELD,
- ElementType.ANNOTATION_TYPE,
- ElementType.CONSTRUCTOR,
- ElementType.PARAMETER
-})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@Constraint(validatedBy = OneOfStringValidator.class)
-public @interface OneOfStrings {
- /** @return Default error message that is returned if the incorrect value is set */
- String message() default "Field value must be one of the following: {value}";
-
- /** @return Allows for the specification of validation groups to which this constraint belongs. */
- Class>[] groups() default {};
-
- /**
- * @return An attribute payload that can be used to assign custom payload objects to a constraint.
- */
- Class extends Payload>[] payload() default {};
-
- /** @return Default value that is returned if no allowed values are configured */
- String[] value() default {};
-}
diff --git a/java/common/src/main/resources/log4j2.xml b/java/common/src/main/resources/log4j2.xml
deleted file mode 100644
index c75c2db13c..0000000000
--- a/java/common/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex
-
-
- {"time":"%d{yyyy-MM-dd'T'HH:mm:ssXXX}","hostname":"${hostName}","severity":"%p","message":%m}%n%ex
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/common/src/test/java/feast/common/logging/entry/AuditLogEntryTest.java b/java/common/src/test/java/feast/common/logging/entry/AuditLogEntryTest.java
deleted file mode 100644
index bc3dcbcf74..0000000000
--- a/java/common/src/test/java/feast/common/logging/entry/AuditLogEntryTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright 2018-2020 The Feast Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package feast.common.logging.entry;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.protobuf.Timestamp;
-import feast.common.logging.entry.LogResource.ResourceType;
-import feast.proto.serving.ServingAPIProto;
-import feast.proto.serving.ServingAPIProto.FeatureReferenceV2;
-import feast.proto.serving.ServingAPIProto.GetOnlineFeaturesRequestV2;
-import feast.proto.serving.ServingAPIProto.GetOnlineFeaturesResponse;
-import feast.proto.types.ValueProto.Value;
-import io.grpc.Status;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Test;
-
-public class AuditLogEntryTest {
- public List getTestAuditLogs() {
- GetOnlineFeaturesRequestV2 requestSpec =
- GetOnlineFeaturesRequestV2.newBuilder()
- .addAllFeatures(
- Arrays.asList(
- FeatureReferenceV2.newBuilder()
- .setFeatureViewName("featuretable_1")
- .setFeatureName("feature1")
- .build(),
- FeatureReferenceV2.newBuilder()
- .setFeatureViewName("featuretable_1")
- .setFeatureName("feature2")
- .build()))
- .build();
-
- GetOnlineFeaturesResponse responseSpec =
- GetOnlineFeaturesResponse.newBuilder()
- .setMetadata(
- ServingAPIProto.GetOnlineFeaturesResponseMetadata.newBuilder()
- .setFeatureNames(
- ServingAPIProto.FeatureList.newBuilder()
- .addAllVal(
- Arrays.asList(
- "featuretable_1:feature_1", "featuretable_1:feature2"))))
- .addAllResults(
- Arrays.asList(
- GetOnlineFeaturesResponse.FeatureVector.newBuilder()
- .addValues(Value.newBuilder().setInt32Val(32).build())
- .addStatuses(ServingAPIProto.FieldStatus.PRESENT)
- .addEventTimestamps(Timestamp.newBuilder().build())
- .build(),
- GetOnlineFeaturesResponse.FeatureVector.newBuilder()
- .addValues(Value.newBuilder().setInt32Val(64).build())
- .addStatuses(ServingAPIProto.FieldStatus.PRESENT)
- .addEventTimestamps(Timestamp.newBuilder().build())
- .build()))
- .build();
-
- return Arrays.asList(
- MessageAuditLogEntry.newBuilder()
- .setComponent("feast-serving")
- .setVersion("0.9")
- .setService("ServingService")
- .setMethod("getOnlineFeatures")
- .setRequest(requestSpec)
- .setResponse(responseSpec)
- .setStatusCode(Status.OK.getCode())
- .setIdentity("adam@no.such.email")
- .build(),
- ActionAuditLogEntry.of(
- "core", "0.9", LogResource.of(ResourceType.JOB, "kafka-to-redis"), "CREATE"),
- TransitionAuditLogEntry.of(
- "core", "0.9", LogResource.of(ResourceType.FEATURE_TABLE, "featuretable_1"), "READY"));
- }
-
- @Test
- public void shouldReturnJSONRepresentationOfAuditLog() {
- for (AuditLogEntry auditLog : getTestAuditLogs()) {
- // Check that auditLog's toJSON() returns valid JSON
- String logJSON = auditLog.toJSON();
- System.out.println(logJSON);
- JsonParser parser = new JsonParser();
-
- // check basic fields are present in JSON representation.
- JsonObject logObject = parser.parse(logJSON).getAsJsonObject();
- assertThat(logObject.getAsJsonPrimitive("logType").getAsString(), equalTo(auditLog.logType));
- assertThat(
- logObject.getAsJsonPrimitive("kind").getAsString(), equalTo(auditLog.getKind().name()));
- }
- }
-}
diff --git a/java/docs/coverage/pom.xml b/java/coverage/pom.xml
similarity index 85%
rename from java/docs/coverage/pom.xml
rename to java/coverage/pom.xml
index f6e08909ee..a604135c79 100644
--- a/java/docs/coverage/pom.xml
+++ b/java/coverage/pom.xml
@@ -30,7 +30,7 @@
dev.feast
feast-parent
${revision}
- ../..
+ ..
Feast Coverage Java
@@ -41,18 +41,6 @@
-
- dev.feast
- feast-storage-api
- ${project.version}
-
-
-
- dev.feast
- feast-storage-connector-redis
- ${project.version}
-
-
dev.feast
feast-serving
diff --git a/java/infra/docker/feature-server/Dockerfile b/java/infra/docker/feature-server/Dockerfile
index dbd8c91472..a728340d6b 100644
--- a/java/infra/docker/feature-server/Dockerfile
+++ b/java/infra/docker/feature-server/Dockerfile
@@ -8,13 +8,9 @@ WORKDIR /build
COPY java/pom.xml .
COPY java/datatypes/pom.xml datatypes/pom.xml
-COPY java/common/pom.xml common/pom.xml
COPY java/serving/pom.xml serving/pom.xml
-COPY java/storage/api/pom.xml storage/api/pom.xml
-COPY java/storage/connectors/pom.xml storage/connectors/pom.xml
-COPY java/storage/connectors/redis/pom.xml storage/connectors/redis/pom.xml
-COPY java/sdk/pom.xml sdk/pom.xml
-COPY java/docs/coverage/pom.xml docs/coverage/pom.xml
+COPY java/serving-client/pom.xml serving-client/pom.xml
+COPY java/coverage/pom.xml coverage/pom.xml
# Setting Maven repository .m2 directory relative to /build folder gives the
# user to optionally use cached repository when building the image by copying
@@ -28,7 +24,7 @@ COPY protos/feast datatypes/src/main/proto/feast
ARG VERSION=dev
RUN mvn --also-make --projects serving -Drevision=$VERSION \
- -DskipUTs=true --batch-mode clean package
+ -DskipUTs=true -DskipITs=true --batch-mode clean package
#
# Download grpc_health_probe to run health check for Feast Serving
# https://kubernetes.io/blog/2018/10/01/health-checking-grpc-servers-on-kubernetes/
diff --git a/java/infra/docker/feature-server/Dockerfile.dev b/java/infra/docker/feature-server/Dockerfile.dev
index 93bbbbb718..4eaec41ae3 100644
--- a/java/infra/docker/feature-server/Dockerfile.dev
+++ b/java/infra/docker/feature-server/Dockerfile.dev
@@ -7,7 +7,7 @@ ARG REVISION=dev
RUN wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.3.1/grpc_health_probe-linux-amd64 \
-O /usr/bin/grpc-health-probe && \
chmod +x /usr/bin/grpc-health-probe
-ADD $PWD/serving/target/feast-serving-$REVISION-exec.jar /opt/feast/feast-serving.jar
+ADD $PWD/java/serving/target/feast-serving-$REVISION-jar-with-dependencies.jar /opt/feast/feast-serving.jar
CMD ["java",\
"-Xms1024m",\
"-Xmx1024m",\
diff --git a/java/pom.xml b/java/pom.xml
index 0bf92ee244..9cff26daa6 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -29,16 +29,13 @@
datatypes
- storage/api
- storage/connectors
serving
- sdk
- docs/coverage
- common
+ serving-client
+ coverage
- 0.23.0
+ 0.24.0
https://github.com/feast-dev/feast
UTF-8
@@ -91,6 +88,7 @@
*/
]]>
+
${maven.multiModuleProjectDirectory}
false
diff --git a/java/sdk/pom.xml b/java/serving-client/pom.xml
similarity index 97%
rename from java/sdk/pom.xml
rename to java/serving-client/pom.xml
index 5896214b27..7b8838a009 100644
--- a/java/sdk/pom.xml
+++ b/java/serving-client/pom.xml
@@ -4,8 +4,8 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- Feast SDK for Java
- SDK for registering, storing, and retrieving features
+ Feast Serving Client
+ Client for retrieving features from a Feast feature server
feast-serving-client
diff --git a/java/sdk/src/main/java/dev/feast/FeastClient.java b/java/serving-client/src/main/java/dev/feast/FeastClient.java
similarity index 100%
rename from java/sdk/src/main/java/dev/feast/FeastClient.java
rename to java/serving-client/src/main/java/dev/feast/FeastClient.java
diff --git a/java/sdk/src/main/java/dev/feast/RequestUtil.java b/java/serving-client/src/main/java/dev/feast/RequestUtil.java
similarity index 100%
rename from java/sdk/src/main/java/dev/feast/RequestUtil.java
rename to java/serving-client/src/main/java/dev/feast/RequestUtil.java
diff --git a/java/sdk/src/main/java/dev/feast/Row.java b/java/serving-client/src/main/java/dev/feast/Row.java
similarity index 100%
rename from java/sdk/src/main/java/dev/feast/Row.java
rename to java/serving-client/src/main/java/dev/feast/Row.java
diff --git a/java/sdk/src/main/java/dev/feast/SecurityConfig.java b/java/serving-client/src/main/java/dev/feast/SecurityConfig.java
similarity index 100%
rename from java/sdk/src/main/java/dev/feast/SecurityConfig.java
rename to java/serving-client/src/main/java/dev/feast/SecurityConfig.java
diff --git a/java/sdk/src/test/java/dev/feast/FeastClientTest.java b/java/serving-client/src/test/java/dev/feast/FeastClientTest.java
similarity index 100%
rename from java/sdk/src/test/java/dev/feast/FeastClientTest.java
rename to java/serving-client/src/test/java/dev/feast/FeastClientTest.java
diff --git a/java/sdk/src/test/java/dev/feast/RequestUtilTest.java b/java/serving-client/src/test/java/dev/feast/RequestUtilTest.java
similarity index 100%
rename from java/sdk/src/test/java/dev/feast/RequestUtilTest.java
rename to java/serving-client/src/test/java/dev/feast/RequestUtilTest.java
diff --git a/java/serving/README.md b/java/serving/README.md
index 5ac7194924..dc23702d0f 100644
--- a/java/serving/README.md
+++ b/java/serving/README.md
@@ -3,14 +3,18 @@
### Overview
This guide is targeted at developers looking to contribute to Feast Serving:
- [Building and running Feast Serving locally](#building-and-running-feast-serving-locally)
+- [Unit / Integration Tests](#unit-/-integration-tests)
+- [Developing against Feast Helm charts](#developing-against-feast-helm-charts)
-### Pre-requisites:
+### Building and running Feast Serving locally:
+
+#### Pre-requisites
- [Maven](https://maven.apache.org/install.html) build tool version 3.6.x
- A Feast feature repo (e.g. https://github.com/feast-dev/feast-demo)
- A running Store instance e.g. local Redis instance with `redis-server`
-### Building and running Feast Serving locally:
+#### Steps
From the Feast GitHub root, run:
1. `mvn -f java/pom.xml install -Dmaven.test.skip=true`
@@ -41,12 +45,12 @@ From the Feast GitHub root, run:
java \
-Xms1g \
-Xmx4g \
- -jar java/serving/target/feast-serving-0.17.1-SNAPSHOT-jar-with-dependencies.jar \
+ -jar java/serving/target/feast-serving-[YOUR VERSION]-jar-with-dependencies.jar \
classpath:/application.yml,file:./application-override.yaml
```
5. Now you have a Feast Serving gRPC service running on port 6566 locally!
-### Running test queries
+#### Running test queries
If you have [grpc_cli](https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md) installed, you can check that Feast Serving is running
```
grpc_cli ls localhost:6566
@@ -116,7 +120,7 @@ results {
Rpc succeeded with OK status
```
-### Debugging Feast Serving
+#### Debugging Feast Serving
You can debug this like any other Java executable. Swap the java command above with:
```
java \
@@ -124,7 +128,7 @@ You can debug this like any other Java executable. Swap the java command above w
-Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y \
-Xms1g \
-Xmx4g \
- -jar java/serving/target/feast-serving-0.17.1-SNAPSHOT-jar-with-dependencies.jar \
+ -jar java/serving/target/feast-serving-[YOUR VERSION]-jar-with-dependencies.jar \
classpath:/application.yml,file:./application-override.yaml
```
Now you can attach e.g. a Remote debugger in IntelliJ to port 5005 to debug / make breakpoints.
@@ -136,4 +140,10 @@ Unit & Integration Tests can be used to verify functionality:
mvn test -pl serving --also-make
# run integration tests
mvn verify -pl serving --also-make
-```
\ No newline at end of file
+# run integration tests with debugger
+mvn -Dmaven.failsafe.debug verify -pl serving --also-make
+```
+
+### Developing against Feast Helm charts
+Look at [java-demo](../../examples/java-demo) for steps on how to update the helm chart or java logic and test their
+interactions.
\ No newline at end of file
diff --git a/java/serving/pom.xml b/java/serving/pom.xml
index f173cdd5fe..8f0cf407e9 100644
--- a/java/serving/pom.xml
+++ b/java/serving/pom.xml
@@ -82,6 +82,29 @@
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+
+ python
+ src/test/resources/docker-compose/feast10/
+
+ setup_it.py
+
+ ${skipITs}
+
+ feast_test_apply
+ process-test-resources
+
+ exec
+
+
+
+
@@ -92,24 +115,6 @@
${project.version}
-
- dev.feast
- feast-common
- ${project.version}
-
-
-
- dev.feast
- feast-storage-api
- ${project.version}
-
-
-
- dev.feast
- feast-storage-connector-redis
- ${project.version}
-
-
com.google.inject
guice
@@ -345,6 +350,16 @@
2.7.4
test
+
+ io.lettuce
+ lettuce-core
+ 6.0.2.RELEASE
+
+
+ org.apache.commons
+ commons-lang3
+ 3.10
+
diff --git a/java/serving/src/main/java/feast/serving/ServingGuiceApplication.java b/java/serving/src/main/java/feast/serving/ServingGuiceApplication.java
index 664d6dd4ec..d91af8abb1 100644
--- a/java/serving/src/main/java/feast/serving/ServingGuiceApplication.java
+++ b/java/serving/src/main/java/feast/serving/ServingGuiceApplication.java
@@ -18,7 +18,7 @@
import com.google.inject.Guice;
import com.google.inject.Injector;
-import feast.serving.config.*;
+import feast.serving.service.config.*;
import io.grpc.Server;
import java.io.IOException;
@@ -32,9 +32,9 @@ public static void main(String[] args) throws InterruptedException, IOException
final Injector i =
Guice.createInjector(
- new ServingServiceConfigV2(),
- new RegistryConfig(),
- new InstrumentationConfig(),
+ new ServingServiceV2Module(),
+ new RegistryConfigModule(),
+ new InstrumentationConfigModule(),
new ServerModule(),
new ApplicationPropertiesModule(args));
diff --git a/java/storage/api/src/main/java/feast/storage/api/retriever/Feature.java b/java/serving/src/main/java/feast/serving/connectors/Feature.java
similarity index 94%
rename from java/storage/api/src/main/java/feast/storage/api/retriever/Feature.java
rename to java/serving/src/main/java/feast/serving/connectors/Feature.java
index 92ae1f31fb..af96a90866 100644
--- a/java/storage/api/src/main/java/feast/storage/api/retriever/Feature.java
+++ b/java/serving/src/main/java/feast/serving/connectors/Feature.java
@@ -14,18 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.api.retriever;
+package feast.serving.connectors;
import com.google.protobuf.Timestamp;
import feast.proto.serving.ServingAPIProto.FeatureReferenceV2;
import feast.proto.types.ValueProto;
import feast.proto.types.ValueProto.Value;
import java.util.HashMap;
+import java.util.Map;
public interface Feature {
- HashMap TYPE_TO_VAL_CASE =
- new HashMap() {
+ Map TYPE_TO_VAL_CASE =
+ new HashMap<>() {
{
put(ValueProto.ValueType.Enum.BYTES, ValueProto.Value.ValCase.BYTES_VAL);
put(ValueProto.ValueType.Enum.STRING, ValueProto.Value.ValCase.STRING_VAL);
diff --git a/java/storage/api/src/main/java/feast/storage/api/retriever/OnlineRetrieverV2.java b/java/serving/src/main/java/feast/serving/connectors/OnlineRetriever.java
similarity index 96%
rename from java/storage/api/src/main/java/feast/storage/api/retriever/OnlineRetrieverV2.java
rename to java/serving/src/main/java/feast/serving/connectors/OnlineRetriever.java
index fde8ba7396..79c062814b 100644
--- a/java/storage/api/src/main/java/feast/storage/api/retriever/OnlineRetrieverV2.java
+++ b/java/serving/src/main/java/feast/serving/connectors/OnlineRetriever.java
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.api.retriever;
+package feast.serving.connectors;
import feast.proto.serving.ServingAPIProto;
import feast.proto.types.ValueProto;
import java.util.List;
import java.util.Map;
-public interface OnlineRetrieverV2 {
+public interface OnlineRetriever {
/**
* Get online features for the given entity rows using data retrieved from the Feature references
* specified in FeatureTable request.
diff --git a/java/storage/api/src/main/java/feast/storage/api/retriever/ProtoFeature.java b/java/serving/src/main/java/feast/serving/connectors/ProtoFeature.java
similarity index 98%
rename from java/storage/api/src/main/java/feast/storage/api/retriever/ProtoFeature.java
rename to java/serving/src/main/java/feast/serving/connectors/ProtoFeature.java
index 09f6b75f49..9820898d00 100644
--- a/java/storage/api/src/main/java/feast/storage/api/retriever/ProtoFeature.java
+++ b/java/serving/src/main/java/feast/serving/connectors/ProtoFeature.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.api.retriever;
+package feast.serving.connectors;
import com.google.protobuf.Timestamp;
import feast.proto.serving.ServingAPIProto;
diff --git a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisHashDecoder.java b/java/serving/src/main/java/feast/serving/connectors/redis/common/RedisHashDecoder.java
similarity index 96%
rename from java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisHashDecoder.java
rename to java/serving/src/main/java/feast/serving/connectors/redis/common/RedisHashDecoder.java
index 78b64fd141..9f5c94924d 100644
--- a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisHashDecoder.java
+++ b/java/serving/src/main/java/feast/serving/connectors/redis/common/RedisHashDecoder.java
@@ -14,15 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.connectors.redis.common;
+package feast.serving.connectors.redis.common;
import com.google.common.hash.Hashing;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Timestamp;
import feast.proto.serving.ServingAPIProto;
import feast.proto.types.ValueProto;
-import feast.storage.api.retriever.Feature;
-import feast.storage.api.retriever.ProtoFeature;
+import feast.serving.connectors.Feature;
+import feast.serving.connectors.ProtoFeature;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
diff --git a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisKeyGenerator.java b/java/serving/src/main/java/feast/serving/connectors/redis/common/RedisKeyGenerator.java
similarity index 97%
rename from java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisKeyGenerator.java
rename to java/serving/src/main/java/feast/serving/connectors/redis/common/RedisKeyGenerator.java
index 389ca0abfd..defb337a82 100644
--- a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/common/RedisKeyGenerator.java
+++ b/java/serving/src/main/java/feast/serving/connectors/redis/common/RedisKeyGenerator.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.connectors.redis.common;
+package feast.serving.connectors.redis.common;
import feast.proto.serving.ServingAPIProto;
import feast.proto.storage.RedisProto;
diff --git a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializer.java b/java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializer.java
similarity index 94%
rename from java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializer.java
rename to java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializer.java
index 6220dd29d4..d25f0da4f9 100644
--- a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializer.java
+++ b/java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializer.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.connectors.redis.retriever;
+package feast.serving.connectors.redis.retriever;
import feast.proto.storage.RedisProto;
diff --git a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializerV2.java b/java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializerV2.java
similarity index 96%
rename from java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializerV2.java
rename to java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializerV2.java
index f99e5cbdb1..672f4d7c31 100644
--- a/java/storage/connectors/redis/src/main/java/feast/storage/connectors/redis/retriever/EntityKeySerializerV2.java
+++ b/java/serving/src/main/java/feast/serving/connectors/redis/retriever/EntityKeySerializerV2.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package feast.storage.connectors.redis.retriever;
+package feast.serving.connectors.redis.retriever;
import com.google.protobuf.ProtocolStringList;
import feast.proto.storage.RedisProto;
@@ -87,14 +87,15 @@ public byte[] serialize(RedisProto.RedisKeyV2 entityKey) {
break;
case INT64_VAL:
buffer.addAll(encodeInteger(ValueProto.ValueType.Enum.INT64.getNumber()));
- buffer.addAll(encodeInteger(Integer.BYTES));
/* This is super dumb - but in https://github.com/feast-dev/feast/blob/dcae1606f53028ce5413567fb8b66f92cfef0f8e/sdk/python/feast/infra/key_encoding_utils.py#L9
we use `struct.pack(" tracerOptional;
+ private final OnlineRetriever retriever;
private final RegistryRepository registryRepository;
private final OnlineTransformationService onlineTransformationService;
private final String project;
@@ -56,16 +62,16 @@ public class OnlineServingServiceV2 implements ServingServiceV2 {
ValueProto.Value.newBuilder().setStringVal(DUMMY_ENTITY_VAL).build();
public OnlineServingServiceV2(
- OnlineRetrieverV2 retriever,
- Tracer tracer,
+ OnlineRetriever retriever,
RegistryRepository registryRepository,
OnlineTransformationService onlineTransformationService,
- String project) {
+ String project,
+ Optional tracerOptional) {
this.retriever = retriever;
- this.tracer = tracer;
this.registryRepository = registryRepository;
this.onlineTransformationService = onlineTransformationService;
this.project = project;
+ this.tracerOptional = tracerOptional;
}
/** {@inheritDoc} */
@@ -107,20 +113,21 @@ public ServingAPIProto.GetOnlineFeaturesResponse getOnlineFeatures(
List