포스 삼촌 2026. 7. 23. 20:55

안녕~ 오늘은 Snowflake의 Cortex Search Service에 대해서 살펴보자구.

 

 

-- =============================================================
-- 1. CREATE CORTEX SEARCH SERVICE — Single-Index (기본형)
-- =============================================================

-- ★★★ 공식 구문 (암기 필수) ★★★
-- CREATE [ OR REPLACE ] CORTEX SEARCH SERVICE [ IF NOT EXISTS ] <name>
--   ON <search_column>     -- 여기에서 검색을 해라.
--   [ PRIMARY KEY ( <col_name> [, ... ] ) ]
--   ATTRIBUTES <col_name> [ , ... ]
--   WAREHOUSE = <warehouse_name>
--   TARGET_LAG = '<num> { seconds | minutes | hours | days }'
--   [ EMBEDDING_MODEL = <embedding_model_name> ]   -- 모델을 지정할 수도 있음
--   [ REFRESH_MODE = { FULL | INCREMENTAL } ]  -- FULL vs INCREMENTAL (PK 필요!)

    -- AS <query> 에서 select하는 컬럼 중 PK를 지정하면, Incremental(증분) 방식의 인덱싱 가능 

    -- 즉, 인덱싱 주기마다 전체가 아닌 변경된 것들만 작업하므로 비.용.절.감 !!
--   [ INITIALIZE = { ON_CREATE | ON_SCHEDULE } ]   -- ON_CREATE(즉시) vs ON_SCHEDULE(다음 주기)

    -- 
--   [ FULL_INDEX_BUILD_INTERVAL_DAYS = <num> ]
--   [ REQUEST_LOGGING = { TRUE | FALSE } ]
--   [ AUTO_SUSPEND = <num_seconds> ]   -- 최소 1800초 (30분) — 이거 숫자 잘 나옴
--   [ COMMENT = '<comment>' ]
-- AS <query>;

 

-- [예시 1] 가장 기본적인 Search Service
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.basic_search_svc
    ON document_text    -- ON 다음에 검색 대상 텍스트 컬럼!!! 1개 지정
    ATTRIBUTES category, department -- 필터링 컬럼들 (OBJECT 타입 불가)

    -- 여기에 지정한 컬럼만 나중에 Search Service를 조회할 때 (=SEARCH_PREVIEW 요청이 들어올 때) filter로 사용가능
    WAREHOUSE = WH_ENGINEER -- 인덱싱에 사용하는 WH 
    TARGET_LAG = '1 hour'   -- 인덱싱 주기
AS (
    SELECT
        document_text,
        category,
        department,
        created_at
    FROM my_db.my_schema.knowledge_base -- 이 쿼리의 결과물로 서치서비스를 만든다.


);

-- ★ ON 절: 검색 대상 텍스트 컬럼 (1개만 지정), 하이브리드 검색을 자동으로 수행
-- ★ ATTRIBUTES: 필터링에 사용할 컬럼들 (OBJECT 타입 불가)
-- ★ TARGET_LAG: 소스 데이터 변경 후 인덱스 반영까지 최대 허용 지연
-- ★ AS 절의 쿼리: SELECT 결과가 인덱스의 소스 데이터

 

Cortex Search는 Single-Index에서도 하이브리드 검색 자동으로 수행합니다.

내부적으로 ON 컬럼에 대해:

  1. 키워드 검색 (BM25)  정확한 단어 매칭
  2. 벡터 검색 (Semantic/Embedding)  의미적 유사도 매칭

  결과를 자동으로 합산(fusion)해서 최종 랭킹을 만들어 줍니다. 사용자가 별도로 "키워드만" 또는 "벡터만" 선택할 필요 없이, CREATE할  ON 컬럼 하나 지정하면 Snowflake가 알아서   처리합니다.

그래서 EMBEDDING_MODEL 파라미터가 존재하는 거예요  벡터 검색 쪽에서  임베딩 모델을 지정하는 겁니다. 생략하면 Snowflake 기본 모델이 적용되고요.

 


-- [예시 2] 임베딩 모델 명시 + 로깅 활성화
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.docs_search_svc
    ON content
    ATTRIBUTES author, doc_type, status
    WAREHOUSE = WH_ENGINEER
    TARGET_LAG = '30 minutes'
    EMBEDDING_MODEL = 'snowflake-arctic-embed-l-v2.0'
    REQUEST_LOGGING = TRUE
    COMMENT = 'Company document search service'
