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”
이제 풀 텍스트 검색을 사용해 위와 같은 두 단어와 맥락이 포함된 검색을 수행해 보겠습니다.
- 새로운 컬럼 추가 풀 텍스트 검색을 수행하기 전에,
tsvector
데이터 유형으로 구성된 새로운 컬럼textsearchable_index_col
을 추가해야 합니다. - 데이터 변환 새로운 컬럼을 기존 데이터(예:
title
,body
열)를 기반으로 **렉셈(lexemes, 토큰)**으로 변환합니다.- 이 작업은 매번 수동으로 업데이트할 필요 없이 트리거를 설정해 자동화할 수도 있습니다.
- GIN 인덱스 생성 데이터 세트가 크고 복잡한 경우를 대비해, GIN 인덱스를 생성합니다. GIN 인덱스는 풀 텍스트 검색에 최적화되어 있어 대량의 텍스트 데이터에서 검색 성능을 크게 향상시킵니다.
추가된 데이터 모습
변환 및 인덱스 추가 후, 데이터는 다음과 같은 형태를 가집니다. 이제 “PostgreSQL & vector”라는 문구로 검색을 시도할 준비가 되었습니다. 다음 섹션에서는 풀 텍스트 검색 결과를 확인하고, 이 방식이 표준 검색보다 어떤 점에서 더 나은지 살펴보겠습니다! 다음은 제가 추가한 데이터의 모습입니다.
이제 PostgreSQL의 풀 텍스트 검색 방법을 사용하여 **”PostgreSQL & vector”**라는 구문을 검색해보겠습니다.
이 방법은 훨씬 정교합니다. “PostgreSQL & vector”를 언급하는 기사를 찾아내는데, 단어의 순서나 위치에 관계없이 검색할 수 있습니다. 또한 언어 분석을 활용하여 더 관련성 높은 결과를 제공합니다.
작동 방식
PostgreSQL의 풀 텍스트 검색은 텍스트를 tsvector
를 사용해 **렉셈(lexeme, 토큰)**으로 분해하고, 이를 tsquery
와 비교합니다. 역방향 인덱스는 문서 내 단어의 발생 위치를 매핑하여 효율적이고 복잡한 검색을 가능하게 합니다. PostgreSQL의 특수 인덱스인 **GIN(역방향 인덱스)**은 tsvector
기반의 풀 텍스트 쿼리 속도를 향상시키는 데 도움을 줍니다.