PostgreSQL로 검색 기능 향상: 표준에서 시맨틱까지

Ajit Gadge 2024년 4월 25일 저는 디지털 세계에서 “검색”이라는 주제에 항상 매료됩니다. 데이터를 텍스트로 바라볼 때, 저는 텍스트가 다른 데이터(예: 숫자는 측정과 계산을 위해 태어난 데이터 ☺)와 비교해 검색을 위해 태어난 데이터라고 항상 믿습니다 ☺. 디지털 시대에 방대한 양의 텍스트 데이터를 효율적이고 효과적으로 분류하는 능력은 매우 중요합니다. PostgreSQL은 강력한 오픈소스 관계형 데이터베이스로, 간단한 패턴 매칭에서 언어 기반 검색, 더 복잡한 시맨틱 검색 이해에 이르기까지 다양한 검색 기능을 제공합니다. 이 글에서는 “PostgreSQL & 벡터”와 관련된 기사를 검색하는 예를 통해 표준 검색, 풀 텍스트 검색, 시맨틱 검색 방법의 차이점, 사용 사례, 내부 작동 방식을 탐구합니다. 몇 가지 예를 통해 이를 이해해 봅시다. 제가 준비한 예제 데이터는 몇 개의 기사에서 가져온 텍스트를 열(column)로 PostgreSQL에 삽입한 것입니다. 이후에는 PostgreSQL의 tsvector 기능을 활용해 풀 텍스트 검색을 생성하고, pgvector를 사용하여 벡터 임베딩을 기반으로 한 시맨틱 검색을 구현할 것입니다. 다음은 제가 준비한 샘플 데이터입니다. PostgreSQL 테이블에 여섯 개의 기사를 삽입했습니다. 이 데이터를 가지고 검색을 해보겠습니다.


LIKE 연산자를 사용한 표준 검색

사용 사례

표준 검색은 정확히 일치하거나 부분적으로 일치하는 항목을 찾는 간단한 쿼리에 적합합니다. 예를 들어, 특정 열에서 특정 단어를 검색하거나 특정 단어로 데이터를 필터링할 때 유용합니다. 위 데이터를 기반으로 한 예제는 다음과 같습니다.

예제: “PostgreSQL”

“PostgreSQL”이라는 단어가 포함된 기사를 찾고 싶다고 상상해 보세요. 단일 단어 검색에서는 정말 매끄럽게 작동합니다. 하지만 이제 두 단어와 그에 따른 맥락이 포함된 검색을 한다고 가정해봅시다. 예를 들어, **”PostgreSQL & vector”**라는 단어를 포함한 기사를 찾고 싶다고 해볼까요? 그럼 한번 시도해 보겠습니다. “PostgreSQL & vector”를 검색하려 했지만 결과가 없습니다. 단일 단어 검색에는 적합했던 방식이 두 단어 이상의 검색과 그들 간의 맥락을 다루는 데는 부족한 점이 있음을 알 수 있습니다.


LIKE 연산자의 작동 방식

LIKE 연산자는 각 행의 데이터를 지정된 패턴과 비교합니다. 이 패턴은 **와일드카드(%)**를 포함할 수 있습니다.

  • 기본적으로 B-트리 인덱스가 사용되며, 접두사나 접미사가 있는 검색의 성능을 개선할 수 있습니다.
  • 하지만 중간 매칭(예: "%PostgreSQL%")이 필요한 경우에는 B-트리의 효율이 떨어집니다.

PostgreSQL의 확장 기능 중 하나인 pg_trgm은 이러한 한계를 극복하도록 설계되었으며, 유사 검색을 수행하거나 풀 텍스트 검색과 유사한 검색 작업을 지원합니다. 이를 위해 PostgreSQL에서는 GIN 인덱스를 사용하여 텍스트 기반 검색의 성능을 향상시킵니다.


풀 텍스트 검색(tsvector 및 tsquery 사용)

풀 텍스트 검색은 대규모 텍스트 데이터에서 세밀한 검색 기능을 제공하며, 콘텐츠 중심 애플리케이션(예: 문서 라이브러리, 기사 저장소)에 필수적입니다.

사용 사례

  • 방대한 텍스트 볼륨에서 중요한 정보를 찾아야 하는 경우
  • 문서, 기사와 같은 텍스트 기반 데이터를 다룰 때
  • 보다 정교하고 맥락 기반 검색이 필요한 상황에서

예제: “PostgreSQL & vector”