AS (
    SELECT
        content,
        title,
        author,
        doc_type,
        status,
        updated_at
    FROM my_db.my_schema.documents
    WHERE status = 'PUBLISHED'
);

-- ★ EMBEDDING_MODEL: 지정하지 않으면 Snowflake가 자동 선택
-- ★ REQUEST_LOGGING = TRUE: 쿼리 모니터링용 로그 기록

 

[예시2]에서 REQUEST_LOGGING = TRUE: 쿼리 모니터링용 로그 기록 옵션은 무슨 뜻이야? 서치서비스를 쿼리할 때마다 로그를 남겨주는 건가?

 

네, 정확합니다. REQUEST_LOGGING = TRUE 켜면  Search Service에 SEARCH_PREVIEW 요청이 들어올 때마다 로그를 남겨줍니다.

기록되는 내용:

  • 누가 검색했는지
  • 어떤 query를 보냈는지
  • 필터 조건은 뭐였는지
  • 언제 요청했는지

조회는 이렇게 합니다:

sql
SELECT *
FROM TABLE(
    INFORMATION_SCHEMA.CORTEX_SEARCH_REQUEST_LOG(
        SERVICE_NAME => 'MY_SEARCH_SVC',
        START_TIME => DATEADD('hour', -24, CURRENT_TIMESTAMP())
    )
);

활용 목적:

  • 사용자들이 실제로  많이 검색하는지 파악 (검색 패턴 분석)
  • 검색 품질 개선  자주 검색되는데 결과가  좋은 키워드 식별
  • Agent 연동  어떤 질문이 Search로 라우팅되는지 모니터링

시험 포인트: 기본값은 FALSE입니다. 명시적으로 켜야 로그가 쌓입니다.

 

일반적인 패턴:

  1. 초기 운영  REQUEST_LOGGING = TRUE 켜놓고 사용자 검색 패턴 수집
  2. 분석/개선  로그 보면서 검색 품질 튜닝 (ATTRIBUTES 추가, 소스 데이터 보강 등)
  3. 안정화   필요 없으면 FALSE 끄거나, 비용/저장 부담 없으면 계속 켜둠

나중에 ALTER로 언제든 on/off 전환 가능합니다:

sql
ALTER CORTEX SEARCH SERVICE my_svc SET REQUEST_LOGGING = TRUE;

처음부터 끄고 만든 뒤, 필요할  켜도 되니까 부담 없이 운영하면 됩니다.

 


 

-- [예시 3] PRIMARY KEY + INCREMENTAL 리프레시
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.incremental_svc
    ON article_body
    PRIMARY KEY (article_id)    -- AS 이후 셀렉트절 중에 PK, PK 컬럼은 TEXT 타입만 가능!
    ATTRIBUTES category, region, publish_date
    WAREHOUSE = WH_ENGINEER
    TARGET_LAG = '15 minutes'
    REFRESH_MODE = INCREMENTAL  -- 변경된 행만 처리 → 임베딩 비용 절감
    FULL_INDEX_BUILD_INTERVAL_DAYS = 7  -- 증분 업데이트 누적 후 주기적 전체 빌드!
    AUTO_SUSPEND = 3600 -- 쿼리 없으면 N초 후 서빙 자동 중지 (최소 1800초=30분)
AS (
    SELECT
        article_id,
        article_body,
        category,
        region,
        publish_date
    FROM my_db.my_schema.news_articles
    WHERE is_active = TRUE
);

-- ★ REFRESH_MODE:
--   - FULL: 매 리프레시마다 전체 재처리 (기본)
--   - INCREMENTAL: PK 기반 변경분만 처리

 

맞습니다  PRIMARYKEY는 TEXT(VARCHAR)타입컬럼만 가능합니다.

이유는 추측하신 것과 비슷합니다:

  1. Cortex Search는 근본적으로 텍스트/문서 검색 엔진  내부적으로 텍스트 인덱싱 구조를 쓰기 때문에 PK도 텍스트 기반으로 관리
  2. INCREMENTAL 리프레시  변경분 추적용  PK로 "이 문서가 새로 추가됐는지, 업데이트됐는지" 식별하는데, 내부 인덱스가 문자열 키로 동작

그래서 실무에서 숫자 ID를 PK로 쓰고 싶으면 캐스팅해야 합니다:

