1. Wprowadzenie
SQL (Structured Query Language) to standardowy język używany w branży do analizy hurtowni danych. Wyrażanie złożonej logiki proceduralnej, obliczeń matematycznych, czyszczenia tekstu lub przepływów pracy związanych z przygotowywaniem danych do uczenia maszynowego w czystym SQL może być jednak bardzo trudne.
Gdy wymagane było złożone niestandardowe przetwarzanie w Pythonie, zespoły zajmujące się danymi zwykle wyodrębniały ogromne zbiory danych z BigQuery, przetwarzały je na zewnętrznych niestandardowych maszynach wirtualnych lub w klastrach i wczytywały wyniki z powrotem. Takie podejście powoduje duże opóźnienia w sieci, zwiększa ryzyko niezgodności z przepisami przez przenoszenie danych i generuje dodatkowe koszty związane z zarządzaniem infrastrukturą.
Zarządzane przez BigQuery funkcje zdefiniowane przez użytkownika (UDF) w Pythonie rozwiązują te problemy, ponieważ uruchamiają niestandardowy kod na zasobach bezserwerowych, które automatycznie skalują się do milionów wierszy. Google Cloud zarządza kompilacją, tworzeniem obrazów, stosowaniem poprawek zabezpieczeń i wykonywaniem kodu, co pozwala uruchamiać niestandardowe obliczenia bezpośrednio w miejscu przechowywania danych.
W tym ćwiczeniu utworzysz potok analizy i wstępnego przetwarzania tekstu na podstawie danych społeczności StackOverflow, przygotowując je do raportowania i uczenia maszynowego.
Wymagania wstępne
- Projekt Google Cloud z włączonymi płatnościami.
- Podstawowa wiedza na temat SQL, IAM i BigQuery.
Czego się nauczysz
- Jak wywoływać wstępnie skompilowaną publiczną funkcję UDF w Pythonie w publicznym zbiorze danych, aby analizować rozkłady danych.
- Jak wdrożyć własną niestandardową funkcję UDF w Pythonie za pomocą biblioteki
beautifulsoup4do czyszczenia danych nieustrukturyzowanych. - Jak skonfigurować połączenie z zasobem Cloud BigQuery, aby bezpiecznie pobierać zasoby uczenia maszynowego i wykonywać lokalną tokenizację ML za pomocą biblioteki Hugging Face Transformers z użyciem pamięci podręcznej kontenera.
- Jak połączyć te kroki w jeden wydajny potok SQL.
2. Konfiguracja i wymagania
Uruchamianie Cloud Shell
Chociaż Google Cloud można obsługiwać zdalnie z laptopa, w tym ćwiczeniu będziesz używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
- Otwórz konsolę Google Cloud, a potem wybierz lub utwórz projekt w chmurze Google Cloud.
- ⚠️ Zapisz identyfikator projektu. Będziesz go używać w tym ćwiczeniu.

