4.2 CRUD - 입력, 조회, 수정, 삭제

이 문서의 허가되지 않은 무단 복제나 배포 및 출판을 금지합니다. 본 문서의 내용 및 도표 등을 인용하고자 하는 경우 출처를 명시하고 김종민(kimjmin@gmail.com)에게 사용 내용을 알려주시기 바랍니다.

Elasticsearch에서는 단일 도큐먼트별로 고유한 URL을 갖습니다. 도큐먼트에 접근하는 URL은

http://<호스트>:<포트>/<인덱스>/_doc/<도큐먼트 id>

구조로 되어 있습니다. 6.x 이전 까지는

http://<호스트>:<포트>/<인덱스>/<도큐먼트 타입>/<도큐먼트 id>

구조였으나, Elasticsearch 7.0 부터는 도큐먼트 타입 개념이 사라지고 대신 고정자 _doc 으로 접근해야 합니다. 다음은 curl 도구를 이용해서 my_index 인덱스에 도큐먼트 id가 1인 데이터를 입력하는 예제입니다.

my_index/_doc/1 에 도큐먼트 입력
$ curl -XPUT "http://localhost:9200/my_index/_doc/1" -H 'Content-Type: application/json' -d'
{
"name": "Jongmin Kim",
"message": "안녕하세요 Elasticsearch"
}'
{"_index":"my_index","_type":"_doc","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}

이후부터는 elasticsearch의 REST 명령들은 Kibana의 Dev Tools 에서 입력하는 형식으로 설명하도록 하겠습니다. 입력은 reqest 탭, 그리고 응답은 response 탭에 표기하도록 하겠습니다.

입력 (PUT)

데이터 입력을 할 때는 PUT 메서드를 이용합니다. 다음은 Kibana 에서 my_index 인덱스에 도큐먼트 id가 1인 데이터를 입력하는 예제입니다.

request
response
request
my_index/_doc/1 최초 입력
PUT my_index/_doc/1
{
"name":"Jongmin Kim",
"message":"안녕하세요 Elasticsearch"
}
response
my_index/_doc/1 최초 입력 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}

처음으로 도큐먼트를 입력하면 결과에 "result" : "created" 로 표시가 됩니다. 동일한 URL에 다른 내용의 도큐먼트를 다시 입력하게 되면 기존 도큐먼트는 삭제되고 새로운 도큐먼트로 덮어씌워지게 됩니다. 이 때는 결과에 created가 아닌 updated가 표시됩니다.

request
response
request
my_index/_doc/1 재입력
PUT my_index/_doc/1
{
"name":"Jongmin Kim",
"message":"안녕하세요 Kibana"
}
response
my_index/_doc/1 재입력 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}

실수로 기존 도큐먼트가 덮어씌워지는 것을 방지하기 위해서는 입력 명령에 _doc 대신 _create 를 사용해서 새로운 도큐먼트의 입력만 허용하는 것이 가능합니다. 입력하려는 도큐먼트 id에 이미 데이터가 있는 경우 아래와 같이 입력 오류가 나게 됩니다. 6.x 이전 버전에서는 PUT <인덱스>/<도큐먼트 타입>/<도큐먼트 id>/_create 형식으로 사용합니다.

request
response
request
_doc 대신 _create 로 새 도큐먼트 입력
PUT my_index/_create/1
{
"name":"Jongmin Kim",
"message":"안녕하세요 Elasticsearch"
}
response
이미 있는 도큐먼트인 경우 _create 명령 실행 불가
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, document already exists (current version [2])",
"index_uuid": "qYOJI9ELR2-HqVtgTeI9jw",
"shard": "0",
"index": "my_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, document already exists (current version [2])",
"index_uuid": "qYOJI9ELR2-HqVtgTeI9jw",
"shard": "0",
"index": "my_index"
},
"status": 409
}

조회 (GET)

GET 메서드로 가져올 도큐먼트의 URL을 입력하면 도큐먼트의 내용을 가져옵니다. 다양한 정보가 함께 표시되며 문서의 내용은 _source 항목에 나타납니다.

request
response
request
my_index/_doc/1 도큐먼트 조회
GET my_index/_doc/1
response
my_index/_doc/1 도큐먼트 조회 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "Jongmin Kim",
"message" : "안녕하세요 Elasticsearch"
}
}

삭제 (DELETE)

DELETE 메서드를 이용해서 도큐먼트 또는 인덱스 단위의 삭제가 가능합니다. 두 경우에 차이가 있는데 먼저 DELETE my_index/_doc/1 명령으로 하나의 도큐먼트를 삭제하면 다음과 같이 도큐먼트가 삭제되었다는 "result" : "deleted" 결과가 리턴됩니다.

request
response
request
my_index/_doc/1 도큐먼트 삭제
DELETE my_index/_doc/1
response
my_index/_doc/1 도큐먼트 삭제 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}

