Skip to main content

데이터 플랫폼에서 Data Catalog의 중요성

· 32 min read
Bogyeong
Data Engineer @ Intellectus
Eunho
Software Engineer @ Intellectus

본 글은 Data Lake/Data Catalog의 정의, 두 플랫폼 사이의 관계, Data Catalog 사용 장단점, 주요기능에 대해 순차적으로 설명합니다.
기업에서 데이터 카탈로그를 구축하기 위해 실질적으로 필요한 코드를 기재하거나 데이터 카탈로그의 작동을 위한 테크니컬적인 부분에 대하여 깊게 설명하고 있지 않습니다.
따라서 해당 글은 사내에 넘치는 데이터를 더 잘 활용하기 위해 Data Lake, Data Catalog 도입을 고민하는 백-엔드, 데이터 엔지니어, 소프트웨어 엔지니어 분들이 읽으시길 추천합니다.

데이터 플랫폼

데이터 플랫폼은 데이터를 활용하고 관리하는데 필요한 기술적 역량을 제공하는 통합 시스템이다. 데이터 플랫폼을 구성하는 컴포넌트는 각각 데이터의 수집, 저장, 전처리, 전송을 지원하고 사용자 혹은 응용 프로그램에 데이터를 제공 한다. 이러한 컴포넌트의 구성과 관계를 사용 목적에 따라 배치하고 정의하면 여러 유형의 시스템을 구축할 수 있다.
이미 최적화된 데이터 구조에 맞춰 데이터를 통합 수집하고 관리할 수 있는 Data Warehous, Raw 데이터를 1차적으로 통합 관리하고 활용 목적에 따라 필요한 데이터를 탐색 후 가공하는 파이프 라인을 구축한 Data Lakes가 대표적인 사례이다. 그리고 분산 환경에서 데이터에 대한 통합 관리를 가능하게 함으로써 데이터가 가진 잠재적 가치 실현을 지원하기 위한 전략을 내포하고 있는 Data Fabric도 데이터 플랫폼의 한가지 유형이라 할 수 있다.

이 문서는 데이터 플랫폼에서 Meta Data를 통해서 데이터에 대한 탐색과 처리 효율, 그리고 이력 관리를 지원하는 Data Catalog에 대해 설명한다. 이를 통해 각 컴포넌트에 대해 깊이 이해 하고 데이터 플랫폼 전체에 대한 시스템을 받아들임으로 발생되는 데이터를 이용해 문제를 해결할 수 있는 제대로 된 데이터 플랫폼 시스템을 구축할 수 있을 것이다.

Data Lakes 시스템과 Data Catalog

Data Lake란 한 저장공간에 데이터의 형태(정형/반정형/비정형)에 상관없이 전처리를 거치지 않은 raw data형태를 통합 관리하는 특징을 갖는 데이터 플랫폼의 한 종류이다. 기업 환경에서 Data Lake 시스템은 전사에서 발생되는 모든 Data를 비즈니스나 경영 의사 결정에 사용하기 위한 기술 역량을 지원하는 플랫폼이다.
traditional_datalake
출처 : medium - Building Data Lake with Snowflake

지금은 Web, Application, Mobile, Wareable device, IoT Seneor 등 모든 것들이 계속 인터넷에 연결돼 있으며 log를 포함한 다양한 형태의 많은 데이터가 쌓이고있다. 때문에 회사가 보유할 데이터의 양은 적게는 GB, 크게는 ZB(Zetta byte)까지 방대하게 증가하고 있고 이러한 데이터를 효과적으로 사용하고자 하는 요구가 증가하고 있고 그를 위한 DataLake 플랫폼을 원하고 있다. 이러한 데이터를 효율적으로 사용하기 위한 플랫폼엔 몇 가지 필요한 조건이 있다.

1. 데이터 접근성 확보를 위해 검색 제공

Data Lakes내에 있는 수많은 데이터 중 User의 사용 목적에 부합하는 데이터를 찾아서 활용할 수 있어야 한다.

각 사내에 있는 Data Scientist나 Data Analyst가 저장되어 있는 모든 데이터를 세세하게 알고 있을 확률은 지극히 낮다. 그렇다면 필요한 데이터를 추출하기위해 Database Administrator나 Data Engineer의 도움을 필요로하게 되는데, 이때 해당 직군의 사람들에게 의존적으로 되고, 이러한 요청이 몰려 DA,DE에서 병목 현상이 발생해 필요한 데이터를 받기까지 긴 시간이 소요 될 수 있다. 그렇게 되면 불필요한 시간을 소모하게 되고, 적기에 필요한 데이터 분석이나 데이터 모델링 작업이 늦춰져 경영자들의 데이터를 기반한 의사 결정(DDDM, Data Driven Decision Making)이 기업 발전에 큰 도움이 되지 못하는 악순환이 벌어질 수도 있다.

이러한 악영향을 방지하기 위해 데이터 추출 병목이 발생하지 않는 User 친화적인 검색시스템을 구축해야한다. 그러려면 실제 데이터명이 아닌 비지니스용어로 검색해 전사 누구나 쉽게 검색할 수 있는 비지니스 메타데이터를 이용한 검색시스템이 필요하다. 만약 이런 시스템이 갖춰있지 않다면 car_types같은 실제 table name이나 column name을 통한 검색이 이뤄져야하는데, 이 같은 이름은 위에 적힌 DBA나 DE 업무를 하고 있는 담당자들이 아니면 정확하게 알기 어렵다. 따라서 차량 종류 처럼 실무자가 사용하는 용어로 변경해야할 필요가 있다. 이를 위해서 필요한 것이 비지니스 메타데이터이다. 그리고 이 메타데이터와 데이터 객체를 서로 연결시켜주는 작업이 필요하며, 이를 검색 가능한 형태로 변경해주기 위해 index화 하는 작업이 필요하다.

더 나아가서는 User 검색어에 맞춰 연관된 데이터를 함께 보여주는 추천 Data 시스템을 구축하는 것도 좋은 방법이다.

2. Schema를 확인하지 않는 수집 시스템

데이터를 원시 구조(raw data)로 수집하는 Data Lake에서는 다양한 데이터를 빠르고 간편하게 저장하기 위해서 Data Input시 Data의 Schema를 먼저 정의하지 않고 저장하는 Schema-on-Read 구조를 따른다.

수많은 데이터를 저장하는 경우엔 현실적으로 모든 데이터의 Schema를 정의하거나 확인하는 작업을 하기 어렵다. 그래서 먼저 데이터 구조의 정의 없이 빠르게 데이터를 수집하고 Data user의 활용성에 맞춰 적절한 형태로 가공해 사용함으로 Data Lake의 가장 큰 장점인 유연성을 보장한다. 이러한 대량의 Raw Data를 저장하고 빠르게 처리하기 위해서 다수의 컴퓨터를 활용하는 기술을 Hadoop system이라 하고, 이런 하둡분산파일시스템(HDFS)은 Schema-on-Read 구조에서 빼놓을 수 없는 기술이다. traditional_datalake_hds
출처 : Redis blog-Understanding Topology-Based Data Architectures

이와 반대되는 개념으로 Schema-on-write 구조가 있다. 이는 데이터를 저장할 때 Schema가 정의되어 있고, 이를 기반으로 데이터를 모델링하고 저장하며 추후 데이터를 활용할 때도 schema를 기준으로 읽고 활용하는 것을 의미한다. 주로 Data Warehouse의 단계에서 이런 구조를 바탕으로 데이터를 저장/읽기를 하게 된다. 이렇게 하면 저장 데이터의 구조와 속성이 고정되어있기에 정돈되고 퀄리티가 보장된 데이터를 얻을 수 있어 한 번의 변환으로 많은 데이터를 사용할 수 있다는 장점이 있다.

하지만 저장시 시간이 많이 소요되고 구조화된 데이터만 저장되기 때문에 다양한 형태의 데이터를 저장할 수 없다. 또한 설계가 유연하지 못하며, 가장 중요한 단점으로 수집하기 전 발생되는 모든 데이터의 구조를 먼저 정의하는 것은 현실적으로 어려움이 있어 Data Lake에 Schema-on-write 구조는 적절하지 않다.

