Как достать вложенные объекты в скрипте при агрегации. How get object in script

Есть объект такой вложенности

"sizeData" : {
           "id" : 1,
           "elasticSizeScale" : {
             "id" : 3,
             "sizes" : [
               {
                 "id" : 321,
                 "sizeOrder" : 2
               },
               {
                 "id" : 323,
                 "sizeOrder" : 4
               },
               {
                 "id" : 322,
                 "sizeOrder" : 3
               }
             ]
           }
         }

Как добраться внутрь и взять каждый объект?
doc['sizeData.elasticSizeScale.sizes'] и разные манипуляции не помогают
могу взять каждое поле отдельно: но for отрабатывает так, что эти поля сортирует по возрастанию(321, 322, 323 и 2, 3,4) и каждый тот же iый объект это будут значения из разных объектов. но мне нужна пара 321-2, 323-4, 322-3

Как маппинг выглядит для этой части документа? Для чего будут использоваться эти пары и в каком контексте (фильтр для поиска, агрегация, результат поиска, и т.д)?

Маппинг такой

        "sizeData": {
          "type": "nested",
          "properties": {
            "elasticSizeScale": {
              "properties": {
                "id": {
                  "type": "long"
                },
                "sizes": {
                  "properties": {
                    "id": {
                      "type": "long"
                    },
                    "sizeOrder": {
                      "type": "long"
                    }
                  }
                }
              }
            },
            "id": {
              "type": "long"
            }
          }
        }

Задача такая - у меня есть продукты, у них есть размеры - 36,37,38 - они лежат объектами в той структуре, что скинула выше.
Я прохожусь по каждому продукту и забираю все размеры - составляю фасеты. Это все происходит в агрегации. Мне нужно поле id и поле sizeOrder.
Дело в том, что когда я делаю

 for(int i=0; i<doc['sizeData.elasticSizeScale.sizes.id'].length; i++){
doc['sizeData.elasticSizeScale.sizes.id'][i];
}

Цикл достает мне все id и достает все sizeOrder, но не парами - как они в объекте.
Проще говоря.. как циклом пройтись по этому листу и достать прям объект (полей там может быть больше)

Как должны выглядеть эти фасеты? Какой конечный желаемый результат?

у меня там дальше много логики, мне нужно достать просто правильную пару
если данные такие:

{
                 "id" : 321,
                 "sizeOrder" : 2
               },
               {
                 "id" : 323,
                 "sizeOrder" : 4
               },
               {
                 "id" : 322,
                 "sizeOrder" : 3
               }

мне нужно : 321-2, 323-4, 322-3

Как с помощью цикла достать объект целиком что лежит внутри sizes ?!

Я все-равно не понимаю, что вам нужно. Ну да ладно, вот несколько примеров. Может, поможет.

DELETE test

PUT test
{
  "mappings": {
    "properties": {
      "sizeData": {
        "type": "nested",
        "properties": {
          "elasticSizeScale": {
            "properties": {
              "id": {
                "type": "long"
              },
              "sizes": {
                "properties": {
                  "id": {
                    "type": "long"
                  },
                  "sizeOrder": {
                    "type": "long"
                  }
                }
              }
            }
          },
          "id": {
            "type": "long"
          }
        }
      }
    }
  }
}


PUT test/_doc/1
{
  "sizeData": [
    {
      "id": 321,
      "sizeOrder": 2
    },
    {
      "id": 323,
      "sizeOrder": 4
    },
    {
      "id": 322,
      "sizeOrder": 3
    }
  ]
}


POST test/_search
{
  "size": 0,
  "aggs": {
    "by_size": {
      "nested": {
        "path": "sizeData"
      },
      "aggs": {
        "by_id": {
          "terms": {
            "script": {
              "source": "doc['sizeData.id'] + ' - ' + doc['sizeData.sizeOrder']"
            },
            "size": 10
          }
        }
      }
    }
  }
}


POST test/_search
{
  "size": 0,
  "aggs": {
    "by_size": {
      "nested": {
        "path": "sizeData"
      },
      "aggs": {
        "by_id": {
          "terms": {
            "field": "sizeData.id",
            "size": 10
          },
          "aggs": {
            "by_sizeOrder": {
              "terms": {
                "field": "sizeData.sizeOrder"
              }
            }
          }
        }
      }
    }
  }
}

