עבודה עם פונקציות בהגדרת המשתמש (UDF) ב-Python

פונקציה בהגדרת המשתמש (UDF) ב-Python מאפשרת להטמיע פונקציה סקלרית ב-Python ולהשתמש בה בשאילתת SQL. פונקציות UDF ב-Python דומות לפונקציות UDF ב-SQL וב-JavaScript, אבל יש להן יכולות נוספות. פונקציות UDF ב-Python מאפשרות להתקין ספריות של צד שלישי מ-Python Package Index‏ (PyPI) ולגשת לשירותים חיצוניים באמצעות חיבור למשאבים ב-Cloud.

פונקציות UDF ב-Python נוצרות ומופעלות במשאבים שמנוהלים ב-BigQuery.

מגבלות

  • ‫python-3.11 היא סביבת זמן הריצה היחידה שנתמכת.
  • אי אפשר ליצור פונקציית Python זמנית בהגדרת המשתמש.
  • אי אפשר להשתמש בפונקציית UDF ב-Python עם תצוגה מהותית.
  • התוצאות של שאילתה שקוראת לפונקציית Python UDF לא נשמרות במטמון, כי ערך ההחזרה של פונקציית Python UDF תמיד נחשב ללא דטרמיניסטי.
  • אין תמיכה ב-Assured Workloads.
  • סוגי הנתונים הבאים לא נתמכים: JSON,‏ RANGE,‏ INTERVAL ו-GEOGRAPHY.
  • אפשר להגדיר קונטיינרים שמריצים פונקציות UDF ב-Python רק עד ‎4 vCpu ו-‎16GiB.
  • אי אפשר להצפין קוד של פונקציות Python מוגדרות-משתמש באמצעות מפתחות הצפנה בניהול הלקוח (CMEK).
  • פונקציות UDF ב-Python תומכות ב-VPC Service Controls, אבל לא ברשתות VPC.

התפקידים הנדרשים

התפקידים הנדרשים ב-IAM מבוססים על השאלה אם אתם הבעלים של פונקציית ה-UDF ב-Python או המשתמשים בה.

בעלי UDF

בדרך כלל, הבעלים של פונקציית Python מוגדרת-משתמש יוצר או מעדכן את הפונקציה. אם אתם יוצרים פונקציית UDF ב-Python שמפנה לקישור למשאבים ב-Cloud, תצטרכו גם תפקידים נוספים. החיבור הזה נדרש רק אם ה-UDF שלך משתמש בפסוקית WITH CONNECTION כדי לגשת לשירות חיצוני.

כדי לקבל את ההרשאות שדרושות ליצירה או לעדכון של פונקציית Python מוגדרת-משתמש, בקשו מהאדמין להקצות לכם את התפקידים הבאים ב-IAM:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

התפקידים המוגדרים מראש האלה כוללים את ההרשאות שנדרשות כדי ליצור או לעדכן פונקציה מוגדרת-משתמש ב-Python. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי ליצור או לעדכן פונקציית Python UDF, נדרשות ההרשאות הבאות:

  • יוצרים פונקציית Python מוגדרת-משתמש באמצעות ההצהרה CREATE FUNCTION: bigquery.routines.create במערך הנתונים
  • מעדכנים פונקציית Python מוגדרת-משתמש באמצעות ההצהרה CREATE FUNCTION: bigquery.routines.update במערך הנתונים
  • הרצת משימת שאילתה של הצהרת CREATE FUNCTION: bigquery.jobs.create בפרויקט
  • יוצרים קישור חדש למשאבים ב-Cloud: ‫bigquery.connections.create בפרויקט
  • משתמשים בחיבור בהצהרה CREATE FUNCTION: bigquery.connections.delegate בחיבור

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

למידע נוסף על תפקידים ב-BigQuery, קראו את המאמר תפקידי IAM מוגדרים מראש.

משתמשי UDF

משתמש של פונקציית UDF ב-Python מפעיל פונקציית UDF שנוצרה על ידי מישהו אחר. אם אתם מפעילים פונקציה מוגדרת-משתמש ב-Python שמפנה לקישור למשאבים ב-Cloud, תצטרכו גם תפקידים נוספים.

כדי לקבל את ההרשאות שנדרשות להפעלת פונקציה מוגדרת-משתמש ב-Python שנוצרה על ידי מישהו אחר, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

התפקידים המוגדרים מראש האלה מכילים את ההרשאות שנדרשות כדי להפעיל UDF ב-Python שנוצרה על ידי מישהו אחר. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי להפעיל פונקציה מוגדרת-משתמש ב-Python שנוצרה על ידי מישהו אחר, נדרשות ההרשאות הבאות:

  • כדי להריץ משימת שאילתה שמפנה לפונקציה מוגדרת-משתמש ב-Python: ‫bigquery.jobs.create בפרויקט
  • כדי להפעיל פונקציית Python UDF שנוצרה על ידי מישהו אחר: ‫bigquery.routines.get במערך הנתונים
  • כדי להריץ פונקציית Python UDF שמפנה לקישור למשאבים ב-Cloud: bigquery.connections.use בקישור

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

למידע נוסף על תפקידים ב-BigQuery, קראו את המאמר תפקידי IAM מוגדרים מראש.

יצירת UDF מתמידה ב-Python

כשיוצרים פונקציית Python UDF, צריך לפעול לפי הכללים הבאים:

  • גוף הפונקציה של Python UDF חייב להיות מחרוזת מילולית במירכאות שמייצגת את קוד Python. מידע נוסף על מחרוזות מילוליות במירכאות מופיע בקטע פורמטים של מחרוזות מילוליות במירכאות.

  • גוף הפונקציה של Python UDF חייב לכלול פונקציית Python שמשמשת בארגומנט entry_point ברשימת האפשרויות של Python UDF.

  • צריך לציין גרסה של סביבת זמן ריצה של Python באפשרות runtime_version. גרסת סביבת זמן הריצה היחידה של Python שנתמכת היא python-3.11. רשימה מלאה של האפשרויות הזמינות מופיעה ברשימת האפשרויות של הפונקציה להצהרה CREATE FUNCTION.

כדי ליצור פונקציית UDF מתמידה ב-Python, משתמשים בהצהרה CREATE FUNCTION בלי מילת המפתח TEMP או TEMPORARY. כדי למחוק פונקציית Python UDF מתמידה, משתמשים בהצהרה DROP FUNCTION.

דוגמה

כדי לראות דוגמה ליצירת פונקציית UDF קבועה ב-Python, בחרו באחת מהאפשרויות הבאות:

המסוף

בדוגמה הבאה נוצרת פונקציית Python מתמידה בשם multiplyInputs, והיא נקראת מתוך הצהרת SELECT:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyInputs(x FLOAT64, y FLOAT64)
    RETURNS FLOAT64
    LANGUAGE python
    OPTIONS(runtime_version="python-3.11", entry_point="multiply")
    AS r'''
    
    def multiply(x, y):
        return x * y
    
    ''';
    
    -- Call the Python UDF.
    WITH numbers AS
        (SELECT 1 AS x, 5 as y
        UNION ALL
        SELECT 2 AS x, 10 as y
        UNION ALL
        SELECT 3 as x, 15 as y)
    SELECT x, y,
    `PROJECT_ID.DATASET_ID`.multiplyInputs(x, y) AS product
    FROM numbers;

    מחליפים את PROJECT_ID.‫DATASET_ID במזהה הפרויקט ובמזהה של מערך הנתונים.

  3. לוחצים על  הפעלה.

    הפלט של הדוגמה הזו:

    +-----+-----+--------------+
    | x   | y   | product      |
    +-----+-----+--------------+
    | 1   | 5   |  5.0         |
    | 2   | 10  | 20.0         |
    | 3   | 15  | 45.0         |
    +-----+-----+--------------+
    

BigQuery DataFrames

בדוגמה הבאה, משתמשים ב-BigQuery DataFrames כדי להפוך פונקציה מותאמת אישית לפונקציה מוגדרת-משתמש ב-Python:

import bigframes.pandas as bpd

# Set BigQuery DataFrames options
bpd.options.bigquery.project = your_gcp_project_id
bpd.options.bigquery.location = "US"

# BigQuery DataFrames gives you the ability to turn your custom functions
# into a BigQuery Python UDF. One can find more details about the usage and
# the requirements via `help` command.
help(bpd.udf)

# Read a table and inspect the column of interest.
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")
df["body_mass_g"].peek(10)

# Define a custom function, and specify the intent to turn it into a
# BigQuery Python UDF. Let's try a `pandas`-like use case in which we want
# to apply a user defined function to every value in a `Series`, more
# specifically bucketize the `body_mass_g` value of the penguins, which is a
# real number, into a category, which is a string.
@bpd.udf(
    dataset=your_bq_dataset_id,
    name=your_bq_routine_id,
)
def get_bucket(num: float) -> str:
    if not num:
        return "NA"
    boundary = 4000
    return "at_or_above_4000" if num >= boundary else "below_4000"

