Elastic 가이드북
  • Elastic 가이드 북
  • 1. 서문
    • 1.1 Elastic Stack 소개
      • 1.1.1 Elasticsearch
      • 1.1.2 Logstash
      • 1.1.3 Kibana
      • 1.1.4 Beats
  • 2. Elasticsearch 시작하기
    • 2.1 데이터 색인
    • 2.2 설치 및 실행
      • 2.2.1 다운로드 설치 및 실행
      • 2.2.2 Unix RPM (yum) 설치 및 실행
      • 2.2.3 윈도우 운영체제에서 MSI 파일로 설치
    • 2.3 elasticsearch 환경 설정
      • 2.3.1 jvm.options
      • 2.3.2 elasticsearch.yml
      • 2.3.3 노드의 역할 : master, data, ingest, ml
      • 2.3.4 커맨드 라인 설정
  • 3. Elasticsearch 시스템 구조
    • 3.1 클러스터 구성
    • 3.2 인덱스와 샤드 - Index & Shards
    • 3.3 마스터 노드와 데이터 노드 - Master & Data Nodes
  • 4. Elasticsearch 데이터 처리
    • 4.1 REST API
    • 4.2 CRUD - 입력, 조회, 수정, 삭제
    • 4.3 벌크 API - _bulk API
    • 4.4 검색 API - _search API
  • 5. 검색과 쿼리 - Query DSL
    • 5.1 풀 텍스트 쿼리 - Full Text Query
    • 5.2 Bool 복합 쿼리 - Bool Query
    • 5.3 정확도 - Relevancy
    • 5.4 Bool : Should
    • 5.5 정확값 쿼리 - Exact Value Query
    • 5.6 범위 쿼리 - Range Query
  • 6. 데이터 색인과 텍스트 분석
    • 6.1 역 인덱스 - Inverted Index
    • 6.2 텍스트 분석 - Text Analysis
    • 6.3 애널라이저 - Analyzer
      • 6.3.1 _analyze API
      • 6.3.2 Term 쿼리
      • 6.3.3 사용자 정의 애널라이저 - Custom Analyzer
      • 6.3.4 텀 벡터 - _termvectors API
    • 6.4 캐릭터 필터 - Character Filter
      • 6.4.1 HTML Strip
      • 6.4.2 Mapping
      • 6.4.3 Pattern Replace
    • 6.5 토크나이저 - Tokenizer
      • 6.5.1 Standard, Letter, Whitespace
      • 6.5.2 UAX URL Email
      • 6.5.3 Pattern
      • 6.5.4 Path Hierarchy
    • 6.6 토큰 필터 - Token Filter
      • 6.6.1 Lowercase, Uppercase
      • 6.6.2 Stop
      • 6.6.3 Synonym
      • 6.6.4 NGram, Edge NGram, Shingle
      • 6.6.5 Unique
    • 6.7 형태소 분석 - Stemming
      • 6.7.1 Snowball
      • 6.7.2 노리 (nori) 한글 형태소 분석기
  • 7. 인덱스 설정과 매핑 - Settings & Mappings
    • 7.1 설정 - Settings
    • 7.2 매핑 - Mappings
      • 7.2.1 문자열 - text, keyword
      • 7.2.2 숫자 - long, double ...
      • 7.2.3 날짜 - date
      • 7.2.4 불리언 - boolean
      • 7.2.5 Object 와 Nested
      • 7.2.6 위치 정보 - Geo
      • 7.2.7 기타 필드 타입 - IP, Range, Binary
    • 7.3 멀티 (다중) 필드 - Multi Field
  • 8. 집계 - Aggregations
    • 8.1 메트릭 - Metrics Aggregations
    • 8.2 버킷 - Bucket Aggregations
    • 8.3 하위 - sub-aggregations
    • 8.4 파이프라인 - Pipeline Aggregations
Powered by GitBook
On this page
  • Object
  • Nested

Was this helpful?

  1. 7. 인덱스 설정과 매핑 - Settings & Mappings
  2. 7.2 매핑 - Mappings

7.2.5 Object 와 Nested

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

Object