вот так это сработало
doc['sizeData.elasticSizeScale.sizes.id'] + ' - ' + doc['sizeData.elasticSizeScale.sizes.sizeOrder']

но при вот что вернуло:
"[321, 322, 323] - [2, 3, 4]"

т.е. все id из листа и все sizeOrder
а мне нужно с помощью for пройти по листу и достать каждый объект, чтобы было:
[321-2], [323-4], [322-3]
Если писать так

   for(int i=0; i<doc['sizeData.elasticSizeScale.sizes.id'].length; i++){
      id= doc['sizeData.elasticSizeScale.sizes.id'][i];
    order= doc['sizeData.elasticSizeScale.sizes.sizeOrder'][i];
}

то тут вернется по первому элемента из каждого массива
"[321, 322, 323] - [2, 3, 4]"
т.е. получится
id =321
order = 2,

id = 322
order = 3,

id = 323
order = 4

а должно быть 321-2, 323-4, 322-3

Немного не так написала по входным данным

{
                 "id" : 321,
                 "sizeOrder" : 2
               },
               {
                 "id" : 323,
                 "sizeOrder" : 4
               },
               {
                 "id" : 322,
                 "sizeOrder" : 5
               }

Каким-то образом получаются массивы по возрастанию id и по sizeOrder
321, 322, 323
2,4,5

но если проходиться циклом, то получится что 321 322 323
2 4 5
но на самом деле 322 соответствует 5

Вы мой пример запускали?

Да. Запускала. Он вывел мне два разных массива отсортированных по возрастанию. А мне нужно в цикле, когда я беру iый элемент сразу достать из объекта два поля, которые находятся в одном объекте

Он вывел мне два разных массива отсортированных по возрастанию.

Как вы его запускали? Вы nested добавить не забыли? Он должен был вывести вот это:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "by_size" : {
      "doc_count" : 3,
      "by_id" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 0,
        "buckets" : [
          {
            "key" : "[321] - [2]",
            "doc_count" : 1
          },
          {
            "key" : "[322] - [3]",
            "doc_count" : 1
          },
          {
            "key" : "[323] - [4]",
            "doc_count" : 1
          }
        ]
      }
    }
  }
}

Цикл в агрегации можно получить только из _source, это возможно, но будет грузить всю запись, что будет очень медленно.

POST test/_search
{
  "size": 0,
  "aggs": {
    "by_id": {
      "terms": {
        "script": {
          "source": "String s =''; for(i in params._source.sizeData) { s += (i.id + '=' + i.sizeOrder + ' '); } return s;"
        },
        "size": 10
      }
    }
  }
}

Отдельные пары можно получить в nested агрегации быстро. надо для того, чтобы показать как с ними работать, мне надо понять что с этими массивами вам потом надо делать?

