From cd4e6cf14ae35e668bda0116b38878a9b423049b Mon Sep 17 00:00:00 2001 From: Ritesh Ghorse Date: Tue, 26 Mar 2024 09:41:54 -0400 Subject: [PATCH] Update documentation link in bigtable_enrichment notebook (#30740) * update links for exception level * clear output --- .../bigtable_enrichment_transform.ipynb | 487 ++++++++---------- 1 file changed, 228 insertions(+), 259 deletions(-) diff --git a/examples/notebooks/beam-ml/bigtable_enrichment_transform.ipynb b/examples/notebooks/beam-ml/bigtable_enrichment_transform.ipynb index 455b5cccd5d5..08d5d064d1e0 100644 --- a/examples/notebooks/beam-ml/bigtable_enrichment_transform.ipynb +++ b/examples/notebooks/beam-ml/bigtable_enrichment_transform.ipynb @@ -4,8 +4,8 @@ "cell_type": "code", "execution_count": null, "metadata": { - "id": "fFjof1NgAJwu", - "cellView": "form" + "cellView": "form", + "id": "fFjof1NgAJwu" }, "outputs": [], "source": [ @@ -61,14 +61,14 @@ }, { "cell_type": "markdown", + "metadata": { + "id": "ltn5zrBiGS9C" + }, "source": [ "This notebook demonstrates the following ecommerce use case:\n", "\n", "A stream of online transaction from [Pub/Sub](https://cloud.google.com/pubsub/docs/guides) contains the following fields: `sale_id`, `product_id`, `customer_id`, `quantity`, and `price`. Additional customer demographic data is stored in a separate Bigtable cluster. The demographic data is used to enrich the event stream from Pub/Sub. Then, the enriched data is used to predict the next product to recommended to a customer." - ], - "metadata": { - "id": "ltn5zrBiGS9C" - } + ] }, { "cell_type": "markdown", @@ -104,6 +104,11 @@ }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SiJii48A2Rnb" + }, + "outputs": [], "source": [ "import datetime\n", "import json\n", @@ -125,12 +130,7 @@ "from apache_beam.runners.interactive.interactive_runner import InteractiveRunner\n", "from apache_beam.transforms.enrichment import Enrichment\n", "from apache_beam.transforms.enrichment_handlers.bigtable import BigTableEnrichmentHandler" - ], - "metadata": { - "id": "SiJii48A2Rnb" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -156,12 +156,12 @@ }, { "cell_type": "markdown", - "source": [ - "Replace ``, ``, and `` with the appropriate values for your setup. These fields are used with Bigtable." - ], "metadata": { "id": "nAmGgUMt48o9" - } + }, + "source": [ + "Replace ``, ``, and `` with the appropriate values for your setup. These fields are used with Bigtable." + ] }, { "cell_type": "code", @@ -178,25 +178,30 @@ }, { "cell_type": "markdown", + "metadata": { + "id": "RpqZFfFfA_Dt" + }, "source": [ "### Train the model\n", "\n" - ], - "metadata": { - "id": "RpqZFfFfA_Dt" - } + ] }, { "cell_type": "markdown", - "source": [ - "Create sample data by using the format `[product_id, quantity, price, customer_id, customer_location, recommend_product_id]`." - ], "metadata": { "id": "8cUpV7mkB_xE" - } + }, + "source": [ + "Create sample data by using the format `[product_id, quantity, price, customer_id, customer_location, recommend_product_id]`." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TpxDHGObBEsj" + }, + "outputs": [], "source": [ "data = [\n", " [3, 5, 127, 9, 'China', 7], [1, 6, 167, 5, 'Peru', 4], [5, 4, 91, 2, 'USA', 8], [7, 2, 52, 1, 'India', 4], [1, 8, 118, 3, 'UK', 8], [4, 6, 132, 8, 'Mexico', 2],\n", @@ -210,60 +215,60 @@ " [4, 7, 175, 6, 'Brazil', 5], [1, 8, 121, 1, 'India', 2], [4, 6, 187, 2, 'USA', 5], [6, 5, 144, 9, 'China', 9], [9, 4, 103, 5, 'Peru', 3], [5, 3, 84, 3, 'UK', 1],\n", " [3, 5, 193, 2, 'USA', 4], [4, 7, 135, 1, 'India', 1], [7, 6, 148, 8, 'Mexico', 8], [1, 6, 160, 5, 'Peru', 7], [8, 6, 155, 6, 'Brazil', 9], [5, 7, 183, 7, 'Bangladesh', 2],\n", " [2, 9, 125, 4, 'Egypt', 4], [6, 3, 111, 9, 'China', 9], [5, 2, 132, 3, 'UK', 3], [4, 5, 104, 7, 'Bangladesh', 7], [2, 7, 177, 8, 'Mexico', 7]]" - ], - "metadata": { - "id": "TpxDHGObBEsj" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "countries_to_id = {'India': 1, 'USA': 2, 'UK': 3, 'Egypt': 4, 'Peru': 5,\n", - " 'Brazil': 6, 'Bangladesh': 7, 'Mexico': 8, 'China': 9}" - ], + "execution_count": null, "metadata": { "id": "bQt1cB4-CSBd" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "countries_to_id = {'India': 1, 'USA': 2, 'UK': 3, 'Egypt': 4, 'Peru': 5,\n", + " 'Brazil': 6, 'Bangladesh': 7, 'Mexico': 8, 'China': 9}" + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Y0Duet4nCdN1" + }, "source": [ "Preprocess the data:\n", "\n", "1. Convert the lists to tensors.\n", "2. Separate the features from the expected prediction." - ], - "metadata": { - "id": "Y0Duet4nCdN1" - } + ] }, { "cell_type": "code", - "source": [ - "X = [torch.tensor(item[:4]+[countries_to_id[item[4]]], dtype=torch.float) for item in data]\n", - "Y = [torch.tensor(item[-1], dtype=torch.float) for item in data]" - ], + "execution_count": null, "metadata": { "id": "7TT1O7sBCaZN" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "X = [torch.tensor(item[:4]+[countries_to_id[item[4]]], dtype=torch.float) for item in data]\n", + "Y = [torch.tensor(item[-1], dtype=torch.float) for item in data]" + ] }, { "cell_type": "markdown", - "source": [ - "Define a simple model that has five input features and predicts a single value." - ], "metadata": { "id": "q6wB_ZsXDjjd" - } + }, + "source": [ + "Define a simple model that has five input features and predicts a single value." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nphNfhUnESES" + }, + "outputs": [], "source": [ "def build_model(n_inputs, n_outputs):\n", " \"\"\"build_model builds and returns a model that takes\n", @@ -274,24 +279,24 @@ " torch.nn.Linear(8, 16),\n", " torch.nn.ReLU(),\n", " torch.nn.Linear(16, n_outputs))" - ], - "metadata": { - "id": "nphNfhUnESES" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Train the model." - ], "metadata": { "id": "_sBSzDllEmCz" - } + }, + "source": [ + "Train the model." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CaYrplaPDayp" + }, + "outputs": [], "source": [ "model = build_model(n_inputs=5, n_outputs=1)\n", "\n", @@ -306,48 +311,48 @@ " loss = loss_fn(pred, Y[i])\n", " loss.backward()\n", " optimizer.step()" - ], - "metadata": { - "id": "CaYrplaPDayp" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Save the model to the `STATE_DICT_PATH` variable." - ], "metadata": { "id": "_rJYv8fFFPYb" - } + }, + "source": [ + "Save the model to the `STATE_DICT_PATH` variable." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "W4t260o9FURP" + }, + "outputs": [], "source": [ "STATE_DICT_PATH = './model.pth'\n", "\n", "torch.save(model.state_dict(), STATE_DICT_PATH)" - ], - "metadata": { - "id": "W4t260o9FURP" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "ouMQZ4sC4zuO" + }, "source": [ "### Set up the Bigtable table\n", "\n", "Create a sample Bigtable table for this notebook." - ], - "metadata": { - "id": "ouMQZ4sC4zuO" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "E7Y4ipuL5kFD" + }, + "outputs": [], "source": [ "# Connect to the Bigtable instance. If you don't have admin access, then drop `admin=True`.\n", "client = Client(project=PROJECT_ID, admin=True)\n", @@ -367,24 +372,38 @@ " table.create(column_families=column_families)\n", "else:\n", " print(\"Table %s already exists in %s:%s\" % (TABLE_ID, PROJECT_ID, INSTANCE_ID))" - ], - "metadata": { - "id": "E7Y4ipuL5kFD" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Add rows to the table for the enrichment example." - ], "metadata": { "id": "eQLkSg3p7WAm" - } + }, + "source": [ + "Add rows to the table for the enrichment example." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LI6oYkZ97Vtu", + "outputId": "c72b28b5-8692-40f5-f8da-85622437d8f7" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Inserted row for key: 1\n", + "Inserted row for key: 2\n", + "Inserted row for key: 3\n" + ] + } + ], "source": [ "# Define column names for the table.\n", "customer_id = 'customer_id'\n", @@ -424,55 +443,41 @@ " timestamp=datetime.datetime.utcnow())\n", " row.commit()\n", " print('Inserted row for key: %s' % customer[customer_id])" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "LI6oYkZ97Vtu", - "outputId": "c72b28b5-8692-40f5-f8da-85622437d8f7" - }, - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Inserted row for key: 1\n", - "Inserted row for key: 2\n", - "Inserted row for key: 3\n" - ] - } ] }, { "cell_type": "markdown", + "metadata": { + "id": "pHODouJDwc60" + }, "source": [ "### Publish messages to Pub/Sub\n", "\n", "Use the Pub/Sub Python client to publish messages.\n" - ], - "metadata": { - "id": "pHODouJDwc60" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QKCuwDioxw-f" + }, + "outputs": [], "source": [ "# Replace with the name of your Pub/Sub topic.\n", "TOPIC = \"\"\n", "\n", "# Replace with the subscription for your topic.\n", "SUBSCRIPTION = \"\"\n" - ], - "metadata": { - "id": "QKCuwDioxw-f" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MaCJwaPexPKZ" + }, + "outputs": [], "source": [ "messages = [\n", " {'sale_id': i, 'customer_id': i, 'product_id': i, 'quantity': i, 'price': i*100}\n", @@ -485,26 +490,24 @@ "for message in messages:\n", " data = json.dumps(message).encode('utf-8')\n", " publish_future = publisher.publish(topic_name, data)" - ], - "metadata": { - "id": "MaCJwaPexPKZ" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "zPSFEMm02omi" + }, "source": [ "## Use the Bigtable enrichment handler\n", "\n", "The [`BigTableEnrichmentHandler`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.bigtable.html#apache_beam.transforms.enrichment_handlers.bigtable.BigTableEnrichmentHandler) is a built-in handler included in the Apache Beam SDK versions 2.54.0 and later." - ], - "metadata": { - "id": "zPSFEMm02omi" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "K41xhvmA5yQk" + }, "source": [ "To establish a client for the Bigtable enrichment handler, replace ``, ``, and `` with the appropriate values for those fields. The `row_key` variable is the field name from the input row that contains the row key to use when querying Bigtable.\n", "\n", @@ -513,49 +516,49 @@ "The default `encoding` type is `utf-8`.\n", "\n", "\n" - ], - "metadata": { - "id": "K41xhvmA5yQk" - } + ] }, { "cell_type": "code", - "source": [ - "row_key = 'customer_id'" - ], + "execution_count": null, "metadata": { "id": "3dB26jhI45gd" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "row_key = 'customer_id'" + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cr1j_DHK4gA4" + }, + "outputs": [], "source": [ "bigtable_handler = BigTableEnrichmentHandler(project_id=PROJECT_ID,\n", " instance_id=INSTANCE_ID,\n", " table_id=TABLE_ID,\n", " row_key=row_key)" - ], - "metadata": { - "id": "cr1j_DHK4gA4" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "yFMcaf8i7TbI" + }, "source": [ "The `BigTableEnrichmentHandler` returns the latest value from the table without its associated timestamp for the `row_key` that you provide. If you want to fetch the `timestamp` associated with the `row_key` value, then pass `include_timestamp=True` to the handler.\n", "\n", - "**Note:** When exceptions occur, by default, the logging severity is set to warning ([`ExceptionLevel.WARN`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.bigtable.html#apache_beam.transforms.enrichment_handlers.bigtable.ExceptionLevel.WARN)). To configure the severity to raise exceptions, set `exception_level` to [`ExceptionLevel.RAISE`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.bigtable.html#apache_beam.transforms.enrichment_handlers.bigtable.ExceptionLevel.RAISE). To ignore exceptions, set `exception_level` to [`ExceptionLevel.QUIET`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.bigtable.html#apache_beam.transforms.enrichment_handlers.bigtable.ExceptionLevel.QUIET)." - ], - "metadata": { - "id": "yFMcaf8i7TbI" - } + "**Note:** When exceptions occur, by default, the logging severity is set to warning ([`ExceptionLevel.WARN`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.utils.html#apache_beam.transforms.enrichment_handlers.utils.ExceptionLevel.WARN)). To configure the severity to raise exceptions, set `exception_level` to [`ExceptionLevel.RAISE`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.utils.html#apache_beam.transforms.enrichment_handlers.utils.ExceptionLevel.RAISE). To ignore exceptions, set `exception_level` to [`ExceptionLevel.QUIET`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment_handlers.utils.html#apache_beam.transforms.enrichment_handlers.utils.ExceptionLevel.QUIET)." + ] }, { "cell_type": "markdown", + "metadata": { + "id": "-Lvo8O2V-0Ey" + }, "source": [ "## Use the enrichment transform\n", "\n", @@ -566,13 +569,13 @@ "* `timeout`: The number of seconds to wait for the request to be completed by the API before timing out. Defaults to 30 seconds.\n", "* `throttler`: Specifies the throttling mechanism. The only supported option is default client-side adaptive throttling.\n", "* `repeater`: Specifies the retry strategy when errors like `TooManyRequests` and `TimeoutException` occur. Defaults to [`ExponentialBackOffRepeater`](https://beam.apache.org/releases/pydoc/current/apache_beam.io.requestresponse.html#apache_beam.io.requestresponse.ExponentialBackOffRepeater).\n" - ], - "metadata": { - "id": "-Lvo8O2V-0Ey" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "xJTCfSmiV1kv" + }, "source": [ "The following example demonstrates the code needed to add this transform to your pipeline.\n", "\n", @@ -590,24 +593,26 @@ "\n", "\n", "\n" - ], - "metadata": { - "id": "xJTCfSmiV1kv" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "F-xjiP_pHWZr" + }, "source": [ "To make a prediction, use the following fields: `product_id`, `quantity`, `price`, `customer_id`, and `customer_location`. Retrieve the value of the `customer_location` field from Bigtable.\n", "\n", "Because the enrichment transform performs a [`cross_join`](https://beam.apache.org/releases/pydoc/current/apache_beam.transforms.enrichment.html#apache_beam.transforms.enrichment.cross_join) by default, design the custom join to enrich the input data. This design ensures that the join includes only the specified fields." - ], - "metadata": { - "id": "F-xjiP_pHWZr" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8LnCnEPNIPtg" + }, + "outputs": [], "source": [ "def custom_join(left: Dict[str, Any], right: Dict[str, Any]):\n", " enriched = {}\n", @@ -617,90 +622,85 @@ " enriched['customer_id'] = left['customer_id']\n", " enriched['customer_location'] = right['demograph']['customer_location']\n", " return beam.Row(**enriched)" - ], - "metadata": { - "id": "8LnCnEPNIPtg" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "CX9Cqybu6scV" + }, "source": [ "## Use the `PyTorchModelHandlerTensor` interface to run inference\n", "\n" - ], - "metadata": { - "id": "CX9Cqybu6scV" - } + ] }, { "cell_type": "markdown", - "source": [ - "Because the enrichment transform outputs data in the format `beam.Row`, to make it compatible with the [`PyTorchModelHandlerTensor`](https://beam.apache.org/releases/pydoc/current/apache_beam.ml.inference.pytorch_inference.html#apache_beam.ml.inference.pytorch_inference.PytorchModelHandlerTensor) interface, convert it to `torch.tensor`. Additionally, the enriched field `customer_location` is a `string` type, but the model requires a `float` type. Convert the `customer_location` field to a `float` type." - ], "metadata": { "id": "zy5Jl7_gLklX" - } + }, + "source": [ + "Because the enrichment transform outputs data in the format `beam.Row`, to make it compatible with the [`PyTorchModelHandlerTensor`](https://beam.apache.org/releases/pydoc/current/apache_beam.ml.inference.pytorch_inference.html#apache_beam.ml.inference.pytorch_inference.PytorchModelHandlerTensor) interface, convert it to `torch.tensor`. Additionally, the enriched field `customer_location` is a `string` type, but the model requires a `float` type. Convert the `customer_location` field to a `float` type." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KBKoB06nL4LF" + }, + "outputs": [], "source": [ "def convert_row_to_tensor(element: beam.Row):\n", " row_dict = element._asdict()\n", " row_dict['customer_location'] = countries_to_id[row_dict['customer_location']]\n", " return torch.tensor(list(row_dict.values()), dtype=torch.float)" - ], - "metadata": { - "id": "KBKoB06nL4LF" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Initialize the model handler with the preprocessing function." - ], "metadata": { "id": "-tGHyB_vL3rJ" - } + }, + "source": [ + "Initialize the model handler with the preprocessing function." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VqUUEwcU-r2e" + }, + "outputs": [], "source": [ "model_handler = PytorchModelHandlerTensor(state_dict_path=STATE_DICT_PATH,\n", " model_class=build_model,\n", " model_params={'n_inputs':5, 'n_outputs':1}\n", " ).with_preprocess_fn(convert_row_to_tensor)" - ], - "metadata": { - "id": "VqUUEwcU-r2e" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Define a `DoFn` to format the output." - ], "metadata": { "id": "vNHI4gVgNec2" - } + }, + "source": [ + "Define a `DoFn` to format the output." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rkN-_Yf4Nlwy" + }, + "outputs": [], "source": [ "class PostProcessor(beam.DoFn):\n", " def process(self, element, *args, **kwargs):\n", " print('Customer %d who bought product %d is recommended to buy product %d' % (element.example[3], element.example[0], math.ceil(element.inference[0])))" - ], - "metadata": { - "id": "rkN-_Yf4Nlwy" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -713,36 +713,41 @@ }, { "cell_type": "markdown", - "source": [ - "Configure the pipeline to run in streaming mode." - ], "metadata": { "id": "WrwY0_gV_IDK" - } + }, + "source": [ + "Configure the pipeline to run in streaming mode." + ] }, { "cell_type": "code", - "source": [ - "options = pipeline_options.PipelineOptions()\n", - "options.view_as(pipeline_options.StandardOptions).streaming = True # Streaming mode is set True" - ], + "execution_count": null, "metadata": { "id": "t0425sYBsYtB" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "options = pipeline_options.PipelineOptions()\n", + "options.view_as(pipeline_options.StandardOptions).streaming = True # Streaming mode is set True" + ] }, { "cell_type": "markdown", - "source": [ - "Pub/Sub sends the data in bytes. Convert the data to `beam.Row` objects by using a `DoFn`." - ], "metadata": { "id": "DBNijQDY_dRe" - } + }, + "source": [ + "Pub/Sub sends the data in bytes. Convert the data to `beam.Row` objects by using a `DoFn`." + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sRw9iL8pKP5O" + }, + "outputs": [], "source": [ "class DecodeBytes(beam.DoFn):\n", " \"\"\"\n", @@ -753,70 +758,34 @@ " def process(self, element, *args, **kwargs):\n", " element_dict = json.loads(element.decode('utf-8'))\n", " yield beam.Row(**element_dict)" - ], - "metadata": { - "id": "sRw9iL8pKP5O" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "xofUJym-_GuB" + }, "source": [ "Use the following code to run the pipeline.\n", "\n", "**Note:** Because this pipeline is a streaming pipeline, you need to manually stop the cell. If you don't stop the cell, the pipeline continues to run." - ], - "metadata": { - "id": "xofUJym-_GuB" - } + ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "St07XoibcQSb", "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, + "id": "St07XoibcQSb", "outputId": "34e0a603-fb77-455c-e40b-d15b672edeb2" }, "outputs": [ { - "output_type": "display_data", - "data": { - "application/javascript": [ - "\n", - " if (typeof window.interactive_beam_jquery == 'undefined') {\n", - " var jqueryScript = document.createElement('script');\n", - " jqueryScript.src = 'https://code.jquery.com/jquery-3.4.1.slim.min.js';\n", - " jqueryScript.type = 'text/javascript';\n", - " jqueryScript.onload = function() {\n", - " var datatableScript = document.createElement('script');\n", - " datatableScript.src = 'https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js';\n", - " datatableScript.type = 'text/javascript';\n", - " datatableScript.onload = function() {\n", - " window.interactive_beam_jquery = jQuery.noConflict(true);\n", - " window.interactive_beam_jquery(document).ready(function($){\n", - " \n", - " });\n", - " }\n", - " document.head.appendChild(datatableScript);\n", - " };\n", - " document.head.appendChild(jqueryScript);\n", - " } else {\n", - " window.interactive_beam_jquery(document).ready(function($){\n", - " \n", - " });\n", - " }" - ] - }, - "metadata": {} - }, - { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Customer 1 who bought product 1 is recommended to buy product 3\n", "Customer 2 who bought product 2 is recommended to buy product 5\n", @@ -851,4 +820,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +}