Bigquery:Extract Job不会创建文件

时间:2012-07-30 05:50:42

标签: google-bigquery

我正在开发一个使用Bigquery作为分析引擎的Java应用程序。能够使用Insert a Query Job上的代码运行查询作业(并获得结果)。必须在stackoverflow上使用this comment修改代码以使用服务帐户。

现在,需要运行提取作业以将表导出到GoogleStorage上的存储桶。基于Exporting a Table,能够修改Java代码以插入提取作业(下面的代码)。运行时,提取作业的状态从PENDING更改为RUNNING更改为DONE。问题是没有文件实际上传到指定的存储桶。

可能有用的信息:

  • createAuthorizedClient函数返回Bigquery实例并适用于查询作业,因此服务帐户,私钥等可能没有问题。
  • 还尝试在google's api-explorer上手动创建并运行插入作业,并在存储桶中成功创建文件。在代码中使用与项目,数据集,表和目标uri相同的值,因此这些值应该是正确的。

以下是代码(粘贴完整文件以防其他人认为有用):

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.Bigquery.Jobs.Insert;
import com.google.api.services.bigquery.BigqueryScopes;
import com.google.api.services.bigquery.model.Job;
import com.google.api.services.bigquery.model.JobConfiguration;
import com.google.api.services.bigquery.model.JobConfigurationExtract;
import com.google.api.services.bigquery.model.JobReference;
import com.google.api.services.bigquery.model.TableReference;

public class BigQueryJavaGettingStarted {

    private static final String PROJECT_ID = "123456789012";
    private static final String DATASET_ID = "MY_DATASET_NAME";
    private static final String TABLE_TO_EXPORT = "MY_TABLE_NAME";
    private static final String SERVICE_ACCOUNT_ID = "123456789012-...@developer.gserviceaccount.com";
    private static final File PRIVATE_KEY_FILE = new File("/path/to/privatekey.p12");
    private static final String DESTINATION_URI = "gs://mybucket/file.csv";

    private static final List<String> SCOPES =  Arrays.asList(BigqueryScopes.BIGQUERY);
    private static final HttpTransport TRANSPORT = new NetHttpTransport();
    private static final JsonFactory JSON_FACTORY = new JacksonFactory();

    public static void main (String[] args) {
        try {
            executeExtractJob();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static final void executeExtractJob() throws IOException, InterruptedException, GeneralSecurityException {
        Bigquery bigquery = createAuthorizedClient();

        //Create a new Extract job
        Job job = new Job();
        JobConfiguration config = new JobConfiguration();
        JobConfigurationExtract extractConfig = new JobConfigurationExtract();
        TableReference sourceTable = new TableReference();

        sourceTable.setProjectId(PROJECT_ID).setDatasetId(DATASET_ID).setTableId(TABLE_TO_EXPORT);
        extractConfig.setSourceTable(sourceTable);
        extractConfig.setDestinationUri(DESTINATION_URI);
        config.setExtract(extractConfig);
        job.setConfiguration(config);

        //Insert/Execute the created extract job
        Insert insert = bigquery.jobs().insert(PROJECT_ID, job);
        insert.setProjectId(PROJECT_ID);
        JobReference jobId = insert.execute().getJobReference();

        //Now check to see if the job has successfuly completed (Optional for extract jobs?)
        long startTime = System.currentTimeMillis();
        long elapsedTime;
        while (true) {
            Job pollJob = bigquery.jobs().get(PROJECT_ID, jobId.getJobId()).execute();
            elapsedTime = System.currentTimeMillis() - startTime;
            System.out.format("Job status (%dms) %s: %s\n", elapsedTime, jobId.getJobId(), pollJob.getStatus().getState());
            if (pollJob.getStatus().getState().equals("DONE")) {
                break;
            }
            //Wait a second before rechecking job status
            Thread.sleep(1000);
        }

    }

    private static Bigquery createAuthorizedClient() throws GeneralSecurityException, IOException {
        GoogleCredential credential = new GoogleCredential.Builder()
            .setTransport(TRANSPORT)
            .setJsonFactory(JSON_FACTORY)
            .setServiceAccountScopes(SCOPES)
            .setServiceAccountId(SERVICE_ACCOUNT_ID)
            .setServiceAccountPrivateKeyFromP12File(PRIVATE_KEY_FILE)
            .build();

        return Bigquery.builder(TRANSPORT, JSON_FACTORY)
            .setApplicationName("My Reports")
            .setHttpRequestInitializer(credential)
            .build();
    }
}

这是输出:

Job status (337ms) job_dc08f7327e3d48cc9b5ba708efe5b6b5: PENDING
...
Job status (9186ms) job_dc08f7327e3d48cc9b5ba708efe5b6b5: PENDING
Job status (10798ms) job_dc08f7327e3d48cc9b5ba708efe5b6b5: RUNNING
...
Job status (53952ms) job_dc08f7327e3d48cc9b5ba708efe5b6b5: RUNNING
Job status (55531ms) job_dc08f7327e3d48cc9b5ba708efe5b6b5: DONE

这是一张小桌子(大约4MB)所以大约一分钟的工作似乎没问题。不知道为什么在桶中没有创建文件或者如何调试它。任何帮助将不胜感激。

正如Craig指出的那样,打印了status.errorResult()和status.errors()值。

  • getErrorResults():{“message”:“后端错误。作业已中止。”,“原因”:“internalError”}
  • getErrors():null

4 个答案:

答案 0 :(得分:0)

我认为问题在于您使用的存储桶名称 - 上面的mybucket只是一个示例,您需要将其替换为您在Google存储中实际拥有的存储桶。如果您以前从未使用过GS,那么intro docs会有所帮助。

你的第二个问题是如何调试它 - 我建议在状态设置为Job后查看返回的DONE对象。以错误结束的作业仍会使其处于DONE状态,不同之处在于它们附加了错误结果,因此job.getStatus().hasErrorResult()应该为真。 (我从未使用过Java客户端库,因此我猜测该方法名称。)您可以在jobs docs中找到更多信息。

答案 1 :(得分:0)

看起来写入路径时出现拒绝访问错误:gs://pixalate_test/from_java.csv。您是否可以确保执行导出作业的用户具有对存储桶的写入权限(并且该文件尚不存在)? 我已经在这个问题上提交了一个内部bigquery错误...我们应该在这种情况下给出一个更好的错误。

答案 2 :(得分:0)

另一个区别是,我注意到您没有将作业类型作为config.setJobType(JOB_TYPE)传递; 其中常量是私有静态最终字符串JOB_TYPE =“ extract”; 同样对于json,也需要设置格式。

答案 3 :(得分:0)

我有同样的问题。但事实证明,我输入了错误的表名。但是,Google并未生成错误消息,指出“该表不存在”。那会帮助我找到问题所在。

谢谢!