이 블로그에 담긴 내용은 순전히 개인적인 견해이며, 특정 제품이나 회사의 공식 입장을 대변하지 않습니다.

들어가며

벡터 검색은 데이터 간 유사성을 기반으로 정보를 검색하는 기법입니다. 이를 통해 단순히 같은 값이나 키워드를 찾는 것에서 벗어나, 데이터의 의미적 유사성을 파악할 수 있습니다.

그렇다면, 정형 데이터(예: 수치 데이터)에서도 벡터 검색을 적용할 수 있을까요? 만약 가능하다면, 정형 데이터를 다차원적으로 분석할 수 있어 더 많은 인사이트를 얻을 수 있을 것입니다. 이렇게 된다면 벡터 검색의 활용 범위는 훨씬 더 넓어질 것입니다.

이 글에서는 비즈니스 데이터를 벡터화하는 과정과 이를 활용해 유사도 검색을 수행하는 방법을 소개합니다. 정형 데이터를 벡터 검색에 적용하는 방법에 대해서 이해할수 있었으면 좋겠습니다.

벡터 검색의 기본 원리

벡터 검색을 수행하려면 벡터 데이터가 필요합니다. 벡터는 보통 사전 훈련된 임베딩 모델에 의해 생성되며,이 모델은 데이터를 분석해 특정 특징(feature)을 추출하고, 이를 숫자 형식의 벡터로 변환합니다.

벡터의 특징

벡터는 각 데이터의 특징과 매핑되어 여러 차원(dimension)으로 정의됩니다. 예를 들어, 숫자 데이터도 특정 기준을 바탕으로 벡터화하면, 정형 데이터 간에도 유사도 검색을 수행할 수 있습니다.

비즈니스 적용 예시

사용자의 제품 구매 이력과 같은 정형 데이터를 벡터화하면, 다음과 같은 과정을 통해 유사한 소비 패턴을 분석할 수 있습니다

  1. 소비 패턴을 위한 특징을 식별 (예 : 구매금액, 구매빈도, 구매상품 카테고리등)
  2. 정규화 작업 수행 : 특징별로 데이터의 범위를 일정하게 맞춥니다. (예 “ 구매 금액은 0-1로 정규과, 구매빈도는 상대빈도로 변환)
  3. 벡터 데이터로 변환 및 저장 : 정규화된 데이터를 벡터 형식으로 변환하여 저장합니다.
  4. 벡터 검색 수행 : 저장된 벡터 데이터를 기반으로, 유사도 계산을 통해 비슷한 소비 패턴을 가진 사용자를 검색합니다.

특징 추출(Feature Extraction) 방법

데이터 패턴의 특징을 식별하는 것은 데이터 분석의 핵심 단계입니다. 특징 식별은 수작업으로 주요 특징을 선택하는 메뉴얼 식별 방법과 수학적 알고리즘을 통해 데이터에서 주요 변동성을 자동으로 추출하는 PCA(주성분 분석) 방법으로 나눌 수 있습니다. 두 방법의 차이점을 비교하여 살펴보겠습니다.

  • 방법 #1 - 메뉴얼 식별방법
    • 분석가가 도메인 지식(업무 이해)를 바탕으로 데이터 패턴을 분석하기 위하여 중요하다고 판단되는 특징(Feature)를 직접 선택하는 방법입니다.
    • 분석가가 직접 선택한 특징이므로 비즈니스적으로 설명하기 쉽고 특정 도메인에 대한 세부 특징을 잘 반영할수 있습니다.
    • 그러나 분석가의 경험과 도메인 지식에 따라 품질이 좌우되므로 대규모 데이터셋에서 특징 식별작업이 오래 걸릴수도 있고 고차원데이터에서는 특징을 놓칠 가능성이 있습니다.
  • 방법 #2 - PCA(Principal Component Analysis, 주성분 분석)
    • PCA는 데이터를 변환하여 분산(변동성)이 가장 큰 방향(주성분)을 자동으로 찾아 주요 특징을 추출하는 기법입니다. 데이터를 고차원 공간에서 저차원 공간으로 투영하여 핵심 정보를 유지 할수 있습니다.
    • 분석가의 개입없이 데이터를 기반으로 주요 특징을 추출하므로 대규모, 고차원 데이터에서도 빠르게 정확하게 적용이 가능합니다.
    • 그러나 데모인 지식을 반영하지 않고 통계적 변동성에만 의존하므로 비즈니스적으로 해석하기 어렵습니다. PCA 적용전 정규화, 표준화 등의 추가 작업이 필요합니다.

