- Windows 10
- Elasticsearch 7.10.2
- Git Bash
<참고>
강의는 5.1.1 버전이며, 강의에서 진행한 실습 코드를 그대로 진행하여 document type이
_doc
이 아닌 custom type입니다.
한 번에 여러 데이터를 삽입하는 것을 Bulk
라고 하며, Elasticsearch에 Bulk 하는 방법에 대해 살펴보려 합니다.
실습 전, Document Bulk 데이터인 classes.json을 확인해보면 아래와 같이 한 데이터가 두 줄로 구성되어 있는 것을 볼 수 있습니다.
{ "index" : { "_index" : "classes", "_type" : "class", "_id" : "1" } }
{"title" : "Machine Learning","Professor" : "Subin Kim","major" : "Computer Science","semester" : ["spring", "fall"],"student_count" : 100,"unit" : 3,"rating" : 5, "submit_date" : "2020-01-02", "school_location" : {"lat" : 36.00, "lon" : -120.00}}
- 첫 번째 라인 : Meta Infomation
- 두 번째 라인 : Document 데이터
파일의 맨 마지막 줄에는 \n(enter)
가 반드시 추가되어야 합니다. 추가하지 않으면, The bulk request must be terminated by a newline [\\n]
에러가 발생합니다.
classes.json의 데이터와 같이 index
를 통해 데이터를 생성하거나 기존의 데이터를 수정을 할 때는 두 줄로 데이터를 구성해야 합니다. 마찬가지로 생성을 위한 create
나 수정을 위한 update
를 사용할 때도 두 줄로 데이터를 구성해야 합니다. 삭제를 하는 delete
를 사용할 때만 한 줄로 데이터를 구성합니다.
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : { "_index" : "test", "_id" : "1" } }
{ "doc" : { "field2" : "value2" } }
Bulk를 위해 구성한 데이터 파일은 아래 명령어를 통해 Elasticsearch 내에 Bulk를 수행할 수 있습니다.
curl -X POST {elasticsearch address}/_bulk --data-binary @{파일명}.json -H'Content-Type:application/json'
# e.g.
curl -X POST http://localhost:9200/_bulk?pretty --data-binary @classes.json -H 'Content-Type:application/json'
데이터가 제대로 들어갔는지 GET을 통해 조회해봅시다.
curl -X GET http://localhost:9200/classes/class/1?pretty
그러면 아래와 같이 데이터가 정상적으로 들어가있는 것을 확인할 수 있습니다.
{
"_index" : "classes",
"_type" : "class",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "Machine Learning",
"Professor" : "Subin Kim",
"major" : "Computer Science",
"semester" : [
"spring",
"fall"
],
"student_count" : 100,
"unit" : 3,
"rating" : 5,
"submit_date" : "2020-01-02",
"school_location" : {
"lat" : 36.0,
"lon" : -120.0
}
}
}
Mapping을 관계형 데이터베이스로 비유하면 Schema로 표현할 수 있습니다. 지금까지 진행했던 실습처럼 Mapping 없이 Elasticsearch의 데이터를 넣을 수 있으며, Mapping 정보를 강제하지 않습니다. Mapping을 직접 설정하지 않는 경우, Elasticsearch에서는 Json 데이터를 기반으로 타입을 Mapping해줍니다. 이를 Dynamic Mapping (다이나믹 매핑) 이라고 합니다.
Dynamic Mapping은 필드가 포함할 수 있는 가장 넓은 범위의 데이터 타입을 선택합니다. 예를 들어 age 필드 값은 0부터 100까지의 숫자가 들어간다고 할 때, int로도 충분하지만 Elasticsearch는 자연수 타입 중 가장 큰 long으로 타입을 지정합니다. 그리고 Json에서 사용하는 ISO8601 표준 날짜 형식의 데이터가 아닌 다른 포맷의 날짜는 text 타입으로 인식됩니다.
올바른 타입으로 설정하고 정확한 데이터를 Kibana 대시보드에 표출하고 분석하기 위해서는 Explict Mapping (명시적 매핑) 을 하는 것이 좋습니다. 지금부터 Explict Mapping에 대해 살펴볼 예정이며, 아래부터는 Explict Mapping을 Mapping이라고 표현하겠습니다.
Mapping 실습 진행 전, Bulk 실습 과정에서 생성된 classes 인덱스를 삭제해줍니다.
curl -X DELETE http://localhost:9200/classes?pretty
그 다음, classes 인덱스를 생성합니다.
curl -X PUT http://localhost:9200/classes?pretty
생성한 classes 인덱스를 GET으로 조회해봅시다.
curl -X GET http://localhost:9200/classes?pretty
그러면 아래와 같이 mapping
부분이 비어있는 것을 확인할 수 있습니다.
{
"classes" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"provided_name" : "classes",
"creation_date" : "1680496039096",
"number_of_replicas" : "1",
"uuid" : "dhteWlj-ReaKCcMpaRFDTg",
"version" : {
"created" : "7100299"
}
}
}
}
}
classesRating_mapping.json 파일에 미리 Mapping 할 정보를 추가한 다음, 아래 명령어를 통해 Mapping을 수행해봅시다.
curl -X PUT '{elasticsearch address}/{index name}/{index_type}/_mapping' -H 'Content-Type:application/json' -d @{파일명}.json
# e.g.
curl -X PUT 'http://localhost:9200/classes/class/_mapping?include_type_name=true&pretty' -H 'Content-Type:application/json' -d @classesRating_mapping.json
실습 명령어를 보면 include_type_name=true
가 존재하는데, 이는 7.x 버전 공식 문서에 나온 것처럼 무형식 API를 사용하기 위해서는 추가주어야 하는 명령어입니다.
추가한 Mapping이 적용되었는지 확인하기 위해 classes 인덱스를 GET으로 조회해봅시다.
curl -X GET http://localhost:9200/classes?pretty
그러면 아래와 같이 Mapping이 정상 적용된 것을 볼 수 있습니다.
{
"classes" : {
"aliases" : { },
"mappings" : {
"properties" : {
"major" : {
"type" : "text"
},
"professor" : {
"type" : "text"
},
"rating" : {
"type" : "integer"
},
"school_location" : {
"type" : "geo_point"
},
"semester" : {
"type" : "text"
},
"student_count" : {
"type" : "integer"
},
"submit_date" : {
"type" : "date",
"format" : "yyyy-MM-dd"
},
"title" : {
"type" : "text"
},
"unit" : {
"type" : "integer"
}
}
},
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"provided_name" : "classes",
"creation_date" : "1680496039096",
"number_of_replicas" : "1",
"uuid" : "dhteWlj-ReaKCcMpaRFDTg",
"version" : {
"created" : "7100299"
}
}
}
}
}
이제 이전에 학습한 Bulk를 통해 데이터를 추가할 때, 정상적으로 추가되는지 실행해봅시다.
curl -X POST http://localhost:9200/_bulk?pretty --data-binary @classes.json -H 'Content-Type:application/json'
데이터가 제대로 들어갔는지 GET을 통해 확인할 수 있습니다. (데이터는 위와 동일하게 표출되므로 여기서는 생략하겠습니다.)
curl -X GET http://localhost:9200/classes/class/1?pretty
Elasticsearch의 Search
기능에 대해 알아보기 전, 실습에 필요한 데이터를 Bulk 합니다.
curl -X POST http://localhost:9200/_bulk?pretty --data-binary @simple_basketball.json -H 'Content-Type:application/json'
simple_basketball.json
은 아래의 데이터로 구성되어 있습니다.
{ "index" : { "_index" : "basketball", "_type" : "record", "_id" : "1" } }
{"team" : "Chicago Bulls","name" : "Subin Kim", "points" : 30,"rebounds" : 3,"assists" : 4, "submit_date" : "2023-04-03"}
{ "index" : { "_index" : "basketball", "_type" : "record", "_id" : "2" } }
{"team" : "Chicago Bulls","name" : "Subin Kim","points" : 20,"rebounds" : 5,"assists" : 8, "submit_date" : "2023-04-03"}
먼저, 옵션 없이 Search
명령어를 사용하는 방법에 대해 알아봅시다.
curl -X GET {elasticsearch address}/{index name}/{document type}/_search
# e.g.
curl -X GET http://localhost:9200/basketball/record/_search?pretty
참고로 7.0 버전부터는 Document Type에 대한 개념이 사라져서 명령어 입력 시 document type에 대해 입력할 필요가 없습니다.
curl -X GET {elasticsearch address}/{index name}/_search
이렇게 옵션 없이 명령어를 입력하면 모든 결과를 출력합니다.
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "basketball",
"_type" : "record",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"team" : "Chicago Bulls",
"name" : "Subin Kim",
"points" : 30,
"rebounds" : 3,
"assists" : 4,
"submit_date" : "2023-03-20"
}
},
{
"_index" : "basketball",
"_type" : "record",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"team" : "Chicago Bulls",
"name" : "Subin Kim",
"points" : 20,
"rebounds" : 5,
"assists" : 8,
"submit_date" : "2023-04-03"
}
}
]
}
}
Search 명령 URI 내에 QueryString을 추가하여 Search Option을 설정할 수 있습니다. 마찬가지로, 위에서 설명한 것처럼 7.0 버전부터는 document type에 대해 입력할 필요가 없습니다.
curl -X GET {elasticsearch address}/{index name}/{document type}/_search?q={value}
# e.g.
curl -X GET 'http://localhost:9200/basketball/record/_search?q=points:30&pretty'
실습 명령어를 실행해보면 points가 30인 document에 대해서만 출력하는 것을 확인할 수 있습니다.
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "basketball",
"_type" : "record",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"team" : "Chicago Bulls",
"name" : "Subin Kim",
"points" : 30,
"rebounds" : 3,
"assists" : 4,
"submit_date" : "2023-03-20"
}
}
]
}
}
Search에는 Request Body에 Option을 넣어 실행하는 방법도 존재합니다. 위의 URI 내에 Optino을 추가하는 Querystring을 Request Body 내에 Option을 설정하는 QueryDSL로 변경하였습니다. 참고로, RequesgBody는 json 구조이기 때문에 {}
아닌 <<>>
로 사용자 입력 값을 표시하였습니다.
curl -X GET '{elasticsearch address}/{index name}/{document type}/_search' -H 'Content-Type: application/json' -d '
{
"query": {
"<<query>>" : {
"field": <<value>>
}
}
}'
# e.g.
curl -X GET 'http://localhost:9200/basketball/record/_search?pretty' -H 'Content-Type: application/json' -d '
{
"query" : {
"term" : {
"points" : 30
}
}
}'
사용할 수 있는 Query는 여러 개가 존재하는데, 여기서는 term
을 사용하여 실습을 진행했습니다. 다른 Query에 대해 알고 싶다면 공식문서를 참고하길 바랍니다.
본 게시글은 ELK 스택 (ElasticSearch, Logstash, Kibana) 으로 데이터 분석 강의를 참고하여 작성되었습니다.
상세한 내용이 궁금하시다면 강의 수강을 추천해 드립니다.
- 추가로 참고한 링크
- https://www.devkuma.com/docs/elasticsearch/crud/#bulk-api%EC%9D%BC%EA%B4%84-%EC%B2%98%EB%A6%AC
- https://esbook.kimjmin.net/07-settings-and-mappings/7.2-mappings
- https://jun108059.github.io/til/ElasticSearch/05.ElasticSearch.html#_2-mapping-%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%A5%E1%86%BC%E1%84%92%E1%85%A1%E1%84%80%E1%85%B5
- https://esbook.kimjmin.net/04-data/4.4-_search