現在、大量のBigQueryデータをエクスポートし、クエリした結果をCSVファイルとしてローカルに保存するソフトウェアを作成しています。私はPython 3とGoogleが提供するクライアントを使用しました。構成と認証を行いましたが、問題は、データをローカルに保存できないことです。実行するたびに、次のようになります- エラーメッセージ:
googleapiclient.errors.HttpError:https://www.googleapis.com/bigquery/v2/projects/round-office-769/jobs?alt=jsonが "無効な抽出先URI 'response/file-name-*。csv'を返しました。有効なGoogleストレージパスである必要があります。 ">
これは私のジョブ設定です:
def export_table(service, cloud_storage_path,
projectId, datasetId, tableId, sqlQuery,
export_format="CSV",
num_retries=5):
# Generate a unique job_id so retries
# don't accidentally duplicate export
job_data = {
'jobReference': {
'projectId': projectId,
'jobId': str(uuid.uuid4())
},
'configuration': {
'extract': {
'sourceTable': {
'projectId': projectId,
'datasetId': datasetId,
'tableId': tableId,
},
'destinationUris': ['response/file-name-*.csv'],
'destinationFormat': export_format
},
'query': {
'query': sqlQuery,
}
}
}
return service.jobs().insert(
projectId=projectId,
body=job_data).execute(num_retries=num_retries)
クラウドストレージの代わりにローカルパスを使用してデータを保存できるといいのですが、それは間違っていました。
だから私の質問は:
クエリされたデータをローカル(またはローカルデータベース)にダウンロードできますか、それともGoogle Cloud Storageを使用する必要がありますか?
ページングメカニズムを使用して、すべてのデータを直接(Google Cloud Storage経由でルーティングせずに)ダウンロードできます。基本的には、ページごとにページトークンを生成し、ページ内のデータをダウンロードして、すべてのデータがダウンロードされるまで、つまり、トークンが使用できなくなるまでこれを繰り返す必要があります。 Javaのコード例を以下に示します。うまくいけばアイデアが明確になります。
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.BigqueryScopes;
import com.google.api.client.util.Data;
import com.google.api.services.bigquery.model.*;
/* your class starts here */
private String projectId = ""; /* fill in the project id here */
private String query = ""; /* enter your query here */
private Bigquery bigQuery;
private Job insert;
private TableDataList tableDataList;
private Iterator<TableRow> rowsIterator;
private List<TableRow> rows;
private long maxResults = 100000L; /* max number of rows in a page */
/* run query */
public void open() throws Exception {
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory);
if (credential.createScopedRequired())
credential = credential.createScoped(BigqueryScopes.all());
bigQuery = new Bigquery.Builder(transport, jsonFactory, credential).setApplicationName("my app").build();
JobConfigurationQuery queryConfig = new JobConfigurationQuery().setQuery(query);
JobConfiguration jobConfig = new JobConfiguration().setQuery(queryConfig);
Job job = new Job().setConfiguration(jobConfig);
insert = bigQuery.jobs().insert(projectId, job).execute();
JobReference jobReference = insert.getJobReference();
while (true) {
Job poll = bigQuery.jobs().get(projectId, jobReference.getJobId()).execute();
String state = poll.getStatus().getState();
if ("DONE".equals(state)) {
ErrorProto errorResult = poll.getStatus().getErrorResult();
if (errorResult != null)
throw new Exception("Error running job: " + poll.getStatus().getErrors().get(0));
break;
}
Thread.sleep(10000);
}
tableDataList = getPage();
rows = tableDataList.getRows();
rowsIterator = rows != null ? rows.iterator() : null;
}
/* read data row by row */
public /* your data object here */ read() throws Exception {
if (rowsIterator == null) return null;
if (!rowsIterator.hasNext()) {
String pageToken = tableDataList.getPageToken();
if (pageToken == null) return null;
tableDataList = getPage(pageToken);
rows = tableDataList.getRows();
if (rows == null) return null;
rowsIterator = rows.iterator();
}
TableRow row = rowsIterator.next();
for (TableCell cell : row.getF()) {
Object value = cell.getV();
/* extract the data here */
}
/* return the data */
}
private TableDataList getPage() throws IOException {
return getPage(null);
}
private TableDataList getPage(String pageToken) throws IOException {
TableReference sourceTable = insert
.getConfiguration()
.getQuery()
.getDestinationTable();
if (sourceTable == null)
throw new IllegalArgumentException("Source table not available. Please check the query syntax.");
return bigQuery.tabledata()
.list(projectId, sourceTable.getDatasetId(), sourceTable.getTableId())
.setPageToken(pageToken)
.setMaxResults(maxResults)
.execute();
}
そのテーブルでtabledata.list()オペレーションを実行し、「alt = csv」を設定すると、テーブルの先頭がCSVとして返されます。
Google BigQuery APIとpandasおよびpandas.ioをインストールすると、Jupyterノートブック内でPythonを実行し、BQテーブルにクエリを実行して、データを取得できますローカルのデータフレームに、そこからCSVに書き出すことができます。
Mikhail Berlyant が言ったように、
BigQueryには、クエリ結果をGCSまたはローカルファイルに直接エクスポート/ダウンロードする機能はありません。
まだ3つのステップでWeb UIを使用してエクスポートできます
コストを低く抑えるには、コンテンツをGCSにエクスポートしたらテーブルを削除し、ファイルをマシンにダウンロードしたらバケットとバケットからコンテンツを削除してください。
BigQuery画面で、クエリを実行する前に、[その他]> [クエリ設定]に移動します
これは以下を開きます
ここにあなたがしたいです
次にそれを保存すると、クエリが特定のテーブルに保存されるように構成されます。これでクエリを実行できます。
これをGCPにエクスポートするには、テーブルに移動して、[エクスポート]> [GCSにエクスポート]をクリックする必要があります。
次の画面が開きます
Select GCS locationで、バケット、フォルダ、ファイルを定義します。
たとえば、daria_bucket(という名前のバケットがあります。小文字、数字、ハイフン(-)、およびアンダースコア(_)のみを使用してください。ドット(。 )を使用して有効なドメイン名を形成することができます。)、ファイルをバケットのルートにtestという名前で保存する場合、書き込み(GCSの場所を選択)
daria_bucket/test.csv
ファイルが大きすぎる(1 GBを超える)場合、エラーが発生します。これを修正するには、ワイルドカードを使用してより多くのファイルに保存する必要があります。したがって、*を追加する必要があります。
daria_bucket/test*.csv
これにより、バケットdaria_bucket内で、テーブルから抽出されたすべてのデータがtest000000000000、test000000000001、test000000000002、... testXという名前の複数のファイルに保存されます。
次に、ストレージに移動すると、バケットが表示されます。
その中に入ると、1つ(または複数)のファイルが見つかります。その後、そこからダウンロードできます。