기술자료

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

쉽고 강력한 RESTFul 분산 검색엔진 : 엘라스틱서치 살펴보기

기술자료
DBMS별 분류
Etc
작성자
dataonair
작성일
2014-05-20 00:00
조회
7407



쉽고 강력한 RESTFul 분산 검색엔진

엘라스틱서치 살펴보기



빅데이터 시대를 맞아 수많은 빅데이터 플랫폼과 검색엔진들이 개발되고 있다. 이 중 엘라스틱서치는 RESTFul API를 지원하고, 뛰어난 검색 기능과 손쉬운 스케일 아웃이 가능한 강력한 분산시스템이다. 엘라스틱서치의 강점은 무엇인지 그리고 기본적인 사용방법은 어떻게 되는지 지금부터 살펴보자.



엘라스틱서치는 Shay Banon이 2010년 처음 발표한 이래 지금까지 아파치2 라이선스 기반의 오픈소스로서 커뮤니티 중심으로 개발이 이루어지고 있다. 2014년 2월 12일에는 드디어 1.0.0 버전이 릴리즈됐다. 엘라스틱서치는 아파치 루씬 기반으로 자바 환경에서 별도의 설정 없이 실행 가능할 뿐 아니라 RESTFul API를 통해 데이터의 입력, 삭제, 검색 등을 할 수 있다. 자바, PHP, 펄(Perl), 자바스크립트, 파이선(Python), 루비 등의 라이브러리를 제공하고, 플러그인 설치도 지원해 기능을 손쉽게 확장할 수 있는 점도 엘라스틱서치의 특징이다.

tech_img1320.jpg

한 가지 흥미로운 것은 엘라스틱서치의 창시자인 Shay Banon의 닉네임이 ‘kimchy(김치)’라는 점이다. 엘라스틱서치 커뮤니티를 유심히 살펴보면 실제로 kimchy란 유저가 많은 활동을 하고 있다. Shay Banon의 외가 쪽 성이 kimchy로 알려져 있는데, 실제로도 그는 한국 음식인 김치를 좋아한다고 한다. 현재 엘라스틱서치는 위키피디아, 넷플릭스, 스택오버플로우 등이 도입했으며, 사용자도 빠르게 증가하고 있다.



tech_img1321.jpg

엘라스틱서치의 특징

우선 설치가 매우 쉽다. 공식 웹사이트에서 압축파일을 다운로드하고 압축을 해제한 다음 실행시키는 것만으로 기본적인 설치가 끝난다. 확장성도 뛰어나 여러 개의 노드를 활용해 손쉽게 분산시스템을 구성할 수 있다. 2개 이상의 엘라스틱서치를 실행하면 하나의 노드가 마스터 노드로 선출된다. 마스터 노드가 정지되면 또다른 노드가 새로운 마스터 노드가 된다. 그리고 각각의 노드는 다시 여러 개의 샤드(Shard)로 데이터를 분산 저장하며 샤드는 0개 이상의 복사본을 가진다. 노드가 정지될 경우 해당 노드의 데이터를 다른 노드에 복사하고 자동으로 정렬되는 점도 엘라스틱서치의 특징이다.

멀티테넌시(Multi-Tenancy) 지원도 빼놓을 수 없는 특징이다. 이 덕분에 하나의 서버에서 여러 인덱스를 생성하고 서로 다른 인덱스들을 하나의 쿼리로 검색할 수 있다. 게다가 NoSQL의 특징도 가지고 있어 스키마를 미리 정의하지 않고 데이터를 입력해도 검색이 가능한 인덱싱이 수행된다. 이밖에도 엘라스틱서치의 데이터는 몽고DB와 유사하게 JSON 형식으로 저장된다. RESTFul API를 지원해 대부분의 명령어가 HTTP 프로토콜로 실행되며, 입출력을 비롯해 환경설정까지 JSON 데이터로 처리할 수 있다.



설치 및 실행

엘라스틱서치를 실행하기 위해서는 자바6 이상의 버전이 필요하다. 엘라스틱서치 웹사이트의 다운로드 페이지(elasticsearch. org/download)에서 zip이나 tar.gz 파일을 다운로드한 후 압축을 풀자. 다음 bin 디렉터리에 있는 엘라스틱서치 프로그램을 실행한다(<리스트 1> 참조).


<리스트 1> bin/elasticsearch 실행$ bin/elasticsearch
[2014-03-05 13:57:40,217][INFO ][node] [Empath] version[1.0.0],
pid[30844], build[a46900e/2014-02-12T16:18:34Z]
[2014-03-05 13:57:40,217][INFO ][node] [Empath] initializing ...

[2014-03-05 13:57:46,071][INFO ][discovery] [Empath]
elasticsearch/L9h28g0cQbO1acIIX1it7w
[2014-03-05 13:57:46,085][INFO ][http] [Empath] bound_address
{inet[/0:0:0:0:0:0:0:0:9200]}, publish_address {inet[/172.31.22.111:9200]}

[2014-03-05 13:57:46,103][INFO ][node] [Empath] started

