아빠는 개발자

[es] nested 구조에서 aggregation 하기 본문

Elastic/elasticsearch

[es] nested 구조에서 aggregation 하기

father6019 2024. 4. 30. 21:41
728x90
반응형

음... 저번에 작성중이던 글이 싹 날아갔네 ..

초심으로 돌아가서 다시 작성해보잣...

 

상품은 n 개의 promotion 에 등록될 수 있고  promotion 에는 m 개의 theme 가 등록될수 있다. 

결론은 하나의 상품은 n x m 의 개의  promotion theme 에  등록될 수 있는것이다. 

 

문제 1

  • 상품이 등록된 유효한 테마의 No 를 구해야 한다. 

해결방법

1. promotion_theme 번호를 연결해서 배열로 색인 후에 .. 후처리?..  머.. 후처리가 들어간다면 안되는게 어딨겠나..

api 의 응답속도나 이것저것 했을때 후처리를 좋아하진 않는 편이라 Pass 

 

2. object 구조로 promos.promo 와 promos.theme 를 색인해서 필터를 promo 로 걸고 aggregation ..

하면 ?? 음..   아래에 테스트 해보니 검색결과가 섞여 나온다. 

object 와 nested 의 차이..

"Object"는 문서 내에서 필드 그룹을 나타내는 반면 "Nested"는 별도의 독립된 문서를 나타냅니다.

 

3. nested 구조로 색인하고 aggs 한다. 

일단 난 3번으로 했는데 이런 구조면 2번도 가능한게 아닌가? 라는 생각이 문득 들어서  다시 테스트 

 

Object: "Object"는 단일 문서 내에서 여러 필드를 그룹화하는 데 사용됩니다.
즉, "Object"는 문서 내에서 서브 필드를 그룹화하는 데 사용됩니다.
그룹화된 필드는 독립적으로 검색되지만, 내부 구조가 고정되어 있습니다.
이러한 구조는 내부의 필드가 일반적으로 상위 레벨 문서 필드와 함께 저장되고 인덱싱된다는 점에서 "Object"의 중요한
특징입니다. 이러한 구조는 일반적으로 특정 필드의 값이 자주 변경되지 않는 경우에 사용됩니다.


Nested: "Nested"는 중첩된 문서나 객체를 색인하는 데 사용됩니다.
"Nested"는 개별적으로 인덱싱되고 별도의 문서로 관리되는 하위 문서를 나타냅니다. 
 이는 단일 필드 내에 중첩된 독립적인 문서가 있다는 것을 의미합니다.
"Nested" 객체는 자체 스코어링과 정렬을 수행할 수 있으며, 별도의 검색 쿼리를 사용하여 검색될 수 있습니다.
"Nested" 객체는 독립적인 문서로 관리되므로 부모 문서의 변경 없이도 검색, 업데이트 및 삭제가 가능합니다.

 

 

테스트 

인덱스 생성 

PUT /promo_prod
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "promos": {
        "type": "nested", 
        "properties": {
          "promo": {
            "type": "keyword"
          },
          "theme": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

 

데이터 색인

주의 : 색인할때 promos 하위에 있는데이터들이 1개라도 배열안으로 들어가야 정상적인 검색결과가 나옴 

POST _bulk?refresh
{"index":{"_index":"promo_prod","_id":"1"}}
{"name":"상품1","promos":[{"promo": "1111", "theme":["11350", "15220"]}, {"promo": "5555", "theme":["55350", "50220"]}]}
{"index":{"_index":"promo_prod","_id":"2"}}
{"name":"상품2","promos":[{"promo": "2222", "theme":["22360", "21290"]}]}
{"index":{"_index":"promo_prod","_id":"3"}}
{"name":"상품3","promos":[{"promo": "3333", "theme":["33150", "35221"]}]}
{"index":{"_index":"promo_prod","_id":"4"}}
{"name":"상품4","promos":[{"promo": "1111", "theme":["40450", "44021"]}]}

 

 

검색/집계 쿼리 

GET promo_prod/_search
{
  "size": 0,
  "query": {
    "nested": {
      "path": "promos",
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "promos.promo": "1111"
              }
            }
          ]
        }
      }
    }
  },
  "aggs": {
    "nested_promos": {
      "nested": {
        "path": "promos"
      },
      "aggs": {
        "promo_terms": {
          "terms": {
            "field": "promos.promo"
          },
          "aggs": {
            "theme_term": {
              "terms": {
                "field": "promos.theme"
              }
            }
          }
        }
      }
    }
  }
}

 

 

