프로젝트/AWS winter camp - ELK&AWS 프로젝트

Elasticsearch, docker, django-elastic_dsl, rest_framework로 n-gram 검색엔진 만들기 - 1차 트러블슈팅

dayeonsheep 2024. 1. 29. 14:07

Django로 API 서버를 구축하고, Elasticsearch와 Docker를 사용하여 n-gram 검색과 `analysis-nori` 형태소 분석기를 도입

 


1. Django 프로젝트 및 앱 생성

   django-admin startproject myproject
   cd myproject
   python3 manage.py startapp search



2. Django 앱 설정
   - `settings.py` 파일에서 앱과 REST framework를 설정

   # myproject/settings.py

   INSTALLED_APPS = [
       # ...
       'rest_framework',
       'search',
   ]

   REST_FRAMEWORK = {
       'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
       'PAGE_SIZE': 10,
   }



3. Django 모델 생성
   - `models.py` 파일에 데이터 모델을 생성

   # search/models.py

   from django.db import models

   class Book(models.Model):
       title = models.CharField(max_length=255)

       def __str__(self):
           return self.title



4. Django 마이그레이션 및 데이터베이스 적용
   - 모델 변경을 적용하여 데이터베이스를 생성

python3 manage.py makemigrations
python3 manage.py migrate



5. Docker Compose 파일 작성
   - Elasticsearch를 Docker로 실행하기 위한 `docker-compose.yml` 파일을 작성

vim docker-compose.yml
 # docker-compose.yml

   version: '3'
   services:
     elasticsearch:
       image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
       environment:
         - discovery.type=single-node
       ports:
         - "9200:9200"


6. Docker Compose 실행
   - Docker Compose를 사용하여 Elasticsearch를 실행

docker-compose up

 


7. Elasticsearch Plugin 설치
   - Docker 컨테이너 내부에서 `analysis-nori` 플러그인을 설치

   ```bash
   docker exec -it [elasticsearch_container_id] /bin/bash

   # 내부에서 실행
   ./bin/elasticsearch-plugin install analysis-nori
   exit
   ```

container_id는 docker ps 명령어로 확인 가능

8. Django 앱에 n-gram 및 analysis-nori 설정 추가
   - `search` 앱 내에 `utils.py` 파일을 생성하고, Elasticsearch 색인 및 설정을 위한 코드를 추가

# search/utils.py

from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
from .models import Book

es = Elasticsearch()

def index_books():
    bulk(client=es, actions=[
        {
            '_op_type': 'index',
            '_index': 'books',
            '_id': str(book.id),
            '_source': {'title': book.title}
        }
        for book in Book.objects.all()
    ])

index_books()



9. Django REST framework Serializer 생성
   - `serializers.py` 파일에 직렬화를 위한 Serializer를 생성

# search/serializers.py

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title']



10. Django REST framework API 뷰 생성
    - `views.py` 파일에 REST framework를 사용하여 API 뷰를 생성

# search/views.py

from rest_framework import generics
from elasticsearch_dsl import Search
from .models import Book
from .serializers import BookSerializer

class BookSearchView(generics.ListAPIView):
    serializer_class = BookSerializer

    def get_queryset(self):
        q = self.request.query_params.get('q', '')
        s = Search(using='elasticsearch_dsl').query('match', title={'query': q, 'analyzer': 'ngram_analyzer'})
        response = s.execute()
        book_ids = [hit.id for hit in response]
        return Book.objects.filter(id__in=book_ids)

 

에러 : Import "elasticsearch_dsl" could not be resolved 

pip install elasticsearch-dsl

로 해결

11. Django REST framework API URL 설정
    - `urls.py` 파일에 API 뷰에 대한 URL을 설정

# search/urls.py

from django.urls import path
from .views import BookSearchView

urlpatterns = [
    path('search/', BookSearchView.as_view(), name='book-search'),
]


    - 메인 프로젝트의 `urls.py`에 앱의 URL을 포함시키기

# myproject/urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('search.urls')),
]

 

 

12. 서버 실행

python3 manage.py runserver

 

에러 : http://127.0.0.1:8000/에 접속하면 Page not found (404) 오류, Using the URLconf defined in myproject.urls, Django tried these URL patterns, in this order:

 

방법1 - url 파일들 코드 수정

