Nested field에 대한 대체 필드 flattened type
데이터베이스/Elasticsearch

Nested field에 대한 대체 필드 flattened type

반응형

일반적으로 하나의 공통 Document내에 서로 다른 속성을 가지고 있어서 별도의 Document인 것 처럼 저장하고 query하기 위해서 우리는 nested obejct 타입을 많이 사용한다. 

 

사용했었던 예로는 가게 - 메뉴, 상품 - 아이템 정도이다.

 

하지만 nested 필드의 개수만큼 내부적으로 별도의 도큐먼트로 분리되어 저장이 되고 쿼리 시 상위 도큐먼트와 합쳐져서 보여줘야하는 등에 여러 이유로 nested 필드는 많이 느리다. 

 

Elasticsearch nested type설명에도 flattened type을 고려해보라고 써있는거 보면 얼마나 좋지 못한지 사용해보지 않아도 가늠해 볼 수 있다. (실사용에서도 퍼포먼스를 극대화 해도 쉽지 않았다.)

https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html

 

그래서 성능이슈를 해결해보고자 찾던 중 7.3 버전부터 나왔던 flattened type을 찾았고 사용할 수 있을 지 리서치를 해봤다.

 

 

 

Flattend Data Type


기본적으로 object 내부에 subfielde들은 별도로 매핑이 된다. 만약에 미리 정의하지 않은 이름과 타입들이 들어오게 되면 그들은 dynamic mapping이 되어 인덱싱이 된다.

 

flattened 타입은 하나의 필드로써 매핑되는 object타입의 대체로써 사용이 가능하다. flattend 매핑타입으로 object가 입력 될 경우 leaf value를 파싱해서 키워드로 하나의 필드로써 인덱싱을 진행한다.

이렇게 매핑된 object 들은 query와 aggregation의 형태로 사용이 가능하다.

 

이 데이터 타입은 unique 키 수가 많거나 정확하게 알 지 못하는 개체를 인덱싱하는데 유용할 수 있다. json object에 대해서 하나의 필드 매핑으로 대응이 가능하기 때문에 매핑 급증으로 인해 고유한 필드 매핑이 너무 많이 발생하는 것을 방지할 수 있다.

 

반대로 flattened object 필드는 검색 기능 부분에서 오직 기본적인 쿼리만 사용이 가능하거나 숫자 range 쿼리나 하이라이팅 기능을 할 수 없는 trade off가 발생된다. 

 

추가적으로 제한되는 기능에 대해서는 이곳에서 확인이 가능하다. (https://www.elastic.co/guide/en/elasticsearch/reference/7.x/flattened.html)

flattened mapping type은 키워드로써 매핑하기 하고 풀 텍스트 검색을 기능적으로 제공하지 않기 때문에 모든 문서에 내용을 flattened 타입으로 매핑하면 안된다.

기본적으로 매핑에 고유한 항목을 가지고 있는 서브필드들의 경우는 동작한다.

 

PUT bug_reports
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "labels": {
        "type": "flattened"
      }
    }
  }
}

POST bug_reports/_doc/1
{
  "title": "Results are not sorted correctly.",
  "labels": {
    "priority": "urgent",
    "release": ["v1.2.5", "v1.3.0"],
    "timestamp": {
      "created": 1541458026,
      "closed": 1541457010
    }
  }
}


// 특정 필드의 value에 대한 값 정상 조회 가능
GET bug_reports/_search
{
  "query": {
    "term": {
      "labels.priority": "urgent"
    }
  }
}

// 모든 leaf 값들을 토큰으로 매핑하고 있기 때문에 아래와 같은 방식으로도 조회 가능
GET bug_reports/_search
{
  "query": {
    "term": {"labels": "urgent"}
  }
}

인덱싱 json object 각각의 leaf value들은 토큰을 생성한다. 토큰은 어떤 analysis 적용되지 않고 number, date 같은 특별한 데이터 타입으로 매핑되지 않고 오직 키워드로써 매핑된다.

 

 

Support Operations


키워드 필드 매핑과 비슷한 방식으로 매핑이 되기 때문에 flattened 필드도 동일한 검색 기능을 많이 사용된다.

 

최근에는 flattened 필드는 아래 쿼리 타입도 지원한다.

  • term, terms, and terms_set
  • prefix
  • range
  • match and multi_match
  • query_string and simple_query_string
  • exists

 

와일드 카드 쿼리는 지원하지 않는다. range를 포함한 모든 쿼리는 string keyword로만 적용이 된다. 하지만 highlighting은 지원되지 않는다. 정렬은 문자열 정렬 정도 지원하고 숫자와 같은 타입은 지원되지 않는다. 그리고 terms와 같은 간단한 스타일의 aggregation을 지원한다.  

 

flattened object 현재 저장할 없기 때문에 store parameter 매핑할 없다.

 

 

 

Flattened field 검색 


field를 사용하여 구체적인 하위필드의 값을 검색할 수 있다. 

flattened field는 많은 서브 필드들을 하나의 싱글 필드로써 매핑을 하기 때문에 _source로 부터 일관된 구조의 응답을 받는다. 

 

하지만 request flattened 필드 내부에 specific field 지정해서 가지고 있다.

// query
GET bug_reports/_search
{
  "_source": "labels.priority", 
  "query": {
    "term": {"labels": "urgent"}
  }
}


// response
{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.42763555,
    "hits" : [
      {
        "_index" : "bug_reports",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.42763555,
        "_source" : {
          "labels" : {
            "priority" : "urgent"
          }
        }
      }
    ]
  }
}

또한 doc['labels.priority'].value 처럼 사용하여 painless script에서도 사용할 있다.

 

 

 

nested type 대체 가능 여부


flattened 문서에 보면 flattened type의 장점은 어떻게 들어올지 모르는 여러 dynamic한 필드들에 대한 내용을 검색가능하게 하나의 json field로써 저장하게 해준다고 기재되어 있다. 물론 이것을 통해서 단순 keyword성 검색을 필요로하다고 한다면 nested에 대체가 가능할 수 도 있다.

 

하지만 내 경험으로 봤을 때 nested를 사용하는건 하나의 공통 객체 속성 내부에서 하위 여러 속성별로 검색을 할 때 사용하기 때문에 flattened type에 아래 속성 때문에 대체가 어려울 거라고 판단된다.

 

1. keyword type 이외에 number, date등과 같은 필드로 매핑이 되지 않는다.

-> nested에서 검색 시 단순하게 검색 조건에 keyword만 들어가지는 않는다. 

 

2. analysis를 사용한 text매핑이 되지 않는다.

-> 검색 시에 정해진 사전, analyzer, tokenizer 등을 사용하지 않고 검색을 하는 경우는 실 사용에서 거의 없다고 판단된다.

 

 

현재 회사에서 검색에 사용되고 있는 nested가 성능에 그렇게 좋지 못하기 때문에 많은 애로사항이 있다.

이를 단순하게 data type을 변경해서 해결포인트를 찾아보려고 했으나 기대했던 flattened type이 단순 로그 저장용 정도로 사용할 수 있을 거라는 판단 때문에 쉽지가 않을 것 같다.

 

대신 저장 구조를 변경해서 느려진 속도를 끌어올릴 수 있는 방법을 고안해봐야겠다.

반응형