Dev/ELK

MacOS 에서 ElasticSearch 설치하기 ( homebrew 사용 X )

린네의 2024. 3. 13. 22:00

 

 Open API 통해서 데이터를 긁어온 뒤 검색 엔진에 ElasticSearch를 연동하는 토이 프로젝트를 해보고 싶어서 사용 방법을 익히기 위해 설치를 진행했다.  새로운 내용을 학습할 때 인프런을 통해 많이 찾아보는 편인데 딱히 강의랄게 없어서 공식 홈페이지를 참고하거나 구글링과 유튜브의 힘을 빌려서 진행했다.  ( 처음 하는건데  따라 할만한 명확한 참고 문서를 못 찾아서 하다가 조금 늙었다 )

 

 

 

 

 

개발환경

OS : Mac OS 13.4 / Mac m2 
JDK : 17 

 

 

ES ( ElasticSearch)  다운로드 및 실행 

ES는 기본적으로 JVM 위에서 돌아가기 때문에, jdk는 설치되어 있어야 한다.   본 글에서는 jdk는 이미 설치되었다는 가정하에 글을 작성한다.

 

jdk를 설치했다면 두 번째로 해야 할 것은 ES 파일을 다운로드하는 것이다. 

 

https://www.elastic.co/guide/en/elasticsearch/reference/current/targz.html

 

Install Elasticsearch from archive on Linux or MacOS | Elasticsearch Guide [8.12] | Elastic

Typically, any cluster-wide settings (like cluster.name) should be added to the elasticsearch.yml config file, while any node-specific settings such as node.name could be specified on the command line.

www.elastic.co

 

 

 

하단 링크를 참고해서 가장 최신 버전인 18.2.2 버전( aarch64 )을 다운로드하여줬다.  ( 하지만 결국 나중에 문제가 생겨서 7.17.18로 다운그레이드 해서 재설치했다. ^_ㅠ  유튜브에 예제들도 대부분 7 버전이 많고 8 버전부터 SSL 도 default로 세팅되어 번거로우니 나처럼 처음 ES를 처음 사용해 보는 사람이라면 7 버전을 추천한다 )

 

원하는 위치에 파일을 이동시키고, 압축을 푼 뒤  bin 폴더에서./elasticsearch로  ES를 실행시킬 수 있다.

 

  • 실행 명령어
./bin/elasticsearch

 

  • 실행 결과
✅ Elasticsearch security features have been automatically configured!
✅ Authentication is enabled and cluster connections are encrypted.

ℹ️  Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
  Nh2hN*_m1UPZjiQikgPh

ℹ️  HTTP CA certificate SHA-256 fingerprint:
  eaa2ffa35a1e38e092e87ae456076fc1c609e2a4143ffe039d35ca0aa2f3e8d8

ℹ️  Configure Kibana to use this cluster:
• Run Kibana and click the configuration link in the terminal when Kibana starts.
• Copy the following enrollment token and paste it into Kibana in your browser (valid for the next 30 minutes):
  eyJ2ZXIiOiI4LjEyLjIiLCJhZHIiOlsiMTkyLjE2OC4xLjY6OTIwMCJdLCJmZ3IiOiJlYWEyZmZhMzVhMWUzOGUwOTJlODdhZTQ1NjA3NmZjMWM2MDllMmE0MTQzZmZlMDM5ZDM1Y2EwYWEyZjNlOGQ4Iiwia2V5IjoiSDVQTE5vNEJ1Nk82TzNuNU5XSnY6U0o5UnlVNE9USnk3bTBhSFZLUEh0USJ9

ℹ️  Configure other nodes to join this cluster:
• On this node:
  ⁃ Create an enrollment token with `bin/elasticsearch-create-enrollment-token -s node`.
  ⁃ Uncomment the transport.host setting at the end of config/elasticsearch.yml.
  ⁃ Restart Elasticsearch.
• On other nodes:
  ⁃ Start Elasticsearch with `bin/elasticsearch --enrollment-token <token>`, using the enrollment token that you generated.

 

 

ES의 default port는 9200  이므로 http://localhost:9200로 접속하면?

 

오류가 뜬다.

 

 

 

 

  • 오류 내용

curl: (52) Empty reply from server 

 

https로 접속해야 하는데 http로 접속해서 문제가 된 것 같아서 https://localhost:9200으로 접속했더니 user / password를 호출하는 창이 떴다. 

 

기본적으로는 user - elastic  / password - 실행 시 뜨는 Password 값을 입력하면 정상적으로 호출되는 것을 볼 수 있다.

 

 

 

하지만 매번 입력하기도 귀찮고 curl 호출할 때 설정해 주기 번거로워서 다음과 같이 설정파일을 변경했다.

 

 

  • 설정 파일 위치
/config/elasticsearch.yml

 

 

  • 체크한 부분을 false로 변경

 

  • ES 재실행 ( ctrl + c를 통해 종료할 수 있음 )

 