따라서 대용량 저장소인 Data Lake에선 데이터 schema에 상관없이 데이터를 용이하게 저장하며 데이터 형태의 구애없이 빠르게 저장하고, 그로인해 스트리밍 데이터까지 처리할 수 있게 된다. 또한 Scale Out Architecture를 이용해 데이터의 용량이 증가하는 것에 맞춰 저장소의 볼륨을 조절할 수 있는 확장성도 갖게 된다.

traditional_datalake_elt
출처 : ETL(Data Warehouse) vs ELT(Data Lake) : 5 Critical Differences

3. 데이터 분석을 위한 환경 구성 및 연계 시스템

데이터 분석을 위해선 먼저 모든 구성원이 전사의 전체 데이터구성을 확인할 수 있어야한다. Data Lake를 사용하는 이점 중 하나가 Data Silo가 만들어지지 않아 전사 조직이 통합된 데이터를 볼 수 있다는 것이다. Data Lake이전의 상황에선, 각 부서/조직별로 데이터셋을 만들 경우 필요 데이터를 따로 적재하고 관리하면 다른 조직과 Data Silo가 발생할 수 있다. 예를 들어 A팀에서 모으는 데이터를 B팀에서 다른 이름으로 중복 저장하거나, 전체적인 회사의 고객 판매실적을 공유해야하는 영업과 회계팀이 팀별 Data Base를 다르게 사용하여 하나의 프로세스로 전반적인 회사 상황을 처리는 것이 불가능해지는 경우가 있다. 이렇게 각 담당 부서/조직간 표준시스템의 부족, 통합 프로세스 실패 등의 이유로 발생하는 데이터 일관성 저해를 데이터 사일로(Data Silo)라 한다.

DataSilo
출처 : What is a data silo and why is it bad for your organization?

이런 데이터 사일로로 인한 문제점은 아래와 같다

  • 데이터의 중복 입력으로 이어져 운영 비용이 증가하고, 조직의 경계를 넘나들며 작업하는 팀에서 데이터를 공유하기가 까다로워짐
  • 엔지니어와 분석가들이 데이터에 대해 포괄적인 관점을 확보하는 데 방해가 되어 처리 결과가 불확실하게 됨
  • 부실한 의사 결정과 기회의 손실로 이어짐
  • 지속되면 시스템 관리 및 제어를 위한 소프트웨어 라이선싱, 모니터링 및 유지관리를 위한 전담 IT 전문가 등이 필요하여 운영 비용이 상승함
  • 기업에서 시장의 변화나 고객의 요구 사항에 빠르게 대응하는 데 어려움을 겪어 민첩성이 저하되거나 소비자 행동의 변화 또는 경쟁 상황에 실시간으로 대응하는 역량이 제한될 수 있음

그래서 전사의 모든 데이터를 Raw형태로 DataLake 한 저장소에 저장해야하고, User가 필요로 하는 데이터를 소속 구분없이 자유롭게 사용할 수 있는 환경을 만들어야한다. 다만, 데이터 개방성(Openness)을 위해 접근성을 높이되, 수집된 데이터 중 정보보호나 다른 특정 사유를 이유로 전체를 보여주지 않고 일부를 가리는 마스킹(난독화 처리, Masking) 기능이 필요하다. 특히 금융권처럼 중요한 개인정보를 강하게 관리해야하는 도메인에선 데이터 마스킹에대한 관심이 높고 데이터를 Load/Extract 할 때 해당 데이터를 다른 값으로 처리하거나 해당 column에 대한 접근을 통제하는 기술이 필수적이다.

또한 대용량 데이터 분석을 위해 성능을 충분히 뒷받침할 수 있는 기술이 필요하다. 데이터는 시간에 따라 계속해서 증가하기 때문에 분석시 사용하는 용량(대부분 3~5년치)은 TB(TeraByte)이상의 대용량이 된다. 대용량 데이터를 다루는 가장 이상적인 방법은 고성능의 대용량 서버를 사용하여 처리하는 것이나, 이러한 방법으로는 얼마못가 어마어마한 비용적 문제에 직면하게 된다. 그 때문에 대안으로 나온 것이 Hadoop 분산 처리 기술(Hadoop Distributed File System, HDFS)이다. Hadoop(High-Availability Distributed Object-Oriented Platform)은 상대적인 저비용 서버를 여러대 사용하여 대용량의 데이터를 처리하기 위한 서비스로, 하둡 생태계의 서비스들을 공통 패키지로 구성해 사용한다.

그리고 최근엔 직접 Hardware 구축이나 Infra Structure 운영을 하지않아 간편하고, 사용량에 따른 비용청구가 되는 Public Cloud환경에서 DataLake를 구축하는 추세이다. 또한 구축의 용이성 뿐만아니라 Cloud Service인 Identity and Access Management (IAM)을 이용하여 각 Object Storage의 권한관리도 쉽게 할 수 있어 Data Governance가 간편하다는 장점이 있다. 실제 사용되고 있는 예시로는 AWS(Amazon Web Service)의 S3를 이용한 AWS Lake Formation, Google의 Cloud Strorage를 이용한 Data Lake, Microsoft의 Data Lake Storage를 이용한 Azure Data Lake 등이 있고 기업에서 주로 사용되고 있다.

더불어 데이터 분석을 위해 필요한 조건은 분석 Tool과의 연계성이다.

Data Lake에 적재되어 있는 수많은 데이터를 기반으로 비지니스 의사결정을 하기 위해선 빠르고 쉽게 의사결정을 내릴 수 있는 BI 대시보드 같은 Tool이 필요하다. User는 Data Lake에서 원하는 Source를 받아 전처리 작업을 진행한 후 데이터를 시각화하고 다각도로 표현하여 원하는 결과를 도출한다. 이럴때 Jupyter Notebook 같은 대화식 쿼리 서비스와 Tableau, PowerBI, Redash 같은 BI Tool을 사용한다. 이때 Raw Data를 얼마나 빠르게 User Computing 환경으로 가져올 수 있는지도 DataLake의 중요 조건 중 하나이다.

Data Lake 시스템에서 Data Catalog의 역할

데이터의 증가 속도와 축적되고 있는 데이터의 볼륨은 일반적인 기대를 뛰어 넘는 수준이다. 소셜 네트워크 사이트(SNS) 중 하나인 Facebook은 Raconteur社에 따르면 하루에 4PB(2020년 기준)를 생성한다고 하며, 2025엔 하루에 463 ZB가 생성될 것이라고 예상한다. 이처럼 회사가 보유하는 데이터는 점점 더 방대하게 증가하고 있다.

datavolume
출처 : 53 Important Statistics About How Much Data Is Created Every Day

이렇게 많은 데이터를 담고 있는 DataLake의 Raw데이터를 효과적으로 다루기 위해서 필요한 것이 바로 Data Catalog이다.

datacatalog
출처 : TIBCO What is a Data Catalog?

Data Catalog는 사내에 존재하고 있는 데이터를 빠르게 찾을 수 있도록 하는 데이터 소스 연결고리 역할을 하는 서비스이다. Data Catalog란 이름에 있는 것 처럼 Catalog의 속성을 생각해보면 Data Catalog를 쉽게 이해할 수 있다. Shopping Catalog는 Catalog 제조업체가 수 많은 판매 제품 하나하나의 정보를 한 페이지에 모아 각 제품의 브랜드/제조사/이름/이미지 등의 속성을 관리하여 일반 구매자에게 제공한다. 이를 통해 구매자는 제조업체나 카테고리에 제한되지 않고 구매자가 검색을 통해 원하는 제품을 찾고 구매할 수 있게 된다. Data Catalog도 마찬가지다.

Data Catalog는 데이터의 정보가 담겨져 있는 메타데이터를 관리하여 User에게 출처, 형식, 속성 등을 확인할 수 있도록 제공한다. DataLake에 있는 데이터를 User가 쉽게 검색하고 데이터의 정보를 확인하며 나아가 다운로드까지 할 수 있기 때문에 Data Catalog를 데이터 전달 플랫폼(Data Delivery Platform, DDP)의 요소로 보기도 한다.

