Skip to content

Commit c1b42c9

Browse files
authored
formatting
1 parent 88bc4a7 commit c1b42c9

1 file changed

Lines changed: 59 additions & 67 deletions

File tree

packages/bigframes/specs/bigframes-bigquery-contributing.md

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# bigframes.bigquery inputs and outputs policies
22

3-
The goal of the [bigframes.bigquery APIs](https://dataframes.bigquery.dev/reference/api/bigframes.bigquery.html#module-bigframes.bigquery)
3+
The goal of the [bigframes.bigquery
4+
APIs](https://dataframes.bigquery.dev/reference/api/bigframes.bigquery.html#module-bigframes.bigquery)
45
is to provide the simplest possible mapping from BigQuery (GoogleSQL)
5-
[functions](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/functions-all) and
6-
[operations](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax) to Python. "Simplest" is somewhat ambiguous
7-
though, when it comes to the types involved and behaviors, so this document aims to expand on that vision with specific examples.
8-
6+
[functions](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/functions-all)
7+
and
8+
[operations](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax)
9+
to Python. "Simplest" is somewhat ambiguous though, when it comes to the types
10+
involved and behaviors, so this document aims to expand on that vision with
11+
specific examples.
912

1013
## SQL and BigFrames expression types
1114

12-
1315
<table>
1416
<tr>
1517
<td style="background-color: #c9daf8"><strong>SQL expression type(s)</strong>
@@ -30,13 +32,19 @@ though, when it comes to the types involved and behaviors, so this document aims
3032
<li><a href="https://github.com/googleapis/google-cloud-python/blob/bdd1cc5e336ec329d994aef28ed1070f1d771b74/packages/bigframes/bigframes/core/col.py#L35">bigframes deferred expression</a></li></ul>
3133

3234
</td>
33-
<td>Both Python Series and column expression should be supported as inputs, with the output reflecting the users input. Use a <a href="https://docs.python.org/3/library/typing.html#typing.TypeVar">TypeVar</a> rather than directly using union types to make type checking easier.
35+
<td>Both Python Series and column expression should be supported as inputs,
36+
with the output reflecting the users input. Use a <a
37+
href="https://docs.python.org/3/library/typing.html#typing.TypeVar">TypeVar</a>
38+
rather than directly using union types to make type checking easier.
3439
<p>
3540
<strong>Special considerations for Series inputs:</strong>
3641
<p>
37-
If an input and output are both a Series with the same number of rows, make sure the output Series is implicitly (row identity) alignable with the original input. In other words, don't generate a table expression.
42+
If an input and output are both a Series with the same number of rows, make sure
43+
the output Series is implicitly (row identity) alignable with the original
44+
input. In other words, don't generate a table expression.
3845
<p>
39-
If there are multiple Series inputs, they should be implicitly aligned if possible so as not to generate unnecessary table expressions.
46+
If there are multiple Series inputs, they should be implicitly aligned if
47+
possible so as not to generate unnecessary table expressions.
4048
</td>
4149
<td>Most scalar <a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/functions-all">functions </a>accept one or more column expressions as input.
4250
</td>
@@ -49,7 +57,10 @@ If there are multiple Series inputs, they should be implicitly aligned if possib
4957
<li><a href="https://github.com/googleapis/google-cloud-python/blob/bdd1cc5e336ec329d994aef28ed1070f1d771b74/packages/bigframes/bigframes/core/col.py#L35">bigframes deferred expression</a></li></ul>
5058

5159
</td>
52-
<td>Theoretically, we could try to get the type system to help the user disambiguate between this case and the "Column expression" case, but I think that's more trouble than it it's worth with regards to the expectations of Python users.
60+
<td>Theoretically, we could try to get the type system to help the user
61+
disambiguate between this case and the "Column expression" case, but I think
62+
that's more trouble than it it's worth with regards to the expectations of
63+
Python users.
5364
</td>
5465
<td><ul>
5566

@@ -62,28 +73,38 @@ If there are multiple Series inputs, they should be implicitly aligned if possib
6273
</td>
6374
<td><a href="https://dataframes.bigquery.dev/reference/api/bigframes.pandas.DataFrame.html#bigframes.pandas.DataFrame">bpd.DataFrame</a>
6475
<p>
65-
All columns are included as normal columns in the input table expression, including named index columns. If column names aren't unique or contain characters not compatible with BigQuery flexible column names, raise an error.
76+
All columns are included as normal columns in the input table expression,
77+
including named index columns. If column names aren't unique or contain
78+
characters not compatible with BigQuery flexible column names, raise an error.
6679
<p>
6780
Outputs are unordered and unindexed to allow for cleaner mapping with SQL.
6881
</td>
69-
<td>Most APIs that take a table expression as input, also output a table expression with the same number of rows and passing through all unused columns. \
70-
\
71-
This should be used to pass through any index or ordering columns (as well as all other columns, if that's the SQL behavior), to allow for easy joining with the original input DataFrame.
82+
<td>Most APIs that take a table expression as input, also output a table
83+
expression with the same number of rows and passing through all unused
84+
columns.
85+
86+
<p>This should be used to pass through any index or ordering columns (as well
87+
as all other columns, if that's the SQL behavior), to allow for easy joining
88+
with the original input DataFrame.
7289
</td>
7390
<td>Same number of rows as the input, so we should preserve index and ordering:<ul>
7491

7592
<li><a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-predict?hl=en">ML.PREDICT</a>
7693

7794
<p>
78-
Different number of rows in output, so no need to preserve index or ordering. Default index / ordering should be specified with the Session's configuration:<ul>
95+
Different number of rows in output, so no need to preserve index or ordering.
96+
Default index / ordering should be specified with the Session's
97+
configuration:
7998

99+
<ul>
80100
<li><a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-create?hl=en">CREATE MODEL</a>
81101
<li><a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/search_functions#search">SEARCH</a>
82102
<li><a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/search_functions#vector_search">VECTOR_SEARCH</a>
83103

84104
<p>
85-
Possible to have the same number of rows as the input, but joining with the original goes against the purpose of the feature:<ul>
105+
Possible to have the same number of rows as the input, but joining with the original goes against the purpose of the feature:
86106

107+
<ul>
87108
<li><a href="https://docs.cloud.google.com/bigquery/docs/differential-privacy#dp_define_privacy_unit_id">WITH DIFFERENTIAL_PRIVACY</a></li></ul>
88109
</li></ul>
89110
</li></ul>
@@ -118,7 +139,7 @@ Some APIs only take a table ID and not an arbitrary table expression:<ul>
118139
</td>
119140
<td><ul>
120141

121-
<li><a href="https://docs.cloud.google.com/bigquery/docs/analysis-rules">WITH AGGREGATION_THRESHOLD</a>
142+
<li><a href="https://docs.cloud.google.com/bigquery/docs/analysis-rules">WITH AGGREGATION_THRESHOLD</a>
122143
<li><a href="https://docs.cloud.google.com/bigquery/docs/differential-privacy#dp_define_privacy_unit_id">WITH DIFFERENTIAL_PRIVACY</a>
123144
<li><a href="https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#having_clause">HAVING</a> clause</li></ul>
124145

@@ -174,7 +195,7 @@ If the associated table expression is input as a DataFrame, validate that these
174195
<tr>
175196
<td>Literal values
176197
</td>
177-
<td>corresponding literal Python value (e.g. int, float, string)
198+
<td>corresponding literal Python value (e.g. int, float, string)
178199
</td>
179200
<td>For cases where scalar values are also supported, it should be safe to start with this and then expand to support expressions without a breaking change, as is done in <a href="https://github.com/googleapis/google-cloud-python/pull/16606">https://github.com/googleapis/google-cloud-python/pull/16606</a>.
180201
</td>
@@ -197,49 +218,42 @@ Would need some sort of bigframes deferred expression that can be tied to a tabl
197218
</tr>
198219
</table>
199220

200-
201-
202221
## Python policies
203222

204-
205223
### Naming
206224

207225
Take the SQL function name, keyword name (used as a function name in Python), or argument name and transform them to lower_snake_case to reflect Python conventions.
208226

209-
210227
### Internal expressions
211228

212-
Prefer creating deferred BigFrames expression objects where feasible. For example, all scalar outputting functions should return a `bigframes.pandas.Series` or `bigframes.core.col.Expression` that wraps a `bigframes.core.expression.Expression`.
229+
Prefer creating deferred BigFrames expression objects where feasible. For
230+
example, all scalar outputting functions should return a
231+
`bigframes.pandas.Series` or `bigframes.core.col.Expression` that wraps a
232+
`bigframes.core.expression.Expression`.
213233

214-
Prefer returning a `bigframes.pandas.DataFrame` that wraps a `bigframes.bigframes.core`
215-
216-
217-
```
218-
.bigframe_node.BigFrameNode. See from_bq_data_source in bigframes.core
219-
```
220-
221-
222-
`.array_value.ArrayValue`, as an example.
223-
224-
Exceptions to this are cases where the output schema is likely to evolve or differ in ways that are difficult to model, such as the `ML.PREDICT` SQL function, where output columns differ based on the model type and support for model types are frequently added to BigQuery. In these exceptional cases, the generated query should run immediately and the returned value should wrap the results.
234+
Prefer returning a `bigframes.pandas.DataFrame` that wraps a
235+
`bigframes.bigframes.core.bigframe_node.BigFrameNode`. See `from_bq_data_source` in
236+
`bigframes.core.array_value.ArrayValue`, as an example.
225237

238+
Exceptions to this are cases where the output schema is likely to evolve or
239+
differ in ways that are difficult to model, such as the `ML.PREDICT` SQL
240+
function, where output columns differ based on the model type and support for
241+
model types are frequently added to BigQuery. In these exceptional cases, the
242+
generated query should run immediately and the returned value should wrap the
243+
results.
226244

227245
### Argument syntax details
228246

229247
Arguments in Python can be one of:
230248

249+
* Positional
250+
* Supported by `*args` in Python, but not recommended. Positional arguments in SQL should map to named positional or keyword arguments in Python.
251+
* Positional or keyword
252+
* Required positional arguments should be positional, just like they are in SQL.
253+
* Keyword-only
254+
* All other arguments should be keyword-only. Use `, * ,` Python syntax to achieve this.
231255

232-
233-
* Positional
234-
* Supported by `*args` in Python, but not recommended. Positional arguments in SQL should map to named positional or keyword arguments in Python.
235-
* Positional or keyword
236-
* Required positional arguments should be positional, just like they are in SQL.
237-
* Keyword-only
238-
* All other arguments should be keyword-only. Use `, * ,` Python syntax to achieve this.
239-
240-
For optional parameters, use an optional sentinel (see: https://stackoverflow.com/a/76606310/101923) and omit the value from the generated SQL if the user doesn't explicitly provide one. This ensures that an explicit NULL / None value can be passed in.
241-
242-
256+
For optional parameters, use an optional sentinel (see: <https://stackoverflow.com/a/76606310/101923>) and omit the value from the generated SQL if the user doesn't explicitly provide one. This ensures that an explicit NULL / None value can be passed in.
243257

244258
```
245259
@@ -260,15 +274,12 @@ def spam(*, ham: list[str] | None | Default = DEFAULT):
260274
261275
```
262276

263-
264-
265277
### Scalar operations types policies
266278

267279
Many operations output a table expression. For these, the output type is always a DataFrame, regardless of the input types.
268280

269281
For scalar operations, there are three cases to consider when determining the output types:
270282

271-
272283
<table>
273284
<tr>
274285
<td><strong>Scalar ops - Input type(s)</strong>
@@ -300,16 +311,12 @@ Preserve ordering and index(es). Join inputs as needed before applying the opera
300311
</tr>
301312
</table>
302313

303-
304-
305314
## Examples
306315

307-
308316
### PIVOT SQL operator
309317

310318
SQL syntax ([docs](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)):
311319

312-
313320
```
314321
FROM from_item[, ...] pivot_operator
315322
@@ -325,10 +332,8 @@ as_alias:
325332
326333
```
327334

328-
329335
SQL example:
330336

331-
332337
```
333338
WITH Produce AS (
334339
SELECT 'Kale' as product, 51 as sales, 'Q1' as quarter, 2020 as year UNION ALL
@@ -372,10 +377,8 @@ SELECT * FROM
372377
373378
```
374379

375-
376380
Python definition:
377381

378-
379382
```
380383
def pivot(
381384
table_expression: bpd.DataFrame,
@@ -387,13 +390,11 @@ def pivot(
387390
...
388391
```
389392

390-
391393
Since pivot creates a table expression, we run immediately.
392394

393395
\
394396
Python usage:
395397

396-
397398
```
398399
pivotted = bbq.pivot(
399400
my_produce_dataframe,
@@ -403,13 +404,10 @@ pivotted = bbq.pivot(
403404
)
404405
```
405406

406-
407-
408407
### UNPIVOT SQL operator
409408

410409
SQL syntax ([docs](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unpivot_operator)):
411410

412-
413411
```
414412
FROM from_item[, ...] unpivot_operator
415413
@@ -441,10 +439,8 @@ unpivot_alias and row_value_alias:
441439
[AS] alias
442440
```
443441

444-
445442
SQL example:
446443

447-
448444
```
449445
WITH Produce AS (
450446
SELECT 'Kale' as product, 51 as Q1, 23 as Q2, 45 as Q3, 3 as Q4 UNION ALL
@@ -475,10 +471,8 @@ UNPIVOT(sales FOR quarter IN (Q1, Q2, Q3, Q4)) -- single_column_unpivot
475471
+---------+-------+---------*/
476472
```
477473

478-
479474
Python definition:
480475

481-
482476
```
483477
def unpivot(
484478
table_expression: bpd.DataFrame,
@@ -491,13 +485,11 @@ def unpivot(
491485
...
492486
```
493487

494-
495488
Since unpivot creates a table expression, we run immediately.
496489

497490
\
498491
Python usage:
499492

500-
501493
```
502494
unpivotted = bbq.unpivot(
503495
my_produce_dataframe,

0 commit comments

Comments
 (0)