{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "rRZ7j28KcY5ZyKWv7dQnxjxF", "metadata": { "id": "rRZ7j28KcY5ZyKWv7dQnxjxF", "tags": [] }, "outputs": [], "source": [ "# Copyright 2025 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", "id": "wOVOgWI290x0", "metadata": { "id": "wOVOgWI290x0" }, "source": [ "# Vector Search and embeddings" ] }, { "cell_type": "markdown", "id": "new_markdown_overview", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "id": "qSLuayS06mCa", "metadata": { "id": "qSLuayS06mCa" }, "source": [ "### The Business Challenge:\n", "For e-commerce platforms, particularly those selling products where images factor into the purchase decision, like appliances, furniture or real estate, the limitations of traditional keyword-based search create significant friction in the customer journey. A user often has a clear visual idea of the product they want but may struggle to describe it with a precise set of keywords (e.g., \"mid-century modern home with a big front lawn\"). This mismatch between visual intent and text-based search can lead to user frustration, poor search results, and ultimately, abandoned shopping carts.\n", "\n", "The business objective is to create a more intuitive and effective product discovery experience that aligns with how users think visually. The technical challenge is to build a system that can accept an image as a search query and return a ranked list of the most visually similar products from a catalog of potentially millions of items. Solving this problem of visual search is critical for improving search relevance, increasing customer engagement, and driving higher conversion rates.\n", "\n" ] }, { "cell_type": "markdown", "id": "K3VvLfqR97x8", "metadata": { "id": "K3VvLfqR97x8" }, "source": [ "### The Data Science Approach:\n", "For this use case, our approach is to implement a large-scale similarity search system using vector embeddings. We will treat the problem of visual similarity as one of proximity in a high-dimensional vector space, building the entire workflow on BigQuery's native multimodal capabilities. We will start by using a remote foundation model, called from a BigQuery ML SQL query, to convert each product image into a high-dimensional vector embedding. To enable fast querying over millions of vectors, we will create a VECTOR INDEX on the embeddings.\n", "\n", "The search functionality is then exposed through the VECTOR_SEARCH function. When a user provides a query image, we will convert it into an embedding and use this function to find the products with the closest embeddings in the indexed catalog, returning a ranked list of visually similar items in real-time.\n" ] }, { "cell_type": "markdown", "id": "new_markdown_setup_1", "metadata": {}, "source": [ "## Setup and Imports" ] }, { "cell_type": "markdown", "id": "new_markdown_setup_2", "metadata": {}, "source": [ "### Install and load required libraries\n", "This cell installs and loads the necessary Python libraries and extensions for interacting with BigQuery." ] }, { "cell_type": "code", "execution_count": null, "id": "a98a2c62", "metadata": {}, "outputs": [], "source": [ "!pip3 install google-cloud-bigquery google-cloud-bigquery-storage tqdm pandas db-dtypes jupyter ipywidgets -q" ] }, { "cell_type": "code", "execution_count": null, "id": "3e048991", "metadata": {}, "outputs": [], "source": [ "%load_ext google.cloud.bigquery" ] }, { "cell_type": "markdown", "id": "new_markdown_setup_3", "metadata": {}, "source": [ "### Define configuration variables\n", "This cell sets up the necessary configuration for the project, including the Google Cloud Project ID, BigQuery Dataset ID, location, and the Google Cloud Storage paths for the image datasets." ] }, { "cell_type": "code", "execution_count": null, "id": "7f94c99c", "metadata": {}, "outputs": [], "source": [ "PROJECT_ID = \"\" # @param {type:\"string\"}\n", "DATASET_ID = \"\" # @param {type:\"string\"}\n", "\n", "if not PROJECT_ID: \n", " PROJECT_ID = input(\"Enter project id\")\n", "if not DATASET_ID: \n", " DATASET_ID = input(\"Enter dataset id\")\n", "\n", "LOCATION = \"US\"\n", "\n", "GCS_IMAGE_DATASET_PATH = \"gs://dataproc-metastore-public-binaries/home_image_search/house_images/*\"\n", "GCS_TEST_IMAGE_DATASET_PATH = \"gs://dataproc-metastore-public-binaries/home_image_search/test_image/*\"" ] }, { "cell_type": "markdown", "id": "new_markdown_setup_4", "metadata": {}, "source": [ "### Create BigQuery Dataset\n", "This section executes a SQL query to create a new BigQuery dataset. The `IF NOT EXISTS` clause ensures that the query doesn't fail if the dataset already exists." ] }, { "cell_type": "code", "execution_count": null, "id": "cb0b2c9b", "metadata": {}, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE SCHEMA IF NOT EXISTS `{PROJECT_ID}.{DATASET_ID}`\n", " OPTIONS (\n", " location = '{LOCATION}');\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "1e7719da", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_model_1", "metadata": {}, "source": [ "### Create a BigQuery ML Model for Embeddings\n", "This SQL statement creates a remote BQML model that connects to the `multimodalembedding@001` Vertex AI endpoint. This model will be used to generate vector embeddings for the images." ] }, { "cell_type": "code", "execution_count": null, "id": "MtL0roXmd3NF", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "MtL0roXmd3NF", "outputId": "87bac002-c0e9-4827-c7a8-ec7a0e2ff426" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE MODEL `{PROJECT_ID}.{DATASET_ID}.home_search`\n", "REMOTE WITH CONNECTION DEFAULT\n", "OPTIONS (ENDPOINT = 'multimodalembedding@001');\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_1", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_ext_table_1", "metadata": {}, "source": [ "### Create an External Table for the Image Dataset\n", "An external table is created in BigQuery to reference the home images stored in Google Cloud Storage. This allows BigQuery to query the images directly without needing to load them into a native table." ] }, { "cell_type": "code", "execution_count": null, "id": "dc3Fmi3Od7Rw", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "dc3Fmi3Od7Rw", "outputId": "79241407-0a49-4166-a2ec-d7eefe351c5e" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE EXTERNAL TABLE `{PROJECT_ID}.{DATASET_ID}.external_images_table`\n", "WITH CONNECTION DEFAULT\n", "OPTIONS(\n", "object_metadata = 'SIMPLE',\n", "uris = ['{GCS_IMAGE_DATASET_PATH}'],\n", "max_staleness = INTERVAL 1 DAY,\n", "metadata_cache_mode = 'AUTOMATIC');\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_2", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_embedding_1", "metadata": {}, "source": [ "### Generate Image Embeddings\n", "Using the `ML.GENERATE_EMBEDDING` function, this query processes each image in the external table, calls the multimodal embedding model, and stores the resulting vector embeddings in a new table called `home_embeddings`." ] }, { "cell_type": "code", "execution_count": null, "id": "VpAIZdoKd-5K", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "VpAIZdoKd-5K", "outputId": "97912921-0bd2-4057-9c8e-b44315d2e8a9" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE TABLE `{PROJECT_ID}.{DATASET_ID}.home_embeddings` AS\n", "SELECT *\n", "FROM ML.GENERATE_EMBEDDING(\n", " MODEL `{PROJECT_ID}.{DATASET_ID}.home_search`,\n", " TABLE `{PROJECT_ID}.{DATASET_ID}.external_images_table`,\n", " STRUCT(TRUE AS flatten_json_output,\n", " 512 AS output_dimensionality)\n", ");\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_3", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_embedding_2", "metadata": {}, "source": [ "### View the Generated Embeddings\n", "This query retrieves and displays the contents of the `home_embeddings` table to verify that the embeddings were generated successfully. Each row contains the original image URI and its corresponding vector embedding." ] }, { "cell_type": "code", "execution_count": null, "id": "foOWRVIdeCiO", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 681 }, "id": "foOWRVIdeCiO", "outputId": "e36dba36-6315-4fdb-82d7-d6af8de0491c" }, "outputs": [], "source": [ "query = f\"\"\"\n", "SELECT * FROM `{PROJECT_ID}.{DATASET_ID}.home_embeddings`;\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_4", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "v0fpfJGYLSdJ", "metadata": { "id": "v0fpfJGYLSdJ" }, "source": [ "## Create Vector Indexes\n", "\n", "(Optional) Use a vector index to enable faster and more scalable semantic search. A vector index efficiently finds the nearest neighbors of a query embedding within a large collection of embeddings using the CREATE VECTOR INDEX statement.\n", "While vector indexes are ideal for large datasets, we are not creating an index in this case because we are only generating embeddings for 80 images.\n", "\n", "Learn more about Vector Indexes on BigQuery [here](https://cloud.google.com/bigquery/docs/vector-index#choose-vector-index-type).\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "xsWrCpgVvhUE", "metadata": { "id": "xsWrCpgVvhUE" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE\n", " VECTOR INDEX `house_images_index`\n", "ON\n", " {DATASET_ID}.home_embeddings(ml_generate_embedding_result)\n", " OPTIONS (\n", " index_type = 'IVF',\n", " distance_type = 'COSINE');\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "f99d5f5a", "metadata": {}, "outputs": [], "source": [ "# %%bigquery --project $PROJECT_ID\n", "# $query" ] }, { "cell_type": "markdown", "id": "new_markdown_index_1", "metadata": {}, "source": [ "### Check Vector Index Status\n", "(Optional) After creating a vector index, you can use this query to check its status. The `INFORMATION_SCHEMA.VECTOR_INDEXES` view provides metadata about the index, including its `index_status` and `coverage_percentage`." ] }, { "cell_type": "code", "execution_count": null, "id": "1811bf63", "metadata": {}, "outputs": [], "source": [ "query = f\"\"\"\n", "SELECT table_name, index_name, index_status,\n", " coverage_percentage, last_refresh_time, disable_reason\n", "FROM {DATASET_ID}.INFORMATION_SCHEMA.VECTOR_INDEXES\n", "WHERE index_name = 'house_images_index';\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "JUnmua-R05QT", "metadata": { "id": "JUnmua-R05QT" }, "outputs": [], "source": [ "# %%bigquery --project $PROJECT_ID\n", "# $query" ] }, { "cell_type": "markdown", "id": "new_markdown_search_1", "metadata": {}, "source": [ "## Perform Image-Based Search\n", "\n", "Now that the image catalog has been processed to generate embeddings, we can perform a visual search. We'll start by providing a new image and finding the most similar images from the catalog." ] }, { "cell_type": "markdown", "id": "new_markdown_search_2", "metadata": {}, "source": [ "### Create an External Table for the Test Image\n", "Similar to the main dataset, an external table is created for the test image stored in Google Cloud Storage. This allows it to be processed by the BQML model." ] }, { "cell_type": "code", "execution_count": null, "id": "f8ttYmOveHZW", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "f8ttYmOveHZW", "outputId": "94d84c21-e4ec-4abe-a850-35f0a438bdbb" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE EXTERNAL TABLE `{PROJECT_ID}.{DATASET_ID}.external_images_test_table`\n", "WITH CONNECTION DEFAULT\n", "OPTIONS(\n", " object_metadata = 'SIMPLE',\n", " uris = ['{GCS_TEST_IMAGE_DATASET_PATH}'],\n", " max_staleness = INTERVAL 1 DAY,\n", " metadata_cache_mode = 'AUTOMATIC');\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_5", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_search_3", "metadata": {}, "source": [ "### Verify the Test Image Table\n", "This query confirms that the external table for the test image has been created correctly and is accessible." ] }, { "cell_type": "code", "execution_count": null, "id": "OUzubOaBzSTT", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 182 }, "id": "OUzubOaBzSTT", "outputId": "2aff4533-80cc-475e-85ca-2b6c8c90033a" }, "outputs": [], "source": [ "query = f\"\"\"\n", "SELECT * FROM `{PROJECT_ID}.{DATASET_ID}.external_images_test_table`;\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_6", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_search_4", "metadata": {}, "source": [ "### Display the Test Image\n", "This Python code downloads the test image from Google Cloud Storage and displays it within the notebook to visualize the search query." ] }, { "cell_type": "code", "execution_count": null, "id": "-dVdlB0hDIxr", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 406 }, "id": "-dVdlB0hDIxr", "outputId": "f84bed22-9b90-4363-f08e-68acb9965b94" }, "outputs": [], "source": [ "from google.cloud import storage\n", "from io import BytesIO\n", "from PIL import Image\n", "\n", "# Initialize a client\n", "storage_client = storage.Client()\n", "\n", "# Specify your bucket and image file name\n", "path_after_protocol = GCS_TEST_IMAGE_DATASET_PATH.split(\"gs://\")[1]\n", "bucket_name = path_after_protocol.split(\"/\", 1)[0]\n", "blob_name = path_after_protocol.split(\"/\", 1)[1][:-1] + \"house_test_image.jpg\"\n", "\n", "# Get the bucket and blob\n", "bucket = storage_client.get_bucket(bucket_name)\n", "blob = bucket.blob(blob_name)\n", "\n", "# Download the image data into a BytesIO object\n", "image_bytes = blob.download_as_bytes()\n", "image_stream = BytesIO(image_bytes)\n", "\n", "# Open the image using PIL (Pillow)\n", "img = Image.open(image_stream)\n", "\n", "# Now 'img' is a PIL Image object, and you can perform operations on it\n", "# For example, to display it (requires matplotlib):\n", "import matplotlib.pyplot as plt\n", "plt.imshow(img)\n", "plt.axis('off')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "new_markdown_search_5", "metadata": {}, "source": [ "### Generate Embedding for the Test Image\n", "The `ML.GENERATE_EMBEDDING` function is used again, this time to generate the vector embedding for the single test image. The result is stored in a new table." ] }, { "cell_type": "code", "execution_count": null, "id": "tKihj5eBeJJE", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "tKihj5eBeJJE", "outputId": "301a733b-95ff-4dbf-ba6e-293f32f8b7a8" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE TABLE `{PROJECT_ID}.{DATASET_ID}.test_embeddings` AS\n", "SELECT *\n", "FROM ML.GENERATE_EMBEDDING(\n", " MODEL `{PROJECT_ID}.{DATASET_ID}.home_search`,\n", " TABLE `{PROJECT_ID}.{DATASET_ID}.external_images_test_table`,\n", " STRUCT(TRUE AS flatten_json_output,\n", " 512 AS output_dimensionality)\n", ");\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_7", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_search_6", "metadata": {}, "source": [ "### Perform the Vector Search\n", "The `VECTOR_SEARCH` function is the core of the image search engine. It takes the test image's embedding as the query and searches the `home_embeddings` table to find the top 10 most similar images based on cosine distance. The `use_brute_force` option is specified here, but for larger datasets, a vector index would be used for performance. The results, containing the GCS URIs of the similar images and their distances, are stored in a new table." ] }, { "cell_type": "code", "execution_count": null, "id": "tEOvpu1neMRA", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "id": "tEOvpu1neMRA", "outputId": "6459b813-7ccc-43df-cb68-173e4b75ee81" }, "outputs": [], "source": [ "query = f\"\"\"\n", "CREATE OR REPLACE TABLE `{PROJECT_ID}.{DATASET_ID}.vector_search_results` AS\n", "SELECT base.uri AS gcs_uri, distance\n", "FROM\n", "VECTOR_SEARCH(\n", " TABLE `{PROJECT_ID}.{DATASET_ID}.home_embeddings`,\n", " 'ml_generate_embedding_result',\n", " (\n", " SELECT * FROM `{PROJECT_ID}.{DATASET_ID}.test_embeddings`\n", " ),\n", " top_k => 10,\n", " distance_type => 'COSINE',\n", " options => '{{\"use_brute_force\":true}}'\n", ");\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_8", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_search_7", "metadata": {}, "source": [ "### Inspect the Search Results Table\n", "This query shows the raw results of the vector search, listing the GCS URIs of the closest matches and their calculated cosine distances to the query image (a smaller distance indicates higher similarity)." ] }, { "cell_type": "code", "execution_count": null, "id": "xK-TQbNXtxgw", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 427 }, "id": "xK-TQbNXtxgw", "outputId": "3930eea2-7adf-4a6c-c00c-61dc0c88aea7" }, "outputs": [], "source": [ "query = f\"\"\"\n", "SELECT * FROM `{PROJECT_ID}.{DATASET_ID}.vector_search_results`;\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "new_cell_9", "metadata": {}, "outputs": [], "source": [ "%%bigquery --project $PROJECT_ID\n", "$query" ] }, { "cell_type": "markdown", "id": "new_markdown_viz_1", "metadata": {}, "source": [ "## Visualize the Search Results\n", "\n", "To better understand the performance of the image search, we will now visualize the results." ] }, { "cell_type": "markdown", "id": "new_markdown_viz_2", "metadata": {}, "source": [ "### Define a Helper Function to Display Images\n", "This Python function, `print_images`, is defined to fetch images from Google Cloud Storage based on their URIs and display them in a grid format within the notebook. It will also show the similarity distance for each image." ] }, { "cell_type": "code", "execution_count": null, "id": "print_images_function", "metadata": {}, "outputs": [], "source": [ "def print_images(query_result):\n", " \"\"\"\n", " Display images from BigQuery results containing GCS URIs and distances.\n", " \n", " Args:\n", " query_result: BigQuery query result with 'gcs_uri' and distance columns\n", " \"\"\"\n", " import matplotlib.pyplot as plt\n", " from google.cloud import storage\n", " from PIL import Image\n", " from io import BytesIO\n", " import math\n", " \n", " # Convert query result to list\n", " results = list(query_result)\n", " \n", " if not results:\n", " print(\"No results found.\")\n", " return\n", " \n", " # Initialize storage client\n", " storage_client = storage.Client()\n", " \n", " # Calculate grid dimensions\n", " num_images = len(results)\n", " cols = min(3, num_images) # Max 3 columns\n", " rows = math.ceil(num_images / cols)\n", " \n", " # Create figure and subplots\n", " fig, axes = plt.subplots(rows, cols, figsize=(15, 5 * rows))\n", " \n", " # Handle single image case\n", " if num_images == 1:\n", " axes = [axes]\n", " elif rows == 1:\n", " axes = [axes] if cols == 1 else axes\n", " else:\n", " axes = axes.flatten()\n", " \n", " for i, row in enumerate(results):\n", " gcs_uri = row.gcs_uri\n", " distance = float(row[\"distance\"])\n", " \n", " try:\n", " # Parse GCS URI\n", " path_after_protocol = gcs_uri.split(\"gs://\")[1]\n", " bucket_name = path_after_protocol.split(\"/\", 1)[0]\n", " blob_name = path_after_protocol.split(\"/\", 1)[1]\n", " \n", " # Download image\n", " bucket = storage_client.get_bucket(bucket_name)\n", " blob = bucket.blob(blob_name)\n", " image_bytes = blob.download_as_bytes()\n", " image_stream = BytesIO(image_bytes)\n", " img = Image.open(image_stream)\n", " \n", " # Display image\n", " ax = axes[i] if num_images > 1 else axes[0]\n", " ax.imshow(img)\n", " ax.set_title(f\"Distance: {distance:.4f}\\n{blob_name}\", fontsize=10)\n", " ax.axis('off')\n", " \n", " except Exception as e:\n", " print(f\"Error loading image {gcs_uri}: {e}\")\n", " ax = axes[i] if num_images > 1 else axes[0]\n", " ax.text(0.5, 0.5, f\"Error loading\\n{gcs_uri}\", \n", " ha='center', va='center', transform=ax.transAxes)\n", " ax.axis('off')\n", " \n", " # Hide unused subplots\n", " for i in range(num_images, len(axes)):\n", " axes[i].axis('off')\n", " \n", " plt.tight_layout()\n", " plt.show()\n", " \n", " # Print summary\n", " print(f\"\\nDisplayed {num_images} similar images, ordered by similarity (lower distance = more similar)\")" ] }, { "cell_type": "markdown", "id": "new_markdown_viz_3", "metadata": {}, "source": [ "### Display the Similar Images\n", "This final code cell executes a query to get the search results, ordered by similarity, and then passes them to the `print_images` helper function to display the top visually similar homes found by the vector search." ] }, { "cell_type": "code", "execution_count": null, "id": "qxUidKkqsPHw", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "id": "qxUidKkqsPHw", "outputId": "325a57e4-ee06-4ad0-92fd-98c24115d53b" }, "outputs": [], "source": [ "from google.cloud import bigquery\n", "client = bigquery.Client()\n", "\n", "query = f\"\"\"\n", " SELECT gcs_uri, CAST(distance AS STRING) as distance FROM `{PROJECT_ID}.{DATASET_ID}.vector_search_results`\n", " ORDER BY distance;\n", "\"\"\"\n", "\n", "print_images(client.query(query))" ] }, { "cell_type": "markdown", "id": "-zUWHNeLydp1", "metadata": { "id": "-zUWHNeLydp1" }, "source": [ "## Conclusion\n", "Learn more about image embeddings in BigQuery [here](https://cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-generate-embedding) and Vector Search on BigQuery [here](https://cloud.google.com/bigquery/docs/vector-search-intro).\n" ] } ], "metadata": { "colab": { "name": "nive_ebook_home_search_use_case", "provenance": [] }, "kernelspec": { "display_name": "myenv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.12" } }, "nbformat": 4, "nbformat_minor": 5 }