# Then we can apply the udf on the `Series` of interest via
# `apply` API and store the result in a new column in the DataFrame.
df = df.assign(body_mass_bucket=df["body_mass_g"].apply(get_bucket))

# This will add a new column `body_mass_bucket` in the DataFrame. You can
# preview the original value and the bucketized value side by side.
df[["body_mass_g", "body_mass_bucket"]].peek(10)

# The above operation was possible by doing all the computation on the
# cloud through an underlying BigQuery Python UDF that was created to
# support the user's operations in the Python code.

# The BigQuery Python UDF created to support the BigQuery DataFrames
# udf can be located via a property `bigframes_bigquery_function`
# set in the udf object.
print(f"Created BQ Python UDF: {get_bucket.bigframes_bigquery_function}")

# If you have already defined a custom function in BigQuery, either via the
# BigQuery Google Cloud Console or with the `udf` decorator,
# or otherwise, you may use it with BigQuery DataFrames with the
# `read_gbq_function` method. More details are available via the `help`
# command.
help(bpd.read_gbq_function)

existing_get_bucket_bq_udf = get_bucket.bigframes_bigquery_function

# Here is an example of using `read_gbq_function` to load an existing
# BigQuery Python UDF.
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")
get_bucket_function = bpd.read_gbq_function(existing_get_bucket_bq_udf)

df = df.assign(body_mass_bucket=df["body_mass_g"].apply(get_bucket_function))
df.peek(10)

# Let's continue trying other potential use cases of udf. Let's say we
# consider the `species`, `island` and `sex` of the penguins sensitive
# information and want to redact that by replacing with their hash code
# instead. Let's define another scalar custom function and decorate it
# as a udf. The custom function in this example has external package
# dependency, which can be specified via `packages` parameter.
@bpd.udf(
    dataset=your_bq_dataset_id,
    name=your_bq_routine_id,
    packages=["cryptography"],
)
def get_hash(input: str) -> str:
    from cryptography.fernet import Fernet

    # handle missing value
    if input is None:
        input = ""

    key = Fernet.generate_key()
    f = Fernet(key)
    return f.encrypt(input.encode()).decode()

# We can use this udf in another `pandas`-like API `map` that
# can be applied on a DataFrame
df_redacted = df[["species", "island", "sex"]].map(get_hash)
df_redacted.peek(10)

# If the BigQuery routine is no longer needed, we can clean it up
# to free up any cloud quota
session = bpd.get_global_session()
session.bqclient.delete_routine(f"{your_bq_dataset_id}.{your_bq_routine_id}")

סטטוס ה-build של הקונטיינר

כשיוצרים פונקציית Python מוגדרת-משתמש באמצעות ההצהרה CREATE FUNCTION, ‏BigQuery יוצר או מעדכן קובץ אימג' של קונטיינר שמבוסס על קובץ אימג' בסיסי. הקונטיינר נוצר על קובץ האימג' הבסיסי באמצעות הקוד שלכם וכל יחסי התלות שצוינו בחבילה.

יצירת הקונטיינר היא תהליך ארוך. השאילתה הראשונה אחרי שמריצים את ההצהרה CREATE FUNCTION ממתינה עד שה-build של קובץ האימג' מסתיים. אם אין יחסי תלות חיצוניים, קובץ האימג' של הקונטיינר נוצר בדרך כלל תוך פחות מדקה.

הגודל של כל מאגרי ה-Python UDF לכל פרויקט ולכל אזור מוגבל לסכום כולל של 10GiB. מידע נוסף זמין במאמר מגבלות על פונקציות מתמידות בהגדרת המשתמש. אם הפרויקט הגיע למכסה, ה-build של הקונטיינר ייכשל.

כדי לראות את הסטטוס של גרסת ה-build של הקונטיינר, בוחרים באחת מהאפשרויות הבאות:

המסוף

  1. נכנסים לדף Studio ב-BigQuery.

    אל Studio

  2. בחלונית הימנית, מרחיבים את הפרויקט ולוחצים על Datasets.

  3. לוחצים על הקישור כדי לפתוח את קבוצת הנתונים שמכילה את ה-UDF ב-Python.

  4. בדף של מערך הנתונים, לוחצים על הכרטיסייה Routines.

  5. בעמודה Routine ID, לוחצים על ה-UDF ב-Python.

  6. בדף Persistent function info אפשר לראות את סטטוס ה-build, משך ה-build וגודל קובץ האימג'. סטטוס ה-build הוא אחד מהבאים:

    • בתהליך
    • הושלמה
    • נכשל

    אם ה-build נכשל, בדף המידע של הפונקציה מופיעות הודעות שגיאה מפורטות, כדי שתוכלו לפתור בעיות כמו שגיאות תחביר או בעיות בהתקנת חבילות חיצוניות.

    הדף Persistent function info במסוף.

SQL

כדי לשלוח שאילתה לשדות של סטטוס ה-build בתצוגה INFORMATION_SCHEMA.ROUTINES, מבצעים את הפעולות הבאות:

  1. נכנסים לדף Studio ב-BigQuery.

    אל Studio

  2. עוברים לעורך השאילתות או לוחצים על שאילתת SQL.

  3. מזינים את השאילתה הבאה כדי לאחזר את השדות של BUILD_STATUS מתצוגת INFORMATION_SCHEMA.ROUTINES. העמודה BUILD_STATUS היא מסוג STRUCT ב-GoogleSQL:

    SELECT
      build_status.*
    FROM
      `PROJECT_ID.DATASET_ID`.INFORMATION_SCHEMA.ROUTINES;
    

    מחליפים את PROJECT_ID.‫DATASET_ID במזהה הפרויקט ובמזהה של מערך הנתונים.

    הפלט אמור להיראות כך: שדות השגיאה מושמטים:

    +---------------+--------------------------------+------------------------+------------------+
    | build_state   | build_state_update_time        | build_duration_seconds | image_size_bytes |
    +---------------+--------------------------------+------------------------+------------------+
    | SUCCEEDED     | 2026-05-14 17:21:49.736000 UTC |                     11 |             3167 |
    +---------------+--------------------------------+------------------------+------------------+
    

API

כדי לראות את סטטוס ה-build של הקונטיינר, משתמשים ב-RoutineBuildStatus ב-API.

יצירת פונקציה וקטורית מוגדרת-משתמש ב-Python

אתם יכולים להטמיע את פונקציית ה-UDF ב-Python כדי לעבד קבוצה של שורות במקום שורה אחת, באמצעות וקטוריזציה. וקטוריזציה יכולה לשפר את ביצועי השאילתות. אפשר ליצור פונקציית UDF וקטורית באמצעות Pandas או Apache Arrow.

כדי לשלוט בהתנהגות של אצווה, מציינים את המספר המקסימלי של שורות בכל אצווה באמצעות האפשרות max_batching_rows בCREATE OR REPLACE FUNCTION רשימת האפשרויות. אם מציינים את הערך max_batching_rows, ‏BigQuery קובע את מספר השורות באצווה, עד למגבלה של max_batching_rows. אם לא מציינים את max_batching_rows, מספר השורות באצווה נקבע באופן אוטומטי.

שימוש ב-Pandas

לפונקציית UDF וקטורית ב-Python יש ארגומנט pandas.DataFrame יחיד שצריך להוסיף לו הערות. הארגומנט pandas.DataFrame מכיל מספר עמודות זהה לזה של הפרמטרים של פונקציית ה-UDF ב-Python שמוגדרים בהצהרה CREATE FUNCTION. שמות העמודות בארגומנט pandas.DataFrame זהים לשמות הפרמטרים של הפונקציה המוגדרת על ידי המשתמש.

הפונקציה צריכה להחזיר pandas.Series או pandas.DataFrame עם עמודה אחת ומספר שורות זהה לזה של הקלט.

בדוגמה הבאה נוצרת פונקציה וקטורית מוגדרת-משתמש ב-Python בשם multiplyInputs עם שני פרמטרים – x ו-y:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyVectorized(x FLOAT64, y FLOAT64)
    RETURNS FLOAT64
    LANGUAGE python
    OPTIONS(runtime_version="python-3.11", entry_point="vectorized_multiply")
    AS r'''
    import pandas as pd
    
    def vectorized_multiply(df: pd.DataFrame):
      return df['x'] * df['y']
    
    ''';

    מחליפים את PROJECT_ID.‫DATASET_ID במזהה הפרויקט ובמזהה של מערך הנתונים.

    הקריאה ל-UDF זהה לדוגמה הקודמת.

  3. לוחצים על  Run.

שימוש ב-Apache Arrow