소규모 데이터 또는 도메인 지식이 명확한경우 메뉴얼방식으로 분석가가 데이터의 특성과 비즈니스 요구를 반영해 필요한 특징을 직접 식별할수 있고, 대규모 또는 고차원 데이터의 경우는 PCA를 사용하여 데이터를 자동으로 분석하여 중요한 정보를 빠르게 추출할수 있습니다.

두 방법은 상호 보완적으로 사용할수 있습니다. PCA를 활용해 주요 특징을 자동 추출한뒤, 도메인 지식을 반영하여 추가적으로 검토 및 조종하여 효율성과 비즈니스 적합성을 모두 충족시킬수 있을것 같습니다.

정형데이터를 벡터데이터로 변환

오라클 데이터베이스는 Oracle Machine Learning (OML) 기능을 통해 표형식으로 정리된 정형 데이터를 벡터 데이터로 변환할 수 있습니다. OML은 데이터베이스 내부에서 직접 데이터 분석 및 처리를 수행할 수 있도록 DBMS_DATA_MINING 패키지를 지원합니다. 이를 활용하면 외부 도구 없이도 데이터 정규화, 특징 추출, 벡터 변환 작업을 데이터베이스에서 처리할 수 있습니다.

OML의 주요 기능

  1. 자동 데이터 정규화
    • 데이터를 벡터화하기 전에 정규화(normalization)과정을 자동으로 수행합니다.
    • 정규화는 데이터 스케일을 조정하여 특징간의 가중치를 균등하기 만들어 줍니다. (컬럼별로 정규화 작업을 지정할수도 있습니다. )
  2. 특징 추출 알고리즘 제공
    • Oracle Machine Learning Feature Extraction Algorithms은 데이터를 분석하고, 주요 특징을 추출한 후 벡터로 변환하는 과정을 자동화합니다.
    • 이를 통해 데이터의 주요 패턴을 벡터 공간에서 효과적으로 표현할 수 있습니다.
  3. 완전 통합된 데이터 분석 환경 제공
    • 벡터 생성 및 특징 추출작업이 데이터베이스 내에서 이루어지므로, 추가적인 데이터 이동이 필요없습니다.
    • 대규모 데이터셋에서도 빠르게 안전하게 작업을 수행 할수 있습니다.

유사소비 패턴 분석 예제

다음은 특정 고객의 소비 패턴을 분석하고, 비슷한 소비 성향을 가진 고객을 검색하기 위하여 SQL 기반으로 벡터 데이터를 생성하고 검색하는 방법을 단계별로 설명하겠습니다.

1. 모델 생성

먼저 데이터을 저장할 테이블을 생성합니다. 고객정보와 구객 구매이력 데이터를 저장하기 위하여 테이블을 생성합니다.

Code : sql
-- 고객 정보 테이블
CREATE TABLE IF NOT EXISTS my_customer (
    customer_id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY, -- 고객번호
    name VARCHAR2(100), -- 고객 이름
    age NUMBER  -- 고객 나이
);
Code : sql
-- 고객 주문 테이블 
CREATE TABLE IF NOT EXISTS my_order (
    order_id NUMBER GENERATED AS IDENTITY PRIMARY KEY, -- 주문번호
    customer_id NUMBER, -- 고객번호
    category_id NUMBER, -- 소비구분(1 = 패션,의류, 2=전자제품, 가전, 3=식음료,외식)
    amount NUMBER,  --소비금액
    order_date DATE --소비일자
);

가상의 샘플 데이터를 저장합니다. 가상의 10명 고객에 고객별로 100건씩 구매이력을 저장합니다. 구매일자는 365이내, 구매금액은 1000원 ~ 100000원 입니다.

