[엘라스틱서치] 스키마(Schema) 등록하기
- 빅데이터 및 DB/검색엔진, 엘라스틱 스택
- 2020. 10. 16.
엘라스틱서치의 장점 중 하나는 바로 스키마리스(Schemaless)가 가능하다는 점이다. 이로 인해서 DB를 설계가 편리해지고 개발하는 과정에서 힘든 부분을 상쇄할 수 있다. 하지만 스키마리스는 양날의 검이 될 수 있는데 원치 않는 스키마로 인해서 색인이 이상하게 될 경우, 검색에 문제가 있거나 퍼포먼스 측면에서 떨어질 수 있다.
개발을 진행중에는 스키마를 등록하지 않고 진행할 수 있겠지만, 데이터 설계가 끝날 즈음에는 스키마를 등록하여 데이터 구조를 고정시키고 원하는 형태의 검색이 가능하게 만들어야 될 것이다.
Schemaless 케이스
우선 스키마리스의 문제부터 파악해보도록 한다. 다음과 같이 주식에 관련된 데이터를 검색엔진에 넣었다고 가정을 해본다.
PUT /stock/_doc/1
{
"stockId":"1",
"stockNm":"삼성전자",
"stockType":"보통주",
"stockCd":"005930",
"trade":"KOSPI",
"current":"59700",
"max":"62800",
"min":"42300",
"description":"삼성전자 주식회사는 전자 제품을 생산하며 정보통신기술에 대한 개발을 진행하고 있는 대한민국의 기업이다. 삼성전자는 삼성그룹 안에서도 가장 규모가 큰, 삼성그룹을 대표하는 기업이기도 하다. 본사는 경기도 수원시 영통구 삼성로 129 에 있다"
}
위와 같이 삼성전자에 관련된 주식 정보를 키바나(Kibana)를 이용해서 엘라스틱서치에 넣었다. 결과는 당연히 잘 생성되었고, 여기까지 보면 문제가 없어보인다.
{
"stock" : {
"aliases" : { },
"mappings" : {
"properties" : {
"current" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"description" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"max" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"min" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"stockCd" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"stockId" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"stockNm" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"stockType" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"trade" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1602814893565",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "d2mLrDURTBSDDvMIzezokA",
"version" : {
"created" : "7060299"
},
"provided_name" : "stock"
}
}
}
}
그러나 생성된 스키마를 보게 되면 모든 컬럼이 동일한 타입 "text"와 "keyword"로 입력이 된 것을 볼 수 있다. 여기에는 가격과 같은 숫자값 뿐만 아니라 숫자형태의 아이디 그리고 자연어 문장으로 된 설명까지 모두 동일한 컬럼으로 되어 있다.
기본적으로 텍스트와 키워드 멀티 구조의 형태로 되어 있어 공간이 낭비되고 있으며, 형태소 분석이 필요할 수 있는 description 컬럼에는 어떤 형태소 분석을 사용할 것인지 정의되어 있지 않고, 숫자값을 문자 형태로 색인되어 있어서 공간낭비 뿐만 아니라 숫자 검색의 장점을 사용할 수 없게 된다.
그러면, 이 스키마는 어떻게 등록하는 것이 좋은지 스키마를 별도로 등록해보도록 해보자.
Schema를 등록하는 경우
stock의 스키마를 등록
PUT /stock
{
"mappings":{
"_doc":{
"properties":{
"stockId":{"type" : "integer"},
"stockNm":{"type" : "keyword"},
"stockType":{"type" : "keyword"},
"stockCd":{"type" : "keyword"},
"trade":{"type" : "keyword"},
"current":{"type" : "integer"},
"max":{"type" : "integer"},
"min":{"type" : "integer"},
"description":{"type" : "text"}
}
}
}
}
stockId 숫자, 그리고 stockNm 등 trade까지는 키워드, 그리고 가격이 있는 current, max, min은 숫자값으로 설정하였다. 마지막 description은 형태소 분석을 위해 text로 설정을 하였다.
그러나 위의 스키마 등록을 시도하면 아래와 같이 에러가 떨어진다.
{
"error" : {
"root_cause" : [
{
"type" : "illegal_argument_exception",
"reason" : "The mapping definition cannot be nested under a type [_doc] unless include_type_name is set to true."
}
],
"type" : "illegal_argument_exception",
"reason" : "The mapping definition cannot be nested under a type [_doc] unless include_type_name is set to true."
},
"status" : 400
}
위와 같은 에러가 왜 발생하냐면 엘라스틱 버전이 7.x부터는 하나의 인덱스당 하나의 타입만 가능하기 때문에 발생하는 에러이다. 위에서 설정한 _doc을 제거해보도록 한다. (6.x이하는 위의 예시를 실행하면 에러가 발생하지 않을 것이다)
PUT /stock
{
"mappings":{
"properties":{
"stockId":{"type" : "integer"},
"stockNm":{"type" : "keyword"},
"stockType":{"type" : "keyword"},
"stockCd":{"type" : "keyword"},
"trade":{"type" : "keyword"},
"current":{"type" : "integer"},
"max":{"type" : "integer"},
"min":{"type" : "integer"},
"description":{"type" : "text"}
}
}
}
{
"error" : {
"root_cause" : [
{
"type" : "resource_already_exists_exception",
"reason" : "index [stock/mPb8Zm3kR0ef2e05zlOe_Q] already exists",
"index_uuid" : "mPb8Zm3kR0ef2e05zlOe_Q",
"index" : "stock"
}
],
"type" : "resource_already_exists_exception",
"reason" : "index [stock/mPb8Zm3kR0ef2e05zlOe_Q] already exists",
"index_uuid" : "mPb8Zm3kR0ef2e05zlOe_Q",
"index" : "stock"
},
"status" : 400
}
아직 실행이 되고 있진 않지만, 보다시피 다른 에러가 발생하며, 이미 인덱스가 존재한다고 표시되었다. 데이터 한건을 넣었을 때 스키마리스이지만 생성된 인덱스가 존재하기 때문인데 인덱스가 있을 경우 무조건 삭제를 해야 한다. 즉, 스키마를 지정할 때는 인덱스가 없는 상태에서 해야 한다는 의미이다.
DELETE /stock
{
"acknowledged" : true
}
위와 같이 인덱스를 삭제 한 후
PUT /stock
{
"mappings":{
"properties":{
"stockId":{"type" : "integer"},
"stockNm":{"type" : "keyword"},
"stockType":{"type" : "keyword"},
"stockCd":{"type" : "keyword"},
"trade":{"type" : "keyword"},
"current":{"type" : "integer"},
"max":{"type" : "integer"},
"min":{"type" : "integer"},
"description":{"type" : "text"}
}
}
}
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "stock"
}
인덱스를 실행하면 이제 인덱스가 생성되었다는 메세지가 뜨게 된다.
PUT /stock/_doc/1
{
"stockId":"1",
"stockNm":"삼성전자",
"stockType":"보통주",
"stockCd":"005930",
"trade":"KOSPI",
"current":"59700",
"max":"62800",
"min":"42300",
"description":"삼성전자 주식회사는 전자 제품을 생산하며 정보통신기술에 대한 개발을 진행하고 있는 대한민국의 기업이다. 삼성전자는 삼성그룹 안에서도 가장 규모가 큰, 삼성그룹을 대표하는 기업이기도 하다. 본사는 경기도 수원시 영통구 삼성로 129 에 있다"
}
{
"_index" : "stock",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
실패했던 레코드를 다시 추가하고
GET /stock
{
"stock" : {
"aliases" : { },
"mappings" : {
"properties" : {
"current" : {
"type" : "integer"
},
"description" : {
"type" : "text"
},
"max" : {
"type" : "integer"
},
"min" : {
"type" : "integer"
},
"stockCd" : {
"type" : "keyword"
},
"stockId" : {
"type" : "integer"
},
"stockNm" : {
"type" : "keyword"
},
"stockType" : {
"type" : "keyword"
},
"trade" : {
"type" : "keyword"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1602825001524",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "5eooVzvHQAWWKkC9to5cnA",
"version" : {
"created" : "7060299"
},
"provided_name" : "stock"
}
}
}
}
인덱스 정보를 호출하면, 등록된 스키마로 데이터가 들어가고 있다는 것을 알 수 있다.
'빅데이터 및 DB > 검색엔진, 엘라스틱 스택' 카테고리의 다른 글
[엘라스틱서치] 필수 옵션 설정하기 (elasticsearch.yml) (0) | 2021.05.28 |
---|---|
[엘라스틱서치] 검색하기 1편 (0) | 2020.11.03 |
엘라스틱서치 노드(Node)의 종류 (0) | 2020.09.16 |
[엘라스틱서치] 데이터 갱신(update)하기, PUT과 POST 비교 (0) | 2020.07.09 |
[엘라스틱서치] GET으로 데이터 가져오기 (0) | 2020.07.09 |