JSON 에서는 한 필드 안에 하위 필드를 넣는 object, 즉 객체 타입의 값을 사용할 수 있습니다. 보통은 한 요소가 여러 하위 정보를 가지고 있는 경우 object 타입 형태로 사용합니다. 다음은 movie 인덱스에 하위 필드 "name", "age", "side" 를 가진 object 타입 "characters" 필드의 예제입니다.

object 타입 characters 필드를 가진 도큐먼트
PUT movie/_doc/1
{
  "characters": {
    "name": "Iron Man",
    "age": 46,
    "side": "superhero"
  }
}

object 필드를 선언 할 때는 다음과 같이 "properties" 를 입력하고 그 아래에 하위 필드 이름과 타입을 지정합니다.

매핑에 object 타입 characters 필드 선언
PUT movie
{
  "mappings": {
    "properties": {
      "characters": {
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "byte"
          },
          "side": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

object 필드를 쿼리로 검색 하거나 집계를 할 때는 다음과 같이 마침표 . 를 이용해서 하위 필드에 접근합니다.

characters 하위의 name 필드 쿼리
GET movie/_search
{
  "query": {
    "match": {
      "characters.name": "Iron Man"
    }
  }
}
characters 하위의 name 필드 쿼리 결과
{
  "took" : 262,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "movie",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "characters" : {
            "name" : "Iron Man",
            "age" : 46,
            "side" : "superhero"
          }
        }
      }
    ]
  }
}

Elasticsearch에는 따로 배열(array) 타입의 필드를 선언하지 않습니다. 필드 타입의 값만 일치하면 다음과 같이 값을 배열로도 넣을 수 있습니다.

  • { "title": "Romeo and Juliet" }

  • { "title": [ "Romeo and Juliet", "Hamlet" ] }

이번에는 다음과 같이 title 필드 값이 각각 "The Avengers", "Avengers: Infinity War" 이고 characters 필드에 object 값이 2개씩 들어있는 두 개의 도큐먼트를 입력 해 보겠습니다.

characters 필드에 2개의 ojbect 값들을 배열로 가진 도큐먼트 2개 입력
PUT movie/_doc/2
{
  "title": "The Avengers",
  "characters": [
    {
      "name": "Iron Man",
      "side": "superhero"
    },
    {
      "name": "Loki",
      "side": "villain"
    }
  ]
}

PUT movie/_doc/3
{
  "title": "Avengers: Infinity War",
  "characters": [
    {
      "name": "Loki",
      "side": "superhero"
    },
    {
      "name": "Thanos",
      "side": "villain"
    }
  ]
}

두 개 도큐먼트 모두 characters 필드의 하위 필드 값으로 "name": "Loki" 가 있습니다. 그리고 한 도큐먼트는 "name": "Loki" 의 "side" 필드 값이 "villain" 이고 다른 도큐먼트는 "superhero" 입니다. 이제 characters 필드의 name 값은 "Loki" 이고 side 값은 "villain" 인 도큐먼트를 검색 해 보겠습니다.

characters 하위 필드의 name: Loki, side: villain 검색
GET movie/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "characters.name": "Loki"
          }
        },
        {
          "match": {
            "characters.side": "villain"
          }
        }
      ]
    }
  }
}
characters 하위 필드의 name: Loki, side: villain 검색 결과
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0611372,
    "hits" : [
      {
        "_index" : "movie",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0611372,
        "_source" : {
          "title" : "Avengers: Infinity War",
          "characters" : [
            {
              "name" : "Loki",
              "side" : "superhero"
            },
            {
              "name" : "Thanos",
              "side" : "villain"
            }
          ]
        }
      },
      {
        "_index" : "movie",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.9827781,
        "_source" : {
          "title" : "The Avengers",
          "characters" : [
            {
              "name" : "Iron Man",
              "side" : "superhero"
            },
            {
              "name" : "Loki",
              "side" : "villain"
            }
          ]
        }
      }
    ]
  }
}

분명 {"name": "Loki", "side": "villain"} 값을 포함하고 있는 도큐먼트는 "_id" : "2" 인 "title": "The Avengers" 도큐먼트 뿐인데 {"name": "Loki", "side": "superhero"} 를 포함하고 있는 "title": "Avengers: Infinity War" 도큐먼트도 같이 검색이 되었습니다. (심지어 스코어도 더 높습니다)