Как-то все равно не правильно у меня работает
давайте с начала.. возможно я что-то не так объяснила. Возьмем полный пример того, что у меня происходит
Данные у меня такие:

    "sizeData" : {
            "id" : 1,
            "identifier" : "group_size_shoes_mn",
            "name" : {
              "ru" : "Размер мужской обуви",
              "en" : "Men's shoe sizes"
            },
            "elasticSizeScale" : {
              "id" : 3,
              "name" : {
                "ru" : "uk",
                "en" : "uk"
              },
              "sizes" : [
                {
                  "id" : 321,
                  "name" : {
                    "ru" : "6",
                    "en" : "6"
                  },
                  "sizeOrder" : 2
                },
                {
                  "id" : 323,
                  "name" : {
                    "ru" : "7",
                    "en" : "7"
                  },
                  "sizeOrder" : 4
                },
                {
                  "id" : 322,
                  "name" : {
                    "ru" : "6.5",
                    "en" : "6.5"
                  },
                  "sizeOrder" : 3
                },
                {
                  "id" : 317,
                  "name" : {
                    "ru" : "13.5",
                    "en" : "13.5"
                  },
                  "sizeOrder" : 17
                },
                {
                  "id" : 318,
                  "name" : {
                    "ru" : "14",
                    "en" : "14"
                  },
                  "sizeOrder" : 18
                },
                {
                  "id" : 315,
                  "name" : {
                    "ru" : "12.5",
                    "en" : "12.5"
                  },
                  "sizeOrder" : 15
                },
                {
                  "id" : 316,
                  "name" : {
                    "ru" : "13",
                    "en" : "13"
                  },
                  "sizeOrder" : 16
                },
                {
                  "id" : 320,
                  "name" : {
                    "ru" : "5.5",
                    "en" : "5.5"
                  },
                  "sizeOrder" : 1
                },
                {
                  "id" : 310,
                  "name" : {
                    "ru" : "10",
                    "en" : "10"
                  },
                  "sizeOrder" : 10
                },
                {
                  "id" : 328,
                  "name" : {
                    "ru" : "9.5",
                    "en" : "9.5"
                  },
                  "sizeOrder" : 9
                },
                {
                  "id" : 324,
                  "name" : {
                    "ru" : "7.5",
                    "en" : "7.5"
                  },
                  "sizeOrder" : 5
                },
                {
                  "id" : 325,
                  "name" : {
                    "ru" : "8",
                    "en" : "8"
                  },
                  "sizeOrder" : 6
                },
                {
                  "id" : 314,
                  "name" : {
                    "ru" : "12",
                    "en" : "12"
                  },
                  "sizeOrder" : 14
                },
                {
                  "id" : 327,
                  "name" : {
                    "ru" : "9",
                    "en" : "9"
                  },
                  "sizeOrder" : 8
                },
                {
                  "id" : 312,
                  "name" : {
                    "ru" : "11",
                    "en" : "11"
                  },
                  "sizeOrder" : 12
                },
                {
                  "id" : 313,
                  "name" : {
                    "ru" : "11.5",
                    "en" : "11.5"
                  },
                  "sizeOrder" : 13
                },
                {
                  "id" : 326,
                  "name" : {
                    "ru" : "8.5",
                    "en" : "8.5"
                  },
                  "sizeOrder" : 7
                }
              ]
            }
          }

Вот код, который я пытаюсь сделать:

   "aggregations": {
        "sizeData": {
          "nested": {
            "path": "sizeData"
          },
          "aggregations": {
            "sizeDataandsizes": {
              "terms": {
                "script": {
                  "source": """def value = "";
 def translateSizeScale = "";
 def translateSize = "";
 def map = new ArrayList();
 try {
   for(int i=0; i<doc['sizeData.elasticSizeScale.sizes.id'].length; i++){
      translateSizeScale = '';
      translateSize = '';
      
      value = doc['sizeData.elasticSizeScale.id'].value+'@'+doc['sizeData.elasticSizeScale.sizes.id'][i];
      translateSizeScale = doc['sizeData.elasticSizeScale.name.'+params.lang+'.keyword'].value;
      translateSize = doc['sizeData.elasticSizeScale.sizes.name.'+params.lang+'.keyword'].get(i);

    if (translateSizeScale == 'uk') {
 def translateMap = new HashMap();
 translateMap.put('"'+ value +'"', '"'+ translateSize + ' (' + translateSizeScale + ')' +'"');
 def orderMap = new HashMap();
   orderMap.put('"'+ doc['sizeData.elasticSizeScale.sizes.sizeOrder'][i] +'"', translateMap);
 
 def sizeDto = new HashMap();
 sizeDto.put('"'+ doc['sizeData.identifier.keyword'].value +'"', orderMap);
 map.add(sizeDto);
  }
  }
 }catch(Exception e){}           
 return map;""",
                  "lang": "painless",
                  "params": {
                    "lang": "ru",
                    "siteLangs": [
                      "en",
                      "ru"
                    ],
                    "defaultLang": "en"
                  }
                },
                "size": 80,
                "min_doc_count": 1,
                "shard_min_doc_count": 0,
                "show_term_doc_count_error": false,
                "order": [
                  {
                    "_count": "desc"
                  },
                  {
                    "_key": "asc"
                  }
                ]
              }
            }
          }
        }
      }

