PostgreSQL과 함께 Swift 검색 환경 구축하기
Wenhao Wang
Dev Intern · Leapcell

서론
오늘날 빠르게 변화하는 디지털 세상에서 사용자들은 정보를 빠르고 쉽게 찾을 수 있기를 기대합니다. 상당한 양의 콘텐츠를 보유한 모든 웹사이트에서 강력하고 반응적인 검색 기능은 단순히 있으면 좋은 것이 아니라 기본적인 필수 요소입니다. Elasticsearch와 같은 독립형 검색 엔진부터 클라우드 기반 서비스에 이르기까지 다양한 정교한 검색 솔루션이 존재하지만, 검색 기능을 통합하는 것은 종종 추가 인프라와 전문 지식이 필요한 어려운 작업처럼 보입니다. 그러나 이미 PostgreSQL을 기본 데이터 저장소로 사용하고 있는 애플리케이션의 경우, 강력하고 종종 간과되는 솔루션이 바로 가까이에 있습니다. 바로 PostgreSQL에 내장된 전문 검색 기능입니다. 이 글에서는 이 네이티브의 힘을 활용하여 웹사이트에 효과적인 검색 기능을 구현하고, 스택을 간소화하며 배포를 단순화하는 방법을 안내합니다.
핵심 개념 이해하기
실제 구현에 들어가기 전에 PostgreSQL의 전문 검색의 기반을 형성하는 몇 가지 필수 용어를 이해해 봅시다.
- 전문 검색(Full-Text Search, FTS): 정확한 부분 문자열을 일치시키는 간단한
LIKE
쿼리와 달리, FTS는 언어적 뉘앙스, 동의어, 스테밍(단어를 기본 형태로 줄임), 관련성 순위를 고려하여 대량의 텍스트를 검색하도록 설계되었습니다. TSVECTOR
: 이것은 전문 검색에 최적화된 문서를 저장하는 PostgreSQL의 특수 데이터 유형입니다. 텍스트가TSVECTOR
로 변환되면 구문 분석, 정규화(예: 소문자로 변환), 스테밍 및 불용어(예: "the", "a", "is"와 같은 일반적인 단어) 제거가 수행됩니다. 각 나머지 단어는 원본 문서 내의 해당 위치와 연결됩니다.TSQUERY
: 이 데이터 유형은 전문 검색 쿼리를 나타냅니다. AND (&
), OR (|
), NOT (!
)과 같은 고급 검색 연산자와 구문 검색 및 근접 검색을 허용합니다. 쿼리 문자열이TSQUERY
로 변환될 때TSVECTOR
와 유사한 처리 단계를 거쳐 일관된 비교를 보장합니다.- 텍스트 검색 구성(Text Search Configuration): 이것은 문서를
TSVECTOR
로 처리하고 쿼리를TSQUERY
로 처리하는 방법을 정의합니다. 구문 분석기(텍스트를 토큰으로 분해하는 방법), 사전(스테밍, 동의어 대체, 불용어 제거용) 및 정규화를 지정합니다. PostgreSQL은 여러 사전 정의된 구성(예:english
,simple
,german
)을 제공하며, 사용자 지정 구성을 만들 수도 있습니다. TO_TSVECTOR()
: 텍스트 열을TSVECTOR
데이터 유형으로 변환하는 PostgreSQL 함수입니다.TO_TSQUERY()
: 일반 텍스트 쿼리 문자열을TSQUERY
데이터 유형으로 변환하는 PostgreSQL 함수입니다.@@
연산자:TSVECTOR
가TSQUERY
와 일치하는지 확인하는 데 사용되는 "일치" 연산자입니다. 이것은 전문 검색 비교의 핵심입니다.RANK()
: 일치하는 문서의 관련성 점수를 계산하는 함수로, 결과 순위를 관련성별로 정렬할 수 있습니다.
원리와 구현
기본 원리는 간단합니다. 텍스트 콘텐츠를 TSVECTOR
형식으로 변환하고, 저장(또는 즉석에서 생성)한 다음, @@
연산자를 사용하여 사용자의 TSQUERY
를 이러한 TSVECTOR
와 비교합니다. 효율적인 검색을 위해서는 인덱스가 필수적입니다.
실제 예로 설명해 보겠습니다. articles
테이블이 있는 블로그 플랫폼을 상상해 보세요.
CREATE TABLE articles ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, author VARCHAR(100), created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); INSERT INTO articles (title, content, author) VALUES ('Getting Started with PostgreSQL Full-Text Search', 'PostgreSQL offers powerful capabilities for searching text within your database. This guide covers the basics.', 'Jane Doe'), ('Optimizing Your Database Queries', 'Learn advanced techniques to speed up your SQL queries and improve performance.', 'John Smith'), ('Understanding Relational Databases', 'A deep dive into the fundamentals of relational database design and normalization.', 'Jane Doe');
1단계: TSVECTOR
열 생성
검색 성능을 최적화하고 모든 쿼리에서 TSVECTOR
를 다시 계산하는 것을 피하기 위해 전용 TSVECTOR
열을 만들고 채우는 것이 좋습니다. 이 열은 자동으로 유지됩니다.
ALTER TABLE articles ADD COLUMN tsv TSVECTOR; -- tsv 열을 업데이트하는 함수 생성 CREATE OR REPLACE FUNCTION update_article_tsv() RETURNS TRIGGER AS $$ BEGIN NEW.tsv = TO_TSVECTOR('english', NEW.title || ' ' || NEW.content); RETURN NEW; END; $$ LANGUAGE plpgsql; -- 삽입 및 업데이트 시 tsv를 자동으로 업데이트하는 트리거 생성 CREATE TRIGGER articles_tsv_insert BEFORE INSERT ON articles FOR EACH ROW EXECUTE FUNCTION update_article_tsv(); CREATE TRIGGER articles_tsv_update BEFORE UPDATE OF title, content ON articles FOR EACH ROW EXECUTE FUNCTION update_article_tsv(); -- 기존 데이터에 대해 tsv 채우기(있는 경우) UPDATE articles SET tsv = TO_TSVECTOR('english', title || ' ' || content);
여기서는 title
과 content
를 단일 검색 가능한 문서로 연결했습니다. 'english'
를 텍스트 검색 구성으로 사용하면 영어 텍스트에 대한 적절한 스테밍 및 불용어 제거가 보장됩니다.
2단계: TSVECTOR
열 인덱싱
빠른 검색을 위해 TSVECTOR
열에 GIN(Generalized Inverted Index) 인덱스가 필수적입니다.
CREATE INDEX idx_articles_tsv ON articles USING GIN (tsv);
3단계: 검색 쿼리 수행
이제 TSVECTOR
가 준비되고 인덱싱되었으므로 일부 검색을 수행해 보겠습니다.
기본 검색:
SELECT title, content FROM articles WHERE tsv @@ TO_TSQUERY('english', 'database');
이 쿼리는 "database"의 스테밍된 형태(예: "database", "databases")를 포함하는 기사를 찾습니다.
여러 용어 검색(AND/OR):
-- AND 연산자: 'PostgreSQL'과 'query'를 모두 포함해야 합니다. SELECT title, content FROM articles WHERE tsv @@ TO_TSQUERY('english', 'PostgreSQL & query'); -- OR 연산자: 'database' 또는 'search'를 포함합니다. SELECT title, content FROM articles WHERE tsv @@ TO_TSQUERY('english', 'database | search');
구문 검색:
정확한 구문을 검색하려면 쿼리에 따옴표를 사용하고 PHRASE
TSQUERY
로 변환하세요.
SELECT title, content FROM articles WHERE tsv @@ PHRASE_TO_TSQUERY('english', 'full-text search');
검색 결과 순위 지정:
더 관련성 높은 결과를 먼저 제공하기 위해 ts_rank
또는 ts_rank_cd
를 사용할 수 있습니다. 이 함수들은 용어 빈도, 근접성, 역문서 빈도와 같은 요소를 기반으로 점수를 계산합니다.
SELECT title, ts_rank(tsv, TO_TSQUERY('english', 'PostgreSQL & search')) AS rank_score FROM articles WHERE tsv @@ TO_TSQUERY('english', 'PostgreSQL & search') ORDER BY rank_score DESC;
ts_rank_cd
는 문서 길이를 정규화하여 종종 더 나은 결과를 제공합니다.
검색어 강조 표시(스니펫 생성):
사용자 경험을 향상시키기 위해 ts_headline
을 사용하여 결과 내에서 검색어를 강조 표시할 수 있습니다.
SELECT title, ts_headline('english', content, TO_TSQUERY('english', 'database & design'), 'StartSel=<b>, StopSel=</b>') AS highlighted_content FROM articles WHERE tsv @@ TO_TSQUERY('english', 'database & design');
일치하는 용어가 <b>
태그로 둘러싸인 content
를 반환합니다.
애플리케이션 시나리오
- 블로그/기사 검색: 보여준 것처럼 사용자가 관련 기사를 찾을 수 있도록 하는 주요 사용 사례입니다.
- 제품 검색: 전자 상거래 사이트에서는 제품 이름, 설명, 카테고리에서 FTS를 사용하여 사용자가 항목을 찾도록 도울 수 있습니다.
- 문서 검색: 소프트웨어 프로젝트 또는 지식 기반의 경우 FTS를 사용하여 방대한 기술 문서를 빠르게 탐색할 수 있습니다.
- 사용자/프로필 검색: 다른 필터와 함께 FTS를 사용하면 사용자가 자신의 약력이나 관심사를 기반으로 사용자를 찾는 데 도움이 될 수 있습니다.
이 접근 방식은 검색을 기존 데이터베이스 설정에 직접 통합하여 많은 일반적인 사용 사례의 외부 검색 서비스와 관련된 복잡성과 잠재적인 오류 지점을 줄여줍니다.
결론
PostgreSQL의 네이티브 전문 검색을 활용하면 웹사이트에서 검색 기능을 구현할 수 있는 강력하고 효율적이며 놀랍도록 강력한 솔루션을 제공합니다. TSVECTOR
및 TSQUERY
를 이해하고, GIN 인덱스를 사용하고, 순위 지정 및 강조 표시를 통합함으로써 외부 도구의 오버헤드 없이 매우 성능이 뛰어나고 사용자 친화적인 검색 경험을 제공할 수 있습니다. 이를 통해 PostgreSQL 전문 검색은 다양한 애플리케이션에 훌륭한 선택이 되며, 검색 가능한 콘텐츠를 위한 견고한 기반을 제공합니다.