# myproject/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('search.urls')),  # 예시로 search 앱의 URL 패턴을 추가
]
# search/urls.py

from django.urls import path
from .views import BookSearchView

urlpatterns = [
    path('search/', BookSearchView.as_view(), name='book-search'),
]

 

settings 에 debug도 바꿔봄

# myproject/settings.py

DEBUG = False

>> CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False. 에러

로 또 생기길래 

# myproject/settings.py

ALLOWED_HOSTS = ['localhost', '127.0.0.1']

이걸로 수정해줌

 

다시 서버 실행해도 에러!

이번에는 페이지에 Not Found The requested resource was not found on this server. 에러

로 뜸

# search/views.py

from django.views.generic import TemplateView

class BookSearchView(TemplateView):
    template_name = 'book_search.html'

 이렇게 추가해줬다 

최종 views.py 코드는

# search/views.py
from django.shortcuts import render
from django.views import View
from rest_framework import generics
from elasticsearch_dsl import Search
from .models import Book
from .serializers import BookSerializer
from django.views.generic import TemplateView

class BookSearchView(View):
    template_name = 'book_search.html'

    def get(self, request, *args, **kwargs):
        query = request.GET.get('query', '')
        results = Book.objects.filter(title__icontains=query)
        return render(request, self.template_name, {'results': results})
    
class BookSearchAPIView(generics.ListAPIView):
    serializer_class = BookSerializer

    def get_queryset(self):
        q = self.request.query_params.get('q', '')
        s = Search(using='elasticsearch_dsl').query('match', title={'query': q, 'analyzer': 'ngram_analyzer'})
        response = s.execute()
        book_ids = [hit.id for hit in response]
        return Book.objects.filter(id__in=book_ids)

요런식이 되었음

그래도 안됨

 


13. 데이터베이스에 샘플 데이터 추가
    - 책 제목 샘플 데이터를 Django 데이터베이스에 추가

python manage.py shell
#!/usr/bin/env python
#myproject/manage.py

"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

from search.models import Book

books_data = ["aws 입문", "awthe 기초", "구의 증명", "쿠우쿠우 맛있게 먹기", "노리분석기", "데이터 구축하기", "데마분 정복하기", "라쇼몬", "뉴턴의 아틀리에", "싯다르타"]

for title in books_data:
    Book.objects.create(title=title)

 

 

 

 

 

elastic search 연결 다시 해보기

from elasticsearch import Elasticsearch

# Elasticsearch에 사용자 인증 정보를 제공합니다.
es = Elasticsearch(
    ['your_elasticsearch_host'],
    http_auth=('your_username', 'your_password'),
    port=9200,
)

# 예제 쿼리
response = es.search(index='your_index_name', body={
    "query": {
        "match_all": {}
    }
})

# 결과 출력
print(response)

 

 

추가 삽질기록 및 레퍼런스


설치 삽질

 

https://velog.io/@soyeon207/ES-2.-docker-%EC%97%90%EC%84%9C-ES-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0

 

[ES] 2. docker 에서 ES 시작하기

docker 에 es 설치해보기

velog.io

yangdayeon@yangdayeon-ui-MacBookPro ~ % docker pull elasticsearch:7.9.3
7.9.3: Pulling from library/elasticsearch
75f829a71a1c: Pull complete 
2dd8aabff665: Pull complete 
fd17121b3976: Pull complete 
a19cf707b4fd: Pull complete 
4ccdd8a52dc0: Pull complete 
d018d3fc07a4: Pull complete 
70f1e3a1960a: Pull complete 
8f58f7e426fa: Pull complete 
817feb91b55c: Pull complete 
Digest: sha256:a13cd87cbf139fadbca64972ef2c8777222236887d303e4177c1ab7cff1b52f6
Status: Downloaded newer image for elasticsearch:7.9.3
docker.io/library/elasticsearch:7.9.3

yangdayeon@yangdayeon-ui-MacBookPro ~ % docker images
REPOSITORY                                                         TAG       IMAGE ID       CREATED        SIZE
925676828058.dkr.ecr.ap-northeast-2.amazonaws.com/asc-demo-repo2   latest    fa7f699ff65e   7 months ago   137MB
elasticsearch                                                      7.9.3     1ab13f928dc8   3 years ago    742MB