בדוגמה הבאה משתמשים בממשק RecordBatch של Apache Arrow. כשמשתמשים בממשק RecordBatch, הפונקציה מעבירה קבוצה של שורות של עמודות באורך שווה לנקודת הכניסה. בדוגמה הבאה משתמשים ב-Apache Arrow כדי ליצור פונקציית UDF וקטורית ב-Python בשם multiplyVectorizedArrow.

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyVectorizedArrow(x FLOAT64, y FLOAT64)
    RETURNS FLOAT64
    LANGUAGE python
    OPTIONS(
      runtime_version="python-3.11",
      entry_point="vectorized_multiply_arrow"
    )
    AS r'''
    import pyarrow as pa
    import pyarrow.compute as pc
    
    def vectorized_multiply_arrow(batch: pa.RecordBatch):
        # Access columns directly from the Arrow RecordBatch
        x = batch.column('x')
        y = batch.column('y')
    
        # Use pyarrow.compute for vectorized operations
        return pc.multiply(x, y)
    ''';

    מחליפים את PROJECT_ID.‫DATASET_ID במזהה הפרויקט ובמזהה של מערך הנתונים.

    הקריאה ל-UDF זהה לדוגמאות הקודמות.

  3. לוחצים על  Run.

קריאה לפונקציית Python UDF

אם יש לכם הרשאה להפעיל פונקציה מוגדרת-משתמש ב-Python, אתם יכולים לקרוא לה כמו לכל פונקציה אחרת. כדי להשתמש בפונקציה שמוגדרת בפרויקט אחר, צריך להשתמש בשם המלא של הפונקציה. לדוגמה, כדי להפעיל פונקציית חילוץ XML בשם cw_xml_extract בפרויקט אחר, מבצעים את השלבים הבאים.

המסוף

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הדוגמה הבאה:

    SELECT
      `PROJECT_ID.DATASET_ID`.`cw_xml_extract`(xml, '//title/text()') AS `title`
    FROM UNNEST([
      STRUCT('''<book id="1">
        <title>The Great Gatsby</title>
        <author>F. Scott Fitzgerald</author>
      </book>''' AS xml),
      STRUCT('''<book id="2">
        <title>1984</title>
        <author>George Orwell</author>
      </book>''' AS xml),
      STRUCT('''<book id="3">
        <title>Brave New World</title>
        <author>Aldous Huxley</author>
      </book>''' AS xml)
    ])
    
  3. לוחצים על  Run.

    הפלט של הדוגמה הזו:

    +--------------------------+
    | title                    |
    +--------------------------+
    | The Great Gatsby         |
    | 1984                     |
    | Brave New World          |
    +--------------------------+
    

BigQuery DataFrames

בדוגמה הבאה נעשה שימוש ב-BigQuery DataFrames באמצעות השיטות sql_scalar,‏ read_gbq_function ו-apply כדי לקרוא לפונקציית Python UDF:

import textwrap
from typing import Tuple

import bigframes.pandas as bpd
import pandas as pd
import pyarrow as pa

# Set partial ordering mode for BigQuery DataFrames.
bpd.options.bigquery.ordering_mode = "partial"


def call_python_udf(
    project_id: str = "your-project-id",
    location: str = "US",
) -> Tuple[pd.Series, bpd.Series]:
    """Demonstrates calling a Python UDF using pandas and BigQuery DataFrames."""
    # Set the billing project to use for queries. This step is optional, as the
    # project can be inferred from your environment in many cases.
    bpd.options.bigquery.project = project_id

    # Since this example works with local data, set a processing location.
    bpd.options.bigquery.location = location

    # Create a sample series.
    xml_series = pd.Series(
        [
            textwrap.dedent(
                """
                <book id="1">
                    <title>The Great Gatsby</title>
                    <author>F. Scott Fitzgerald</author>
                </book>
                """
            ),
            textwrap.dedent(
                """
                <book id="2">
                    <title>1984</title>
                    <author>George Orwell</author>
                </book>
                """
            ),
            textwrap.dedent(
                """
                <book id="3">
                    <title>Brave New World</title>
                    <author>Aldous Huxley</author>
                </book>
                """
            ),
        ],
        dtype=pd.ArrowDtype(pa.string()),
    )
    df = pd.DataFrame({"xml": xml_series})

    # Use the BigQuery Accessor, which is automatically registered on pandas
    # DataFrames when you import bigframes. This example uses a function that
    # has been deployed to bigquery-utils for demonstration purposes. To use in
    # production, deploy the function at
    # https://github.com/GoogleCloudPlatform/bigquery-utils/blob/master/udfs/community/cw_xml_extract.sqlx
    # to your own project.
    titles_pandas = df.bigquery.sql_scalar(
        "`bqutil`.`fn`.cw_xml_extract({xml}, '//title/text()')",
    )

    # Alternatively, call read_gbq_function to get a pointer to the function
    # that can be applied on BigQuery DataFrames objects.
    cw_xml_extract = bpd.read_gbq_function("bqutil.fn.cw_xml_extract")
    xml_bigframes = bpd.read_pandas(xml_series)

    xpath_query = "//title/text()"
    titles_bigframes = xml_bigframes.apply(cw_xml_extract, args=(xpath_query,))
    return titles_pandas, titles_bigframes


# Run the sample:
# titles_pandas, titles_bigframes = call_python_udf("your-project-id", "US")

סוגי נתונים נתמכים של פונקציות UDF ב-Python

בטבלה הבאה מוגדר המיפוי בין סוגי הנתונים של BigQuery, סוגי הנתונים של Python וסוגי הנתונים של Pandas:

סוג הנתונים ב-BigQuery סוג נתונים מובנה ב-Python שמשמש פונקציה רגילה בהגדרת המשתמש סוג הנתונים של Pandas שמשמש את הפונקציה המוגדרת על ידי המשתמש (UDF) שעברה וקטוריזציה סוג הנתונים של PyArrow שמשמש ל-ARRAY ול-STRUCT בפונקציה וקטורית בהגדרת המשתמש (vUDF)
BOOL bool BooleanDtype DataType(bool)
INT64 int Int64Dtype DataType(int64)
FLOAT64 float FloatDtype DataType(double)
STRING str StringDtype DataType(string)
BYTES bytes binary[pyarrow] DataType(binary)
TIMESTAMP

פרמטר הפונקציה: datetime.datetime (עם הגדרה של אזור הזמן UTC)

ערך ההחזרה של הפונקציה: datetime.datetime (עם כל אזור זמן שמוגדר)

פרמטר הפונקציה: timestamp[us, tz=UTC][pyarrow]

ערך ההחזרה של הפונקציה: timestamp[us, tz=*][pyarrow]\(any timezone\)

‫TimestampType(timestamp[us]), עם אזור זמן
DATE datetime.date date32[pyarrow] DataType(date32[day])
TIME datetime.time time64[pyarrow] Time64Type(time64[us])
DATETIME ‫datetime.datetime (בלי אזור זמן) timestamp[us][pyarrow] ‫TimestampType(timestamp[us]), בלי אזור זמן
ARRAY list list<...>[pyarrow], כאשר סוג הנתונים של הרכיב הוא pandas.ArrowDtype ListType
STRUCT dict struct<...>[pyarrow], כאשר סוג הנתונים של השדה הוא pandas.ArrowDtype StructType

גרסאות נתמכות של סביבת זמן הריצה

פונקציות UDF ב-Python ב-BigQuery תומכות בסביבת זמן הריצה python-3.11. גרסת Python הזו כוללת כמה חבילות נוספות שמותקנות מראש. לספריות מערכת, צריך לבדוק את תמונת הבסיס של זמן הריצה.

גרסת זמן ריצה גרסת Python כולל
python-3.11 Python 3.11 numpy 1.26.3
pyarrow 14.0.2
pandas 2.1.4
python-dateutil 2.8.2
absl-py 2.0.0
pytz 2023.3.post1
tzdata 2023.4
six 1.16.0

שימוש בחבילות של צד שלישי

אתם יכולים להשתמש ברשימת האפשרויות של CREATE FUNCTION כדי להשתמש במודולים אחרים, מלבד אלה שסופקו על ידי הספרייה הרגילה של Python וחבילות שהותקנו מראש. אפשר להתקין חבילות מ-Python Package Index (PyPI)‎, או לייבא קובצי Python מ-Cloud Storage.

התקנת חבילה מאינדקס החבילות של Python

כשמתקינים חבילה, צריך לציין את שם החבילה, ואפשר גם לציין את גרסת החבילה באמצעות מפרטי גרסאות של חבילות Python.

אם החבילה נמצאת בסביבת זמן הריצה, המערכת משתמשת בה, אלא אם צוינה גרסה מסוימת ברשימת האפשרויות של CREATE FUNCTION. אם לא מציינים גרסת חבילה, והחבילה לא נמצאת בסביבת זמן הריצה, המערכת משתמשת בגרסה הזמינה האחרונה. יש תמיכה רק בחבילות עם הפורמט הבינארי wheels.

