Yönetilen UDF'lerle Python'ın gücünü BigQuery'ye taşıma

1. Giriş

Yapılandırılmış sorgu dili (SQL), veri ambarı analizi için endüstri standardıdır. Ancak karmaşık prosedürel mantığı, matematiksel hesaplamaları, metin temizlemeyi veya makine öğrenimine hazırlık iş akışlarını tamamen SQL ile ifade etmek oldukça zor olabilir.

Veri ekipleri, karmaşık özel Python işleme gerektiğinde geçmişte BigQuery'den büyük veri kümeleri ayıklamış, bunları harici özel sanal makinelerde veya kümelerde işlemiş ve sonuçları geri yüklemiştir. Bu yaklaşım, yüksek ağ gecikmesine neden olur, verileri taşıyarak uyumluluk risklerini artırır ve altyapı yönetimi ek yükü oluşturur.

BigQuery Managed Python Kullanıcı Tanımlı İşlevleri (UDF'ler), özel kodu milyonlarca satıra otomatik olarak ölçeklenen sunucusuz kaynaklarda çalıştırarak bu sorunları çözer. Google Cloud, derleme, görüntü oluşturma, güvenlik yaması uygulama ve yürütme işlemlerini yöneterek özel hesaplamaları doğrudan verilerinizin bulunduğu yerde çalıştırmanıza olanak tanır.

Bu codelab'de, StackOverflow topluluk verileri üzerinde bir analiz ve metin ön işleme ardışık düzeni oluşturacak, bunu sonraki raporlama ve makine öğrenimi için hazırlayacaksınız.

Ön koşullar

  • Faturalandırmanın etkin olduğu bir Google Cloud projesi.
  • SQL, IAM ve BigQuery kavramları hakkında temel düzeyde bilgi sahibi olmanız gerekir.

Neler öğreneceksiniz?

  • Veri dağılımlarını analiz etmek için önceden derlenmiş herkese açık bir Python UDF'yi herkese açık bir veri kümesinde çağırma
  • Yapılandırılmamış verileri temizlemek için beautifulsoup4 kullanarak kendi özel Python UDF'nizi nasıl dağıtabilirsiniz?
  • Bellek içi kapsayıcı önbelleğe alma özelliğini kullanarak makine öğrenimi öğelerini güvenli bir şekilde indirmek ve Hugging Face Transformers kitaplığıyla yerel ML jetonlaştırma işlemi gerçekleştirmek için BigQuery Cloud Resource bağlantısını yapılandırma.
  • Bu adımları tek bir yüksek performanslı SQL işlem hattında nasıl birleştireceğinizi öğrenin.

2. Kurulum ve şartlar

Cloud Shell'i başlatma

Google Cloud, dizüstü bilgisayarınızdan uzaktan çalıştırılabilir ancak bu codelab'de Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacaksınız.

  1. Google Cloud Console'a gidin, ardından bir Google Cloud projesi seçin veya oluşturun.
  2. ⚠️ Proje kimliğini not edin. Bu laboratuvar boyunca bu bilgiyi kullanacaksınız.

39b6a5563d69ccfb.png

  1. Yeni sekmede Cloud Shell'i açın: https://shell.cloud.google.com/.
  2. İstenirse Yetkilendir'i tıklayın.
  3. PROJECT_ID yerine aşağıdaki komutu yapıştırın:
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

Değişkenleri etkin oturumunuza uygulayın:

source ./env.sh

API'leri etkinleştirme ve BigQuery veri kümesi oluşturma

Projenizde gerekli Google Cloud hizmetlerini etkinleştirin ve hedef veri kümesini oluşturun:

# 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. Herkese açık bir Python UDF ile veri dağılımlarını keşfetme

Özel kodu dağıtmadan önce veri kümesini incelemek ve düşük kaliteli gürültüyü filtrelemek faydalı olur. Bu adımda, etkin kullanıcıları bulmak ve soru puanlarının istatistiksel dağılımını anlamak için Stack Overflow sorularını analiz edeceksiniz.

Bu işlem için neden Python UDF kullanmalısınız?

Gruplandırılmış veri dizilerinde birden fazla kesin yüzdelik dilimi (ör. 25., 50., 75. ve 95. yüzdelik dilimler) hesaplamak, saf SQL'de karmaşık ve kaynak yoğun bir işlemdir. PERCENTILE_CONT gibi standart SQL analiz işlevleri, iç içe geçmiş diziler yerine satırların düz sütunlarını bekler. Önceden toplanmış dizilerin satır başına tam yüzdelik dilimlerini hesaplamak için her yüzdelik dilim metriği için iç içe yerleştirme, sıralama ve yeniden toplama işlemlerini gerçekleştiren ayrıntılı alt sorgular yazmanız gerekir. Bu da verimsiz bir yöntemdir.

NumPy'yi (Python'ın UDF içindeki son derece optimize edilmiş bilimsel kitaplığı) kullanarak tek bir kod satırıyla bir sayı dizisinde tam matematiksel yüzdelik dilimler hesaplayabilirsiniz.