Code : sql
BEGIN
    -- 고객 데이터 삽입
    INSERT INTO my_customer (customer_id, name, age) VALUES 
     (1, '이정재', 25),(2, '김철수', 30),(3, '장동건', 28),
     (4, '원빈', 35),(5, '이영희', 22),(6, '박민준', 22),
     (7, '최수정', 41),(8, '정다은', 21),(9, '한지우', 33),(10, '윤서현', 40);

    -- 소비 데이터 삽입(각 고객별 100건 생성)
    FOR rec in (SELECT customer_id FROM my_customer) LOOP
        FOR j IN 1..100 LOOP
            INSERT INTO my_order (customer_id, category_id, amount, order_date)
            VALUES (rec.customer_id, MOD(j, 3) + 1, ROUND(DBMS_RANDOM.VALUE(1000, 100000)), SYSDATE - DBMS_RANDOM.VALUE(1, 365));
        END LOOP;
    END LOOP;
    COMMIT;
END;
/

모델 생성을 위하여 필요한 데이터를 제공하기 위하여 뷰를 생성합니다. 나이와 제품 카테고리별로 구매금액 정보를 제공합니다.

Code : sql
-- 모델 학습에 필요한 데이터만 생성
CREATE OR REPLACE VIEW vw_my_customer_order
AS
SELECT c.customer_id,c.age, 
        SUM(CASE WHEN o.category_id = 1 THEN o.amount ELSE 0 END) AS fashion_amount,
        SUM(CASE WHEN o.category_id = 2 THEN o.amount ELSE 0 END) AS electronics_amount,
        SUM(CASE WHEN o.category_id = 3 THEN o.amount ELSE 0 END) AS food_amount
    FROM my_customer c, my_order o
    WHERE c.customer_id = o.customer_id
    GROUP BY c.customer_id,c.age;

모델 생성 작업을 수행합니다. 모델 생성시 데이터 정규화 작업을 자동으로 수행하고, 각 특징별로 벡터로 변환하기 위한 수식이 자동으로 생성됩니다.

Code : sql
declare
  -- 모델 설정 정보
 v_setlst DBMS_DATA_MINING.SETTING_LIST;

BEGIN
  -- 차원 축소와 데이터 분석을 위하여 Singular Value Decomposition (SVD) 알고리즘을 설정
  v_setlst(dbms_data_mining.algo_name) := dbms_data_mining.algo_singular_value_decomp;
  -- 데이터 전처리 옵션을 자동으로 활성화(데이터 정규화 및 스케일링 작업을 수행)
  v_setlst(dbms_data_mining.prep_auto) := dbms_data_mining.prep_auto_on;
  -- SVD 모델의 Scoring 모드를 Principal Component Analysis (PCA)로 지정
  v_setlst(dbms_data_mining.svds_scoring_mode) := dbms_data_mining.svds_scoring_pca;

  BEGIN 
	DBMS_DATA_MINING.DROP_MODEL(model_name => 'MY_SVD_MODEL');
	EXCEPTION WHEN OTHERS THEN NULL; 
  END;

  DBMS_DATA_MINING.CREATE_MODEL2(
    model_name         => 'MY_SVD_MODEL',
    mining_function    => dbms_data_mining.feature_extraction,
    data_query         => 'SELECT * FROM vw_my_customer_order',
    case_id_column_name=> 'customer_id',
    set_list           => v_setlst);
END;
/

생성된 모델을 확인합니다. (결과 가독성을 위하여 SELECT json_arrayagg(json_object(*)) FROM (<쿼리>)를 이용하여 JSON으로 출력했습니다. )

Code : sql
SELECT json_arrayagg(json_object(*)) FROM ( --JSON출력
  -- 질의 쿼리 
  SELECT model_name, attribute_name, data_type, vector_info
  FROM   user_mining_model_attributes
  WHERE  model_name = 'MY_SVD_MODEL'
  AND    attribute_name = 'ORA$VECTOR'

);

MY_SVD_MODEL모델은 4차원의 벡터데이터를 생성할수 있습니다.

