עבודה עם פונקציות מרוחקות

אתם יכולים להשתמש בפונקציות משירותים חיצוניים של BigQuery כדי להטמיע פונקציות בהתאמה אישית באמצעות שפות, ספריות או שירותים שלא נתמכים בפונקציות בהגדרת המשתמש (UDF) רגילות. אתם יכולים לפרוס את הפונקציות המרוחקות ב-Cloud Run או בפונקציות Cloud Run כדי להפעיל אותן ישירות מהשאילתות ב-GoogleSQL.

תהליך עבודה

  1. יוצרים את נקודת הקצה ל-HTTP בפונקציות Cloud Run או ב-Cloud Run.
  2. יוצרים פונקציה מרוחקת ב-BigQuery.
    1. יוצרים חיבור מסוג CLOUD_RESOURCE.
    2. יוצרים פונקציה מרוחקת.
  3. משתמשים בפונקציה המרוחקת בשאילתה, בדיוק כמו בכל פונקציה בהגדרת המשתמש (UDF) אחרת.

מגבלות

  • פונקציות מרוחקות תומכות רק באחד מסוגי הנתונים הבאים כסוג ארגומנט או כסוג החזרה:

    • בוליאני
    • בייטים
    • Numeric
    • String
    • תאריך
    • תאריך ושעה
    • שעה
    • חותמת הזמן
    • JSON

    פונקציות מרוחקות לא תומכות בסוגים ARRAY,‏ STRUCT,‏ INTERVAL או GEOGRAPHY.

  • אי אפשר ליצור פונקציות מרוחקות עם ערכי טבלה.

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

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

  • יכול להיות שתראו בקשות חוזרות עם אותם נתונים לנקודת הקצה, גם אחרי תגובות מוצלחות, בגלל שגיאות זמניות ברשת או שגיאות פנימיות ב-BigQuery.

  • כשמדלגים על הערכה של פונקציה מרוחקת בשורות מסוימות בגלל קצר חשמלי, למשל בביטויים מותנים או בהצהרת MERGE עם WHEN [NOT] MATCHED, לא נעשה שימוש באצווה עם הפונקציה המרוחקת. במקרה הזה, השדה calls בגוף בקשת ה-HTTP מכיל בדיוק רכיב אחד.

  • אם קבוצת הנתונים שמשויכת לפונקציה המרוחקת משוכפלת לאזור יעד באמצעות שכפול של קבוצת נתונים בין אזורים, אפשר לשלוח שאילתות לפונקציה המרוחקת רק באזור שבו היא נוצרה.

  • פונקציות מרוחקות תומכות בנתיב מותאם אישית בכתובת ה-URL של נקודת הקצה. לנתיבים בהתאמה אישית יש את המגבלות הבאות:

    • הנתיב יכול להכיל רק אותיות רישיות (A-Z), אותיות קטנות (a-z), ספרות (0-9), מקפים (-) וקווים תחתונים (_).
    • אסור להשתמש במזהי מקטעים (#), בפרמטרים של שאילתות (?) ובטילדות (~).
    • אסור להשתמש בנתיבים שמתחילים ב-/_ah/, בנתיב הספציפי /eventlog ובכל נתיב שמסתיים באות z.

יצירת נקודת קצה (endpoint)

כדי ליצור פונקציה מרוחקת שיכולה להטמיע לוגיקה עסקית, צריך ליצור נקודת קצה (endpoint) מסוג HTTP באמצעות פונקציות Cloud Run או Cloud Run. נקודת הקצה צריכה להיות מסוגלת לעבד קבוצה של שורות בבקשת POST אחת, ולהחזיר את התוצאות של הקבוצה כתגובת HTTP. פונקציות מרוחקות תומכות בנתיב בהתאמה אישית בכתובת ה-URL של נקודת הקצה (ראו מגבלות).

אם אתם יוצרים את הפונקציה המרוחקת באמצעות BigQuery DataFrames, אתם לא צריכים ליצור ידנית את נקודת הקצה של ה-HTTP. השירות עושה את זה בשבילכם באופן אוטומטי.

במדריך של פונקציות Cloud Run ובמסמכי התיעוד של פונקציות Cloud Run מוסבר איך לכתוב, לפרוס, לבדוק ולתחזק פונקציית Cloud Run.

במדריך למתחילים של Cloud Run ובמסמכי תיעוד אחרים של Cloud Run מוסבר איך לכתוב, לפרוס, לבדוק ולתחזק שירות של Cloud Run.

מומלץ להשאיר את האימות שמוגדר כברירת מחדל, ולא לאפשר הפעלה ללא אימות של פונקציית Cloud Run או של שירות Cloud Run.

פורמט הקלט

‫BigQuery שולח בקשות HTTP POST עם גוף JSON בפורמט הבא:

שם השדה תיאור סוג השדה
requestId מזהה הבקשה. ייחודית לכמה בקשות שנשלחות לנקודת הקצה הזו בשאילתת GoogleSQL. תמיד מסופק. מחרוזת.
פונקציית קריאה חוזרת (caller) השם המלא של משאב המשימה לשאילתת GoogleSQL שקוראת לפונקציה המרוחקת. תמיד מסופק. מחרוזת.
sessionUser כתובת האימייל של המשתמש שמריץ את שאילתת GoogleSQL. תמיד מסופק. מחרוזת.
userDefinedContext ההקשר שהוגדר על ידי המשתמש ושימש ליצירת הפונקציה המרוחקת ב-BigQuery. זה שינוי אופציונלי. אובייקט JSON עם צמדי מפתח/ערך.
שיחות אצווה של נתוני קלט. תמיד מסופק. מערך JSON.

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

דוגמה לבקשה:

{
 "requestId": "124ab1c",
 "caller": "//bigquery.googleapis.com/projects/myproject/jobs/myproject:US.bquxjob_5b4c112c_17961fafeaf",
 "sessionUser": "test-user@test-company.com",
 "userDefinedContext": {
  "key1": "value1",
  "key2": "v2"
 },
 "calls": [
  [null, 1, "", "abc"],
  ["abc", "9007199254740993", null, null]
 ]
}

פורמט הפלט

‫BigQuery מצפה שנקודת הקצה תחזיר תגובת HTTP בפורמט הבא, אחרת BigQuery לא יוכל לצרוך אותה והשאילתה שקוראת לפונקציה המרוחקת תיכשל.

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

כל רכיב תואם לערך החזרה בקידוד JSON של הפונקציה החיצונית.

גודל המערך חייב להתאים לגודל של מערך ה-JSON של calls בבקשת ה-HTTP. לדוגמה, אם במערך ה-JSON ב-calls יש 4 רכיבים, גם במערך ה-JSON הזה צריכים להיות 4 רכיבים.

errorMessage הודעת שגיאה שמוצגת כשמוחזר קוד תגובת HTTP שונה מ-200. בשגיאות שלא ניתן לנסות שוב, אנחנו מחזירים את השגיאה למשתמש כחלק מהודעת השגיאה של המשימה ב-BigQuery. זה שינוי אופציונלי. מחרוזת. הגודל צריך להיות קטן מ-1KB.

דוגמה לתגובה מוצלחת:

{
  "replies": [
    1,
    0
  ]
}

דוגמה לתגובה שנכשלה:

{
  "errorMessage": "Received but not expected that the argument 0 be null".
}

קוד תגובת HTTP

נקודת הקצה צריכה להחזיר את קוד התגובה 200 של תגובת HTTP כדי לציין שהתגובה תקינה. אם BigQuery מקבל ערך אחר, הוא מתייחס לתגובה כאל כשל ומנסה שוב כשהקוד של תגובת ה-HTTP הוא 408, ‏ 429, ‏ 500, ‏ 503 או 504, עד למגבלה פנימית מסוימת.

קידוד JSON של סוג נתונים ב-SQL

קידוד JSON בבקשת HTTP ובתגובה פועל לפי קידוד ה-JSON הקיים של BigQuery עבור הפונקציה TO_JSON_STRING.

קוד לדוגמה של פונקציית Cloud Run

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

import functions_framework

from flask import jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
# See https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_encodings
_MAX_LOSSLESS=9007199254740992

@functions_framework.http
def batch_add(request):
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return_json = jsonify( { "replies":  replies } )
    return return_json
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

נניח שהפונקציה נפרסה בפרויקט my_gcf_project באזור us-east1 בתור שם הפונקציה remote_add, אפשר לגשת אליה באמצעות נקודת הקצה https://us-east1-my_gcf_project.cloudfunctions.net/remote_add.

קוד לדוגמה של Cloud Run

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

import os

from flask import Flask, request, jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
# See https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_encodings
_MAX_LOSSLESS=9007199254740992

app = Flask(__name__)

@app.route("/", methods=['POST'])
def batch_add():
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return jsonify( { "replies" :  replies } )
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

במדריך מוסבר איך ליצור ולפרוס את הקוד.

נניח שהשירות של Cloud Run נפרס בפרויקט my_gcf_project באזור us-east1 בתור שם השירות remote_add. אפשר לגשת אליו באמצעות נקודת הקצה https://remote_add-<project_id_hash>-ue.a.run.app.

בדוגמה הבאה ב-Python, מיושם נתיב כתובת URL אחר /subtract_list (ראו מגבלות על נתיב כתובת ה-URL בהתאמה אישית) בשירות האינטרנט שנפרס קודם:

@app.route("/subtract_list", methods=['POST'])
def batch_subtract():
  """
  Processes batch requests to subtract numbers within inner lists (e.g., a - b - c).
  Handles integers, string representations of integers, and None values.
  """
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      nums_to_process = [int(x) if isinstance(x, str) else x for x in call if x is not None]
      if not nums_to_process:
        result = 0
      else:
        result = nums_to_process[0] - sum(nums_to_process[1:])
      return_value.append(result)
    replies = [str(x) if abs(x) > _MAX_LOSSLESS else x for x in return_value]
    return jsonify({"replies": replies})
  except Exception as e:
    return jsonify({"errorMessage": str(e)}), 400

יצירת פונקציה מרוחקת

‫BigQuery משתמש בחיבור CLOUD_RESOURCE כדי לקיים אינטראקציה עם פונקציית Cloud Run. כדי ליצור פונקציה מרוחקת, צריך ליצור חיבור CLOUD_RESOURCE. אם אתם יוצרים את הפונקציה המרוחקת באמצעות BigQuery DataFrames וקיבלתם את התפקיד "אדמין IAM בפרויקט" (roles/resourcemanager.projectIamAdmin), אתם לא צריכים ליצור את החיבור באופן ידני ולתת לו גישה. השירות עושה את זה בשבילכם באופן אוטומטי.

יצירת חיבור

כדי להתחבר לפונקציית Cloud Run ול-Cloud Run, צריך קישור למשאבים ב-Cloud.

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

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

המסוף

  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. ‫לוחצים על Run.

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

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."}
    

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.

הגדרת הגישה

אתם צריכים לתת לחיבור החדש הרשאת קריאה בלבד לפונקציית Cloud Run או לשירות Cloud Run. לא מומלץ לאפשר הפעלה ללא אימות של פונקציית Cloud Run או של שירות Cloud Run.

כדי להקצות תפקידים:

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

    כניסה לדף IAM & Admin

  2. לוחצים על הוספה.

    תיבת הדו-שיח Add principals נפתחת.

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

  4. בשדה Select a role, בוחרים אחת מהאפשרויות הבאות:

    • אם משתמשים בפונקציית Cloud Run מהדור הראשון, בוחרים באפשרות Cloud Function ואז בוחרים בתפקיד Cloud Function Invoker.
    • אם משתמשים בפונקציית Cloud Run מהדור השני, בוחרים באפשרות Cloud Run ואז בוחרים בתפקיד Cloud Run Invoker.
    • אם אתם משתמשים בשירות של Cloud Run, בחרו באפשרות Cloud Run ואז בתפקיד Cloud Run Invoker.
  5. לוחצים על Save.

יצירת פונקציה מרוחקת

כדי ליצור פונקציה מרוחקת:

SQL

מריצים את ההצהרה הבאה של CREATE FUNCTION ב-BigQuery:

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

    כניסה ל-BigQuery

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

    CREATE FUNCTION PROJECT_ID.DATASET_ID.remote_add(x INT64, y INT64) RETURNS INT64
    REMOTE WITH CONNECTION PROJECT_ID.LOCATION.CONNECTION_NAME
    OPTIONS (
      endpoint = 'ENDPOINT_URL'
    )

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

    • ‫DATASET_ID: המזהה של מערך הנתונים ב-BigQuery.
    • ‫ENDPOINT_URL: כתובת ה-URL של פונקציית Cloud Run או של נקודת הקצה של הפונקציה המרוחקת של Cloud Run. פונקציות מרוחקות תומכות בנתיב מותאם אישית בכתובת ה-URL של נקודת הקצה (ראו מגבלות של נתיב מותאם אישית). אפשר ליצור פונקציות מרוחקות שונות בכל נתיב באותה אפליקציה. האפשרות endpoint בהצהרה CREATE FUNCTION יכולה לכלול נתיב מסלול מיד אחרי כתובת ה-URL של Cloud Run (לדוגמה, https://service_name-project_number.region.run.app/subtract_list).

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

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

BigQuery DataFrames

  1. מפעילים את ממשקי ה-API הנדרשים ומוודאים שקיבלתם את התפקידים הנדרשים, כפי שמתואר בקטע דרישות במאמר פונקציות מרוחקות.
  2. משתמשים במעצב remote_function.

צריכה להיות לכם ההרשאה bigquery.routines.create במערך הנתונים שבו אתם יוצרים את הפונקציה המרוחקת, וההרשאה bigquery.connections.delegate (זמינה מהתפקיד "אדמין של חיבורי BigQuery") בחיבור שבו משתמשת הפונקציה המרוחקת.

הצגת הקשר שהמשתמש הגדיר

אפשר לציין את user_defined_context ב-OPTIONS כצמדים של מפתח/ערך, שיהיו חלק מכל בקשת HTTP לנקודת הקצה. באמצעות הקשר בהגדרת המשתמש, אתם יכולים ליצור כמה פונקציות מרוחקות אבל להשתמש שוב בנקודת קצה אחת, שמספקת התנהגויות שונות על סמך ההקשר שמועבר אליה.

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

CREATE FUNCTION `PROJECT_ID.DATASET_ID`.encrypt(x BYTES)
RETURNS BYTES
REMOTE WITH CONNECTION `PROJECT_ID.LOCATION.CONNECTION_NAME`
OPTIONS (
  endpoint = 'ENDPOINT_URL',
  user_defined_context = [("mode", "encryption")]
)

CREATE FUNCTION `PROJECT_ID.DATASET_ID`.decrypt(x BYTES)
RETURNS BYTES
REMOTE WITH CONNECTION `PROJECT_ID.LOCATION.CONNECTION_NAME`
OPTIONS (
  endpoint = 'ENDPOINT_URL',
  user_defined_context = [("mode", "decryption")]
)

הגבלת מספר השורות בבקשת Batch

כדי למנוע זמן קצוב לתפוגה של פונקציות Cloud Run, אפשר לציין את הערך max_batching_rows ב-OPTIONS כמספר המקסימלי של שורות בכל בקשת HTTP. אם מציינים את הערך max_batching_rows, המערכת של BigQuery קובעת את מספר השורות באצווה עד למגבלה של max_batching_rows. אם לא מציינים את הפרמטר, BigQuery קובע את מספר השורות לכל אצווה באופן אוטומטי.

שימוש בפונקציה מרוחקת בשאילתה

חשוב לוודא שנתתם את ההרשאה לפונקציית Cloud Run, כדי שלחשבון השירות של BigQuery שמשויך לחיבור של הפונקציה המרוחקת תהיה גישה אליה.

בנוסף, צריכה להיות לכם ההרשאה bigquery.routines.get במערך הנתונים שבו נמצאת הפונקציה המרוחקת, וההרשאה bigquery.connections.use בחיבור שבו משתמשת הפונקציה המרוחקת, שאותה אפשר לקבל באמצעות התפקיד BigQuery Connection User.

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

לדוגמה, אפשר להשתמש בפונקציה remote_add בשאילתה לדוגמה:

SELECT
  val,
  `PROJECT_ID.DATASET_ID`.remote_add(val, 2)
FROM
  UNNEST([NULL,2,3,5,8]) AS val;

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

+------+-----+
|  val | f0_ |
+------+-----+
| NULL |   2 |
|    2 |   4 |
|    3 |   5 |
|    5 |   7 |
|    8 |  10 |
+------+-----+

אזורים נתמכים

יש שני סוגים של מיקומים ב-BigQuery:

  • השדה הזה יכול להכיל אזור, כלומר, מקום גיאוגרפי ספציפי, כמו לונדון.

  • מספר אזורים – אזור גיאוגרפי נרחב, כמו ארצות הברית, שכולל שני מקומות גיאוגרפיים או יותר.

אזורים בודדים

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

  • פונקציה מרוחקת באזור יחיד us-east4 ב-BigQuery יכולה להשתמש רק בפונקציית Cloud Run באזור us-east4.

לכן, באזורים בודדים, פונקציות מרוחקות נתמכות רק באזורים שתומכים גם בפונקציות Cloud Run וגם ב-BigQuery.

במספר אזורים

במערך נתונים של BigQuery במספר אזורים (US, EU), אפשר ליצור פונקציה מרוחקת רק אם היא משתמשת בפונקציית Cloud Run שנפרסה באזור שנמצא באותו שטח גיאוגרפי גדול (ארה"ב, האיחוד האירופי). לדוגמה:

  • פונקציה מרוחקת ב-BigQuery במספר אזורים US יכולה להשתמש רק בפונקציית Cloud Run שנפרסה באזור אחד בארה"ב, כמו us-central1,‏ us-east4,‏ us-west2 וכו'.
  • פונקציה מרוחקת ב-BigQuery במספר אזורים ב-EU יכולה להשתמש רק בפונקציית Cloud Run שנפרסה באזור אחד במדינות החברות באיחוד האירופי, כמו europe-north1,‏ europe-west3 וכו'.

למידע נוסף על אזורים ומספר אזורים ב-BigQuery, קראו את הדף מיקומי מערכי נתונים. מידע נוסף על אזורים של פונקציות Cloud Run מופיע בדף מיקומים של פונקציות Cloud Run.

חיבורים

במיקום באזור יחיד או במיקום במספר אזורים, אפשר ליצור פונקציה מרוחקת רק באותו מיקום של החיבור שבו משתמשים. לדוגמה, כדי ליצור פונקציה מרוחקת ב-US במספר אזורים, צריך להשתמש בחיבור שנמצא ב-US במספר אזורים.

תמחור

שימוש ב-VPC Service Controls

VPC Service Controls הוא מאפיין של Google Cloud שמאפשר להגדיר מתחם אבטחה היקפית כדי להגן מפני זליגת נתונים. כדי להשתמש ב-VPC Service Controls עם פונקציות מרוחקות לאבטחה נוספת, או כדי להשתמש בנקודות קצה עם הגדרות תעבורת נתונים נכנסת (ingress) של internal traffic, פועלים לפי המדריך של VPC Service Controls כדי:

  1. יוצרים גבולות גזרה לשירות.

  2. מוסיפים להיקף את פרויקט BigQuery של השאילתה שמשתמשת בפונקציה המרוחקת.

  3. מוסיפים את הפרויקט של נקודת הקצה להיקף ההגנה ומגדירים את Cloud Functions API או את Cloud Run API בשירותים המוגבלים, בהתאם לסוג של נקודת הקצה. פרטים נוספים זמינים במאמרים VPC Service Controls בפונקציות Cloud Run ו-VPC Service Controls ב-Cloud Run.

שיטות מומלצות לשימוש בפונקציות מרוחקות

  • סינון מראש של הקלט: אם אתם יכולים לסנן את הקלט לפני שאתם מעבירים אותו לפונקציה מרוחקת, סביר להניח שהשאילתה תהיה מהירה וזולה יותר.
  • שמירה על פונקציית Cloud Run ניתנת להתאמה. יכולת ההתאמה לעומס היא פונקציה של מספר המכונות המינימלי, מספר המכונות המקסימלי והבו-זמניות.

    • אם אפשר, השתמשו בערך ברירת המחדל של המספר המקסימלי של מכונות לפונקציית Cloud Run.
    • שימו לב שאין מגבלת ברירת מחדל לפונקציות Cloud Run מסוג HTTP מהדור הראשון. כדי למנוע אירועי התרחבות בלתי מוגבלים עם פונקציות Cloud Run מסוג HTTP מהדור הראשון במהלך בדיקה או בסביבת הייצור, מומלץ להגדיר מגבלה, למשל 3, 000.
  • כדי לשפר את הביצועים, כדאי לפעול לפי הטיפים הנוספים לפונקציות Cloud Run. שאילתות של פונקציות מרוחקות שמקיימות אינטראקציה עם פונקציית Cloud Run עם זמן אחזור ארוך עלולות להיכשל בגלל זמן קצוב לתפוגה.

  • מטמיעים את נקודת הקצה (endpoint) כך שתחזיר קוד תגובה של HTTP ומטען ייעודי (payload) מתאימים לתגובה שנכשלה.

    • כדי לצמצם את מספר הניסיונות החוזרים מ-BigQuery, השתמשו בקודי תגובה של HTTP שאינם 408, ‏ 429, ‏ 500, ‏ 503 ו-504 לתגובה שנכשלה, וודאו שאתם תופסים את כל החריגות בקוד הפונקציה. אחרת, יכול להיות שמסגרת שירות ה-HTTP תחזיר באופן אוטומטי את הקוד 500 לכל חריגה שלא נתפסה. יכול להיות שעדיין תראו בקשות HTTP חוזרות כש-BigQuery מנסה שוב לבצע שאילתה או מחיצה של נתונים שנכשלו.

    • נקודת הקצה צריכה להחזיר מטען ייעודי (payload) של JSON בפורמט שהוגדר לתגובה שנכשלה. למרות שזה לא חובה, זה עוזר ל-BigQuery להבחין אם התגובה שנכשלה היא מההטמעה של הפונקציה או מהתשתית של פונקציות Cloud Run או Cloud Run. במקרה השני, יכול להיות ש-BigQuery ינסה שוב עם מגבלה פנימית אחרת.

מכסות

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

המספר המקסימלי של שאילתות בו-זמניות שמכילות פונקציות מרוחקות

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

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

הודעת שגיאה

Exceeded rate limits: too many concurrent queries with remote functions for
this project

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

האבחון

במאמר מגבלות של פונקציות מרוחקות מפורטות המגבלות על שאילתות בו-זמניות שמכילות פונקציות מרוחקות.

רזולוציה

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