Data Catalog의 역할은 여기서 멈추지 않고, 데이터가 회사의 자산으로 활용될 수 있도록 돕는다. “데이터가 아마존에서 왕(Data is king at Amazon)”이라는 말이 있을 정도로 이러한 데이터들은 개인들의 기록임과 동시에 회사의 입장에서는 각 고객들의 사용 흔적이며 이는 고객 맞춤형 서비스를 제공하기 위한 자산이다. 특히 최근엔 쿠키 값을 통해 각 사용자 별 데이터를 특정해서 모을 수 있으며 해당 데이터들을 통해 사용자의 과거 행동기반으로 유저가 관심을 가질만한 콘텐츠들을 추천하며 적합한 콘텐츠를 제공할 수 있다. 해당 방법은 Amazon, Meta, Coupang, 등 이미 많은 기업에서 사용하며 유저별로 다른 광고를 하며 수익을 올리고 있다. Amazon 구매 중 35%의 제품은 Amazon이 추천한 제품을 구매한다고 하니 유저의 편의성뿐만 아니라 기업의 매출 향상에도 큰 기여를 하고 있음을 알 수 있다.

이렇게 데이터를 자산으로써 활용하려면 Raw Data 그자체로는 큰 도움을 줄 수 없다. 이 Raw Data사이에서 User가 올바른 데이터를 찾고 사용할 수 있도록 User에게 데이터의 설명이나 속성, 데이터 리니지(계보), 등을 제공해야 한다. 이러한 전체적인 작업은 Data Catalog가 제공하는 프로세스 안에서 자동화되어 진행 되어야한다.

먼저, Data Pipeline을 통해 데이터를 수집하고, 카탈로그의 Agent를 통해 데이터의 Column이나 field를 확인해 Meta Data를 생성한다. 그리고 추가적으로 데이터의 Lineage를 구축하고 Data Profiling을 진행하며 데이터의 품질을 향상 시킨다. 이후 직접 사용하는 User를 통해 각 데이터에대한 설명과 태그정보를 수정하거나 사용자의 평가 및 리뷰를 통해 데이터를 자산화 한다.

이러한 작업들을 통해 데이터가 자산화 되며 활용성이 늘어나기 때문에 기업의 데이터 활용 역량과 Data Catalog 기술의 수준은 밀접한 관련이 있으며, 그에 따라 Data Catalog의 중요성은 더욱 커질 것으로 예상된다.

Data Fabric에서의 Data Catalog

데이터의 탐색 가능 역량은 다양한 유형의 Data Platform 시스템에서 공통적으로 요구된다. 앞서 Data Lakes 시스템 에서도 Data Catalog가 비즈니스 목적이 부합하도록 효과적인 방법으로 데이터 검색을 지원하는 것과 같은 맥락에서 Data Fabric 시스템에서도 Data Catalog는 핵심적인 요소 기술로 한층 더 강조된다.

Data Fabric의 특성 중 Data Lakes와 구분되는 것 중 하나는 분산 데이터 환경을 지원한다는 점이다. 때문에 Data Catalog와 직접 관련이 있는 고도화 된 Metadata 관리 기술이 필요하다. Data Lakes에서 통합 저장소에 원천 데이터를 수집하고 일관된 방법으로 데이터를 처리할 수 있는 것과 비교 했을 때, 상대적으로 분산 환경에서 효과적인 관리 방법을 구축하고 운영하는 것은 복잡도가 증가할 수 밖에 없다. 이러한 문제를 다루기 위해 도입된 기술 개념을 Active Metadata 관리라 하며, Data Fabric 시스템에서 핵심 정인 요소 기술 중 하나 이다.

또한, 분산 데이터 시스템의 특성에 따라 데이터의 구조, 스키마 정의에 사용하는 용어, Metadata 등을 표현할 때 사용하는 용어를 특정 형태로 통일해서 관리하는 것이 어렵다. 원천 데이터 소스 시스템 개별적으로 사용하는 용어가 다를 수 있기 때문이다. Data Catalog도 동일한 이유에서 의미론적 확장의 개념으로 Knowledge Catalog라는 기술 개념으로 발전한다.

Active Metadata 관리에서 중요한 것 중 하나는 분산 환경의 데이터 소스에서 발생하는 변경을 추적하고 반영하는 것이다. Data Lakes나 Data Warehouse와 같은 데이터 플랫폼 시스템은 중앙 집중식 저장소 구조를 갖고 있기 때문에, 여기서 축적된 기술을 Data Fabric 시스템에 그대로 적용하는 것은 어렵다.

Active Metadata 관리 체계에 대한 구조적 접근은 크게 두 가지로 볼 수 있다. 1)개별 데이터 소스를 작은 단위의 Data Platform 시스템 형태(ex. Data Product)로 구축하고 Metadata의 관리를 각각의 시스템이 독립적으로 운영 하면서 필요한 다른 Data Product 를 통합할 수 있는 Mesh 구조가 그 중 하나 이고, 다른 하나는 2)Metadata 관리에 대한 책임은 중앙 집중식을 유지 하면서 필요에 따라 동적으로 분산 된 데이터 소스와 커뮤니케이션 하면서 동작하는 Fabric 구조이다.

Metadata 관리에 대한 기술적인 기초가 마련 됐다면, Data Catalog에 대해 이야기 해 볼 수 있다. 분산형 시스템의 구조적인 특징이 Data Catalog 요소 기술에도 영향을 미친다. 중앙 집중식 시스템에서는 Metadata의 분석이나 재-가공 등에서 일관된 규칙 등을 적용해서 정의한 관리 체계에 부합하는 시스템을 구현할 수 있었다. 분산 데이터 환경에서 동적으로 데이터를 통합할 수 있는 역량이 필요한 Data Fabric의 경우 더 진화 된 형태의 지능형(Intelligent) Data Catalog 시스템이 필요하다. 기존의 Data Catalog가 기호와 용어를 일관되게 관리하고 전체 시스템에 적용하는 방식이라고 한다면, Data Fabric 시스템에서 Data Catalog는 도메인 전문 지식과 자연어 처리에 대한 역량이 통합돼 보다 효과적인 방식의 동적 데이터 통합을 지원해야 한다. 이를 Knowledge Catalog라는 용어로 표현하기도 한다.

요약 및 결론(Key Takeaways)

Data Platform은 데이터들을 통합 관리하기 위한 컴포넌트들의 집합체로 빅데이터를 효율적으로 자산화하기 위해서는 필수적으로 구축해야한다.

그 중 이번 글에서 언급하고 있는 Data Lake는 데이터 자산화를 위해 먼저 데이터를 수집하는 방법에 대해 이야기했다. 빠른 데이터 Load를 위해 schema-on-read 사용, 수집된 데이터에 용이하게 접근하기 위한 검색서비스, 접근한 데이터의 분석을 위한 환경 구성 및 Tool 연계성의 중요성을 제시하였다. 그 결과로 유저는 Data Silo 없이 곳곳에 흩어진 데이터를 Data Platform 한 곳에서 통합 관리할 수 있게 된다.

그리고 글에서 언급한 또 다른 Data Platform 컴포넌트는 Data Catalog로, 이는 Metadata를 이용해 Data Lake에 있는 대규모 데이터를 체계적으로 관리하고 효율적으로 활용하기 위해 필요한 핵심 기술 중 하나이다. Data Catalog를 통해 유저는 Data Engineer나 Data Base Administrator의 도움 없이도 손쉽게 원하는 데이터를 찾고 사용할 수 있게 됨으로 높은 활용성을 갖게된다. 이로써 조직은 데이터를 보다 효과적으로 관리하고, 비즈니스 의사결정을 위한 가치 있는 인사이트를 뽑아낼 수 있게 되어 데이터 자산화를 이룬다.

Metadata는 데이터의 전반적인 상태를 나타낼 뿐만아니라 이를 통해 실제 데이터를 직접 다운받지않고도 접속해 확인할 수 있는 데이터 가상화를 만들어내는 데에도 핵심 역할을 하기 때문에 이 Metadata 관리는 Data Catalog 제작에 있어 중요한 부분이다. 나아가 Data Fabric에서는 분산 구조의 특성에 따라서 동적 데이터 통합을 할 수 있는 지능형 Data Catalog가 요구되며, 이를 위해 Metadata 관리 또한 Active Metadata 관리라는 기존보다 진보된 기술이 필요하다.