ES ( ElasticSearch)  Index 생성해 보기  - GET / PUT / DELETE

기본적으로 ES는 restfulAPI 통신을 통해 동작한다.  ES를 공부하다 보니까 RDB와 비교돼서 표현되는 경우가 많은데 간단하게 표로 나타내면 다음과 같다.

 

RestFul RDB
GET select
PUT update
POST insert
DELETE delete

 

 

  • GET으로 인덱스 조회하기 
curl -XGET http://localhost:9200/classes

 

위 내용으로 classes라는 인덱스에 대한 정보를 요청하면, 초기 요청이므로 classes 라는 인덱스가 없다고 오류가 발생한다.

 

  • PUT으로 인덱스 생성하기 

PUT을 통해 classes라는 인덱스를 생성하는 요청을 실행했다.

curl -XPUT http://localhost:9200/classes

 

정상적으로 실행 됐다면 아래와 같은 결과가 출력된다.

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "classes"
}


// GET http://localhost:9200/classes 재호출한 결과

{
    "classes": {
        "aliases": {},
        "mappings": {},
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "number_of_shards": "1",
                "provided_name": "classes",
                "creation_date": "1710318094329",
                "number_of_replicas": "1",
                "uuid": "Bm7VKC2dRSSP5wa_pfO3vA",
                "version": {
                    "created": "8500010"
                }
            }
        }
    }
}

 

 

  • DELETE로 인덱스 삭제하기 

PUT을 통해 생성한 인덱스를 DELETE를 통해 제거할 수 있다.

curl -XDELETE http://localhost:9200/classes

 

정상적으로 실행되었을 때 응답은 다음과 같다. 

{
    "acknowledged": true
}



// GET http://localhost:9200/classes 재호출한 결과
{
    "error": {
        "root_cause": [
            {
                "type": "index_not_found_exception",
                "reason": "no such index [classes]",
                "resource.type": "index_or_alias",
                "resource.id": "classes",
                "index_uuid": "_na_",
                "index": "classes"
            }
        ],
        "type": "index_not_found_exception",
        "reason": "no such index [classes]",
        "resource.type": "index_or_alias",
        "resource.id": "classes",
        "index_uuid": "_na_",
        "index": "classes"
    },
    "status": 404
}

 

DELETE를 통해 삭제했기 때문에 index_not_found_exception 이 발생한 것을 알 수 있다.

 

 

 

 

ES ( ElasticSearch)  Document 생성해 보기  -  POST

document는 주로 인덱스가 있을 때 생성하지만 인덱스가 없을 경우 인덱스명과 타입명을 명시하면 도큐먼트 생성이 바로 된다.

 

  • POST를 통해 Document 추가하기
curl -XPOST http://localhost:9200/classes/class/1/ -d '{"title" : "algorithm", "professor" : "John"}'

 

 

하지만 나는 안 됐다.

 

{"error":"no handler found for uri [/classes/class/1/] and method [POST]"}

 

야속하게도 이 오류가 계속 발생하면서 난관에 봉착했다.

 

오...안돼는걸?

 

 

구글링을 해도 EndPoint를 잘못 입력했다는 게 제일 많은 답변이었는데 내가 봤을 때 EndPoint는 문제가 없었고 ChatGPT 가 알려준 내용은 오늘 ES 걸음마를 시작한 내게는 큰 도움이 되지 못했다.

 

  • ChatGTP의 친절한 답변
더보기

"no handler found for uri" 오류는 Elasticsearch에서 URI에 대한 핸들러가 없을 때 발생합니다. 이 오류가 발생하는 경우에는 다음과 같은 몇 가지 가능한 원인이 있을 수 있습니다:

잘못된 URI: 요청한 URI가 올바른 Elasticsearch 엔드포인트를 가리키지 않을 수 있습니다. URI를 확인하고 올바른 엔드포인트를 지정하는지 확인하십시오.

올바른 HTTP 메서드: Elasticsearch 요청에 사용된 HTTP 메서드가 해당 엔드포인트에서 허용되지 않는 경우에도 이 오류가 발생할 수 있습니다. 예를 들어, GET 메서드로는 문서를 생성할 수 없습니다. 올바른 메서드를 사용하는지 확인하십시오.

권한 및 권한 부족: Elasticsearch 클러스터에서 요청을 실행하는 데 필요한 권한이 부족한 경우에도 이 오류가 발생할 수 있습니다. Elasticsearch에 필요한 권한을 부여하고 권한이 올바르게 구성되어 있는지 확인하십시오.

Elasticsearch 클러스터 상태: Elasticsearch 클러스터 자체의 문제로 인해 요청이 처리되지 않을 수 있습니다. 클러스터의 상태를 확인하고 문제가 있는지 확인하십시오.