이걸로 기본적인 엘라스틱서치 설치가 모두 끝났다. 믿기 어렵겠지만 정말이다. 만약 유닉스 환경에서는 백그라운드 프로세스로 실행하길 원한다면 ‘bin/elasticsearch -d’ 명령어를 입력하면 된다. 별도의 설정을 지정하지 않은 경우 엘라스틱서치는 기본적으로 9200 포트에 elasticsearch라는 클러스터 명으로 실행된다. <리스트 1>을 실제로 실행해보면 Empath라는 노드명으로 실행된 것을 확인할 수 있는데, 노드명도 별도로 지정하지 않는 경우 실행될 때마다 임의의 이름이 부여되니 참고하자. 유닉스의 curl 명령을 이용하면 엘라스틱서치에 데이터를 저장 또는 삭제하거나 설정을 변경하고 조회할 수 있다. <리스트 2>처럼 콘솔에서 curl locahost:9200 명령어를 실행하면 실행 중인 엘라스틱서치에 대한 정보가 출력된다. 원격 환경에서 작업하는 경우 명령어에 localhost 대신 서버의 IP 또는 url을 입력하면 된다.


<리스트 2> curl localhost:9200 실행$ curl localhost:9200
{
"status" : 200,
"name" : "Empath",
"version" : {
"number" : "1.0.0",
"build_hash" : "a46900e9c72c0a623d71b54016357d5f94c8ea32",
"build_timestamp" : "2014-02-12T16:18:34Z",
"build_snapshot" : false,
"lucene_version" : "4.6"
},
"tagline" : "You Know, for Search"
}

curl 대신 웹브라우저 주소창에 localhost:9200을 입력하는 것으로도 정보를 확인할 수 있다(<그림 3> 참조). 같은 네트워크상에서 한번 더 엘라스틱서치를 실행시키면 새로운 노드로 실행된다. 분산 환경을 손쉽게 구성할 수 있는 것이다. 다른 네트워크상에서 분산시스템을 구성하려면 환경설정에서 마스터 노드의 주소를 명시하면 된다.


<리스트 3> 추가로 bin/elasticsearch 실행$ bin/elasticsearch
[2014-03-05 16:05:10,439][INFO ][node] [Astrid Bloom] version
[1.0.0], pid[31426], build[a46900e/2014-02-12T16:18:34Z]
[2014-03-05 16:05:10,440][INFO ][node] [Astrid Bloom] initializing ...

[2014-03-05 16:05:16,094][INFO ][discovery] [Astrid Bloom]
elasticsearch/MmHCJyeuQuKCeFE63hAghA
[2014-03-05 16:05:16,099][INFO ][http] [Astrid Bloom] bound_address
{inet[/0:0:0:0:0:0:0:0:9201]}, publish_address {inet[/172.31.22.111:9201]}
[2014-03-05 16:05:16,100][INFO ][node] [Astrid Bloom] started

<리스트 3>을 실행하면 Astrid Bloom 이름의 노드가 9201 포트에 실행된 것을 확인할 수 있다. 이제 <리스트 1>에서 실행했던 처음 노드의 로그를 살펴보면 <리스트 4>와 같이 로그가 추가돼 있을 것이다.


<리스트 4> 마스터노드 Empath 에 추가된 Astrid Bloom 노드…
[2014-03-05 16:05:16,066][INFO ][cluster.service] [Empath] added
{[Astrid Bloom][MmHCJyeuQuKCeFE63hAghA]
[ip-172-31-22-111] [inet[/172.31.22.111:9301]],}, reason: zen-disco-receive
(join from node[[Astrid Bloom]
[MmHCJyeuQuKCeFE63hAghA][ip-172-31-22-111] [inet[/172.31.22.111:9301]]])

데이터 구조 단위

엘라스틱서치는 인덱스(Index), 타입(Type), 도큐먼트(Document)의 구조로 이루어져 있다. 관계형 데이터베이스에 익숙한 사람들의 이해를 위해 엘라스틱서치와 관계형 데이터베이스의 구조 분석 자료를 먼저 살펴보자(<표 1> 참조).

tech_img1322.jpg

엘라스틱서치는 RESTFul API를 이용해 ‘http://host:port/<인덱스>/<타입>/[id]’ 형식으로 접근할 수 있다. 유닉스 환경에서는 curl 명령어로 접근 가능한데, 구체적인 사용법은 <리스트 5>와 같다.



<리스트 5> 유닉스 curl 명령어를 이용한 RESTFul API 활용curl ­X (메서드) http://host:port/<인덱스>/<타입>/[아이디] ­d '(데이터)'

데이터 생성, 변경, 조회 및 삭제

지금부터 엘라스틱서치의 기본적인 명령어를 실습해보자. 먼저 books란 인덱스의 book 타입 안에 아이디가 1인 데이터를 입력해보자. 유닉스의 curl 명령어에 PUT 메소드를 사용하면 되는데, -d 옵션 뒤에 ‘ ’로 JSON 데이터를 묶어 입력하면 된다(<리스트 6> 참조).


<리스트 6> 데이터 입력$ curl -XPUT localhost:9200/books/book/1 -d '
{
"title" : "Elasticsearch Guide ",
"author" : "Kim",
"started" : "2014-03-14",
"pages" : 250
}'
{"_index":"books","_type":"book","_id":"1","_version":1,"created":true}

