- Published on
[Django] 풀텍스트 서치를 만들자
- Authors
- Name
- Almer Minified
[Django] Vector를 이용한 풀텍스트 서치 구현
Search Vector를 이용해서 풀텍스트 서치를 만들자
장고에서 기본적인 검색 기능은 몇 가지로 나뉜다. 그 중 많이 쓰는 것이 icontains 혹은 contains필터를 쓰는 것이고 그 다음이 startswith필터를 쓰는 방법이 있을 것이다. 혹은 해시 태그를 이용해 equal연산을 이용해서 검색결과를 반환하는 방법도 있다. 인스타그램이 그렇게 하는 것처럼 말이다. 하지만 이 모든 기능이 부족할 수 있다. 특히 데이터의 수가 많아질수록 contains나 icontains의 부하는 훨씬 커진다. 테이블을 다 순회하며 모든 행을 다 읽어야 하니까 성능이 떨어진다. 이 문제를 해결하기 위해 몇 데이터베이스는 풀텍스트 서치를 제공한다. 풀텍스트 서치를 쓰면 성능을 크게 향상시킬 수 있다.
풀텍스트 서치란?
풀텍스트 서치는 대규모 데이터베이스에서 빠르게 검색할 수 있는 기술이다. 이 기술은 특히 텍스트에 유용한데 풀텍스트검색은 인덱싱을 어떤 문장에서 단어들을 추출해서 직접 따로 인덱싱한다. 그러니까 /안녕하세요 /나는 /누구야 라고 한다면 안녕하세요, 안녕, 나는, 누구야 이런 단어들을 따로 인덱싱한다는 뜻이다. 그렇기떄문에 인덱싱에서 한번 검색하고 데이터를 찾아내게 되기 떄문에 빨라지는 것이다. 또한 내부적으로 랭킹을 매긴다. 내부 알고리즘에 의해 검색어랑 원래 데이터랑 관련성을 비교한다. 그 기준으론 빈도수, 문서 내 어디에 위치하는지, 쿼리와 얼마나 일치하는지 등이 있다. 게다가 의미없는 조사들, 영어로 치면 is, at, the, 같은 것들은 나름 처리해서 의도적으로 인덱싱에서 제외시킬 수도 있다.
장고에서 풀텍스트 서치를 구현하는 방법
우선 데이터베이스가 풀텍스트서치를 지원하는지 확인해야한다. django4 에 2023년 11월 기준으론 postgresql이 풀텍스트 서치를 지원한다. 본 글은 django4, postgresql 기준으로 작성할 것이다.
모델 필드 코드 변경
풀텍스트 서치를 할 필드를 결정한다.
class PostTitle(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE )
title = models.TextField(max_length=1000)
search_vector = SearchVectorField(null=True) # 이 줄이 중요
search_vector가 중요한데 이 부분을 추가해주면 postgresql내부적으로 풀텍스트 서치를 위한 인덱스를 생성하고 거기에 데이터를 저장한다. 만약 데이터가저장되어있지 않다면 또 세이브를 재차 해주거나 처리해줘야한다.
모델 검색 코드 변경
풀텍스트 서치를 위한 필드를 생성했으니 이제 뷰를 처리하면된다.
PostTitle.objects.annotate(
search=SearchVector('title'),
).filter(search=query)
이제 search에다가 SearchVector를 이용해서 필드명을 title로 넣어서 처리할 수 있게 된다. 그 다음에 filter(search=query)로 바꾸면된다. 간단하게 마무리되었다.
풀텍스트 서치 원리
풀텍스트 서치를 하려고 하게 되면 이제 데이터베이스가 내부적으로 토크나이징, 정규화, 인덱싱을 처리한다. 토크나이징은 어떤 텍스트를 아까 말한 것처럼 여러가지 조각으로 나누는 것이다. 토큰화라고 표현하겠다. 토큰화를 할때 그 기준을 직접 정할 수도 있다. 주로 띄어쓰기 위주로 되는 것같다. 스페이스 위주라고 해야할까 공백 위주이다. 그 다음에 단어를 정규화하는 경우가 있다. 한글에서는 많이 발생하지 않는 것같지만 영어일 경우에 running을 run으로 저장한다던지 하는 작업이 실행될 수 있다. 이것도 설정가능하다. 그 다음에 indexing작업인데 기본적으로 다들 알고 있는 그런 인덱싱 작업이라고 생각할 수있다.
성능 차이
풀텍스트 서치를 하려고 한다면 데이터가 많을수록 그게 크게 체감됨을 알 수 있다. 간단한 예시로 10000개의 글을 검색할 때 5초가 걸린다면 풀텍스트서치를 적용하면 0.1초까지 속도를 줄일 수 있다고 생각하면 된다.