|
14 | 14 |
|
15 | 15 | """Define API Jobs.""" |
16 | 16 |
|
17 | | -import copy |
18 | 17 | import threading |
19 | 18 |
|
20 | 19 | import six |
@@ -1291,12 +1290,12 @@ def query_plan(self): |
1291 | 1290 | See: |
1292 | 1291 | https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#statistics.query.queryPlan |
1293 | 1292 |
|
1294 | | - :rtype: list of dict |
| 1293 | + :rtype: list of :class:`QueryPlanEntry` |
1295 | 1294 | :returns: mappings describing the query plan, or an empty list |
1296 | 1295 | if the query has not yet completed. |
1297 | 1296 | """ |
1298 | 1297 | plan_entries = self._job_statistics().get('queryPlan', ()) |
1299 | | - return [copy.deepcopy(entry) for entry in plan_entries] |
| 1298 | + return [QueryPlanEntry.from_api_repr(entry) for entry in plan_entries] |
1300 | 1299 |
|
1301 | 1300 | def query_results(self): |
1302 | 1301 | """Construct a QueryResults instance, bound to this job. |
@@ -1324,3 +1323,149 @@ def result(self, timeout=None): |
1324 | 1323 | super(QueryJob, self).result(timeout=timeout) |
1325 | 1324 | # Return a QueryResults instance instead of returning the job. |
1326 | 1325 | return self.query_results() |
| 1326 | + |
| 1327 | + |
| 1328 | +class QueryPlanEntryStep(object): |
| 1329 | + """Map a single step in a query plan entry. |
| 1330 | +
|
| 1331 | + :type kind: str |
| 1332 | + :param kind: step type |
| 1333 | +
|
| 1334 | + :type substeps: |
| 1335 | + :param substeps: names of substeps |
| 1336 | + """ |
| 1337 | + def __init__(self, kind, substeps): |
| 1338 | + self.kind = kind |
| 1339 | + self.substeps = list(substeps) |
| 1340 | + |
| 1341 | + @classmethod |
| 1342 | + def from_api_repr(cls, resource): |
| 1343 | + """Factory: construct instance from the JSON repr. |
| 1344 | +
|
| 1345 | + :type resource: dict |
| 1346 | + :param resource: JSON representation of the entry |
| 1347 | +
|
| 1348 | + :rtype: :class:`QueryPlanEntryStep` |
| 1349 | + :return: new instance built from the resource |
| 1350 | + """ |
| 1351 | + return cls( |
| 1352 | + kind=resource.get('kind'), |
| 1353 | + substeps=resource.get('substeps', ()), |
| 1354 | + ) |
| 1355 | + |
| 1356 | + def __eq__(self, other): |
| 1357 | + if not isinstance(other, self.__class__): |
| 1358 | + return NotImplemented |
| 1359 | + return self.kind == other.kind and self.substeps == other.substeps |
| 1360 | + |
| 1361 | + |
| 1362 | +class QueryPlanEntry(object): |
| 1363 | + """Map a single entry in a query plan. |
| 1364 | +
|
| 1365 | + :type name: str |
| 1366 | + :param name: name of the entry |
| 1367 | +
|
| 1368 | + :type entry_id: int |
| 1369 | + :param entry_id: ID of the entry |
| 1370 | +
|
| 1371 | + :type wait_ratio_avg: float |
| 1372 | + :param wait_ratio_avg: average wait ratio |
| 1373 | +
|
| 1374 | + :type wait_ratio_max: float |
| 1375 | + :param wait_ratio_avg: maximum wait ratio |
| 1376 | +
|
| 1377 | + :type read_ratio_avg: float |
| 1378 | + :param read_ratio_avg: average read ratio |
| 1379 | +
|
| 1380 | + :type read_ratio_max: float |
| 1381 | + :param read_ratio_avg: maximum read ratio |
| 1382 | +
|
| 1383 | + :type copute_ratio_avg: float |
| 1384 | + :param copute_ratio_avg: average copute ratio |
| 1385 | +
|
| 1386 | + :type copute_ratio_max: float |
| 1387 | + :param copute_ratio_avg: maximum copute ratio |
| 1388 | +
|
| 1389 | + :type write_ratio_avg: float |
| 1390 | + :param write_ratio_avg: average write ratio |
| 1391 | +
|
| 1392 | + :type write_ratio_max: float |
| 1393 | + :param write_ratio_avg: maximum write ratio |
| 1394 | +
|
| 1395 | + :type records_read: int |
| 1396 | + :param records_read: number of records read |
| 1397 | +
|
| 1398 | + :type records_written: int |
| 1399 | + :param records_written: number of records written |
| 1400 | +
|
| 1401 | + :type status: str |
| 1402 | + :param status: entry status |
| 1403 | +
|
| 1404 | + :type steps: List(QueryPlanEntryStep) |
| 1405 | + :param steps: steps in the entry |
| 1406 | + """ |
| 1407 | + def __init__(self, |
| 1408 | + name, |
| 1409 | + entry_id, |
| 1410 | + wait_ratio_avg, |
| 1411 | + wait_ratio_max, |
| 1412 | + read_ratio_avg, |
| 1413 | + read_ratio_max, |
| 1414 | + compute_ratio_avg, |
| 1415 | + compute_ratio_max, |
| 1416 | + write_ratio_avg, |
| 1417 | + write_ratio_max, |
| 1418 | + records_read, |
| 1419 | + records_written, |
| 1420 | + status, |
| 1421 | + steps): |
| 1422 | + self.name = name |
| 1423 | + self.entry_id = entry_id |
| 1424 | + self.wait_ratio_avg = wait_ratio_avg |
| 1425 | + self.wait_ratio_max = wait_ratio_max |
| 1426 | + self.read_ratio_avg = read_ratio_avg |
| 1427 | + self.read_ratio_max = read_ratio_max |
| 1428 | + self.compute_ratio_avg = compute_ratio_avg |
| 1429 | + self.compute_ratio_max = compute_ratio_max |
| 1430 | + self.write_ratio_avg = write_ratio_avg |
| 1431 | + self.write_ratio_max = write_ratio_max |
| 1432 | + self.records_read = records_read |
| 1433 | + self.records_written = records_written |
| 1434 | + self.status = status |
| 1435 | + self.steps = steps |
| 1436 | + |
| 1437 | + @classmethod |
| 1438 | + def from_api_repr(cls, resource): |
| 1439 | + """Factory: construct instance from the JSON repr. |
| 1440 | +
|
| 1441 | + :type resource: dict |
| 1442 | + :param resource: JSON representation of the entry |
| 1443 | +
|
| 1444 | + :rtype: :class:`QueryPlanEntry` |
| 1445 | + :return: new instance built from the resource |
| 1446 | + """ |
| 1447 | + records_read = resource.get('recordsRead') |
| 1448 | + if records_read is not None: |
| 1449 | + records_read = int(records_read) |
| 1450 | + |
| 1451 | + records_written = resource.get('recordsWritten') |
| 1452 | + if records_written is not None: |
| 1453 | + records_written = int(records_written) |
| 1454 | + |
| 1455 | + return cls( |
| 1456 | + name=resource.get('name'), |
| 1457 | + entry_id=resource.get('id'), |
| 1458 | + wait_ratio_avg=resource.get('waitRatioAvg'), |
| 1459 | + wait_ratio_max=resource.get('waitRatioMax'), |
| 1460 | + read_ratio_avg=resource.get('readRatioAvg'), |
| 1461 | + read_ratio_max=resource.get('readRatioMax'), |
| 1462 | + compute_ratio_avg=resource.get('computeRatioAvg'), |
| 1463 | + compute_ratio_max=resource.get('computeRatioMax'), |
| 1464 | + write_ratio_avg=resource.get('writeRatioAvg'), |
| 1465 | + write_ratio_max=resource.get('writeRatioMax'), |
| 1466 | + records_read=records_read, |
| 1467 | + records_written=records_written, |
| 1468 | + status=resource.get('status'), |
| 1469 | + steps=[QueryPlanEntryStep.from_api_repr(step) |
| 1470 | + for step in resource.get('steps', ())], |
| 1471 | + ) |
0 commit comments