메인 콘텐츠로 건너뛰기
ExecutableExecutablePool 테이블 엔진을 사용하면 사용자가 정의한 스크립트(stdout에 행을 기록하여)가 생성하는 행으로 구성된 테이블을 정의할 수 있습니다. 실행형 스크립트는 user_scripts 디렉터리에 저장되며, 임의의 소스에서 데이터를 읽을 수 있습니다.
  • Executable 테이블: 스크립트가 각 쿼리마다 실행됩니다
  • ExecutablePool 테이블: 지속적인 프로세스 풀을 유지하고, 읽기 시 풀에서 프로세스를 가져옵니다
선택적으로 하나 이상의 입력 쿼리를 포함할 수 있으며, 해당 쿼리의 결과를 스크립트가 읽을 수 있도록 stdin으로 스트리밍할 수 있습니다.

Executable 테이블 생성

Executable 테이블 엔진(table engine)에는 두 개의 매개변수가 필요합니다. 스크립트 이름과 입력 데이터의 포맷입니다. 필요에 따라 하나 이상의 입력 쿼리를 전달할 수도 있습니다.
다음은 Executable 테이블의 관련 설정입니다:
  • send_chunk_header
    • 설명: 처리할 청크를 보내기 전에 각 청크의 행 수를 전송합니다. 이 설정을 사용하면 일부 리소스를 미리 할당할 수 있어 스크립트를 더 효율적으로 작성하는 데 도움이 됩니다
    • 기본값: false
  • command_termination_timeout
    • 설명: 초 단위의 명령 종료 타임아웃
    • 기본값: 10
  • command_read_timeout
    • 설명: 밀리초 단위로 명령의 stdout에서 데이터를 읽는 타임아웃
    • 기본값: 10000
  • command_write_timeout
    • 설명: 밀리초 단위로 명령의 stdin에 데이터를 쓰는 타임아웃
    • 기본값: 10000
예시를 살펴보겠습니다. 다음 Python 스크립트의 이름은 my_script.py이며 user_scripts 폴더에 저장되어 있습니다. 이 스크립트는 숫자 i를 입력받아, 각 문자열 앞에 탭으로 구분된 숫자를 붙인 무작위 문자열 i개를 출력합니다:
다음 my_executable_tablemy_script.py의 출력으로 만들어지며, my_executable_table에서 SELECT를 실행할 때마다 임의의 문자열 10개를 생성합니다:
테이블을 생성해도 즉시 완료되며 스크립트는 호출되지 않습니다. my_executable_table을 쿼리하면 스크립트가 호출됩니다:

쿼리 결과를 스크립트에 전달하기

Hacker News 웹사이트 사용자들은 댓글을 남깁니다. Python에는 자연어 처리 툴킷인 nltk가 있으며, 여기에는 댓글이 긍정적인지, 부정적인지, 중립적인지를 판별하는 SentimentIntensityAnalyzer가 포함되어 있습니다. 또한 -1(매우 부정적인 댓글)부터 1(매우 긍정적인 댓글)까지의 값을 할당할 수 있습니다. nltk를 사용해 Hacker News 댓글의 감성을 계산하는 Executable 테이블을 만들어 보겠습니다. 이 예시에서는 여기에 설명된 hackernews 테이블을 사용합니다. hackernews 테이블에는 UInt64 유형의 id 컬럼과 comment라는 이름의 String 컬럼이 있습니다. 먼저 Executable 테이블을 정의하겠습니다:
sentiment 테이블에 관한 몇 가지 설명입니다:
  • sentiment.py 파일은 user_scripts 폴더(user_scripts_path 설정의 기본 폴더)에 저장됩니다
  • TabSeparated 포맷은 Python 스크립트가 탭으로 구분된 값을 포함하는 원시 데이터 행을 생성해야 한다는 의미입니다
  • 이 쿼리는 hackernews에서 2개의 컬럼을 선택합니다. Python 스크립트는 들어오는 행에서 해당 컬럼 값을 파싱해야 합니다
다음은 sentiment.py의 정의입니다:
Python 스크립트에 관해 몇 가지 설명합니다:
  • 이를 작동시키려면 nltk.downloader.download('vader_lexicon')를 실행해야 합니다. 이 코드를 스크립트에 넣을 수도 있지만, 그러면 sentiment 테이블에서 쿼리가 실행될 때마다 매번 다운로드하게 되어 비효율적입니다
  • row의 각 값은 SELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20의 result set에 있는 하나의 행이 됩니다
  • 들어오는 행은 탭으로 구분되므로 Python의 split 함수를 사용해 idcomment를 파싱합니다
  • polarity_scores의 결과는 몇 개의 값을 포함한 JSON 객체입니다. 여기서는 이 JSON 객체에서 compound 값만 사용하기로 했습니다
  • ClickHouse의 sentiment 테이블은 TabSeparated 포맷을 사용하고 2개의 컬럼을 포함하므로 print 함수는 이 컬럼들을 탭으로 구분합니다
sentiment 테이블에서 행을 선택하는 쿼리를 작성할 때마다 SELECT id, comment FROM hackernews WHERE id > 0 AND comment != '' LIMIT 20 쿼리가 실행되고, 그 결과가 sentiment.py로 전달됩니다. 테스트해 보겠습니다:
응답은 다음과 같습니다:

ExecutablePool 테이블 생성

ExecutablePool의 구문은 Executable과 유사하지만, ExecutablePool 테이블에만 적용되는 몇 가지 설정이 있습니다:
  • pool_size
    • 설명: 프로세스 풀의 크기입니다. 크기가 0이면 크기 제한이 없습니다
    • 기본값: 16
  • max_command_execution_time
    • 설명: 명령의 최대 실행 시간(초)입니다
    • 기본값: 10
위의 sentiment 테이블은 Executable 대신 ExecutablePool을 사용하도록 쉽게 변환할 수 있습니다:
클라이언트가 sentiment_pooled 테이블을 쿼리하면 ClickHouse는 필요 시 4개의 프로세스를 유지합니다.
마지막 수정일 2026년 7월 2일