이제 풀 텍스트 검색을 사용해 위와 같은 두 단어와 맥락이 포함된 검색을 수행해 보겠습니다.

  1. 새로운 컬럼 추가 풀 텍스트 검색을 수행하기 전에, tsvector 데이터 유형으로 구성된 새로운 컬럼 textsearchable_index_col을 추가해야 합니다.
  2. 데이터 변환 새로운 컬럼을 기존 데이터(예: title, body 열)를 기반으로 **렉셈(lexemes, 토큰)**으로 변환합니다.
    • 이 작업은 매번 수동으로 업데이트할 필요 없이 트리거를 설정해 자동화할 수도 있습니다.
  3. GIN 인덱스 생성 데이터 세트가 크고 복잡한 경우를 대비해, GIN 인덱스를 생성합니다. GIN 인덱스는 풀 텍스트 검색에 최적화되어 있어 대량의 텍스트 데이터에서 검색 성능을 크게 향상시킵니다.

추가된 데이터 모습

변환 및 인덱스 추가 후, 데이터는 다음과 같은 형태를 가집니다. 이제 “PostgreSQL & vector”라는 문구로 검색을 시도할 준비가 되었습니다. 다음 섹션에서는 풀 텍스트 검색 결과를 확인하고, 이 방식이 표준 검색보다 어떤 점에서 더 나은지 살펴보겠습니다! 다음은 제가 추가한 데이터의 모습입니다. 이제 PostgreSQL의 풀 텍스트 검색 방법을 사용하여 **”PostgreSQL & vector”**라는 구문을 검색해보겠습니다. 이 방법은 훨씬 정교합니다. “PostgreSQL & vector”를 언급하는 기사를 찾아내는데, 단어의 순서나 위치에 관계없이 검색할 수 있습니다. 또한 언어 분석을 활용하여 더 관련성 높은 결과를 제공합니다.


작동 방식

PostgreSQL의 풀 텍스트 검색은 텍스트를 tsvector를 사용해 **렉셈(lexeme, 토큰)**으로 분해하고, 이를 tsquery와 비교합니다. 역방향 인덱스는 문서 내 단어의 발생 위치를 매핑하여 효율적이고 복잡한 검색을 가능하게 합니다. PostgreSQL의 특수 인덱스인 **GIN(역방향 인덱스)**은 tsvector 기반의 풀 텍스트 쿼리 속도를 향상시키는 데 도움을 줍니다.  

 

pgvector를 사용한 시맨틱 검색

사용 사례

시맨틱 검색은 텍스트의 의도의미를 이해하는 것이 중요한 응용 프로그램(예: 추천 엔진, 고급 콘텐츠 검색 플랫폼)에서 뛰어난 성능을 발휘합니다. 이러한 이유로 **생성형 AI(GenAI)**가 도입되었으며, 많은 새로운 애플리케이션이 이와 같은 유사성 검색을 기반으로 만들어지고 있습니다.

예제: “PostgreSQL & vector”

시맨틱 검색을 수행하려면 PostgreSQL에서 사용할 수 있는 pgvector 확장 기능을 이용해 기사 데이터를 벡터 데이터 타입으로 임베딩해야 합니다. 이 작업에는 Python 프로그램을 사용해 데이터를 임베딩해야 하며, 저는 Hugging Face의 오픈소스 라이브러리를 사용했습니다. 사용한 모델은 **SentenceTransformer(‘all-MiniLM-L6-v2’)**입니다. 전체 Python 코드는 제 GitHub에서 확인할 수 있습니다.

시맨틱 검색의 작동 방식

