writer-jill commented on code in PR #13787:
URL: https://github.com/apache/druid/pull/13787#discussion_r1114651673
##########
docs/tutorials/tutorial-jupyter-index.md:
##########
@@ -22,50 +22,85 @@ title: "Jupyter Notebook tutorials"
~ under the License.
-->
-<!-- tutorial-jupyter-index.md and
examples/quickstart/juptyer-notebooks/README.md share a lot of the same
content. If you make a change in one place, update the other too. -->
+<!-- tutorial-jupyter-index.md and
examples/quickstart/juptyer-notebooks/README.md
+ share a lot of the same content. If you make a change in one place, update
the other
+ too. -->
-You can try out the Druid APIs using the Jupyter Notebook-based tutorials.
These tutorials provide snippets of Python code that you can use to run calls
against the Druid API to complete the tutorial.
+You can try out the Druid APIs using the Jupyter Notebook-based tutorials.
These
+tutorials provide snippets of Python code that you can use to run calls against
+the Druid API to complete the tutorial.
## Prerequisites
Make sure you meet the following requirements before starting the
Jupyter-based tutorials:
-- Python 3
+- Python 3
+
+- The `requests` package for Python. For example, you can install it with the
following command:
-- The `requests` package for Python. For example, you can install it with the
following command:
-
```bash
pip3 install requests
```
-- 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.
+- 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
- - JupyterLab
+
+ ```bash
+ # Install JupyterLab
+ pip3 install jupyterlab
+ # Install Jupyter Notebook
+ pip3 install notebook
+ ```
+ - Start Jupyter:
+ - JupyterLab
```bash
# Start JupyterLab on port 3001
jupyter lab --port 3001
```
- Jupyter Notebook
- ```bash
- # Start Jupyter Notebook on port 3001
- jupyter notebook --port 3001
- ```
+ ```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.
+
+ Druid developers can use a cluster launched for an integration test:
+
+ ```bash
+ cd $DRUID_DEV
+ ./it.sh build
+ ./it.sh image
+ ./it.sh up <category>
+ ```
+
+ Where `DRUID_DEV` points to your Druid source code repo, and `<catagory>` is
one
Review Comment:
```suggestion
Replace `DRUID_DEV` with your Druid source code repo, and `<category>`
with one
```
##########
examples/quickstart/jupyter-notebooks/README.md:
##########
@@ -57,33 +65,25 @@ Make sure you meet the following requirements before
starting the Jupyter-based
jupyter notebook --port 3001
```
-- An available Druid instance. You can use the `micro-quickstart`
configuration described in [Quickstart
(local)](../../../docs/tutorials/index.md). The tutorials assume that you are
using the quickstart, so no authentication or authorization is expected unless
explicitly mentioned.
-
-## Tutorials
-
-The notebooks are located in the [apache/druid
repo](https://github.com/apache/druid/tree/master/examples/quickstart/jupyter-notebooks/).
You can either clone the repo or download the notebooks you want individually.
-
-The links that follow are the raw GitHub URLs, so you can use them to download
the notebook directly, such as with `wget`, or manually through your web
browser. Note that if you save the file from your web browser, make sure to
remove the `.txt` extension.
-
-- [Introduction to the Druid API](api-tutorial.ipynb) walks you through some
of the basics related to the Druid API and several endpoints.
-
-## Contributing
-
-If you build a Jupyter tutorial, you need to do a few things to add it to the
docs in addition to saving the notebook in this directory. The process requires
two PRs to the repo.
-
-For the first PR, do the following:
-
-1. Clear the outputs from your notebook before you make the PR. You can use
the following command:
+- An available Druid instance. You can use the `micro-quickstart` configuration
+ described in
[Quickstart](https://druid.apache.org/docs/latest/tutorials/index.html).
+ The tutorials assume that you are using the quickstart, so no authentication
or authorization
+ is expected unless explicitly mentioned.
- ```bash
- jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace
./path/to/notebook/notebookName.ipynb
- ```
+ Druid developers can use a cluster launched for an integration test:
-2. Create the PR as you normally would. Make sure to note that this PR is the
one that contains only the Jupyter notebook and that there will be a subsequent
PR that updates related pages.
+ ```bash
+ cd $DRUID_DEV
+ ./it.sh build
+ ./it.sh image
+ ./it.sh up <category>
+ ```
-3. After this first PR is merged, grab the "raw" URL for the file from GitHub.
For example, navigate to the file in the GitHub web UI and select **Raw**. Use
the URL for this in the second PR as the download link.
+ Where `DRUID_DEV` points to your Druid source code repo, and `<catagory>` is
one
Review Comment:
```suggestion
Replace `DRUID_DEV` with your Druid source code repo, and `<category>`
with one
```
##########
docs/tutorials/tutorial-jupyter-index.md:
##########
@@ -22,50 +22,85 @@ title: "Jupyter Notebook tutorials"
~ under the License.
-->
-<!-- tutorial-jupyter-index.md and
examples/quickstart/juptyer-notebooks/README.md share a lot of the same
content. If you make a change in one place, update the other too. -->
+<!-- tutorial-jupyter-index.md and
examples/quickstart/juptyer-notebooks/README.md
+ share a lot of the same content. If you make a change in one place, update
the other
+ too. -->
-You can try out the Druid APIs using the Jupyter Notebook-based tutorials.
These tutorials provide snippets of Python code that you can use to run calls
against the Druid API to complete the tutorial.
+You can try out the Druid APIs using the Jupyter Notebook-based tutorials.
These
+tutorials provide snippets of Python code that you can use to run calls against
+the Druid API to complete the tutorial.
## Prerequisites
Make sure you meet the following requirements before starting the
Jupyter-based tutorials:
-- Python 3
+- Python 3
+
+- The `requests` package for Python. For example, you can install it with the
following command:
-- The `requests` package for Python. For example, you can install it with the
following command:
-
```bash
pip3 install requests
```
-- 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.
+- 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
- - JupyterLab
+
+ ```bash
+ # Install JupyterLab
+ pip3 install jupyterlab
+ # Install Jupyter Notebook
+ pip3 install notebook
+ ```
+ - Start Jupyter:
+ - JupyterLab
```bash
# Start JupyterLab on port 3001
jupyter lab --port 3001
```
- Jupyter Notebook
- ```bash
- # Start Jupyter Notebook on port 3001
- jupyter notebook --port 3001
- ```
+ ```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.
+
+ Druid developers can use a cluster launched for an integration test:
Review Comment:
```suggestion
If you're a Druid developer, you can use a cluster launched for an
integration test:
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -151,7 +209,18 @@
"source": [
"### Get cluster health\n",
"\n",
- "The `/status/health` endpoint returns `true` if your cluster is up and
running. It's useful if you want to do something like programmatically check if
your cluster is available. When you run the following cell, you should get
`true` if your Druid cluster has finished starting up and is running."
+ "The `/status/health` endpoint returns JSON `true` if your cluster is up
and running. It's useful if you want to do something like programmatically
check if your cluster is available. When you run the following cell, you should
get the `True` Python value if your Druid cluster has finished starting up and
is running."
Review Comment:
```suggestion
"The `/status/health` endpoint returns JSON `true` if your cluster is up
and running. It's useful if you want to do something like programmatically
check if your cluster is available. When you run the following cell, you should
receive the `True` Python value if your Druid cluster has finished starting up
and is running."
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -376,25 +546,54 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "694900d0-891f-41bd-9b45-5ae957385244",
+ "id": "44868ff9",
"metadata": {},
"outputs": [],
"source": [
- "endpoint = \"/druid/v2/sql\"\n",
- "print(f\"\\033[1mQuery endpoint\\033[0m: {druid_host+endpoint}\")\n",
- "http_method = \"POST\"\n",
- "\n",
- "payload = json.dumps({\n",
- " \"query\": \"SELECT * FROM wikipedia_api LIMIT 3\"\n",
- "})\n",
- "headers = {'Content-Type': 'application/json'}\n",
- "\n",
- "response = requests.request(http_method, druid_host+endpoint,
headers=headers, data=payload)\n",
- "\n",
- "print(\"\\033[1mQuery\\033[0m:\\n\" + payload)\n",
- "print(f\"\\nEach JSON object in the response represents a row in the
{dataSourceName} datasource.\") \n",
- "print(\"\\n\\033[1mResponse\\033[0m: \\n\" + json.dumps(response.json(),
indent=4))\n",
- "\n"
+ "endpoint = druid_host + '/druid/v2/sql'\n",
+ "endpoint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b2b366ad",
+ "metadata": {},
+ "source": [
+ "As we did for ingestion, define a query, then create a `SQLRequest`
object as a Python `dict`."
Review Comment:
```suggestion
"Define a query, then create a `SQLRequest` object as a Python `dict`."
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -210,60 +286,141 @@
"\n",
"To learn more, see
[Partitioning](https://druid.apache.org/docs/latest/ingestion/partitioning.html).\n",
"\n",
- "Now, run the next cell to start the ingestion."
+ "The query uses `INSERT INTO`. If you have an existing datasource with the
name `wikipedia_api`, use `REPLACE INTO` instead."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "362b6a87",
+ "id": "90c34908",
"metadata": {},
"outputs": [],
"source": [
- "endpoint = \"/druid/v2/sql/task\"\n",
- "print(f\"\\033[1mQuery endpoint\\033[0m: {druid_host+endpoint}\")\n",
- "http_method = \"POST\"\n",
- "\n",
+ "sql = '''\n",
+ "INSERT INTO wikipedia_api \n",
+ "SELECT \n",
+ " TIME_PARSE(\"timestamp\") AS __time,\n",
+ " * \n",
+ "FROM TABLE(EXTERN(\n",
+ " '{\"type\": \"http\", \"uris\":
[\"https://druid.apache.org/data/wikipedia.json.gz\"]}', \n",
+ " '{\"type\": \"json\"}', \n",
+ " '[{\"name\": \"added\", \"type\": \"long\"}, {\"name\": \"channel\",
\"type\": \"string\"}, {\"name\": \"cityName\", \"type\": \"string\"},
{\"name\": \"comment\", \"type\": \"string\"}, {\"name\": \"commentLength\",
\"type\": \"long\"}, {\"name\": \"countryIsoCode\", \"type\": \"string\"},
{\"name\": \"countryName\", \"type\": \"string\"}, {\"name\": \"deleted\",
\"type\": \"long\"}, {\"name\": \"delta\", \"type\": \"long\"}, {\"name\":
\"deltaBucket\", \"type\": \"string\"}, {\"name\": \"diffUrl\", \"type\":
\"string\"}, {\"name\": \"flags\", \"type\": \"string\"}, {\"name\":
\"isAnonymous\", \"type\": \"string\"}, {\"name\": \"isMinor\", \"type\":
\"string\"}, {\"name\": \"isNew\", \"type\": \"string\"}, {\"name\":
\"isRobot\", \"type\": \"string\"}, {\"name\": \"isUnpatrolled\", \"type\":
\"string\"}, {\"name\": \"metroCode\", \"type\": \"string\"}, {\"name\":
\"namespace\", \"type\": \"string\"}, {\"name\": \"page\", \"type\":
\"string\"}, {\"name\": \"regionIsoCode\", \
"type\": \"string\"}, {\"name\": \"regionName\", \"type\": \"string\"},
{\"name\": \"timestamp\", \"type\": \"string\"}, {\"name\": \"user\", \"type\":
\"string\"}]'\n",
+ " ))\n",
+ "PARTITIONED BY DAY\n",
+ "'''"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7dcddd7",
+ "metadata": {},
+ "source": [
+ "The query is included inline here. You can also store it in a file and
provide the file.\n",
"\n",
- "# The query uses INSERT INTO. If you have an existing datasource with the
name wikipedia_api, use REPLACE INTO instead.\n",
- "payload = json.dumps({\n",
- "\"query\": \"INSERT INTO wikipedia_api SELECT
TIME_PARSE(\\\"timestamp\\\") \\\n",
- " AS __time, * FROM TABLE \\\n",
- " (EXTERN('{\\\"type\\\": \\\"http\\\", \\\"uris\\\":
[\\\"https://druid.apache.org/data/wikipedia.json.gz\\\"]}', '{\\\"type\\\":
\\\"json\\\"}', '[{\\\"name\\\": \\\"added\\\", \\\"type\\\": \\\"long\\\"},
{\\\"name\\\": \\\"channel\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"cityName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"comment\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"commentLength\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\":
\\\"countryIsoCode\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"countryName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"deleted\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"delta\\\",
\\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"deltaBucket\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"diffUrl\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"flags\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isAnonymous\\\", \\\"type\\\": \\\"string\\\"}, {\\\
"name\\\": \\\"isMinor\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isNew\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isRobot\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isUnpatrolled\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"metroCode\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"namespace\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"page\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionIsoCode\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionName\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"timestamp\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"user\\\", \\\"type\\\": \\\"string\\\"}]')) \\\n",
- " PARTITIONED BY DAY\",\n",
- " \"context\": {\n",
- " \"maxNumTasks\": 3\n",
+ "Just as Requests can convert the response from JSON to Python, it can
also convert the request from Python to JSON. The next cell builds up a Python
map that represents the Druid `SqlRequest` object. In this case, we need the
query and a context variable to set the task count to 3."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6e82c0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "sql_request = {\n",
+ " 'query': sql,\n",
+ " 'context': {\n",
+ " 'maxNumTasks': 3\n",
" }\n",
- "})\n",
- "\n",
- "headers = {'Content-Type': 'application/json'}\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6aa7f230",
+ "metadata": {},
+ "source": [
+ "With the SQL request ready, we now use the the `json` parameter to the
`Session` `post` method to send a `POST` request with our object as the
payload. The result is a Requests `Response` which we save in a variable.\n",
"\n",
- "response = requests.request(http_method, druid_host+endpoint,
headers=headers, data=payload)\n",
- "ingestion_taskId_response = response\n",
- "print(f\"\\033[1mQuery\\033[0m:\\n\" + payload)\n",
- "print(f\"\\nInserting data into the table named {dataSourceName}\")\n",
- "print(\"\\nThe response includes the task ID and the status: \" +
response.text + \".\")"
+ "Now, run the next cell to start the ingestion."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2939a07",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = session.post(endpoint, json=sql_request)"
]
},
{
"cell_type": "markdown",
- "id": "c1235e99-be72-40b0-b7f9-9e860e4932d7",
+ "id": "9ba1821f",
"metadata": {
"tags": []
},
"source": [
- "Extract the `taskId` value from the `taskId_response` variable so that
you can reference it later:"
+ "The MSQ task engine uses a task to ingest data. The response for the API
includes a `taskId` and `state` for your ingestion. You can use this `taskId`
to reference this task later on to get more information about it."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9cc2e45",
+ "metadata": {},
+ "source": [
+ "It is good to check that the response suceeded by checking the return
status. It should be 20x. (202 means \"accepted\".) If the response is
something else (4xx, say) then display `response.text` to see the error
message."
Review Comment:
```suggestion
"It is good practice to ensure that the response succeeded by checking
the return status. The status should be 20x. (202 means \"accepted\".) If the
response is something else, such as 4xx, display `response.text` to see the
error message."
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -119,7 +144,28 @@
"\n",
"In this cell, you'll use the `GET /status` endpoint to return basic
information about your cluster, such as the Druid version, loaded extensions,
and resource consumption.\n",
"\n",
- "The following cell sets `endpoint` to `/status` and updates the HTTP
method to `GET`. When you run the cell, you should get a response that starts
with the version number of your Druid deployment."
+ "The following cell sets `endpoint` to `/status` and updates the HTTP
method to `GET`. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8a1b453e",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "endpoint = druid_host + '/status'\n",
+ "endpoint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1e853795",
+ "metadata": {},
+ "source": [
+ "The Requests `Session` has a `get()` method that posts an HTTP `GET`
request. The method takes multiple arguments. Here we only need the URL. The
method returns a Requests `Response` object, which can convert the returned
result to JSON. When you run the cell, you should get a response that starts
with the version number of your Druid deployment."
Review Comment:
```suggestion
"The Requests `Session` has a `get()` method that posts an HTTP `GET`
request. The method takes multiple arguments. Here you only need the URL. The
method returns a Requests `Response` object, which can convert the returned
result to JSON. When you run the cell, you should get a response that starts
with the version number of your Druid deployment."
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -91,21 +102,35 @@
"outputs": [],
"source": [
"import requests\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. In
this tutorial, you'll use the Router service as the `druid_host`. \n",
"druid_host = \"http://localhost:8888\"\n",
- "dataSourceName = \"wikipedia_api\"\n",
- "print(f\"\\033[1mDruid host\\033[0m: {druid_host}\")"
+ "druid_host"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a22c69c8",
+ "metadata": {},
+ "source": [
+ "If your cluster is secure, you'll need to provide authorization
information on each request. That can be automated by using the Requests
`session` feature. Although we assume no authorization here, we'll still use a
session to show how it is done."
Review Comment:
```suggestion
"If your cluster is secure, you'll need to provide authorization
information on each request. You can automate it by using the Requests
`session` feature. Although this tutorial assumes no authorization, the
configuration below defines a session as an example."
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -131,15 +177,27 @@
},
"outputs": [],
"source": [
- "endpoint = \"/status\"\n",
- "print(f\"\\033[1mQuery endpoint\\033[0m: {druid_host+endpoint}\")\n",
- "http_method = \"GET\"\n",
- "\n",
- "payload = {}\n",
- "headers = {}\n",
- "\n",
- "response = requests.request(http_method, druid_host+endpoint,
headers=headers, data=payload)\n",
- "print(\"\\033[1mResponse\\033[0m: : \\n\" + json.dumps(response.json(),
indent=4))"
+ "response = session.get(endpoint)\n",
+ "json = response.json()\n",
+ "json"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "de82029e",
+ "metadata": {},
+ "source": [
+ "Since Druid's responses are JSON, and Requests converted the JSON to a
set of Python dicts (maps) and arrays, we can easily pull out the information
we want. For example, to seee just the version:"
Review Comment:
"you" instead of "we"
##########
examples/quickstart/jupyter-notebooks/README.md:
##########
@@ -57,33 +65,25 @@ Make sure you meet the following requirements before
starting the Jupyter-based
jupyter notebook --port 3001
```
-- An available Druid instance. You can use the `micro-quickstart`
configuration described in [Quickstart
(local)](../../../docs/tutorials/index.md). The tutorials assume that you are
using the quickstart, so no authentication or authorization is expected unless
explicitly mentioned.
-
-## Tutorials
-
-The notebooks are located in the [apache/druid
repo](https://github.com/apache/druid/tree/master/examples/quickstart/jupyter-notebooks/).
You can either clone the repo or download the notebooks you want individually.
-
-The links that follow are the raw GitHub URLs, so you can use them to download
the notebook directly, such as with `wget`, or manually through your web
browser. Note that if you save the file from your web browser, make sure to
remove the `.txt` extension.
-
-- [Introduction to the Druid API](api-tutorial.ipynb) walks you through some
of the basics related to the Druid API and several endpoints.
-
-## Contributing
-
-If you build a Jupyter tutorial, you need to do a few things to add it to the
docs in addition to saving the notebook in this directory. The process requires
two PRs to the repo.
-
-For the first PR, do the following:
-
-1. Clear the outputs from your notebook before you make the PR. You can use
the following command:
+- An available Druid instance. You can use the `micro-quickstart` configuration
+ described in
[Quickstart](https://druid.apache.org/docs/latest/tutorials/index.html).
+ The tutorials assume that you are using the quickstart, so no authentication
or authorization
+ is expected unless explicitly mentioned.
- ```bash
- jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace
./path/to/notebook/notebookName.ipynb
- ```
+ Druid developers can use a cluster launched for an integration test:
Review Comment:
```suggestion
If you're a Druid developer, you can use a cluster launched for an
integration test:
```
##########
examples/quickstart/jupyter-notebooks/README.md:
##########
@@ -57,33 +65,25 @@ Make sure you meet the following requirements before
starting the Jupyter-based
jupyter notebook --port 3001
```
-- An available Druid instance. You can use the `micro-quickstart`
configuration described in [Quickstart
(local)](../../../docs/tutorials/index.md). The tutorials assume that you are
using the quickstart, so no authentication or authorization is expected unless
explicitly mentioned.
-
-## Tutorials
-
-The notebooks are located in the [apache/druid
repo](https://github.com/apache/druid/tree/master/examples/quickstart/jupyter-notebooks/).
You can either clone the repo or download the notebooks you want individually.
-
-The links that follow are the raw GitHub URLs, so you can use them to download
the notebook directly, such as with `wget`, or manually through your web
browser. Note that if you save the file from your web browser, make sure to
remove the `.txt` extension.
-
-- [Introduction to the Druid API](api-tutorial.ipynb) walks you through some
of the basics related to the Druid API and several endpoints.
-
-## Contributing
-
-If you build a Jupyter tutorial, you need to do a few things to add it to the
docs in addition to saving the notebook in this directory. The process requires
two PRs to the repo.
-
-For the first PR, do the following:
-
-1. Clear the outputs from your notebook before you make the PR. You can use
the following command:
+- An available Druid instance. You can use the `micro-quickstart` configuration
+ described in
[Quickstart](https://druid.apache.org/docs/latest/tutorials/index.html).
+ The tutorials assume that you are using the quickstart, so no authentication
or authorization
+ is expected unless explicitly mentioned.
- ```bash
- jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace
./path/to/notebook/notebookName.ipynb
- ```
+ Druid developers can use a cluster launched for an integration test:
-2. Create the PR as you normally would. Make sure to note that this PR is the
one that contains only the Jupyter notebook and that there will be a subsequent
PR that updates related pages.
+ ```bash
+ cd $DRUID_DEV
+ ./it.sh build
+ ./it.sh image
+ ./it.sh up <category>
+ ```
-3. After this first PR is merged, grab the "raw" URL for the file from GitHub.
For example, navigate to the file in the GitHub web UI and select **Raw**. Use
the URL for this in the second PR as the download link.
+ Where `DRUID_DEV` points to your Druid source code repo, and `<catagory>` is
one
+ of the available integration test categories. See the integration test
`README.md`
+ for details.
-For the second PR, do the following:
+## Continue in Jupyter
-1. Update the list of [Tutorials](#tutorials) on this page and in the [
Jupyter tutorial index
page](../../../docs/tutorials/tutorial-jupyter-index.md#tutorials) in the
`docs/tutorials` directory.
-2. Update `tutorial-jupyter-index.md` and provide the URL to the raw version
of the file that becomes available after the first PR is merged.
+Fire up Jupyter (see above) and navigate to the "- START HERE -" page for more
Review Comment:
```suggestion
Start Jupyter (see above) and navigate to the "- START HERE -" page for more
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -210,60 +286,141 @@
"\n",
"To learn more, see
[Partitioning](https://druid.apache.org/docs/latest/ingestion/partitioning.html).\n",
"\n",
- "Now, run the next cell to start the ingestion."
+ "The query uses `INSERT INTO`. If you have an existing datasource with the
name `wikipedia_api`, use `REPLACE INTO` instead."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "362b6a87",
+ "id": "90c34908",
"metadata": {},
"outputs": [],
"source": [
- "endpoint = \"/druid/v2/sql/task\"\n",
- "print(f\"\\033[1mQuery endpoint\\033[0m: {druid_host+endpoint}\")\n",
- "http_method = \"POST\"\n",
- "\n",
+ "sql = '''\n",
+ "INSERT INTO wikipedia_api \n",
+ "SELECT \n",
+ " TIME_PARSE(\"timestamp\") AS __time,\n",
+ " * \n",
+ "FROM TABLE(EXTERN(\n",
+ " '{\"type\": \"http\", \"uris\":
[\"https://druid.apache.org/data/wikipedia.json.gz\"]}', \n",
+ " '{\"type\": \"json\"}', \n",
+ " '[{\"name\": \"added\", \"type\": \"long\"}, {\"name\": \"channel\",
\"type\": \"string\"}, {\"name\": \"cityName\", \"type\": \"string\"},
{\"name\": \"comment\", \"type\": \"string\"}, {\"name\": \"commentLength\",
\"type\": \"long\"}, {\"name\": \"countryIsoCode\", \"type\": \"string\"},
{\"name\": \"countryName\", \"type\": \"string\"}, {\"name\": \"deleted\",
\"type\": \"long\"}, {\"name\": \"delta\", \"type\": \"long\"}, {\"name\":
\"deltaBucket\", \"type\": \"string\"}, {\"name\": \"diffUrl\", \"type\":
\"string\"}, {\"name\": \"flags\", \"type\": \"string\"}, {\"name\":
\"isAnonymous\", \"type\": \"string\"}, {\"name\": \"isMinor\", \"type\":
\"string\"}, {\"name\": \"isNew\", \"type\": \"string\"}, {\"name\":
\"isRobot\", \"type\": \"string\"}, {\"name\": \"isUnpatrolled\", \"type\":
\"string\"}, {\"name\": \"metroCode\", \"type\": \"string\"}, {\"name\":
\"namespace\", \"type\": \"string\"}, {\"name\": \"page\", \"type\":
\"string\"}, {\"name\": \"regionIsoCode\", \
"type\": \"string\"}, {\"name\": \"regionName\", \"type\": \"string\"},
{\"name\": \"timestamp\", \"type\": \"string\"}, {\"name\": \"user\", \"type\":
\"string\"}]'\n",
+ " ))\n",
+ "PARTITIONED BY DAY\n",
+ "'''"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7dcddd7",
+ "metadata": {},
+ "source": [
+ "The query is included inline here. You can also store it in a file and
provide the file.\n",
"\n",
- "# The query uses INSERT INTO. If you have an existing datasource with the
name wikipedia_api, use REPLACE INTO instead.\n",
- "payload = json.dumps({\n",
- "\"query\": \"INSERT INTO wikipedia_api SELECT
TIME_PARSE(\\\"timestamp\\\") \\\n",
- " AS __time, * FROM TABLE \\\n",
- " (EXTERN('{\\\"type\\\": \\\"http\\\", \\\"uris\\\":
[\\\"https://druid.apache.org/data/wikipedia.json.gz\\\"]}', '{\\\"type\\\":
\\\"json\\\"}', '[{\\\"name\\\": \\\"added\\\", \\\"type\\\": \\\"long\\\"},
{\\\"name\\\": \\\"channel\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"cityName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"comment\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"commentLength\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\":
\\\"countryIsoCode\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"countryName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"deleted\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"delta\\\",
\\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"deltaBucket\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"diffUrl\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"flags\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isAnonymous\\\", \\\"type\\\": \\\"string\\\"}, {\\\
"name\\\": \\\"isMinor\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isNew\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isRobot\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isUnpatrolled\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"metroCode\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"namespace\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"page\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionIsoCode\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionName\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"timestamp\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"user\\\", \\\"type\\\": \\\"string\\\"}]')) \\\n",
- " PARTITIONED BY DAY\",\n",
- " \"context\": {\n",
- " \"maxNumTasks\": 3\n",
+ "Just as Requests can convert the response from JSON to Python, it can
also convert the request from Python to JSON. The next cell builds up a Python
map that represents the Druid `SqlRequest` object. In this case, we need the
query and a context variable to set the task count to 3."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6e82c0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "sql_request = {\n",
+ " 'query': sql,\n",
+ " 'context': {\n",
+ " 'maxNumTasks': 3\n",
" }\n",
- "})\n",
- "\n",
- "headers = {'Content-Type': 'application/json'}\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6aa7f230",
+ "metadata": {},
+ "source": [
+ "With the SQL request ready, we now use the the `json` parameter to the
`Session` `post` method to send a `POST` request with our object as the
payload. The result is a Requests `Response` which we save in a variable.\n",
Review Comment:
```suggestion
"With the SQL request ready, use the the `json` parameter to the
`Session` `post` method to send a `POST` request with our object as the
payload. The result is a Requests `Response` which you save in a variable.\n",
```
##########
examples/quickstart/jupyter-notebooks/api-tutorial.ipynb:
##########
@@ -210,60 +286,141 @@
"\n",
"To learn more, see
[Partitioning](https://druid.apache.org/docs/latest/ingestion/partitioning.html).\n",
"\n",
- "Now, run the next cell to start the ingestion."
+ "The query uses `INSERT INTO`. If you have an existing datasource with the
name `wikipedia_api`, use `REPLACE INTO` instead."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "362b6a87",
+ "id": "90c34908",
"metadata": {},
"outputs": [],
"source": [
- "endpoint = \"/druid/v2/sql/task\"\n",
- "print(f\"\\033[1mQuery endpoint\\033[0m: {druid_host+endpoint}\")\n",
- "http_method = \"POST\"\n",
- "\n",
+ "sql = '''\n",
+ "INSERT INTO wikipedia_api \n",
+ "SELECT \n",
+ " TIME_PARSE(\"timestamp\") AS __time,\n",
+ " * \n",
+ "FROM TABLE(EXTERN(\n",
+ " '{\"type\": \"http\", \"uris\":
[\"https://druid.apache.org/data/wikipedia.json.gz\"]}', \n",
+ " '{\"type\": \"json\"}', \n",
+ " '[{\"name\": \"added\", \"type\": \"long\"}, {\"name\": \"channel\",
\"type\": \"string\"}, {\"name\": \"cityName\", \"type\": \"string\"},
{\"name\": \"comment\", \"type\": \"string\"}, {\"name\": \"commentLength\",
\"type\": \"long\"}, {\"name\": \"countryIsoCode\", \"type\": \"string\"},
{\"name\": \"countryName\", \"type\": \"string\"}, {\"name\": \"deleted\",
\"type\": \"long\"}, {\"name\": \"delta\", \"type\": \"long\"}, {\"name\":
\"deltaBucket\", \"type\": \"string\"}, {\"name\": \"diffUrl\", \"type\":
\"string\"}, {\"name\": \"flags\", \"type\": \"string\"}, {\"name\":
\"isAnonymous\", \"type\": \"string\"}, {\"name\": \"isMinor\", \"type\":
\"string\"}, {\"name\": \"isNew\", \"type\": \"string\"}, {\"name\":
\"isRobot\", \"type\": \"string\"}, {\"name\": \"isUnpatrolled\", \"type\":
\"string\"}, {\"name\": \"metroCode\", \"type\": \"string\"}, {\"name\":
\"namespace\", \"type\": \"string\"}, {\"name\": \"page\", \"type\":
\"string\"}, {\"name\": \"regionIsoCode\", \
"type\": \"string\"}, {\"name\": \"regionName\", \"type\": \"string\"},
{\"name\": \"timestamp\", \"type\": \"string\"}, {\"name\": \"user\", \"type\":
\"string\"}]'\n",
+ " ))\n",
+ "PARTITIONED BY DAY\n",
+ "'''"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7dcddd7",
+ "metadata": {},
+ "source": [
+ "The query is included inline here. You can also store it in a file and
provide the file.\n",
"\n",
- "# The query uses INSERT INTO. If you have an existing datasource with the
name wikipedia_api, use REPLACE INTO instead.\n",
- "payload = json.dumps({\n",
- "\"query\": \"INSERT INTO wikipedia_api SELECT
TIME_PARSE(\\\"timestamp\\\") \\\n",
- " AS __time, * FROM TABLE \\\n",
- " (EXTERN('{\\\"type\\\": \\\"http\\\", \\\"uris\\\":
[\\\"https://druid.apache.org/data/wikipedia.json.gz\\\"]}', '{\\\"type\\\":
\\\"json\\\"}', '[{\\\"name\\\": \\\"added\\\", \\\"type\\\": \\\"long\\\"},
{\\\"name\\\": \\\"channel\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"cityName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"comment\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"commentLength\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\":
\\\"countryIsoCode\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"countryName\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"deleted\\\", \\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"delta\\\",
\\\"type\\\": \\\"long\\\"}, {\\\"name\\\": \\\"deltaBucket\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"diffUrl\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"flags\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isAnonymous\\\", \\\"type\\\": \\\"string\\\"}, {\\\
"name\\\": \\\"isMinor\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"isNew\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isRobot\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"isUnpatrolled\\\",
\\\"type\\\": \\\"string\\\"}, {\\\"name\\\": \\\"metroCode\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"namespace\\\", \\\"type\\\":
\\\"string\\\"}, {\\\"name\\\": \\\"page\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionIsoCode\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"regionName\\\", \\\"type\\\": \\\"string\\\"},
{\\\"name\\\": \\\"timestamp\\\", \\\"type\\\": \\\"string\\\"}, {\\\"name\\\":
\\\"user\\\", \\\"type\\\": \\\"string\\\"}]')) \\\n",
- " PARTITIONED BY DAY\",\n",
- " \"context\": {\n",
- " \"maxNumTasks\": 3\n",
+ "Just as Requests can convert the response from JSON to Python, it can
also convert the request from Python to JSON. The next cell builds up a Python
map that represents the Druid `SqlRequest` object. In this case, we need the
query and a context variable to set the task count to 3."
Review Comment:
```suggestion
"As well as converting the response from JSON to Python, Requests can
also convert the request from Python to JSON. The next cell builds up a Python
map that represents the Druid `SqlRequest` object. In this case, you need the
query and a context variable to set the task count to 3."
```
--
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: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]