yangdayeon@yangdayeon-ui-MacBookPro ~ % docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --name elasticsearchTest elasticsearch:7.9.3

f32237ed21b54f18bbbecfcd2be6529561c8c8a7ddebe13662821e54eb5e7a90

yangdayeon@yangdayeon-ui-MacBookPro ~ % docker ps
CONTAINER ID   IMAGE                 COMMAND                   CREATED          STATUS          PORTS                                            NAMES
f32237ed21b5   elasticsearch:7.9.3   "/tini -- /usr/local…"   16 seconds ago   Up 15 seconds   0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   elasticsearchTest

yangdayeon@yangdayeon-ui-MacBookPro ~ % curl localhost:9200
{
  "name" : "f32237ed21b5",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "-OdxG6xrTRaDF_dKee7iyw",
  "version" : {
    "number" : "7.9.3",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "c4138e51121ef06a6404866cddc601906fe5c868",
    "build_date" : "2020-10-16T10:36:16.141335Z",
    "build_snapshot" : false,
    "lucene_version" : "8.6.2",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

f32237ed21b5

 

docker exec -it f32237ed21b5 /bin/bash

 

 

https://soyoung-new-challenge.tistory.com/77

 

[Elasticsearch] Plugin 설치 및 적용

이번 포스팅은 엘라스틱서치 플러그인 사용과 실제 검색 시 적용되는 예제에 관한 포스팅입니다. "이미지 검색에 관한 검색엔진을 만드는 데 사용하는 벡터 검색 플러그인" 1. 적용 할 플러그인

soyoung-new-challenge.tistory.com

bin/elasticsearch-plugin install file:///fast-elasticsearch-vector-scoring/target/releases/elasticsearch-binary-vector-scoring-7.5.1.zip

 

 

 

sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-nori

 

 


python - django - es 삽질

 

https://soyoung-new-challenge.tistory.com/72

 

[Elasticsearch] python에서 엘라스틱 사용하기

이번 포스팅은 파이썬에서 엘라스틱을 연결해서 데이터를 insert, delete, search 등 다양한 요청을 하는 튜토리얼입니다. 필요한 라이브러리 설치 $ pip install elasticsearch - 파이썬에서 엘라스틱을 연결

soyoung-new-challenge.tistory.com

https://python-jamo.readthedocs.io/en/latest/

 

A Guide to using Python-Jamo — jamo 0.4-beta documentation

Hangul is a modern writing system that originated in 1443 to represent the Korean language. It uses an alphabet of 24 consonants and vowels, each of which are called jamo (자모, 字母). Let’s analyze Korean phonemes by decomposing some Hangul. Using t

python-jamo.readthedocs.io


연결 삽질

 

https://blog.yevgnenll.me/elk/install-plugin-to-elastic-search-and-check-install-or-not

 

Elastic Search 에 plugin install 하기, file plugin 설치 방법, plugin 설치 확인하기

Elastic Search 에 직접 개발한 plugin 을 설치해야 하는 상황이 왔다. 매번 찾아보기 귀찮아 설치와 설치 후 제대로 설치가 된 것인지 확인하는 과정을 추가하고자 한다.

blog.yevgnenll.me

잘 설치 되는데... 

문제가 우리팀 es 계정이 아니고 

애먼 걸 연결했다는 거임. 새로파서...? 

험...

 

 

https://happiestmemories.tistory.com/45

 

[AWS] Elasticsearch 구축하기

개발중인 LectureSearch 프로젝트에서는 관계형 데이터베이스(RDBMS: mysql, oracle, mariadb)를 대신하여 검색엔진 엘라스틱서치를 이용하려 합니다. AWS에서는 Elasticsearch Service를 제공하는데 이를 설정하

happiestmemories.tistory.com

 

 


https://esbook.kimjmin.net/06-text-analysis/6.7-stemming/6.7.2-nori

 

6.7.2 노리 (nori) 한글 형태소 분석기 - Elastic 가이드북

이번 장에서는 elasticsearch가 데이터를 저장하는 색인 과정에서 처리하는 수많은 작업들에 대해 알아보았습니다. 텍스트 분석 및 텀의 개념과, 데이터 분석에 사용되는 애널라이저, 토크나이저,

esbook.kimjmin.net