בדוגמה הבאה מוסבר איך ליצור UDF ב-Python שמתקינה את החבילה scipy באמצעות רשימת האפשרויות CREATE OR REPLACE FUNCTION:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.area(radius FLOAT64)
    RETURNS FLOAT64 LANGUAGE python
    OPTIONS (entry_point='area_handler', runtime_version='python-3.11', packages=['scipy==1.15.3'])
    AS r"""
    import scipy
    
    def area_handler(radius):
      return scipy.constants.pi*radius*radius
    """;
    
    SELECT `PROJECT_ID.DATASET_ID`.area(4.5);

    מחליפים את PROJECT_ID.‫DATASET_ID במזהה הפרויקט ובמזהה של מערך הנתונים.

  3. לוחצים על  Run.

ייבוא קובצי Python נוספים כספריות

אפשר להרחיב את הפונקציות המוגדרות על ידי המשתמש ב-Python באמצעות רשימת האפשרויות של הפונקציה, על ידי ייבוא קובצי Python מ-Cloud Storage.

בקוד ה-Python של ה-UDF, אתם יכולים לייבא את קובצי ה-Python מ-Cloud Storage כמודולים באמצעות הצהרת הייבוא, ואחריה הנתיב לאובייקט Cloud Storage. לדוגמה, אם אתם מייבאים את gs://BUCKET_NAME/path/to/lib1.py, הצהרת הייבוא תהיה import path.to.lib1.

שם הקובץ של Python צריך להיות מזהה של Python. כל שם של folder בשם האובייקט (אחרי /) צריך להיות מזהה תקין ב-Python. בטווח ASCII‏ (U+0001..U+007F), אפשר להשתמש בתווים הבאים במזהים:

  • אותיות רישיות ואותיות קטנות מ-A עד Z.
  • קווים תחתונים.
  • הספרות אפס עד תשע, אבל מספר לא יכול להופיע כתו הראשון במזהה.

בדוגמה הבאה מוסבר איך ליצור פונקציית UDF ב-Python שמייבאת את חבילת ספריית הלקוח lib1.py מקטגוריה של Cloud Storage בשם my_bucket:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.myFunc(a FLOAT64, b STRING)
    RETURNS STRING LANGUAGE python
    OPTIONS (
    entry_point='compute', runtime_version='python-3.11',
    library=['gs://BUCKET_NAME/PATH/lib1.py'])
    AS r"""
    import path.to.lib1 as lib1
    
    def compute(a, b):
      # doInterestingStuff is a function defined in
      # gs://BUCKET_NAME/PATH/lib1.py
      return lib1.doInterestingStuff(a, b);
    
    """;

    מחליפים את מה שכתוב בשדות הבאים:

    • PROJECT_ID: מזהה הפרויקט.
    • ‫DATASET_ID: מזהה מערך הנתונים.
    • ‫BUCKET_NAME: השם של הקטגוריה ב-Cloud Storage שמכילה את lib1.py.
    • ‫PATH: הנתיב לקטגוריה של Cloud Storage.
  3. לוחצים על  Run.

הגדרת מגבלות לקונטיינרים של פונקציות UDF ב-Python

אתם יכולים להשתמש ברשימת האפשרויות של CREATE FUNCTION כדי לציין את מגבלות המעבד (CPU), הזיכרון והבקשות בו-זמנית לקונטיינרים שמריצים פונקציות UDF ב-Python.

כברירת מחדל, למאגרים מוקצים המשאבים הבאים:

  • הזיכרון שהוקצה הוא 512Mi.
  • המעבד (CPU) שהוקצה הוא 1.0 vCPU.
  • מגבלת הבקשות בו-זמנית של הקונטיינר היא 80.

בדוגמה הבאה נוצרת UDF ב-Python באמצעות רשימת האפשרויות CREATE FUNCTION כדי לציין את מגבלות הקונטיינר:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את הצהרת ה-CREATE FUNCTION הבאה:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.square_area(length FLOAT64)
    RETURNS FLOAT64 LANGUAGE python
    OPTIONS (entry_point='square_area', runtime_version='python-3.11',
    container_memory='CONTAINER_MEMORY', container_cpu=CONTAINER_CPU, container_request_concurrency=CONTAINER_REQUEST_CONCURRENCY)
    AS r"""
    def square_area(length):
      return length*length
    """;
    
    SELECT `PROJECT_ID.DATASET_ID`.square_area(4.5);

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫PROJECT_ID.DATASET_ID: מזהה הפרויקט ומזהה מערך הנתונים.
    • ‫CONTAINER_MEMORY: ערך הזיכרון בפורמט הבא: <integer_number><unit>. היחידה חייבת להיות אחד מהערכים הבאים: Mi ‏ (MiB),‏ M ‏ (MB),‏ Gi ‏ (GiB) או G ‏ (GB). לדוגמה, 2Gi.
    • ‫CONTAINER_CPU: ערך המעבד (CPU). פונקציות UDF ב-Python תומכות בערכי CPU שבריים בין 0.33 ל-1.0 ובערכי CPU לא שבריים של 1,‏ 2 ו-4.
    • ‫CONTAINER_REQUEST_CONCURRENCY: המספר המקסימלי של בקשות מקבילות לכל מכונה של קונטיינר Python UDF. הערך צריך להיות מספר שלם בין 1 ל-1000.
  3. לוחצים על  Run.

ערכי מעבד נתמכים

פונקציות UDF ב-Python תומכות בערכי CPU שבריים בין 0.33 ל-1.0, ובערכי CPU לא שבריים של 1, ‏ 2 ו-4. אפשר להגדיר קונטיינרים שמריצים פונקציות UDF ב-Python עד 4 vCpu. ערך ברירת המחדל הוא 1.0. ערכי קלט שבריים מעוגלים לשתי ספרות אחרי הנקודה העשרונית לפני שהם מוחלים על מאגר התגים.

ערכי זיכרון נתמכים

אפשר להגדיר את ערכי הזיכרון של קונטיינרים של פונקציות Python מוגדרות-משתמש בפורמט הבא: <integer_number><unit>. היחידה חייבת להיות אחד מהערכים הבאים: Mi, ‏ M, ‏ Gi,‏ G. כמות הזיכרון המינימלית שאפשר להגדיר היא 256Mi. כמות הזיכרון המקסימלית שאפשר להגדיר היא 16Gi.

בהתאם לערך הזיכרון שבוחרים, צריך גם לציין כמות מתאימה של מעבד (CPU). בטבלה הבאה מוצגים ערכי המינימום והמקסימום של המעבד (CPU) לכל ערך זיכרון:

זיכרון מעבד (CPU) מינימלי מעבד (CPU) מקסימלי
256Mi עד 512Mi 0.33 2
גדול מ-512Mi וקטן מ-1Gi או שווה לו 0.5 2
גדול מ-1Gi וקטן מ-2Gi 1 2
2Gi עד 4Gi 1 4
יותר מ-4Gi ועד 8Gi 2 4
יותר מ-8Gi ועד 16Gi 4 4

לחלופין, אם קבעתם את כמות המעבד (CPU) שאתם מקצים, תוכלו להשתמש בטבלה הבאה כדי לקבוע את טווח הזיכרון המתאים:

CPU זיכרון מינימלי זיכרון מקסימלי
פחות מ-0.5 256Mi 512Mi
0.5 עד פחות מ-1 256Mi 1Gi
1 256Mi 4Gi
2 256Mi 8Gi
4 2Gi 16Gi

קריאה ל- Google Cloud או לשירותים אונליין בקוד Python

פונקציית UDF ב-Python ניגשת לשירות של Google Cloud או לשירות חיצוני באמצעות חשבון השירות חיבור למשאבים ב-Cloud. צריך לתת לחשבון השירות של החיבור הרשאות גישה לשירות. ההרשאות הנדרשות משתנות בהתאם לשירות שאליו ניגשים ולממשקי ה-API שמופעלים מקוד Python.

אם יוצרים פונקציית Python מוגדרת-משתמש בלי להשתמש בקישור למשאבים ב-Cloud, הפונקציה מופעלת בסביבה שחוסמת את הגישה לרשת. אם הפונקציה המוגדרת על ידי המשתמש ניגשת לשירותים אונליין, צריך ליצור אותה עם חיבור למשאבים ב-Cloud. אם לא תעשו את זה, ה-UDF לא יוכל לגשת לרשת עד שיסתיים הזמן הקצוב לחיבור פנימי. כשמשתמשים בקישור למשאבים ב-Cloud, צריך להטמיע את הדברים הבאים:

  • חסימות זמניות. כשמבצעים קריאות רשת בתוך פונקציית Python UDF, תמיד צריך לכלול זמן קצוב לתפוגה (timeout) סביר. כך ה-UDF לא תיתקע ללא הגבלת זמן אם השירות החיצוני מגיב לאט או לא נגיש.

  • להשתמש בטיפול בשגיאות. כדאי להוסיף את קוד הקריאה לרשת בבלוק try...except כדי לטפל בצורה חלקה בשגיאות פוטנציאליות, כמו שגיאות בחיבור, זמן קצוב לתפוגה או קודי סטטוס של כשל ב-HTTP. כך הפונקציה המוגדרת על ידי המשתמש יכולה להחזיר שגיאה משמעותית או ערך חלופי, במקום לגרום לשאילתה להיכשל או להפסיק להגיב.