결과 

 

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "nested_promos": {
      "doc_count": 3,
      "promo_terms": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "1111",
            "doc_count": 2,
            "theme_term": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "11350",
                  "doc_count": 1
                },
                {
                  "key": "15220",
                  "doc_count": 1
                },
                {
                  "key": "40450",
                  "doc_count": 1
                },
                {
                  "key": "44021",
                  "doc_count": 1
                }
              ]
            }
          },
          {
            "key": "5555",
            "doc_count": 1,
            "theme_term": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "50220",
                  "doc_count": 1
                },
                {
                  "key": "55350",
                  "doc_count": 1
                }
              ]
            }
          }
        ]
      }
    }
  }
}

 

 

음...

obejct 를 색인로 색인하는 2번째 방법은 데이터가 섞여서 나옴

 

검색쿼리 

GET promo_prod/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "promos.promo.keyword": "1111"
          }
        }
      ]
    }
  },
  "aggs": {
    "promo_terms": {
      "terms": {
        "field": "promos.promo.keyword"
      },
      "aggs": {
        "theme_term": {
          "terms": {
            "field": "promos.theme.keyword"
          }
        }
      }
    }
  }
}

 

결과 

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "promo_terms": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "1111",
          "doc_count": 2,
          "theme_term": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "11350",
                "doc_count": 1
              },
              {
                "key": "15220",
                "doc_count": 1
              },
              {
                "key": "40450",
                "doc_count": 1
              },
              {
                "key": "44021",
                "doc_count": 1
              },
              {
                "key": "50220",
                "doc_count": 1
              },
              {
                "key": "55350",
                "doc_count": 1
              }
            ]
          }
        },
        {
          "key": "5555",
          "doc_count": 1,
          "theme_term": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "11350",
                "doc_count": 1
              },
              {
                "key": "15220",
                "doc_count": 1
              },
              {
                "key": "50220",
                "doc_count": 1
              },
              {
                "key": "55350",
                "doc_count": 1
              }
            ]
          }
        }
      ]
    }
  }
}

 

일단 원하는 결과는 나왔으니까 성능 테스트를 해보자

 

  1. 일단 색인 사이즈의 변화
  2. 검색성능 
  3. 캐시사이즈 

3가지를 확인해봐야겠다. 

 

Nested 구조에서 Aggregation을 수행할 때 발생할 수 있는 주요 성능 이슈는 다음과 같다. 

 

1. Nested 객체 수: Nested 구조의 객체 수가 많을수록 Aggregation 처리 시에도 더 많은 계산이 필요합니다. Nested 객체 수가 많을수록 Aggregation 성능이 저하될 수 있습니다.

2. Shard Size 및 데이터 크기: Aggregation은 여러 샤드에서 데이터를 가져와 병합하는 작업을 수행하므로 Shard Size와 데이터 크기가 Aggregation 성능에 영향을 줄 수 있습니다. 특히, 데이터가 크고 Shard Size가 작으면 Aggregation 처리에 더 많은 시간이 소요될 수 있습니다.

3. Aggregation 종류: 어떤 종류의 Aggregation을 수행하느냐에 따라 성능이 달라질 수 있습니다. 일부 Aggregation은 다른 것보다 더 많은 계산이 필요하므로 성능에 영향을 줄 수 있습니다.

4. 하위 문서 수: Nested 구조의 하위 문서가 많을수록 Aggregation의 성능이 저하될 수 있습니다. 이는 하위 문서를 처리할 때 추가적인 작업이 필요하기 때문입니다.

 

따라서 Nested 구조에서 Aggregation을 수행할 때는 데이터 구조, 데이터 크기, Aggregation 종류 등을 고려하여 성능을 평가하고 최적화해야 합니다. 필요에 따라서는 샤드 사이즈를 조정하거나 Aggregation 파이프라인을 사용하여 성능을 향상시킬 수 있습니다.

 

 

성능테스트 

https://father-lys.tistory.com/103

 

[es] nested 구조에서 aggregation 하기 - 성능테스트

nested 와 object 구조에서 aggregation 테스트를 해보자 동일한 데이터를 색인하는데 nested 구조에서 index의 크기가 증가하고 docs 가 늘어난다.   100만개 색인..  목표는 1000 만개였으나 데이터를 랜

father-lys.tistory.com

 

728x90
반응형