본문 바로가기

portfolio

Django + Postgresql (트라이그램 유사성을 이용하여 유사한단어 검색하기)

예를들어 내용검색 중 검색 단어를 "리눅스 명"을 오타로 "리늑스 명"이라고 검색하면 "리눅스 명"과 "리늑스 명"은 유사한 단어이지만, 하나의 글자만 다르기 때문에 트라이그램은 세 개의 유사한 연속된 문자열을 찾을 수 있다. 예를 들어, "리눅스 명"은 '리눅', '눅스', '스 명'과 같은 트라이그램을 가지며, "리늑스 명"도 '리늑', '늑스', '스 명'과 같은 트라이그램을 가진다.
 
 
 
1. form.py
 

# 검색을 위해 검색 form을 만든다
class SearchForm(forms.Form):
  query = forms.CharField()

 
 
 
2. view.py
 

# 검색 요청 view
def post_search(request):
    form = SearchForm()
    # 쿼리와 결과는 처음에 빈값으로 함
    query = None
    results = []

    if 'query' in request.GET:
        # form태그에 GET요청
        form = SearchForm(request.GET)
        # form 데이터 유효성검사를 하고 
        if form.is_valid():
            # query변수에 유효성검사값을 넣는다.
            query = form.cleaned_data['query']
            results = Post.published.annotate(similarity = TrigramSimilarity('body', query)).filter(similarity__gt=0.1).order_by('-similarity')
          
    return render(request,'blog/post/search.html', {'form':form, 'query':query, 'results':results,})

 
annotate(similarity=TrigramSimilarity('body', query)): 이 부분은 Post.published 쿼리셋에 대해 TrigramSimilarity를 사용하여 body(내용)필드와 입력된 query의 유사성을 계산한다. 각 게시물의 유사성 값은 similarity 필드에 할당됨 
 
.filter(similarity__gt=0.1): 이 부분은 유사성 값이 0.1보다 큰 결과만 필터링 한다. 이 값은 임계값으로 설정되어, 이보다 낮은 유사성을 가진 결과는 필터링된다(0.1보다 작은값은 제외). 필터링된 결과는 results 변수에 저장
 
.order_by('-similarity'): 이 부분은 유사성 값에 따라 결과를 내림차순으로 정렬, 따라서 가장 유사성이 높은 결과가 먼저 표시된다.
 
 
 
3. templates - search.html 
 
설명은 <!----> 주석 태그 참조 

{% extends "blog/base.html" %} 
{% load blog_tags %} 
{% block title %}검색창{% endblock %} 
{% block content %}
  {% if query %}
    <h1>"{{ query }}"</h1>
    <h3>
      <!--with태그는 변수를 지정함-->
      {% with results.count as total_results %}
      <!--파이프 |pluralize를 붙이면 복수의 결과에 접미사s가 붙여짐 -->
      검색결과: {{ total_results }} result{{ total_results|pluralize }}
      {% endwith %}
    </h3>
    {% for post in results %} 
    <h4>
      <a href="{{ post.get_absolute_url }}">
        {{ post.title }}
      </a>
    </h4>
    <!--게시글 내용 12글자-->
      {{ post.body|markdown|truncatewords_html:12 }}
    {% empty %}
    <p>검색 결과가 일치하지 않습니다.</p>
    {% endfor %}
    <p><a href="{% url "blog:post_search" %}">검색하기</a></p>
  {% else %} 
    <h1>포스트 검색하기</h1>
    <form method="get">
      {{ form.as_p }}
      <input type="submit" value="Search">
    </form>
  {% endif %}
{% endblock %}

 
 
 
4. 결과 화면 

 
파이프가 붙여진 pluralize태그는 게시글이 하나라서 result에 접미사s가 붙여지지 않는다 게시글이 여러개이면 접미사s가 붙여져서 results가 된다.

 

 

참고한 책입니다.

https://www.yes24.com/Product/Goods/125101496

 

예제로 배우는 Django 4 - 예스24

Django 연습에 최적! 프로젝트 4개로 배우는 Django 4Django를 익히는 제일 좋은 방법은 무엇일까? 이 책에서는 ‘좋은 예제 많이 만들어 보기’를 그 답으로 정했다. 블로그, 소셜 웹사이트, 온라인 상

www.yes24.com