Google BigQuery使用.net客户端库

时间:2015-06-24 04:45:57

标签: google-bigquery google-api-dotnet-client

我正在尝试执行查询(带有10个字段的Basic select语句)。我的表包含超过500k行。 C#应用程序仅返回4260行的响应。但Web UI会返回所有记录。

为什么我的代码只返回部分数据,选择所有记录并加载到C#数据表的最佳方法是什么?如果有任何代码段,对我来说会更有帮助。

using Google.Apis.Auth.OAuth2;
using System.IO;
using System.Threading;
using Google.Apis.Bigquery.v2;
using Google.Apis.Bigquery.v2.Data;
using System.Data;
using Google.Apis.Services;
using System;
using System.Security.Cryptography.X509Certificates;

namespace GoogleBigQuery
{
    public class Class1
    {
        private static void Main()
        {
            try
            {
                Console.WriteLine("Start Time: {0}", DateTime.Now.ToString());
                String serviceAccountEmail = "SERVICE ACCOUNT EMAIL";

                var certificate = new X509Certificate2(@"KeyFile.p12", "notasecret", X509KeyStorageFlags.Exportable);

                ServiceAccountCredential credential = new ServiceAccountCredential(
                   new ServiceAccountCredential.Initializer(serviceAccountEmail)
                   {
                       Scopes = new[] { BigqueryService.Scope.Bigquery, BigqueryService.Scope.BigqueryInsertdata, BigqueryService.Scope.CloudPlatform, BigqueryService.Scope.DevstorageFullControl }
                   }.FromCertificate(certificate));

                BigqueryService Service = new BigqueryService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "PROJECT NAME"
                });

                string query = "SELECT * FROM [publicdata:samples.shakespeare]";

                JobsResource j = Service.Jobs;

                QueryRequest qr = new QueryRequest();

                string ProjectID = "PROJECT ID";

                qr.Query = query;
                qr.MaxResults = Int32.MaxValue;
                qr.TimeoutMs = Int32.MaxValue;

                DataTable DT = new DataTable();
                int i = 0;

                QueryResponse response = j.Query(qr, ProjectID).Execute();

                string pageToken = null;

                if (response.JobComplete == true)
                {
                    if (response != null)
                    {
                        int colCount = response.Schema.Fields.Count;

                        if (DT == null)
                            DT = new DataTable();

                        if (DT.Columns.Count == 0)
                        {
                            foreach (var Column in response.Schema.Fields)
                            {
                                DT.Columns.Add(Column.Name);
                            }
                        }

                        pageToken = response.PageToken;

                        if (response.Rows != null)
                        {
                            foreach (TableRow row in response.Rows)
                            {
                                DataRow dr = DT.NewRow();

                                for (i = 0; i < colCount; i++)
                                {
                                    dr[i] = row.F[i].V;
                                }

                                DT.Rows.Add(dr);
                            }
                        }
                        Console.WriteLine("No of Records are Readed: {0} @ {1}", DT.Rows.Count.ToString(), DateTime.Now.ToString());

                        while (true)
                        {
                            int StartIndexForQuery = DT.Rows.Count;
                            Google.Apis.Bigquery.v2.JobsResource.GetQueryResultsRequest SubQR = Service.Jobs.GetQueryResults(response.JobReference.ProjectId, response.JobReference.JobId);
                            SubQR.StartIndex = (ulong)StartIndexForQuery;
                            //SubQR.MaxResults = Int32.MaxValue;
                            GetQueryResultsResponse QueryResultResponse = SubQR.Execute();

                            if (QueryResultResponse != null)
                            {
                                if (QueryResultResponse.Rows != null)
                                {
                                    foreach (TableRow row in QueryResultResponse.Rows)
                                    {
                                        DataRow dr = DT.NewRow();

                                        for (i = 0; i < colCount; i++)
                                        {
                                            dr[i] = row.F[i].V;
                                        }

                                        DT.Rows.Add(dr);
                                    }
                                }

                                Console.WriteLine("No of Records are Readed: {0} @ {1}", DT.Rows.Count.ToString(), DateTime.Now.ToString());

                                if (null == QueryResultResponse.PageToken)
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        Console.WriteLine("Response is null");
                    }
                }


                int TotalCount = 0;

                if (DT != null && DT.Rows.Count > 0)
                {
                    TotalCount = DT.Rows.Count;
                }
                else
                {
                    TotalCount = 0;
                }

                Console.WriteLine("End Time: {0}", DateTime.Now.ToString());
                Console.WriteLine("No. of records readed from google bigquery service: " + TotalCount.ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine("Error Occurred: " + e.Message);
            }

            Console.ReadLine();
        }
    }
}

在此示例查询中获取公共数据集的结果,In表中包含164656行,但响应仅首次返回85000行,然后再次查询以获取第二组结果。 (但不知道这是获得所有结果的唯一解决方案。)

在这个示例中只包含4个字段,即使它不返回所有行,在我的case表中包含超过15个字段,我得到约~10k行~~ 4000行的响应,我需要再次查询再次获取选择1000行的剩余结果需要时间长达2分钟,因此我期望在单个响应中选择所有记录的最佳方式。

3 个答案:

答案 0 :(得分:2)

来自用户#的答案:Pentium10

无法运行查询并在单次拍摄中选择较大的响应。您可以对结果进行分页,也可以创建要导出到文件的作业,然后使用应用程序中生成的文件。出口是免费的。

步骤运行大型查询并将结果导出到存储在GCS上的文件:

1)在作业配置中将allowLargeResults设置为true。您还必须使用allowLargeResults标志指定目标表。

