어떤 선생님이 그러셨어요. C(Create). R(Read). U(Update). D(Delete)를 할 줄 알면 그 건 그 기술을 사용할 줄 아는 거라구요. 그런데 엘라스틱서치는 C.R.U.D 다 해도 반에 반도 사용하지 못하는 거 같아요. 그래도 못하는 것보다는 할 줄 알면 좋을 것 같으니까 해볼게요.

 

그전에 docker를 사용해서 Elasticsearch 하나랑 Kibana 하나씩 설치했는데 앞에서도 봤듯이 싱글-노드 클러스터는 뭔가 하다 만 것 같은 느낌이잖아요? Health가 Yellow에서 Green으로 또 바뀌는 것도 보고 싶구요. 그리고 지금 상태는 컨테이너가 삭제되면 안에 있는 데이터도 모두 그냥 날아가게 생겼어요. 그래서 먼저 Elasticsearch에 저장소도 붙여주고 노드도 3개 만들어줄 거예요.

물론 docker를 사용해서요. 설치하는데 진을 빼면 공부할 힘도 떨어져요. 정작 중요한 건 못해보고 설치만 하다 끝날 수도 있으니까요.

 

https://www.elastic.co/guide/en/elastic-stack-get-started/current/get-started-docker.html

 

Running the Elastic Stack on Docker | Getting Started [7.14] | Elastic

At this point, Kibana cannot connect to the Elasticsearch cluster. You must generate a password for the built-in kibana_system user, update the ELASTICSEARCH_PASSWORD in the compose file, and restart to enable Kibana to communicate with the secured cluster

www.elastic.co

여기 들어가면 docker-compose.yml이라는 파일을 만들라고 나오는데요 적당한 위치에 elastic이라는 폴더를 만들고 그 안에 docker-compose.yml이라는 파일을 만들어서 넣어주세요. 그리고 docker-compose를 설치해주세요. 예전에는 docker-compose 설치하는 게 어려웠던 거 같은데 지금은 sudo yum install docker-compose 하면 설치가 되는 거 같아요. epel-release는 설치되어있으시지요?

 

docker-compose.yml 파일을 잠깐 보면 services 밑에 있는 게 각각 하나의 컨테이너가 될 애들이에요.

es01 ~ es03까지 엘라스틱서치 3개가 각각 컨테이너에 설치가 되구요. 키바나도 하나 설치가 돼요.

엘라스틱서치는 environment라는 항목에 있는 값들을 환경변수로 가지게 되는데 자세한 내용은 심화 과정에 들어가야 이해할 수 있을 것 같아요 우선은 그냥 놔두기로 해요. es01은 9200번 포트를 호스트의 9200번 포트로 노출시키는 게 있는데 es02, es03에는 없네요. 그리고 각 엘라스틱서치마다 volumes에 data01 ~ data03을 붙여놓네요. 얘네들은 저기 밑에 volumes에 local이라는 드라이버 설정을 가지고 정의되어 있는 걸 볼 수 있는데요 도커 공부하는 시간이 아니니까 일단 넘어갈게요.

 

마지막으로 키바나는 5601번 포트를 5601번 포트에 노출시키고 있는 걸 확인할 수 있네요. 참고로 앞에 있는 숫자가 호스트에서 노출될 포트구요 뒤에 오는 숫자가 컨테이너에서 사용되는 포트 넘버예요 그러니까 내 호스트 머신에서 사용할 포트 넘버를 바꾸고 싶다면 앞에 숫자를 바꾸면 되겠지요?

 

먼저 기존에 있던 엘라스틱 스택, 키바나 컨테이너를 죽여주세요. docker rm es01-test kib-test -f  해주세요. 네트워크도 docker network rm {엘라스틱 네트워크 이름}으로 지워주시구요.

 

그럼 이제 docker-compose.yml 파일이 있는 곳에서 

docker-compose -f {도커 컴포즈 파일 위치} up -d

해주세요. -d 옵션을 넣으면 컨테이너들이 백그라운드에서 촤좌작 돌아갈 거예요. 혹시 엘라스틱서치가 올라오지 않을 수 있는데 그럴 때는 docker logs es01 -f 해서 어떤 에러로그가 남는지 확인하시고 적당한 조치를 취해주세요. 보통 vm.max_map_count  값이 작다고 하는 원인이 많은데 그 건 여기 한번 보시면 해결할 수 있을 거에요.

 

그럼 웹브라우저로 Kibana를 켜고 들어가 볼까요? Multiple Cluster를 생성한 기념으로 클러스터 상태 먼저 확인해볼게요.

GET /_cluster/health

{
  "cluster_name" : "es-docker-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 8,
  "active_shards" : 16,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  ...
}

status가 green이래요. 기분 좋아요. unassigned_shards도 없네요.

 

Create. 생성

이전에 Kibana로 cURL로 Postman으로 인덱스 생성하는 걸 해봤어요. 그런데 방금 엘라스틱서치 새로 설치해서 다 날아갔어요. 마음에 새긴다 생각하고 다시 한번 해볼게요. Kibana로요.

첫 번째 책은 해리포터와 마법사의 돌이에요. 아마존에서 캡처했어요. 별점은 4.8/5.0이네요. 그런데 저 리뷰 개수를 지금 남은 책 개수라고 생각하고 저장해 볼게요.

POST /books/_doc
{
  "title": "Harry Potter and the Sorcerer's Stone",
  "price": 29.99,
  "rating": 4.8,
  "in_stock": 737
}