Graph DB에 Vector 를 통합하여 Semantic Search 구현하기

· 7 min read
Bogyeong
Data Engineer @ Intellectus

이 글에서는 텍스트(자연어) 데이터의 색인(Index) 방식과 활용 방법에 대해서 기술적으로 설명한다. LLM 모델 자체에 대한 기술적인 설명이나, 자연어 처리(NLP)에 대해 구현(implementation) 관점의 상세한 설명은 핵심 주제가 아니다. 텍스트 임베딩을 이용한 검색 시스템의 전반적인 설명은 이전 포스팅에서 다루었다. 임베딩을 이용한 벡터 유사도(Vector Similarity) 기반 시맨틱 검색을 이해 하거나, Graph DB를 적용한 검색 기능 고도화에 관심이 있는 소프트웨어 엔지니어에게 도움이 될 것이다.

Semantic vs. Synthetic

사용자가 자연어를 이용해 필요한 정보를 찾기 위한 기술 중 비교해볼 수 있는 것으로 아래와 같은 두 방식이 있다.

  1. 직접적인 키워드 매칭 을 이용한 Synthetic Search(Keyword Search)
  2. 벡터 유사도 측정(Vector Similarity)을 이용한 Semantic Search

Synthetic Search의 대표적인 예로 n-gram을 기반으로 Full-text search를 지원하는 방식이 있는데, 이는 전문을 일정 단위(n)로 쪼개어 각각의 부분들을 인덱스로 활용하여 검색 정확도를 올리는 방법이다. 웹 브라우저나 일부 프로그램에서 사용하는 Ctrl + f(찾기)기능이 바로 대표적이다. 이는 입력된 검색어의 일치를 검사하기 때문에 높은 정확도의 장점이 있지만, 반대로 그렇기 때문에 검색어 내의 오타 발생이나 잘못된 띄어쓰기 같은 문법적 차이로 기대하는 검색 결과를 얻지 못할 수도 있다. 또한 인덱스 단위 데이터가 별도로 저장되고 정렬되기 때문에 인덱스 데이터베이스의 용량과 변경에 따른 재 정렬 과정에서 부하가 발생하는 단점이 있다.

또한, 데이터의 의미론적 연관성을 반영할 수 없기 때문에 비슷한 의미를 가진 데이터를 찾는 데 어려움이 있을 수 있습니다. 이런 한계를 극복하고 보완하는 방법으로 Vector Similarity를 활용하는 것이 Semantic Search 의 여러 방식 중 하나가 있다. Semantic Search는 자연어의 의미론적 요소를 반영하기 때문에 사용자 입장에서 더 풍부한 검색 결과를 제공받을 수 있다. 임베일 기술을 이용해서 단어를 벡터화로 표현하면 유사성을 계산할 수 있으므로 이러한 검색 방식을 구현하는 것이 가능하다. 사용자가 입력한 검색어와 관련된 정보를 더욱 효과적으로 찾을 수 있다.

먼저 단어를 컴퓨터가 처리할 수 있도록 다차원의 벡터로 변경시키는 Text Embedding이 필요하다. 임베딩 방법이나 벡터 유사도에 대한 설명은 이전 포스트를 참고하면 된다.

텍스트 임베딩은 (일반적으로) 많은 데이터를 사용하여 모델을 학습시킬 수록 성능이 향상되며, 여러 파라미터/임베딩 차원 등을 조정해야 한다. 직접 임베딩 모델을 구축하고 충분한 양의 데이터를 학습 시키고, 충분한 하드웨어 자원을 이용해서 동작 시키는 일은 기술적 난이도나 비용 면에서 쉬운 일이 아니다. 최근에는 LLM 기반의 서비스들이 제공하는 임베딩 API가 좋은 대안이 될 수 있다. 상용 수준의 서비스를 제공하는 만큼 결과 면에서도 높은 품질을 제공하며, 모델 생성을 위한 학습과 추론에 필요한 하드웨어 자원을 공유하는 모델이기 때문에 사용량 만큼의 합리적인 비용을 기대할 수 있다. OpenAI에서 제공하는 Embedding API도 그 중 하나 이다. API 사용량에 따라 일정 비용(23년 6월 기준 0.0001$/1K token)이 발생한다. 무엇보다 NLP 서비스를 개발하는 초기 단계에서 합리적인 비용과 성능으로 사용할 수 있다. 모델 생성의 자세한 내용은 비공개 이지만, 경우에 따라서는 영어 외 언어에 대해서도 유의미한 결과를 얻을 수 있다는 것은 장점 중 하나 이다.

하기는 데모 애플리케이션의 동작 모습으로 이모지(Emoji) 데이터를 GloVe 방식으로 twitter 에서 생성된 corpus 를 직접 훈련시켜 개발 환경에서 직접 동작시킨 모델과 OpenAI 의 임베딩 API를 사용하여 각각 입력 검색어에 대해 관련성이 있는 결과를 표시한 것이다.

demo-screenshot-01demo screenshot demo-screenshot-02demo screenshot demo-screenshot-03demo screenshot

AWS에서 Roles Anywhere로 credential 관리 대체하기

· 2 min read
Eunho
Software Engineer @ Intellectus

AWS IAM Roles Anywhere는 AWS 내에서 Role을 이용해서 임시 credential을 사용하는 것과 동일하게, 외부에서도 Role을 이용해서 임시 credential을 이용해서 AWS내의 자원을 사용할 수 있도록 한다. IAM User에 credential을 생성하여 프로그램 환경 변수나 aws CLI config 사용하는 것과 비교 했을 때 보안이 강화된다. 또한, Devfile 과 같은 개발 환경 자동화 도구를 통합하여 개별 개발자가 복잡한 개발환경 설정에서 자유로워 진다.

Roles Anywhere 설정하고 Dev Environments in CodeCatalyst 인스턴스에 적용하는 예를 통해서 구현 방법에 대해서 알아본다.

  • 전체 흐름
  • AWS Private Certificate Authority를 이용한 사설 인증서(Private certificate) 발급

AWS Private Certificate Authority를 이용한 사설 인증서(Private certificate) 발급

openssl을 이용해서 직접 사설 인증서를 발급하고 IAM > Roles > Roles Anywhere > Create a trust anchor 에서 직접 입력하는 방법도 있지만, 여기서는 사설 인증서를 관리할 수 있는 AWS Private Certificate Authority를 이용한다.

먼저 사설 인증서를 발급하기 위해서 CA(인증 기관)을 생성한다.

create-a-private-CAAWS Private Certificate Authority > Private certificate authorities

create-CA-form-part1Mode: General-purpose | Type: Root create-CA-form-part2CSR create-CA-form-part3algorithm: RSA 2048

Serverless

· 15 min read
Eunho
Software Engineer @ Intellectus

Serverless 방식이 추구하는 성과는 충분히 설득력이 있다. 유지보수와 변경관리를 쉽게 만들고, 운영 환경에서의 자원 관리를 효율성을 높인다. 이 성과를 취하기 위해서는 변화를 수용해야 한다. 경험에 비추어 봤을 때, 팀 단위로 움직이고 있는 프로젝트에서는 변화의 정도에 비례하여 저항이 발생한다. Serverless 방식이 제공하는 구조적인 장점을 온전히 취하면서, 프로젝트에 환경에 맞게 최적화 하는 일은 기존에 동작하고 있는 업무 프로세스의 성숙도가 높을수록 큰 저항이 발생할 가능성이 높다.

이 글은 개별 엔지니어의 생산성을 넘어서 프로젝트 혹은 팀의 생산성과 성과에 대해 고민하고 있는 소프트웨어 엔지니어들과 나누고 싶은 이야기이다.