בדוגמה הבאה אפשר לראות איך לגשת לשירות Cloud Translation מ-UDF ב-Python. בדוגמה הזו יש שני פרויקטים: פרויקט בשם my_query_project שבו יוצרים את הפונקציה המוגדרת על ידי המשתמש ואת הקישור למשאבים ב-Cloud, ופרויקט בשם my_translate_project שבו מריצים את Cloud Translation.

יצירת קישור למשאבים ב-Cloud

קודם כל, יוצרים קישור למשאבים ב-Cloud ב-my_query_project. כדי ליצור את הקישור למשאבים ב-Cloud, פועלים לפי השלבים הבאים.

בוחרים באחת מהאפשרויות הבאות:

המסוף

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. בחלונית הימנית, לוחצים על Explorer:

    כפתור מודגש לחלונית Explorer.

    אם החלונית הימנית לא מוצגת, לוחצים על Expand left pane כדי לפתוח אותה.

  3. בחלונית Explorer, מרחיבים את שם הפרויקט ולוחצים על Connections.

  4. בדף Connections, לוחצים על Create connection.

  5. בשדה Connection type, בוחרים באפשרות Vertex AI remote models, remote functions, BigLake and Spanner (Cloud Resource).

  6. בשדה מזהה החיבור, נותנים שם לחיבור.

  7. בשדה Location type, בוחרים מיקום לחיבור. החיבור צריך להיות באותו מיקום כמו המשאבים האחרים, למשל מערכי נתונים.

  8. לוחצים על יצירת חיבור.

  9. לוחצים על מעבר לחיבור.

  10. בחלונית Connection info, מעתיקים את מזהה חשבון השירות כדי להשתמש בו בשלב מאוחר יותר.

SQL

משתמשים בהצהרה CREATE CONNECTION:

  1. נכנסים לדף BigQuery במסוף Google Cloud .

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את ההצהרה הבאה:

    CREATE CONNECTION [IF NOT EXISTS] `CONNECTION_NAME`
    OPTIONS (
      connection_type = "CLOUD_RESOURCE",
      friendly_name = "FRIENDLY_NAME",
      description = "DESCRIPTION"
      );

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫CONNECTION_NAME: שם החיבור בפורמט PROJECT_ID.LOCATION.CONNECTION_ID,‏ LOCATION.CONNECTION_ID או CONNECTION_ID. אם לא מציינים את הפרויקט או המיקום, הם נגזרים מהפרויקט ומהמיקום שבהם ההצהרה מופעלת.
    • ‫FRIENDLY_NAME (אופציונלי): שם תיאורי לחיבור.
    • ‫DESCRIPTION (אופציונלי): תיאור של החיבור.

  3. לוחצים על הפעלה.

מידע נוסף על הרצת שאילתות זמין במאמר הרצת שאילתה אינטראקטיבית.

BQ

  1. בסביבה של שורת הפקודה, יוצרים חיבור:

    bq mk --connection --location=REGION --project_id=PROJECT_ID \
        --connection_type=CLOUD_RESOURCE CONNECTION_ID

    הפרמטר --project_id מבטל את פרויקט ברירת המחדל.

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫REGION: אזור החיבור שלכם
    • ‫PROJECT_ID: מזהה הפרויקט ב- Google Cloud
    • ‫CONNECTION_ID: מזהה לחיבור

    כשיוצרים משאב חיבור, BigQuery יוצר חשבון שירות ייחודי של המערכת ומשייך אותו לחיבור.

    פתרון בעיות: אם מופיעה שגיאת החיבור הבאה, עדכנו את Google Cloud SDK:

    Flags parsing error: flag --connection_type=CLOUD_RESOURCE: value should be one of...
    
  2. מאחזרים ומעתיקים את מזהה חשבון השירות כדי להשתמש בו בשלב מאוחר יותר:

    bq show --connection PROJECT_ID.REGION.CONNECTION_ID

    הפלט אמור להיראות כך:

    name                          properties
    1234.REGION.CONNECTION_ID     {"serviceAccountId": "connection-1234-9u56h9@gcp-sa-bigquery-condel.iam.gserviceaccount.com"}
    

Python

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי הוראות ההגדרה של Python במדריך למתחילים של BigQuery באמצעות ספריות לקוח. למידע נוסף, קראו את מאמרי העזרה של BigQuery Python API.

כדי לבצע אימות ב-BigQuery, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

import google.api_core.exceptions
from google.cloud import bigquery_connection_v1

client = bigquery_connection_v1.ConnectionServiceClient()


def create_connection(
    project_id: str,
    location: str,
    connection_id: str,
):
    """Creates a BigQuery connection to a Cloud Resource.

    Cloud Resource connection creates a service account which can then be
    granted access to other Google Cloud resources for federated queries.

    Args:
        project_id: The Google Cloud project ID.
        location: The location of the connection (for example, "us-central1").
        connection_id: The ID of the connection to create.
    """

    parent = client.common_location_path(project_id, location)

    connection = bigquery_connection_v1.Connection(
        friendly_name="Example Connection",
        description="A sample connection for a Cloud Resource.",
        cloud_resource=bigquery_connection_v1.CloudResourceProperties(),
    )

    try:
        created_connection = client.create_connection(
            parent=parent, connection_id=connection_id, connection=connection
        )
        print(f"Successfully created connection: {created_connection.name}")
        print(f"Friendly name: {created_connection.friendly_name}")
        print(
            f"Service Account: {created_connection.cloud_resource.service_account_id}"
        )

    except google.api_core.exceptions.AlreadyExists:
        print(f"Connection with ID '{connection_id}' already exists.")
        print("Please use a different connection ID.")
    except Exception as e:
        print(f"An unexpected error occurred while creating the connection: {e}")

Node.js

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי הוראות ההגדרה של Node.js במדריך למתחילים של BigQuery באמצעות ספריות לקוח. למידע נוסף, קראו את מאמרי העזרה של BigQuery Node.js API.

כדי לבצע אימות ב-BigQuery, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

const {ConnectionServiceClient} =
  require('@google-cloud/bigquery-connection').v1;
const {status} = require('@grpc/grpc-js');

const client = new ConnectionServiceClient();

/**
 * Creates a new BigQuery connection to a Cloud Resource.
 *
 * A Cloud Resource connection creates a service account that can be granted access
 * to other Google Cloud resources.
 *
 * @param {string} projectId The Google Cloud project ID. for example, 'example-project-id'
 * @param {string} location The location of the project to create the connection in. for example, 'us-central1'
 * @param {string} connectionId The ID of the connection to create. for example, 'example-connection-id'
 */
async function createConnection(projectId, location, connectionId) {
  const parent = client.locationPath(projectId, location);

  const connection = {
    friendlyName: 'Example Connection',
    description: 'A sample connection for a Cloud Resource',
    // The service account for this cloudResource will be created by the API.
    // Its ID will be available in the response.
    cloudResource: {},
  };

  const request = {
    parent,
    connectionId,
    connection,
  };

  try {
    const [response] = await client.createConnection(request);

    console.log(`Successfully created connection: ${response.name}`);
    console.log(`Friendly name: ${response.friendlyName}`);

    console.log(`Service Account: ${response.cloudResource.serviceAccountId}`);
  } catch (err) {
    if (err.code === status.ALREADY_EXISTS) {
      console.log(`Connection '${connectionId}' already exists.`);
    } else {
      console.error(`Error creating connection: ${err.message}`);
    }
  }
}

Java

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי הוראות ההגדרה של Java במדריך למתחילים של BigQuery באמצעות ספריות לקוח. למידע נוסף, קראו את מאמרי העזרה של BigQuery Java API.

כדי לבצע אימות ב-BigQuery, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

import com.google.api.gax.rpc.AlreadyExistsException;
import com.google.api.gax.rpc.ApiException;
import com.google.cloud.bigquery.connection.v1.CloudResourceProperties;
import com.google.cloud.bigquery.connection.v1.Connection;
import com.google.cloud.bigquery.connection.v1.CreateConnectionRequest;
import com.google.cloud.bigquery.connection.v1.LocationName;
import com.google.cloud.bigqueryconnection.v1.ConnectionServiceClient;
import java.io.IOException;

public class CreateConnection {