[
  {"MODEL_NAME":"MY_SVD_MODEL","ATTRIBUTE_NAME":"ORA$VECTOR","DATA_TYPE":"VECTOR","VECTOR_INFO":"VECTOR(4,FLOAT64)"}
]

정형 데이터로 부터 벡터화하는 방법은 아래와 같습니다. VECTOR_EMBEDDING함수에 생성된 모델명을 사용하고 데이터를 넣어주면 됩니다.

Code : sql
select customer_id , vector_embedding(MY_SVD_MODEL using * ) vector from vw_my_customer_order;

고객별로 4차원의 벡터베이터가 생성됩니다.

[
  {"CUSTOMER_ID":7,"VECTOR":[-37073.39150070638,12067.724238876614,-164670.0388867871,6.899551577662791]},
  {"CUSTOMER_ID":8,"VECTOR":[-327380.41835890274,-198598.86113343993,182715.34377581492,-4.311179934611252]},
  {"CUSTOMER_ID":9,"VECTOR":[-341094.3100891472,-202340.97106954159,-141578.6948448256,-0.85404740075198]},
  {"CUSTOMER_ID":10,"VECTOR":[261141.28392330644,-190058.04946727314,72290.29656133645,12.79478602680115]},
  {"CUSTOMER_ID":1,"VECTOR":[141617.30181680623,238749.94095482316,133058.3056150318,-1.1414379797998075]},
  {"CUSTOMER_ID":2,"VECTOR":[115428.1278889779,96328.45857936806,44076.66055533825,1.5837392708831044]},
  {"CUSTOMER_ID":3,"VECTOR":[-174715.75693159917,380120.99276420183,32048.367826251095,-1.4489250118941706]},
  {"CUSTOMER_ID":4,"VECTOR":[-136458.09178686605,135493.47685886125,-81954.45910596287,2.807771852768457]},
  {"CUSTOMER_ID":5,"VECTOR":[358217.13718869543,-26846.992069571614,-148279.58559325544,-10.958746353751927]},
  {"CUSTOMER_ID":6,"VECTOR":[140318.11784943476,-244915.7196563035,72293.80409705845,-5.3715120473063624]}
]

2. 유사 고객 검색

유사한 고객을 검색할 기준 고객을 선택합니다.

Code : sql
SELECT customer_id, name, age FROM my_customer fetch first 1 rows only;

“이정재” 고객이 검색되었습니다.

[
  {"CUSTOMER_ID":1,"NAME":"이정재","AGE":25}
]

“이정재” 고객의 소비 금액(최근 60일)을 확인합니다.

Code : sql
SELECT decode(category_id,1,'패션,의류',2,'전자제품,가전',3,'식음료,외식') category_name,sum(amount) TOTAL_AMOUNT 
  FROM my_order where customer_id = 1 and order_date >= sysdate - 60
GROUP BY category_id order by 2 desc;

“이정재”고개의 카테고리별 소비 금액은 아래와 같습니다.

  • (가장많은소비)식음료,외식 -> 전자제품,가전 -> 패션,의류(가장적은소비)
[
  {"CATEGORY_NAME":"패션,의류","TOTAL_AMOUNT":48464},
  {"CATEGORY_NAME":"식음료,외식","TOTAL_AMOUNT":190091},
  {"CATEGORY_NAME":"전자제품,가전","TOTAL_AMOUNT":176678}
]

“이정재” 고객과 유사한 소비 성향을 가진 고객을 검색합니다. 이때 벡터 검색을 활용합니다. 벡터 검색을 위하여 백터 변환 작업은 앞서 생성한 모델(MY_SVD_MODEL)을 이용합니다.

Code : sql
WITH ts AS
(  SELECT c.customer_id,c.age,
        SUM(CASE WHEN o.category_id = 1 THEN o.amount ELSE 0 END) AS fashion_amount,
        SUM(CASE WHEN o.category_id = 2 THEN o.amount ELSE 0 END) AS electronics_amount,
        SUM(CASE WHEN o.category_id = 3 THEN o.amount ELSE 0 END) AS food_amount
    FROM my_customer c, my_order o
    WHERE c.customer_id = o.customer_id
      and o.order_date >= SYSDATE - 60
    GROUP BY c.customer_id, c.age )