По итогу мне нужно получить:

             "key" : """{"group_size_shoes_mn"={"1"={"3@310"="10 (uk)"}}}""",
             "doc_count" : 1
           },
           {
             "key" : """{"group_size_shoes_mn"={"10"={"3@321"="6 (uk)"}}}""",
             "doc_count" : 1
           },

В результате меня все устраивает, кроме "1", "10 "- это и есть sizeOrder, который не правильно берется по iому элементу
Должно быть:

             "key" : """{"group_size_shoes_mn"={"10"={"3@310"="10 (uk)"}}}""",
             "doc_count" : 1
           },
           {
             "key" : """{"group_size_shoes_mn"={"2"={"3@321"="6 (uk)"}}}""",
             "doc_count" : 1
           },

Так кто у вас nested? sizeData? elasticSizeScale? size? или все 3? Маппинг-то реально какой?

Маппинг вот такой

{
  "mappings": {
    "new_product": {
      "properties": {
        "sizeData": {
          "type": "nested",
          "properties": {
            "elasticSizeScale": {
              "properties": {
                "id": {
                  "type": "long"
                },
                "name": {
                  "properties": {
                    "en": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    },
                    "ru": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    }
                  }
                },
                "sizes": {
                  "properties": {
                    "id": {
                      "type": "long"
                    },
                    "name": {
                      "properties": {
                        "en": {
                          "type": "text",
                          "fields": {
                            "keyword": {
                              "type": "keyword",
                              "ignore_above": 256
                            }
                          }
                        },
                        "ru": {
                          "type": "text",
                          "fields": {
                            "keyword": {
                              "type": "keyword",
                              "ignore_above": 256
                            }
                          }
                        }
                      }
                    },
                    "sizeOrder": {
                      "type": "long"
                    }
                  }
                }
              }
            },
            "id": {
              "type": "long"
            },
            "identifier": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "name": {
              "properties": {
                "en": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "ru": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
          }
        }
      }
    }
  }
}

Это какая версия elasticsearch? Вы на 7.12 перейти можете? Конечная цель - это сгруппировать все по набору name+size+lang?

Конечная цель это сгруппировать размеры по группам и и сеткам
например, у меня есть мужские размеры в ru сетке со значениями 42,43,44 - посчитать сколько таких размеров в продуктах каждого... перевод - это просто дополнительно, по нему группировать не надо... мне нужно знать сколько например,
мужская группа - ru - 42
мужская группа - ru - 43
мужская группа - ru - 44
Перевод - это чтобы лишний раз не лезть в базу, чтобы сразу отобразить наименование в фасетах. И проблема в том, что мне нужно доп поле sizeOrder - оно определяет порядок фасета, чт сначала 42 потом 43, и пото 44

Возможности на 7.12 пока нет, там какие-то новые позелные фичи?!

Теперь понятно.