Yürütme

Google Cloud, çeşitli önceden derlenmiş herkese açık UDF'ler barındırır (Routines sekmesini tıklayın). BigQuery, tür eşleştirme gerektirdiğinden verileri önceden toplamak ve UNNEST ifadesini kullanarak tam sayı dizilerini kayan nokta dizilerine dönüştürmek için ortak tablo ifadesi (CTE) kullanacağız.

BigQuery Studio Konsolu'nda aşağıdaki sorguyu çalıştırın:

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;

Bu sayede, önce izinleri yapılandırmanıza veya özel Python kodu yazmanıza gerek kalmadan kullanıcı performansını anında anlayabilirsiniz.

Sonuçları Doğrulama

Bu sorgu iç içe geçmiş dizi türleri (scores ve score_percentiles) döndürdüğü için BigQuery Studio'daki varsayılan tablo biçimindeki Sonuçlar sekmesinde düzleştirilmiş veya kesilmiş çıkış gösterilebilir. Bu da dizi öğelerinin incelenmesini zorlaştırır.

Yapılandırılmış, iç içe yerleştirilmiş çıkışı görüntülemek için:

  1. Sorgu sonuçları bölmesinde, sekme çubuğunu (varsayılan olarak Sonuçlar) bulun.
  2. JSON sekmesini tıklayın.

Satırları temsil eden, aşağıdaki gibi yapılandırılmış bir JSON dizisi görmeniz gerekir:

[{
  "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"]
}]

Çıkışı Anlama

  • scores: Her bir tekil kullanıcı tarafından yayınlanan ham soru puanlarının tamamı.
  • score_percentiles: Hesaplanan dört kayan nokta değerini içeren bir dizi. Bunlar, istenen yüzdelik dilimlerle tam olarak eşleşir: [25th, 50th, 75th, and 95th] yüzdelik dilim. Örneğin, 533463 kullanıcısının sorularının 95. yüzdelik dilim puanı yaklaşık 8.85'dir. Bu, kullanıcının en iyi sorularının yüksek puan aldığını gösterir.

4. Özel bir UDF oluşturarak metni yerel olarak temizleme

Hedef kullanıcılar belirlendikten sonra gönderi içeriklerini analiz etmek istiyoruz. Ancak ham forum yayınları genellikle karmaşık HTML etiketleri ve öğeleri içerir. Okunabilirliği artırmak ve sonraki model maliyetlerini azaltmak için bunları kaldırmamız gerekiyor.

Bunun neden gerekli olduğunu anlamak için önce biçimlendirilmemiş Stack Overflow gönderi gövdesinin nasıl göründüğünü inceleyelim. BigQuery Studio Konsolu'nda aşağıdaki sorguyu çalıştırın:

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;

Çıktıyı incelerseniz metnin içine yerleştirilmiş <p>, <b>, <code> gibi çeşitli biçimlendirme etiketleri görürsünüz. Bunları doğrudan aşağı akış makine öğrenimi belirteçleyicileriyle işlemek gereksiz gürültüye neden olur ve belirteç alımı maliyetlerini yapay olarak artırır.

Bu işlem için neden Python UDF kullanmalısınız?

