커스텀 템플릿을 Clean Room에 추가해요
커스텀 템플릿을 Clean Room에 추가해요
서비스 종료 공지
레거시 Provider 및 Consumer Data Clean Rooms은 지원이 중단될 예정이에요. 날짜와 마이그레이션 지침은 end-of-life timeline을 참고하세요.
공급자와 소비자 모두 Clean Room에 사용자 지정 템플릿을 추가할 수 있어요. 사용자 지정 템플릿은 Snowflake 제공 템플릿과 동일한 방식으로 실행돼요. 사용자 지정 템플릿은 API를 사용해 만들고, API 또는 (그에 맞게 설계된 경우) UI를 사용해 실행해요.
Clean Room 템플릿은 유효한 JinjaSQL 템플릿이에요. 자체 Clean Room 템플릿을 만들기 전에 read the clean room reference guide for custom templates를 읽어 보시는 것이 좋아요.
출처: 문서
본문
공급자가 작성한 사용자 지정 템플릿
공급자는 소비자 승인 없이 clean room에 사용자 지정 템플릿을 추가할 수 있어요. 소비자는 승인 없이 공급자가 작성한 템플릿을 실행할 수 있어요. 다음 섹션에서는 API를 사용하여 공급자가 사용자 지정 템플릿을 추가하는 방법과 소비자가 해당 템플릿을 실행하는 방법을 설명할게요.
공급자가 소비자가 clean rooms UI에서 실행할 수 있는 템플릿을 설계하려면 해당 템플릿에 대한 사용자 입력 양식을 만들어야 해요.
공급자가 작성한 템플릿 추가
공급자는 provider.add_custom_sql_template을 호출하여 사용자 지정 템플릿을 한 번에 하나씩 추가해요. 이때 템플릿 JinjaSQL을 문자열로 전달해요. 사용자 지정 템플릿은 clean room의 템플릿 목록에 표시되며 Snowflake 제공 템플릿과 동일하게 동작해요. clean room에는 사용자 지정 템플릿과 Snowflake 제공 템플릿을 원하는 비율로 혼합하여 포함할 수 있어요.
템플릿에서 호출할 사용자 지정 Python UDF를 업로드할 수도 있어요.
팁
소비자가 사용할 사용자 지정 템플릿을 추가할 때는 템플릿이 수행하는 작업과 템플릿에서 사용하는 필수 및 선택 인수를 설명하는 문서를 제공해야 해요.
다음 SQL 예제는 공급자가 간단한 사용자 지정 템플릿을 clean room에 추가하는 방법을 보여줘요.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
$basic_template_name,
$$
SELECT
COUNT(*) AS total_count
FROM IDENTIFIER({{ my_table[0] }}) AS c
INNER JOIN IDENTIFIER({{ source_table[0] }}) AS p
ON IDENTIFIER({{ consumer_id | join_policy }}) = IDENTIFIER({{ provider_id | join_policy }})
{% if where_clause %}
WHERE {{ where_clause | sqlsafe }}
{% endif %};
$$
);
이 템플릿은 네 개의 필수 매개 변수(my_table 배열, source_table 배열, consumer_id 열 이름, provider_id 열 이름)와 WHERE 절을 지정하는 선택적 where_clause 매개 변수를 사용해요.
대부분의 템플릿(앞의 예제 포함)에서는 열 이름 충돌을 피하기 위해 사용자가 제공하는 열 이름을 테이블 이름으로 완전히 한정해야 해요. 접두사에서 테이블 이름 접두사를 열 이름에 연결하여 유효한 식별자를 얻는 것은 쉽지 않기 때문이에요 (IDENTIFIER(p.{{ col_name | sqlsafe }})는 오류예요). 따라서 호출자에게 열 이름만이 아니라 완전히 한정된 테이블 이름을 요청해야 할 수도 있어요. 테이블 이름은 승인된 소문자 별칭 p와 c를 사용해야 해요.
공급자가 작성한 템플릿 실행
clean rooms API를 사용할 때 소비자는 템플릿을 실행하기 위해 consumer.run_analysis를 호출하고, 공급자는 공급자 실행 분석을 위해 provider.submit_analysis_request를 호출해요.
템플릿을 clean rooms UI에서 실행할 수 있게 하려면 공급자가 해당 템플릿에 대한 사용자 입력 양식을 만들어야 해요. clean rooms UI에서는 공급자가 작성한 템플릿만 실행할 수 있어요.
clean room 협업자는 consumer.view_template_definition을 호출하여 clean room에 있는 모든 템플릿의 JinjaSQL을 볼 수 있어요. 단, 공급자가 템플릿을 난독화한 경우는 예외예요. 공급자가 작성한 템플릿만 난독화할 수 있어요.
consumer.get_arguments_from_template을 호출하면 템플릿에서 사용되는 변수를 파싱하고 나열할 수 있어요. 하지만 크거나 복잡한 템플릿의 경우 이 프로시저가 모든 템플릿 변수를 나열하지 못할 수도 있으므로 템플릿 사용자를 위한 유용한 문서를 꼭 제공하세요.
다음 예제는 소비자가 앞에서 본 공급자의 사용자 지정 템플릿을 실행하는 방법을 보여줘요.
CALL samooha_by_snowflake_local_db.consumer.run_analysis(
$cleanroom_name,
'basic_template',
['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS'], -- Populates the my_table array.
['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS'], -- Populates the source_table array.
OBJECT_CONSTRUCT(
'consumer_id', 'c.hashed_email', -- Populates the consumer_id variable.
'provider_id', 'p.hashed_email', -- Populates the provider_id variable.
'where_clause','c.status = $$MEMBER$$ AND c.age_band > 30' -- Populates the where_clause variable.
-- $$...$$ is used to stringify the column value.
)
);
공급자 템플릿 예제 코드
공급자가 사용자 지정 템플릿을 추가하는 방법과 소비자가 이를 실행하는 방법을 보여주는 전체 코드 예제는 다음과 같아요. 이 코드를 실행하려면 clean rooms API가 설치된 두 개의 별도 계정이 필요해요. 하나는 공급자 역할을 하고 다른 하나는 소비자 역할을 해요.
소비자가 작성한 사용자 지정 템플릿
소비자는 공급자가 승인하면 clean room에 사용자 지정 템플릿을 추가할 수 있어요. clean room에 추가되면 소비자가 작성한 템플릿은 공급자가 작성한 템플릿과 동일한 방식으로 실행할 수 있어요. 소비자가 사용자 지정 템플릿을 추가하는 방법은 다음과 같아요.
공급자가 표준 방식으로 clean room을 생성, 공유, 게시해요.
소비자가 표준 방식으로 clean room을 설치하고 구성해요.
소비자가 consumer.create_template_request를 호출하고 사용자 지정 템플릿 문자열을 전달해요.
공급자가 provider.list_pending_template_requests를 호출하여 보류 중인 요청을 확인해요.
공급자는 소비자가 자신의 템플릿을 실행하려는 요청을 승인(provider.approve_template_request)하거나 거부(provider.reject_template_request)할 수 있어요. (여러 요청을 승인하거나 거부하는 일괄 처리 버전의 메서드도 있어요.) 공급자가 템플릿을 승인하면 템플릿이 즉시 clean room에 추가돼요.
- 공급자가 템플릿을 승인하기 전에 먼저 데이터에 필요한 조인 및 열 정책을 선언해야 해요.
소비자는 consumer.list_template_requests(승인 상태를 표시) 또는 consumer.view_added_templates(자신의 템플릿이 clean room에 추가되었는지 확인)를 호출하여 요청 상태를 확인해요. 템플릿은 공급자가 승인한 후에만 clean room에 추가돼요.
소비자는 표준 방식으로 consumer.run_analysis를 호출하여 템플릿을 실행해요.
참고
공급자는 소비자가 권한을 부여한 경우 소비자가 추가한 템플릿을 실행할 수 있어요.
소비자 템플릿 예제
여기 소비자가 커스텀 템플릿을 제출하고 실행하는 방법을 보여 주는 전체 코드 예시가 있어요. 다음 워크시트 파일을 Snowflake 계정에 업로드하세요. 코드를 실행하려면 clean rooms API가 설치된 별도의 계정 두 개가 필요해요. 하나는 공급자(provider) 역할을 하고 다른 하나는 소비자(consumer) 역할을 해요.
커스텀 템플릿의 사용자 입력 양식 정의하기
커스텀 템플릿을 clean rooms UI에서 실행하려면 공급자가 템플릿에 대한 입력 양식을 정의해야 해요. 이 요구 사항은 템플릿에 소비자가 설정할 인수가 없어도 적용돼요. 소비자는 템플릿의 사용자 입력 양식을 정의할 수 없어요.
중요
provider.restrict_table_options_to_consumers 또는 provider.restrict_template_options_to_consumers를 사용해서 테이블이나 템플릿을 특정 사용자로 제한했다면, 이러한 제한은 clean rooms UI에서 예상대로 작동하지 않아요. 이런 제한이 있는 상태에서는 템플릿을 clean rooms에서 UI 사용으로 활성화하지 않는 것이 좋아요.
구성 양식(configuration form)을 사용하면 clean rooms UI에서 사용자가 커스텀 템플릿에 값을 전달할 수 있어요. API를 사용할 때 템플릿에 값을 전달하는 방식과 비슷해요.
다음 예시는 max_age, favorite_color, source_table 세 가지 변수를 사용하는 커스텀 템플릿을 보여 줘요.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
'color_picker_template',
$$
SELECT p.hashed_email
FROM source_table[0] AS p
WHERE
p.age <= {{ max_age }} AND
UPPER(p.favorite_color) = UPPER({{ favorite_color }});
$$);
다음 예시는 앞선 커스텀 템플릿을 코드로 실행할 때 템플릿 변수를 전달하는 방법을 보여 줘요.
CALL samooha_by_snowflake_local_db.consumer.run_analysis(
$cleanroom_name,
'color_picker_template',
[], -- Consumer tables, assigned to my_table array.
['MYDB.MYSCH.COLOR_PREFERENCES'], -- Provider tables, assigned to source_table array.
object_construct(
'max_age', 30, -- Assign max_age.
'favorite_color', 'blue' -- Assign favorite_color.
)
);
이 템플릿을 clean rooms UI에서 실행하려면 소비자가 이러한 템플릿 변수를 할당할 수 있는 양식을 정의해야 해요. 다음 예시는 소비자가 max_age, favorite_color, source_table에 값을 할당할 수 있는 간단한 양식을 정의하는 방법을 보여 줘요.
CALL samooha_by_snowflake_local_db.provider.add_ui_form_customizations(
$cleanroom_name,
'color_picker_template',
{ -- Top-level template settings.
'display_name': 'Color matcher',
'description': 'See which users like the same color as you',
'methodology': 'Choose a color and a max age',
'render_table_dropdowns': {
'render_consumer_table_dropdown': false,
'render_provider_table_dropdown': true -- Show a dropdown of provider tables.
} -- Chosen value is assigned to source_table.
},
{ -- Form entry elements, one per template argument.
'max_age': {
'type': 'integer',
'display_name': 'Maximum age',
'description': 'Matching user must be less than or equal to this value.',
'required': TRUE
},
'favorite_color': {
'type': 'dropdown',
'display_name': 'Favorite color',
'description': 'Choose the favorite color to match.',
'choices': ['Red', 'Blue', 'Green', 'Yellow'],
'required': TRUE
}
},
{} -- Output config not used in this example.
);
-- You must always call this procedure to propagate UI changes.
CALL samooha_by_snowflake_local_db.provider.create_or_update_cleanroom_listing(
$cleanroom_name);
앞서 정의한 양식은 소비자가 Configure Analysis & Query 단계에서 템플릿을 실행할 때 clean rooms UI에 나타나요. 이 양식에는 Collaborator table로 표시된 source_table용 테이블 선택기, Maximum age로 표시된 max_age용 정수 선택 요소, Favorite color로 표시된 favorite_color용 색상 이름 드롭다운 메뉴가 포함돼요. 다음 이미지에서 확인할 수 있어요.
또한 공급자 또는 소비자의 조인 정책(join policies), 열 정책(column policies), 테이블 등에서 미리 채워진 드롭다운 메뉴를 정의할 수도 있어요. 양식 요소 유형에 대한 자세한 내용은 을(를) 참조하세요.
### Populate source_table and my_table
The standard `source_table` and `my_table` template variables can be populated as follows:
- **Enable the default table selector drop-down menus:** These drop-down menus are single-selection. You can show or hide them by using the
`render_provider_table_dropdown` and `render_consumer_table_dropdown` settings. The drop-down menus pass fully qualified table names
to the `source_table` and `my_table` template variables, respectively.
### Qualify your column names
Most templates require all column names to be fully qualified to avoid column-name ambiguity.
The template must alias all tables as `p` or `c`, depending on whether they are provider or consumer tables. The template should
reference all columns using their `p` or `c` aliases. [Learn more about aliasing.](https://docs.snowflake.com/user-guide/cleanrooms/custom-templates#label-dcr-required-template-table-aliases)
If you create a drop-down column selector, you must either supply the `p` or `c` table alias explicitly in a `choices` array of the
drop-down menu, or you must add the alias in your template.
The following example shows how to provide the table alias in a drop-down menu:
```
'provider_join_col': {
'display_name': 'Provider Join Column',
'choices': ['p.HASHED_EMAIL', 'p.HASHED_SSN'],
'type': 'dropdown',
'description': 'Select the provider column to join users on.',
'infoMessage': 'We recommend using HASHED_EMAIL.',
'size': 'M',
'group': 'Enable Provider Features'
}
```
However, this method is limiting because you must know all the column names in advance.
As an alternative, you can dynamically populate a column drop-down menu by providing a `references` property. However, such a
selector returns bare column names — for example, *hashed_email* — rather than fully-qualified column names — for example,
*p.hashed_email*. If bare column names are returned, you must scope the column to the table explicitly in your template. For example, the
following code creates a drop-down menu where a user can select a column from the provider’s join policy:
>
```
'p_join_col': {
'type': 'dropdown',
'references': ['PROVIDER_JOIN_POLICY']
}
```
To use the column name in a template, the template must hard-code the table alias in front of the column name as shown in the following
example:
>
```
SELECT p.{{ p_join_col | sqlsafe }} FROM table_col AS p;
```
### Recommendations for developing a template that can be run in the clean rooms UI
The following steps show a recommended workflow for developing a template that can be run in the clean rooms UI:
#### 1. Develop the template
First develop your template and any [scripts](https://docs.snowflake.com/user-guide/cleanrooms/demo-flows/custom-code) that it calls by using only the clean
rooms API in both the provider and consumer accounts. Testing the template in the API is much faster and less error-prone than using the UI.
Test your template thoroughly in the API, both on the provider and consumer side, to ensure that the template does exactly what you
want it to do. Testing in the API is very quick, and changes are propagated immediately to the consumer account.
After you test your template and it runs exactly as you want, then move on to designing the input form.
#### 2. Develop the input form
When the template and any uploaded scripts are working as intended, then start working on the input form. At this stage, you use the API in
the provider account, but the UI in the consumer account.
When you make changes using the API, some values in the UI are refreshed immediately, some are refreshed when the user clicks
**Refresh**, and some are refreshed only every 10 minutes. Therefore, when you work on the input form, create and update the form on the
provider side using the API, but install and configure the clean room in the consumer account using the clean rooms UI,
not the API. This ensures that you are using fresh data in the clean room UI.
Additionally, each time that you make changes to the input form in the API, create a new clean room to ensure that you use the latest clean
room data. Use an incrementing number in the name; for example, “My clean room 1,” “My clean room 2,” and so on. Then, install the clean
room in the client by using the UI. Finally, delete the old clean rooms because there is a limit to the number of clean rooms an account
can hold.
An input form must be attached to a template, otherwise the clean room and form won’t be runnable in the clean rooms UI. When you develop
your form, consider using a template that simply mirrors back all the values that are selected in the form so that you can verify what
values are sent to the template.
For example, let’s suppose that your production template looks like the following template:
```
SELECT {{ col1 | sqlsafe | column_policy }}, {{ col2 | sqlsafe | column_policy }}
FROM IDENTIFIER({{ source_table[0] }}) AS p
JOIN IDENTIFIER({{ my_table[0] }}) AS c
```
You could create the following template that mirrors back all the values of that production template:
```
SELECT
{{ col1 | default('Undefined')}},
{{ col2 | default('Undefined') }},
{{ source_table[0] | default('Undefined') }},
{{ my_table[0] | default('Undefined') }},
{{ provider_join_col | default('Undefined') }},
{{ consumer_join_col | default('Undefined') }}
;
그런 다음 이 여섯 가지 변수 값을 설정하는 양식을 설계하고, 해당 양식을 프로덕션 템플릿이 아니라 미러 템플릿에 연결하세요.
**입력 양식 개발을 위한 일반적인 팁**
다음 목록은 효과적인 입력 양식을 개발하는 데 도움이 되는 자세한 팁을 제공해요.
- UI에서 clean room을 설치, 구성 또는 실행할 때 일반적인 “Installation failed” 또는 “Something went wrong” 메시지가 표시된다면, 해당 메시지는 양식이나 템플릿을 추가할 때 잡히지 않은 UI 양식 또는 연결된 템플릿에 오류가 있음을 의미할 수 있어요.
- 한 필드가 다른 필드에 의존하는 경우(예: 테이블 드롭다운 메뉴에서 선택한 값을 기반으로 하는 열 드롭다운 메뉴)에는 부모 필드를 먼저 배치하고, 가능하면 자식 필드 바로 위에 배치해서 사용자가 자식 필드를 채우기 전에 부모 필드를 먼저 채우도록 하세요. 의존 필드가 있는 경우 부모 필드에서 값을 선택하기 전까지 자식 드롭다운 메뉴는 비어 있어요.
- `order` 또는 `group` 값을 지정하지 않으면 항목은 정의된 순서대로 렌더링돼요.
- 유용한 `infoMessage` 및 `description` 텍스트를 포함하고, 사용자가 입력할 수 있는 예시 값을 보여 주세요.
- 변수 데이터 유형에 맞는 정확한 요소 유형을 선택하세요. 예를 들어 정수라면 자유 형식 텍스트 상자 대신 `integer`를 선택하세요. 템플릿에서 Jinja 필터를 사용하여 값을 캐스팅할 수 있어요. 예: `SELECT {{ max_age | int }};`.
- 커스텀 템플릿에 대한 최소 구성 양식을 정의하지 않으면 해당 템플릿은 clean rooms UI에서 실행할 수 없어요.
- 템플릿의 변수에 대한 양식 요소를 정의하지 않으면 사용자 양식에 해당 변수에 대한 일반 텍스트 상자가 렌더링돼요. 텍스트 상자에 템플릿 변수 이름이 레이블로 표시되고 설명이나 제안이 없기 때문에 원하는 방식이 아닐 가능성이 커요.
- `add_ui_form_customizations`에 지정된 양식 요소는 요소와 같은 이름의 일치하는 템플릿 변수가 없으면 렌더링되지 않아요.
---
---
- API에서 이루어진 템플릿 변경 사항은 UI로 빠르고 안정적으로 전파되므로, 템플릿 변경을 위해 새 clean room을 만들 필요가 없어요. 하지만 UI 단계에 도달하기 전에 API에서 템플릿을 개발하고 테스트해야 해요.
- 드롭다운 메뉴를 특정 테이블의 컬럼 값으로 자동으로 채울 수는 없어요. 드롭다운 메뉴에 값을 하드코딩할 수는 있지만, 런타임에 테이블의 값을 표시할 수는 없어요.
#### 3. 입력 폼을 프로덕션 템플릿에 연결하기
폼이 원하는 대로 정확히 보이고, 폼이 모든 템플릿 변수를 사용자가 접근할 수 있게 만든 다음에는, `provider.add_ui_form_customizations` 호출에서 작업 중인 템플릿을 입력 폼에 할당하세요.
---
## 더 알아보기 (Learn more)
- [end-of-life timeline](https://docs.snowflake.com/user-guide/cleanrooms/pc-eol)
- [read the clean room reference guide for custom templates](https://docs.snowflake.com/user-guide/cleanrooms/custom-templates)
- [custom Python UDFs](https://docs.snowflake.com/user-guide/cleanrooms/demo-flows/custom-code)
- [provider-run analyses](https://docs.snowflake.com/user-guide/cleanrooms/demo-flows/provider-run-analysis)
- [Provider example code](https://docs.snowflake.com/static/samples/clean-rooms/provider-template-p.sql)
- [Consumer example code](https://docs.snowflake.com/static/samples/clean-rooms/provider-template-c.sql)
- [consumer grants permission](https://docs.snowflake.com/user-guide/cleanrooms/demo-flows/provider-run-analysis)
- [Provider example code](https://docs.snowflake.com/static/samples/clean-rooms/consumer-template-p.sql)
- [Consumer example code](https://docs.snowflake.com/static/samples/clean-rooms/consumer-template-c.sql)
- [Learn more about aliasing.](https://docs.snowflake.com/user-guide/cleanrooms/custom-templates#label-dcr-required-template-table-aliases)
- [scripts](https://docs.snowflake.com/user-guide/cleanrooms/demo-flows/custom-code)