도큐먼트는 삭제되었지만 인덱스는 남아있는 경우 삭제된 도큐먼트를 GET 해서 가져오려고 하면 아래와 같이 my_index/_doc/1 도큐먼트를 못 찾았다는 "found" : false 응답을 받습니다. 인덱스는 있으나 입력되지 않은 조회할 때도 마찬가지 입니다.

request
response
request
삭제된 my_index/_doc/1 도큐먼트 조회
GET my_index/_doc/1
response
삭제된 my_index/_doc/1 도큐먼트 조회 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"found" : false
}

이제 DELETE my_index 으로 전체 인덱스를 삭제하면 다음과 같이 "acknowledged" : true 응답만 리턴됩니다.

request
response
request
my_index 인덱스 전체 삭제
DELETE my_index
response
my_index 인덱스 전체 삭제 결과
{
"acknowledged" : true
}

삭제된 인덱스 또는 처음부터 없는 인덱스의 도큐먼트를 조회하려고 하면 도큐먼트를 못 찾았다는 "found" : false 응답이 아니라 다음과 같이 "type" : "index_not_found_exception" , "status" : 404 오류가 리턴됩니다.

request
response
request
삭제된 my_index 인덱스의 도큐먼트 조회
GET my_index/_doc/1
response
삭제된 my_index 인덱스의 조회 결과
{
"error" : {
"root_cause" : [
{
"type" : "index_not_found_exception",
"reason" : "no such index [my_index]",
"resource.type" : "index_expression",
"resource.id" : "my_index",
"index_uuid" : "_na_",
"index" : "my_index"
}
],
"type" : "index_not_found_exception",
"reason" : "no such index [my_index]",
"resource.type" : "index_expression",
"resource.id" : "my_index",
"index_uuid" : "_na_",
"index" : "my_index"
},
"status" : 404
}

수정 (POST)

POST 메서드는 PUT 메서드와 유사하게 데이터 입력에 사용이 가능합니다. 도큐먼트를 입력할 때 POST 메서드로 <인덱스>/_doc 까지만 입력하게 되면 자동으로 임의의 도큐먼트id 가 생성됩니다. 도큐먼트id의 자동 생성은 PUT 메서드로는 동작하지 않습니다.

request
response
request
POST 명령으로 my_index/_doc 도큐먼트 입력
POST my_index/_doc
{
"name":"Jongmin Kim",
"message":"안녕하세요 Elasticsearch"
}
response
POST 명령으로 도큐먼트 입력 결과 - 도큐먼트 아이디 자동 생성
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "ZuFv12wBspWtEG13dOut",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}

위 결과에서 도큐먼트 id "_id" : "ZuFv12wBspWtEG13dOut" 가 자동 생성 된 것을 확인할 수 있습니다.

_update

입력된 도큐먼트를 수정하기 위해서는 기존 도큐먼트의 URL에 변경될 내용의 도큐먼트 내용을 다시 PUT 하는 것으로 대치가 가능합니다. 하지만 필드가 여럿 있는 도큐먼트에서 필드 하나만 바꾸기 위해 전체 도큐먼트 내용을 매번 다시 입력하는 것은 번거로운 작업일 것입니다. 이 때는 POST <인덱스>/_update/<도큐먼트 id> 명령을 이용해 원하는 필드의 내용만 업데이트가 가능합니다. 업데이트 할 내용에 "doc" 이라는 지정자를 사용합니다.

_update API를 이용해서 my_index/_doc/1 도큐먼트의 "message" 필드 값을 "안녕하세요 Kibana" 로 업데이트를 한 뒤 도큐먼트 내용을 확인 해 보겠습니다. my_index/_doc/1 도큐먼트를 삭제 하였다면 위의 입력 (PUT) 내용을 참고해서 새로 입력 한 뒤 아래 명령을 실행합니다.

request
response
request
my_index/_update/1 도큐먼트의 message 필드 업데이트
POST my_index/_update/1
{
"doc": {
"message":"안녕하세요 Kibana"
}
}
response
my_index/_update/1 도큐먼트의 message 필드 업데이트 실행 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}

이제 다시 GET 명령으로 my_index/_doc/1 도큐먼트를 조회 해 보면 message 필드가 "안녕하세요 Kibana" 로 변경 된 것을 확인할 수 있습니다.

request
response
request
message 필드 업데이트 후 도큐먼트 확인
GET /my_index/_doc/1
response
message 필드 업데이트 후 도큐먼트 확인 결과
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "Jongmin Kim",
"message" : "안녕하세요 Kibana"
}
}

위 결과를 보면 "_version" : 2로 버전이 증가한 것을 확인할 수 있습니다. _update API 를 사용해서 단일 필드만 수정하는 경우에도 실제로 내부에서는 도큐먼트 전체 내용을 가져와서 _doc 에서 지정한 내용을 변경한 새 도큐먼트를 만든 뒤 전체 내용을 다시 PUT 으로 입력하는 작업을 진행합니다.

6.x 이전 버전에서 _update API 는 POST <인덱스>/<도큐먼트 타입>/<도큐먼트 id>/_update 형식으로 사용합니다.