본문 바로가기
elastic search

[elastic search] 엘라스틱 서치 mapping(매핑)이란(mapper_parsing_exception 이유)

by devjh 2022. 8. 29.
반응형

이번 게시글에서는 엘라스틱 서치의 매핑에 대해 정리합니다.(mapper_parsing_exception)

1. mapping이란

엘라스틱서치 매핑이란 인덱스에 어떤 필드는 어떤 형식의 데이터이니 어떠한 구조로 저장하겠다는 규칙입니다.
그러나 엘라스틱 써치는 인덱스와 json만 입력해주면 데이터를 저장할 수 있긴 합니다.
매핑을 하면 뭐가 좋고 안하면 뭐가 좋은지는, 아래의 예제로 확인하겠습니다.

// 저장
POST my_index/_doc
{
  "name": "Tom",
  "age": 1
}

POST my_index/_doc
{
  "name": "June",
  "age": 2
}

POST my_index/_doc
{
  "name": "John",
  "age": 1
}

저장 후 이름이 J로 시작하는 애들을 검색하면 조회가 잘 됩니다.

GET my_index/_search
{
  "query": {
    "query_string" : 
    {
      "default_field" : "name",
      "query" : "J*"
    }
  } 
}
{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "q1TK6IIBaVBQdg28vlbx",
        "_score" : 1.0,
        "_source" : {
          "name" : "June",
          "age" : 2
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "rFTL6IIBaVBQdg28Elby",
        "_score" : 1.0,
        "_source" : {
          "name" : "John",
          "age" : 1
        }
      }
    ]
  }
}

름을 개명한 친구가 있습니다.
이름이 두개인 칭구니 뎁스를 하나 더해서 key value 페어인 object로 저장해봅니다.

POST my_index/_doc
{
  "name": {"name1": "Bug", "name2": "Robben"},
  "age": 15
}

아래와 같은 에러가 떨어집니다.
name은 text타입인데 object를 넣으려고 했으니 받아주지 않는다는 소리입니다.

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "failed to parse field [name] of type [text] in document with id 'rlTQ6IIBaVBQdg2891ZG'"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "failed to parse field [name] of type [text] in document with id 'rlTQ6IIBaVBQdg2891ZG'",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "Can't get text on a START_OBJECT at 2:11"
    }
  },
  "status": 400
}

 

2. mapper_parsing_exception


아래의 명령어를 입력해 my_index의 매핑을 확인해보니
age필드는 long타입이 name필드는 text(string)필드로 매핑되어 있는것을 확인할 수 있습니다.
엘라스틱 서치는 스키마리스로 아무 json이나 저장할수 있다고 알려져있지만,
처음 들어오는 데이터를 기반으로 다이나믹매핑을 하게 됩니다.
처음 들어오는 데이터로 name필드는 string이라고 알고있었는데 갑자기 object가 들어와서 에러가 발생한 것입니다.

GET my_index/_mapping
-----------------------------------------
// 결과
{
  "my_index" : {
    "mappings" : {
      "_doc" : {
        "properties" : {
          "age" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  }
}

 

3. 에러제거 방법

같은 key에는 같은 value가 와야하지만 인덱스템플릿을 사용하여 에러를 피해갈 수도 있습니다.

아래와 같은 인덱스 템플릿을 을 생성합니다.
my_로 시작하는 index는 생성될때 dynamic 옵션을 껐으므로 age로만 매핑을 하게 되며 새로운 필드가 오더라도 자동매핑을 하지 않습니다.

PUT _template/my_template
{
  "index_patterns": "my_*",
  "mappings": {
     "server_log": {
       "dynamic": false,
      "properties" : {
        "age": {
          "type" : "long"
        }
      }
    }
  }
}

이제 개명한 친구와 그렇지 않은 친구 모두 저장할수 있습니다.

POST my_index/_doc
{
  "name": {"name1": "Bug", "name2": "Robben"},
  "age": 15
}

POST my_index/_doc
{
  "name": "John",
  "age": 15
}

대신 매핑이 되지 않았으므로 해당 필드로 검색이 힘들어집니다.(키바나 filter 역시 동작하지 않습니다)

GET my_index/_search
{
  "query": {
    "query_string" : 
    {
      "default_field" : "name",
      "query" : "J*"
    }
  } 
}

 

하나의 인덱스에서는 data type을 일시켜서 매핑을 시켜놔야 저장과 검색을 정상적으로 이용할 수 있습니다.

해당방법은 일부 필드를 매핑에서 제외시켜 검색이 안되는 대신 저장의 자유로움을 택한 방식입니다.

 

검색이 필요하다면 object(key, value) 타입을 es로 넣기전에 string으로 변경해서 넣으면 검색에서 사용할수 있으니

해당에러를 만나게 되면 효율적인 방법을 사용해 회피하도록 합니다.

반응형

댓글