שליחת שאילתות לנתונים ב-Bigtable

במאמר הזה מוסבר איך להשתמש ב-BigQuery כדי לשלוח שאילתות לנתונים שמאוחסנים בטבלה חיצונית של Bigtable. מידע על הפעלת שאילתות על נתונים ישירות מ-Bigtable זמין במאמר סקירה כללית על GoogleSQL ל-Bigtable.

Bigtable הוא מסד נתונים NoSQL של Google עם אוכלוסייה דלילה, שאפשר להרחיב אותו למיליארדי שורות, אלפי עמודות ונתונים בנפח פטה-בייט. מידע על מודל הנתונים של Bigtable זמין במאמר בנושא מודל אחסון.

שליחת שאילתות לטבלאות חיצוניות קבועות

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

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

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

  • צפייה בנתוני BigQuery ‏ (roles/bigquery.dataViewer)
  • משתמש BigQuery‏ (roles/bigquery.user)
  • קורא ב-Bigtable (roles/bigtable.reader)

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

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

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

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

הפעלת שאילתה בטבלה

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

שאילתות על טבלאות חיצוניות זמניות

שאילתות של מקור נתונים חיצוני באמצעות טבלה זמנית שימושיות לשאילתות חד-פעמיות אד-הוק על נתונים חיצוניים, או לתהליכי חילוץ, טרנספורמציה וטעינה (ETL).

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

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

כשמשתמשים בטבלה חיצונית זמנית, לא יוצרים טבלה באחד ממערכי הנתונים של BigQuery. אי אפשר לשתף את הטבלה עם אחרים כי היא לא נשמרת לצמיתות במערך נתונים.

יש כמה מגבלות על שימוש בטבלה חיצונית זמנית במקום בטבלה חיצונית קבועה, כולל:

  • התפקיד שלכם צריך להיות אדמין של Bigtable‏ (roles/bigtable.admin).
  • בגישה הזו אי אפשר להשתמש במסוף Google Cloud כדי להסיק את הסכימה של טבלת Bigtable וליצור באופן אוטומטי את הגדרת הטבלה. אתם צריכים ליצור את הגדרת הטבלה בעצמכם.

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

כדי לשלוח שאילתות לטבלאות חיצוניות זמניות ב-Bigtable, צריך לוודא שיש לכם את התפקידים הבאים:

  • צפייה בנתוני BigQuery ‏ (roles/bigquery.dataViewer)
  • משתמש BigQuery‏ (roles/bigquery.user)
  • אדמין של Bigtable‏ (roles/bigtable.admin)

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

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

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

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

יצירה של טבלה וביצוע שאילתה עליה

כדי לשלוח שאילתה לנתוני Bigtable באמצעות טבלה חיצונית זמנית:

הכלי bq לשורת הפקודה וממשק ה-API תומכים ביצירה ובשאילתות של טבלה חיצונית זמנית.

BQ

כדי לשלוח שאילתה לטבלה זמנית באמצעות קובץ הגדרת טבלה, מזינים את הפקודה bq query עם הדגל --external_table_definition.

(אופציונלי) מציינים את הדגל --location ומגדירים את הערך למיקום.

bq --location=LOCATION query \
--use_legacy_sql=false \
--external_table_definition=TABLE::DEFINITION_FILE \
'QUERY'

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

  • LOCATION: השם של המיקום. הדגל --location הוא אופציונלי.
  • TABLE: השם של הטבלה הזמנית שיוצרים.
  • DEFINITION_FILE: הנתיב אל קובץ הגדרת הטבלה במחשב המקומי.
  • QUERY: השאילתה ששולחים לטבלה הזמנית.

לדוגמה, הפקודה הבאה יוצרת שאילתה על טבלה זמנית בשם follows באמצעות קובץ הגדרת טבלה בשם follows_def.

bq query \
--use_legacy_sql=false \
--external_table_definition=follows::/tmp/follows_def \
'SELECT
  COUNT(rowkey)
 FROM
   follows'

API

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

  • (אופציונלי) מציינים את המיקום במאפיין location בקטע jobReference של משאב המשרה.

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

Java

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

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

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.BigtableColumn;
import com.google.cloud.bigquery.BigtableColumnFamily;
import com.google.cloud.bigquery.BigtableOptions;
import com.google.cloud.bigquery.ExternalTableDefinition;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableResult;
import com.google.common.collect.ImmutableList;
import org.apache.commons.codec.binary.Base64;

// Sample to queries an external bigtable data source using a temporary table
public class QueryExternalBigtableTemp {

  public static void main(String[] args) {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "MY_PROJECT_ID";
    String bigtableInstanceId = "MY_INSTANCE_ID";
    String bigtableTableName = "MY_BIGTABLE_NAME";
    String bigqueryTableName = "MY_TABLE_NAME";
    String sourceUri =
        String.format(
            "https://googleapis.com/bigtable/projects/%s/instances/%s/tables/%s",
            projectId, bigtableInstanceId, bigtableTableName);
    String query = String.format("SELECT * FROM %s ", bigqueryTableName);
    queryExternalBigtableTemp(bigqueryTableName, sourceUri, query);
  }