FULL vs INCREMENTAL 비용 차이:

  • FULL   리프레시마다 전체 데이터를 다시 인덱싱 (웨어하우스 크레딧 소모 )
  • INCREMENTAL  변경된 행만 인덱싱 (PK로 변경분 식별)

그래서 비용 절감 공식은:

text
PK 지정 → INCREMENTAL 가능 → 변경분만 처리 → 크레딧 절약

여기에 추가로 TARGET_LAG 비용에 영향을 줍니다:

TARGET_LAG비용데이터 신선도
1 minute 높음 (자주 리프레시) 거의 실시간
1 hour 중간 적당
1 day 낮음 (하루 1회) 느림

비용 절감 3종 세트 (시험 포인트):

  1. PK + INCREMENTAL  변경분만 처리
  2. TARGET_LAG 넉넉하게  리프레시 빈도 줄임
  3. AUTO_SUSPEND  쿼리 없을  서빙 리소스 자동 중지 (최소 1800초)

실시간성이  중요한 서비스라면   가지를 조합해서 비용을  낮출 수 있어요~

 


-- [예시 4] INITIALIZE = ON_SCHEDULE (대용량 데이터)
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.large_data_svc
    ON text_content
    PRIMARY KEY (doc_id)
    ATTRIBUTES source_system
    WAREHOUSE = WH_ENGINEER
    TARGET_LAG = '2 hours'
    INITIALIZE = ON_SCHEDULE
AS (
    SELECT doc_id, text_content, source_system
    FROM my_db.my_schema.massive_documents
);

-- ★ INITIALIZE:
--   - ON_CREATE (기본): 생성 즉시 인덱싱 시작
--   - ON_SCHEDULE: 다음 스케줄 시점에 인덱싱 시작 (대용량 시 유용)

 

ON_SCHEDULE을 쓰는 상황:

  1. 소스 테이블이 아직 비어있거나 준비 중일   서비스 DDL을 먼저 배포해놓고, 데이터 적재는 나중에 하는 경우. ON_CREATE로 하면  인덱스를 만들고 크레딧만 낭비.
  2. 대규모 초기 데이터를 로딩 중일   데이터를 배치로 밀어넣는 중에 CREATE하면, 중간 상태로 인덱싱이 시작됨.  넣고 나서  번에 인덱싱하는  효율적.
  3. CI/CD 파이프라인에서 DDL만 먼저 배포  인프라 프로비저닝과 데이터 준비를 분리하고 싶을 때.

 

-- =============================================================
-- 2. CREATE CORTEX SEARCH SERVICE — Multi-Index (고급형)
-- =============================================================

-- ★★★ 공식 구문 (Multi-Index) ★★★
-- CREATE [ OR REPLACE ] CORTEX SEARCH SERVICE <name>
--   TEXT INDEXES <text_column_name> [ , ... ]
--   VECTOR INDEXES <column_specification> [ , ... ]
--   [ PRIMARY KEY ( <col_name> [, ... ] ) ]
--   ATTRIBUTES <col_name> [ , ... ]
--   WAREHOUSE = <warehouse_name>
--   TARGET_LAG = '<num> { seconds | minutes | hours | days }'
--   ...
-- AS <query>;

-- column_specification: <column_name> ( MODEL = '<embedding_model_name>' )

-- [예시 5] Multi-Index: 여러 텍스트 컬럼 + 벡터 컬럼
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.multi_idx_svc
    TEXT INDEXES title, body, summary
    VECTOR INDEXES
        title_embedding (MODEL = 'snowflake-arctic-embed-m-v1.5'),
        body_embedding  (MODEL = 'snowflake-arctic-embed-l-v2.0')
    PRIMARY KEY (doc_id)
    ATTRIBUTES category, language, priority
    WAREHOUSE = WH_ENGINEER
    TARGET_LAG = '1 hour'
    REQUEST_LOGGING = TRUE
AS (
    SELECT
        doc_id,
        title,
        body,
        summary,
        title_embedding,
        body_embedding,
        category,
        language,
        priority
    FROM my_db.my_schema.multi_source_docs
);

 

★ Single-Index vs Multi-Index 차이:

