קריאת נתונים באמצעות BigQuery API עם חלוקה לעמודים

במסמך הזה מוסבר איך לקרוא נתונים של טבלאות ותוצאות של שאילתות באמצעות BigQuery API עם חלוקה לעמודים.

מעבר בין תוצאות באמצעות ה-API

כל השיטות של *collection*.list מחזירות תוצאות עם מספור דפים בנסיבות מסוימות. המאפיין maxResults מגביל את מספר התוצאות בדף.

‏Method קריטריונים של עימוד ערך ברירת המחדל של maxResults ערך מקסימלי של maxResults ערך מקסימלי של maxFieldValues
tabledata.list הפונקציה מחזירה תוצאות עם עימוד אם גודל התגובה הוא יותר מ-‎10 MB1 של נתונים או יותר מ-maxResults שורות. ללא הגבלה ללא הגבלה ללא הגבלה
כל שאר השיטות של *collection*.list הפונקציה מחזירה תוצאות עם חלוקה לדפים אם התשובה מכילה יותר מ-maxResults שורות וגם פחות מהמגבלות המקסימליות. 10,000 ללא הגבלה 300,000

אם התוצאה גדולה מהמגבלה של בייט או שדה, התוצאה נחתכת כדי להתאים למגבלה. אם שורה אחת גדולה ממגבלת הבייטים או השדות, הפונקציה tabledata.list יכולה להחזיר עד 100 MB של נתונים1, שזה בהתאם למגבלת הגודל המקסימלי של שורה בתוצאות של שאילתות. אין גודל מינימלי לכל דף, ויכול להיות שדפים מסוימים יחזירו יותר שורות מאחרים.

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

jobs.getQueryResults יכול להחזיר 20 MB של נתונים, אלא אם ביקשתם במפורש יותר נתונים דרך התמיכה.

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

השיטה tabledata.list, שמשמשת להצגת נתוני טבלאות בדפים, משתמשת בערך היסט של שורה או באסימון דף. מידע נוסף זמין במאמר עיון בנתוני טבלה.

חזרה על התוצאות של ספריות הלקוח

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

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

C#

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

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


using Google.Api.Gax;
using Google.Apis.Bigquery.v2.Data;
using Google.Cloud.BigQuery.V2;
using System;
using System.Linq;

public class BigQueryBrowseTable
{
    public void BrowseTable(
        string projectId = "your-project-id"
    )
    {
        BigQueryClient client = BigQueryClient.Create(projectId);
        TableReference tableReference = new TableReference()
        {
            TableId = "shakespeare",
            DatasetId = "samples",
            ProjectId = "bigquery-public-data"
        };
        // Load all rows from a table
        PagedEnumerable<TableDataList, BigQueryRow> result = client.ListRows(
            tableReference: tableReference,
            schema: null
        );
        // Print the first 10 rows
        foreach (BigQueryRow row in result.Take(10))
        {
            Console.WriteLine($"{row["corpus"]}: {row["word_count"]}");
        }
    }
}

Java

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

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

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQuery.TableDataListOption;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TableResult;

// Sample to directly browse a table with optional paging
public class BrowseTable {

  public static void runBrowseTable() {
    // TODO(developer): Replace these variables before running the sample.
    String table = "MY_TABLE_NAME";
    String dataset = "MY_DATASET_NAME";
    browseTable(dataset, table);
  }

  public static void browseTable(String dataset, String table) {
    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();

      // Identify the table itself
      TableId tableId = TableId.of(dataset, table);

      // Page over 100 records. If you don't need pagination, remove the pageSize parameter.
      TableResult result = bigquery.listTableData(tableId, TableDataListOption.pageSize(100));

      // Print the records
      result
          .iterateAll()
          .forEach(
              row -> {
                row.forEach(fieldValue -> System.out.print(fieldValue.toString() + ", "));
                System.out.println();
              });

      System.out.println("Query ran successfully");
    } catch (BigQueryException e) {
      System.out.println("Query failed to run \n" + e.toString());
    }
  }
}

Go

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

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

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

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
)

// browseTable demonstrates reading data from a BigQuery table directly without the use of a query.
// For large tables, we also recommend the BigQuery Storage API.
func browseTable(w io.Writer, projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	table := client.Dataset(datasetID).Table(tableID)
	it := table.Read(ctx)
	for {
		var row []bigquery.Value
		err := it.Next(&row)
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintln(w, row)
	}
	return nil
}

Node.js

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

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

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

// Import the Google Cloud client library using default credentials
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery();