  public static void queryExternalBigtableTemp(String tableName, String sourceUri, String query) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      BigtableColumnFamily.Builder statsSummary = BigtableColumnFamily.newBuilder();

      // Configuring Columns
      BigtableColumn connectedCell =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("connected_cell".getBytes()))
              .setFieldName("connected_cell")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();
      BigtableColumn connectedWifi =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("connected_wifi".getBytes()))
              .setFieldName("connected_wifi")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();
      BigtableColumn osBuild =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("os_build".getBytes()))
              .setFieldName("os_build")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();

      // Configuring column family and columns
      statsSummary
          .setColumns(ImmutableList.of(connectedCell, connectedWifi, osBuild))
          .setFamilyID("stats_summary")
          .setOnlyReadLatest(true)
          .setEncoding("TEXT")
          .setType("STRING")
          .build();

      // Configuring BigtableOptions is optional.
      BigtableOptions options =
          BigtableOptions.newBuilder()
              .setIgnoreUnspecifiedColumnFamilies(true)
              .setReadRowkeyAsString(true)
              .setColumnFamilies(ImmutableList.of(statsSummary.build()))
              .build();

      // Configure the external data source and query job.
      ExternalTableDefinition externalTable =
          ExternalTableDefinition.newBuilder(sourceUri, options).build();
      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query)
              .addTableDefinition(tableName, externalTable)
              .build();

      // Example query
      TableResult results = bigquery.query(queryConfig);

      results
          .iterateAll()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString())));

      System.out.println("Query on external temporary table performed successfully.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Query not performed \n" + e.toString());
    }
  }
}

שיקולי ביצועים

הביצועים של שאילתות שמופעלות על מקורות נתונים חיצוניים של Bigtable תלויים בשלושה גורמים:

  • מספר השורות
  • כמות הנתונים שנקראו
  • מידת ההקבלה

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

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

Compute

כשמריצים שאילתה על נתוני Bigtable מ-BigQuery, יש לכם את האפשרויות הבאות לחישוב:

  • צמתי אשכול, שזו ברירת המחדל.
  • Data Boost (גרסת Preview) היא אפשרות חישוב ללא שרתים שמאפשרת לבודד את התנועה של ניתוח הנתונים בלי להשפיע על התנועה של האפליקציה שמועברת דרך הצמתים של האשכולות.

כדי להשתמש ב-Data Boost, אתם או האדמין שלכם צריכים ליצור קובץ הגדרה שמציין פרופיל אפליקציה של Data Boost ב-URI של Bigtable. מידע נוסף זמין במאמר בנושא יצירת טבלה חיצונית של Bigtable.

אם אתם לא משתמשים ב-Data Boost, חשוב לדעת ששאילתות ב-Bigtable מ-BigQuery צורכות מחזורי CPU של Bigtable. צריכת המעבד (CPU) על ידי BigQuery כשמשתמשים בצמתים שהוקצו לחישובים עשויה להשפיע על זמן האחזור ועל קצב העברת הנתונים של בקשות מקבילות אחרות, כמו תעבורת משתמשים בזמן אמת. לדוגמה, שימוש גבוה במעבד ב-Bigtable משפיע על שאילתות עם זנב ארוך ומגדיל את זמן האחזור באחוזון ה-99.

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

מסנני שאילתות

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

מסנן מפתח שורה

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

SELECT
  COUNT(follows.column.name)
FROM
  `dataset.table`
WHERE
  rowkey = "alice";

יש תמיכה גם במסנני טווח כמו rowkey > '1' ו-rowkey < '8', אבל רק אם rowkey נקרא כמחרוזת עם האפשרות readRowkeyAsString.

סינון לפי קבוצת עמודות ומאפיין

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

    SELECT
      rowkey AS user_id,
      user_info
    FROM
      project.dataset.table;
כדי לסנן לפי מאפיין ספציפי, צריך קודם להצהיר עליו ב-"columns" בהגדרת הטבלה החיצונית:
CREATE OR REPLACE EXTERNAL TABLE project.dataset.table
  OPTIONS (
    format = 'CLOUD_BIGTABLE',
    uris = ['https://googleapis.com/bigtable/projects/…/instances/…/tables/…'],
    bigtable_options = '''{
  "columnFamilies": [
    {
      "familyId": "user_info",
      "columns": [
        {
          "qualifierString": "name"
        },
        {
          "qualifierString": "email"
        },
        {
          "qualifierString": "registered_at"
        }
      ]
    },
    {
      "familyId": "session_data"
    }
  ],
  "readRowkeyAsString": true,
  "timestampSuffix": "_ts"
}'''
  );

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

    SELECT
      rowkey AS user_id,
      user_info.email.cell[SAFE_OFFSET(0)].value as email
    FROM
      project.dataset.table;