- Otwórz Cloud Shell na nowej karcie: https://shell.cloud.google.com/.
- Jeśli pojawi się pytanie o autoryzację, kliknij Autoryzuj.
- Zastąp
PROJECT_IDi wklej to polecenie w terminalu:
cat << 'EOF' > env.sh
#!/bin/bash
# env.sh: Environment variables for BigQuery Python UDFs codelab
# ⚠️ Replace 'YOUR_PROJECT_ID' with your actual Google Cloud Project ID
export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="us"
export BQ_DATASET="python_udfs"
export BQ_RESOURCE_CONN="external_api_connection"
EOF
Zastosuj zmienne do aktywnej sesji:
source ./env.sh
Włączanie interfejsów API i tworzenie zbioru danych BigQuery
Włącz w projekcie niezbędne usługi Google Cloud i utwórz docelowy zbiór danych:
# Enable API Services
gcloud services enable \
bigquery.googleapis.com \
bigqueryconnection.googleapis.com --quiet
# Create BigQuery Dataset
bq mk --location=${REGION} --dataset ${PROJECT_ID}:${BQ_DATASET}
3. Analizowanie rozkładów danych za pomocą publicznej funkcji UDF w Pythonie
Zanim wdrożysz niestandardowy kod, warto zapoznać się ze zbiorem danych i odfiltrować szumy o niskiej jakości. W tym kroku przeanalizujesz pytania na StackOverflow, aby znaleźć aktywnych użytkowników i poznać statystyczny rozkład ich wyników.
Dlaczego warto użyć do tego funkcji UDF w Pythonie?
Obliczanie wielu dokładnych percentyli (np. 25., 50., 75. i 95.) w pogrupowanych tablicach danych jest złożone i wymaga dużych zasobów w czystym SQL. Standardowe funkcje analityczne standardowej wersji SQL, takie jak PERCENTILE_CONT, oczekują płaskich kolumn wierszy, a nie zagnieżdżonych tablic. Aby obliczyć dokładne percentyle wstępnie zagregowanych tablic w każdym wierszu, musisz napisać obszerne podzapytania, które rozpakowują, sortują i ponownie agregują dane dla każdego wskaźnika percentyla, co jest nieefektywne.
Używając NumPy, czyli wysoce zoptymalizowanej biblioteki naukowej Pythona w funkcji UDF, możesz obliczyć dokładne percentyle matematyczne w tablicy liczb za pomocą jednego wiersza kodu.
Wykonanie
Google Cloud hostuje kilka wstępnie skompilowanych publicznych funkcji UDF (kliknij kartę Procedury). Ponieważ BigQuery wymaga dokładnego dopasowania typów, użyjemy wyrażenia CTE (Common Table Expression), aby wstępnie zagregować dane i przekształcić tablice liczb całkowitych w tablice reprezentacji zmiennoprzecinkowej za pomocą wyrażenia UNNEST.
Uruchom to zapytanie w konsoli BigQuery Studio:
WITH raw_user_scores AS (
-- 1. Pre-aggregate user scores into an array
SELECT
owner_user_id,
ARRAY_AGG(score) AS scores
FROM
`bigquery-public-data.stackoverflow.posts_questions`
WHERE
owner_user_id IS NOT NULL
GROUP BY
owner_user_id
HAVING
ARRAY_LENGTH(scores) >= 5
LIMIT 5
)
SELECT
owner_user_id,
scores,
-- 2. Cast arrays to FLOAT64 and call the public percentile Python UDF
`bigquery-public-data.python_udfs.percentiles`(
ARRAY(SELECT CAST(s AS FLOAT64) FROM UNNEST(scores) AS s),
[25.0, 50.0, 75.0, 95.0]
) AS score_percentiles
FROM
raw_user_scores;
Dzięki temu możesz od razu poznać wydajność użytkowników bez konieczności konfigurowania uprawnień ani pisania niestandardowego kodu w Pythonie.
Sprawdzanie wyników
Ponieważ to zapytanie zwraca zagnieżdżone typy tablic (scores i score_percentiles), domyślna tabela Wyniki w BigQuery Studio może wyświetlać spłaszczone lub obcięte dane wyjściowe, co utrudnia sprawdzanie elementów tablicy.
Aby wyświetlić uporządkowane, zagnieżdżone dane wyjściowe:
- W panelu wyników zapytania znajdź pasek kart (domyślnie jest to Wyniki).
- Kliknij kartę JSON.
Powinna się wyświetlić uporządkowana tablica JSON reprezentująca wiersze, podobna do tej:
[{
"owner_user_id": "533463",
"scores": ["0", "0", "-1", "0", "0", "2", "-1", "1", "0", "0", "-1", "0", "-3", "1", "1", "0", "1", "2", "3", "1", "0", "0", "1", "0", "0", "3", "6", "11", "0", "1", "0", "0", "3", "17", "0", "1", "1", "3", "5", "-2", "1", "-1", "-1", "2", "3", "0", "0", "0", "5", "0", "4", "0", "0", "0", "3", "3", "0", "140", "0", "1", "3", "0", "0", "-2", "-1", "0", "0", "2", "0", "9", "9", "0", "0", "1", "0", "0", "1", "-1", "0", "0", "0", "0"],
"score_percentiles": ["0.0", "0.0", "1.75", "8.8500000000000085"]
}, {
"owner_user_id": "13502536",
"scores": ["0", "1", "0", "-5", "0", "1", "0", "1", "0", "0", "-2", "0", "1", "0", "1", "0", "0", "1", "0", "1", "0", "0"],
"score_percentiles": ["0.0", "0.0", "1.0", "1.0"]
}, {
"owner_user_id": "1170153",
"scores": ["1", "0", "1", "0", "1", "0", "2", "0", "0", "0", "10", "5", "1", "0", "0", "2", "0", "2", "3", "-1", "1", "0", "1", "0", "0", "1", "0", "2", "0", "4", "0", "3", "0", "0", "2", "0", "0", "1", "0"],
"score_percentiles": ["0.0", "0.0", "1.5", "4.1000000000000014"]
}, {
"owner_user_id": "8558174",
"scores": ["0", "0", "-1", "1", "2", "0"],
"score_percentiles": ["0.0", "0.0", "0.75", "1.75"]
}, {
"owner_user_id": "1073044",
"scores": ["0", "1", "0", "0", "2", "2", "2", "1", "1", "1", "2", "1", "0", "2", "3", "1"],
"score_percentiles": ["0.75", "1.0", "2.0", "2.25"]
}]
Interpretowanie danych wyjściowych
scores: pełna tablica surowych wyników pytań opublikowanych przez każdego unikalnego użytkownika.score_percentiles: tablica zawierająca 4 obliczone wartości zmiennoprzecinkowe. Odpowiadają one dokładnie żądanym percentylom:[25th, 50th, 75th, and 95th]. Na przykład w przypadku użytkownika53346395. percentyl wyniku jego pytań wynosi około8.85, co oznacza, że jego najlepsze pytania mają wysokie wyniki.
4. Natywne czyszczenie tekstu przez utworzenie niestandardowej funkcji UDF
Gdy zidentyfikujemy docelowych użytkowników, chcemy przeanalizować treść ich postów. Surowe posty na forum często zawierają jednak nieuporządkowane tagi i encje HTML. Musimy je usunąć, aby poprawić czytelność i zmniejszyć koszty modelu.
Aby zrozumieć, dlaczego jest to konieczne, najpierw sprawdźmy, jak wygląda surowa, niesformatowana treść posta na Stack Overflow. Uruchom to zapytanie w konsoli BigQuery Studio:
SELECT
id,
title,
body AS raw_html_body
FROM
`bigquery-public-data.stackoverflow.posts_questions`
-- Check specific questions that we will use in our final pipeline
WHERE
id IN (9, 17, 33969)
ORDER BY
id ASC;
Jeśli przyjrzysz się danym wyjściowym, zobaczysz w tekście tagi formatowania, takie jak <p>, <b>, <code> i inne. Przetwarzanie ich bezpośrednio za pomocą tokenizatorów uczenia maszynowego spowoduje niepotrzebne szumy i sztucznie zwiększy koszty pozyskiwania tokenów.
Dlaczego warto użyć do tego funkcji UDF w Pythonie?
Niezawodne analizowanie kodu HTML za pomocą wyrażeń regularnych w czystym SQL jest trudne i podatne na błędy. Uruchamianie niezawodnej biblioteki Pythona, takiej jak beautifulsoup4, bezpośrednio w zapytaniach zapewnia niezawodny sposób usuwania tagów.
Aby wdrożyć trwałą funkcję clean_html w zbiorze danych, uruchom to zapytanie DDL:
CREATE OR REPLACE FUNCTION `YOUR_PROJECT_ID.python_udfs.clean_html`(html_content STRING)
RETURNS STRING
LANGUAGE python
OPTIONS (
runtime_version = 'python-3.11',
entry_point = 'strip_tags',
packages = ['beautifulsoup4>=4.12.0']
) AS r'''
from bs4 import BeautifulSoup
def strip_tags(html_content):
if not html_content:
return ""
soup = BeautifulSoup(html_content, "html.parser")
return soup.get_text(separator=" ")
''';
Sprawdź dane wyjściowe funkcji za pomocą prostego zapytania:
SELECT `YOUR_PROJECT_ID.python_udfs.clean_html`('<p>Hello <b>world</b>!</p>') AS cleaned_text;
Powinien się wyświetlić tekst bez elementów HTML:
+----------------+
| cleaned_text |
+----------------+
| Hello world ! |
+----------------+
5. Bezpieczne integracje zewnętrzne i zaawansowane przetwarzanie ML
Gdy mamy już czysty tekst, musimy go przygotować do modeli uczenia maszynowego lub dużych modeli językowych (LLM), takich jak Gemma. LLM nie mogą bezpośrednio odczytywać surowego tekstu. Przetwarzają numeryczne identyfikatory tokenów.
Aby przekonwertować czysty tekst na tokeny, zaimportujemy bibliotekę transformers Hugging Face i wczytamy wstępnie wytrenowany tokenizator Google T5 bezpośrednio do bazy danych.
Tworzenie połączenia z zasobem Cloud
Aby nawiązać bezpieczne połączenie, uruchom to zapytanie w konsoli BigQuery Studio:
CREATE CONNECTION IF NOT EXISTS `YOUR_PROJECT_ID.us.external_api_connection`
OPTIONS (
connection_type = "CLOUD_RESOURCE",
friendly_name = "Hugging Face Hub Egress Connection",
description = "Connection used to securely download model configs from public ML hubs"
);
Tworzenie funkcji UDF tokenizatora
Teraz wdróż niestandardową funkcję UDF tokenizatora. Zwróć uwagę, jak funkcja pomocnicza get_tokenizer() sprawdza, czy zmienna globalna tokenizer jest już zainicjowana, zanim spróbuje pobrać:
CREATE OR REPLACE FUNCTION `YOUR_PROJECT_ID.python_udfs.tokenize`(text STRING)
RETURNS ARRAY<INT64>
LANGUAGE python
WITH CONNECTION `YOUR_PROJECT_ID.us.external_api_connection`
OPTIONS (
runtime_version = 'python-3.11',
entry_point = 'tokenize',
packages = ['transformers', 'sentencepiece']
) AS r'''
from transformers import T5TokenizerFast
# Initialize global variable for in-memory container caching
tokenizer = None
def get_tokenizer():
global tokenizer
if tokenizer is None:
# Securely download T5 tokenizer config from Hugging Face Hub (runs once per warm container)
tokenizer = T5TokenizerFast.from_pretrained("t5-base")
return tokenizer
def tokenize(text):
if not text:
return []
try:
t = get_tokenizer()
# Convert raw clean text into integer token IDs
return [int(x) for x in t.encode(text)]
except Exception:
return []
''';
Aby sprawdzić, czy tokenizator prawidłowo pobiera zasób i zwraca tablicę identyfikatorów liczb całkowitych, przetestuj go za pomocą prostego zapytania:
SELECT `YOUR_PROJECT_ID.python_udfs.tokenize`('Hello world!') AS token_ids;
Aby zobaczyć uporządkowaną tablicę, przełącz się na kartę JSON w panelu wyników zapytania:
[
{
"token_ids": ["8774", "296", "55", "1"]
}
]
6. Uruchamianie kompleksowego potoku wstępnego przetwarzania
Gdy wszystkie 3 kroki potoku są gotowe, możemy połączyć je w jedno zapytanie SQL za pomocą wyrażeń CTE (Common Table Expressions).
Ten potok reprezentuje nowoczesny proces inżynierii danych:
- Izoluj aktywnych użytkowników i ich pytania z najwyższymi wynikami za pomocą publicznej funkcji UDF percentyla.
- Usuń surowe formatowanie HTML z tekstu lokalnie za pomocą funkcji UDF clean_html.
- Przekonwertuj oczyszczony tekst na tablice tokenów za pomocą naszej funkcji UDF tokenize z pamięci podręcznej.
Uruchom to zapytanie potoku w konsoli BigQuery Studio:
WITH raw_user_scores AS (
-- Step 1: Pre-aggregate scores to safely run percentiles with deterministic ordering
SELECT
owner_user_id,
ARRAY_AGG(score ORDER BY id ASC) AS scores
FROM
`bigquery-public-data.stackoverflow.posts_questions`
WHERE
owner_user_id IS NOT NULL
GROUP BY
owner_user_id
HAVING
ARRAY_LENGTH(scores) >= 5
ORDER BY
owner_user_id ASC
LIMIT 3
),
active_users AS (
-- Step 1: Extract exact percentile limits using the public UDF)
SELECT
owner_user_id,
percentiles_arr AS score_percentiles,
-- Extract the 95th percentile score from the array's 4th element (OFFSET 3) directly
percentiles_arr[OFFSET(3)] AS p95_score
FROM (
SELECT
owner_user_id,
`bigquery-public-data.python_udfs.percentiles`(
ARRAY(SELECT CAST(s AS FLOAT64) FROM UNNEST(scores) AS s),
[25.0, 50.0, 75.0, 95.0]
) AS percentiles_arr
FROM
raw_user_scores
)
),
target_questions AS (
-- Isolate high-scoring questions from active users
SELECT
q.id,
q.owner_user_id,
q.title,
q.body AS raw_body,
u.score_percentiles
FROM
`bigquery-public-data.stackoverflow.posts_questions` q
JOIN
active_users u ON q.owner_user_id = u.owner_user_id
WHERE
-- Explicit cast for robust comparison
q.score >= CAST(u.p95_score AS FLOAT64)
),
cleaned_data AS (
-- Step 2: Clean HTML tags natively
SELECT
id,
owner_user_id,
title,
score_percentiles,
`YOUR_PROJECT_ID.python_udfs.clean_html`(raw_body) AS cleaned_body
FROM
target_questions
),
tokenized_data AS (
-- Step 3: Perform local ML tokenization on the clean preview text
SELECT
id,
owner_user_id,
title,
score_percentiles,
SUBSTR(cleaned_body, 1, 120) AS cleaned_body_preview,
`YOUR_PROJECT_ID.python_udfs.tokenize`(SUBSTR(cleaned_body, 1, 120)) AS token_ids
FROM
cleaned_data
)
SELECT
id,
owner_user_id,
title,
score_percentiles,
cleaned_body_preview AS cleaned_body,
token_ids,
ARRAY_LENGTH(token_ids) AS token_count
FROM
tokenized_data
ORDER BY
id ASC;
Aby sprawdzić uporządkowane dane wyjściowe, przełącz się na kartę JSON w BigQuery Studio.
[{
"id": "9",
"owner_user_id": "1",
"title": "How do I calculate someone\u0027s age based on a DateTime type birthday?",
"score_percentiles": ["22.5", "61.5", "346.75", "1762.0"],
"cleaned_body": "Given a DateTime representing a person\u0027s birthday, how do I calculate their age in years?",
"token_ids": ["9246", "3", "9", "7678", "13368", "9085", "3", "9", "568", "31", "7", "3591", "6", "149", "103", "27", "11837", "70", "1246", "16", "203", "58", "1"],
"token_count": "23"
}, {
"id": "17",
"owner_user_id": "2",
"title": "Binary Data in MySQL",
"score_percentiles": ["3.5", "10.0", "90.0", "184.09999999999997"],
"cleaned_body": "How do I store binary data in MySQL ?",
"token_ids": ["571", "103", "27", "1078", "14865", "331", "16", "27563", "3", "58", "1"],
"token_count": "11"
}, {
"id": "33969",
"owner_user_id": "3",
"title": "Best way to implement request throttling in ASP.NET MVC?",
"score_percentiles": ["3.25", "14.0", "24.75", "175.25"],
"cleaned_body": "We\u0027re experimenting with various ways to throttle user actions in a given time period : Limit question/answer posts Limi",
"token_ids": ["101", "31", "60", "3", "26718", "28", "796", "1155", "12", "28731", "1139", "2874", "16", "3", "9", "787", "97", "1059", "3", "10", "18185", "822", "87", "3247", "3321", "3489", "10908", "23", "1"],
"token_count": "29"
}]
7. Dodatek: jak działa potok i jak sprawdzać koszty wykonania
W tej sekcji szczegółowo opisujemy mechanizmy kompleksowego zapytania o wstępne przetwarzanie i pokazujemy, jak monitorować dokładne zużycie przedziałów i koszty zarządzanego kontenera.
Architektura potoku
WITH raw_user_scores AS (
SELECT
owner_user_id,
ARRAY_AGG(score ORDER BY id ASC) AS scores
FROM
`bigquery-public-data.stackoverflow.posts_questions`
WHERE
owner_user_id IS NOT NULL
GROUP BY
owner_user_id
HAVING
ARRAY_LENGTH(scores) >= 5
ORDER BY
owner_user_id ASC
LIMIT 3
)
Ten pierwszy segment zapytania zbiera surowe wyniki pytań aktywnych współtwórców Stack Overflow. Konsoliduje wyniki każdego użytkownika w jedną tablicę (ARRAY_AGG), jednocześnie wymuszając deterministyczny porządek sortowania (ORDER BY id). Zbiór danych jest filtrowany tak, aby zawierał tylko użytkowników, którzy zadali co najmniej 5 pytań, aby ustalić prawidłową statystyczną linię bazową.
active_users AS (
SELECT
owner_user_id,
percentiles_arr AS score_percentiles,
-- Extract the 95th percentile score from the array's 4th element (OFFSET 3) directly
percentiles_arr[OFFSET(3)] AS p95_score
FROM (
SELECT
owner_user_id,
`bigquery-public-data.python_udfs.percentiles`(
ARRAY(SELECT CAST(s AS FLOAT64) FROM UNNEST(scores) AS s),
[25.0, 50.0, 75.0, 95.0]
) AS percentiles_arr
FROM
raw_user_scores
)
)
Aby zidentyfikować najlepszych współtwórców, ten segment używa publicznej funkcji UDF w Pythonie percentiles do znajdowania dokładnych rozkładów wyników (25., 50., 75. i 95. percentyl). Aby uniknąć wielokrotnego wykonywania tej wymagającej obliczeń funkcji UDF, obliczenia są zawijane w zagnieżdżone podzapytanie. Wartość 95. percentyla jest następnie pobierana bezpośrednio z tablicy wynikowej na pozycji indeksu 3 (OFFSET(3)).
target_questions AS (
-- Isolate high-scoring questions from active users
SELECT
q.id,
q.owner_user_id,
q.title,
q.body AS raw_body,
u.score_percentiles
FROM
`bigquery-public-data.stackoverflow.posts_questions` q
JOIN
active_users u ON q.owner_user_id = u.owner_user_id
WHERE
-- Explicit cast for robust comparison
q.score >= CAST(u.p95_score AS FLOAT64)
)
Oryginalne pytania są łączone z listą aktywnych użytkowników, aby pobrać posty, które spełniają lub przekraczają próg 95. percentyla. Aby zapobiec błędom porównywania typów baz danych, wynik benchmarku jest przed oceną jawnie konwertowany za pomocą operacji CAST na typ FLOAT64.
cleaned_data AS (
-- Clean HTML tags natively
SELECT
id,
owner_user_id,
title,
score_percentiles,
`YOUR_PROJECT_ID.python_udfs.clean_html`(raw_body) AS cleaned_body
FROM
target_questions
)
Surowe treści postów często zawierają nieuporządkowane znaczniki i kod HTML, które pogarszają dane wejściowe uczenia maszynowego. Zamiast używać złożonych wyrażeń regularnych, potok wywołuje naszą niestandardową funkcję UDF w Pythonie clean_html. Dynamicznie uruchamia środowisko wykonawcze Pythona w izolowanym kontenerze, używając biblioteki BeautifulSoup do czystego usuwania elementów i generowania zwykłego, czytelnego tekstu.
tokenized_data AS (
-- Perform local ML tokenization on the clean preview text (called only once)
SELECT
id,
owner_user_id,
title,
score_percentiles,
SUBSTR(cleaned_body, 1, 120) AS cleaned_body_preview,
`YOUR_PROJECT_ID.python_udfs.tokenize`(SUBSTR(cleaned_body, 1, 120)) AS token_ids
FROM
cleaned_data
)
Aby przygotować podgląd czystego tekstu do pozyskiwania przez model generatywny, potok wywołuje naszą niestandardową funkcję UDF w Pythonie tokenize na 120-znakowym wycinku. Funkcja UDF bezpiecznie łączy się z centrum Hugging Face, aby pobrać parametry tokenizatora Google T5. Ponieważ instancja tokenizatora jest wczytywana do zmiennej globalnej, pamięć podręczna kontenera przechowuje konfigurację, co pozwala na szybką tokenizację w pamięci bez opóźnień w sieci.
SELECT
id,
owner_user_id,
title,
score_percentiles,
cleaned_body_preview AS cleaned_body,
token_ids,
ARRAY_LENGTH(token_ids) AS token_count
FROM
tokenized_data
ORDER BY
id ASC;
Ostatni blok zapytania generuje przetworzony zbiór danych. Zamiast ponownie wykonywać funkcję UDF tokenizacji, aby zliczyć wygenerowane tokeny, natywna funkcja BigQuery ARRAY_LENGTH jest stosowana bezpośrednio do wstępnie obliczonej tablicy token_ids. Ta strategia zmniejsza liczbę zbędnych cykli procesora, operacji na kontenerach i ogólnych kosztów wykonania.
Sprawdzanie zużycia przedziałów i kosztów zarządzanych funkcji UDF
Chociaż BigQuery wdraża kompleksowe panele informacyjne dotyczące widoczności kosztów bezpośrednio w interfejsie konsoli Google Cloud, inżynierowie mogą programowo sprawdzać dokładne zużycie przedziałów i koszty wykonania zarządzanych kontenerów w przypadku dowolnego zapytania za pomocą identyfikatorów zadań BigQuery.
Aby sprawdzić wykonanie zapytania, znajdź identyfikator zadania.
- W BigQuery Studio możesz go znaleźć, otwierając kartę Historia zapytań u dołu konsoli.
- Kliknij wykonane zapytanie potoku.
- W panelu szczegółów Informacje o zadaniu znajdź pole Identyfikator zadania.
Gdy znajdziesz czysty identyfikator zadania, zastąp JOB_ID w zapytaniu poniżej i uruchom je w BigQuery Studio:
SELECT
job_id,
total_slot_ms,
external_service_costs
FROM
`YOUR_PROJECT_ID.region-us`.INFORMATION_SCHEMA.JOBS
WHERE
job_id = "JOB_ID";
Aby sprawdzić uporządkowane dane wyjściowe, przełącz się na kartę JSON w BigQuery Studio. Powinien się wyświetlić ładunek podobny do tego:
[{
"job_id": "bquxjob_1234f5a_67ea8c9051a",
"total_slot_ms": "815459",
"external_service_costs": [{
"external_service": "MANAGED_ROUTINE_EXECUTION",
"bytes_processed": null,
"bytes_billed": null,
"slot_ms": "3000",
"reserved_slot_count": null,
"billing_method": "SERVICES_SKU"
}]
}]
Interpretowanie danych wyjściowych:
total_slot_ms: łączny czas obliczeń w milisekundach używany na wszystkich etapach zapytania. W przypadku tego ujednoliconego potoku wykonanie trwa zwykle około 815 tys. milisekund przedziałów.external_service_costs: tablica, która zawiera podział zasobów wykorzystywanych poza standardowym silnikiem analizy BigQuery.external_service: wartość „MANAGED_ROUTINE_EXECUTION” potwierdza, że koszt dotyczy konkretnie wykonania kontenera bezserwerowego, który hostuje nasze niestandardowe środowisko funkcji UDF w Pythonie.slot_ms: wartość „3000” reprezentuje dokładną liczbę milisekund specjalistycznych zasobów obliczeniowych zużytych w środowisku wykonawczym kontenera do wykonania logiki Pythona.billing_method: wartość „SERVICES_SKU” oznacza, że te zlokalizowane opłaty za kontener są naliczane dynamicznie za pomocą specjalistycznej jednostki SKU usług BigQuery na podstawie czasu wykonania kontenera i narzutu pamięci. Przy standardowej cenie zasobów obliczeniowych w regionie obejmującym wiele regionów w USA wynoszącej 0,06 USD za godzinę przedziału (więcej informacji znajdziesz na stronie z cennikiem usług BigQuery) czysty koszt wykonania 3000 milisekund przedziałów jest obliczany jako (3000 ms / 3 600 000 ms) * 0,06 USD = 0,00005 USD, co świadczy o opłacalności procesu.
8. Zwalnianie miejsca w zasobach w chmurze
Aby uniknąć ciągłych opłat lub wyczerpania limitów projektu, usuń zbiór danych BigQuery i połączenia w Cloud Shell:
# Cleanup BigQuery routines
bq rm -f --routine ${PROJECT_ID}:${BQ_DATASET}.clean_html
bq rm -f --routine ${PROJECT_ID}:${BQ_DATASET}.tokenize
# Cleanup connection
bq rm -f --connection --location=${REGION} ${PROJECT_ID}.${REGION}.${BQ_RESOURCE_CONN}
# Cleanup BigQuery Dataset
bq rm -r -f -d ${PROJECT_ID}:${BQ_DATASET}
9. Gratulacje!
Ukończono ćwiczenie dotyczące tworzenia i zabezpieczania funkcji UDF w Pythonie w środowisku wykonawczym bezserwerowym BigQuery.
W tym ćwiczeniu dowiesz się, jak:
- Analizować dane za pomocą publicznych funkcji UDF: wywoływać wstępnie skompilowane publiczne funkcje UDF w Pythonie w zbiorach danych Stack Overflow, aby wykonywać operacje matematyczne na zagregowanych tablicach.
- Integrować pakiety innych firm: wdrażać niestandardową trwałą funkcję UDF, która korzysta ze standardowego środowiska wykonawczego Pythona i biblioteki
beautifulsoup4, aby natywnie usuwać surowe tagi HTML w zapytaniach SQL. - Konfigurowanie bezpiecznych połączeń zewnętrznych: Utwórz połączenie z zasobem Cloud BigQuery, aby bezpiecznie przyznawać izolowanym kontenerom funkcji UDF dostęp do sieci wychodzącej w celu pobierania zasobów zewnętrznych bez kodowania na stałe danych logowania.
- Implementować lokalną tokenizację z użyciem pamięci podręcznej: importować bibliotekę
transformersHugging Face, aby wczytać tokenizator T5, używając zmiennych globalnych do przechowywania plików konfiguracyjnych w pamięci podręcznej i przetwarzania wierszy w kontenerach. - Sprawdzać wydajność i koszty wykonania: programowo wysyłać zapytania do regionalnych widoków INFORMATION_SCHEMA.JOBS za pomocą identyfikatorów zadań BigQuery, aby śledzić zużycie przedziałów (
total_slot_ms) i koszty użycia kontenera (external_service_costs).
Co dalej?
- Zapoznaj się z sprawdzonymi metodami i limitami: dowiedz się więcej o limitach wykonania, współbieżności i pamięci w przewodniku po limitach funkcji UDF w Pythonie w BigQuery.
- Szczegółowe informacje o optymalizacji kosztów: dowiedz się, jak działa rozliczenie w przypadku środowisk funkcji UDF w kontenerach i wywołań połączeń zewnętrznych, w dokumentacji cen BigQuery.
- Twórz aplikacje oparte na AI w BigQuery: wyjdź poza podstawową manipulację tekstem i dowiedz się, jak tworzyć kompleksowe systemy multimodalne. Zapoznaj się z ćwiczeniem Tworzenie platformy sprzedaży pojazdów opartej na AI za pomocą BigQuery i modeli Gemini, aby wykorzystać wyszukiwanie semantyczne i modele Gemini bezpośrednio w hurtowni danych.