async function browseTable() {
  // Retrieve a table's rows using manual pagination.

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const datasetId = 'my_dataset'; // Existing dataset
  // const tableId = 'my_table'; // Table to create

  const query = `SELECT name, SUM(number) as total_people
    FROM \`bigquery-public-data.usa_names.usa_1910_2013\`
    GROUP BY name 
    ORDER BY total_people 
    DESC LIMIT 100`;

  // Create table reference.
  const dataset = bigquery.dataset(datasetId);
  const destinationTable = dataset.table(tableId);

  // For all options, see https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#jobconfigurationquery
  const queryOptions = {
    query: query,
    destination: destinationTable,
  };

  // Run the query as a job
  const [job] = await bigquery.createQueryJob(queryOptions);

  // For all options, see https://cloud.google.com/bigquery/docs/reference/v2/jobs/getQueryResults
  const queryResultsOptions = {
    // Retrieve zero resulting rows.
    maxResults: 0,
  };

  // Wait for the job to finish.
  await job.getQueryResults(queryResultsOptions);

  function manualPaginationCallback(err, rows, nextQuery) {
    rows.forEach(row => {
      console.log(`name: ${row.name}, ${row.total_people} total people`);
    });

    if (nextQuery) {
      // More results exist.
      destinationTable.getRows(nextQuery, manualPaginationCallback);
    }
  }

  // For all options, see https://cloud.google.com/bigquery/docs/reference/v2/tabledata/list
  const getRowsOptions = {
    autoPaginate: false,
    maxResults: 20,
  };

  // Retrieve all rows.
  destinationTable.getRows(getRowsOptions, manualPaginationCallback);
}
browseTable();

PHP

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

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

החלוקה לדפים מתבצעת באופן אוטומטי בספריות הלקוח של Cloud עבור PHP באמצעות פונקציית הגנרטור rows, שמביאה את הדף הבא של התוצאות במהלך האיטרציה.

use Google\Cloud\BigQuery\BigQueryClient;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $datasetId = 'The BigQuery dataset ID';
// $tableId   = 'The BigQuery table ID';
// $maxResults = 10;

$maxResults = 10;
$startIndex = 0;

$options = [
    'maxResults' => $maxResults,
    'startIndex' => $startIndex
];
$bigQuery = new BigQueryClient([
    'projectId' => $projectId,
]);
$dataset = $bigQuery->dataset($datasetId);
$table = $dataset->table($tableId);
$numRows = 0;
foreach ($table->rows($options) as $row) {
    print('---');
    foreach ($row as $column => $value) {
        printf('%s: %s' . PHP_EOL, $column, $value);
    }
    $numRows++;
}

Python

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

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

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


from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the table to browse data rows.
# table_id = "your-project.your_dataset.your_table_name"

# Download all rows from a table.
rows_iter = client.list_rows(table_id)  # Make an API request.

# Iterate over rows to make the API requests to fetch row data.
rows = list(rows_iter)
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Download at most 10 rows.
rows_iter = client.list_rows(table_id, max_results=10)
rows = list(rows_iter)
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Specify selected fields to limit the results to certain columns.
table = client.get_table(table_id)  # Make an API request.
fields = table.schema[:2]  # First two columns.
rows_iter = client.list_rows(table_id, selected_fields=fields, max_results=10)
rows = list(rows_iter)
print("Selected {} columns from table {}.".format(len(rows_iter.schema), table_id))
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Print row data in tabular format.
rows = client.list_rows(table, max_results=10)
format_string = "{!s:<16} " * len(rows.schema)
field_names = [field.name for field in rows.schema]
print(format_string.format(*field_names))  # Prints column headers.
for row in rows:
    print(format_string.format(*row))  # Prints row data.

Ruby

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

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

החלוקה לדפים מתבצעת באופן אוטומטי בספריות הלקוח ב-Cloud עבור Ruby באמצעות Table#data ו-Data#next.

require "google/cloud/bigquery"

def browse_table
  bigquery = Google::Cloud::Bigquery.new project_id: "bigquery-public-data"
  dataset  = bigquery.dataset "samples"
  table    = dataset.table "shakespeare"

  # Load all rows from a table
  rows = table.data

  # Load the first 10 rows
  rows = table.data max: 10

  # Print row data
  rows.each { |row| puts row }
end

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

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

כל method‏ collection.list (חוץ מ-Tabledata) מחזירה מאפיין etag בתוצאה. המאפיין הזה הוא גיבוב של תוצאות הדף, שאפשר להשתמש בו כדי לבדוק אם הדף השתנה מאז הבקשה האחרונה. כששולחים בקשה ל-BigQuery עם ערך ETag, המערכת משווה את הערך הזה לערך ETag שמוחזר על ידי ה-API, ומגיבה בהתאם לתוצאת ההשוואה. כדי להימנע מקריאות מיותרות לרשימה, אפשר להשתמש ב-ETags באופן הבא:

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

    אם רוצים לקבל דף של ערכי רשימה רק אם הערכים השתנו, אפשר לבצע קריאה לרשימה עם ETag שמאוחסן מראש באמצעות הכותרת HTTP if-none-match. אם ה-ETag שסיפקתם לא תואם ל-ETag בשרת, BigQuery מחזיר דף של ערכי רשימה חדשים. אם תגי ה-ETag זהים, BigQuery מחזיר קוד סטטוס HTTP 304 Not Modified וללא ערכים. דוגמה לכך היא דף אינטרנט שבו המשתמשים ממלאים מעת לעת מידע שמאוחסן ב-BigQuery. אם לא חלו שינויים בנתונים, אפשר להימנע מביצוע קריאות מיותרות לרשימה ב-BigQuery באמצעות הכותרת if-none-match עם תגי ETags.

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

    אם רוצים להחזיר דף של ערכי רשימה רק אם ערכי הרשימה לא השתנו, אפשר להשתמש בכותרת HTTP 'if-match'. המערכת של BigQuery משווה את ערכי ה-ETag ומחזירה את דף התוצאות אם התוצאות לא השתנו, או מחזירה את התוצאה 412 Precondition Failed (התנאי המוקדם נכשל) אם הדף השתנה.

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