항목 Single-Index Multi-Index
검색 컬럼 ON <colimn> 1개 TEXT INDEXES (n개)
+
VECTOR INDEXES (n개)
임베딩 EMBEDDING_MODEL (선택적) 각 VECTOR INDEX에 MODEL 지정
텍스트 검색 1개 컬럼 여러 텍스트 컬럼 동시 검색
벡터 검색 자동 생성 사전 생성된 벡터 컬럼 사용
쿼리 제어 제한적 각 인덱스별 가중치(weight) 설정 가능
용도 단일 문서 검색 멀티 필드/멀티 모달 검색

 비교표가 핵심입니다. 차이를 직관적으로 정리하면:

Single-Index:

  • ON content   1개 컬럼만 검색 대상
  • 임베딩은 Snowflake가 알아서 생성해줌 (자동)

Multi-Index:

  • TEXT INDEXES title, body, summary  텍스트 검색 대상이 여러 
  • VECTOR INDEXES title_embedding(MODEL=...), body_embedding(MODEL=...)  벡터 컬럼도 여러 개, 모델도 각각 다르게 지정 가능

핵심 차이점:

SingleMulti
임베딩 생성 Snowflake가 자동 내가 미리 만든 벡터 컬럼 사용
검색 대상 1개 컬럼 여러 컬럼 동시
쿼리  제어 제한적 인덱스별 boost(가중치) 가능

Multi-Index를 쓰는 실무 상황: 오래된 게시판의 많은 데이터라고 가정해보자.

  • 제목은 가볍게, 본문은 깊게 검색하되 가중치를 다르게 주고 싶을 
  • 이미 임베딩을 생성해둔 테이블이 있을 
  • Q&A처럼 질문/답변/맥락 각각을 독립적으로 검색해야  

시험에서는 "Single과 Multi의 차이를 고르시오" 유형으로 나올  있으니  비교표를 기억하면 됩니다. 다음으로!

 

Single-Index에서는 Snowflake가 텍스트를 받아서 자동으로 임베딩을 생성했죠. Multi-Index에서는:

  1. 내가 미리 임베딩 컬럼을 만들어놓고 (예: SNOWFLAKE.CORTEX.EMBED_TEXT_1024(...) 등으로)
  2. 어떤 모델로 만들었는지 MODEL = '...' 명시
  3. 컬럼마다 다른 모델 가능  제목은 가벼운 모델, 본문은  모델
sql
VECTOR INDEXES
    title_embedding (MODEL = 'snowflake-arctic-embed-m-v1.5'),   -- 가벼운 모델
    body_embedding  (MODEL = 'snowflake-arctic-embed-l-v2.0')    -- 정밀 모델

정리:

인덱스 타입검색 방식boost 가능
TEXT INDEX 키워드 + 시맨틱 (자동 하이브리드) O
VECTOR INDEX 벡터 유사도만 O

전부 세밀하게 튜닝할  있다는  Multi-Index의 강점입니다. 대신 복잡하고 관리 포인트가 늘어나니까, 단순한 검색은 Single-Index로 충분합니다.

 

 

Single-Index:

text
ON content → content 컬럼 하나에 대해 자동으로 키워드+벡터 둘 다 적용

 Snowflake가 알아서 하이브리드 처리

 

 

Multi-Index:

text
TEXT INDEXES a, b         → a, b는 키워드 검색만
VECTOR INDEXES b_emb, c_emb  → b_emb, c_emb는 벡터 검색만

  인덱스가 독립적으로 동작. 하나의 컬럼이 자동으로   되는  아님.

하이브리드는 "쿼리 시점에 조합"으로 달성합니다:

json
{
  "multi_index_query": {
    "b": { "query": "연차 규정", "boost": 1.0 },
    "b_emb": { "query": "연차 규정", "boost": 1.0 }
  }
}

 b 컬럼에 대해 텍스트 검색 결과 + b_emb 벡터 검색 결과를 합산 = 수동 하이브리드

 

 

-- [예시 6] Multi-Index: 텍스트만 여러 개 (벡터 없이)
CREATE OR REPLACE CORTEX SEARCH SERVICE my_db.my_schema.text_only_multi_svc
    TEXT INDEXES question, answer, context
    ATTRIBUTES topic, difficulty
    WAREHOUSE = WH_ENGINEER
    TARGET_LAG = '1 hour'
AS (
    SELECT question, answer, context, topic, difficulty
    FROM my_db.my_schema.faq_dataset
);

 

의도적인 경우:

  • a = 짧은 제목  키워드 매칭이면 충분 (벡터 불필요)
  • c = 이미 외부에서 만든 임베딩  원본 텍스트가 없음 (텍스트 검색 불가)