{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fsbQpUPpQ4BH"
      },
      "outputs": [],
      "source": [
        "# Copyright 2023 Google LLC\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QHa16b1bQ_np"
      },
      "source": [
        "# Vertex AI Vector Search Quickstart\n",
        "\n",
        "<table align=\"left\">\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://www.gstatic.com/pantheon/images/bigquery/welcome_page/colab-logo.svg\" alt=\"Google Colaboratory logo\"><br> Run in Colab\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://raw.githubusercontent.com/primer/octicons/refs/heads/main/icons/mark-github-24.svg\" alt=\"GitHub logo\"><br> View on GitHub\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/embeddings/vector-search-quickstart.ipynb\">\n",
        "      <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\"><br> Open in Vertex AI Workbench\n",
        "    </a>\n",
        "  </td>\n",
        "</table>\n",
        "\n",
        "<div style=\"clear: both;\"></div>\n",
        "\n",
        "<b>Share to:</b>\n",
        "\n",
        "<a href=\"https://www.linkedin.com/sharing/share-offsite/?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/8/81/LinkedIn_icon.svg\" alt=\"LinkedIn logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://bsky.app/intent/compose?text=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/7/7a/Bluesky_Logo.svg\" alt=\"Bluesky logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://twitter.com/intent/tweet?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/5a/X_icon_2.svg\" alt=\"X logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://reddit.com/submit?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://redditinc.com/hubfs/Reddit%20Inc/Brand/Reddit_Logo.png\" alt=\"Reddit logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg\" alt=\"Facebook logo\">\n",
        "</a>            "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4d742715e6de"
      },
      "source": [
        "| | |\n",
        "|-|-|\n",
        "|Author(s) | [Smitha Venkat](https://github.com/smitha-google), [Kaz Sato](https://github.com/kazunori279), Zachary Layne|"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kQYJ6hXSm0HR"
      },
      "source": [
        "### Prerequisites\n",
        "\n",
        "This tutorial requires a Google Cloud project that is linked with a billing account. To create a new project, take a look at [this document](https://cloud.google.com/vertex-ai/docs/start/cloud-environment) to create a project and setup a billing account for it.",
        "\n",
        "To get the permissions that you need to give a service account access to enable APIs and interact with Vertex AI resources, ask your administrator to grant you the [Security Admin](https://cloud.google.com/iam/docs/roles-permissions/iam#iam.securityAdmin) (`roles/iam.securityAdmin`) IAM role on your project. For more information about granting roles, see [Manage access to projects, folders, and organizations](https://cloud.google.com/iam/docs/granting-changing-revoking-access)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tC4i08xh5lQw"
      },
      "source": [
        "### Choose the runtime environment\n",
        "\n",
        "This tutorial can be run on either Google Colab or [Vertex AI Workbench](https://cloud.google.com/vertex-ai-workbench).\n",
        "\n",
        "- To use Colab: Click [this link](https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/embeddings/vector-search-quickstart.ipynb) to open the tutorial in Colab.\n",
        "\n",
        "- To use Workbench: If it is the first time to use Workbench in your Google Cloud project, open [the Workbench console](https://console.cloud.google.com/vertex-ai/workbench) and click ENABLE button to enable Notebooks API. The click [this link](https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/embeddings/vector-search-quickstart.ipynb),  and select an existing notebook or create a new notebook.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JVwslLQxnAdK"
      },
      "source": [
        "### How much will this cost?\n",
        "\n",
        "To go through this tutorial, it will cost roughly a few US dollars. The pricing of the Cloud services we will use in this tutorial are available in the following pages:\n",
        "\n",
        "- [Vertex AI Embeddings for Text](https://cloud.google.com/vertex-ai/pricing#generative_ai_models)\n",
        "- [Vertex AI Vector Search](https://cloud.google.com/vertex-ai/pricing#matchingengine)\n",
        "- [Vertex AI Workbench](https://cloud.google.com/vertex-ai/pricing#notebooks) if you use one\n",
        "\n",
        "You can use the [Pricing Calculator](https://cloud.google.com/products/calculator) to generate a cost estimate based on your projected usage.\n",
        "\n",
        "### **Warning: delete your objects after the tutorial**\n",
        "\n",
        "In case you are using your own Cloud project, please make sure to delete all the Indexes and Index Endpoints (and the Workbench instance if you use one) after finishing this tutorial. Otherwise the remaining assets would incur unexpected costs.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "k9uyNwTISc9u"
      },
      "source": [
        "## Setup\n",
        "\n",
        "Before get started with the Vertex AI services, we need to setup the following.\n",
        "\n",
        "* Install Python SDK\n",
        "* Environment variables\n",
        "* Authentication (Colab only)\n",
        "* Enable APIs\n",
        "* Set IAM permissions"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "u8eMxpb6-0n4"
      },
      "source": [
        "### Install the Vertex AI SDK\n",
        "\n",
        "Vertex AI APIs can be accessed with multiple ways including REST API and Python SDK. In this tutorial we will use the SDK."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7hUF_94TRTPb"
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade --quiet --user google-cloud-aiplatform"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "R5Xep4W9lq-Z"
      },
      "source": [
        "### Restart current runtime\n",
        "\n",
        "To use the newly installed packages in this Jupyter runtime, you must restart the runtime. You can do this by running the cell below, which will restart the current kernel.\n",
        "\n",
        "For Colab users: you will see \"Your session crushed\" message when restarting the kernel, but it is expected. Continue to the following cells."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XRvKdaPDTznN"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'status': 'ok', 'restart': True}"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Restart kernel after installs so that your environment can access the new packages\n",
        "import IPython\n",
        "\n",
        "app = IPython.Application.instance()\n",
        "app.kernel.do_shutdown(True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SbmM4z7FOBpM"
      },
      "source": [
        "<div class=\"alert alert-block alert-warning\">\n",
        "<b>⚠️ The kernel is going to restart. In Colab or Colab Enterprise, you might see an error message that says \"Your session crashed for an unknown reason.\" This is expected. Please wait until it is finished before continuing to the next step. ⚠️</b>\n",
        "</div>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QnKVMQ7coUGQ"
      },
      "source": [
        "### Environment variables\n",
        "\n",
        "Sets environment variables. If asked, replace the following `[your-project-id]` with your project ID and run it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HPfsNnW1e5mm"
      },
      "outputs": [],
      "source": [
        "# get project ID\n",
        "PROJECT_ID = ! gcloud config get project\n",
        "PROJECT_ID = PROJECT_ID[0]\n",
        "LOCATION = \"us-central1\"\n",
        "if PROJECT_ID == \"(unset)\":\n",
        "    print(f\"Please set the project ID manually below\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2C0lUcDGoW_x"
      },
      "outputs": [],
      "source": [
        "# define project information\n",
        "if PROJECT_ID == \"(unset)\":\n",
        "    PROJECT_ID = \"[your-project-id]\"  # @param {type:\"string\"}\n",
        "\n",
        "# generate an unique id for this session\n",
        "from datetime import datetime\n",
        "\n",
        "UID = datetime.now().strftime(\"%m%d%H%M\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bLEgrr3ORwJH"
      },
      "source": [
        "### Authentication (Colab only)\n",
        "\n",
        "If you are running this notebook on Colab, you will need to run the following cell authentication. This step is not required if you are using Vertex AI Workbench as it is pre-authenticated."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "p9iGiaF7RgZs"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "WARNING: google.colab.auth.authenticate_user() is not supported in Colab Enterprise.\n"
          ]
        }
      ],
      "source": [
        "import sys\n",
        "\n",
        "# if it's Colab runtime, authenticate the user with Google Cloud\n",
        "if \"google.colab\" in sys.modules:\n",
        "    from google.colab import auth\n",
        "\n",
        "    auth.authenticate_user()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HPd9NaBxn7ho"
      },
      "source": [
        "### Set IAM permissions\n",
        "\n",
        "Also, we need to add access permissions to the default service account for using those services.\n",
        "\n",
        "- Go to [the IAM page](https://console.cloud.google.com/iam-admin/) in the Console\n",
        "- Look for the principal for default compute service account. It should look like: `<project-number>-compute@developer.gserviceaccount.com`\n",
        "- Click the edit button at right and click `ADD ANOTHER ROLE` to add `Vertex AI User` and `Service Usage Admin` roles to the account.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8hIbkmLEn2Z_"
      },
      "source": [
        "### Enable APIs\n",
        "\n",
        "Run the following to enable APIs for Compute Engine and Vertex AI with this Google Cloud project."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tTga7JZen3bk"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Operation \"operations/acat.p2-761793285222-effb80de-d42f-4a2f-9e81-0e997d5b8f19\" finished successfully.\n"
          ]
        }
      ],
      "source": [
        "! gcloud services enable compute.googleapis.com aiplatform.googleapis.com --project \"{PROJECT_ID}\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z-c1kR7nSO80"
      },
      "source": [
        "## Prepare the sample data\n",
        "\n",
        "In this tutorial, we will use [TheLook dataset](https://console.cloud.google.com/marketplace/product/bigquery-public-data/thelook-ecommerce) that has a [products](bigquery-public-data.thelook_ecommerce.products) table with about 30,000 rows of synthetic product data for a fictious e-commerce clothing site.\n",
        "\n",
        "![](https://storage.googleapis.com/github-repo/img/embeddings/vs-quickstart/products-table.png)\n",
        "\n",
        "From this table, we have prepared the `product-embs.json` file.\n",
        "\n",
        "![](https://storage.googleapis.com/github-repo/img/embeddings/vs-quickstart/product-embs-json.png)\n",
        "\n",
        "This file is in JSONL format and each row has `id` for the product id, `name` for the product name, and `embedding` for the embedding of the product name in 768 dimensions which was generated previously with [Vertex AI Embeddings for Text](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings).\n",
        "\n",
        "The text embeddings represent the meaning of the clothing product names. In this tutorial, we will use Vector Search for completing a [semantic search](https://en.wikipedia.org/wiki/Semantic_search) of the items. This sample code can be used as a basis for other simple recommendation system where you can quickly find \"other products similar to this one\".\n",
        "\n",
        "To learn more about how to create the embeddings from the data on a BigQuery table and store them in a JSON file, see [Getting Started with Text Embeddings + Vertex AI Vector Search](https://github.com/GoogleCloudPlatform/generative-ai/blob/main/embeddings/intro-textemb-vectorsearch.ipynb)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xSGFr7oaowIm"
      },
      "source": [
        "### Download the data\n",
        "\n",
        "For building an index with Vector Search, download the JSONL file."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yemCClOvpXFY"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Copying gs://github-repo/data/vs-quickstart/product-embs.json...\n",
            "\\\n",
            "Operation completed over 1 objects/79.3 MiB.                                     \n"
          ]
        }
      ],
      "source": [
        "! gcloud storage cp \"gs://github-repo/data/vs-quickstart/product-embs.json\" ."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ysMTx4aoZVeX"
      },
      "source": [
        "## Build and Deploy a Vector Search Index\n",
        "\n",
        "### Create Index\n",
        "\n",
        "Now it's ready to load the embeddings to Vector Search. Its APIs are available under the [aiplatform](https://cloud.google.com/python/docs/reference/aiplatform/latest/google.cloud.aiplatform) package of the SDK."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ouj2eqq_p8KA"
      },
      "outputs": [],
      "source": [
        "# init the aiplatform package\n",
        "from google.cloud import aiplatform\n",
        "\n",
        "aiplatform.init(project=PROJECT_ID, location=LOCATION)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ntsHYfR2p_IP"
      },
      "source": [
        "Create an [MatchingEngineIndex](https://cloud.google.com/python/docs/reference/aiplatform/latest/google.cloud.aiplatform.MatchingEngineIndex) with its `create_tree_ah_index` function (Matching Engine is the previous name of Vector Search)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AwEsPjL5yxPK"
      },
      "outputs": [],
      "source": [
        "# create Index\n",
        "INDEX_NAME = f\"vs-quickstart-index-{UID}\"\n",
        "\n",
        "my_index = aiplatform.MatchingEngineIndex.create_tree_ah_index(\n",
        "    display_name=INDEX_NAME,\n",
        "    dimensions=768,\n",
        "    approximate_neighbors_count=10,\n",
        "    index_update_method=\"STREAM_UPDATE\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hSYZLtUWqUke"
      },
      "source": [
        "By calling the `create_tree_ah_index` function, it starts building an Index.  This will take a few minutes if the dataset is small, otherwise about 60 minutes or more depending on the size of the dataset. You can check status of the index creation on [the Vector Search Console > INDEXES tab](https://console.cloud.google.com/vertex-ai/matching-engine/indexes).\n",
        "\n",
        "#### The parameters for creating index\n",
        "\n",
        "- `dimensions`: Dimension size of each embedding. In this case, it is 768 as we are using the embeddings from the Text Embeddings API.\n",
        "- `approximate_neighbors_count`: how many similar items we want to retrieve in typical cases\n",
        "- `index_update_method`: `STREAM_UPDATE` allows real time update to the index.\n",
        "\n",
        "See [the document](https://cloud.google.com/vertex-ai/docs/vector-search/create-manage-index) for more details on creating Index and the parameters."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hVhqRmHAZ98X"
      },
      "source": [
        "### Create Index Endpoint and deploy the Index\n",
        "\n",
        "To use the Index, you need to create an [Index Endpoint](https://cloud.google.com/vertex-ai/docs/vector-search/deploy-index-public). It works as a server instance accepting query requests for your Index."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0yLJT925Z_xq"
      },
      "outputs": [],
      "source": [
        "# create IndexEndpoint\n",
        "my_index_endpoint = aiplatform.MatchingEngineIndexEndpoint.create(\n",
        "    display_name=f\"vs-quickstart-index-endpoint-{UID}\", public_endpoint_enabled=True\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fcfe1a2560f4"
      },
      "source": [
        "This tutorial utilizes a [Public Endpoint](https://cloud.google.com/vertex-ai/docs/vector-search/setup/setup#choose-endpoint) and does not support [Virtual Private Cloud (VPC)](https://cloud.google.com/vpc/docs/private-services-access). Unless you have a specific requirement for VPC, we recommend using a Public Endpoint. Despite the term \"public\" in its name, it does not imply open access to the public internet. Rather, it functions like other endpoints in Vertex AI services, which are secured by default through IAM. Without explicit IAM permissions, as we have previously established, no one can access the endpoint."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xvuoav-wqwZr"
      },
      "source": [
        "With the Index Endpoint, deploy the Index by specifying an unique deployed index ID."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KVzk-ax_q3AL"
      },
      "outputs": [],
      "source": [
        "DEPLOYED_INDEX_ID = f\"vs_quickstart_deployed_{UID}\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d7d67d3d2c5c"
      },
      "source": [
        "**Note:** There is a difference between INDEX_NAME and DEPLOYED_INDEX_ID. The first one may include dashes (-), while the second one only allows underscores (_)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xsVbHllsAZtr"
      },
      "outputs": [],
      "source": [
        "# deploy the Index to the Index Endpoint\n",
        "my_index_endpoint.deploy_index(index=my_index, deployed_index_id=DEPLOYED_INDEX_ID)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBg5sPRYrJzS"
      },
      "source": [
        "If it is the first time to deploy an Index to an Index Endpoint, it will take around 30 minutes to automatically build and initiate the backend for it. After the first deployment, it will finish in seconds. To see the status of the index deployment, open [the Vector Search Console > INDEX ENDPOINTS tab](https://console.cloud.google.com/vertex-ai/matching-engine/index-endpoints) and click the Index Endpoint."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZVi5utDUdmfn"
      },
      "source": [
        "## Streaming update to the vector search index\n",
        "\n",
        "At this time, the vector search index still empty. The following code will insert the product embeddings from the JSONL file by using `upsert_datapoints` method."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rhYw_jr2eWQJ"
      },
      "outputs": [],
      "source": [
        "import json\n",
        "\n",
        "# read product-embs.json and put them to a list\n",
        "with open(\"product-embs.json\") as f:\n",
        "    datapoints = []\n",
        "    for line in f:\n",
        "        item = json.loads(line)\n",
        "        datapoints.append(\n",
        "            {\"datapoint_id\": str(item[\"id\"]), \"feature_vector\": item[\"embedding\"]}\n",
        "        )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ejQx3oo2k1Cp"
      },
      "outputs": [],
      "source": [
        "# insert datapoints to the index\n",
        "for i in range(0, len(datapoints), 1000):\n",
        "    my_index.upsert_datapoints(datapoints=datapoints[i : i + 1000])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8gYMOgnWfYOu"
      },
      "source": [
        "The `upsert_datapoints()` method takes a list of dicts where each dict should have two properties: `datapoint_id` for ID of the item, and `feature_vector` for embeddings of the item. The method can take up to 1000 items at a time.\n",
        "\n",
        "The `upsert_datapoints()` method adds the items in the list to the vector search index in near real-time. As long as you are adding a few items at a time, it should be reflected to the query results in a couple of seconds. So this is suitable for use cases such as product catalogs where the sellers want to add or update many items every day and want the search system to reflect it instantly.\n",
        "\n",
        "See [the document](https://cloud.google.com/vertex-ai/docs/vector-search/update-rebuild-index#upsert-streaming) for more details on streaming update."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z2feyXkRaovq"
      },
      "source": [
        "## Run a Query with Vector Search\n",
        "\n",
        "Finally it's ready to use Vector Search. To run a query, you need to get an embedding for a query item. For example, if you like to find products with similar names to \"cloudveil women's excursion short\", you need to get the embedding for it before running a query. In this tutorial, we will get the embedding from the `product-embs.json` file as follows:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "poGM2hWrn3Rt"
      },
      "outputs": [],
      "source": [
        "# read product-embs.json and build dicts of product names and embeddings\n",
        "with open(\"product-embs.json\") as f:\n",
        "    product_names = {}\n",
        "    product_embs = {}\n",
        "    for line in f:\n",
        "        item = json.loads(line)\n",
        "        product_names[str(item[\"id\"])] = item[\"name\"]\n",
        "        product_embs[str(item[\"id\"])] = item[\"embedding\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "e31HB8_tr0II"
      },
      "source": [
        "With the `product_embs` dict, you can specify a product ID to get an embedding for it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yusFJLd954nH"
      },
      "outputs": [],
      "source": [
        "# get the embedding for ID 6523 \"cloudveil women's excursion short\"\n",
        "# you can also try with other IDs such as 12711, 18090, 19536 and 11863\n",
        "query_emb = product_embs[\"6523\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iBoEWB3TAsJp"
      },
      "source": [
        "### Run a Query\n",
        "\n",
        "Then, pass the embedding to `find_neighbors` function to find similar product names."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bUnjsDkWbMAa"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1.00 cloudveil women's excursion short\n",
            "0.82 quiksilver womens cruiser short\n",
            "0.80 xcvi women's alisal short\n",
            "0.80 cloudveil men's kahuna short\n",
            "0.78 ibex women's gozo short\n",
            "0.78 sanctuary clothing women's coquette short\n",
            "0.78 sunner women's collins printed short\n",
            "0.77 hurley lowrider cargo 2.5 short - women's\n",
            "0.77 stitch's women's fox knee length short\n",
            "0.77 sanctuary clothing women's passenger skirt\n"
          ]
        }
      ],
      "source": [
        "# run query\n",
        "response = my_index_endpoint.find_neighbors(\n",
        "    deployed_index_id=DEPLOYED_INDEX_ID, queries=[query_emb], num_neighbors=10\n",
        ")\n",
        "\n",
        "# show the results\n",
        "for idx, neighbor in enumerate(response[0]):\n",
        "    print(f\"{neighbor.distance:.2f} {product_names[neighbor.id]}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o_sXlLpysUtf"
      },
      "source": [
        "The `find_neighbors` function only takes milliseconds to fetch the similar items even when you have billions of items on the Index, thanks to the ScaNN algorithm. Vector Search also supports [autoscaling](https://cloud.google.com/vertex-ai/docs/vector-search/deploy-index-public#autoscaling) which can automatically resize the number of nodes based on the demands of your workloads."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gDmv_HkObedQ"
      },
      "source": [
        "# IMPORTANT: Cleaning Up\n",
        "\n",
        "In case you are using your own Cloud project, not a temporary project on Qwiklab, please make sure to delete all the Indexes and Index Endpoints after finishing this tutorial. Otherwise the remaining objects would **incur unexpected costs**.\n",
        "\n",
        "If you used Workbench, you may also need to delete the Notebooks from [the console](https://console.cloud.google.com/vertex-ai/workbench)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QhInCv3sscAH"
      },
      "outputs": [],
      "source": [
        "# wait for a confirmation\n",
        "input(\"Press Enter to delete Index Endpoint and Index:\")\n",
        "\n",
        "# delete Index Endpoint\n",
        "my_index_endpoint.undeploy_all()\n",
        "my_index_endpoint.delete(force=True)\n",
        "\n",
        "# delete Index\n",
        "my_index.delete()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F9OG7QbCmqqx"
      },
      "source": [
        "## Utilities\n",
        "\n",
        "It can take some time to create or deploy indexes, and in that time you might lose connection with the Colab runtime. If you lose connection, instead of creating or deploying your new index again, you can check [the Vector Search Console](https://console.cloud.google.com/vertex-ai/matching-engine/index-endpoints) and use the existing ones to continue.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "n8yeRRZrmyn1"
      },
      "source": [
        "### Get an existing Index\n",
        "\n",
        "To get an index object that already exists, replace the following `[numeric-index-id]` with the index ID and run the cell. You can check the ID on [the Vector Search Console > INDEXES tab](https://console.cloud.google.com/vertex-ai/matching-engine/indexes)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cvdaNEw4mw2c"
      },
      "outputs": [],
      "source": [
        "my_index_id = \"[numeric-index-id]\"  # @param {type:\"string\"}\n",
        "my_index = aiplatform.MatchingEngineIndex(my_index_id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "87N_WmeDnPaX"
      },
      "source": [
        "### Get an existing Index Endpoint\n",
        "\n",
        "To get an index endpoint object that already exists, replace the following `[numeric-index-endpoint-id]` with the index endpoint ID and run the cell. You can check the ID on [the Vector Search Console > INDEX ENDPOINTS tab](https://console.cloud.google.com/vertex-ai/matching-engine/index-endpoints)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YDz9ir72o44x"
      },
      "outputs": [],
      "source": [
        "my_index_endpoint_id = \"[numeric-index-endpoint-id]\"  # @param {type:\"string\"}\n",
        "my_index_endpoint = aiplatform.MatchingEngineIndexEndpoint(my_index_endpoint_id)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "vector-search-quickstart.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
