我用Scala语言写了一个小批量的工作,我首先从数据库中提取数据,然后将其转储到谷歌电子表格中。
最初的工作非常好,但突然间,它开始失败与以下错误。
ERR com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
ERR "code" : 400,
ERR "errors" : [ {
ERR "domain" : "global",
ERR "reason" : "badRequest"
ERR {
ERR } ],
ERR "message" : "This action would increase the number of cells in the workbook above the limit of 5000000 cells.",
ERR at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
ERR at
令人惊讶的是,我正在插入一个1800条记录的列表,每条记录有20列。因此,在我的情况下,单元格的总数为36000,但它是远离错误中提到的限制50,00,000单元格。
我无法找到任何具体的解决方案,但我从电子表格中删除了几个空列,批处理工作开始正常工作。所以,这可能是那些空行和空列在限制溢出背后的原因。
我已经在插入数据之前对整个电子表格进行了清理。但我认为,我需要删除那些空的单元格,而不是清理它。
请看下面的代码片段来检查我目前的执行情况。请注意,在这里,我已经使用了范围值"A2:Z",因为第一行是页眉,我不想删除它。",因为第一行是页眉,我不希望它被删除。
def clearAndInsertRowsToSpreadSheet(itemsToAppend : util.List[util.List[AnyRef]],
range : String,
spreadSheetId : String){
clearSpreadSheet(range,spreadSheetId)
insertRowsToSpreadSheet(itemsToAppend,range,spreadSheetId)
}
private def insertRowsToSpreadSheet(itemsToAppend : util.List[util.List[AnyRef]], range : String,
spreadSheetId : String) ={
val data : ValueRange = new ValueRange()
data.setValues(itemsToAppend)
val appendRequest = googleSpreadSheetService.getSheets().spreadsheets()
.values().append(spreadSheetId, range,data)
appendRequest.setValueInputOption("USER_ENTERED")
appendRequest.setInsertDataOption("INSERT_ROWS")
val appendValuesResponse = appendRequest.execute()
appendValuesResponse.getUpdates
}
private def clearSpreadSheet(range : String, spreadSheetId : String) : String = {
val clearDataRequest = googleSpreadSheetService.
getSheets().spreadsheets().
values().clear(spreadSheetId,range, new ClearValuesRequest())
val clearResponse = clearDataRequest.execute()
clearResponse.getClearedRange
}
但是,我怎么能写一个代码来删除所有的行和列是空的,然后再转储我的数据。我试着用 BatchClearValuesByDataFilterRequest
但它没有工作。我正在寻找一个机制,在这个机制中,我可以提供一个条件来检查ROWs和Columns的空单元格。
感谢任何建议
经过几轮的测试和观察,我发现问题出在我使用""的方式上。附加"函数。在我的代码中,我是先对电子表格进行清理,然后用Append方法追加新数据。
这里,需要注意两点。
清理函数只清除单元格的值,但不删除单元格,也不释放内存。所以那些被清除的单元格仍然是已经被占用的。
Google API append函数实际上是用现有的行(单元格)预增新数据,而不是使用现有的空单元格。
为了让它更清楚,假设我们有100行,12列。所以总共有1200个单元格被占用。在执行问题陈述中提到的代码时,清理函数会清理这1200个单元格,但不会删除它。所以,Google API认为这些单元格仍然被占用。现在,当调用有50个对象的append函数时,append方法会将现有的100行移到下行,从而预置50行新行。所以,现在,在执行我的代码后,被占用的单元格总数将达到1800个。
Total Number of Old cells = 100 ROWs * 12 Columns = 1200
Total Number of New cells = 50 ROWs * 12 Columns = 600
---------------------------------------------------------
Total Number of cell after job execution = 1800
所以,考虑到上面的例子,频繁的执行上面的代码会导致我们的电子表格达到最大允许单元格数限制50,00,000的错误。
我们可以通过两种方式来解决上述问题。
移除未使用的单元格,而不是使用以下方法清除它们 批量更新 和 删除尺寸请求.
使用 更新 方法而不是 附加 这将使用现有的单元格来插入数据。但是需要注意的是,在使用Update方法之前,需要先清除电子表格。
我建议使用解决方案#2更新方法,因为UpdateResponse提供了更好的深度统计。它提供了更新的行、列和单元格的总数,可以用于跟踪目的。
以下是上述两种解决方案的代码片段。
这里,我们需要注意一点。我们不能删除电子表格的所有行。所以我们需要在电子表格中保持静态的标题。而在使用DeleteDimentionRequest的时候,统计索引是以0开始的。
val dimensionRange : DimensionRange = new DimensionRange()
dimensionRange.setDimension("ROWS")
dimensionRange.setStartIndex(1)
//dimensionRange.setEndIndex(1001)
val deleteDimensionRequest : DeleteDimensionRequest = new DeleteDimensionRequest()
deleteDimensionRequest.setRange(dimensionRange)
val request : Request = new Request()
request.setDeleteDimension(deleteDimensionRequest)
val requests : util.List[Request] = new util.ArrayList[Request]()
requests.add(request)
val batchUpdateRequest : BatchUpdateSpreadsheetRequest =new BatchUpdateSpreadsheetRequest()
batchUpdateRequest.setRequests(requests)
val batchUpdate: Sheets#Spreadsheets#BatchUpdate = googleSpreadSheetService.getSheets()
.spreadsheets()
.batchUpdate(spreadSheetId, batchUpdateRequest)
val batchUpdateResponse = batchUpdate.execute()
解决方案#2. 清理单元格,然后调用 更新 方法来插入数据。
嵌入数据的方法:/Code
private def clearAndInsertRowsToSpreadSheet(itemsToAppend : util.List[util.List[AnyRef]], range : String, spreadSheetId : String) : UpdateValuesResponse = {
clearSpreadSheet(range, spreadSheetId)
updateSpreadSheetData(itemsToAppend,range, spreadSheetId)
}
private def updateSpreadSheetData(itemsToAppend : util.List[util.List[AnyRef]], range : String, spreadSheetId : String) ={
val data : ValueRange = new ValueRange()
data.setValues(itemsToAppend)
val updateRequest: Sheets#Spreadsheets#Values#Update = googleSpreadSheetService.getSheets()
.spreadsheets()
.values()
.update(spreadSheetId, range, data)
updateRequest.setValueInputOption("USER_ENTERED")
val updateValuesResponse: UpdateValuesResponse = updateRequest.execute()
updateValuesResponse
}
private def clearSpreadSheet(range : String, spreadSheetId : String) : String = {
val clearDataRequest = googleSpreadSheetService.
getSheets().spreadsheets().
values().clear(spreadSheetId,range, new ClearValuesRequest())
val clearResponse = clearDataRequest.execute()
clearResponse.getClearedRange
}
希望,以上回答足以让你明白问题的本质及其可能的解决方法。