nested type을..아주 많이..사용해야하는 경우가 생겨버렸다…. 🥺 디테일하게 살펴보쟈..!
처음에 nested type 필드를 매핑해놓고 아래처럼 몇개 데이터를 미리 넣어뒀다.
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "6AfWQ4IB18RgfuY2grRT",
"_score": 1.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2": "naoek"
}
],
"test_key": "key1"
}
},
{
"_index": "text_index",
"_type": "_doc",
"_id": "6QfWQ4IB18RgfuY2grRT",
"_score": 1.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2e": "sgsgs"
}
],
"test_key": "key2"
}
}
]
}
}
기본데이터에 nested 타입에 object 데이터를 추가해보고자 했는데, 처음의 request 형태와 response 형태는 바로 아래 코드와 같았다.
Request
POST test_index/_update_by_query
{
"script": {
"source": "ctx._source.nestedtypefield.add(params.new_param),
"lang": "painless",
"params" : {
"new_param" : [
{"field1" : "asdf", "field2" : "asdf"},
{"field1" : "1234", "field2" : "sfdsf"},
]
}
},
"query": {
"terms": {
"test_key": ["key1", "key2"]
}
}
}
추가된 데이터 형태
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 2.0,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "4gdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2": "naoek"
},
[
{"field1" : "asdf", "field2" : "asdf"},
{"field1" : "1234", "field2" : "sfdsf"},
]
],
"test_key": "key1"
}
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "4wdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2e": "sgsgs"
}
[
{"field1" : "asdf", "field2" : "asdf"},
{"field1" : "1234", "field2" : "sfdsf"},
]
],
"test_key": "key2"
}
}
]
}
}
그런데 이건 내가 원하던 형태가 아니였다. ㅠㅠ 넣어보니 위 response처럼 데이터가 nested 타입의 필드 안에 배열 그대로 들어간 게 아닌가..ㅂㄷㅂㄷ… 내가 원하는 건 nested 타입 필드에 object형태로 차곡차곡 쌓이는 형태였다.
다시 구글을 열심히 뒤져봐서 다른 addAll
이란 메소드를 사용해야한다는 것을 알게 되었다. 🤓 아래 코드를 통해 결국 내가 원하는 결과를 얻었다!
Request
POST test_index/_update_by_query
{
"script": {
"source": "ctx._source.nestedtypefield.addAll(params.new_param)",
"lang": "painless",
"params" : {
"new_param" : [
{"field1" : "asdf", "field2" : "asdf"},
{"field1" : "1234", "field2" : "sfdsf"},
]
}
},
"query": {
"terms": {
"test_key": ["key1", "key2"]
}
}
}
추가된 데이터 형태
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 2.0,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "4gdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2": "naoek"
},
{
"field1" : "asdf",
"field2" : "asdf"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key1"
}
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "4wdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2e": "sgsgs"
}
{
"field1" : "asdf",
"field2" : "asdf"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key2"
}
}
]
}
}
이번에는 nested type안에 object를 수정하기 위한 작업을 위해 서치를 해서 쿼리문을 만들어봤다.
여기서, 이미 query
조건에 "nestedtypefield.field1": "asdf"
이게 있는데 왜 script에서 findAll
를 사용해서 타켓을 for문으로 하나씩 수정해주지? 라는 생각이 들 수 있다. 이건 아래 조회에서 더 자세히 볼 수 있을 텐데, query
조건으로 nested type을 검색해주면 inner_hits
라는 응답 부분에는 쿼리문 조건에 맞는 nested type의 object들만 노출되지만 기본적으로 사용하는 _source
응답 부분에는 조건에 맞는 nested type의 object 데이터 + 그 nested type에 존재하는 다른 object 데이터들이 존재한다. 그래서 script에서 사용하고 있는 ctx._source
를 이용하여 수정하기 위해서는, 일단 쿼리문으로 조건에 해당하는 데이터를 가져와서 nested type 필드안에서 직접 for문으로 데이터를 수정해줘야한다. 이게.. 성능에 많은 영향을 끼칠 것 같지만.. 일단 내가 생각한 최선이였다…ㅠㅠ
Request
POST test_index/_update_by_query
{
"script": {
"source": "def targets = ctx._source.nestedtypefield.findAll(test -> test.field1== params.update_field1); for(update_target in targets) { update_target.field2 = params.update_field2 }",
"lang": "painless",
"params" : {
"update_field1" : "asdf",
"update_field2" : "update했다!"
}
},
"query": {
"bool": {
"must": [
{
"nested": {
"path": "nestedtypefield",
"query": {
"term": {
"nestedtypefield.field1": "asdf"
}
}
}
}
]
}
}
}
수정된 데이터 형태
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 2.0,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "4gdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2": "naoek"
},
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key1"
}
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "4wdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1": "asdfsdf",
"field2": "update됨"
},
{
"field1": "asdfsdf",
"field2e": "sgsgs"
}
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key2"
}
}
]
}
}
삭제도 update와 비슷한 방법인데, removeIf
라는 메소드를 써서 더 간단하게 작업할 수 있다.
Request
POST test_index/_update_by_query
{
"script": {
"source": "ctx._source.nestedtypefield.removeIf(it->params.remove_field1 == it.field1)",
"lang": "painless",
"params" : {
"remove_field1" : "asdfsdf"
}
},
"query": {
"bool": {
"must": [{
"terms": {
"test_key": ["key1","key2"]
}
}]
}
}
}
삭제된 데이터 형태
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 2.0,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "4gdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key1"
}
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "4wdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "sfdsf"
}
],
"test_key": "key2"
}
}
]
}
}
이번에는 조회!
아래와 같이 query문으로 요청을 보낼 수 있고, must
안에 조건을 추가하거나 bool
안에 filter
등을 사용하여 추가로 조건을 붙일 수 있다.
또, 2. nested type안 object 수정
에서 설명했듯이 nested type 조건이 일치하는 데이터와 함께 inner_hits
에 노출하고자하는 nested type 필드명을 적고 nested type 안에 object들을 정렬할 수도 있다. 이때, 정렬은 inner_hits
안에서 된다.
Request
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"_index": [
"test_indx"
]
}
},
{
"nested": {
"path": "nestedtypefield",
"query": {
"term" : {
"nestedtypefield.field1" : "1234"
}
},
"inner_hits": {
"highlight": {
"fields": {
"nestedtypefield": {}
}
},
"sort" : {
"nestedtypefield.field2" : "asc"
}
}
}
}
]
}
},
"from": 0,
"size": 100
}
조회 결과
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 16.028084,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "4gdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "789"
},
{
"field1" : "1234",
"field2" : "456"
}
],
"test_key": "key1"
},
"inner_hits": {
"customer_tags": {
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "5Qe5QoIB18RgfuY2grT6",
"_nested": {
"field": "nestedtypefield",
"offset": 2
},
"_score": null,
"_source": {
"field1" : "1234",
"field2" : "456"
},
"sort": [
1595203200000
]
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "5Qe5QoIB18RgfuY2grT6",
"_nested": {
"field": "nestedtypefield",
"offset": 0
},
"_score": null,
"_source": {
"field1" : "1234",
"field2" : "789"
},
"sort": [
1650412800000
]
}
]
}
}
}
},
{
"_index": "test_index",
"_type": "_doc",
"_id": "4wdhQoIB18RgfuY28rTG",
"_score": 2.0,
"_source": {
"nestedtypefield": [
{
"field1" : "asdf",
"field2" : "update했다!"
},
{
"field1" : "1234",
"field2" : "1000"
},
{
"field1" : "1234",
"field2" : "4500"
}
],
"test_key": "key2"
},
"inner_hits": {
"customer_tags": {
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "test_index",
"_type": "_doc",
"_id": "5Qe5QoIB18RgfuY2grT6",
"_nested": {
"field": "nestedtypefield",
"offset": 2
},
"_score": null,
"_source": {
"field1" : "1234",
"field2" : "1000"
},
"sort": [
1595203200000
]
},
{
"_index": "tmp_product10",
"_type": "_doc",
"_id": "5Qe5QoIB18RgfuY2grT6",
"_nested": {
"field": "customer_tags",
"offset": 0
},
"_score": null,
"_source": {
"field1" : "1234",
"field2" : "4500"
},
"sort": [
1650412800000
]
}
]
}
}
}
}
]
}
}