  /**
   * Creates a BigQuery connection to a Cloud Resource. A Cloud Resource connection provisions a
   * service account that can be granted access to other Google Cloud resources for federated
   * queries.
   *
   * @param projectId The Google Cloud project ID (for example, "example-project-id").
   * @param location The geographic location of the connection (for example, "us-central1").
   * @param connectionId The ID of the connection to create (for example, "example-connection-id").
   */
  public static void createConnection(String projectId, String location, String connectionId) {
    LocationName parent = LocationName.of(projectId, location);

    // CloudResourceProperties provisions a managed Google Cloud service account on creation.
    CloudResourceProperties cloudResourceProperties = CloudResourceProperties.newBuilder().build();
    Connection connection =
        Connection.newBuilder()
            .setFriendlyName("Example Connection")
            .setDescription("Cloud Resource connection for federated queries.")
            .setCloudResource(cloudResourceProperties)
            .build();

    CreateConnectionRequest request =
        CreateConnectionRequest.newBuilder()
            .setParent(parent.toString())
            .setConnectionId(connectionId)
            .setConnection(connection)
            .build();

    try (ConnectionServiceClient client = ConnectionServiceClient.create()) {
      Connection response = client.createConnection(request);

      System.out.printf("Successfully created connection: %s%n", response.getName());
      System.out.printf("Friendly name: %s%n", response.getFriendlyName());
      System.out.printf(
          "Service Account: %s%n", response.getCloudResource().getServiceAccountId());
    } catch (AlreadyExistsException err) {
      System.err.printf(
          "error: connection '%s' already exists in location '%s' for project '%s': %s%n",
          connectionId, location, projectId, err.getMessage());
    } catch (ApiException | IOException err) {
      System.err.printf(
          "error: failed to create connection '%s' in location '%s' for project '%s': %s%n",
          connectionId, location, projectId, err.getMessage());
    }
  }

Terraform

משתמשים במשאב google_bigquery_connection.

כדי לבצע אימות ב-BigQuery, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

בדוגמה הבאה נוצר קישור למשאבים ב-Cloud בשם my_cloud_resource_connection באזור US:


# This queries the provider for project information.
data "google_project" "default" {}

# This creates a cloud resource connection in the US region named my_cloud_resource_connection.
# Note: The cloud resource nested object has only one output field - serviceAccountId.
resource "google_bigquery_connection" "default" {
  connection_id = "my_cloud_resource_connection"
  project       = data.google_project.default.project_id
  location      = "US"
  cloud_resource {}
}

כך מחילים את ההגדרות של Terraform בפרויקט ב- Google Cloud :

הכנת Cloud Shell

  1. מפעילים את Cloud Shell.
  2. מגדירים את פרויקט ברירת המחדל ב- Google Cloud שבו רוצים להחיל את ההגדרות של Terraform.

    תצטרכו להריץ את הפקודה הזו רק פעם אחת לכל פרויקט, ותוכלו לעשות זאת בכל ספרייה.

    export GOOGLE_CLOUD_PROJECT=PROJECT_ID

    אם תגדירו ערכים ספציפיים בקובץ התצורה של Terraform, הם יבטלו את ערכי ברירת המחדל של משתני הסביבה.

הכנת הספרייה

לכל קובץ תצורה של Terraform צריכה להיות ספרייה משלו (שנקראת גם מודול ברמה הבסיסית).

  1. יוצרים ספרייה חדשה ב-Cloud Shell ובה יוצרים קובץ חדש. שם הקובץ חייב לכלול את הסיומת .tf, למשל main.tf. במדריך הזה, הקובץ נקרא main.tf.
    mkdir DIRECTORY && cd DIRECTORY && touch main.tf
  2. אם אתם עוקבים אחרי המדריך, תוכלו להעתיק את הקוד לדוגמה בכל קטע או שלב.

    מעתיקים את הקוד לדוגמה בקובץ main.tf החדש שיצרתם.

    לחלופין, אפשר גם להעתיק את הקוד מ-GitHub. כדאי לעשות את זה כשקטע הקוד של Terraform הוא חלק מפתרון מקצה לקצה.

  3. בודקים את הפרמטרים לדוגמה ומשנים אותם בהתאם לסביבה שלכם.
  4. שומרים את השינויים.
  5. מפעילים את Terraform. צריך לעשות זאת רק פעם אחת לכל ספרייה.
    terraform init

    אופציונלי: תוכלו לכלול את האפשרות -upgrade, כדי להשתמש בגרסה העדכנית ביותר של הספק של Google:

    terraform init -upgrade

החלה של השינויים

  1. בודקים את ההגדרות ומוודאים שהמשאבים שמערכת Terraform תיצור או תעדכן תואמים לציפיות שלכם:
    terraform plan

    מתקנים את ההגדרות לפי הצורך.

  2. מריצים את הפקודה הבאה ומזינים yes בהודעה שמופיעה, כדי להחיל את הגדרות Terraform:
    terraform apply

    ממתינים עד שב-Terraform תוצג ההודעה "Apply complete!‎".

  3. פותחים את הפרויקט ב- Google Cloud כדי להציג את התוצאות. במסוף Google Cloud , נכנסים למשאבים בממשק המשתמש כדי לוודא שהם נוצרו או עודכנו ב-Terraform.

מתן גישה לחשבון השירות של החיבור

כדי להגדיר את ההרשאות לחיבור, תצטרכו את מזהה חשבון השירות שהעתקתם קודם. כשיוצרים משאב חיבור, BigQuery יוצר חשבון שירות ייחודי של המערכת ומשייך אותו לחיבור.

כדי לתת לחשבון השירות של הקישור למשאבים ב-Cloud גישה לפרויקטים, מקצים לחשבון השירות את התפקיד Service usage consumer (roles/serviceusage.serviceUsageConsumer) ב-my_query_project ואת התפקיד Cloud Translation API user (roles/cloudtranslate.user) ב-my_translate_project.

המסוף

  1. נכנסים לדף IAM.

    כניסה לדף IAM

  2. מוודאים שהאפשרות my_query_project נבחרה.

  3. לוחצים על Grant Access.

  4. בשדה New principals, מזינים את מזהה חשבון השירות של הקישור למשאבים ב-Cloud שהעתקתם קודם.

  5. בשדה Select a role, בוחרים באפשרות Service usage ואז באפשרות Service usage consumer.

  6. לוחצים על Save.

  7. בבורר הפרויקטים, בוחרים באפשרות my_translate_project.

  8. נכנסים לדף IAM.

    כניסה לדף IAM

  9. לוחצים על Grant Access.

  10. בשדה New principals, מזינים את מזהה חשבון השירות של הקישור למשאבים ב-Cloud שהעתקתם קודם.

  11. בשדה Select a role, בוחרים באפשרות Cloud translation ואז באפשרות Cloud Translation API user.

  12. לוחצים על Save.

SQL

משתמשים בהצהרה GRANT כדי לתת את התפקיד "צרכן של שימוש בשירות" (roles/serviceusage.serviceUsageConsumer) לחשבון השירות ב-my_query_project:

  1. נכנסים לדף BigQuery במסוף Google Cloud .

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את ההצהרה הבאה:

      GRANT `roles/serviceusage.serviceUsageConsumer`
      ON PROJECT `my_query_project`
      TO "connection:SERVICE_ACCOUNT_ID";
      

    מחליפים את SERVICE_ACCOUNT_ID במזהה של חשבון השירות שהעתקתם קודם.

  3. לוחצים על הפעלה.

מידע נוסף על הרצת שאילתות זמין במאמר הרצת שאילתה אינטראקטיבית.

משתמשים בהצהרה GRANT כדי להקצות את תפקיד המשתמש ב-Cloud Translation API (roles/cloudtranslate.user) ב-my_translate_project:

  1. נכנסים לדף BigQuery במסוף Google Cloud .

    כניסה ל-BigQuery

  2. בעורך השאילתות, מזינים את ההצהרה הבאה:

      GRANT `roles/cloudtranslate.user`
      ON PROJECT `my_translate_project`
      TO "connection:SERVICE_ACCOUNT_ID";
      

    מחליפים את SERVICE_ACCOUNT_ID במזהה של חשבון השירות שהעתקתם קודם.

  3. לוחצים על הפעלה.

מידע נוסף על הרצת שאילתות זמין במאמר הרצת שאילתה אינטראקטיבית.

יצירת פונקציה מוגדרת על ידי המשתמש ב-Python שקוראת לשירות Cloud Translation

ב-my_query_project, יוצרים פונקציה מוגדרת-משתמש ב-Python שקוראת לשירות Cloud Translation באמצעות הקישור למשאבים ב-Cloud.

  1. נכנסים לדף BigQuery במסוף Google Cloud .

    כניסה ל-BigQuery

  2. מזינים את ההצהרה הבאה של CREATE FUNCTION בעורך השאילתות:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.translate_to_es(x STRING)
    RETURNS STRING LANGUAGE python
    WITH CONNECTION `PROJECT_ID.REGION.CONNECTION_ID`
    OPTIONS (entry_point='do_translate', runtime_version='python-3.11', packages=['google-cloud-translate>=3.11', 'google-api-core'])
    AS r"""
    
    from google.api_core.retry import Retry
    from google.cloud import translate
    
    project = "my_translate_project"
    translate_client = translate.TranslationServiceClient()
    
    def do_translate(x : str) -> str:
    
        response = translate_client.translate_text(
            request={
                "parent": f"projects/PROJECT_ID/locations/us-central1",
                "contents": [x],
                "target_language_code": "es",
                "mime_type": "text/plain",
            },
            retry=Retry(),
        )
        return response.translations[0].translated_text
    
    """;
    