코드 작성에 사용하는 툴이나 프로그래밍 언어, 혹은 새로운 개발 프레임워크의 도입은 Serverless 방식을 온전히 적용하는 것에 비하면 단순한 변화라 할 정도다. 이 포스트에서 경험을 바탕으로 다음의 주제에 대해서 생각을 나눠 보고자 한다:

  • 왜 Serverless 방식을 선택해야 할까?
  • 바꿔야 하는 것들
  • 주어진 비즈니스 환경에서 성공에 기여하기 위한 소프트웨어 개발 전략과 기술적인 구현 사례

왜 Serverless 방식을 선택해야 할까?

왜 해야 하는지 따라서 어떻게 할 것인가가 결정된다.

소프트웨어 업계에서 'No Silver Bullet'1은 널리 알려진 명제이다. 특정 관점에서 우월할 수 있는 어떤 선택도 다른 관점과 상충(trade-off) 되는 경우는 매우 흔하다. 무엇보다도 소프트웨어 시스템은 순수 창작물이 아니라 비즈니스를 지원하고 혁신하기 위해 사용되기 때문에 비즈니스 환경 변화에 따라 적응해야 하는 것은 필연적이다. 이러한 특성에 비추어 Serverless 방식의 도입의 이유는 단순하고 직관적이다. 비즈니스 환경의 움직임을 자동차와 비교하면 이 생태계는 항상 accelerator-pedal을 힘껏 밟고 있다. 단순히 특정 방향으로 움직이고 있는것이 아니라 항상 가속을 하고 있는 것이다. 역사적으로 이 위태로워 보이는 질주를 지속하는 방법은 감속 장치((brake))를 발전시키는 것이 아니라, 더 단단한 섀시(chassis)와 스테빌라이저(stabilizer)를 보완하면서 동시에 더 빠른 가속 장치를 추가하는 것이다. Serverless 방식은 새로운 가속 장치이다.

산업 현장에서는 소프트웨어 시스템을 활용해서 비즈니스 기회를 확장하고 실행을 가속화 하고있다. 소프트웨어 제품의 구현과 유지보수도 이러한 속도에 발을 맞춰야 한다. 이 변화는 이미 정립된 기술 분야의 연속적인 발전으로는 설명하기 힘들다. 이 변화의 속도는 구조적인 진화에서 비롯된 것이다.

소프트웨어를 기초로 인터넷을 통해 연결된 디지털 세계는 비즈니스의 한 관점에서 보면 일종의 실험실이다. 위험(risk)를 효과적으로 관리 하면서 구상하고 있는 비즈니스를 실증하고 동작시켜볼 수 있는 기회다. 시장 경쟁 구도 속에서 이 실험을 얼마나 효율적으로 실행하고 효과를 극대화 하느냐 하는 것이 비즈니스의 경쟁력에 영향을 미친다. 개별 실험들은 시스템화 되면서 체계적으로 조직되어 개별 실험의 생명 주기는 더 빨라지고, 데이터로 확인된 기회들은 비즈니스 가치로 변환된다. 소프트웨어 개발, 즉 구현 관점에서는 실질적으로 동작하여 사용자에게 전달될 수 있는 소프트웨어 제품들이 이러한 프로세스에 맞춰 공급돼야 한다. 빨리 만들어서 사용자에게 공개 해야 하는 것이다.

일정 수준 이상 품질의 소프트웨어를 개발하는 역량은 개별 엔지니어의 역량과 밀접한 관련성이 있을 수 있다. 하지만 프로젝트의 규모가 일정 수준 이상 커지면 개인의 역량으로는 제어할 수 없는 위험 요소들이 생긴다. 그 중 한가지가 제품을 배포하고 변경을 관리하는 부분이다. 소프트웨어의 본질적인 속성에 의해 소프트웨어는 지속적으로 변경된다. 이 속성은 비즈니스 환경의 변화를 수용할 수 있는 기초가 되기도 한다. 문제는 이 변경이 동작하고 있는 제품과 지원하고 있는 비즈니스 성과에 영향을 미치는 위험 요소라는 것이다. 개발 과정에서 발견되지 못한 프로그램 오류나 기대하지 않은 부작용(side effects)과 같은 현상을 개별 엔지니어의 역량 만으로 통제 하는 것은 불가능한 일이다.

바꿔야 하는 것들

운영 환경(코드가 최종적으로 동작하는 환경)에서 개발하기

코드를 작성한 개발자가 확인해야 하는 것은 이 코드가 실제 사용자의 요청을 제대로 처리할 수 있는가 하는 것이다. 소프트웨어가 놀라울 정도로 잘 작동하기 때문에 사람들은 종종 실체적 복잡성과 위험에 대해 잘 생각하지 않는 듯 하다. 개발 환경에서 실행한 빌드의 결과와 배포 과정에서 실행한 빌드의 결과는 정말 같을까? 개발 환경의 느슨한 보안 정책으로 인해 잘 동작하던 외부 API연동은 운영 환경에서도 당연히 문제 없이 동작할까? 프로그램이 참조하고 있는 특정 환경 변수의 값은 내 컴퓨터의 메모장에만 존재하는 것은 아닐까? 컨테이너 기술의 보급은 큰 의미가 있는 진보이다. 작성된 코드가 최종적으로 사용자에 의해 사용될 수 있도록 만들기 위한 모든 단계에서 위험성을 제어할 수 있는 기반을 마련했다.

Serverless 방식을 고려 한다면 운영 환경은 일반적으로 클라우드 서비스가 제공한다. 클라우드 서비스에서 동작하는 개발 환경이 필요하고, 상당히 잦은 주기로 로컬 개발 환경의 작업물이 동기화 되고 테스트 케이스의 실행 결과를 확인할 수 있어야 한다. 여기에 더해서 Serverless 어플리케이션의 주요 전략 중 하나가 상태 관리의 책임을 분리하는 stateless라는 것을 생각 해 본다면, 상태를 관리하는 어떤 컴포넌트와의 연동이 필요할 것이다. 우리의 경험을 통해서 제안하고자 하는 방법은 클라우드 환경에 개별 소프트웨어 엔지니어를 위한 개발 환경을 제공하는 것이다. github에서 제공하는 CodespacesAWS의 CodeCatalyst와 같은 서비스가 좋은 대안이다. 우리 팀은 개발과 운영 환경으로 사용하고 있는 AWS와 더 쉬운 통합을 위해 CodeCatalyst를 선택했다.

주어진 비즈니스 환경에서 성공에 기여하기 위한 소프트웨어 개발 전략과 기술적인 구현 사례

Poc(Proof of concept) 수행의 목적은 '만들어보는 것'이 아니라, 본격적인 비즈니스 모델의 실현에 진입하기 전에 비즈니스 모델의 가설을 데이터를 통해 검증하는 것이다. 동작하는 시스템을 통해 이해당사자 또는 불특정 사용자에게 아이디어를 노출시켜 피드백을 수집하고 분석하는 일이다. 이 과정은 빠르고 효율적이어야 한다. 또 한번 강조하고 싶은 것은 구현하는 것 자체가 목적이 아니라 아이디어에 대한 데이터를 확보하는 것이 진짜 목적이라는 것이다.

이러한 작업의 반복은 생각보다 유쾌하지 않다. 단순한 기능이 아니라 단 하나라도 비즈니스 시나리오를 실행할 수 있어야 한다. 유의미한 데이터를 확보하기 위해서는 시장에서의 비교 우위를 주장할 수 있을 정도는 아니더라도 일반 사용자들이 일정 시간 머물면서 써볼 수 있을 정도는 돼야 한다. 트래픽이 어느정도 발생해야 데이터에 대한 해석이 가치가 있게 되는 경우들도 있기에 특정 목적의 마케팅이나 홍보 같은 활동을 진행할 수 있도록 시스템이 지속적으로 운영돼야 한다. 아직 비즈니스 모델 전체가 작동하지 않는 상황에서 아주 작은 자원들 일지라도 비용은 무시할 수 없다.