Надо убрать nested из sizeData и elasticSizeScale (они у вас в единственном экземпляре, там nested не нужен. А вот с size все наоборот - там, как раз, nested необходим. Если это сделать то получится так:

DELETE test

PUT test
{
  "mappings": {
      "properties": {
        "sizeData": {
          "properties": {
            "elasticSizeScale": {
              "properties": {
                "id": {
                  "type": "long"
                },
                "name": {
                  "properties": {
                    "en": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    },
                    "ru": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    }
                  }
                },
                "sizes": {
                  "type": "nested",
                  "properties": {
                    "id": {
                      "type": "long"
                    },
                    "name": {
                      "properties": {
                        "en": {
                          "type": "text",
                          "fields": {
                            "keyword": {
                              "type": "keyword",
                              "ignore_above": 256
                            }
                          }
                        },
                        "ru": {
                          "type": "text",
                          "fields": {
                            "keyword": {
                              "type": "keyword",
                              "ignore_above": 256
                            }
                          }
                        }
                      }
                    },
                    "sizeOrder": {
                      "type": "long"
                    }
                  }
                }
              }
            },
            "id": {
              "type": "long"
            },
            "identifier": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "name": {
              "properties": {
                "en": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "ru": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
}


PUT test/_doc/1
{
  "sizeData": {
    "id": 1,
    "identifier": "group_size_shoes_mn",
    "name": {
      "ru": "Размер мужской обуви",
      "en": "Men's shoe sizes"
    },
    "elasticSizeScale": {
      "id": 3,
      "name": {
        "ru": "uk",
        "en": "uk"
      },
      "sizes": [
        {
          "id": 321,
          "name": {
            "ru": "6",
            "en": "6"
          },
          "sizeOrder": 2
        },
        {
          "id": 323,
          "name": {
            "ru": "7",
            "en": "7"
          },
          "sizeOrder": 4
        },
        {
          "id": 322,
          "name": {
            "ru": "6.5",
            "en": "6.5"
          },
          "sizeOrder": 3
        },
        {
          "id": 317,
          "name": {
            "ru": "13.5",
            "en": "13.5"
          },
          "sizeOrder": 17
        },
        {
          "id": 318,
          "name": {
            "ru": "14",
            "en": "14"
          },
          "sizeOrder": 18
        },
        {
          "id": 315,
          "name": {
            "ru": "12.5",
            "en": "12.5"
          },
          "sizeOrder": 15
        },
        {
          "id": 316,
          "name": {
            "ru": "13",
            "en": "13"
          },
          "sizeOrder": 16
        },
        {
          "id": 320,
          "name": {
            "ru": "5.5",
            "en": "5.5"
          },
          "sizeOrder": 1
        },
        {
          "id": 310,
          "name": {
            "ru": "10",
            "en": "10"
          },
          "sizeOrder": 10
        },
        {
          "id": 328,
          "name": {
            "ru": "9.5",
            "en": "9.5"
          },
          "sizeOrder": 9
        },
        {
          "id": 324,
          "name": {
            "ru": "7.5",
            "en": "7.5"
          },
          "sizeOrder": 5
        },
        {
          "id": 325,
          "name": {
            "ru": "8",
            "en": "8"
          },
          "sizeOrder": 6
        },
        {
          "id": 314,
          "name": {
            "ru": "12",
            "en": "12"
          },
          "sizeOrder": 14
        },
        {
          "id": 327,
          "name": {
            "ru": "9",
            "en": "9"
          },
          "sizeOrder": 8
        },
        {
          "id": 312,
          "name": {
            "ru": "11",
            "en": "11"
          },
          "sizeOrder": 12
        },
        {
          "id": 313,
          "name": {
            "ru": "11.5",
            "en": "11.5"
          },
          "sizeOrder": 13
        },
        {
          "id": 326,
          "name": {
            "ru": "8.5",
            "en": "8.5"
          },
          "sizeOrder": 7
        }
      ]
    }
  }
}

POST test/_search
{
  "size": 0,
  "aggs": {
    "by_size": {
      "nested": {
        "path": "sizeData.elasticSizeScale.sizes"
      },
      "aggs": {
        "by_id": {
          "terms": {
            "script": {
              "source": "doc['sizeData.elasticSizeScale.sizes.id'][0] + ' - ' + doc['sizeData.elasticSizeScale.sizes.name.ru.keyword'][0] + ' - ' + doc['sizeData.elasticSizeScale.sizes.sizeOrder'][0]"
            },
            "size": 10,
            "order": {
              "by_size": "asc"
            }
          },
          "aggs": {
            "by_size": {
              "max": {
                "field": "sizeData.elasticSizeScale.sizes.sizeOrder"
              }
            }
          }
        }
      }
    }
  }
}

В 7.12 мы добавили новую агрегацию, для таких случаев:


POST test/_search
{
  "size": 0,
  "aggs": {
    "by_size": {
      "nested": {
        "path": "sizeData.elasticSizeScale.sizes"
      },
      "aggs": {
        "by_id": {
          "multi_terms": {
            "terms": [{
              "field" : "sizeData.elasticSizeScale.sizes.id"
            }, {
              "field" : "sizeData.elasticSizeScale.sizes.name.ru.keyword"
            }, {
              "field" : "sizeData.elasticSizeScale.sizes.sizeOrder"
            }],
            "size": 10,
            "order": {
              "by_size": "asc"
            }
          },
          "aggs": {
            "by_size": {
              "max": {
                "field": "sizeData.elasticSizeScale.sizes.sizeOrder"
              }
            }
          }
        }
      }
    }
  }
}