시맨틱 검색을 통해 유사한 기사를 찾으려면, 각 기사 간의 벡터 유사도를 계산해야 합니다. 이 과정은 문서 간 의미적 연관성을 파악하고, 관련된 콘텐츠를 효과적으로 찾을 수 있도록 돕습니다. 위 쿼리는 유클리드(<->)를 사용하여 가장 가까운 기사를 제공합니다. 코사인 유사도(<=>)나 내적 유사도(<#>), 그리고 기타 연산자를 사용할 수도 있습니다. 코사인 유사도는 다차원 공간에서 두 벡터 간 각도의 코사인을 측정하는 방식이고, 유클리드 거리(Euclidean Distance)는 두 점(벡터) 사이의 직선 거리를 측정합니다. 내적 유사도(Inner Product Similarity)는 두 벡터의 내적(Dot Product)을 기반으로 유사도를 측정합니다. 그러나 “PostgreSQL & vector”라는 텍스트를 찾으려면, 이 검색/입력 데이터를 벡터로 변환한 뒤 저장된 벡터들과 입력 벡터를 매칭해야 합니다. 아래는 이를 Python 코드로 구현한 검색 예제입니다. “PostgreSQL”와 “vector”와 같은 단어를 문맥에 따라 유사한 기사들을 쉽게 구분할 수 있습니다. 이는 유사성 검색(similarity search)의 작동 원리이며, AI 모델을 사용한 다양한 활용 사례에 적용할 수 있습니다.

결론

PostgreSQL의 표준 검색에서 시맨틱 검색으로의 진화는 개발자들에게 정교한 검색 기능을 구현할 강력한 도구를 제공합니다. PostgreSQL은 단순한 표준 검색에서부터 pgvector를 활용한 심층적 의미 이해에 이르기까지 폭넓은 검색 요구 사항을 충족합니다. “PostgreSQL & vector”와 관련된 기사를 찾는 과정에서, 각 방법이 다른 시나리오에 적합하다는 것을 확인하며, 사용자 경험을 향상시키고 애플리케이션 요구 사항을 효과적으로 충족하기 위해 적합한 접근 방식을 선택하는 것이 중요함을 알 수 있었습니다. 아래는 각 방법을 언제 사용해야 하고, 언제 사용하지 말아야 하는지에 대한 정리입니다.

표준 검색

장점
  • 단순성: LIKE 연산자는 간단하고 이해하기 쉽습니다.
  • 기본 패턴 매칭: %_ 와일드카드를 사용하여 텍스트 데이터에서 패턴을 매칭할 수 있습니다.
단점
  • 성능: LIKE 쿼리는 대규모 데이터셋에서 느릴 수 있으며, 종종 전체 테이블 스캔이 필요합니다.
  • 기능 제한: 언어 분석, 어근 분석(stemming), 그리고 관련성 순위 지정과 같은 기능이 부족합니다.
  • 인덱싱 제한: 텍스트 열에 인덱스를 추가하더라도 와일드카드 검색에서는 성능 향상이 미미할 수 있습니다.
사용 시점
  • 간단한 패턴 매칭이 필요하거나 전체 텍스트 검색 기능이 필요하지 않을 때.
  • 데이터셋이 작거나 성능이 큰 문제가 되지 않을 때.

전체 텍스트 검색 (tsvector 활용)

장점
  • 빠르고 효율적: 전체 텍스트 검색은 대규모 텍스트 데이터를 검색할 때 최적화되어 있으며, LIKE 쿼리보다 더 빠른 결과를 제공합니다.
  • 언어 분석 지원: 어근 분석, 순위 지정, 언어 분석 등을 지원하여 더 정확하고 관련성 높은 검색 결과를 제공합니다.
  • 인덱스 지원: GIN 인덱스와 tsvector를 활용하면 복잡한 쿼리에 대해 검색 성능이 크게 향상됩니다.
단점
  • 학습 곡선: tsvector 데이터 타입 및 GIN/GIST 인덱스를 구성하고 사용하는 방법을 이해해야 합니다.
  • 설정 부담: 초기 설정과 전체 텍스트 검색 인덱싱 구성은 표준 검색보다 더 많은 노력이 필요합니다.
사용 시점
  • 대규모 문서 검색이나 관련성 순위 지정이 필요한 고급 검색 기능이 요구되는 애플리케이션.
  • 대규모 텍스트 데이터를 검색할 때 성능이 중요한 경우.

시맨틱 검색 (pgvector 활용)

장점
  • 향상된 관련성: 코사인 유사도 또는 유클리드 거리를 활용한 시맨틱 검색은 기본 텍스트 매칭보다 정교한 관련성 순위를 제공합니다.
  • 유사도 매칭: 텍스트 조각 간 유사성 기반 검색이 가능하며, 맞춤법 검사, 자동 완성, 추천 시스템 등의 애플리케이션에 유용합니다.
  • 문맥 기반 검색: 챗봇과 같은 문맥 기반 애플리케이션에서 효과적입니다.
단점
  • 복잡성: 시맨틱 검색은 표준 검색이나 전체 텍스트 검색보다 더 많은 노력과 전문 지식이 필요할 수 있습니다.
  • 자원 소모: 대규모 데이터셋에서 유사도 점수를 계산하는 것은 자원을 많이 소모하며, 성능에 영향을 미칠 수 있습니다.
사용 시점
  • 텍스트 데이터 기반의 정밀한 유사도 매칭이나 추천 시스템이 필요한 애플리케이션.
  • 검색 결과의 시맨틱 유사성 기반 관련성 순위가 중요한 경우.
  • RAG(검색-생성)과 같은 머신러닝 모델과 문맥 기반 검색을 구현할 때.
본문: Enhancing Search Capabilities with PostgreSQL: From Standard to Semantic.
EDB 영업 기술 문의: 02-501-5113
홈페이지 문의: https://www.enterprisedb.com/contact_kr