SELECT o.customer_id, c.name, c.age, o.fashion_amount, o.electronics_amount, o.food_amount,
       VECTOR_DISTANCE(o.data_vector, m.query_vector, COSINE) dist
 FROM ( SELECT ts.*, VECTOR_EMBEDDING(MY_SVD_MODEL USING *) data_vector
          FROM ts)  o, 
      ( SELECT customer_id, VECTOR_EMBEDDING(MY_SVD_MODEL USING *) query_vector 
          FROM ts
         WHERE customer_id = 1)  m,
      my_customer c
 WHERE o.customer_id <>  m.customer_id
   AND o.customer_id = c.customer_id
   AND VECTOR_DISTANCE(o.data_vector, m.query_vector, COSINE)  < 0.0009
ORDER BY dist
FETCH FIRST 5 ROWS ONLY;

소비성향이 유사한 5명 고객을 검색하였습니다. 가장 유사한 고객은 “한지우” 고객으로 “이정재” 고객과 비슷하게 식음료,외식 -> 전자제품,가전 -> 패션,의류순으로 소비하고 있습니다.

[
  {"CUSTOMER_ID":9,"NAME":"한지우","AGE":33,"FASHION_AMOUNT":104547,"ELECTRONICS_AMOUNT":257146,"FOOD_AMOUNT":322754,"DIST":0.0002624949741961702},
  {"CUSTOMER_ID":7,"NAME":"최수정","AGE":41,"FASHION_AMOUNT":78486,"ELECTRONICS_AMOUNT":124310,"FOOD_AMOUNT":129316,"DIST":0.000349675310787001},
  {"CUSTOMER_ID":5,"NAME":"이영희","AGE":22,"FASHION_AMOUNT":185261,"ELECTRONICS_AMOUNT":260406,"FOOD_AMOUNT":225837,"DIST":0.00036976359419205185},
  {"CUSTOMER_ID":10,"NAME":"윤서현","AGE":40,"FASHION_AMOUNT":76284,"ELECTRONICS_AMOUNT":161651,"FOOD_AMOUNT":292196,"DIST":0.0005169519339311979},
  {"CUSTOMER_ID":4,"NAME":"원빈","AGE":35,"FASHION_AMOUNT":77572,"ELECTRONICS_AMOUNT":296585,"FOOD_AMOUNT":351380,"DIST":0.000789338416505525}]

벡터 검색은 단순히 숫자의 크기를 비교하는 것이 아닙니다. 벡터 간의 방향성을 기준으로 데이터를 분석합니다. 즉, 특정 데이터가 어떤 방향으로 소비 성향을 나타내는지를 중점적으로 파악합니다.

마치며

지금까지 정형 데이터를 활용해 벡터 검색을 수행하는 절차에 대해 알아보았습니다. 소규모 데이터의 경우 데이터 분석가가 직접 주요 특징을 추출할 수 있지만, 대규모 데이터나 전문적인 도메인 지식이 없는 상황에서는 특징 추출이 매우 어렵습니다.

위 예제는 간단히 4개의 특징만 사용해 벡터 데이터를 구성했지만, 대규모 데이터에서는 알고리즘을 활용해 자동으로 특징을 추출하고 이를 분석에 활용할 수 있습니다.

특히, 벡터 검색은 기존의 단순한 데이터 일치 기반 검색을 넘어, 데이터의 패턴과 방향성을 활용한 새로운 검색 방식을 제공합니다. 이를 통해 다양한 업무에 활용할 가능성이 열려 있습니다.

예제를 통해 도구 사용의 이해를 돕고자 했지만, 이러한 아이디어의 실질적인 활용 방안은 이 글을 읽고 있는 여러분이 훨씬 더 잘 알고 계실 것이라 생각합니다. 😊 앞으로도 벡터 검색을 활용한 새로운 아이디어가 다양하게 시도되길 기대합니다!

참고문서

댓글남기기