<리스트 6> 마지막 라인에 성공적으로 데이터가 입력됐음을 확인할 수 있다. 만약 같은 인덱스, 타입, 아이디로 다시 입력할 경우 기존 데이터가 수정될 것이다(<리스트 7> 참조).


<리스트 7> 데이터 수정$ curl -XPUT localhost:9200/books/book/1 -d '
{
"title" : "Elasticsearch Guide",
"author" : ["Kim", "Lee"],
"started" : "2014-03-14",
"pages" : 250
}'
{"_index":"books","_type":"book","_id":"1","_version":2,"created":false}

<리스트 7>처럼 엘라스틱서치는 데이터 수정도 손쉽다. 데이터를 확인은 GET 메소드로 주소를 호출하면 되는데, XGET 메소드의 경우 생략할 수 있으니 참고하자.


<리스트 8> 데이터 확인$ curl -XGET localhost:9200/books/book/1
{"_index":"books","_type":"book","_id":"1","_version":2,"found":true, "_source" :
{
"title" : "Elasticsearch Guide",
"author" : ["Kim", "Lee"],
"started" : "2014-03-14",
"pages" : 250
}
}

엘라스틱서치에서는 입력한 데이터가 ‘_source’ 필드에 저장되는데, 메타 정보를 제외한 정보 데이터만 확인하길 원한다면 아이디 뒤에 _source 필드를 명시하면 된다(<리스트 9> 참조).


<리스트 9> _source 데이터 확인$ curl -XGET localhost:9200/books/book/1/_source
{
"title" : "Elasticsearch Guide",
"author" : ["Kim", "Lee"],
"started" : "2014-03-14",
"pages" : 250
}

DELETE 메소드로는 데이터를 삭제할 수 있다(<리스트 10> 참조). 삭제는 도규먼트, 타입, 인덱스 단위의 전체 삭제 등을 지원하며, 차후 설명할 쿼리를 이용한 선별적인 삭제도 가능하다..


<리스트 10> 데이터 삭제$ curl -XDELETE localhost:9200/books/book/1
{"found":true,"_index":"books","_type":"book","_id":"1","_version":3}

검색

엘라스틱서치에서는 URI를 이용한 검색과 Request Body를 이용한 검색, 이 두 가지를 모두 지원한다. 여기서 URI 쿼리 검색은 q 매개변수를 이용한 방식이다.


<리스트 11> URI 검색$ curl ­XGET localhost:9200/books/book/_searchq=elasticsearch
{"took":2,"timed_out":false,"_shards":{"total":6,"successful":6,"failed":0},
"hits":{"total":1,"max_score":0.095891505,"hits"
:[{"_index":"books","_type":"book","_id":"1","_score":0.095891505, "_source" :
{
"title" : "Elasticsearch Guide",
"author" : ["Kim", "Lee"],
"started" : "2014-03-14",
"pages" : 250
}}]}}

특정 필드의 내용을 검색(<리스트 12>)하고자 한다면 ‘필드명:검색어’ 형식으로 질의스트 13> 참조).



<리스트 12> title 필드의 검색어 elasticsearch 검색$ curl ­XGET localhost:9200/books/book,magazine/_searchq=title:elasticsearch

<리스트 13> book, magazine 타입 동시 검색$ curl -XGET localhost:9200/books/book,magazine/_searchq=elasticsearch

엘라스틱서치의 경우 _all 커맨드를 이용해 해당 클러스터의 모든 인덱스를 검색할 수 있다(<리스트 14> 참조). 그러나 성능을 고려한다면 _all 대신 필요한 인덱스를 명시해 검색하는 것이 좋다.



<리스트 14> 전체 인덱스 데이터 검색$ curl -XGET localhost:9200/_all/_searchq=elasticsearch

Request Body를 이용하면 더욱 복잡한 형식의 질의도 가능하다. 검색은 match, filter, bool, range 등 다양한 검색 API가 제공되는데 루씬의 색인 단위인 term과 prefix도 지원한다.


<리스트 15> Request Body를 이용한 질의$ curl localhost:9200/books/book/_search -d '
{
"query" : {
"term" : { "title" : "elasticsearch" }
}
}'
{"took":2,"timed_out":false,"_shards":{"total":6,"successful":6,"failed":0},"hits":
{"total":1,"max_score":0.19178301,"hits":[{"_index":"books","_type":"book","_id"
:"1","_score":0.19178301, "_source" :
{
"title" : "Elasticsearch Guide",
"author" : ["Kim", "Lee"],
"started" : "2014-03-14",
"pages" : 250
}}]}}

엘라스틱서치와 관련된 더 많은 질의를 알고싶다면 엘라스틱서치 레퍼런스 문서(elasticsearch.org/guide)를 참고하길 바란다. 여기까지 엘라스틱서치의 소개와 기본적인 사용 방법에 대해 알아봤다. 다음 시간에는 엘라스틱서치의 클러스터와 노드의 분산 메커니즘에 대해 보다 자세히 살펴보니 많은 기대 부탁한다.