示例:

"configuration": 
  {
    "query": 
    {
      "allowLargeResults": true,
      "query": "select uid from [project:dataset.table]"
      "destinationTable": [project:dataset.table]

    }
  }

2)现在您的数据位于您设置的目标表中。您需要创建一个新作业,并将导出属性设置为能够将表导出到文件。导出是免费的,但您需要激活Google云端存储才能将结果文件放在那里。

3)最后,您从GCS下载大文件。

轮到我设计解决方案以获得更好的结果。

答案 1 :(得分:0)

Web UI自动flattens数据。这意味着您会看到每个嵌套字段有多行。

当您通过API运行相同的查询时,它将不会被展平,并且您将获得更少的行,因为嵌套字段作为对象返回。您应该检查是否属于这种情况。

另一个是你确实需要对结果进行分页。 Paging through list results解释了这一点。

如果您只想做一个工作,而不是将查询输出写入表,而不是将表导出为JSON,并从GCS下载导出。

答案 2 :(得分:0)

希望这可以帮助某人。可以使用PageToken检索下一组分页结果。以下是如何使用PageToken的示例代码。虽然,我喜欢免费出口的想法。在这里,我将行写入平面文件,但您可以将它们添加到DataTable中。显然,将大型DataTable保留在内存中是一个坏主意。

    public void ExecuteSQL(BigqueryService bqservice, String ProjectID)
    {
        string sSql = "SELECT r.Dealname, r.poolnumber, r.loanid FROM [MBS_Dataset.tblRemitData] R left join each [MBS_Dataset.tblOrigData] o on R.Dealname = o.Dealname and R.Poolnumber = o.Poolnumber and R.LoanID = o.LoanID Order by o.Dealname, o.poolnumber, o.loanid limit 100000";

        QueryRequest _r = new QueryRequest();
        _r.Query = sSql;
        QueryResponse _qr = bqservice.Jobs.Query(_r, ProjectID).Execute();

        string pageToken = null;
        if (_qr.JobComplete != true)
        {
            //job not finished yet! expecting more data
            while (true)
            {
                var resultReq = bqservice.Jobs.GetQueryResults(_qr.JobReference.ProjectId, _qr.JobReference.JobId);
                resultReq.PageToken = pageToken;
                var result = resultReq.Execute();

                if (result.JobComplete == true)
                {
                    WriteRows(result.Rows, result.Schema.Fields);
                    pageToken = result.PageToken;
                    if (pageToken == null)
                        break;
                }
            }
        }
        else
        {
            List<string> _fieldNames = _qr.Schema.Fields.ToList().Select(x => x.Name).ToList();
            WriteRows(_qr.Rows, _qr.Schema.Fields);
        }
    }