본문 바로가기

Dev/web

python, django,haystack, elasticsearch 장고 엘라스틱서치 연동 - 1 (db에 있는거 옮기기)

3줄 요약:

1. 헤이스택 좋음 근데 es 1.x, 2.x 버전만 지원함 (2017년10월 19일 기준)

2. elastic-dsl도 괜찮고 디비처럼 쓰는 방법은 알겠는데 기존디비에서 이주 시키방법 모르겠음

3. elastic-py가 공식 low-level 라이브러리긴 함


개요:

장고에서 엘라스틱 연동할려고 함

3가지 방법이 있음 (3가지방법밖에 모름..)

헤이스택이용: http://django-haystack.readthedocs.io/en/master/installing_search_engines.html#elasticsearch

elasticsearchDSL이용:https://elasticsearch-dsl.readthedocs.io/en/latest/

공식라이브러리이용: https://elasticsearch-py.readthedocs.io/en/master/   https://elasticsearch-py.readthedocs.io/en/master/


무엇을 선택해야하는가 고민될때 참고글

django-haystack 이냐 elasticsearch-dsl 비교글: https://python.libhunt.com/project/django-haystack/vs/elasticsearch-dsl-py

django-haystack 이냐 elasticsearch-py 비교글:  https://python.libhunt.com/project/django-haystack/vs/elasticsearch?rel=cmp-cmp


정리:

haystack 인기많고 활발해서 다 좋은데 엘라스틱만 최신버전 지원안해서 별로임

내생각은 걍 haystack은 populating용으로 쓰고 인기없는 elastic-dsl은 피하고 elastic-py공식 라이브러리를 써서 작업하는게 나을듯 함

정리2:

hybrid로 사용하거나,

실서비스할땐 걍 https://github.com/Alkalit/haystack-elasticsearch5 이거 쓰면 될듯;;

https://pypkg.com/pypi/django-haystack-elasticsearch5/



django-haystack-elasticsearch start!


요새 서치엔진 중요함

아마존에 검색없으면 말도안됨

장고에 대한 약간의 지식이 있으면 이미 만들어진 라이브러리로 쉽게 만들수있음.


Elastic Search

루씬 기반의 검색엔진, 분산처리가능, JSON형식의 전문검색가능함

그리고 빠름 왜냐면 text를 검색하는게 아니라 index로 검색하기 때문

RESTful API로 작동함

자세한건 공식문서로


Haystack

엘라스틱같은거 연동하는 장고앱

이거쓰면 통합된API로 코드수정없이 엘라스틱 그때그때 변경될수있음  


Settings up haystack and elastic search (설치)


installing haystack

헤이스택 설치

ubuntu 17.04

django 1.11.6

python 3.5.3

django_haystack_elastic이란 장고프로젝트 만듦

manage.py있는데서


$python3 manage.py migrate
$python3 manage.py createsuperuser
$python3 manage.py runserver

$ tree
.
├── db.sqlite3
├── django_haystack_elastic
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   ├── settings.cpython-35.pyc
│   │   └── urls.cpython-35.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

$python3 manage.py startapp blog
완전 기초적인 장고 blog 앱 구성함

$ tree
.
├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       └── __init__.cpython-35.pyc
│   ├── models.py
│   ├── __pycache__
│   │   ├── admin.cpython-35.pyc
│   │   ├── __init__.cpython-35.pyc
│   │   ├── models.cpython-35.pyc
│   │   ├── urls.cpython-35.pyc
│   │   └── views.cpython-35.pyc
│   ├── templates
│   │   └── blog
│   │       └── post_list.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── db.sqlite3
├── django_haystack_elastic
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   ├── settings.cpython-35.pyc
│   │   ├── urls.cpython-35.pyc
│   │   └── wsgi.cpython-35.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

$pip3 install django-haystack


앱에다가 추가 해줌 (헤이스택 추가하면 에러남 왜냐면 그에대한 설정을 아직안해줬음)

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'haystack'
]