이미 알려진 많은 성공 사례에서 민첩하게 비즈니스를 서포트하는 시스템을 어떻게 개발하면 좋은지에 대해서 이야기하고 있지만, 잘 생각해 보면 그런 이야기들은 성공했기 때문에 성립되는 논리 인 경우가 많다. 현실은 아이디어를 아무리 잘 구현해서 치열한 논의 끝에 결정한 우리 브랜드의 도메인에 연결시켜 공개해도 아무일도 일어나지 않는다는 것이다. 팀 내부의 여러 가설을 증명하기 위해 테스트용 트래픽을 발생시키는 또 다른 개발을 하거나, 계속 쏟아져 나오는 여러 개발 및 운영 도구들을 찾아보면서 어떻게 적용시켜야 할지를 고민하면서 스크립트를 작성해야 한다.

그래서 필요한 것은 시간이다. 필요한 구현체를 더 빨리 만들어내고, 또 필요한 무언가를 해야 할 시간 동안 발생하는 비용을 줄이면 무언가를 할 수 있는 시간이 생긴다.

이 문제에 대한 해결 방법 중 하나는 사용량 기반 과금 정책 서비스를 최대한 활용하는 것이었고, 바로 Serverless 방식의 체택이다. 그리고 Microservice 설계 방식을 활용한 재사용이다. 서버를 계속 실행 상태로 유지할 수 없는 환경에서는 소스코드 레포지토리에서 다시 해당 부분을 복사하거나 패키지를 불러와서 코드 레벨에서 재사용이 이루어진다. 하지만 Serverless 방식을 통해 배포된 기능들은 개발 작업 중이거나 배포된 상황에 상관없이 요청하고 응답을 처리하는 방식으로 이미 구현된 기능들을 재사용한다.

Footnotes

  1. Frederick P. Brooks Jr., No Silver Bullet - Essence and Accident in Software Engineering

CodeCatalyst로 개발환경 구축하기

· 4 min read
Eunho
Software Engineer @ Intellectus

Amazon CodeCatalyst는 AWS에서 제공하는 CDE (Cloud Development Environments) 서비스다. CodeCatalyst는 프로젝트가 AWS의 서비스를 활용해서 설계 됐을 때 좋은 선택이다. 접근 권한 시스템인 AWS IAM 혹은 VPC 와 같은 네트워크 환경 구성을 사용할 수 있기 때문이다.

실제 사례를 통해서 Amazon CodeCatalyst를 이용해서 Serverless 개발환경을 구축하는 것을 단계적으로 알아본다.

  • Devfile: 개발환경 기본 컨테이너 이미지 및 의존성 패키지 설치
  • codecatalyst/workflows: CI/CD 배포 자둥화 구성

Devfile: 개발환경 기본 컨테이너 이미지 및 의존성 패키지 설치

CodeCatayst에서 실질적인 개발을 위한 컴퓨팅 인스턴스를 제공하는 것은 Dev Environment 이다. 여기서는 Github에 생성된 코드 레포지토리를 Clone 해서 개발 인스턴스를 생성하도록 한다. 이 때 사용하는 컨테이너 베이스 이미지를 Devfile를 이용해서 설정 할 수 있다. 레포지토리에 devfile.yaml 이 최상위 디렉토리(/)에 생성되어 있지 않다면 CodeCatayst의 기본 설정 베이스 이미지를 사용하며, 컨테이너에 미리 설치된 주요 패키지의 정보는 AWS 문서에서 확인할 수 있다.

schemaVersion: 2.0.0
metadata:
name: aws-universal
version: 1.0.1
displayName: AWS Universal
description: Stack with AWS Universal Tooling
tags: ["aws", "al2"]
projectType: "aws"
components:
- name: aws-runtime
container:
image: public.ecr.aws/aws-mde/universal-image:latest
mountSources: true
volumeMounts:
- name: docker-store
path: /var/lib/docker
- name: docker-store
volume:
size: 16Gi

본 사례에서는 nodejs 의 버전이 18 이상 필요했기 때문에, devfile.yaml 을 수정해서 레포지토리의 루트 위치에 추가했다.

schemaVersion: 2.0.0
metadata:
name: aws-universal
version: 1.0.1
displayName: AWS Universal
description: Stack with AWS Universal Tooling
tags: ["aws", "al2"]
projectType: "aws"
components:
- name: aws-runtime
container:
image: public.ecr.aws/aws-mde/universal-image:3.0
mountSources: true
volumeMounts:
- name: docker-store
path: /var/lib/docker
- name: docker-store
volume:
size: 16Gi

*컨테이너 베이스 이미지의 버전이 latest 인 경우 Universal image 1.0 runtime versions을 참조 하며, 위에서 수정된 것과 같이 특정 버전(3.0)을 명시하여 이미지를 선택할 수 있다.

codecatalyst/workflows: CI/CD 배포 자둥화 구성

변경 사항에 대한 통합과 배포는 팀의 협업 방식에 맞추어 결정해야 한다. 여기서는 기본적으로 main 브랜치에 커밋이 발생하면 자동적으로 특정 AWS 계정 내에 개발 환경에 배포하는 것을 예로 설명한다. workflows는 yaml 파일 형태로 프로젝트의 해당 경로에 .codecatalyst/workflows/ 위치 시킨다. 예제 에서는 간단하게 TriggersActions 두 속성을 이용해서 메인 브랜치에 업데이트 발생 했을 때, 지정된 베이스 이미지에서 명령어를 실행하는 worklow이다.

Name: onPushToMainRunDeployment
SchemaVersion: "1.0"
Triggers:
- Type: PUSH
Branches:
- main
Actions:
LambdaFunctionDeployment:
Environment:
Name: environemt-name
Connections:
- Name: connection-name
Role: role-name
Identifier: aws/build@v1
Compute:
Type: EC2
Inputs:
Sources:
- WorkflowSource
Configuration:
Container:
Registry: ECR
Image: public.ecr.aws/aws-mde/universal-image:3.0
Steps:
- Run: aws sts get-caller-identity
- Run: yarn
- Run: yarn run sls:deploy

텍스트(자연어) 데이터 인덱스 방식과 활용

· 23 min read
Bogyeong
Data Engineer @ Intellectus
Eunho
Software Engineer @ Intellectus

벡터 인덱스와 유사도를 이용해서 이모지(Emoji) 시맨틱 검색 기능 구현하기

이 글에서는 텍스트(자연어) 데이터의 색인(Index) 방식과 활용 방법에 대해서 기술적으로 설명합니다. 개별적인 텍스트 데이터의 색인 방법인 n-gram의 구체적인 작동 방식을 심도 있게 설명하거나, 자연어 처리(NLP)에 대해 구현(implementation) 관점의 상세한 설명은 이야기하려고 하는 핵심 주제가 아닙니다.

때문에, 자연어 검색 시스템을 전반적으로 이해를 목적으로 하거나, 벡터 유사도(Vector Similarity)를 이용한 시맨틱 검색(Semantic Search)에 관심이 있는 소프트웨어 엔지니어 분들이 읽어보시고 의견을 나누어 보면 좋겠습니다.

데이터 관리를 위한 시스템의 공통적인 요구사항 중 하나는 검색 기능입니다. 일반적인 사용자는 특별한 시스템이 아니더라도 자연어로 작성한 키워드를 입력하고 적절한 결과가 제공될 것으로 기대합니다. 기술적으로 이러한 강력한 성능의 검색 성능에 부합하는 소프트웨어 기능을 직접 구현하는 것은 쉬운 일이 아닙니다.

키워드로 이모지 검색하기

메신저나 이메일을 작성할 때 이모지(emoji)의 활용 빈도는 점점 늘어나는 듯 보입니다. 경험적으로도 실용적으로 메시지의 내용을 간결하게 유지 하면서도 뉘앙스를 함께 전달하기 위해서 매우 유용한 커뮤니케이션 도구 중 하나라고 생각합니다.

하지만 상황에 맞는 적절한 이모지를 이용하는 것은 여간 쉬운 일이 아닙니다. Window에서 기본적인 이모지 검색을 지원하고 있지만 해당 검색 시스템을 이용해 원하는 이모지를 찾을 수 있는 확률이 상대적으로 낮기 때문에 주로 사용했던 것들만 사용하게 됩니다.

emoji-windows-app실제 Window 이모지에서 케이크를 검색한 결과. 🎂(생일케이크)는 보이지 않는다.

이러한 이모지 검색이 직관적으로 보여질 수 있는 좋은 사례로 생각되어 이번 검색 기능 구현의 사용 데이터로 설정하였습니다.

