ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ElasticSearch 무작정 시도해보기 (with. django)
    ElasticSearch 2021. 5. 30. 14:20

    서론

    다른걸 공부하던중 ElasticSearch가 자꾸 보여서 한번 공부해보는 페이지 입니다.

    필자는 ElasticSearch를 처음 시도합니다. docs를 거의 읽지 않고 구글링한 코드들을 짜집기 한 것입니다.

    필자의 시도했던 순서대로 설명글이 진행되므로 다른 방법이 있을 수 있습니다.

    필자의 낮은 실력으로 이해했던 내용이므로 뇌피셜이 포함된 글입니다.

    Window 운영체제 기반으로 설명된 글 입니다.

     

     

     

    ElasticSearch 준비

    https://www.elastic.co/kr/downloads/elasticsearch

     

    Download Elasticsearch Free | Get Started Now | Elastic

    Download Elasticsearch or the complete Elastic Stack (formerly ELK stack) for free and start searching and analyzing in minutes with Elastic.

    www.elastic.co

     

    위의 링크에서 다운받고 C에 압축을 풀어둡시다.

     

     

    한글분석기 nori 설치

    압축 푼 elastcisearch의 bin폴더 경로의 cmd창을 켠 후 다음 명령어를 입력합니다.

    elasticsearch-plugin install analysis-nori

     

     

     

    ElasticSearch에 예시로 사용할 데이터셋

    아래의 Dataset Search 사용하여 아무거나 가져왔습니다.

    필자는 한국민족문화대백과사전을 가져왔습니다.

    단 필요한 타입은 json 형태이므로 데이터를 json으로 가공하는 과정이 필요합니다.

    https://datasetsearch.research.google.com/

     

    Dataset Search

     

    datasetsearch.research.google.com

     

    elasticsearch 실행

    명령어로 실행하거나 백그라운드, 서비스 자동 시작 명령어도 있으나 여기에서는 그냥 프로그램 키는 방법으로 진행하겠습니다.

    elasticsearch/bin/elasticsearch.bat 실행

     

     

    Django 설치

    검색 기능을 활용할 django, restframework, elasticsearch를 설치합시다.

    pip install django
    pip install djangorestframework
    pip install elasticsearch

     

    django 프로젝트 search_project 생성

    django-admin startproject search_project

     

     

    검색기능으로 활용할 django search_app 생성

    python manage.py startapp search_app

     

    그 후 settings.py에 등록 해둡시다.

    # settings.py
    
    INSTALLED_APPS = [
    ...
    'search_app',
    'rest_framework',
    ]

     

     

    bulk 파일 만들기

    elasticsearch 에서의 bulk는 데이터를 Post 또는 Put을 하는 행위입니다.

    search_app에 적용할 내용이니 search_app에 setting_bulk.py를 만듭니다.

    # search_app/setting_bulk.py
    
    from elasticsearch import Elasticsearch
    import json
    es = Elasticsearch(hosts='localhost', port=9200)
    if es.indices.exists(index='dictionary'):
        pass
    else:
        es.indices.create(
            index='dictionary',
            body={
                "settings": {
                    "index": {
                        "analysis": {
                            "analyzer": {
                                "my_analyzer": {
                                    "type": "custom",
                                    "tokenizer": "nori_tokenizer"
                                }
                            }
                        }
                    }
                },
                "mappings": {
                        "properties": {
                            "id": {
                                "type": "long"
                            },
                            "title": {
                                "type": "text",
                                "analyzer": "my_analyzer"
                            },
                            "keyword": {
                                "type": "text",
                                "analyzer": "my_analyzer"
                            },
                            "field": {
                                "type": "text",
                                "analyzer": "my_analyzer"
                            },
                            "type": {
                                "type": "text",
                                "analyzer": "my_analyzer"
                            },
                        }
                }
            }
        )
    
    
    with open("dictionary_data.json", encoding='utf-8') as json_file:
        json_data = json.loads(json_file.read())
    
    body = ""
    for i in json_data:
        body = body + json.dumps({"index": {"_index": "dictionary"}}) + '\n'
        body = body + json.dumps(i, ensure_ascii=False) + '\n'
    
    es.bulk(body)

    코드 내용대로 설명을 하자면

    dictionary 라는 인덱스 주소를 만들고 한글분석기 nori를 지정합니다.

    mapping은 elasticsearch에 적용할 속성들을 넣습니다.

     

    그리고 json 형태로 불러온 데이터셋을 읽어와서 아래와 같은 형태로 만들어집니다.

     

    만들어진 예시

    {"index": {"_index": "dictionary"}}
    {"id": "1", "title": "가계", "keyworld": "", "field": "사회/가족", "type": "개념용어"}

    그후 es.bulk(body)로 데이터를 집어넣습니다.

     

    주의사항 dictionary라는 index가 이미 생성되었다면 다시 생성되지않습니다.

    그 땐 index 지우고 다시 데이터를 넣어야 합니다.

    지우는 방법

    더보기

    콘솔창에 다음 명령어 실행

    curl -XDELETE localhost:9200/dictionary

     

    다음 명령어를 실행하여 elasticsearch에 dataset을 import합니다.

    ** curl로 데이터 import 하는 방법도 있는데 여기서는 다루지 않습니다.

    python setting_bulk.py

     

     

    API View 만들기

    elasticsearch에 데이터까지 넣어줬으니 API View를 봅시다.

    # views.py
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    
    from elasticsearch import Elasticsearch
    
    
    class SearchView(APIView):
    
        def get(self, request):
            es = Elasticsearch(hosts='localhost',port=9200)
    
            # 검색어
            search_word = request.query_params.get('search')
    
            if not search_word:
                return Response(status=status.HTTP_400_BAD_REQUEST, data={'message': 'search word param is missing'})
            docs = es.search(index='dictionary',
                             body={
                                 "query": {
                                     "multi_match": {
                                         "query": search_word,
                                         "fields": ["title", "keyword", "field", "type"]
                                     }
                                 }
                             })
    
            data_list = docs['hits']
    
            return Response(data_list)

    search 라는 query로 검색어를 받고 없으면 400코드, 있으면 dictionary에서 검색을 하는 코드입니다.

     

     

    search_app urls.py

     

    SearchView 만들었으니 url을 지정해줍시다.

    # search_app/urls.py
    
    from django.urls import path
    from search_app import views
    
    urlpatterns = [
        path('', views.SearchView.as_view()),
    ]

     

    search_project urls.py

     

    search_app url include 해줍시다.

    # search_project/urls.py
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('search_app.urls')),
    ]

     

     

    실행 및 결과창

    실행

    python manage.py runserver

    (http://127.0.0.1:8000/?search=ㄱ) 로 접속하여 결과창을 확인 해봅시다.

    와 잘뜬다!

    index가 무엇인지, 검색 결과에 가장 근접한 내용이 무엇인지 보여줍니다.

     

     

    마치며(회고록)

    elasticsearch7 부터는 mapping 부분에 type 지정이 없어졌습니다.

    필자는 왜 에러가 나는지 몰라서 한참을 찾았습니다 :(

     

    curl로 데이터셋 import하는 문제

    curl로 데이터를 import를 시도 해봤는데 왜 그런지 모르겠지만 Content-Type이 고정이 되어서 바뀌지 않아서

    bulk.py를 통해 데이터셋을 올렸습니다...

     

    다음 글은 활용 방안이나 근본적인 기초 내용 또는 kibana 활용방안에 대하여 포스팅하겠습니다.

     

     

    참조

    elasticsearch-django 

    https://ariels1996.github.io/elasticsearch/elasticsearch_django_1/

    https://blog.nerdfactory.ai/2019/04/29/django-elasticsearch-restframework.html

    https://livetodaykono.tistory.com/64

     

    elasticsearch 명령어, 쿼리

    https://lovekmg.github.io/2018/10/11/elasticsearch-1/#index-mapping

    https://stackoverflow.com/questions/8829468/elasticsearch-query-to-return-all-records

    댓글

Designed by Tistory.