얼핏 생각했을 때는 "title": "The Avengers" 도큐먼트만 검색이 되어야 맞는 것으로 생각이 되는데 실제 결과는 그렇지가 않습니다. 이유는 Elasticsearch는 위 예제에서 역 색인을 다음과 같은 모양으로 생성하기 때문입니다. 기억하세요. 역 색인은 필드 별로 생성됩니다.

역 색인에서는 object 필드의 하위 필드들은 모두 상위 필드의 이름과 함께 펼쳐져서 한 필드로 저장이 됩니다. 그렇기 때문에 "characters.name": "Loki", "characters.side": "villain" 두 필드값들은 "_id" : "2" , "_id" : "3" 두 도큐먼트 모두를 리턴합니다.

Nested

만약에 object 타입 필드에 있는 여러 개의 object 값들이 서로 다른 역 색인 구조를 갖도록 하려면 nested 타입으로 지정해야 합니다. nested 타입으로 지정하려면 매핑에 다음과 같이 "type": "nested" 를 명시합니다. 다른 부분은 object 와 동일합니다.

매핑에 nested 타입 characters 필드 선언
PUT movie
{
  "mappings": {
    "properties": {
      "characters": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text"
          },
          "side": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

입력할 데이터는 의 object 예제에서 입력 한 데이터와 동일합니다. 매핑을 위와 같이 nested 형식으로 선언하고 앞에서 했던 title 필드 값이 각각 "The Avengers", "Avengers: Infinity War" 이고 characters 필드에 object 값이 2개씩 들어있는 두 개의 도큐먼트를 다시 한번 입력 해 보도록 합니다. 그 뒤 다시 characters 필드의 name 값은 "Loki" 이고 side 값은 "villain" 인 도큐먼트를 검색 해 보도록 합니다.

characters 하위 필ㄹ드의 name: Loki, side: villain 검색
GET movie/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "characters.name": "Loki"
          }
        },
        {
          "match": {
            "characters.side": "villain"
          }
        }
      ]
    }
  }
}
characters 하위 필ㄹ드의 name: Loki, side: villain 검색 결과
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

검색 결과가 하나도 나타나지 않았습니다.

nested 필드를 검색 할 때는 반드시 nested 쿼리를 써야 합니다. nested 쿼리 안에는 path 라는 옵션으로 nested로 정의된 필드를 먼저 명시하고 그 안에 다시 쿼리를 넣어서 입력합니다.

nested 쿼리로 characters 하위 필드의 name: Loki, side: villain 검색
GET movie/_search
{
  "query": {
    "nested": {
      "path": "characters",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "characters.name": "Loki"
              }
            },
            {
              "match": {
                "characters.side": "villain"
              }
            }
          ]
        }
      }
    }
  }
}
nested 쿼리로 characters 하위 필드의 name: Loki, side: villain 검색 결과
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.4480599,
    "hits" : [
      {
        "_index" : "movie",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.4480599,
        "_source" : {
          "title" : "The Avengers",
          "characters" : [
            {
              "name" : "Iron Man",
              "side" : "superhero"
            },
            {
              "name" : "Loki",
              "side" : "villain"
            }
          ]
        }
      }
    ]
  }
}

결과로 {"name" : "Loki", "side" : "villain"} 값을 포함하고 있는 "_id" : "2" 도큐먼트만 검색이 되었습니다.

nested 쿼리로 검색하면 nested 필드의 내부에 있는 값 들을 모두 별개의 도큐먼트로 취급합니다. 앞의 예제에서 본 object 도큐먼트와 nested 도큐먼트를 그림으로 비교 해 보면 다음과 같습니다.

object 필드 값들은 실제로 하나의 도큐먼트 안에 전부 포함되어 있습니다. 반면에 nested 필드 값들은 내부적으로 별도의 도큐먼트로 분리되어 저장되며 쿼리 결과에서 상위 도큐먼트와 합쳐져서 보여지게 됩니다.

Previous7.2.4 불리언 - booleanNext7.2.6 위치 정보 - Geo

Last updated 5 years ago

Was this helpful?

characters 하위 필드들의 역 색인 구조