installing elastic search

이부분은 다른거보고함

일단 자바 깔아야함 ㅇㄹㅇㄹ

$java -version

java version "1.8.0_144"

$echo $JAVA_HOME

/usr/lib/jvm/java-8-oracle

한번 확인해주고

https://www.elastic.co/kr/downloads/elasticsearch?baymax=KR-ES-getting-started&elektra=landing-page

들어가보니 벌써 5.6.3임 하..

curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.3.tar.gz

해서 다운받는다.

$ tar -xvf elasticsearch-5.6.3.tar.gz
압축 풀어주고요 (sudo 압축풀지않기)

/elasticsearch-5.6.3/bin$ ./elasticsearch

(sudo로 실행하지 않기)

(설정파일안건들이면 default로 시작함)

그리고 pip3 install elasticsearch 하고


modifying django configuration to specify haystack backend

장고설정에 헤이스택이 어디에 연동되는지 명시해주는거임

장고 settings.py에

이거추가함

HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': 'http://127.0.0.1:9200/',
'INDEX_NAME': 'haystack',
},
}

이제 설치는 됐음 이제 어떻게 사용하는지 보도록 하자


Working with Search Indexes

이제 인덱스를 이용해 작업해보자(인덱스란 무엇인가)

*index : 관련데 documemt를 저장하는 장소(관계형 데이터 베이스에서 데이터 베이스에 해당)

*es데이터 구조는 인덱스, 타입, 다큐먼트 단위로 구성


먼저 할일은 헤이스택이 뭐를 검색할지 알기위해 장고안에서 index(SearchIndex)를 만들어주는것임

헤이스택의 서치 인댁스는 장고 모델하고 비슷함


일단 blog model은 이렇게

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
user = models.ForeignKey(User)
pub_date = models.DateTimeField()
title = models.CharField(max_length=200)
body = models.TextField()

def __unicode__(self):
return self.title

서치 인덱스는 

모델하고 같은계층에 search_indexes.py 만들고

import datetime
from haystack import indexes
from .models import Blog

class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
author = indexes.CharField(model_attr='user')
pub_date = indexes.DateTimeField(model_attr='pub_date')

def get_model(self):
return Blog

def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.filter(pub_date__lte=datetime.datetime.now())

이렇게 했음

Understanding Search Index

저기 주황색부분 보면 모든 서치 인덱스의 하나의 필드는 저렇게 document=True로 되어있어야한다함

이게 헤이스택이랑 서치엔진(엘라스틱)의 프라이머리 서치 필드라고 함

이게 우리가 데이터 템플릿을 이용해 다큐먼트를 만들수있게 해줌

템플릿은 걍 텍스트 파일이고 검색할것들은 이 파일로 가게 되어있음


파일 하나를 만들어줌 난 post_text.txt 라고 함

거기에 이거 입력함

{{ object.title }}
{{ object.user.get_full_name }}
{{ object.body }}

파일 정리해보면


tree

.

├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-35.pyc
│   │       └── __init__.cpython-35.pyc
│   ├── models.py
│   ├── __pycache__
│   │   ├── admin.cpython-35.pyc
│   │   ├── __init__.cpython-35.pyc
│   │   ├── models.cpython-35.pyc
│   │   ├── search_indexes.cpython-35.pyc
│   │   ├── urls.cpython-35.pyc
│   │   └── views.cpython-35.pyc
│   ├── search_indexes.py
│   ├── templates
│   │   ├── blogg
│   │   │   └── post_list.html
│   │   └── search
│   │       └── indexes
│   │           └── blog
│   │               └── post_text.txt
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── db.sqlite3
├── django_haystack_elastic
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   ├── settings.cpython-35.pyc
│   │   ├── urls.cpython-35.pyc
│   │   └── wsgi.cpython-35.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py


나는 장고에서 템플릿로더 충돌안나게 앱이름을 템플릿에 넣어주는데 blog를 안에 넣어야되서 일단 임시로 이름 변경했음