HTML'yi saf SQL'de normal ifadeler (Regex) kullanarak güvenilir bir şekilde ayrıştırmak zor ve ayrıştırma hatalarına yatkındır. beautifulsoup4 gibi güçlü bir Python kitaplığını doğrudan sorgularınızda çalıştırmak, etiketleri kaldırmak için güvenilir bir yöntemdir.

Kalıcı clean_html işlevini veri kümenize dağıtmak için aşağıdaki DDL sorgusunu çalıştırın:

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=" ")
''';

İşlevin çıkışını basit bir sorguyla doğrulayın:

SELECT `YOUR_PROJECT_ID.python_udfs.clean_html`('<p>Hello <b>world</b>!</p>') AS cleaned_text;

HTML öğeleri olmadan temizlenmiş metni görmelisiniz:

+----------------+
| cleaned_text   |
+----------------+
| Hello  world ! |
+----------------+

5. Güvenli Harici Entegrasyonlar ve Gelişmiş Makine Öğrenimi İşleme

Temiz metin elde ettiğimize göre, bunu makine öğrenimi modelleri veya Gemma gibi büyük dil modelleri (LLM'ler) için hazırlamamız gerekir. LLM'ler ham metni doğrudan okuyamaz, sayısal jeton kimliklerini işler.

Temiz metnimizi jetonlara dönüştürmek için Hugging Face'in transformers kitaplığını içe aktaracak ve önceden eğitilmiş bir Google T5 belirteç oluşturucuyu doğrudan veritabanımıza yükleyeceğiz.

Cloud Resource Connection'ı oluşturma

Güvenli bir bağlantı oluşturmak için BigQuery Studio Konsolu'nda aşağıdaki sorguyu çalıştırın:

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"
);

Tokenizer UDF'sini oluşturma

Şimdi özel belirteç oluşturucu UDF'yi dağıtın. get_tokenizer() yardımcı işlevinin, indirme girişiminde bulunmadan önce tokenizer genel değişkeninin zaten başlatılıp başlatılmadığını nasıl kontrol ettiğine dikkat edin:

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 []
''';

Öğenin başarıyla indirildiğini ve tam sayı kimliklerinden oluşan bir dizi döndürdüğünü doğrulamak için belirteç oluşturucuyu basit bir sorguyla test edin:

SELECT `YOUR_PROJECT_ID.python_udfs.tokenize`('Hello world!') AS token_ids;

Yapılandırılmış diziyi görmek için sorgu sonuçları panelinizde JSON sekmesine geçin:

[
  {
    "token_ids": ["8774", "296", "55", "1"]
  }
]

6. Uçtan uca ön işleme ardışık düzenini çalıştırma

İşlem hattımızın üç adımı da hazır olduğuna göre, Common Table Expressions (CTE'ler) kullanarak bunları tek bir SQL sorgusunda birleştirebiliriz.

Bu ardışık düzen, modern bir veri mühendisliği iş akışını temsil eder:

  1. Herkese açık yüzdelik UDF'yi kullanarak etkin kullanıcıları ve en yüksek puanlı sorularını ayırın.
  2. clean_html UDF'mizi kullanarak metindeki ham HTML biçimlendirmesini yerel olarak kaldırın.
  3. Önbelleğe alınmış tokenize UDF'mizi kullanarak temizlenmiş metni jeton dizilerine dönüştürün.

BigQuery Studio Konsolu'nda aşağıdaki ardışık düzen sorgusunu yürütün:

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;

Yapılandırılmış çıktıyı incelemek için BigQuery Studio'da JSON sekmesine geçin.

[{
  "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. Ek: Ardışık Düzen Nasıl Çalışır ve Denetleme Yürütme Maliyetleri

Bu bölümde, uçtan uca ön işleme sorgusunun mekanizmalarına ayrıntılı bir bakış sunulmakta ve yürütmenizin tam yuva tüketimini ve yönetilen kapsayıcı maliyetlerini nasıl izleyeceğiniz gösterilmektedir.

Ardışık Düzenin Mimari Dökümü

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
)

Bu ilk sorgu segmenti, etkin Stack Overflow katkıda bulunan kullanıcıların ham soru puanlarını toplar. Her kullanıcının puanlarını tek bir dizide (ARRAY_AGG) birleştirirken deterministik bir sıralama düzeni (ORDER BY id) uygular. Veri kümesi, geçerli bir istatistiksel temel oluşturmak için yalnızca en az beş sorusu olan kullanıcıları içerecek şekilde filtrelenir.

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
  )
)