검색 시스템 중 가장 고전적인 방법인 입력된 단어가 포함된 결과를 모두 보여주는 것을 Synthetic Search, Keyword Search라 부르고, 대표적인 방법으로는 N-Gram이 있습니다.

synthetic-search-breadn-gram을 이용한 Synthetic Search 결과 1

synthetic-search-cakn-gram을 이용한 Synthetic Search 결과 2 | ‘cak’ 까지만 입력해도 cake가 검색된 것을 볼 수 있다.

n-gram에서 n은 숫자를 의미하며 문자열에서 n개의 연속적인 요소를 잘라서 Index로 사용하는 방법입니다(그래서 n을 n-gram token size 라고도 합니다). 예를들어 “DATA”를 n=2인 Bi-gram으로 적용하면, 인덱스는 “DA”, “AT”, “TA”가 생성됩니다.

ngram-examplen-gram “data” 예시 ngram-mysqlMySQL에서 n-gram token 수를 확인하는 쿼리. Default는 2이다.

한글로 적용하면 “데이터” 에서 “데이”, “이터” 라는 인덱스가 생성됩니다.

이렇게 n-gram을 사용한 full-text search를 하게 되면, 전문에서 부분적으로 인덱스를 가지게 되어 검색의 정확도가 상승하게 됩니다. “아메리카노”를 검색하기 위해서 “아메”라고만 넣어도 “아메리카노”가 나오니까요(물론 “아메”가 포함된 “아메리카” 같은 다른 단어들도 나옵니다). 이를 정렬하는 방법은 관련성 점수, 검색 옵션에 따라서 달라집니다. 특히 한국어, 중국어, 일본어의 경우 단어+단어 조합으로 새로운 문자를 만들 수 있기 때문에 n-gram을 사용하면 검색의 정확도가 더욱 올라갈 수 있습니다.

하지만 n-gram이 무조건 좋은 것은 아닙니다. 검색 결과에서 누락이 발생할 확률이 적다는 장점이 있지만, 인덱스가 늘어남에 따라 DB 용량이 증가한다는 단점 또한 가지고 있기에 상황에 맞춰 적절한 token size(=n) 설정이 필요합니다.

그렇다면 모든 검색 시스템을 확실한 n-gram으로 만들어야 할까요? 사랑을 입력했을 때, 하트가 나오고 연인의 모습이 나온다면 어떨까요? ‘이런 것도 나오네?’ 하면서 유저의 검색 만족도가 올라가지 않을까요? 또 케이크를 입력했을 때, 촛불, 풍선 같은 이모지들이 같이 나온다면요?

이렇게 텍스트 자체가 아닌, 그 검색어가 가지고 있는 의미에 기반해서 검색 결과를 보여주는 것이 바로 Semantic Search 입니다. 0과 1밖에 모르는 컴퓨터가 어떻게 우리가 사용하는 단어의 의미를 이해하고 관련 결과를 보여줄 수 있는 걸까요?

그건 바로 데이터의 Vector화와 **유사도 검색(Similarity Search)**에 달려있습니다. 데이터를 다차원의 공간 속 벡터로 표현하고 해당 벡터와 유사한 벡터를 찾음으로 효율적인 데이터 검색을 진행하며, 이는 곧 사용자의 검색 만족도를 높여줍니다. 유사한 벡터는 다차원의 공간에서 유사한 위치에 존재하기에 다른 말로 ‘최인접 이웃 검색(Nearest Neighbor Search)’이라고도 합니다. 이런 방법은 문서 검색뿐만 아니라 추천시스템, 머신러닝, 컴퓨터비전 등 다양한 곳에서 사용됩니다.

앞서 n-gram이 단어를 n개의 연속된 단어로 쪼개서 인덱스로 설정해 검색했다면, Semantic Search는 데이터를 다차원의 Vector로 만든 Vetor값([12.23, 456.789, …])을 인덱스로 설정해 검색을 진행합니다.

synthetic-vs-semantic“Sandwich”를 검색했을 때 보여지는 Keyword Search와 Vector Search의 결과 차이

Word to Vector

단어를 벡터로 수치화하려면 어떻게 해야할까요? 데이터 벡터화 중 텍스트데이터인 단어를 고정된 사이즈의 벡터로 변환하는 ‘단어 임베딩(Word Embedding)’ 방법과 그를 통해 유사도를 측정하는 방법을 알아보겠습니다.

word-tokenization문장수집 → 토큰화의 단계1

  1. 문장수집

: 원하는 대상에서 텍스트 데이터를 수집하는 단계입니다. 이는 자연어 처리를 위한 첫번째 단계로 특정 목적을 가진 텍스트들을 모읍니다. 대부분 웹크롤링이나 ebook 데이터를 사용합니다. 이 단계는 벡터화의 시작점으로 양질의 데이터를 모으는 것이 중요합니다. 좋은 재료로 요리해야 맛있는 음식이 나오는 것 처럼 Input 데이터가 좋아야 Output 또한 좋은 결과가 나오기 때문입니다. 그리고 이렇게 자연언어 연구를 위해 특정한 목적을 가지고 언어의 표본을 추출한 것을 코퍼스(Corpus)라고 합니다.

  1. 텍스트 전처리 및 토큰화(Tokenization)

: 수집한 텍스트에서 불필요한 정보를 제거하거나 바꿔주는 전처리를 거칩니다. 이때, 크롤링할 때 노이즈로 들어오는 html 태그 내용(br, a,…)을 삭제하거나, 대문자를 소문자로 통합하거나 특수문자들을 제거하는 등의 과정이 들어갑니다. 그리고 의미있는 단어(Token)를 기준으로 자르는 작업(Word Tokenization)을 진행합니다. 가장 쉬운 방법으로는 I love data → i, love, data 처럼 구분 기호/띄어쓰기 기준으로 나누는 방법이 있습니다. 하지만 단어 토큰화를 진행할 때엔 고려해야할 사항이 많으므로 상황에 맞춰 전처리 및 토큰화를 진행하는 것이 좋습니다. 예를들어 한국어는 띄어쓰기 기준으로 하면 ‘데이터가 좋아’ → ‘데이터가’, ‘좋아’ 처럼 실질적 의미인 ‘데이터’와 접미사 ‘-가’가 함께 쓰이는 교착어이기 때문에 형태소 분석을 통한 토큰화가 더 유리합니다.

  1. 단어 임베딩(Word Embedding)

: 모든 텍스트를 토큰화 한 후, 각 단어를 고정된 크기의 실수 벡터로 변경하는 단계입니다. 주로 Word2Vec이나 GloVe FastText 같은 단어 임베딩 기법을 사용하며 단어를 벡터로 변형하여 은 단어 또는 문서를 벡터로 변환하여 의미론적 뜻(semantic meaning)에 따라 유사한 문서 또는 단어를 효율적으로 검색할 수 있습니다.

  1. 유사도 구하기

: 이제 모든 단어(혹은 문장)은 일정 차원을 가진 벡터로 변경되었습니다. 그렇다면 이제 벡터들 간의 유사도를 구함으로 비슷한 의미를 가진 단어인지 확인하는 순서만 남았습니다. 이런 벡터간 유사도를 구하기 위해 사용되는 방법은 주로 코사인 유사도(Cosine similarity), 유클리디안 거리(Euclidean distance), 자카드 유사도(Jaccard similarity) 3가지가 사용됩니다. 각각의 방법에대해 간단히 소개하겠습니다.

  • 코사인 유사도(Cosine similarity)

두 벡터사이의 내각를 측정하여 유사도를 측정하는 방법입니다. 백터의 방향이 비슷할 수록(cosθ= 1) 두 벡터는 유사하다고 할 수 있으며, 반대로 직각(cosθ= 0)을 이룰 때에 두 벡터는 유사성이 없음을 의미합니다. Cosθ의 값은 -1~1 사이의 값을 갖지만 자연어 처리의 경우A, B 피쳐 벡터 행렬은 보통 단어 빈도(tf-idf 가중치)로 측정되어 음수값이 없으므로 코사인 유사도는 0~1 사이의 값을 갖게 됩니다. 그리고 자연어는 고차원의 벡터를 사용하게 되는데, 코사인 유사도의 경우 벡터 차원수의 영향을 덜 받고, 단어의 다양성으로 발생하는 단어 희소성(sparsity)의 문제에도 민감하지 않기 때문에 자연어 부분에서 유사도를 측정할 때 Cos유사도를 많이 사용하고 있습니다.

