> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-trino-dialect.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud의 사용자 정의 FUNCTION

> Cloud에 실행형 Python 사용자 정의 FUNCTION을 추가합니다

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>베타</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>베타 기능</span>
        </a>;
};

사용자 정의 FUNCTION(UDF)를 사용하면 1,000개가 넘는 기본 제공 [FUNCTION](/ko/reference/functions/regular-functions/overview)만으로는 제공되지 않는 ClickHouse의 기능까지 확장할 수 있습니다.

ClickHouse Cloud에서 사용자 정의 FUNCTION을 생성하고 관리하는 방법은 여러 가지입니다:

1. SQL 사용
2. UI와 직접 작성한 코드 사용(공개 베타)
3. [Cloud API](#manage-udfs-with-the-cloud-api) 사용(베타)
4. [Terraform](#manage-udfs-with-terraform) 사용(알파)

<div id="sql-udfs">
  ## SQL 사용자 정의 함수
</div>

SQL UDF는 람다 표현식으로 [`CREATE FUNCTION`](/ko/reference/statements/create/function) SQL 문을 사용해 생성할 수 있습니다.

이 예시에서는 간단한 실행형 사용자 정의 함수 `isBusinessHours`를 생성합니다.
이 함수는 특정 타임스탬프가 일반적인 업무 시간 내에 해당하는지 확인하고, 해당하면 true를, 그렇지 않으면 false를 반환합니다.

1. Cloud Console에 로그인한 다음 SQL 콘솔을 엽니다
2. 다음 SQL 쿼리를 작성하여 `isBusinessHours` 함수를 생성합니다:

```sql theme={null}
CREATE FUNCTION isBusinessHours AS (ts) ->
toDayOfWeek(ts) BETWEEN 1 AND 5
AND toHour(ts) BETWEEN 9 AND 17;
```

3. 새로 생성한 UDF를 테스트하려면 아래 명령을 실행하세요:

```sql theme={null}
SELECT isBusinessHours('2026-03-20 10:00:00'::DateTime), isBusinessHours('2026-03-20 23:00:00'::DateTime);
```

다음과 같은 결과가 반환됩니다:

```response theme={null}
1   0
```

4. 방금 생성한 UDF를 삭제하려면 `DROP FUNCTION` 명령을 사용할 수 있습니다:

```sql theme={null}
DROP FUNCTION isBusinessHours
```

<Warning>
  **중요**

  ClickHouse Cloud의 UDF는 **사용자 수준 설정을 상속하지 않습니다**. UDF는 기본 시스템 설정으로 실행됩니다.
</Warning>

이는 다음을 의미합니다:

* 세션 수준 설정(`SET` 문로 설정)은 UDF 실행 Context로 전달되지 않습니다
* 사용자 프로필 설정은 UDF에 상속되지 않습니다
* 쿼리 수준 설정은 UDF 실행 중에는 적용되지 않습니다

<div id="ui-udfs">
  ## UI를 통해 생성한 사용자 정의 함수
</div>

<BetaBadge />

ClickHouse Cloud는 UI를 통해 사용자 정의 함수를 생성할 수 있는 환경을 제공합니다.

이 예시에서는 특정 타임스탬프가 일반적인 업무 시간에 해당하는지 확인하는 동일한 간단한 실행형 사용자 정의 함수 `isBusinessHours`를 생성합니다.
이전에는 SQL로 이를 생성했지만, 이번에는 Python으로 작성하고 UI를 통해 구성합니다.

<Steps>
  <Step title="Python 파일 생성" id="create-python-file">
    로컬에 새 파일 `main.py`를 만드세요:

    ```python theme={null}
    cat > main.py << 'EOF'
    import sys
    from datetime import datetime

    for line in sys.stdin:
        ts = datetime.fromisoformat(line.strip())
        result = 1 if (0 <= ts.weekday() <= 4 and 9 <= ts.hour <= 17) else 0
        print(result)
        sys.stdout.flush()
    EOF
    ```

    Python 스크립트에서 서드파티 패키지를 import하는 경우, 해당 패키지를 `requirements.txt` 파일에 나열하면 ClickHouse Cloud가 이를 설치합니다. ZIP에 의존성을 직접 번들할 수도 있지만, 이 경우 두 CPU 아키텍처 모두에 대한 캐시된 패키지를 포함해야 하므로 `requirements.txt`를 사용하는 편이 더 간단합니다. 예시는 다음과 같습니다:

    ```text theme={null}
    requests>=2.28.0
    numpy>=1.23.0
    ```

    <Note>
      ClickHouse Cloud는 다음 단계에서 UI를 통해 업로드할 zip 파일에 `main.py`가 포함되어 있다고 가정합니다.
      파일 이름을 다르게 지정하면 오류가 발생합니다.
    </Note>
  </Step>

  <Step title="번들 종속성 및 로컬 파일" id="bundle-dependencies">
    종속성 패키지와 추가 로컬 파일(예: wheel 파일, 설정 파일, 데이터 파일)을 포함하려면 `main.py` 및 `requirements.txt`와 같은 디렉터리에 배치하십시오. ZIP 아카이브를 만들 때는 모든 파일을 포함하십시오:

    ```bash theme={null}
    zip is_business_hours.zip main.py requirements.txt
    ```

    Python 코드에서 `os.path.dirname(os.path.abspath(__file__))`를 사용하면 로컬에 번들된 기본 디렉터리 경로를 참조할 수 있습니다. 이 값은 ZIP 아카이브 내에서 `main.py`가 위치한 디렉터리의 절대 경로를 반환하므로, 함께 번들된 다른 파일에도 접근할 수 있습니다:

    ```python theme={null}
    import os

    # Get the base directory of the bundled files
    base_dir = os.path.dirname(os.path.abspath(__file__))
    config_path = os.path.join(base_dir, 'config.json')
    ```

    다음과 같은 작업이 필요할 때 유용합니다:

    * UDF와 함께 번들된 설정 파일에 액세스
    * 사용자 지정 종속성에 필요한 wheel 패키지 로드
    * 추가 스크립트 또는 데이터 파일 참조

    이제 파일을 ZIP 아카이브로 압축하십시오:

    ```bash theme={null}
    zip is_business_hours.zip main.py
    ```

    <Warning>
      **심볼릭 링크는 허용되지 않습니다**

      ClickHouse Cloud는 심볼릭 링크가 포함된 UDF 아카이브를 허용하지 않습니다. ZIP 번들에는 일반 파일과 디렉터리만 포함되도록 하십시오 — 심볼릭 링크가 포함된 업로드는 유효성 검사에 실패합니다.
    </Warning>
  </Step>

  <Step title="UI를 통해 UDF 만들기" id="create-udf-via-ui">
    1. Cloud Console 홈 페이지에서 왼쪽 하단 메뉴의 조직 이름을 클릭합니다.
    2. 메뉴에서 **사용자 정의 함수**를 선택합니다.
    3. 사용자 정의 함수 페이지에서 **UDF 설정**을 클릭합니다. 화면 오른쪽에 구성 패널이 열립니다.
    4. 함수 이름을 입력합니다. 이 예시에서는 `isBusinessHours`를 사용합니다.
    5. 함수 유형으로 **실행형 풀** 또는 **실행형** 중 하나를 선택합니다:
       * **실행형 풀**: 지속적으로 유지되는 프로세스 풀이 관리되며, 읽기 시 풀에서 프로세스를 가져와 사용합니다.
       * **실행형**: 모든 쿼리마다 스크립트가 실행됩니다.
    6. 이 예시에서는 기본 설정을 사용합니다. 전체 구성 매개변수 목록은 [Executable user-defined functions](/ko/reference/functions/regular-functions/udf#executable-user-defined-functions)를 참조하십시오.
    7. **파일 찾아보기**를 클릭하여 이 튜토리얼 시작 부분에서 만든 `.zip` 파일을 업로드합니다.
    8. 새 인수를 추가합니다. 이 예시에서는 유형이 `DateTime`인 인수 `timestamp`를 추가합니다.
    9. 반환 유형을 선택합니다. 이 예시에서는 `Bool`을 선택합니다.
    10. **UDF 만들기**를 클릭합니다. 현재 빌드 상태를 보여주는 대화 상자가 표시됩니다.
        * 문제가 있으면 상태가 **오류**로 변경됩니다.
        * 그렇지 않으면 상태가 **빌드 중**에서 **프로비저닝 중**으로 진행됩니다. 프로비저닝을 완료하려면 서비스가 실행 중이어야 합니다. 서비스가 유휴 상태이면 서비스 이름 옆의 **UDF 세부 정보** 패널에서 **서비스 깨우기**를 클릭합니다.
        * 완료되면 상태가 **배포됨**으로 변경됩니다。
  </Step>

  <Step title="UDF를 테스트해 보세요" id="test-your-udf">
    1. 페이지 왼쪽 상단의 **Settings - return to your service view**를 클릭하여 SQL 콘솔의 홈 페이지로 돌아가세요
    2. 왼쪽 메뉴에서 **SQL 콘솔**을 클릭하세요
    3. 다음 쿼리를 작성하세요:

    ```sql theme={null}
    SELECT isBusinessHours('2026-03-20 10:00:00'::DateTime), isBusinessHours('2026-03-20 23:00:00'::DateTime);
    ```

    다음과 같은 결과가 표시됩니다:

    ```response theme={null}
    true    false
    ```
  </Step>

  <Step title="새 버전 만들기" id="create-new-version">
    UDF의 코드를 변경하려면 새 버전을 만드십시오. **Edit** 패널은 UDF가 할당된 서비스를 관리하는 용도로만 사용되며, 여기에서 파일을 업로드해도 배포된 코드가 교체되지는 않습니다.

    1. Cloud Console 홈페이지에서 왼쪽 하단 메뉴의 조직 이름을 클릭합니다.
    2. 메뉴에서 **사용자 정의 함수**를 선택합니다.
    3. `isBusinessHours` UDF의 **Actions** 아래에 있는 점 3개를 선택한 다음 **새 버전 만들기**를 클릭합니다.
    4. 수정된 코드가 포함된 zip 파일을 업로드하거나 설정을 변경한 다음 **새 버전 만들기**를 클릭합니다.

    이제 UI를 통해 첫 번째 사용자 정의 함수를 성공적으로 추가하고, 해당 함수가 실행되는 것을 확인했으며, 필요할 경우 새 버전을 만드는 방법도 확인했습니다.
  </Step>
</Steps>

<div id="manage-udfs-with-the-cloud-api">
  ## Cloud API를 사용하여 UDF 관리
</div>

<BetaBadge />

UI에서 제공되는 모든 기능은 [ClickHouse Cloud API](/ko/products/cloud/features/admin-features/api/api-overview)를 통해 프로그래밍 방식으로도 사용할 수 있습니다.
UDF 엔드포인트를 사용하면 소스 아카이브 업로드, FUNCTION 및 버전 생성, 서비스 ATTACH, 정리 등 UDF의 전체 수명 주기를 스크립트로 처리할 수 있습니다.

<Note>
  이 엔드포인트는 베타이며 API 계약은 변경될 수 있습니다.
</Note>

API를 통해 UDF를 생성하고 배포하는 일반적인 워크플로는 다음과 같습니다.

1. 사전 서명된 `application/zip` 업로드 URL을 받기 위해 [업로드 URL을 생성](/ko/products/cloud/api-reference/udf/udf-upload-session-create)한 다음, 해당 URL로 ZIP 아카이브를 업로드합니다. 각 업로드 ID는 생성 또는 버전 생성 시도에 한 번만 사용할 수 있습니다. 재시도할 때는 새 업로드 URL을 요청하십시오.
2. 업로드한 아카이브로부터 FUNCTION 이름, 런타임, 인수 및 반환 유형을 지정하여 [UDF를 생성](/ko/products/cloud/api-reference/udf/udf-create)합니다.
3. [UDF를 서비스에 ATTACH](/ko/products/cloud/api-reference/udf/udf-attach)합니다. 버전을 생략하면 준비된 최신 버전이 ATTACH됩니다. 서비스가 실행 중이어야 하며, 유휴 상태인 서비스는 먼저 시작할 수 있습니다.

전체 엔드포인트 목록은 다음과 같습니다.

| 엔드포인트                                                                            | 설명                                              |
| -------------------------------------------------------------------------------- | ----------------------------------------------- |
| [UDF 업로드 URL 생성](/ko/products/cloud/api-reference/udf/udf-upload-session-create) | org 범위의 사전 서명된 `application/zip` 업로드 URL을 생성합니다 |
| [UDF 생성](/ko/products/cloud/api-reference/udf/udf-create)                        | 업로드된 아카이브로부터 새 UDF를 생성합니다                       |
| [UDF 목록](/ko/products/cloud/api-reference/udf/udf-list)                          | organization에 있는 각 UDF의 최신 버전을 반환합니다            |
| [UDF 가져오기](/ko/products/cloud/api-reference/udf/udf-get)                         | UDF의 최신 버전을 반환합니다                               |
| [UDF 삭제](/ko/products/cloud/api-reference/udf/udf-delete)                        | UDF의 모든 버전을 삭제하고 모든 서비스에서 분리합니다                 |
| [UDF 버전 생성](/ko/products/cloud/api-reference/udf/udf-version-create)             | 소스 아카이브를 사용하여 버전을 할당하고 UDF 빌드를 시작합니다            |
| [UDF 버전 목록](/ko/products/cloud/api-reference/udf/udf-version-list)               | UDF의 모든 버전을 반환합니다                               |
| [UDF 버전 삭제](/ko/products/cloud/api-reference/udf/udf-version-delete)             | 어떤 서비스에도 ATTACH되지 않은 UDF 버전을 삭제합니다              |
| [UDF를 서비스에 ATTACH](/ko/products/cloud/api-reference/udf/udf-attach)              | 필요한 경우 현재 버전을 교체하여 UDF 버전 하나를 서비스에 ATTACH합니다    |
| [UDF ATTACH 목록](/ko/products/cloud/api-reference/udf/udf-attachment-list)        | UDF의 현재 서비스 ATTACH 정보를 반환합니다                    |
| [UDF ATTACH 가져오기](/ko/products/cloud/api-reference/udf/udf-attachment-get)       | UDF가 특정 서비스에 현재 ATTACH된 상태를 반환합니다               |
| [서비스에서 UDF 분리](/ko/products/cloud/api-reference/udf/udf-detach)                  | 서비스에서 UDF를 분리합니다                                |

요청 및 응답 스키마는 [UDF API 참조](/ko/products/cloud/api-reference/udf/udf-create)를 확인하십시오.

<div id="manage-udfs-with-terraform">
  ## Terraform으로 UDF 관리
</div>

공식 [ClickHouse Terraform 프로바이더](https://registry.terraform.io/providers/ClickHouse/clickhouse/latest/docs)에는 Infrastructure as Code 방식으로 UDF를 관리할 수 있는 2개의 리소스가 포함되어 있습니다.

* [`clickhouse_udf`](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/docs/resources/udf.md)는 FUNCTION 자체를 관리합니다. FUNCTION 소스 코드가 포함된 ZIP 아카이브를 사용하며, 아카이브 hash가 변경될 때마다 새 버전을 publish하고 빌드가 완료될 때까지 기다립니다.
* [`clickhouse_udf_attachment`](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/docs/resources/udf_attachment.md)는 UDF 버전을 서비스에 연결합니다. 서비스에는 한 번에 FUNCTION의 버전을 최대 1개만 연결할 수 있습니다. 고정 버전 번호를 지정하거나 `clickhouse_udf.<name>.version`을 참조하여 서비스를 최신 버전으로 자동 업데이트할 수 있습니다.

<Note>
  이 리소스는 프로바이더 버전 3.24.0 이상에서 사용할 수 있습니다. 알파 상태이므로 향후 프로바이더 버전에서 동작이 변경될 수 있습니다.
</Note>

예를 들어, 앞선 예시의 `isBusinessHours` UDF를 Terraform으로 배포하려면 다음과 같이 합니다.

```terraform theme={null}
resource "clickhouse_udf" "is_business_hours" {
  function_name = "isBusinessHours"
  runtime       = "python3.11"
  type          = "executable_pool"
  return_type   = "Bool"

  arguments = [
    { name = "timestamp", type = "DateTime" },
  ]

  source_archive_path = "${path.module}/is_business_hours.zip"
  source_archive_hash = filebase64sha256("${path.module}/is_business_hours.zip")
}

resource "clickhouse_udf_attachment" "production" {
  function_name = clickhouse_udf.is_business_hours.function_name
  service_id    = var.service_id
  version       = clickhouse_udf.is_business_hours.version
}
```

ATTACH는 준비된 상태인 버전에서만 성공하며, 완료하는 데 몇 분이 걸릴 수 있습니다. 유휴 상태의 서비스는 자동으로 시작됩니다. `clickhouse_udf` resource를 삭제하면 해당 FUNCTION의 모든 버전이 제거되고 모든 서비스에서 분리됩니다.