(나중에 post_text.txt 위치 설정하는거 알게되먼 수정하겠음)

이렇게 하고 makemigrations, migrate 돌려주고


localhost:8000/admin 에서 post 하나 써놈

그리고

python3 manage.py rebuild_index 해줌

(엘라스틱서치,장고 켜논상태에서 했음)


$ curl -XGET '127.0.0.1:9201/_cat/indices?v&pretty'
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   haystack CJ6KA6yhSaKxwWGymalM3A   5   1          1            0      5.6kb          5.6kb


$ curl -XGET '127.0.0.1:9201/haystack/_search?pretty'
{
  "took" : 70,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "haystack",
        "_type" : "modelresult",
        "_id" : "blog.post.1",
        "_score" : 1.0,
        "_source" : {
          "author" : "austinkoma",
          "django_id" : "1",
          "text" : "안녕하세요\n\n테스트중입니다.",
          "django_ct" : "blog.post",
          "id" : "blog.post.1",
          "pub_date" : "2017-10-18T15:50:17+00:00"
        }
      }
    ]
  }
}

값이 들어갔음^^ django -> elasticsearch

지금은 값이 들어갔지만 이방식으로 값이나 인덱스를 CRUD 할수있어


Querying Data

이제 검색엔진이랑 연동했고 인덱스도 만들어졌음.

내가 필요한 데이터를 질의를 통해 가려올 것만 남았음.

헤이스텍은 꽤 좋은 질의를 위한 API를 가지고 있음 그리고 장고 ORM이랑 비슷함


헤이스택은 SearchQuerySet 클래스를 제공함 이걸로 아까 넣은 값을 검색해보자

근데 fillter기능 작동안함 ;; 내가 못하는건가? 하여튼 안됨

찾아보니

http://django-haystack.readthedocs.io/en/master/installing_search_engines.html#elasticsearch

Haystack currently only supports Elasticsearch 1.x and 2.x. Elasticsearch 5.x is not supported yet,

엘라스틱서치 5.x 지원을 안한다고 함. 지난학기에 친구가 스프링데이터가 es5점대 지원안한다고 했을때 안믿었는데..(지금은 지원함)




https://pypkg.com/pypi/django-haystack-elasticsearch5/

https://github.com/Alkalit/haystack-elasticsearch5


이거 쓰기로 함


pip3 install django-haystack-elasticsearch5

하고 settings.py도 변경해줌


HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack_elasticsearch5.Elasticsearch5SearchEngine',
'URL': 'http://127.0.0.1:9201/',
'INDEX_NAME': 'test_backend',
}
}


그리고 views.py에 이런코드로 테스트를 했음


from django.shortcuts import render
from haystack.query import SearchQuerySet
from .models import Post

# Create your views here.
def post_list(request):
sqs = SearchQuerySet().all()
print(sqs.count())

results = SearchQuerySet().filter(content='hello')
for t in results:
print(t.author)
print(t.text)

return render(request, 'blogg/post_list.html')

내 엘라스틱서치는 지금 다큐멘트 4개 있음

내가 localhost:8000/blog 로 접속하면 post_list함수가 작동되면서

내 es에 있는 다큐먼트 수 다 조회함 (4 나옴 ^^)

그리고 SearchQuerySet().filter()를 이용해 hello라는 str을 가지고 있는 다큐먼트를 조회해서 출력함

필터짱짱


Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
4
austinkoma
hello world


austinkoma
haha hello hello


만약의 multiple searchIndex 클래스를 가지고 있다면 아래와 같이 하는게 더 좋다고 함

from haystack.query import SearchQuerySet results = SearchQuerySet().models(Post).filter(content='haystack with elastic search'


또 Haystack 공식문서에서 이것저것 해볼수있다고 함 (공식문서)


그럼 검색은 걍 저걸로 구현하면 될것같고



참조:
bookofstranger.com/elastic-search-wih-django-haystack-for-search-functionality/