Bu segment, en çok katkıda bulunanları belirlemek için tam puan dağılımlarını (25., 50., 75. ve 95. yüzdelikler) bulmak üzere herkese açık percentiles Python UDF'sini kullanır. Bu hesaplama açısından yoğun UDF'nin birden fazla kez yürütülmesini önlemek için hesaplama iç içe yerleştirilmiş bir alt sorguya sarılır. Daha sonra 95. yüzdelik dilim karşılaştırması, sonuç dizisinden doğrudan dizin konumunda üç (OFFSET(3)) alınır.

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)
)

Orijinal sorular, %95'lik yüzdelik dilim eşiğini karşılayan veya aşan gönderileri almak için etkin kullanıcıların listesiyle birleştirilir. Veritabanı türü karşılaştırma hatalarını önlemek için karşılaştırma puanı, değerlendirmeden önce CAST işlemiyle açıkça FLOAT64 türüne dönüştürülür.

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
)

Ham gönderi gövdeleri genellikle karmaşık biçimlendirme ve HTML standart metni içerir. Bu da sonraki makine öğrenimi girişlerinin kalitesini düşürür. Karmaşık normal ifadeler kullanmak yerine, ardışık düzen özel clean_html Python UDF'mizi çağırır. Bu araç, öğeleri temiz bir şekilde kaldırmak ve düz, okunabilir metinler oluşturmak için BeautifulSoup kitaplığını kullanarak izole bir kapsayıcıda dinamik olarak bir Python çalışma zamanı başlatır.

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
)

Üretken model alımı için temiz metin önizlemesini hazırlamak üzere ardışık düzen, 120 karakterlik bir dilimde özel tokenize Python UDF'mizi çağırır. UDF, Google T5 belirteç oluşturucu parametrelerini indirmek için Hugging Face Hub'a güvenli bir şekilde ulaşır. Tokenleştirici örneği global bir değişkene yüklendiğinden, sıcak kapsayıcı yapılandırmayı önbelleğe alır. Böylece, sonraki satırlar ağ gecikmesi olmadan hızlı bir şekilde bellek içi tokenleştirme işlemine tabi tutulur.

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;

Son sorgu bloğu, işlenen veri kümesini çıkarır. Oluşturulan jetonları saymak için jetonlaştırma UDF'sini ikinci kez yürütmek yerine, BigQuery'nin yerel ARRAY_LENGTH işlevi doğrudan önceden hesaplanmış token_ids dizisine uygulanır. Bu strateji, gereksiz CPU döngülerini, kapsayıcı işlemlerini ve genel yürütme maliyetlerini azaltır.

Slot tüketimi ve yönetilen UDF maliyetlerini denetleme

BigQuery, Google Cloud Console kullanıcı arayüzünde doğrudan kapsamlı maliyet görünürlüğü gösterge tablolarını kullanıma sunarken mühendisler, BigQuery iş kimliklerini kullanarak herhangi bir sorgunun tam slot tüketimini ve yönetilen kapsayıcı yürütme maliyetlerini programatik olarak denetleyebilir.

Sorgu yürütmenizi denetlemek için iş kimliğinizi bulun.

  1. BigQuery Studio'da, konsolun alt kısmındaki Sorgu geçmişi sekmesine giderek bu bilgiyi bulabilirsiniz.
  2. Yürütülen ardışık düzen sorgunuzu tıklayın.
  3. Job Information (İş Bilgileri) ayrıntıları panelinde Job ID (İş Kimliği) alanını bulun.

Net iş kimliğinizi belirledikten sonra aşağıdaki sorguda JOB_ID yerine bu kimliği girin ve sorguyu BigQuery Studio'da çalıştırın:

SELECT 
  job_id,
  total_slot_ms,
  external_service_costs
FROM 
  `YOUR_PROJECT_ID.region-us`.INFORMATION_SCHEMA.JOBS
WHERE 
  job_id = "JOB_ID";

Yapılandırılmış çıktıyı incelemek için BigQuery Studio'da JSON sekmesine geçin. Aşağıdakine benzer bir yük alırsınız:

[{
  "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"
  }]
}]

Çıktıyı anlama:

  • total_slot_ms: Tüm sorgu aşamalarında kullanılan toplam hesaplama süresi (milisaniye). Bu birleştirilmiş ardışık düzen için yürütme genellikle ortalama 815 bin yuva milisaniyesi sürer.
  • external_service_costs: Standart BigQuery analiz motoru dışında kullanılan kaynakları gösteren bir dizi.
  • external_service: "MANAGED_ROUTINE_EXECUTION" değeri, maliyetin özellikle özel Python UDF ortamımızı barındıran sunucusuz kapsayıcı yürütme işlemine ait olduğunu onaylar.
  • slot_ms: "3000" değeri, Python mantığını yürütmek için sıcak kapsayıcı çalışma zamanında kullanılan özel bilgi işlem kaynaklarının tam milisaniye değerini gösterir.
  • billing_method: "SERVICES_SKU" değeri, bu yerelleştirilmiş kapsayıcı ücretlerinin, kapsayıcı yürütme süresine ve bellek ek yüküne göre özel BigQuery Hizmetleri SKU'su üzerinden dinamik olarak faturalandırıldığını gösterir. Yuva saati başına 0,06 ABD doları olan standart ABD çoklu bölge işlem fiyatlandırmasıyla (BigQuery Hizmetleri Fiyatlandırma Sayfası'na bakın) 3.000 yuva-ms'lik saf yürütme maliyeti (3.000 ms / 3.600.000 ms) * 0,06 ABD doları = 0,00005 ABD doları olarak hesaplanır. Bu da maliyet açısından verimli bir iş akışını gösterir.

8. Bulut kaynaklarını temizleme

Sürekli ücretlendirilmemek veya proje kotalarını tüketmemek için Cloud Shell'de BigQuery veri kümenizi ve bağlantılarınızı silin:

# 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. Tebrikler!

BigQuery sunucusuz çalışma zamanında Python UDF'leri oluşturma ve güvenliğini sağlama ile ilgili codelab'i tamamlamış olmanız gerekir.

Bu codelab'de şunları öğrendiniz:

  • Herkese Açık UDF'lerle Verileri Keşfetme: Toplanmış dizilerde matematiksel yüzdelik işlemleri gerçekleştirmek için Stack Overflow veri kümelerinde önceden derlenmiş herkese açık Python UDF'lerini çağırın.
  • Üçüncü taraf paketlerini entegre etme: Standart Python çalışma zamanını ve beautifulsoup4 kitaplığını kullanarak SQL sorgularınızdaki ham HTML etiketlerini yerel olarak kaldırmak için özel bir kalıcı UDF dağıtın.
  • Güvenli Harici Bağlantıları Yapılandırma: Kimlik bilgilerini sabit kodlamadan harici öğeleri getirmek için yalıtılmış UDF kapsayıcılarına giden ağ erişimini güvenli bir şekilde vermek üzere BigQuery Cloud Resource Connection oluşturun.
  • Bellek İçi Önbelleğe Alma ile Yerel Tokenleştirme Uygulama: Yapılandırma dosyalarını önbelleğe almak ve satırları sıcak kapsayıcılarda işlemek için genel değişkenlerden yararlanarak T5 tokenleştirici yüklemek üzere Hugging Face transformers kitaplığını içe aktarın.
  • Yürütme Performansını ve Maliyetleri Denetleme: Slot tüketimini (total_slot_ms) ve kapsayıcı kullanım maliyetlerini (external_service_costs) izlemek için BigQuery iş kimliklerini kullanarak bölgesel INFORMATION_SCHEMA.JOBS görünümlerini programatik olarak sorgulayın.

Yapabilecekleriniz