이곳에 있는 데이터 모델을 기반으로 합니다.
공무원 김공무(27)은, DB에 있는 사람들이 몇년도 생인지 궁금하다.
{
"name":"김이름",
"gender":"M",
"age": 27,
"address": {
"personId": 1,
"country": "KR",
"city": "Suwon"
}
}
27살은
2022(올해) - 27(나이) + 1(태어나자마자 1살이기에)
을 하면 1996년생임을 계산할 수 있다.
> ES 버전이 7.11 이상이라면
럭키! 인덱스를 수정하지 않고 search 쿼리만으로 가능하다.
> ES 버전이 7.11 미만이라면
저런,, 인덱스를 수정해야만 한다.
mappings
하위에 runtime
필드를 추가한다.
PUT /person
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"runtime": {
"birthYear": {
"type": "long",
"script": {
"source": "emit(2022-doc['age'].value+1)",
"lang": "painless"
}
}
},
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"personId": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"gender": {
"type": "keyword"
},
"age": {
"type": "integer"
},
"address": {
"type": "nested",
"properties": {
"personId": {
"type": "keyword"
},
"country": {
"type": "keyword"
},
"city": {
"type": "keyword"
}
}
}
}
}
}
query
바깥에 runtime_mappings
필드를 추가해준다.
GET /person/_search
{
"runtime_mappings": {
"birthYear2": {
"type": "long",
"script": {
"source": "emit(2022-doc['age'].value+1)",
"lang": "painless"
}
}
},
"fields": [
"birthYear2"
],
"query": {
"match_all": {}
}
}
fields
필드에서 함께 노출할 런타임 매핑 필드를 명시
해야한다.사실 위 예제와 같이 단순히 계산 값을 출력
할 때에는 runtime mappings 를 사용하지 않아도 된다. 오히려 코드레벨에서 계산하는게 유지보수가 더 쉽다.
더군다나, field
필드에 노출할 런타임 필드를 명시해주는것도 썩 불편하다. response 형식도 맘에 안들고.
SELECT product_no, SUM(price * order_cnt) AS total_order_price
FROM statistic
GROUP BY product_no
GET /statistic/_search
{
"runtime_mappings": {
"totalOrderPrice": { // 여기있는 런타임 필드가
"type": "long",
"script": {
"source": "emit(doc['price'].value * doc['order_cnt'].value)",
"lang": "painless"
}
}
},
"aggs": {
"byProductNo": {
"terms": {
"field": "productNo"
}
},
"totalOrderPrice": {
"sum": {
"field": "totalOrderPrice" // 요기랑 매핑된다.
}
}
}
}
Reference
Runtime mapping 공식 문서 : https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-mapping-fields.html