    -- Call the UDF.
    WITH text_table AS
      (SELECT "Hello" AS text
      UNION ALL
      SELECT "Good morning" AS text
      UNION ALL
      SELECT "Goodbye" AS text)
    SELECT text,
    `PROJECT_ID.DATASET_ID`.translate_to_es(text) AS translated_text
    FROM text_table;

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫PROJECT_ID: מזהה הפרויקט.
    • ‫DATASET_ID: מזהה מערך הנתונים.
    • ‫REGION: האזור של החיבור.
    • ‫CONNECTION_ID: מזהה החיבור.
  3. לוחצים על  Run.

    הפלט אמור להיראות כך:

    +--------------------------+-------------------------------+
    | text                     | translated_text               |
    +--------------------------+-------------------------------+
    | Hello                    | Hola                          |
    | Good morning             | Buen dia                      |
    | Goodbye                  | Adios                         |
    +--------------------------+-------------------------------+
    

שימוש ב-VPC Service Controls

פונקציות UDF ב-Python יורשות את גבולות הגזרה של VPC Service Controls מהפרויקט שמריץ את משימת השאילתה. ההיקף הזה מגן על המשימות מפני זליגת נתונים, ומבטיח שהאינטראקציות בין השירותים מאובטחות.

כשמפעילים פונקציית Python UDF בתוך היקף השירות של VPC Service Controls, יש לה את הקישוריות הבאה לרשת:

  • פונקציות UDF ב-Python שלא משתמשות בקישור למשאבים ב-Cloud מבודדות לחלוטין. כל התנועה היוצאת חסומה.
  • פונקציות UDF ב-Python שמשתמשות בקישור למשאבים ב-Cloud חסומות לגישה ציבורית לאינטרנט. פונקציות Python מוגדרות-משתמש יכולות לגשת רק לשירותי Google Cloud שתומכים ב-VPC Service Controls. תנועה יוצאת לכל יעד אחר מלבד restricted.googleapis.com חסומה.

הגדרת פונקציות Python מוגדרות-משתמש כדי לגשת לשירותי Google Cloud באופן מאובטח ב-VPC Service Controls

כדי לגשת לשירותי Google Cloud מפונקציות Python UDF תוך אכיפת VPC Service Controls, מבצעים את השלבים הבאים:

  1. יוצרים את פונקציית ה-UDF ב-Python באמצעות הסעיף WITH CONNECTION של ההצהרה CREATE FUNCTION.
  2. כוללים בגבולות הגזרה לשירות את הפרויקט ב-BigQuery שבו פועלת משימת השאילתה ואת פרויקט השירות המטורגט. לחלופין, אפשר להגדיר גבולות גזרה מגושרים.
  3. מוסיפים את ה-API של שירות היעד להגדרת גבולות הגזרה. לדוגמה, translate.googleapis.com אם מתחברים ל-Cloud Translation API.

לפרטים נוספים על הגדרת היקף של VPC Service Controls, ראו:

שימוש ברישום ביומן

כשמפעילים את הרישום ביומן, אפשר לראות ב-Cloud Logging יומנים בזמן אמת שנוצרו על ידי פונקציות ה-UDF ב-Python, כדי לזהות ולפתור בעיות בקוד. כדי למנוע זליגת מידע בטעות, רישום ביומן של פונקציות UDF ב-Python מושבת כברירת מחדל.

הפעלת הרישום ביומן

כדי להפעיל את הרישום ביומן של הסשן, מריצים את ההצהרה הבאה לפני שמריצים את השאילתה:

SET @@udf.properties = JSON '{"enableDebugOutput": true}';

כדי לתעד מידע, משתמשים בפונקציות בספריית logging של Python, כמו logging.info או logging.error. הפונקציה print() לא נתמכת.

היומנים נכתבים במשאב bigquery.googleapis.com/ManagedRoutineInvocation ב-Logging, ואפשר לסנן אותם לפי התוויות הבאות:

  • ‫resource_container: מזהה הפרויקט שבו הופעלה משימת השאילתה.
  • ‫location: המיקום שבו הופעלה משימת השאילתה.
  • ‫query_job_id: המזהה של משימת השאילתה שהפעילה את ה-UDF ב-Python.
  • ‫routine_project_id: מזהה הפרויקט שבו מאוחסנת השגרה שהופעלה.
  • ‫routine_dataset_id: מזהה מערך הנתונים שבו מאוחסנת השגרה שהופעלה.
  • ‫routine_id: המזהה של השגרה שהופעלה.

הנתונים שנרשמים ב-Cloud Logging כפופים לתמחור של Google Cloud Observability.

דוגמה

בדוגמה הבאה מוסבר איך להשתמש ברישום ביומן כדי לנפות באגים בשגיאות ב-UDF ב-Python, בלי לגרום לשאילתה להיכשל.

הפונקציה extract_user_email של Python מחלצת כתובות אימייל ממחרוזות JSON. חריגה לא מטופלת ב-UDF יכולה לגרום לכישלון של כל השאילתה, ולכן הפונקציה תופסת חריגות ומחזירה את הערך None, שהופך לערך NULL ב-BigQuery. כדי לעזור לכם לזהות את הקלט הלא תקין שלא הצליח לעבור ניתוח, הפונקציה מתעדת באופן סלקטיבי את המטען הייעודי (payload) הבעייתי ב-Cloud Logging:

CREATE OR REPLACE FUNCTION `PROJECT_ID.DATASET_ID`.extract_user_email(payload STRING)
RETURNS STRING
LANGUAGE python
OPTIONS (entry_point='parse_email', runtime_version='python-3.11')
AS
r"""
import json
import logging
def parse_email(payload):
  try:
    # Attempt to parse the JSON and extract the email
    data = json.loads(payload)
    return data.get('email')
  except Exception as e:
    # Log the exact bad data and the error to Cloud Logging
    logging.info(f"Failed to parse payload: '{payload}'. Error: {e}")
    # Return None (NULL in BigQuery) to prevent the query from failing.
    return None
""";

-- The query completes successfully, returning NULL for the invalid row.
-- The info log for 'corrupted_payload_string' is sent to Cloud Logging.
SET @@udf.properties = JSON '{"enableDebugOutput": true}';
SELECT `PROJECT_ID.DATASET_ID`.extract_user_email(raw_data) AS email
FROM UNNEST([
    '{"email": "cloudysanfrancisco@gmail.com", "event": "click"}',
    'corrupted_payload_string',
    '{"email": "baklavainthebalkans@gmail.com", "event": "view"}'
]) AS raw_data;

אפשר לגשת ליומנים שמכילים את הקלט corrupted_payload_string ב-Logging.

צפייה ביומנים

כדי לראות את היומנים של פונקציות ה-UDF ב-Python, בוחרים באחת מהאפשרויות בקטעים הבאים.

פרטי המשרה

כדי לצפות ביומני ה-UDF ב-Python של משימת שאילתה בכרטיסייה Job information:

  1. בחלונית Query results, לוחצים על הכרטיסייה Job information.

  2. בשדה Log, לוחצים על Log. הכלי Logs Explorer ייפתח, ותוצג בו שאילתה עם היומנים של הקריאה לפונקציית ה-UDF ב-Python.

Logs Explorer

אתם יכולים גם לעבור ישירות ל-Logs Explorer וליצור שאילתה בעצמכם כדי להציג את היומנים של פונקציות Python UDF:

  1. נכנסים לדף Logs Explorer ב-Cloud Logging.

    כניסה לדף Logs Explorer

  2. בכלי לעריכת שאילתות, יוצרים שאילתה באמצעות סוג המשאב bigquery.googleapis.com/ManagedRoutineInvocation וכל תווית משאב רלוונטית. לדוגמה, אתם יכולים להשתמש בשאילתה הבאה כדי להציג יומני UDF ב-Python שהגיעו ממשימת שאילתה:

    resource.type="bigquery.googleapis.com/ManagedRoutineInvocation"
    resource.labels.query_job_id="QUERY_JOB_ID"
    

    מחליפים את QUERY_JOB_ID במזהה של משימת השאילתה שהפעילה את ה-UDF ב-Python.

הצגת מדדי Python UDF

פונקציות Python מוגדרות-משתמש מייצאות מדדים ל-Cloud Monitoring. המדדים האלה עוזרים לעקוב אחרי היבטים שונים של תקינות התפעול וצריכת המשאבים של הפונקציה המוגדרת על ידי המשתמש, ומספקים תובנות לגבי הביצועים וההתנהגות של המכונות של הפונקציה המוגדרת על ידי המשתמש.

סוג המשאב במעקב

המדדים של פונקציות UDF ב-Python מדווחים בסוג המשאב הבא ב-Cloud Monitoring:

  • סוג: bigquery.googleapis.com/ManagedRoutineInvocation
  • Display Name: BigQuery Managed Routine Invocation
  • תוויות:
    • ‫resource_container: מזהה הפרויקט שבו הופעלה משימת השאילתה.
    • ‫location: המיקום שבו הופעלה משימת השאילתה.
    • ‫query_job_id: המזהה של משימת השאילתה שהפעילה את ה-UDF ב-Python.
    • ‫routine_project_id: מזהה הפרויקט שבו מאוחסנת השגרה שהופעלה.
    • ‫routine_dataset_id: מזהה מערך הנתונים שבו מאוחסנת השגרה שהופעלה.
    • ‫routine_id: המזהה של השגרה שהופעלה.

מדדים

המדדים הבאים זמינים לסוג המשאב bigquery.googleapis.com/ManagedRoutineInvocation:

מדד תיאור יחידה סוג הערך
bigquery.googleapis.com/managed_routine/python/cpu_utilizations כשמופעלת פונקציית Python UDF, המדד הזה מציג את התפלגות ניצול המעבד (CPU) בכל המופעים של Python UDF במשימת השאילתה. ערך באחוזים DISTRIBUTION
bigquery.googleapis.com/managed_routine/python/memory_utilizations כשמופעלת פונקציית Python UDF, המדד הזה מציג את התפלגות ניצול הזיכרון בכל המופעים של Python UDF במשימת השאילתה. ערך באחוזים DISTRIBUTION
bigquery.googleapis.com/managed_routine/python/max_request_concurrencies המדד הזה מציג את ההתפלגות של המספר המקסימלי של בקשות בו-זמניות שכל מכונה של פונקציית Python מוגדרת-משתמש מטפלת בהן. ספירה DISTRIBUTION

הצגת המדדים

כדי לראות את המדדים של פונקציות ה-UDF ב-Python, בוחרים באחת מהאפשרויות בקטעים הבאים.

פרטי משרה

כדי לראות את המדדים של פונקציות UDF ב-Python במשימת שאילתה ספציפית:

  1. נכנסים לדף BigQuery.

    כניסה ל-BigQuery

  2. לוחצים על Job history.

  3. בעמודה Job ID, לוחצים על מזהה משימת השאילתה.

  4. בדף Query job details, לוחצים על Cloud Monitoring dashboard. בקישור הזה מוצג לוח בקרה שמסונן כדי להציג את המדדים של פונקציית ה-UDF ב-Python של המשימה.

Metrics Explorer

כדי לראות את המדדים של פונקציות Python UDF ב-Metrics Explorer:

  1. נכנסים לדף Metrics explorer ב-Cloud Monitoring.

    כניסה לדף Metrics Explorer

  2. לוחצים על Select a metric, ובשדה Filter מקלידים BigQuery Managed Routine Invocation או bigquery.googleapis.com/ManagedRoutineInvocation.

  3. בוחרים באפשרות BigQuery Managed Routine > Managed_routine.

  4. לוחצים על אחד מהמדדים הזמינים, למשל:

    • ניצול המעבד (CPU) של המכונה
    • ניצול הזיכרון של המכונה
    • מספר מקסימלי של בקשות מקבילות
  5. לוחצים על אישור.

    כברירת מחדל, המדדים מוצגים בתרשים.

  6. אפשר לסנן ולקבץ את המדדים באמצעות התוויות שמוגדרות בסוגי המשאבים במעקב. כדי לסנן את המדדים:

    1. בשדה Filter בוחרים סוג משאב, כמו query_job_id או routine_id.

    2. בשדה Value, מזינים את מזהה המשימה או מזהה השגרה, או בוחרים אחד מהרשימה.

מרכזי הבקרה של Cloud Monitoring

כדי לראות את המדדים של פונקציות Python UDF באמצעות לוחות הבקרה למעקב:

  1. נכנסים לדף Dashboards ב-Cloud Monitoring.

    כניסה לדף Dashboards

  2. לוחצים על לוח הבקרה BigQuery Managed Routine Query Monitoring.

    בלוח הבקרה הזה מוצגת סקירה כללית של מדדים עיקריים בכל הפונקציות המוגדרות על ידי המשתמש.

  3. כדי לסנן את מרכז הבקרה:

    1. לוחצים על סינון.

    2. ברשימה Filter by resource, בוחרים אפשרות כמו מזהה פרויקט, מיקום, מזהה שגרה או מזהה משימה.

שיטות מומלצות

כשיוצרים פונקציות UDF ב-Python, כדאי לפעול לפי השיטות המומלצות הבאות:

  • אופטימיזציה של לוגיקת השאילתות לעיבוד באצווה. מבנים מורכבים של שאילתות יכולים להשבית את האפשרות לשלוח בקשות באצווה. הפעולה הזו מאלצת עיבוד איטי, שורה אחר שורה, מה שמאריך משמעותית את זמן האחזור במערכי נתונים גדולים.
  • אופטימיזציה של המטען הייעודי (payload) של הנתונים. הגודל של שורות ספציפיות יכול להשפיע על היעילות של תכונת האצווה. כדי לעבד כמה שיותר שורות באצווה אחת, כדאי לשמור על שורות קטנות ככל האפשר.
  • להגדיר ביעילות את מגבלות הקונטיינר. המדרגיות היא פונקציה של המעבד (CPU), הזיכרון והבקשות בו-זמנית. בודקים את מדדי המעקב כדי לשנות את הגדרות הקונטיינר. אם ניצול המעבד (CPU) גבוה, מגדילים את הקצאת המעבד (CPU) באמצעות המגבלה container_cpu, או מפחיתים את מספר הבקשות בו-זמנית לקונטיינר באמצעות המגבלה container_request_concurrency.
  • כשמשתמשים בכוונון איטרטיבי, מתחילים עם ערכי ברירת המחדל. אם הביצועים לא אופטימליים, נתחו את מדדי המעקב כדי לזהות צווארי בקבוק ספציפיים.
  • הטמעת פסקי זמן (timeout) ב-API. כשפונקציית ה-UDF ב-Python ניגשת לאינטרנט, צריך להגדיר זמן קצוב לתפוגה בקריאה ל-API כדי למנוע התנהגות בלתי צפויה. דוגמה לגישה לאינטרנט היא קריאה מקטגוריה של Cloud Storage.
  • כדי להפחית את העלות ולשפר את הקריאוּת, כדאי להגביל את הרישום ביומן לחריגות, לאנומליות בנתונים או לחלונות ספציפיים של ניפוי באגים.

מיקומים נתמכים

אפשר להשתמש בפונקציות UDF ב-Python בכל המיקומים האזוריים והמיקומים במספר אזורים של BigQuery.

תמחור

החיובים על פונקציות UDF ב-Python מתבצעים באמצעות המק"ט של שירותי BigQuery.

החיובים כוללים:

  • יצירה או יצירה מחדש של קובץ האימג' של קונטיינר ה-UDF. החיוב הזה הוא יחסי למשך הזמן שנדרש כדי ליצור את קובץ האימג' התואם עם קוד הלקוח והתלויות.

    • אם אתם משתמשים ב-Routines API, משך ה-build האחרון מופיע בשדה BuildStatus. אפשר גם לראות את משך ה-build בעמודה BuildStatus בתצוגה INFORMATION_SCHEMA.ROUTINES.
    • כדי לראות את העלות הכוללת של גרסאות ה-build לכל פרויקט, אפשר לסנן את דוח החיוב לפי:
      • מפתח: goog-bq-feature-type
      • ערך: MANAGED_ROUTINE_BUILD
  • לקוחות שמשתמשים בפונקציות UDF ב-Python מחויבים גם בעלות של הפעלת פונקציית UDF ב-Python. החיוב הזה הוא יחסי לכמות המחשוב והזיכרון שנצרכים כשמפעילים את ה-UDF ב-Python.

    • כדי לראות את העלויות של פונקציות UDF ב-Python לכל שאילתה, אתם יכולים לשלוח שאילתה לשדה ExternalServiceCosts באמצעות Job API. אפשר גם לראות את העלויות לכל שאילתה בעמודה external_service_costs בתצוגה INFORMATION_SCHEMA.JOBS, ולהחיל את המסנן הבא: 'external_service_costs.external_service="MANAGED_ROUTINE_EXECUTION"'.
    • כדי לראות את העלות הכוללת של הפעלת פונקציות Python UDF לכל פרויקט, אפשר לסנן את דוח החיוב לפי:
      • מפתח: goog-bq-feature-type
      • ערך: MANAGED_ROUTINE_EXECUTION
  • אם פונקציות UDF ב-Python גורמות לתעבורת נתונים יוצאת לרשת חיצונית או לאינטרנט, תראו גם חיוב על תעבורת נתונים לאינטרנט במסלול פרימיום, על סמך המק"טים של תעבורת נתונים יוצאת ב-BigQuery.

מכסות

מכסות ומגבלות של פונקציות UDF