מעבר בין דפים בתוצאות של שאילתות

כל שאילתה כותבת לטבלת יעד. אם לא מציינים טבלת יעד, BigQuery API מאכלס אוטומטית את מאפיין טבלת היעד בהפניה לטבלה זמנית אנונימית.

API

קוראים את השדה jobs.config.query.destinationTable כדי לדעת לאיזו טבלה נכתבו תוצאות השאילתה. מתקשרים אל tabledata.list כדי לקרוא את תוצאות השאילתה.

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.QueryJobConfiguration;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TableResult;

// Sample to run query with pagination.
public class QueryPagination {

  public static void main(String[] args) {
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String query =
        "SELECT name, SUM(number) as total_people"
            + " FROM `bigquery-public-data.usa_names.usa_1910_2013`"
            + " GROUP BY name"
            + " ORDER BY total_people DESC"
            + " LIMIT 100";
    queryPagination(datasetName, tableName, query);
  }

  public static void queryPagination(String datasetName, String tableName, 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();

      TableId tableId = TableId.of(datasetName, tableName);
      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query)
              // save results into a table.
              .setDestinationTable(tableId)
              .build();

      bigquery.query(queryConfig);

      TableResult results =
          bigquery.listTableData(tableId, BigQuery.TableDataListOption.pageSize(20));

      // First Page
      results
          .getValues()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,\n", val.toString())));

      while (results.hasNextPage()) {
        // Remaining Pages
        results = results.getNextPage();
        results
            .getValues()
            .forEach(row -> row.forEach(val -> System.out.printf("%s,\n", val.toString())));
      }

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

כדי להגדיר את מספר השורות שיוחזרו בכל דף, משתמשים בGetQueryResults job ומגדירים את האפשרות pageSize של QueryResultsOption object שמעבירים, כמו בדוגמה הבאה:

TableResult result = job.getQueryResults();
QueryResultsOption queryResultsOption = QueryResultsOption.pageSize(20);

TableResult result = job.getQueryResults(queryResultsOption);

Node.js

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

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

// Import the Google Cloud client library using default credentials
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery();

async function queryPagination() {
  // Run a query and get rows using automatic pagination.

  const query = `SELECT name, SUM(number) as total_people
  FROM \`bigquery-public-data.usa_names.usa_1910_2013\`
  GROUP BY name
  ORDER BY total_people DESC
  LIMIT 100`;

  // Run the query as a job.
  const [job] = await bigquery.createQueryJob(query);

  // Wait for job to complete and get rows.
  const [rows] = await job.getQueryResults();

  console.log('Query results:');
  rows.forEach(row => {
    console.log(`name: ${row.name}, ${row.total_people} total people`);
  });
}
queryPagination();

Python

השיטה QueryJob.result מחזירה אובייקט שניתן לחזור עליו של תוצאות השאילתה. לחלופין,

  1. מומלץ לקרוא את הנכס QueryJob.destination. אם לא מגדירים את המאפיין הזה, ה-API מגדיר אותו כהפניה לטבלה זמנית אנונימית.
  2. אפשר לקבל את סכימת הטבלה באמצעות השיטה Client.get_table.
  3. יוצרים אובייקט שאפשר לחזור עליו בכל השורות בטבלת היעד באמצעות השיטה Client.list_rows.

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

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


from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

query = """
    SELECT name, SUM(number) as total_people
    FROM `bigquery-public-data.usa_names.usa_1910_2013`
    GROUP BY name
    ORDER BY total_people DESC
"""
query_job = client.query(query)  # Make an API request.
query_job.result()  # Wait for the query to complete.

# Get the destination table for the query results.
#
# All queries write to a destination table. If a destination table is not
# specified, the BigQuery populates it with a reference to a temporary
# anonymous table after the query completes.
destination = query_job.destination

# Get the schema (and other properties) for the destination table.
#
# A schema is useful for converting from BigQuery types to Python types.
destination = client.get_table(destination)

# Download rows.
#
# The client library automatically handles pagination.
print("The query data:")
rows = client.list_rows(destination, max_results=20)
for row in rows:
    print("name={}, count={}".format(row["name"], row["total_people"]))