AWS 기술 블로그
Amazon OpenSearch Service의 검색 엔진으로서의 기능 설명
이 글은 AWS Big Data Blog에 게시된 ‘Amazon OpenSearch Service’s vector database capabilities explained‘을 기반으로 한국어로 번역 및 신기능과 관련된 사항을 최신화하였습니다.
개요
OpenSearch는 검색, 분석, 보안 모니터링 및 통합 가시성 애플리케이션을 위한 확장 가능하고 유연하며 확장 가능한 오픈 소스 소프트웨어 제품군으로, Apache 2.0 라이선스에 따라 라이센스가 부여됩니다. 지연 시간이 짧은 검색 및 집계를 제공하는 검색 엔진, 시각화 및 대시보드 도구, 알림, 세분화된 액세스 제어, 통합 가시성, 보안 모니터링, 벡터 저장 및 처리와 같은 고급 기능을 제공하는 플러그인으로 구성되어 있습니다. Amazon OpenSearch Service 는 AWS 클라우드에서 OpenSearch를 간편하게 배포, 확장, 운영할 수 있는 완전 관리형 서비스입니다.
사용자는 OpenSearch의 검색엔진으로서의 기능을 사용할 때 특수한 목적을 가지고 있습니다. 그러한 목적을 달성하기 위한 정보를 검색하기 위해 사용자는 OpenSearch를 검색 도구로서 사용합니다. 우리 모두는 단어를 입력하면 검색 엔진이 단어 대 단어 매칭을 기반으로 결과를 가져오는 ‘검색어 입력 창’ 인터페이스에 익숙해져 있습니다. 만약 무더운 여름 에어컨이 필요하여 벽지가 하얀 집에 어울리는 에어컨을 찾고자 한다면 먼저 Amazon.com에 접속하여 “28평 하얀 벽지에 어울리는 에어컨”라고 입력합니다. 안타깝게도 Amazon.com에서 이 검색어를 실행하면 의도한 것과는 달리 에어컨, 벽지, 인테리어용품과 같은 상품이 표시됩니다. 문제는 에어컨 제조업체가 제품 제목이나 설명 또는 검색 키워드로 ‘하얀’, ‘벽지’, ‘어울리다’ 라는 단어를 사용하지 않았을 가능성이 높다는 것입니다.
최근의 검색을 개선하기 위하여 ML기법이 대거 활용되고 있습니다. 그중 대량의 데이터를 n차원의 공간으로 인코딩하여 각 엔티티를 해당 공간의 데이터 포인트인 벡터로 인코딩 하고 유사한 엔티티가 서로 가깝게 배열되도록 구성하는 모델인 임베딩 모델을 사용하는 사례가 늘어나고 있습니다. 예를 들어 임베딩 모델은 말뭉치의 의미를 인코딩 할 수 있습니다. 인코딩된 문서에서 가장 가까운 벡터를 검색하는 K-NN(k-Nearest Neighbor) 검색을 통해 의미론적으로 가장 유사한 문서를 찾을 수 있습니다. 정교한 임베딩 모델은 제품의 카탈로그의 이미지와 텍스트를 인코딩하고 두 양식 모두에서 유사성 매칭을 활성화하는 등 여러 기능을 지원할 수 있습니다.
전통적인 검색 엔진으로서의 OpenSearch Service
Lexical Search(키워드 검색)
검색 엔진은 BM25 라는 확률적 검색 모델을 기반으로 데이터를 찾습니다. 이 알고리즘은 용어의 포화도와 문서 길이를 고려하여 각 문서별 점수를 부여합니다. 일치하는 항목에 대하여 문서 길이를 고려해 가변적으로 가중치를 부여합니다. 아래의 알고리즘은 BM25의 수식을 보여줍니다. 이 수식은 Term으로 분리된 최소단위인 형태소를 기반으로 문서의 가중치를 부여합니다.
따라서 Lexical Search는 보다 정확한 Term을 도출하기 위한 사용자 사전, 동의어 사전 생성과 형태소 분석이 검색 결과에 매우 큰 영향을 미칩니다. ‘Amazon OpenSearch Service, 한국어 분석을 위한 ‘노리(Nori)’ 플러그인 활용‘ 에서는 이러한 Term을 보다 효과적으로 분석 및 분류하기 위한 Nori 플러그인에 대하여 소개하고 있습니다.
Lexical Search 구성 요소
키워드 검색에는 앞서 이야기 한 여러 구성요소가 필요합니다. 대표적으로 아래의 3가지가 있습니다.
1. 사전
2. 형태소 분석기
3. Term과 Token
검색 엔진에서의 사전은 어학 사전과 같이 단어의 정의가 담겨있는 사전과는 다른 성격을 가지고 있습니다. 이 사전은 해당 단어가 명사인지 보조사인지와 같은 단어의 형태와 품사 정보를 담고 있습니다. 이 사전을 기반으로 형태소 분석기가 색인된 문서를 분석하여 최소단위인 형태소로 분리하고 분리된 Token이 해당 문서를 지칭하는 Term이 되어 저장됩니다.
이러한 구성 요소로 OpenSearch는 키워드 기반의 검색에서 높은 정확도로 검색 결과를 도출할 수 있었습니다. 하지만 Lexical 검색은 키워드 검색에는 높은 정확도를 보이나 자연어 검색에서는 검색 쿼리의 문맥/의미를 찾기까지 어려움이 있습니다.
벡터 데이터베이스로서의 OpenSearch Service
OpenSearch Service는 K-NN 플러그인을 통한 벡터 데이터베이스로서 Semantic 검색, LLM을 사용하기 위한 검색 증강 생성(RAG), 추천 검색등 다양한 활용 사례로 구현할 수 있습니다.
Semantic Search(의미론적 검색)
Semantic 검색을 사용하면 검색 문서에 언어 기반 임베딩을 사용하여 검색 결과의 관련성을 향상시킬 수 있습니다. 고객이 만약 “하얀 벽지와 어울리는 타워형 에어컨”과 같은 자연어 쿼리를 사용하면 그와 알 맞는 타워형 에어컨을 찾을 수 있도록 할 수 있습니다. 자세한 내용은 OpenSearch 에서 Semantic 검색 엔진 구축을 참조하여 Lexical Search(키워드 검색)과 비교해 보세요. nDCG@k와 같은 성능 평가 방법을 채택하여 보다 자세하게 비교 분석할 수 있습니다.
아래의 예는 OpenSearch에서 Bedrock Embedding Model과 통합하여 데이터를 벡터화 하는 아키텍처를 보여줍니다. 자세한 내용은 Amazon OpenSearch Service Integration 기능을 활용한 손쉬운 임베딩 파이프라인 구성 을 참조하세요.
LLM을 사용한 검색 증강 생성(RAG)
RAG는 Anthropic Claude와 같은 생성형 LLM을 사용할 때 신뢰할수 있는 생성형 AI 챗봇을 구축하는 방법입니다. Generative LLM의 등장으로 애플리케이션 개발자들은 이 혁신적인 기술을 활용할 방법을 모색하고 있습니다. 인기 있는 사용 사례 중 하나는 지능형 에이전트를 통해 대화형 경험을 제공하는 것입니다. 제품 정보, 고객 셀프 서비스 또는 세금 신고 규칙이나 질병 및 치료에 관한 의료 정보와 같은 업계 도메인 지식에 대한 지식 기반을 갖춘 소프트웨어 제공업체일 수도 있습니다. 대화형 검색 환경은 사용자가 대화와 Q&A를 통해 정보를 탐색할 수 있는 직관적인 인터페이스를 제공합니다. 생성형 LLM은 그 자체로는 모델이 믿을 만하지만 사실과 다른 응답을 생성하는 상황인 환각에 빠지기 쉽습니다. RAG는 일반적으로 벡터 인코딩된 지식 문서로 채워진 벡터 데이터베이스를 사용하여 구축된 외부 지식 베이스로 생성형 LLM을 보완함으로써 이 문제를 해결합니다.
RAG 와 관련하여 “Amazon Bedrock과 OpenSearch를 활용한 Multimodal RAG 기반 상품 검색 챗봇”에서 보다 상세한 내용을 다루고 있습니다.
Semantic Search 구성 요소
OpenSearch는 NMSLIB, FAISS, Lucene 라이브러리의 Approximate k-NN(ANN) 알고리즘을 사용하여 k-NN 검색을 강화합니다. 이러한 검색 방법은 대규모 데이터 세트의 검색 지연 시간을 개선하기 위해 ANN을 사용합니다. k-NN 플러그인이 제공하는 세 가지 검색 방법 중 이 방법은 대규모 데이터 세트에 가장 적합한 검색 확장성을 제공합니다. 엔진 세부 사항은 다음과 같습니다.
- Non-Metric Space Library(NMSLIB) – NMSLIB는 HNSW 알고리즘을 구현합니다.
- Facebook AI Similarity Search (FAISS) – FAISS는 HNSW 및 IVF 알고리즘을 모두 구현합니다.
- Lucene – Lucene은 HNSW 알고리즘을 구현합니다.
Approximate k-NN 검색에 사용되는 세 가지 엔진은 각각 주어진 상황에서 다른 엔진보다 사용하기에 더 합리적인 고유한 속성을 가지고 있습니다. 이 섹션의 일반적인 정보를 참고하여 요구 사항을 가장 잘 충족하는 엔진을 결정할 수 있습니다.
일반적으로 대규모 사용 사례에는 NMSLIB와 FAISS를 선택해야 합니다. Lucene은 소규모 배포에 적합한 옵션이지만 상황에 따라 최적의 필터링 전략(사전 필터링, 사후 필터링 또는 정확한 k-NN)이 자동으로 적용되는 스마트 필터링과 같은 이점을 제공합니다. 다음 표에는 각 옵션 간의 차이점이 요약되어 있습니다.
NMSLIB-HNW | FAISS-HNSW | FAISS-IVF | Lucene-HNSW | |
최대 차원 | 16,000 | 16,000 | 16,000 | 16,000 |
지원 가능한 필터 | Post-filter | Post-filter/Efficient filtering | Post-filter/Efficient filtering | Pre/Post-filters |
Training 필요 여부 | 불필요 | 불필요 | 필요 | 불필요 |
유사도 알고리즘 | l2, innerproduct, cosinesimil, l1, linf | l2, innerproduct | l2, innerproduct | l2, cosinesimil, innerproduct |
벡터 볼륨 | 수백억 | 수백억 | 수백억 | 천만 단위 |
색인 지연 시간 | 낮음 | 낮음 | 최저 | 낮음 |
쿼리 지연 시간 및 품질 | 짧은 지연시간 및 높은 품질 | 짧은 지연 시간 및 높은 품질 | 짧은 지연시간 및 낮은 품질 | 높은 지연 시간 및 높은 품질 |
벡터 압축 기법 | Flat | FlatProduct Quantization, Scalar Quantization(fp_16) | FlatProduct Quantization, Scalar Quantization(fp_16) | Flat,Scalar Quantization(int8/byte) |
메모리 소비량 | 높음 | 높으나 PQ를 사용하는 경우 낮아질 수 있음 | 중간이나 PQ를 사용하는경우 낮아질 수 있음 | 높으나 SQ를 사용하는 경우 낮아질 수 있음 |
Approximate 와 Exact K-NN 검색
OpenSearch Service k-NN 플러그인은 벡터 인덱스에서 k-nearest neighbors를 구하는 세 가지 방법을 제공합니다. Approximate k-NN, score script (exact k-NN)그리고 painless extensions (exact k-NN)입니다.
Approximate k-NN
첫 번째 방법은 근사 최인접 이웃 접근법을 사용하는데, 여러 알고리즘 중 하나를 사용해 쿼리 벡터에 근사 k-nearest neighbors를 반환합니다. 일반적으로 이러한 알고리즘은 지연 시간 단축, 더 작은 메모리 사용량, 더 확장 가능한 검색과 같은 성능상의 이점을 제공하는 대신 색인 속도와 검색 정확도를 희생합니다. Approximate k-NN은 짧은 지연 시간이 필요한 대규모 인덱스(즉, 수십만 개 이상의 벡터)에 대한 검색에 가장 적합한 선택입니다.
k-NN 검색시 인덱스에 필터를 적용하여 검색할 벡터의 수를 크게 줄이려는 경우에는 Efficient Filter를 사용할 수 있습니다. 이 기능은 HNSW를 사용하는 Lucene과 Faiss엔진에서만 사용이 가능합니다.
Exact k-NN (Score script)
Scoring script는 이진 객체를 나타낼 수 있는 knn_vector
필드 또는 필드에 대해 Exact k-NN 검색을 실행하는 것입니다. 이 접근 방식을 사용하면 인덱스의 벡터 하위 집합에 대해 k-NN 검색을 실행할 수 있습니다(pre-filter 검색 이라고도 합니다). 이 접근 방식은 작은 문서 본문에 대한 검색이나 pre-filter가 필요한 경우에 선호됩니다. 대규모 인덱스에 이 접근 방식을 사용하면 지연 시간이 길어질 수 있습니다.
Exact k-NN (Painless extensions)
세 번째 방법은 거리 함수를 더 복잡한 조합에 사용할 수 있는 간편한 확장으로 추가합니다. k-NN Scoring script와 마찬가지로 이 방법을 사용하여 인덱스의 각 벡터를 서로 대입하여 비교하는 Exact k-NN 검색을 수행할 수 있으며, Pre-filter도 함께 지원합니다. 이 접근 방식은 k-NN Scoring script에 비해 쿼리 성능이 약간 느립니다. 사용 사례에서 최종 점수에 대해 더 많은 사용자 지정 조절이 필요한 경우, Scoring script k-NN보다 이 접근 방식을 사용하는 것이 좋습니다.
벡터 검색 알고리즘
유사한 벡터를 찾는 간단한 방법은 쿼리 벡터와 벡터 데이터베이스의 다른 벡터 사이의 거리를 계산하는 k-NN(k-nearest neighbors) 알고리즘을 사용하는 것입니다. 앞서 언급했듯이, Score script k-NN과 Painless extensions 검색 방법은 내부적으로 Exact k-NN 알고리즘을 사용합니다. 그러나 차원이 매우 큰 데이터 세트의 경우, 이는 검색의 효율성을 떨어뜨리는 확장 문제를 일으킵니다. 근사 Approximate k-NN,(ANN) 검색 방법은 인덱스를 보다 효율적으로 재구성하고 검색 가능한 벡터의 차원을 줄이는 도구를 사용하여 이 문제를 극복할 수 있습니다.
지역 민감 해싱, 트리 기반, 클러스터 기반, 그래프 기반 등 다양한 ANN 검색 알고리즘이 있습니다. OpenSearch는 Hierarchical Navigable Small World(HNSW)와 Inverted file system(IVF)이라는 두 가지 ANN 알고리즘을 구현합니다. OpenSearch에서 HNSW 및 IVF 알고리즘이 어떻게 작동하는지에 대한 자세한 설명은 블로그 게시물 “OpenSearch에서 수십억 규모 검색을 위한 적합한 k-NN 알고리즘을 선택하기“을 참고하시기 바랍니다.
HNSW
HNSW 알고리즘은 인공 신경망 검색에 가장 많이 사용되는 알고리즘 중 하나입니다. 이 알고리즘의 핵심 아이디어는 서로 가까운 인덱스 벡터를 연결하는 가장자리가 있는 그래프를 구축하는 것입니다. 그런 다음 검색 시 이 그래프를 부분적으로 탐색하여 쿼리 벡터에 가장 가까운 이웃을 찾습니다. 쿼리의 가장 가까운 이웃을 향해 탐색을 진행하기 위해 알고리즘은 항상 쿼리 벡터에 가장 가까운 후보를 다음으로 방문합니다.
각 벡터는 계층구조로 추상화 되어 있으며 맨 하단에 있는 계층에는 전체 벡터가 배치됩니다.
IVF
IVF 알고리즘은 인덱스 벡터를 버킷 집합으로 분리한 다음, 검색 시간을 줄이기 위해 이러한 버킷의 하위 집합만 검색합니다. 그러나 알고리즘이 벡터를 무작위로 여러 버킷으로 분할하고 그 하위 집합만 검색하면 근사값이 좋지 않습니다. 따라서, IVF 알고리즘은 보다 개선된 접근 방식을 사용합니다. 먼저, 인덱싱을 시작하기 전에 각 버킷에 대표 벡터를 할당합니다. 벡터가 색인되면 가장 가까운 대표 벡터를 가진 버킷에 추가됩니다. 이렇게 하면 서로 더 가까운 벡터는 대략 같은 버킷이나 가까운 버킷에 배치됩니다.
이러한 버킷 배치를 위하여 IVF 알고리즘을 사용하는 경우 학습이 필요합니다.
벡터 유사도 알고리즘
모든 검색 엔진은 검색 키워드와 도큐먼트의 유사도를 비교하는 알고리즘을 사용하여 결과의 순위를 매기고 정렬하여 가장 관련성이 높은 결과를 맨 위에 표시합니다. 일반 텍스트 쿼리를 사용하는 경우 유사도 알고리즘으로 BM25를 사용합니다. BM25는 쿼리에서 각 Term(단어)의 중요도를 측정하고 텍스트 일치 횟수를 기준으로 점수를 생성합니다. 쿼리에 벡터가 포함된 경우, 유사도 알고리즘은 벡터 공간에서의 근접성을 활용하는 공간적 성격을 띱니다. OpenSearch는 아래의 유사도 알고리즘을 지원합니다.
- L1(맨해튼 거리)
- 모든 벡터 구성 요소의 차이 합계 입니다. 시가지 거리 알고리즘이라고도 하며 출발지부터 도착지까지의 직교하는 블록의 수를 측정합니다.
- 단점: 고차원에서 성능이 저하가 발생할 수 있습니다.
- L2(유클리드 거리)
- 두 점 간의 직선 거리입니다.
- L-infinity(최대 거리)
- n차원 체스판에서 왕이 움직일 수 있는 수를 의미합니다. 다른 차원의 정보를 무시한다는 특성을 가지고 있습니다.
- Cosine similarity(코사인 유사도)
- 벡터 공간에서 두 벡터 사이의 각도에 대한 코사인입니다.
- Inner product(백터 내적)
- 두 벡터의 크기와 그 사이의 각도의 코사인의 곱입니다. 일반적으로 자연어 처리(NLP) 벡터 유사도에 사용됩니다.
벡터의 유사도 알고리즘과 OpenSearch의 검색 관점에서의 Scoring 척도는 차이가 있습니다. K-NN 관점에서는 더 낮은 점수는 더 가까운 거리를 뜻하며 이는 더 나은 검색결과를 가져옵니다. 반대로 OpenSearch에서는 점수가 더 높을 수록 더 나은 결과를 가져옵니다. 따라서 OpenSearch는 해당 검색 결과를 1/(1+거리)
식을 통해 OpenSearch에 맞는 Score로 치환하여 정렬합니다.
K-NN 검색에서 고려해야할 라이브러리와 벡터 검색 알고리즘, 유사도 알고리즘에 대해 알아 보았습니다. knn_vector
필드는 이러한 구성요소를 보다 세밀하게 조정하기 위한 많은 옵션이 있습니다. 이와 관련하여 OpenSearch 에서는 knn_vector의 method를 보다 알맞게 조정하기 위한 가이드를 제공하고 있습니다. 또한 Semantic 검색시 유용하게 사용할수 있는 알고리즘별 벤치마크에 대한 글도 있으니 참고하시기 바랍니다.
Hybrid Search
OpenSearch 서비스를 벡터 데이터베이스로 사용하면 사용성, 확장성, 가용성, 상호 운용성 및 보안과 같은 서비스의 기능을 활용할 수 있습니다. 하지만, 벡터 검색만으로 해결할 수 없는 여러 문제가 있습니다. 예를 들어 지구 최대의 정글인 ‘Amazon’에 대한 정보를 찾기 위하여 amazon을Semantic 검색 하는 경우 잘못된 추론으로 amazon.com의 정보가 제공될 수 있습니다. 이러한 잘못된 추론으로 인한 검색 품질 저하를 막기 위해, OpenSearch의 Hybrid Query 기능을 활용하여 Sementic Search와 Lexical Search를 함께 사용할 수 있습니다.
다음 ‘Amazon OpenSearch Service Hybrid Query를 통한 검색 기능 강화’ 에서 Hybrid Search를 사용하는 방법에 대하여 자세하게 다루고 있습니다.
추천 엔진
검색 엔진에서 사용되는 BM25 알고리즘과 K-NN 알고리즘은 각각 키워드를 통한 문서에 관련성 점수를 할당하거나 벡터를 활용한 유사도를 측정하여 관련 문서를 찾습니다. 하지만, 이 두 알고리즘 모두 클릭률이나 구매 데이터와 같은 사용자 행동은 고려하지 않습니다.
OpenSearch의 Learning to Rank(LTR)를 사용하여 사용자 클릭 행동 데이터를 검색 애플리케이션에 통합하고 검색 관련성을 개선할 수 있습니다. LTR은 XGBoost 또는 Ranklib 라이브러리를 통해 사용자 데이터를 학습하여 검색 순위를 각 사용자에 맞게 재 조정할 수 있습니다. “Learn-to-Rank with OpenSearch and Metarank” 에서 LTR 구성에대한 자세한 내용을 다루고 있습니다.
LTR의 경우는 모델 학습에 대한 사전 지식이 필요합니다. 따라서, 사전에 ML에 대한 지식이 없다면 개인화 추천 검색을 구현하기가 매우 어렵습니다. OpenSearch Services는 Amazon Personalize와 통합하여 보다 손쉽게 개인화 추천 검색 시스템을 구성할 수 있습니다. “Amazon Personalize와 Amazon OpenSearch Service를 사용한 AI기반 개인화 검색 구현하기” 에서 자세한 내용을 다루고 있으니 참고하시기 바랍니다.
결론
지금까지 Amazon OpenSearch Service의 다양한 검색 기능에 대하여 알아 보았습니다. OpenSearch는 생셩형 AI의 RAG로서의 활용을하던 이커머스의 상품 검색, 논문, 특허, 제품가이드등 다양한 검색을 기반으로 하는 어플리케이션 에서 유연하게 동작할 수 있는 훌륭한 도구입니다. 또한, 검색 품질을 강화 하기 위한 다양한 엔진, 알고리즘을 제공하며 짧은 지연시간으로 특정 사용자가 원하는 데이터를 소위 찰떡같이 찾아낼수 있는 개인화 추천또한 여러 AWS의 서비스와 통합하여 손쉽게 구성할 수 있습니다. OpenSearch로 여러분들의 검색 서비스에 날개를 달아 보시기 바랍니다.