{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LCeNu3sBSx-nWPvrR9rC",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

result: created라고 나오는 거보니 잘 생성이 되었나 봐요. 이번에도 인덱스를 한 번 확인해볼까요?

GET /_cat/indices/books?v

health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   books K57ZizxgTzOaSq5MfGz5ig   1   1          1            0      9.4kb          4.7kb

아.. 이번엔 health가 green이네요. 

해리포터와 마법사의 돌 다음은 비밀의 방이에요.

POST /books/_doc
{
  "title": "Harry Potter and the Chamber of Secrets",
  "price": 29.99,
  "rating": 4.9,
  "in_stock": 32049
}

{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LSeSu3sBSx-nWPvrcdo5",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

와.. 어떻게 저런 리뷰수에 저런 평점이 나올까요? 아무튼 같은 방법으로 아즈카반의 죄수까지 books 인덱스에 총 3권의 책을 만들어 넣었어요. 

 

Read. 읽기

지금까지 입력해 넣은 책들이 잘 들어갔는지 확인을 해야겠어요. POST로 책을 하나씩 넣을 때마다 응답 값이 왔는데 거기에 _id라는 필드에 요오상한 문자랑 숫자가 왔었어요. 인덱스를 읽을 때 이 id값이 있으면 아주 쉬워요.

GET /books/_doc/LCeNu3sBSx-nWPvrR9rC

{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LCeNu3sBSx-nWPvrR9rC",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "Harry Potter and the Sorcerer's Stone",
    "price" : 29.99,
    "rating" : 4.8,
    "in_stock" : 737
  }
}

마법사의 돌을 입력하고 반환된 값에서 id를 /books/_doc/{_id} 이 부분에 넣고 GET 요청을 하면 위와 같은 응답 값을 받을 수 있어요. 인덱스 이름은 뭔지 타입은 어떤 타입인지 아이디는 뭔지 버전 시퀀스 넘버는 잘 모르겠어요. found: true 찾았대요. 그리고 처음에 입력했던 내용. 책 제목, 가격, 별점 등등은 _source라는 곳에 들어가 있네요.

 

Update. 갱신

방금 해리포터와 마법사의 돌이 한 권 더 팔렸어요. 어떻게 해야 할까요? 재고에서 하나 빼야죠. 방금 해리포터와 마법사의 돌이 737권 남아있는 걸 봤어요. 그럼 여기에서 한 권 더 팔렸으니까 지금은 총 736권 남았어요. 수정해주세요.

Kibana의 장점 중 하나예요. Ctrl + Space 키를 누르면 자동완성이 딱 떠요. 이 것뿐만 아니라 아래와 같이 이런 기능도 있어요. 위치만 알려주는 게 아니라 각 endpoint에 맞는 추천 구문을 딱딱 제시해줘요.

POST /books/_update/LCeNu3sBSx-nWPvrR9rC
{
  "doc": {"in_stock": 736}
}


{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LCeNu3sBSx-nWPvrR9rC",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

자동완성의 도움을 받아 위와 같이 API 요청을 만들어서 보내고 아래는 응답 값이에요. result: updated 라네요. 확인해볼까요?

GET /books/_doc/LCeNu3sBSx-nWPvrR9rC



{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LCeNu3sBSx-nWPvrR9rC",
  "_version" : 2,
  "_seq_no" : 3,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "Harry Potter and the Sorcerer's Stone",
    "price" : 29.99,
    "rating" : 4.8,
    "in_stock" : 736
  }
}

 

 

Delete. 삭제

를 해야 하는데 아즈카반의 죄수를 삭제하고 싶어요. 그런데 아이디를 몰라요. 그럼 어떻게 해야 할까요?

찾아야지요. 검색어를 가지고 검색을 하던지 아니면 싹 다 찾아서 쭈욱 봐야지요.

POST /books/_search
{
  "query": {"term": {
    "title": {
      "value": "azkaban"
    }
  }}
}


{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.9611689,
    "hits" : [
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "LieWu3sBSx-nWPvrKtqc",
        "_score" : 0.9611689,
        "_source" : {
          "title" : "Harry Potter and the Prisoner of Azkaban",
          "price" : 29.99,
          "rating" : 4.9,
          "in_stock" : 31545
        }
      }
    ]
  }
}

다행히 azkaban이라는 검색어로 찾았어요. 이제 삭제하려면 id(LieWu3sBSx-nWPvrKtqc)값을 가지고 삭제를 해야 돼요.

DELETE /books/_doc/LieWu3sBSx-nWPvrKtqc


{
  "_index" : "books",
  "_type" : "_doc",
  "_id" : "LieWu3sBSx-nWPvrKtqc",
  "_version" : 2,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 4,
  "_primary_term" : 1
}

자. result: deleted래요 삭제되었나 봐요. 깔끔하게 한 방에 확인해봐요.

GET /books/_search



{
  "took" : 657,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "LSeSu3sBSx-nWPvrcdo5",
        "_score" : 1.0,
        "_source" : {
          "title" : "Harry Potter and the Chamber of Secrets",
          "price" : 29.99,
          "rating" : 4.9,
          "in_stock" : 32049
        }
      },
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "LCeNu3sBSx-nWPvrR9rC",
        "_score" : 1.0,
        "_source" : {
          "title" : "Harry Potter and the Sorcerer's Stone",
          "price" : 29.99,
          "rating" : 4.8,
          "in_stock" : 736
        }
      }
    ]
  }
}

 

 

끝.