cos-similarityCos유사도 수식 (출처 : Wiki백과2) vector-space-example3 단어를 2D의 공간 상에 표시한 예시 출처 : (출처 : Digital begriffsgeschichte: Tracing semantic change using word embeddings) 3)

  • 유클리디안 거리(Euclidean distance) :

두 벡터간의 직선 거리를 계산하여 유사성을 평가하는 방법으로 두 벡터간의 거리가 작을 수록 더 유사하다고 평가 할 수 있습니다. 하지만 다차원의 공간에서 거리를 측정하게 되면 각 데이터들의 유사도가 보존되지 못한다는 단점이 있습니다. 이를 보완하기 위해서 차원을 축소시키는 방법도 있으나 많은 연산을 필요로 합니다.

euclidean-distanceEuclidean distance (출처 : Deep Dive: How do Vector Databases Work4) euclidean-distance-2Euclidean distance는 동일하지만 유사도가 다른 벡터의 경우 (출처 : Deep Dive: How do Vector Databases Work4)

  • 자카드 유사도 (Jaccard Similarity) :

집합에 대한 유사성을 측정하는 방법으로, 자연어 처리의 경우 두 집합(Token)의 공통된 원소의 비율을 측정하여 0~1사이의 값으로 유사도를 나타냅니다. 이는 단어의 순서나 길이, 의미를 무시하고 단순 단어 비교만 진행하기 때문에 정확한 유사성을 판단하지 못한다는 단점이 있습니다.

jaccard-similarityJaccard Similarity 수식

Github에 있는 예시를 참고하여 Vector를 이용한 Semantic Search를 구현하였습니다. 먼저, 효과적인 작업 진행을 위해 직접 문장을 수집하고 전처리, 단어 임베딩하지 않고, Pre-trained Vecrtor를 사용했습니다. 사용한 Pre-trained Vector는 Tweeter(현 X) 데이터를 Corpus로 사용하여 GloVe라는 Word Embedding방법으로 2B tweets을 27B의 token으로 나눠 Embedding한 Vector 데이터입니다.

vector-data-examples*glove.twitter.27B.200d.txt의 일부분으로 단어와 특수문자들에 200demansion의 vector가 부여되어 있다. *

위처럼 동일한 Word Embedding model의 Pre-trained Vecrtor를 사용하여 Emoji data의 Emoji 설명과 유저가 입력하는 Search Query를 처리해 동일한 Vector size로 변경하는 작업을 진행했습니다. 이렇게 동일한 Embedding model을 사용해야 동일한 Demansion의 벡터로 나오며, 같은 차원 내에서 유사도를 계산할 수 있습니다.

example-architectrue-for-semantic-searchPre-trained vector를 이용한 Semantic search Architecture emoji-vector-example.pngbirthday cake을 vector화 한 결과. 단어들의 조합도 동일한 demansion을 갖도록 만듭니다.

def cosine_similarity(query_word_vec, emoji_desc_vec):
dot_product = sum(x * y for x, y in zip(query_word_vec, emoji_desc_vec))
magnitude_query_word = sum(x * x for x in query_word_vec) ** 0.5
magnitude_emoji_desc = sum(x * x for x in emoji_desc_vec) ** 0.5
return dot_product / (magnitude_query_word * magnitude_emoji_desc)

# bread와 cake을 vector화 하여 넣은 결과
cosine_similarity(bread, cake)
>>> 0.6345

상기 식을 사용하여 User가 입력한 Query word를 Vector로 변형한 값과 이미 Vector로 변형하여 넣어둔 Emoji description 두 벡터 사이의 Similarity를 구합니다. 이렇게 Query word Vector와 모든 Emoji description Vector와 비교하여 Top 10개의 Emoji 를 출력하도록 구성합니다.

semantic-search-demo‘bread’를 검색한 결과 내용 캡쳐

bread를 검색한 결과 Similarity가 0.6345로 낮은 cake은 나오지 않았으며, 0.6886인 butter와 0.6601인 rice craker까지 출력된 것을 확인할 수 있습니다.

Review

가장 기본적인 n-gram을 사용하여 키워드에 따른 결과를 확인하고 사용자의 검색 만족도를 높이기 위해 Vector search의 과정과 그 결과를 확인하였습니다.

n-gram에 기반한 Full-text search는 User의 Input query에 있는 word 매칭으로 정확한 데이터를 출력해주었지만, 의미적 관련성이 있는 데이터를 출력해줄 수 없다는 점, 오탈자나 띄어쓰기 오류에 취약하다는 점, 큰 데이터베이스에서 검색을 수행할 때 계산 복잡성이나 저장공간 등에서 효율성이 떨어진다는 단점이 있었다.

이를 보완하고자 고차원의 벡터 공간에 데이터를 매핑하고 벡터간 유사성을 계산하여 검색하는 Vector search 방법을 이용해 의미적 유사성이 높은 데이터를 추천해 줄 수 있었다.

하지만 이런 Vector Search 방법 또한 고질적인 단점이 있다. 훈련 데이터에 없는 단어(Out of Vocabulary)는 처리할 수 없다는 것, 신규 단어를 넣을 경우 Embedding을 다시 계산해야하므로 경우에 따라 리소스 투입이 크다는 것, 경우에 따라 보편적이지 않은 관계성을 만들고자 할 때 어려움이 있다는 것이 문제이다.

demo-synthetic-vs-semanticOut of Vocabulary의 예시. Twitter Corpus에 없는 ‘Keycap’이란 단어를 입력하니, keyword search에서는 결과가 출력되나 vector에선 비슷한 emoji를 찾을 수 없다는 결과가 나온다.

이러한 Embedding 리소스에 대한 문제점은 최근 많은 이슈를 가져온 OpenAI의 API를 사용하는 것으로 개선할 수 있다. OpenAI는 자체 개발한 LLM(Large Language Model)에서 사용된 word Embedding 소스를 API를 통해 유료(23년 6월 기준 0.0001$/1K token)로 제공하고 있다. (참고 : OpenAI API Embedding)

사용 예시를 살펴보면, 미리 OpenAI 의 api key를 설정한 후 아래의 형태로 text를 입력하여 openai.Embedding.create()함수를 호출한다.

word_vector = openai.Embedding.create(
input=text,
model='text-embedding-ada-002'
)

그러면 아래와 같은 형태로 respond를 받을 수 있고 해당 embedding 값을 활용함으로 위에 문제된 리소스 뿐만 아니라 OpenAI가 지원하는 다국어 또한 사용이 가능해짐으로 추가적인 언어적 이점이 생겨난다.

{
"data": [
{
"embedding": [
-0.006929283495992422,
-0.005336422007530928,
...
-4.547132266452536e-05,
-0.024047505110502243
],
"index": 0,
"object": "embedding"
}
],
"model": "text-embedding-ada-002",
"object": "list",
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
}

이렇게 LLM 모델이 OpenAI를 통해 합리적인 가격대로 확산되면서 많은 개발자들이 보다 쉽게 자연어 처리에 접근할 수 있게 되었고, 이를 통해 다양한 자연어 Application들이 개발되고 있다.

더불어 최근 새로운 DB의 형태로 뜨고 있는 VectorDB의 발전 또한 이런 행보와 같이 한다고 생각합니다. 쉽게 만들어지는 Embedding 데이터를 저장하고 위처럼 검색하기 위해 Index화 한 후 시스템을 구축해가는 것입니다.

Footnotes

  1. dudeperf3ct Blog, Force of LSTM and GRU

  2. wikipedia, Cosine similarity

  3. Melvin Wevers and Marijn Koolen, Digital begriffsgeschichte: Tracing semantic change using word embeddings

  4. DAMIEN BENVENISTE, Deep Dive: How do Vector Databases Work 2