잘못된 Elasticsearch 버전: 사용 중인 Elasticsearch 클러스터와 호환되지 않는 Elasticsearch 클라이언트 라이브러리를 사용하는 경우에도 이러한 유형의 오류가 발생할 수 있습니다. Elasticsearch 클러스터와 일치하는 버전의 클라이언트 라이브러리를 사용하는지 확인하십시오.

 

그래서 위에 적은 대로 버전을 낮췄더니 해결이 됐다.

 

  • 18.2.2  ->7.17.18로 다운그레이드 진행 

 

바로 된 것은 아니고

 

  {"error":"Content-Type header [application/x-www-form-urlencoded] is not supported", "status":406}

 

오류가 발생해서 curl 옵션에 -H를 추가해서 다음과 같이 호출하니 문제없이 동작했다.

 

curl -XPOST http://localhost:9200/classes/class/1/ -d '{"title" : "algorithm", "professor" : "John"}' -H 'Content-Type: application/json'

 

 

실행 결과는 다음과 같다

 

// GET classes/class/1 결과 _source 하위에 데이터가 들어간 모습을 확인할 수 있디

{
    "_index": "classes",
    "_type": "class",
    "_id": "1",
    "_version": 1,
    "_seq_no": 0,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "title": "algorithm",
        "professor": "John"
    }
}

 

 

 

ES ( ElasticSearch)  Document 수정해 보기  -  _update

 

  • _update를 통해서 document 수정하기 

_update 를 사용하면 지정한 인덱스에 있는 도큐먼트를 수정할 수 있다.

 

crul -XPOST http://localhost:9200/classes/class/1/_update -d '{"doc" : {"unit" 1}}' -H 'Content-Type: application/json'

 

실행 결과는 다음과 같다.

 

{
    "_index": "classes",
    "_type": "class",
    "_id": "1",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}




// GET http://localhost:9200/classes/class/1 로 확인한 모습
// _source 에 Unit 이 추가 된 것을 알 수 있음

{
    "_index": "classes",
    "_type": "class",
    "_id": "1",
    "_version": 2,
    "_seq_no": 1,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "title": "algorithm",
        "professor": "John",
        "unit": 1
    }
}

 

 

  • 스크립트를 사용해서 수정하기

제공하는 스크립트를 사용하면 데이터를 직접 지정하지 않고 수정도 가능하다.

 

curl -XPOST http://localhost:9200/classes/class/1/_update -d '{"script" : "ctx._source.unit +=5"}'

 

예를 들어 ctx._source.unit += 5라고 실행하면 결과는 다음과 같다.

{
    "_index": "classes",
    "_type": "class",
    "_id": "1",
    "_version": 4,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 3,
    "_primary_term": 1
}

// GET http://localhost:9200/classes/class/1

{
    "_index": "classes",
    "_type": "class",
    "_id": "1",
    "_version": 4,
    "_seq_no": 3,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "title": "algorithm",
        "professor": "John",
        "unit": 7
    }
}

 

 

결과 값을 보면 unit 이 7로 업데이트 된 것을 확인할 수 있다.  ( 중간에 내가 한번 더 unit : 2로 업데이트 실행을 진행해서 2 + 5 = 7 이 리턴됐다. )

 

 

 

ES ( ElasticSearch)  벌크(bulk) 사용하기 - _bulk

벌크를 사용하면 미리 작성해 둔 json 파일을 통해 데이터를 일괄로 업데이트할 수 있다.

 

  • 기본 명령어
curl -XPOST http://localhost:9200/_bulk?pretty --data-binary @[파일명.json] -H 'Content-Type: application/json'

 

  • 사용 예시
curl -XPOST http://localhost:9200/_bulk?pretty --data-binary @classes.json -H 'Content-Type: application/json'

 

 

ES ( ElasticSearch)  매핑(mapping) 사용하기  - _mapping

mapping을 사용하면 데이터를 시각화할 때 도움이 된다. 

 

  • 기본 명령어
curl -XPUT "http://localhost:9200/classes/class/_mapping' -d @[매핑기재파일명.json] -H 'ContentType: application/json'

 

 

  • 사용 예시
curl -XPUT 'http://localhost:9200/classes/class/_mapping' -d @classesRating_mapping.json 
-H 'Content-Type: application/json'

 

 

ES ( ElasticSearch)  검색 사용하기  - _search

_search를 사용해서 원하는 데이터를 조회할 수 있다.

 

  • 기본 명령어
http://localhost:9200/인덱스/도큐먼트/_search

http://localhost:9200/인덱스/도큐먼트/_search -d '검색할 request body' 지정

 

request body 에는 다양한 옵션이 제공되는데 상세 내용은 하단 링크를 참조 바란다.

 

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html

 

Request body search | Elasticsearch Guide [8.12] | Elastic

 

www.elastic.co

 

 

 

이상으로 ElasticSearch를 사용하기 위해 기본적으로 설치해 보고 restful 기반 요청을 보내서 index와 document를 생성하고 삭제해봤다.

 

 

나... 원하는 대로 구현할 수 있을까...?