You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by "vtlim (via GitHub)" <gi...@apache.org> on 2023/03/27 20:59:28 UTC

[GitHub] [druid] vtlim opened a new pull request, #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

vtlim opened a new pull request, #13984:
URL: https://github.com/apache/druid/pull/13984

   ### Description
   
   This PR adds a new Jupyter notebook tutorial to walk users through ingesting data into Druid using Kafka and analyze the data from the newly ingested datasource.
   
   This PR also adds a Dockerfile and a Docker Compose file for use with the Jupyter tutorials, which allows users to run the notebooks without setting up Jupyter/Druid/Kafka, installing Python packages, or downloading the required tutorials.
   
   ### Release note
   
   #### Streaming ingestion tutorial
   Added a new tutorial to our collection of Jupyter Notebook-based Druid tutorials.
   This interactive tutorial introduces you to streaming ingestion into Druid using Apache Kafka.
   
   #### Docker Compose for use with Jupyter tutorials
   Added a Docker Compose file you can use for Jupyter Notebook-based Druid tutorials. With the Compose file, you can also bring up services for Druid and Apache Kafka.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181804021


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""

Review Comment:
   I think for the tutorial it's easier to understand the example data (what it's made of and what's being sent to Druid) in JSON format since we're not doing anything with the Kafka metadata fields. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181806841


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",
+    "'''\n",
+    "response = sql_client.sql_query(sql)\n",
+    "response.show()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Visualize the total number of upvotes per user using a line plot. You sort the results by username before plotting because the order of users may vary as new results arrive."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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
 CC\n",

Review Comment:
   I think it's due to the scale 😬 The LHS axis is multiplied by 10 million and the RHS is multiplied by 1 million, so it's hard to see differences. I can try to play around with the axis limits for the bar plots so the differences are more pronounced.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181805135


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"

Review Comment:
   Not sure how to make this nicer, but I can add some text after it with some details.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181804473


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""

Review Comment:
   I'll update the notebook to add a short description for the ingestion spec.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181818406


##########
examples/quickstart/jupyter-notebooks/docker-jupyter/environment:
##########
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#

Review Comment:
   It's referenced in https://druid.apache.org/docs/latest/tutorials/docker.html#environment-file. Referring to Docker syntax rules for environment files: https://docs.docker.com/compose/environment-variables/env-file/



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1164781296


##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,185 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.

Review Comment:
   I think people could install these separately if they wanted but I included that the suggested method is Docker Desktop:
   > We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1165826254


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""

Review Comment:
   We should briefly describe what the ingestion spec does. `ioConfig` tells where the source is -- see it's set to the stream we created earlier...
   
   Maybe not for this PR, but we might want to consider using the `kafka` input format.



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",

Review Comment:
   since this is multiline, can we actually break at the commas and keywords:
   ```
   SELECT COUNT(post_title) as num_posts,
   SUM(upvotes),
   username
   FROM social_media...
   ```



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",
+    "'''\n",
+    "response = sql_client.sql_query(sql)\n",
+    "response.show()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Visualize the total number of upvotes per user using a line plot. You sort the results by username before plotting because the order of users may vary as new results arrive."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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
 CC\n",

Review Comment:
   For me this is showing 1 post for everybody, so the correlation bit doesn't come through that much.
   <img width="870" alt="Screen Shot 2023-04-13 at 10 26 26 AM" src="https://user-images.githubusercontent.com/38529548/231837863-320962be-7b76-4dc4-bc18-8969c30956fb.png">
   



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"

Review Comment:
   might be nicer if we had a pretty output here instead of this response looking object.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on PR #13984:
URL: https://github.com/apache/druid/pull/13984#issuecomment-1522473302

   @vtlim we'll need to update the `0-START-HERE` notebook to reflect the fact that you may be running Jupyter from the container version that has all the pre-reqs you need.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1194416863


##########
examples/quickstart/jupyter-notebooks/docker-jupyter/docker-compose-local.yaml:
##########
@@ -0,0 +1,172 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#
+---
+version: "2.2"
+
+volumes:
+  metadata_data: {}
+  middle_var: {}
+  historical_var: {}
+  broker_var: {}
+  coordinator_var: {}
+  router_var: {}
+  druid_shared: {}
+
+
+services:
+  postgres:

Review Comment:
   @paul-rogers / @vtlim , tracking here: https://github.com/apache/druid/issues/14286



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] paul-rogers commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "paul-rogers (via GitHub)" <gi...@apache.org>.
paul-rogers commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1169383399


##########
examples/quickstart/jupyter-notebooks/docker-jupyter/docker-compose-local.yaml:
##########
@@ -0,0 +1,172 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#
+---
+version: "2.2"
+
+volumes:
+  metadata_data: {}
+  middle_var: {}
+  historical_var: {}
+  broker_var: {}
+  coordinator_var: {}
+  router_var: {}
+  druid_shared: {}
+
+
+services:
+  postgres:

Review Comment:
   Not super-critical, but it would be nice to use the same third-party images here and in the "new" ITs. The ITs use MySQL as its DB. It has setup to create the required user and permissions. See [dependencies.yaml](https://github.com/apache/druid/blob/master/integration-tests-ex/cases/cluster/Common/dependencies.yaml) for the IT setup.



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,193 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker compose --profile jupyter up -d
+```
+
+The Docker Compose file assigns `8889` for the Jupyter port.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.

Review Comment:
   the --> an?
   
   We've not talked about an environment file yet so I don't know which one is "the" environment file.



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,193 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker compose --profile jupyter up -d
+```
+
+The Docker Compose file assigns `8889` for the Jupyter port.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile all-services up -d
+```
+
+### Update image from Docker Hub
+
+If you already have a local cache of the Jupyter image, you can update the image before running the application using the following command:

Review Comment:
   When might I want to update the image? Doesn't Docker grab the latest one itself?



##########
examples/quickstart/jupyter-notebooks/docker-jupyter/docker-compose.yaml:
##########
@@ -0,0 +1,170 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#
+---
+version: "2.2"
+
+volumes:
+  metadata_data: {}
+  middle_var: {}
+  historical_var: {}
+  broker_var: {}
+  coordinator_var: {}
+  router_var: {}
+  druid_shared: {}
+
+
+services:

Review Comment:
   Cool use of the `profiles` feature!
   
   There is redundancy between this file and the previous one. Compose allows common services to be defined in a separate file, then imported. See the `dependencies.yaml` mentioned above, along with the corresponding `druid.yaml`.



##########
examples/quickstart/jupyter-notebooks/docker-jupyter/environment:
##########
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#

Review Comment:
   Would be great if we could reference the clever encoding scheme used here. Do we explain it elsewhere? If so, perhaps provide a link to newbies can sort out the odd "druid_something" format of the env vars.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1160303834


##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,181 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` supplies the Docker tag that specifies which version of Druid to pull from the

Review Comment:
   ```suggestion
   `DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
   ```



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,181 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` supplies the Docker tag that specifies which version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile all-services up -d
+```
+
+### Use locally built image
+
+The default Docker Compose file pulls the custom Jupyter Notebook image from Imply's Docker Hub.
+If you would rather build the image locally, do the following:

Review Comment:
   ```suggestion
   If you prefer to build the image locally, do the following:
   ```
   avoid conditional



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,181 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` supplies the Docker tag that specifies which version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile all-services up -d
+```
+
+### Use locally built image
+
+The default Docker Compose file pulls the custom Jupyter Notebook image from Imply's Docker Hub.
+If you would rather build the image locally, do the following:
+1. Clone the Apache Druid repository.
+2. Navigate to `examples/quickstart/jupyter-notebooks/docker-jupyter`.
+3. Start the services using `-f docker-compose-local.yaml` in the `docker-compose` command. For example:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile all-services -f docker-compose-local.yaml up -d
+```
+
+## Access Jupyter-based tutorials
+
+At startup, Docker creates and mounts a volume to persist data from the container to your local machine.
+Access the files created in the Docker container in the `notebooks` folder in your local working directory.
+
+1. Navigate to available notebooks at http://localhost:8889.
+   > If you set `JUPYTER_PORT` to another port number, replace `8889` with the value of the Jupyter port.
+
+2. Select a tutorial.
+
+3. From the navigation menu, select **File > Save as...**.

Review Comment:
   you only need to do this if you want to edit the notebook? If so, Maybe make an optional step?



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,181 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` supplies the Docker tag that specifies which version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile all-services up -d
+```
+
+### Use locally built image
+
+The default Docker Compose file pulls the custom Jupyter Notebook image from Imply's Docker Hub.
+If you would rather build the image locally, do the following:
+1. Clone the Apache Druid repository.
+2. Navigate to `examples/quickstart/jupyter-notebooks/docker-jupyter`.
+3. Start the services using `-f docker-compose-local.yaml` in the `docker-compose` command. For example:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile all-services -f docker-compose-local.yaml up -d
+```
+
+## Access Jupyter-based tutorials
+
+At startup, Docker creates and mounts a volume to persist data from the container to your local machine.
+Access the files created in the Docker container in the `notebooks` folder in your local working directory.
+
+1. Navigate to available notebooks at http://localhost:8889.
+   > If you set `JUPYTER_PORT` to another port number, replace `8889` with the value of the Jupyter port.
+
+2. Select a tutorial.
+
+3. From the navigation menu, select **File > Save as...**.
+In the **Save As** dialog, enter `work/<notebook name>.ipynb`. This step allows you to retain a local copy of your work in the notebook. If the notebook still displays as read only, you may need to refresh the page in your browser.
+
+## View the Druid web console
+
+To access the Druid web console in Docker, go to http://localhost:8888/unified-console.html.
+Use the web console to view datasources and ingestion tasks that you create in the tutorials.
+
+## Stop Docker containers
+
+Shut down the Docker application using the following command:
+
+```bash
+docker-compose down -v
+```
+
+## Tutorial setup without using Docker
+
+To use the Jupyter Notebook-based tutorials without using Docker, do the following:
+
+1. Clone the Apache Druid repo, or download the [tutorials](tutorial-jupyter-index.md#tutorials)
+as well as the [Python client for Druid](tutorial-jupyter-index.md#python-api-for-druid).
+
+2. Install the prerequisite Python packages with the following commands:

Review Comment:
   Add note that individual notebooks may require you to install additional packages and that they'll be listed w/in the notebook



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on PR #13984:
URL: https://github.com/apache/druid/pull/13984#issuecomment-1512160139

   @paul-rogers would you be able to review this PR?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181858916


##########
examples/quickstart/jupyter-notebooks/docker-jupyter/docker-compose.yaml:
##########
@@ -0,0 +1,170 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+#
+---
+version: "2.2"
+
+volumes:
+  metadata_data: {}
+  middle_var: {}
+  historical_var: {}
+  broker_var: {}
+  coordinator_var: {}
+  router_var: {}
+  druid_shared: {}
+
+
+services:

Review Comment:
   Correct. There was originally just the one file `docker-compose.yaml`, but we created the `docker-compose-local.yaml` version to give users an option to build the image locally from the repository. Otherwise users can pull the image from the third party Docker Hub.
   
   Diff between the two files:
   ```
   <     build:
   <       context: ..
   <       dockerfile: Dockerfile
   ---
   >     image: imply/druid-notebook:latest
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1183136701


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",

Review Comment:
   Updated



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1181815899


##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,193 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker compose --profile jupyter up -d
+```
+
+The Docker Compose file assigns `8889` for the Jupyter port.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile all-services up -d
+```
+
+### Update image from Docker Hub
+
+If you already have a local cache of the Jupyter image, you can update the image before running the application using the following command:

Review Comment:
   From what I can tell, you can set up tooling to automatically update to the latest image, but this doesn't happen by default... https://stackoverflow.com/questions/26423515/how-to-automatically-update-your-docker-containers-if-base-images-are-updated



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1183130569


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",
+    "'''\n",
+    "response = sql_client.sql_query(sql)\n",
+    "response.show()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Visualize the total number of upvotes per user using a line plot. You sort the results by username before plotting because the order of users may vary as new results arrive."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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
 CC\n",

Review Comment:
   I configured the bar plot y-axis to log scale which shows the trends much better:
   ![image](https://user-images.githubusercontent.com/7747997/235805862-a5ca7378-09ff-43ff-965f-2229173203f6.png)
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith merged pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith merged PR #13984:
URL: https://github.com/apache/druid/pull/13984


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1177115348


##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,193 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker compose --profile jupyter up -d
+```
+
+The Docker Compose file assigns `8889` for the Jupyter port.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile all-services up -d
+```
+
+### Update image from Docker Hub
+
+If you already have a local cache of the Jupyter image, you can update the image before running the application using the following command:
+
+```bash
+docker compose pull jupyter
+```
+
+### Use locally built image
+
+The default Docker Compose file pulls the custom Jupyter Notebook image from Imply's Docker Hub.
+If you prefer to build the image locally, do the following:

Review Comment:
   ```suggestion
   If you prefer to build the image locally from the official source, do the following:
   ```



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,193 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker compose --profile jupyter up -d
+```
+
+The Docker Compose file assigns `8889` for the Jupyter port.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile druid-jupyter up -d
+```
+
+### Start Jupyter, Druid, and Kafka
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION={{DRUIDVERSION}} docker compose --profile all-services up -d
+```
+
+### Update image from Docker Hub
+
+If you already have a local cache of the Jupyter image, you can update the image before running the application using the following command:
+
+```bash
+docker compose pull jupyter
+```
+
+### Use locally built image
+
+The default Docker Compose file pulls the custom Jupyter Notebook image from Imply's Docker Hub.

Review Comment:
   ```suggestion
   The default Docker Compose file pulls the custom Jupyter Notebook image from a third party Docker Hub.
   ```
   per @gianm , this seems more appropriate.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] techdocsmith commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "techdocsmith (via GitHub)" <gi...@apache.org>.
techdocsmith commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1164724485


##########
docs/tutorials/tutorial-jupyter-index.md:
##########
@@ -32,65 +32,28 @@ the Druid API to complete the tutorial.
 
 ## Prerequisites
 
-Make sure you meet the following requirements before starting the Jupyter-based tutorials:
+The Jupyter-based tutorials require the following:
 
+- An available Druid instance.
 - Python 3.7 or later
+- The `requests` package for Python
+- JupyterLab (recommended) or Jupyter Notebook running on a non-default port.
+By default, Druid and Jupyter both try to use port `8888`, so start Jupyter on a different port.
 
-- The `requests` package for Python. For example, you can install it with the following command:
+Individual tutorials may require additional Python packages, such as for visualization or streaming ingestion.
 
-   ```bash
-   pip3 install requests
-   ```
+You can use the custom Jupyter Notebook Docker image to run the tutorials

Review Comment:
   What if we put this first since it is the easiest way. For example:
   
   The simplest way to get started is to use [Docker ...](link.md) . In this case, you only need Docker desktop.
   
   Otherwise here's what you need:



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,747 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "This tutorial depends on the following Python packages:\n",
+    "* `druidapi`, a Python client for Apache Druid\n",
+    "* `DruidDataDriver`, a data generator\n",
+    "* `kafka`, a Python client for Apache Kafka\n",
+    "* `pandas`, `matplotlib`, and `seaborn` for data visualization\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-index.html)."

Review Comment:
   Data drive uses `confluent_kafka`. I had to install



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,185 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile druid-jupyter up -d

Review Comment:
   should this be a variable like `{{DRUID-VERSION}}` that automatically updates w/ new Druid docs? Line 85 too.



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,747 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "This tutorial depends on the following Python packages:\n",
+    "* `druidapi`, a Python client for Apache Druid\n",
+    "* `DruidDataDriver`, a data generator\n",
+    "* `kafka`, a Python client for Apache Kafka\n",
+    "* `pandas`, `matplotlib`, and `seaborn` for data visualization\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-index.html)."

Review Comment:
   Can we make this first. And I think it would make sense to link to the `tutorial-jupyter-docker.md` since the instructions are there.
   
   If you're running the tutorial in [Docker](t-j-d.md), then BAM! it's all there for you. Otherwise you need:
   - Running Druid
   - Running Kafka
   - All these Python libraries here: x y z
   Also, you may need to configure the ports for Kafka and Druid.



##########
docs/tutorials/tutorial-jupyter-index.md:
##########
@@ -32,65 +32,28 @@ the Druid API to complete the tutorial.
 
 ## Prerequisites
 
-Make sure you meet the following requirements before starting the Jupyter-based tutorials:
+The Jupyter-based tutorials require the following:
 
+- An available Druid instance.
 - Python 3.7 or later
+- The `requests` package for Python
+- JupyterLab (recommended) or Jupyter Notebook running on a non-default port.
+By default, Druid and Jupyter both try to use port `8888`, so start Jupyter on a different port.
 
-- The `requests` package for Python. For example, you can install it with the following command:
+Individual tutorials may require additional Python packages, such as for visualization or streaming ingestion.
 
-   ```bash
-   pip3 install requests
-   ```
+You can use the custom Jupyter Notebook Docker image to run the tutorials
+with minimal setup, or install the prerequisites on your own.
+For more information, see [Docker for Jupyter Notebook tutorials](tutorial-jupyter-docker.md).
 
-- JupyterLab (recommended) or Jupyter Notebook running on a non-default port. By default, Druid
-  and Jupyter both try to use port `8888`, so start Jupyter on a different port.
-
-
-  - Install JupyterLab or Notebook:
-
-    ```bash
-    # Install JupyterLab
-    pip3 install jupyterlab
-    # Install Jupyter Notebook
-    pip3 install notebook
-    ```
-  - Start Jupyter using either JupyterLab
-    ```bash
-    # Start JupyterLab on port 3001
-    jupyter lab --port 3001
-    ```
-
-    Or using Jupyter Notebook
-    ```bash
-    # Start Jupyter Notebook on port 3001
-    jupyter notebook --port 3001
-    ```
-
-- An available Druid instance. You can use the [Quickstart (local)](./index.md) instance. The tutorials
-  assume that you are using the quickstart, so no authentication or authorization
-  is expected unless explicitly mentioned.
-
-  If you contribute to Druid, and work with Druid integration tests, can use a test cluster.
-  Assume you have an environment variable, `DRUID_DEV`, which identifies your Druid source repo.
-
-  ```bash
-  cd $DRUID_DEV
-  ./it.sh build
-  ./it.sh image
-  ./it.sh up <category>
-  ```
-
-  Replace `<category>` with one of the available integration test categories. See the integration
-  test `README.md` for details.
-
-## Simple Druid API
+## Python API for Druid
 
 One of the notebooks shows how to use the Druid REST API. The others focus on other
 topics and use a simple set of Python wrappers around the underlying REST API. The
 wrappers reside in the `druidapi` package within the notebooks directory. While the package
 can be used in any Python program, the key purpose, at present, is to support these
-notebooks. See the [Introduction to the Druid Python API]
-(https://github.com/apache/druid/tree/master/examples/quickstart/jupyter-notebooks/python-api-tutorial.ipynb)
+notebooks. See the
+[Introduction to the Druid Python API](https://github.com/apache/druid/tree/master/examples/quickstart/jupyter-notebooks/python-api-tutorial.ipynb)
 for an overview of the Python API.
 
 ## Tutorials

Review Comment:
   line 61, would reiterate you can use the Docker option



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,185 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.

Review Comment:
   nit: Juptyer default is technically `8888` which we're overriding w/ compose to `8889`.



##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,747 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "This tutorial depends on the following Python packages:\n",
+    "* `druidapi`, a Python client for Apache Druid\n",
+    "* `DruidDataDriver`, a data generator\n",
+    "* `kafka`, a Python client for Apache Kafka\n",
+    "* `pandas`, `matplotlib`, and `seaborn` for data visualization\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-index.html)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"

Review Comment:
   nit: maybe some indication that this is expected? Not sure if there's a way to have the output be more meaningful



##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,185 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.

Review Comment:
   **Docker Compose** is included in current versions of desktop:
   https://docs.docker.com/get-started/08_using_compose/#install-docker-compose



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1164799518


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,747 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "This tutorial depends on the following Python packages:\n",
+    "* `druidapi`, a Python client for Apache Druid\n",
+    "* `DruidDataDriver`, a data generator\n",
+    "* `kafka`, a Python client for Apache Kafka\n",
+    "* `pandas`, `matplotlib`, and `seaborn` for data visualization\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-index.html)."

Review Comment:
   Updated the script to avoid having to install this package



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1164778501


##########
docs/tutorials/tutorial-jupyter-docker.md:
##########
@@ -0,0 +1,185 @@
+---
+id: tutorial-jupyter-docker
+title: "Docker for Jupyter Notebook tutorials"
+sidebar_label: "Docker for tutorials"
+---
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+
+
+Apache Druid provides a custom Jupyter container that contains the prerequisites
+for all Jupyter-based Druid tutorials, as well as all of the tutorials themselves.
+You can run the Jupyter container, as well as containers for Druid and Apache Kafka,
+using the Docker Compose file provided in the Druid GitHub repository.
+
+You can run the following combination of applications:
+* [Jupyter only](#start-only-the-jupyter-container)
+* [Jupyter and Druid](#start-jupyter-and-druid)
+* [Jupyter, Druid, and Kafka](#start-jupyter-druid-and-kafka)
+
+## Prerequisites
+
+Jupyter in Docker requires that you have **Docker** and **Docker Compose**.
+We recommend installing these through [Docker Desktop](https://docs.docker.com/desktop/).
+
+## Launch the Docker containers
+
+You run Docker Compose to launch Jupyter and optionally Druid or Kafka.
+Docker Compose references the configuration in `docker-compose.yaml`.
+Running Druid in Docker also requires the `environment` file, which
+sets the configuration properties for the Druid services.
+To get started, download both `docker-compose.yaml` and `environment` from
+[`tutorial-jupyter-docker.zip`](https://github.com/apache/druid/blob/master/examples/quickstart/jupyter-notebooks/docker-jupyter/tutorial-jupyter-docker.zip).
+
+Alternatively, you can clone the [Apache Druid repo](https://github.com/apache/druid) and
+access the files in `druid/examples/quickstart/jupyter-notebooks/docker-jupyter`.
+
+### Start only the Jupyter container
+
+If you already have Druid running locally, you can run only the Jupyter container to complete the tutorials.
+In the same directory as `docker-compose.yaml`, start the application:
+
+```bash
+docker-compose --profile jupyter up -d
+```
+
+The port assigned to Jupyter is `8889` by default.
+You can override the port number by setting the `JUPYTER_PORT` environment variable before starting the Docker application.
+
+### Start Jupyter and Druid
+
+Running Druid in Docker requires the `environment` file as well as the `DRUID_VERSION` environment variable.
+`DRUID_VERSION` references the Docker tag for the version of Druid to pull from the
+[Apache Druid Docker Hub](https://hub.docker.com/r/apache/druid/tags).
+
+In the same directory as `docker-compose.yaml` and `environment`, start the application:
+
+```bash
+DRUID_VERSION=25.0.0 docker-compose --profile druid-jupyter up -d

Review Comment:
   Looks like I should be able to use `{{DRUIDVERSION}}` like in [pull-deps.md](https://github.com/apache/druid/blob/master/docs/operations/pull-deps.md)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org


[GitHub] [druid] vtlim commented on a diff in pull request #13984: Docs: Tutorial for streaming ingestion using Kafka + Docker file to use with Jupyter tutorials

Posted by "vtlim (via GitHub)" <gi...@apache.org>.
vtlim commented on code in PR #13984:
URL: https://github.com/apache/druid/pull/13984#discussion_r1183131578


##########
examples/quickstart/jupyter-notebooks/kafka-tutorial.ipynb:
##########
@@ -0,0 +1,753 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tutorial: Ingest and query data from Apache Kafka\n",
+    "\n",
+    "<!--\n",
+    "  ~ Licensed to the Apache Software Foundation (ASF) under one\n",
+    "  ~ or more contributor license agreements.  See the NOTICE file\n",
+    "  ~ distributed with this work for additional information\n",
+    "  ~ regarding copyright ownership.  The ASF licenses this file\n",
+    "  ~ to you under the Apache License, Version 2.0 (the\n",
+    "  ~ \"License\"); you may not use this file except in compliance\n",
+    "  ~ with the License.  You may obtain a copy of the License at\n",
+    "  ~\n",
+    "  ~   http://www.apache.org/licenses/LICENSE-2.0\n",
+    "  ~\n",
+    "  ~ Unless required by applicable law or agreed to in writing,\n",
+    "  ~ software distributed under the License is distributed on an\n",
+    "  ~ \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
+    "  ~ KIND, either express or implied.  See the License for the\n",
+    "  ~ specific language governing permissions and limitations\n",
+    "  ~ under the License.\n",
+    "  -->\n",
+    "\n",
+    "This tutorial introduces you to streaming ingestion in Apache Druid using the Apache Kafka event streaming platform.\n",
+    "Follow along to learn how to create and load data into a Kafka topic, start ingesting data from the topic into Druid, and query results over time. This tutorial assumes you have a basic understanding of Druid ingestion, querying, and API requests."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Table of contents\n",
+    "\n",
+    "* [Prerequisites](#Prerequisites)\n",
+    "* [Load Druid API client](#Load-Druid-API-client)\n",
+    "* [Create Kafka topic](#Create-Kafka-topic)\n",
+    "* [Load data into Kafka topic](#Load-data-into-Kafka-topic)\n",
+    "* [Start Druid ingestion](#Start-Druid-ingestion)\n",
+    "* [Query Druid datasource and visualize query results](#Query-Druid-datasource-and-visualize-query-results)\n",
+    "* [Learn more](#Learn-more)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "Launch this tutorial and all prerequisites using the `all-services` profile of the Docker Compose file for Jupyter-based Druid tutorials. For more information, see [Docker for Jupyter Notebook tutorials](https://druid.apache.org/docs/latest/tutorials/tutorial-jupyter-docker.html).\n",
+    "\n",
+    "Otherwise, you need the following:\n",
+    "* A running Druid instance.\n",
+    "   * Update the `druid_host` variable to point to your Router endpoint. For example, `druid_host = \"http://localhost:8888\"`.\n",
+    "* A running Kafka cluster.\n",
+    "   * Update the Kafka bootstrap servers to point to your servers. For example, `bootstrap_servers=[\"localhost:9092\"]`.\n",
+    "* The following Python packages:\n",
+    "   * `druidapi`, a Python client for Apache Druid\n",
+    "   * `DruidDataDriver`, a data generator\n",
+    "   * `kafka`, a Python client for Apache Kafka\n",
+    "   * `pandas`, `matplotlib`, and `seaborn` for data visualization\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load Druid API client"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To start the tutorial, run the following cell. It imports the required Python packages and defines a variable for the Druid client, and another for the SQL client used to run SQL commands."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "<style>\n",
+       "  .druid table {\n",
+       "    border: 1px solid black;\n",
+       "    border-collapse: collapse;\n",
+       "  }\n",
+       "\n",
+       "  .druid th, .druid td {\n",
+       "    padding: 4px 1em ;\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-right, th.druid-right {\n",
+       "    text-align: right;\n",
+       "  }\n",
+       "\n",
+       "  td.druid-center, th.druid-center {\n",
+       "    text-align: center;\n",
+       "  }\n",
+       "\n",
+       "  .druid .druid-left {\n",
+       "    text-align: left;\n",
+       "  }\n",
+       "\n",
+       "  .druid-alert {\n",
+       "    font-weight: bold;\n",
+       "  }\n",
+       "\n",
+       "  .druid-error {\n",
+       "    color: red;\n",
+       "  }\n",
+       "</style>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import druidapi\n",
+    "import json\n",
+    "\n",
+    "# druid_host is the hostname and port for your Druid deployment. \n",
+    "# In a distributed environment, you can point to other Druid services.\n",
+    "# In this tutorial, you'll use the Router service as the `druid_host`.\n",
+    "druid_host = \"http://router:8888\"\n",
+    "\n",
+    "druid = druidapi.jupyter_client(druid_host)\n",
+    "display = druid.display\n",
+    "sql_client = druid.sql\n",
+    "\n",
+    "# Create a rest client for native JSON ingestion for streaming data\n",
+    "rest_client = druidapi.rest.DruidRestClient(\"http://coordinator:8081\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Create Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This notebook relies on the Python client for the Apache Kafka. Import the Kafka producer and consumer modules, then create a Kafka client. You use the Kafka producer to create and publish records to a new topic named `social_media`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from kafka import KafkaProducer\n",
+    "from kafka import KafkaConsumer\n",
+    "\n",
+    "# Kafka runs on kafka:9092 in multi-container tutorial application\n",
+    "producer = KafkaProducer(bootstrap_servers='kafka:9092')\n",
+    "topic_name = \"social_media\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create the `social_media` topic and send a sample event. The `send()` command returns a metadata descriptor for the record."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<kafka.producer.future.FutureRecordMetadata at 0x7f0d904e4940>"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "event = {\n",
+    "    \"__time\": \"2023-01-03T16:40:21.501\",\n",
+    "    \"username\": \"willow_bean\",\n",
+    "    \"post_title\": \"This title is required\",\n",
+    "    \"views\": 15284,\n",
+    "    \"upvotes\": 124,\n",
+    "    \"comments\": 21,\n",
+    "    \"edited\": \"True\"\n",
+    "}\n",
+    "\n",
+    "producer.send(topic_name, json.dumps(event).encode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To verify that the Kafka topic stored the event, create a consumer client to read records from the Kafka cluster, and get the next (only) message:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\"__time\": \"2023-01-03T16:40:21.501\", \"username\": \"willow_bean\", \"post_title\": \"This title is required\", \"views\": 15284, \"upvotes\": 124, \"comments\": 21, \"edited\": \"True\"}\n"
+     ]
+    }
+   ],
+   "source": [
+    "consumer = KafkaConsumer(topic_name, bootstrap_servers=['kafka:9092'], auto_offset_reset='earliest',\n",
+    "     enable_auto_commit=True)\n",
+    "\n",
+    "print(next(consumer).value.decode('utf-8'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load data into Kafka topic"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Instead of manually creating events to send to the Kafka topic, use a data generator to simulate a continuous data stream. This tutorial makes use of Druid Data Driver to simulate a continuous data stream into the `social_media` Kafka topic. To learn more about the Druid Data Driver, see the Druid Summit talk, [Generating Time centric Data for Apache Druid](https://www.youtube.com/watch?v=3zAOeLe3iAo).\n",
+    "\n",
+    "In this notebook, you use a background process to continuously load data into the Kafka topic.\n",
+    "This allows you to keep executing commands in this notebook while data is constantly being streamed into the topic."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run the following cells to load sample data into the `social_media` Kafka topic:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import multiprocessing as mp\n",
+    "from datetime import datetime\n",
+    "import DruidDataDriver"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_driver():\n",
+    "    DruidDataDriver.simulate(\"kafka_docker_config.json\", None, None, \"REAL\", datetime.now())\n",
+    "        \n",
+    "mp.set_start_method('fork')\n",
+    "ps = mp.Process(target=run_driver)\n",
+    "ps.start()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Druid ingestion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now that you have a new Kafka topic and data being streamed into the topic, you ingest the data into Druid by submitting a Kafka ingestion spec.\n",
+    "For more information about Kafka ingestion in Druid, see [Apache Kafka ingestion](https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html).\n",
+    "\n",
+    "Run the following cells to define and submit the Kafka ingestion spec."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "kafka_ingestion_spec = \"{\\\"type\\\": \\\"kafka\\\",\\\"spec\\\": {\\\"ioConfig\\\": {\\\"type\\\": \\\"kafka\\\",\\\"consumerProperties\\\": {\\\"bootstrap.servers\\\": \\\"kafka:9092\\\"},\\\"topic\\\": \\\"social_media\\\",\\\"inputFormat\\\": {\\\"type\\\": \\\"json\\\"},\\\"useEarliestOffset\\\": true},\\\"tuningConfig\\\": {\\\"type\\\": \\\"kafka\\\"},\\\"dataSchema\\\": {\\\"dataSource\\\": \\\"social_media\\\",\\\"timestampSpec\\\": {\\\"column\\\": \\\"__time\\\",\\\"format\\\": \\\"iso\\\"},\\\"dimensionsSpec\\\": {\\\"dimensions\\\": [\\\"username\\\",\\\"post_title\\\",{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"views\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"upvotes\\\"},{\\\"type\\\": \\\"long\\\",\\\"name\\\": \\\"comments\\\"},\\\"edited\\\"]},\\\"granularitySpec\\\": {\\\"queryGranularity\\\": \\\"none\\\",\\\"rollup\\\": false,\\\"segmentGranularity\\\": \\\"hour\\\"}}}}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"type\": \"kafka\",\n",
+      "    \"spec\": {\n",
+      "        \"ioConfig\": {\n",
+      "            \"type\": \"kafka\",\n",
+      "            \"consumerProperties\": {\n",
+      "                \"bootstrap.servers\": \"kafka:9092\"\n",
+      "            },\n",
+      "            \"topic\": \"social_media\",\n",
+      "            \"inputFormat\": {\n",
+      "                \"type\": \"json\"\n",
+      "            },\n",
+      "            \"useEarliestOffset\": true\n",
+      "        },\n",
+      "        \"tuningConfig\": {\n",
+      "            \"type\": \"kafka\"\n",
+      "        },\n",
+      "        \"dataSchema\": {\n",
+      "            \"dataSource\": \"social_media\",\n",
+      "            \"timestampSpec\": {\n",
+      "                \"column\": \"__time\",\n",
+      "                \"format\": \"iso\"\n",
+      "            },\n",
+      "            \"dimensionsSpec\": {\n",
+      "                \"dimensions\": [\n",
+      "                    \"username\",\n",
+      "                    \"post_title\",\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"views\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"upvotes\"\n",
+      "                    },\n",
+      "                    {\n",
+      "                        \"type\": \"long\",\n",
+      "                        \"name\": \"comments\"\n",
+      "                    },\n",
+      "                    \"edited\"\n",
+      "                ]\n",
+      "            },\n",
+      "            \"granularitySpec\": {\n",
+      "                \"queryGranularity\": \"none\",\n",
+      "                \"rollup\": false,\n",
+      "                \"segmentGranularity\": \"hour\"\n",
+      "            }\n",
+      "        }\n",
+      "    }\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(json.dumps(json.loads(kafka_ingestion_spec), indent=4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Response [200]>"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "headers = {\n",
+    "  'Content-Type': 'application/json'\n",
+    "}\n",
+    "\n",
+    "rest_client.post(\"/druid/indexer/v1/supervisor\", kafka_ingestion_spec, headers=headers)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query Druid datasource and visualize query results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can now query the new datasource called `social_media`. In this section, you also visualize query results using the Matplotlib and Seaborn visualization libraries. Run the following cell import these packages."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "import matplotlib\n",
+    "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Run a simple query to view a subset of rows from the new datasource:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>__time</th><th>username</th><th>post_title</th><th>views</th><th>upvotes</th><th>comments</th><th>edited</th></tr>\n",
+       "<tr><td>2023-01-03T16:40:21.501Z</td><td>willow_bean</td><td>This title is required</td><td>15284</td><td>124</td><td>21</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>mish_middy</td><td>l0g!9IQdgd9uOBoBVAr.eNBxxDCrn_</td><td>11674</td><td>53</td><td>14</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.920Z</td><td>rocket</td><td>rpF!DoCRz:Ityskmor752VZIPOPb7_gjbNNUCxmRDMhaIJlWJBKucW</td><td>2791</td><td>56</td><td>1</td><td>True</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>jojo</td><td>pb3gqohSiTRfy.CBU:n;SNHMHH5WG._2Am,L1Z!eS7zg:&#x27;E3rAsbRhbOh3Px!8fVFhKTHx,&#x27;cvUbHmzT,r,1d3</td><td>2022</td><td>47</td><td>9</td><td>False</td></tr>\n",
+       "<tr><td>2023-03-15T23:59:46.921Z</td><td>willow_bean</td><td>06!JKoyFKhpuHvZtXgB4GpYjcG9GGn5</td><td>36305</td><td>78</td><td>-2</td><td>True</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT * FROM social_media LIMIT 5\n",
+    "'''\n",
+    "display.sql(sql)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this social media scenario, each incoming event represents a post on social media, for which you collect the timestamp, username, and post metadata. You are interested in analyzing the total number of upvotes for all posts, compared between users. Preview this data with the following query:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div class=\"druid\"><table>\n",
+       "<tr><th>num_posts</th><th>total_upvotes</th><th>username</th></tr>\n",
+       "<tr><td>193219</td><td>13406871</td><td>jambalion</td></tr>\n",
+       "<tr><td>193495</td><td>13446847</td><td>miette</td></tr>\n",
+       "<tr><td>193608</td><td>13452801</td><td>milton</td></tr>\n",
+       "<tr><td>193720</td><td>13467209</td><td>willow_bean</td></tr>\n",
+       "<tr><td>193851</td><td>13461992</td><td>mish_middy</td></tr>\n",
+       "<tr><td>193908</td><td>13480426</td><td>shadow</td></tr>\n",
+       "<tr><td>193949</td><td>13480342</td><td>jojo</td></tr>\n",
+       "<tr><td>194197</td><td>13492537</td><td>rocket</td></tr>\n",
+       "</table></div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "sql = '''\n",
+    "SELECT COUNT(post_title) as num_posts, SUM(upvotes) as total_upvotes, username FROM social_media GROUP BY username ORDER BY num_posts\n",
+    "'''\n",
+    "response = sql_client.sql_query(sql)\n",
+    "response.show()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Visualize the total number of upvotes per user using a line plot. You sort the results by username before plotting because the order of users may vary as new results arrive."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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
 CC\n",

Review Comment:
   I configured the bar plot y-axis to log scale which shows the trends much better:
   
   ![image](https://user-images.githubusercontent.com/7747997/235806145-61330794-13a2-4a1e-801b-79675549d4f0.png)
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org