通过API上传本地CSV失败

时间:2012-08-04 00:16:08

标签: ruby google-bigquery

我正在使用官方的Google Ruby gem,虽然到目前为止我所尝试的其他所有内容都工作正常(包括列出项目,数据集和表格以及创建表格),但启动加载作业失败了以下内容在JSON错误响应中:

"Job configuration must contain exactly one job-specific configuration object (e.g., query, load, extract, spreadsheetExtract), but there were 0: "

我创建的正文字符串如下:

--xxx
Content-Type: application/json; charset=UTF-8
{"configuration":{"load":{"destinationTable":{"projectId":"mycompany.com:projectId","datasetId":"all_events","tableId":"install"},"createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND"}}}
--xxx
Content-Type: application/octet-stream
test,second,1234,6789,83838
--xxx

我以前创建了install表,其中包含适用于该数据的模式,因此不应该是问题。

最后,为了完整性,这里是我用来触发请求的实际代码段(这是更大类中的两个方法):

def create_insert_job
  config = {
    'configuration' => {
      'load' => {
        'destinationTable' => {
          'projectId' => 'mycompany.com:projectId',
          'datasetId' => 'all_events',
          'tableId' => 'install'
        },
        'createDisposition' => 'CREATE_NEVER',
        'writeDisposition' => 'WRITE_APPEND'
      }
    }
  }

  body = "#{multipart_boundary}\n"
  body += "Content-Type: application/json; charset=UTF-8\n"
  body += "#{config.to_json}\n"
  body += "#{multipart_boundary}\n"
  body +="Content-Type: application/octet-stream\n"
  body += "test,second,1234,6789,83838\n"
  body += "#{multipart_boundary}\n"

  prepare_big_query # This simply gets tokens and instantiates google_client and big_query_api
  param_hash = { api_method: big_query_api.jobs.insert }
  param_hash[:parameters] = {'projectId' =>'mycompany.com:projectId'}
  param_hash[:body] = body
  param_hash[:headers] = {'Content-Type' => "multipart/related; boundary=#{multipart_boundary}"}

  result = google_client.execute(param_hash)
  JSON.parse(result.response.body)
end

def multipart_boundary
  '--xxx'
end

有什么想法吗?

为使此代码工作而给予以下答案的补充

请注意,上面的#multipart_boundary方法返回时已经预先添加了“ - ”。这是一个问题,因为设置边界标题(在参数哈希中)将导致' - xxx',当我们真正想要'xxx'时。

此外,这个宝石的文档非常粗糙,因为在修复我的换行问题后(根据@jcondit的回答)我收到一个关于上传到错误URL的新错误。那是因为你需要添加:

'uploadType' => 'multipart'

参数,以便将请求发送到正确的URL。

所以有效的最终param_hash(再次修复新行和边界之后)看起来像:

param_hash = { api_method: big_query_api.jobs.insert }
param_hash[:parameters] = {'projectId' => project_id, 'uploadType' => 'multipart'}
param_hash[:body] = body
param_hash[:headers] = {'Content-Type' => "multipart/related; boundary=#{multipart_boundary}"}

2 个答案:

答案 0 :(得分:0)

您的http请求格式错误 - bigquery根本不会将此识别为加载作业。我正在出去吃饭的路上,所以我不能做更深入的调查,但希望能给你一个指示继续进行。

我仔细看了一下,我发现你的要求没有任何问题。一个建议是尝试在bigquery UI中执行相同的加载,并使用chrome工具 - >开发人员工具/网络选项卡查看发送的RPC。

如果我使用虚拟csv文件,我得到:

--yql9f05215ct
Content-Type: application/json; charset=utf-8

{"jobReference":{"projectId":"helixdata2"},"configuration":{"load":{"destinationTable":{"projectId":"helixdata2","datasetId":"lotsOdata","tableId":"import"}}}}
--yql9f05215ct
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

YSxiLGMKYyxkLGUKZixnLGgK
--yql9f05215ct--

答案 1 :(得分:0)

您需要在每个MIME部分的标题和每个MIME部分的正文之间插入一个额外的换行符。您的请求正文应如下所示:

--xxx
Content-Type: application/json; charset=UTF-8

{"configuration":{"load":{"destinationTable":{"projectId":"mycompany.com:projectId","datasetId":"all_events","tableId":"install"},"createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND"}}}
--xxx
Content-Type: application/octet-stream

test,second,1234,6789,83838
--xxx--

请注意每个部分中Content-Type标题后面的额外换行符。

另外,不要忘记最后的边界分隔符有一个尾随 - 附加到它。